001package jmri.jmrix.cmri.serial.serialmon;
002
003import jmri.jmrix.cmri.CMRISystemConnectionMemo;
004import jmri.jmrix.cmri.serial.SerialListener;
005import jmri.jmrix.cmri.serial.SerialMessage;
006import jmri.jmrix.cmri.serial.SerialReply;
007import jmri.jmrix.cmri.serial.SerialNode;
008
009import java.awt.event.ActionEvent;
010
011import javax.swing.BoxLayout;
012import javax.swing.JButton;
013import javax.swing.JPanel;
014
015/**
016 * Frame displaying (and logging) CMRI serial command messages.
017 *
018 * @author Bob Jacobsen Copyright (C) 2001
019 * @author Chuck Catania  Copyright (C) 2014, 2016, 2017
020 */
021public class SerialMonFrame extends jmri.jmrix.AbstractMonFrame implements SerialListener {
022    // member declarations
023    // String deltaTCheck = this.getClass().getName()+".DeltaT"; // NOI18N
024   
025    protected JButton packetfilterButton = new JButton(Bundle.getMessage("FilterPacketsText") );  // NOI18N
026    protected static int _DLE    = 0x10;    
027   
028    private CMRISystemConnectionMemo _memo = null;    
029
030    public SerialMonFrame(CMRISystemConnectionMemo memo) {
031        super();
032        _memo = memo;        
033    }
034
035    @Override
036    public void dispose() { 
037        super.dispose();
038  }
039
040    @Override
041    protected String title() {
042        return Bundle.getMessage("SerialCommandMonTitle")+" "+Bundle.getMessage("Connection")+_memo.getUserName();  // NOI18N
043    }
044
045    @Override
046    protected void init() {
047        // connect to TrafficController
048        _memo.getTrafficController().addSerialListener(this);
049        // Load the packet filter bits
050        initializePacketFilters();
051        
052        // Add additional controls to the super class window
053        JPanel paneA = new JPanel();
054        paneA.setLayout(new BoxLayout(paneA, BoxLayout.Y_AXIS));
055        
056        JPanel pane1 = new JPanel();
057        pane1.setLayout(new BoxLayout(pane1, BoxLayout.X_AXIS));
058        
059        packetfilterButton.setText(Bundle.getMessage("FilterPacketsText"));  // NOI18N
060        packetfilterButton.setVisible(true);
061        packetfilterButton.setToolTipText(Bundle.getMessage("FilterPacketTip"));  // NOI18N
062        pane1.add(packetfilterButton);
063        packetfilterButton.addActionListener(this::openPacketFilterPerformed);
064        
065        paneA.add(pane1);
066        getContentPane().add(paneA);
067        pack();
068        paneA.setMaximumSize(paneA.getSize());
069        pack();
070        
071        // Move the filter packets button to the middle
072        getContentPane().setComponentZOrder(paneA,1);
073    }
074    
075    /**
076     * Define system-specific help item.
077     */
078    @Override
079    protected void setHelp() {
080        addHelpMenu("package.jmri.jmrix.cmri.serial.serialmon.SerialMonFrame", true);  // NOI18N
081    }
082
083    /**
084     * Initialize packet type filters.
085     */  
086    public void initializePacketFilters() {
087        // get all configured nodes
088        SerialNode node = (SerialNode) _memo.getTrafficController().getNode(0);
089        int index = 1,
090                pktTypeIndex = 0;
091
092        while (node != null) {
093            // Set all nodes and packet types to be monitored
094            //-----------------------------------------------
095            do {
096                node.setMonitorPacketBit(pktTypeIndex, true);
097                pktTypeIndex++;
098            } while (pktTypeIndex < SerialFilterFrame.numMonPkts);
099
100            node = (SerialNode) _memo.getTrafficController().getNode(index);
101            index++;
102            pktTypeIndex = 0;
103        }
104    }
105
106    /**
107     * Open the node/packet filter window.
108     * @param e unused.
109     */
110    public void openPacketFilterPerformed(ActionEvent e) {
111        // create a SerialFilterFrame
112        SerialFilterFrame f = new SerialFilterFrame(_memo);
113        try {
114            f.initComponents();
115        }
116        catch (Exception ex) {
117            log.warn("SerialMonFrame starting SerialFilterFrame: Exception: {}", ex.toString());
118        }
119        f.setVisible(true);
120    }
121
122    //-------------------
123    //  Transmit Packets
124    //-------------------
125    @Override
126    public synchronized void message(SerialMessage l) {
127
128        SerialNode monitorNode = (SerialNode) _memo.getTrafficController().getNodeFromAddress(l.getUA());
129        
130        // Test for node and packets being monitored
131        //------------------------------------------
132        if (monitorNode == null) return;       
133        if (!monitorNode.getMonitorNodePackets()) return;
134
135        int aPacketTypeID = l.getElement(1);
136        
137        // check for valid length
138        if (l.getNumDataElements() < 2) {
139            nextLine("Truncated message of length "+l.getNumDataElements()+"\n",l.toString());
140            return;
141        }
142        
143        switch(aPacketTypeID) {
144            case 0x50:        // (P) Poll
145                if(monitorNode.getMonitorPacketBit(SerialFilterFrame.monPktPoll))
146                {
147                    nextLine("Poll ua="+l.getUA()+"\n", l.toString());
148                }
149                break;
150
151            case 0x54:        // (T) Transmit
152                if (monitorNode.getMonitorPacketBit(SerialFilterFrame.monPktTransmit))
153                {
154                    StringBuilder sb = new StringBuilder("Transmit ua=");
155                    sb.append(l.getUA());
156                    sb.append(" OB=");
157                    for (int i=2; i<l.getNumDataElements(); i++)
158                    {
159                        if ((rawCheckBox.isSelected()) && ( l.getElement(i) == _DLE )) //c2
160                        {
161                            sb.append("<dle>");  // Convert DLE (0x10) to text
162                            i++;
163                        }
164
165                        sb.append(Integer.toHexString(l.getElement(i)&0x000000ff).toUpperCase());  //c2
166                        sb.append(" ");
167                    }
168                    sb.append("\n");
169                    nextLine(new String(sb), l.toString());
170                }
171                break;
172
173            case 0x49:        // (I) Initialize
174                if (monitorNode.getMonitorPacketBit(SerialFilterFrame.monPktInit)) {
175                    StringBuilder sb = new StringBuilder("Init ua=");
176                    sb.append(l.getUA());
177                    sb.append(" type=");
178                    int ndp=l.getElement(2); // ndp node type
179                    sb.append((char)ndp);
180                    int len = l.getNumDataElements();
181
182                    switch (ndp) {
183                        // SMINI/SUSIC/USIC
184                        case SerialNode.NDP_USICSUSIC24:
185                        case SerialNode.NDP_USICSUSIC32:
186                        case SerialNode.NDP_SMINI:
187                            if (len>=5)
188                            {
189                                sb.append(" DL=");
190                                sb.append(l.getElement(3)*256+l.getElement(4));
191                            }
192
193                            if (len>=6)
194                            {
195                                sb.append(" NS=");
196                                sb.append(l.getElement(5));
197                                sb.append(" CT: ");
198                                for (int i=6; i<l.getNumDataElements(); i++)
199                                {
200                                    sb.append(Integer.toHexString(l.getElement(i)&0x000000ff).toUpperCase()); //c2
201                                    sb.append(" ");
202                                }
203                            }
204                            break;
205
206                        case SerialNode.NDP_CPNODE: // CPNODE
207                        case SerialNode.NDP_CPMEGA: // CPMEGA
208                            if (len>=5)
209                            {
210                                sb.append(" DL=");
211                                sb.append(l.getElement(3)*256+l.getElement(4));
212                            }
213                            sb.append(" Opts=");
214                            int i=5;
215                            while (i<l.getNumDataElements()) {
216                                if (l.getElement(i) != _DLE) { // skip DLE
217                                    sb.append(Integer.toHexString(l.getElement(i)&0x000000ff).toUpperCase()); //c2
218                                    sb.append(" ");
219                                }
220                                i++;
221                            }
222                            break;
223
224                        default:
225                            sb.append("Unrecognized node type NDP: [").append(ndp).append("] ");
226                            break;
227
228                        } //ndp case
229
230                    sb.append("\n");
231                    nextLine(new String(sb), l.toString());
232                }
233                break;
234
235            default:
236                nextLine("Unrecognized cmd: \""+l.toString()+"\"\n", "");
237        }  // end packet ID case
238    }
239
240    //-------------------
241    //  Receive Packets
242    //-------------------
243    @Override
244    public synchronized void reply(SerialReply l) {
245
246        // Test for node and packets being monitored 
247        //------------------------------------------
248        SerialNode monitorNode = (SerialNode) _memo.getTrafficController().getNodeFromAddress(l.getUA());
249
250        if (monitorNode == null) {
251            return;
252        }
253        if (!monitorNode.getMonitorNodePackets()) {
254            return;
255        }
256
257        int aPacketTypeID = l.getElement(1);
258
259        // check for valid length
260        if (l.getNumDataElements() < 2) {
261            nextLine("Truncated reply of length " + l.getNumDataElements() + "\n", l.toString());
262            // CMRInetMetricsData.incMetricErrValue( CMRInetMetricsData.CMRInetMetricTruncReply );
263            return;
264        }
265        switch (aPacketTypeID) {
266            case 0x52:  // (R) Receive (poll reply)
267                if (monitorNode.getMonitorPacketBit(SerialFilterFrame.monPktRead)) {
268                    StringBuilder sb = new StringBuilder("Receive ua=");
269                    sb.append(l.getUA());
270                    sb.append(" IB=");
271                    for (int i = 2; i < l.getNumDataElements(); i++) {
272                        if ((rawCheckBox.isSelected()) && (l.getElement(i) == _DLE)) //c2
273                        {
274                            sb.append("<dle>");
275                            i++;
276                        }
277                        sb.append(Integer.toHexString(l.getElement(i) & 0x000000ff).toUpperCase());  //c2
278                        sb.append(" ");
279                    }
280                    sb.append("\n");
281                    nextLine(new String(sb), l.toString());
282                }
283                break;
284
285            case 0x45:  // (E) EOT c2
286                if (monitorNode.getMonitorPacketBit(SerialFilterFrame.monPktEOT)) {
287                    StringBuilder sb = new StringBuilder("Receive ua=");
288                    sb.append(l.getUA());
289                    sb.append(" eot");
290                    sb.append("\n");
291                    nextLine(new String(sb), l.toString());
292                }
293                break;
294
295            default:
296                // CMRInetMetricsData.incMetricErrValue( CMRInetMetricsData.CMRInetMetricUnrecResponse );
297                nextLine("Unrecognized response: \"" + l.toString() + "\"\n", "");
298                break;
299        }
300    }
301
302    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SerialMonFrame.class);
303
304}
305