001package jmri.jmrix.openlcb.swing.send; 002 003import java.awt.event.ActionEvent; 004import java.awt.event.ActionListener; 005import java.awt.BorderLayout; 006import java.awt.Dimension; 007 008import javax.swing.Box; 009import javax.swing.BoxLayout; 010import javax.swing.JButton; 011import javax.swing.JCheckBox; 012import javax.swing.JComboBox; 013import javax.swing.JComponent; 014import javax.swing.JLabel; 015import javax.swing.JPanel; 016import javax.swing.JSeparator; 017import javax.swing.JTextField; 018import javax.swing.JToggleButton; 019 020import jmri.jmrix.can.CanListener; 021import jmri.jmrix.can.CanMessage; 022import jmri.jmrix.can.CanReply; 023import jmri.jmrix.can.CanSystemConnectionMemo; 024import jmri.jmrix.can.TrafficController; 025import jmri.jmrix.can.cbus.CbusAddress; 026import jmri.jmrix.openlcb.swing.ClientActions; 027import jmri.jmrix.openlcb.swing.NamedEventIdTextField; 028import jmri.util.StringUtil; 029import jmri.util.javaworld.GridLayout2; 030import jmri.util.swing.WrapLayout; 031 032import org.openlcb.*; 033import org.openlcb.can.AliasMap; 034import org.openlcb.implementations.MemoryConfigurationService; 035import org.openlcb.swing.NodeSelector; 036import org.openlcb.swing.MemorySpaceSelector; 037 038/** 039 * User interface for sending OpenLCB CAN frames to exercise the system 040 * <p> 041 * When sending a sequence of operations: 042 * <ul> 043 * <li>Send the next message and start a timer 044 * <li>When the timer trips, repeat if buttons still down. 045 * </ul> 046 * 047 * @author Bob Jacobsen Copyright (C) 2008, 2012 048 * 049 */ 050public class OpenLcbCanSendPane extends jmri.jmrix.can.swing.CanPanel implements CanListener { 051 052 // member declarations 053 final JLabel jLabel1 = new JLabel(); 054 final JButton sendButton = new JButton(); 055 final JTextField packetTextField = new JTextField(60); 056 057 // internal members to hold sequence widgets 058 static final int MAXSEQUENCE = 4; 059 final JTextField[] mPacketField = new JTextField[MAXSEQUENCE]; 060 final JCheckBox[] mUseField = new JCheckBox[MAXSEQUENCE]; 061 final JTextField[] mDelayField = new JTextField[MAXSEQUENCE]; 062 final JToggleButton mRunButton = new JToggleButton(Bundle.getMessage("ButtonGo")); 063 064 final JTextField srcAliasField = new JTextField(4); 065 NodeSelector nodeSelector; 066 NamedEventIdTextField sendEventField; 067 final JTextField datagramContentsField = new JTextField("20 61 00 00 00 00 08"); // NOI18N 068 final JTextField configNumberField = new JTextField("40"); // NOI18N 069 final JTextField configAddressField = new JTextField("000000"); // NOI18N 070 final JTextField readDataField = new JTextField(60); 071 final JTextField writeDataField = new JTextField(60); 072 final MemorySpaceSelector addrSpace = new MemorySpaceSelector(0xFF); 073 final JComboBox<String> validitySelector = new JComboBox<String>(new String[]{Bundle.getMessage("ValiditySelectorUnknown"), 074 Bundle.getMessage("ValiditySelectorValid"), Bundle.getMessage("ValiditySelectorInvalid")}); 075 076 JButton cdiButton; 077 078 Connection connection; 079 AliasMap aliasMap; 080 NodeID srcNodeID; 081 MemoryConfigurationService mcs; 082 MimicNodeStore store; 083 OlcbInterface iface; 084 ClientActions actions; 085 086 public OpenLcbCanSendPane() { 087 // most of the action is in initComponents 088 } 089 090 @Override 091 public void initComponents(CanSystemConnectionMemo memo) { 092 super.initComponents(memo); 093 iface = memo.get(OlcbInterface.class); 094 actions = new ClientActions(iface, memo); 095 tc = memo.getTrafficController(); 096 tc.addCanListener(this); 097 connection = memo.get(org.openlcb.Connection.class); 098 srcNodeID = memo.get(org.openlcb.NodeID.class); 099 aliasMap = memo.get(org.openlcb.can.AliasMap.class); 100 101 sendEventField = new NamedEventIdTextField(memo); 102 103 // register request for notification 104 Connection.ConnectionListener cl = new Connection.ConnectionListener() { 105 @Override 106 public void connectionActive(Connection c) { 107 log.debug("connection active"); 108 // load the alias field 109 srcAliasField.setText(Integer.toHexString(aliasMap.getAlias(srcNodeID))); 110 } 111 }; 112 connection.registerStartNotification(cl); 113 114 mcs = memo.get(MemoryConfigurationService.class); 115 store = memo.get(MimicNodeStore.class); 116 nodeSelector = new NodeSelector(store); 117 nodeSelector.addActionListener (new ActionListener () { 118 @Override 119 public void actionPerformed(ActionEvent e) { 120 setCdiButton(); 121 jmri.util.ThreadingUtil.runOnGUIDelayed( ()->{ 122 setCdiButton(); 123 }, 500); 124 } 125 }); 126 127 // start window layout 128 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 129 130 // handle single-packet part 131 add(getSendSinglePacketJPanel()); 132 133 add(new JSeparator()); 134 135 // Configure the sequence 136 add(new JLabel(Bundle.getMessage("ConfigureSendSequence"))); 137 JPanel pane2 = new JPanel(); 138 pane2.setLayout(new GridLayout2(MAXSEQUENCE + 2, 4)); 139 pane2.add(new JLabel("")); 140 pane2.add(new JLabel(Bundle.getMessage("ConfigureSend"))); 141 pane2.add(new JLabel(Bundle.getMessage("ConfigureSendPacket"))); 142 pane2.add(new JLabel(Bundle.getMessage("ConfigureWait"))); 143 for (int i = 0; i < MAXSEQUENCE; i++) { 144 pane2.add(new JLabel(Integer.toString(i + 1))); 145 mUseField[i] = new JCheckBox(); 146 mPacketField[i] = new JTextField(20); 147 mDelayField[i] = new JTextField(10); 148 pane2.add(mUseField[i]); 149 pane2.add(mPacketField[i]); 150 pane2.add(mDelayField[i]); 151 } 152 add(pane2); 153 add(mRunButton); // below rows 154 155 mRunButton.addActionListener(this::runButtonActionPerformed); 156 157 // special packet forms 158 add(new JSeparator()); 159 160 pane2 = new JPanel(); 161 pane2.setLayout(new WrapLayout()); 162 add(pane2); 163 pane2.add(new JLabel(Bundle.getMessage("SpecialSendControlFrame"))); 164 pane2.add(srcAliasField); 165 JButton b; 166 b = new JButton(Bundle.getMessage("SpecialSendCIM")); 167 b.addActionListener(this::sendCimPerformed); 168 pane2.add(b); 169 170 // send OpenLCB messages 171 add(new JSeparator()); 172 173 pane2 = new JPanel(); 174 pane2.setLayout(new WrapLayout()); 175 add(pane2); 176 pane2.add(new JLabel(Bundle.getMessage("OpenLCBMessagesGlobal"))); 177 b = new JButton(Bundle.getMessage("OpenLCBMessagesVerify")); 178 b.addActionListener(this::sendVerifyNodeGlobal); 179 pane2.add(b); 180 b = new JButton(Bundle.getMessage("OpenLCBMessagesNodeID")); 181 b.addActionListener(this::sendVerifyNodeGlobalID); 182 pane2.add(b); 183 184 // event messages 185 add(new JSeparator()); 186 187 var insert = new JPanel(); 188 insert.setLayout(new WrapLayout()); 189 insert.add(sendEventField); 190 insert.add(validitySelector); 191 192 193 add(addLineLabel(Bundle.getMessage("EventMessagesEventID"), insert)); 194 pane2 = new JPanel(); 195 pane2.setLayout(new WrapLayout()); 196 add(pane2); 197 b = new JButton(Bundle.getMessage("EventMessagesGlobalIdentify")); 198 b.addActionListener(this::sendGlobalIdentifyEvents); 199 pane2.add(b); 200 b = new JButton(Bundle.getMessage("EventMessagesEventProduced")); 201 b.addActionListener(this::sendEventPerformed); 202 pane2.add(b); 203 pane2 = new JPanel(); 204 pane2.setLayout(new WrapLayout()); 205 add(pane2); 206 b = new JButton(Bundle.getMessage("EventMessagesIdentifyConsumers")); 207 b.addActionListener(this::sendReqConsumers); 208 pane2.add(b); 209 b = new JButton(Bundle.getMessage("EventMessagesConsumerIdentified")); 210 b.addActionListener(this::sendConsumerID); 211 pane2.add(b); 212 b = new JButton(Bundle.getMessage("EventMessagesIdentifyProducers")); 213 b.addActionListener(this::sendReqProducers); 214 pane2.add(b); 215 b = new JButton(Bundle.getMessage("EventMessagesProducerIdentified")); 216 b.addActionListener(this::sendProducerID); 217 pane2.add(b); 218 219 // addressed messages 220 add(new JSeparator()); 221 add(addLineLabel(Bundle.getMessage("AddressedMessagesMessageTo"), nodeSelector)); 222 pane2 = new JPanel(); 223 pane2.setLayout(new WrapLayout()); 224 add(pane2); 225 b = new JButton(Bundle.getMessage("AddressedMessagesIdentifyEvents")); 226 b.addActionListener(this::sendRequestEvents); 227 pane2.add(b); 228 b = new JButton(Bundle.getMessage("AddressedMessagesPIPRequest")); 229 b.addActionListener(this::sendRequestPip); 230 pane2.add(b); 231 b = new JButton(Bundle.getMessage("AddressedMessagesSNIPRequest")); 232 b.addActionListener(this::sendRequestSnip); 233 pane2.add(b); 234 235 add(new JSeparator()); 236 237 pane2 = new JPanel(); 238 pane2.setLayout(new WrapLayout()); 239 add(pane2); 240 b = new JButton(Bundle.getMessage("AddressedMessagesDatagram")); 241 b.addActionListener(this::sendDatagramPerformed); 242 pane2.add(b); 243 pane2.add(new JLabel(Bundle.getMessage("AddressedMessagesContents"))); 244 datagramContentsField.setColumns(45); 245 pane2.add(datagramContentsField); 246 b = new JButton(Bundle.getMessage("AddressedMessagesPositiveReply")); 247 b.addActionListener(this::sendDatagramReply); 248 pane2.add(b); 249 250 // send OpenLCB Configuration message 251 add(new JSeparator()); 252 253 pane2 = new JPanel(); 254 pane2.setLayout(new WrapLayout()); 255 add(pane2); 256 257 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesMemoryRequest"))); 258 pane2.add(configAddressField); 259 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesAddressSpace"))); 260 pane2.add(addrSpace); 261 pane2 = new JPanel(); 262 pane2.setLayout(new WrapLayout()); 263 add(pane2); 264 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesByteCount"))); 265 pane2.add(configNumberField); 266 b = new JButton(Bundle.getMessage("ConfigMessagesRead")); 267 b.addActionListener(this::readPerformed); 268 pane2.add(b); 269 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesData"))); 270 pane2.add(readDataField); 271 272 pane2 = new JPanel(); 273 pane2.setLayout(new WrapLayout()); 274 add(pane2); 275 b = new JButton(Bundle.getMessage("ConfigMessagesWrite")); 276 b.addActionListener(this::writePerformed); 277 pane2.add(b); 278 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesData"))); 279 writeDataField.setText("00 00"); // NOI18N 280 pane2.add(writeDataField); 281 282 pane2 = new JPanel(); 283 pane2.setLayout(new WrapLayout()); 284 add(pane2); 285 286 var restartButton = new JButton(Bundle.getMessage("ConfigMessagesRestart")); 287 pane2.add(restartButton); 288 restartButton.addActionListener(this::restartNode); 289 290 cdiButton = new JButton(Bundle.getMessage("ConfigMessagesOpenCDI")); 291 pane2.add(cdiButton); 292 cdiButton.addActionListener(e -> openCdiPane()); 293 cdiButton.setToolTipText(Bundle.getMessage("ConfigMessagesOpenCDItt")); 294 setCdiButton(); // get initial state 295 296 var clearCacheButton = new JButton(Bundle.getMessage("ConfigMessagesClearCDI")); 297 pane2.add(clearCacheButton); 298 clearCacheButton.addActionListener(this::clearCache); 299 clearCacheButton.setToolTipText(Bundle.getMessage("ConfigMessagesClearCDItt")); 300 301 // listen for mimic store changes to set CDI button 302 store.addPropertyChangeListener(e -> { 303 setCdiButton(); 304 }); 305 jmri.util.ThreadingUtil.runOnGUIDelayed( ()->{ 306 setCdiButton(); 307 }, 500); 308 } 309 310 /** 311 * Set whether Open CDI button is enabled based on whether 312 * the selected node has CDI in its PIP 313 */ 314 protected void setCdiButton() { 315 var nodeID = nodeSelector.getSelectedNodeID(); 316 if (nodeID == null) { 317 cdiButton.setEnabled(false); 318 log.debug("null nodeID disables cdiButton"); 319 return; 320 } 321 var pip = store.getProtocolIdentification(nodeID); 322 if (pip == null || pip.getProtocols() == null) { 323 cdiButton.setEnabled(false); 324 log.debug("null pip info disables cdiButton"); 325 return; 326 } 327 boolean setValue = 328 pip.getProtocols() 329 .contains(org.openlcb.ProtocolIdentification.Protocol.ConfigurationDescription); 330 cdiButton.setEnabled(setValue); 331 log.debug("cdiButton set {} from PIP info", setValue); 332 } 333 334 private JPanel getSendSinglePacketJPanel() { 335 JPanel outer = new JPanel(); 336 outer.setLayout(new BoxLayout(outer, BoxLayout.X_AXIS)); 337 338 JPanel pane1 = new JPanel(); 339 pane1.setLayout(new BoxLayout(pane1, BoxLayout.Y_AXIS)); 340 341 jLabel1.setText(Bundle.getMessage("SinglePacketLabel")); 342 jLabel1.setVisible(true); 343 344 sendButton.setText(Bundle.getMessage("SinglePacketSend")); 345 sendButton.setVisible(true); 346 sendButton.setToolTipText(Bundle.getMessage("SinglePacketSendTt")); 347 348 packetTextField.setToolTipText(Bundle.getMessage("SinglePacketText")); 349 packetTextField.setMaximumSize(packetTextField.getPreferredSize()); 350 351 pane1.add(jLabel1); 352 pane1.add(packetTextField); 353 pane1.add(sendButton); 354 pane1.add(Box.createVerticalGlue()); 355 356 sendButton.addActionListener(this::sendButtonActionPerformed); 357 358 outer.add(Box.createHorizontalGlue()); 359 outer.add(pane1); 360 outer.add(Box.createHorizontalGlue()); 361 return outer; 362 } 363 364 @Override 365 public String getHelpTarget() { 366 return "package.jmri.jmrix.openlcb.swing.send.OpenLcbCanSendFrame"; // NOI18N 367 } 368 369 @Override 370 public String getTitle() { 371 if (memo != null) { 372 return (memo.getUserName() + " " + Bundle.getMessage("Title")); 373 } 374 return Bundle.getMessage("Title"); 375 } 376 377 JComponent addLineLabel(String text) { 378 return addLineLabel(text, null); 379 } 380 381 JComponent addLineLabel(String text, JComponent c) { 382 JLabel lab = new JLabel(text); 383 JPanel p = new JPanel(); 384 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); 385 if (c != null) { 386 p.add(lab, BorderLayout.EAST); 387 if (c instanceof JTextField) { 388 int height = lab.getMinimumSize().height+4; 389 int width = c.getMinimumSize().width; 390 Dimension d = new Dimension(width, height); 391 c.setMaximumSize(d); 392 } 393 p.add(c); 394 } else { 395 p.add(lab, BorderLayout.EAST); 396 } 397 p.add(Box.createHorizontalGlue()); 398 return p; 399 } 400 401 public void sendButtonActionPerformed(java.awt.event.ActionEvent e) { 402 String input = packetTextField.getText(); 403 // TODO check input + feedback on error. Too easy to cause NPE 404 CanMessage m = createPacket(input); 405 log.debug("sendButtonActionPerformed: {}",m); 406 tc.sendCanMessage(m, this); 407 } 408 409 public void sendCimPerformed(java.awt.event.ActionEvent e) { 410 String data = "[10700" + srcAliasField.getText() + "]"; // NOI18N 411 log.debug("sendCimPerformed: |{}|",data); 412 CanMessage m = createPacket(data); 413 log.debug("sendCimPerformed"); 414 tc.sendCanMessage(m, this); 415 } 416 417 NodeID destNodeID() { 418 return nodeSelector.getSelectedNodeID(); 419 } 420 421 EventID eventID() { 422 return sendEventField.getEventID(); 423 } 424 425 public void sendVerifyNodeGlobal(java.awt.event.ActionEvent e) { 426 Message m = new VerifyNodeIDNumberGlobalMessage(srcNodeID); 427 connection.put(m, null); 428 } 429 430 public void sendVerifyNodeGlobalID(java.awt.event.ActionEvent e) { 431 Message m = new VerifyNodeIDNumberGlobalMessage(srcNodeID, destNodeID()); 432 connection.put(m, null); 433 } 434 435 public void sendRequestEvents(java.awt.event.ActionEvent e) { 436 Message m = new IdentifyEventsAddressedMessage(srcNodeID, destNodeID()); 437 connection.put(m, null); 438 } 439 440 public void sendRequestPip(java.awt.event.ActionEvent e) { 441 Message m = new ProtocolIdentificationRequestMessage(srcNodeID, destNodeID()); 442 connection.put(m, null); 443 } 444 445 public void sendRequestSnip(java.awt.event.ActionEvent e) { 446 Message m = new SimpleNodeIdentInfoRequestMessage(srcNodeID, destNodeID()); 447 connection.put(m, null); 448 } 449 450 public void sendGlobalIdentifyEvents(java.awt.event.ActionEvent e) { 451 Message m = new IdentifyEventsGlobalMessage(srcNodeID); 452 connection.put(m, null); 453 } 454 455 public void sendEventPerformed(java.awt.event.ActionEvent e) { 456 Message m = new ProducerConsumerEventReportMessage(srcNodeID, eventID()); 457 connection.put(m, null); 458 } 459 460 public void sendReqConsumers(java.awt.event.ActionEvent e) { 461 Message m = new IdentifyConsumersMessage(srcNodeID, eventID()); 462 connection.put(m, null); 463 } 464 465 EventState validity() { 466 switch (validitySelector.getSelectedIndex()) { 467 case 1 : return EventState.Valid; 468 case 2 : return EventState.Invalid; 469 case 0 : 470 default: return EventState.Unknown; 471 } 472 } 473 474 public void sendConsumerID(java.awt.event.ActionEvent e) { 475 Message m = new ConsumerIdentifiedMessage(srcNodeID, eventID(), validity()); 476 connection.put(m, null); 477 } 478 479 public void sendReqProducers(java.awt.event.ActionEvent e) { 480 Message m = new IdentifyProducersMessage(srcNodeID, eventID()); 481 connection.put(m, null); 482 } 483 484 public void sendProducerID(java.awt.event.ActionEvent e) { 485 Message m = new ProducerIdentifiedMessage(srcNodeID, eventID(), validity()); 486 connection.put(m, null); 487 } 488 489 public void sendDatagramPerformed(java.awt.event.ActionEvent e) { 490 Message m = new DatagramMessage(srcNodeID, destNodeID(), 491 jmri.util.StringUtil.bytesFromHexString(datagramContentsField.getText())); 492 connection.put(m, null); 493 } 494 495 public void sendDatagramReply(java.awt.event.ActionEvent e) { 496 Message m = new DatagramAcknowledgedMessage(srcNodeID, destNodeID()); 497 connection.put(m, null); 498 } 499 500 public void restartNode(java.awt.event.ActionEvent e) { 501 Message m = new DatagramMessage(srcNodeID, destNodeID(), 502 new byte[] {0x20, (byte) 0xA9}); 503 connection.put(m, null); 504 } 505 506 public void clearCache(java.awt.event.ActionEvent e) { 507 jmri.jmrix.openlcb.swing.DropCdiCache.drop(destNodeID(), memo.get(OlcbInterface.class)); 508 } 509 510 public void readPerformed(java.awt.event.ActionEvent e) { 511 int space = addrSpace.getMemorySpace(); 512 long addr = Integer.parseInt(configAddressField.getText(), 16); 513 int length = Integer.parseInt(configNumberField.getText()); 514 mcs.requestRead(destNodeID(), space, addr, 515 length, new MemoryConfigurationService.McsReadHandler() { 516 @Override 517 public void handleReadData(NodeID dest, int space, long address, byte[] data) { 518 log.debug("Read data received {} bytes",data.length); 519 readDataField.setText(jmri.util.StringUtil.hexStringFromBytes(data)); 520 } 521 522 @Override 523 public void handleFailure(int errorCode) { 524 log.warn("OpenLCB read failed: 0x{}", Integer.toHexString 525 (errorCode)); 526 } 527 }); 528 } 529 530 public void writePerformed(java.awt.event.ActionEvent e) { 531 int space = addrSpace.getMemorySpace(); 532 long addr = Integer.parseInt(configAddressField.getText(), 16); 533 byte[] content = jmri.util.StringUtil.bytesFromHexString(writeDataField.getText()); 534 mcs.requestWrite(destNodeID(), space, addr, content, new MemoryConfigurationService.McsWriteHandler() { 535 @Override 536 public void handleSuccess() { 537 // no action required on success 538 } 539 540 @Override 541 public void handleFailure(int errorCode) { 542 log.warn("OpenLCB write failed: 0x{}", Integer.toHexString 543 (errorCode)); 544 } 545 }); 546 } 547 548 public void openCdiPane() { 549 actions.openCdiWindow(destNodeID(), destNodeID().toString()); 550 } 551 552 // control sequence operation 553 int mNextSequenceElement = 0; 554 javax.swing.Timer timer = null; 555 556 /** 557 * Internal routine to handle timer starts and restarts 558 * @param delay milliseconds to delay 559 */ 560 protected void restartTimer(int delay) { 561 if (timer == null) { 562 timer = new javax.swing.Timer(delay, e -> sendNextItem()); 563 } 564 timer.stop(); 565 timer.setInitialDelay(delay); 566 timer.setRepeats(false); 567 timer.start(); 568 } 569 570 /** 571 * Internal routine to handle a timeout and send next item 572 */ 573 protected synchronized void timeout() { 574 sendNextItem(); 575 } 576 577 /** 578 * Run button pressed down, start the sequence operation 579 * @param e event from GUI 580 * 581 */ 582 public void runButtonActionPerformed(java.awt.event.ActionEvent e) { 583 if (!mRunButton.isSelected()) { 584 return; 585 } 586 // make sure at least one is checked 587 boolean ok = false; 588 for (int i = 0; i < MAXSEQUENCE; i++) { 589 if (mUseField[i].isSelected()) { 590 ok = true; 591 } 592 } 593 if (!ok) { 594 mRunButton.setSelected(false); 595 return; 596 } 597 // start the operation 598 mNextSequenceElement = 0; 599 sendNextItem(); 600 } 601 602 /** 603 * Echo has been heard, start delay for next packet 604 */ 605 void startSequenceDelay() { 606 // at the start, mNextSequenceElement contains index we're 607 // working on 608 int delay = Integer.parseInt(mDelayField[mNextSequenceElement].getText()); 609 // increment to next line at completion 610 mNextSequenceElement++; 611 // start timer 612 restartTimer(delay); 613 } 614 615 /** 616 * Send next item; may be used for the first item or when a delay has 617 * elapsed. 618 */ 619 void sendNextItem() { 620 // check if still running 621 if (!mRunButton.isSelected()) { 622 return; 623 } 624 // have we run off the end? 625 if (mNextSequenceElement >= MAXSEQUENCE) { 626 // past the end, go back 627 mNextSequenceElement = 0; 628 } 629 // is this one enabled? 630 if (mUseField[mNextSequenceElement].isSelected()) { 631 // make the packet 632 CanMessage m = createPacket(mPacketField[mNextSequenceElement].getText()); 633 // send it 634 tc.sendCanMessage(m, this); 635 startSequenceDelay(); 636 } else { 637 // ask for the next one 638 mNextSequenceElement++; 639 sendNextItem(); 640 } 641 } 642 643 /** 644 * Create a well-formed message from a String String is expected to be space 645 * seperated hex bytes or CbusAddress, e.g.: 12 34 56 +n4e1 646 * @param s string of spaced hex byte codes 647 * @return The packet, with contents filled-in 648 */ 649 CanMessage createPacket(String s) { 650 CanMessage m; 651 // Try to convert using CbusAddress class to reuse a little code 652 CbusAddress a = new CbusAddress(s); 653 if (a.check()) { 654 m = a.makeMessage(tc.getCanid()); 655 } else { 656 m = new CanMessage(tc.getCanid()); 657 // check for header 658 if (s.charAt(0) == '[') { // NOI18N 659 // extended header 660 m.setExtended(true); 661 int i = s.indexOf(']'); // NOI18N 662 String h = s.substring(1, i); 663 m.setHeader(Integer.parseInt(h, 16)); 664 s = s.substring(i + 1); 665 } else if (s.charAt(0) == '(') { // NOI18N 666 // standard header 667 int i = s.indexOf(')'); // NOI18N 668 String h = s.substring(1, i); 669 m.setHeader(Integer.parseInt(h, 16)); 670 s = s.substring(i + 1); 671 } 672 // Try to get hex bytes 673 byte[] b = StringUtil.bytesFromHexString(s); 674 m.setNumDataElements(b.length); 675 // Use &0xff to ensure signed bytes are stored as unsigned ints 676 for (int i = 0; i < b.length; i++) { 677 m.setElement(i, b[i] & 0xff); 678 } 679 } 680 return m; 681 } 682 683 /** 684 * Don't pay attention to messages 685 */ 686 @Override 687 public void message(CanMessage m) { 688 // ignore outgoing messages 689 } 690 691 /** 692 * Don't pay attention to replies 693 */ 694 @Override 695 public void reply(CanReply m) { 696 // ignore incoming replies 697 } 698 699 /** 700 * When the window closes, stop any sequences running 701 */ 702 @Override 703 public void dispose() { 704 mRunButton.setSelected(false); 705 super.dispose(); 706 } 707 708 // private data 709 private TrafficController tc = null; // was CanInterface 710 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OpenLcbCanSendPane.class); 711 712}