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.JFormattedTextField; 015import javax.swing.JLabel; 016import javax.swing.JPanel; 017import javax.swing.JSeparator; 018import javax.swing.JTextField; 019import javax.swing.JToggleButton; 020 021import jmri.jmrix.can.CanListener; 022import jmri.jmrix.can.CanMessage; 023import jmri.jmrix.can.CanReply; 024import jmri.jmrix.can.CanSystemConnectionMemo; 025import jmri.jmrix.can.TrafficController; 026import jmri.jmrix.can.cbus.CbusAddress; 027import jmri.jmrix.openlcb.swing.ClientActions; 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.EventIdTextField; 036import org.openlcb.swing.NodeSelector; 037import org.openlcb.swing.MemorySpaceSelector; 038 039/** 040 * User interface for sending OpenLCB CAN frames to exercise the system 041 * <p> 042 * When sending a sequence of operations: 043 * <ul> 044 * <li>Send the next message and start a timer 045 * <li>When the timer trips, repeat if buttons still down. 046 * </ul> 047 * 048 * @author Bob Jacobsen Copyright (C) 2008, 2012 049 * 050 */ 051public class OpenLcbCanSendPane extends jmri.jmrix.can.swing.CanPanel implements CanListener { 052 053 // member declarations 054 final JLabel jLabel1 = new JLabel(); 055 final JButton sendButton = new JButton(); 056 final JTextField packetTextField = new JTextField(60); 057 058 // internal members to hold sequence widgets 059 static final int MAXSEQUENCE = 4; 060 final JTextField[] mPacketField = new JTextField[MAXSEQUENCE]; 061 final JCheckBox[] mUseField = new JCheckBox[MAXSEQUENCE]; 062 final JTextField[] mDelayField = new JTextField[MAXSEQUENCE]; 063 final JToggleButton mRunButton = new JToggleButton(Bundle.getMessage("ButtonGo")); 064 065 final JTextField srcAliasField = new JTextField(4); 066 NodeSelector nodeSelector; 067 final JFormattedTextField sendEventField = new EventIdTextField();// NOI18N 068 final JTextField datagramContentsField = new JTextField("20 61 00 00 00 00 08"); // NOI18N 069 final JTextField configNumberField = new JTextField("40"); // NOI18N 070 final JTextField configAddressField = new JTextField("000000"); // NOI18N 071 final JTextField readDataField = new JTextField(60); 072 final JTextField writeDataField = new JTextField(60); 073 final MemorySpaceSelector addrSpace = new MemorySpaceSelector(0xFF); 074 final JComboBox<String> validitySelector = new JComboBox<String>(new String[]{Bundle.getMessage("ValiditySelectorUnknown"), 075 Bundle.getMessage("ValiditySelectorValid"), Bundle.getMessage("ValiditySelectorInvalid")}); 076 077 JButton cdiButton; 078 079 Connection connection; 080 AliasMap aliasMap; 081 NodeID srcNodeID; 082 MemoryConfigurationService mcs; 083 MimicNodeStore store; 084 OlcbInterface iface; 085 ClientActions actions; 086 087 public OpenLcbCanSendPane() { 088 // most of the action is in initComponents 089 } 090 091 @Override 092 public void initComponents(CanSystemConnectionMemo memo) { 093 super.initComponents(memo); 094 iface = memo.get(OlcbInterface.class); 095 actions = new ClientActions(iface, memo); 096 tc = memo.getTrafficController(); 097 tc.addCanListener(this); 098 connection = memo.get(org.openlcb.Connection.class); 099 srcNodeID = memo.get(org.openlcb.NodeID.class); 100 aliasMap = memo.get(org.openlcb.can.AliasMap.class); 101 102 // register request for notification 103 Connection.ConnectionListener cl = new Connection.ConnectionListener() { 104 @Override 105 public void connectionActive(Connection c) { 106 log.debug("connection active"); 107 // load the alias field 108 srcAliasField.setText(Integer.toHexString(aliasMap.getAlias(srcNodeID))); 109 } 110 }; 111 connection.registerStartNotification(cl); 112 113 mcs = memo.get(MemoryConfigurationService.class); 114 store = memo.get(MimicNodeStore.class); 115 nodeSelector = new NodeSelector(store); 116 nodeSelector.addActionListener (new ActionListener () { 117 @Override 118 public void actionPerformed(ActionEvent e) { 119 setCdiButton(); 120 jmri.util.ThreadingUtil.runOnGUIDelayed( ()->{ 121 setCdiButton(); 122 }, 500); 123 } 124 }); 125 126 // start window layout 127 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 128 129 // handle single-packet part 130 add(getSendSinglePacketJPanel()); 131 132 add(new JSeparator()); 133 134 // Configure the sequence 135 add(new JLabel(Bundle.getMessage("ConfigureSendSequence"))); 136 JPanel pane2 = new JPanel(); 137 pane2.setLayout(new GridLayout2(MAXSEQUENCE + 2, 4)); 138 pane2.add(new JLabel("")); 139 pane2.add(new JLabel(Bundle.getMessage("ConfigureSend"))); 140 pane2.add(new JLabel(Bundle.getMessage("ConfigureSendPacket"))); 141 pane2.add(new JLabel(Bundle.getMessage("ConfigureWait"))); 142 for (int i = 0; i < MAXSEQUENCE; i++) { 143 pane2.add(new JLabel(Integer.toString(i + 1))); 144 mUseField[i] = new JCheckBox(); 145 mPacketField[i] = new JTextField(20); 146 mDelayField[i] = new JTextField(10); 147 pane2.add(mUseField[i]); 148 pane2.add(mPacketField[i]); 149 pane2.add(mDelayField[i]); 150 } 151 add(pane2); 152 add(mRunButton); // below rows 153 154 mRunButton.addActionListener(this::runButtonActionPerformed); 155 156 // special packet forms 157 add(new JSeparator()); 158 159 pane2 = new JPanel(); 160 pane2.setLayout(new WrapLayout()); 161 add(pane2); 162 pane2.add(new JLabel(Bundle.getMessage("SpecialSendControlFrame"))); 163 pane2.add(srcAliasField); 164 JButton b; 165 b = new JButton(Bundle.getMessage("SpecialSendCIM")); 166 b.addActionListener(this::sendCimPerformed); 167 pane2.add(b); 168 169 // send OpenLCB messages 170 add(new JSeparator()); 171 172 pane2 = new JPanel(); 173 pane2.setLayout(new WrapLayout()); 174 add(pane2); 175 pane2.add(new JLabel(Bundle.getMessage("OpenLCBMessagesGlobal"))); 176 b = new JButton(Bundle.getMessage("OpenLCBMessagesVerify")); 177 b.addActionListener(this::sendVerifyNodeGlobal); 178 pane2.add(b); 179 b = new JButton(Bundle.getMessage("OpenLCBMessagesNodeID")); 180 b.addActionListener(this::sendVerifyNodeGlobalID); 181 pane2.add(b); 182 183 // event messages 184 add(new JSeparator()); 185 186 var insert = new JPanel(); 187 insert.setLayout(new WrapLayout()); 188 insert.add(sendEventField); 189 insert.add(validitySelector); 190 191 192 add(addLineLabel(Bundle.getMessage("EventMessagesEventID"), insert)); 193 pane2 = new JPanel(); 194 pane2.setLayout(new WrapLayout()); 195 add(pane2); 196 b = new JButton(Bundle.getMessage("EventMessagesGlobalIdentify")); 197 b.addActionListener(this::sendGlobalIdentifyEvents); 198 pane2.add(b); 199 b = new JButton(Bundle.getMessage("EventMessagesEventProduced")); 200 b.addActionListener(this::sendEventPerformed); 201 pane2.add(b); 202 pane2 = new JPanel(); 203 pane2.setLayout(new WrapLayout()); 204 add(pane2); 205 b = new JButton(Bundle.getMessage("EventMessagesIdentifyConsumers")); 206 b.addActionListener(this::sendReqConsumers); 207 pane2.add(b); 208 b = new JButton(Bundle.getMessage("EventMessagesConsumerIdentified")); 209 b.addActionListener(this::sendConsumerID); 210 pane2.add(b); 211 b = new JButton(Bundle.getMessage("EventMessagesIdentifyProducers")); 212 b.addActionListener(this::sendReqProducers); 213 pane2.add(b); 214 b = new JButton(Bundle.getMessage("EventMessagesProducerIdentified")); 215 b.addActionListener(this::sendProducerID); 216 pane2.add(b); 217 218 // addressed messages 219 add(new JSeparator()); 220 add(addLineLabel(Bundle.getMessage("AddressedMessagesMessageTo"), nodeSelector)); 221 pane2 = new JPanel(); 222 pane2.setLayout(new WrapLayout()); 223 add(pane2); 224 b = new JButton(Bundle.getMessage("AddressedMessagesIdentifyEvents")); 225 b.addActionListener(this::sendRequestEvents); 226 pane2.add(b); 227 b = new JButton(Bundle.getMessage("AddressedMessagesPIPRequest")); 228 b.addActionListener(this::sendRequestPip); 229 pane2.add(b); 230 b = new JButton(Bundle.getMessage("AddressedMessagesSNIPRequest")); 231 b.addActionListener(this::sendRequestSnip); 232 pane2.add(b); 233 234 add(new JSeparator()); 235 236 pane2 = new JPanel(); 237 pane2.setLayout(new WrapLayout()); 238 add(pane2); 239 b = new JButton(Bundle.getMessage("AddressedMessagesDatagram")); 240 b.addActionListener(this::sendDatagramPerformed); 241 pane2.add(b); 242 pane2.add(new JLabel(Bundle.getMessage("AddressedMessagesContents"))); 243 datagramContentsField.setColumns(45); 244 pane2.add(datagramContentsField); 245 b = new JButton(Bundle.getMessage("AddressedMessagesPositiveReply")); 246 b.addActionListener(this::sendDatagramReply); 247 pane2.add(b); 248 249 // send OpenLCB Configuration message 250 add(new JSeparator()); 251 252 pane2 = new JPanel(); 253 pane2.setLayout(new WrapLayout()); 254 add(pane2); 255 256 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesMemoryRequest"))); 257 pane2.add(configAddressField); 258 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesAddressSpace"))); 259 pane2.add(addrSpace); 260 pane2 = new JPanel(); 261 pane2.setLayout(new WrapLayout()); 262 add(pane2); 263 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesByteCount"))); 264 pane2.add(configNumberField); 265 b = new JButton(Bundle.getMessage("ConfigMessagesRead")); 266 b.addActionListener(this::readPerformed); 267 pane2.add(b); 268 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesData"))); 269 pane2.add(readDataField); 270 271 pane2 = new JPanel(); 272 pane2.setLayout(new WrapLayout()); 273 add(pane2); 274 b = new JButton(Bundle.getMessage("ConfigMessagesWrite")); 275 b.addActionListener(this::writePerformed); 276 pane2.add(b); 277 pane2.add(new JLabel(Bundle.getMessage("ConfigMessagesData"))); 278 writeDataField.setText("00 00"); // NOI18N 279 pane2.add(writeDataField); 280 281 pane2 = new JPanel(); 282 pane2.setLayout(new WrapLayout()); 283 add(pane2); 284 285 var restartButton = new JButton(Bundle.getMessage("ConfigMessagesRestart")); 286 pane2.add(restartButton); 287 restartButton.addActionListener(this::restartNode); 288 289 cdiButton = new JButton(Bundle.getMessage("ConfigMessagesOpenCDI")); 290 pane2.add(cdiButton); 291 cdiButton.addActionListener(e -> openCdiPane()); 292 cdiButton.setToolTipText(Bundle.getMessage("ConfigMessagesOpenCDItt")); 293 setCdiButton(); // get initial state 294 295 var clearCacheButton = new JButton(Bundle.getMessage("ConfigMessagesClearCDI")); 296 pane2.add(clearCacheButton); 297 clearCacheButton.addActionListener(this::clearCache); 298 clearCacheButton.setToolTipText(Bundle.getMessage("ConfigMessagesClearCDItt")); 299 300 // listen for mimic store changes to set CDI button 301 store.addPropertyChangeListener(e -> { 302 setCdiButton(); 303 }); 304 jmri.util.ThreadingUtil.runOnGUIDelayed( ()->{ 305 setCdiButton(); 306 }, 500); 307 } 308 309 /** 310 * Set whether Open CDI button is enabled based on whether 311 * the selected node has CDI in its PIP 312 */ 313 protected void setCdiButton() { 314 var nodeID = nodeSelector.getSelectedNodeID(); 315 if (nodeID == null) { 316 cdiButton.setEnabled(false); 317 log.debug("null nodeID disables cdiButton"); 318 return; 319 } 320 var pip = store.getProtocolIdentification(nodeID); 321 if (pip == null || pip.getProtocols() == null) { 322 cdiButton.setEnabled(false); 323 log.debug("null pip info disables cdiButton"); 324 return; 325 } 326 boolean setValue = 327 pip.getProtocols() 328 .contains(org.openlcb.ProtocolIdentification.Protocol.ConfigurationDescription); 329 cdiButton.setEnabled(setValue); 330 log.debug("cdiButton set {} from PIP info", setValue); 331 } 332 333 private JPanel getSendSinglePacketJPanel() { 334 JPanel outer = new JPanel(); 335 outer.setLayout(new BoxLayout(outer, BoxLayout.X_AXIS)); 336 337 JPanel pane1 = new JPanel(); 338 pane1.setLayout(new BoxLayout(pane1, BoxLayout.Y_AXIS)); 339 340 jLabel1.setText(Bundle.getMessage("SinglePacketLabel")); 341 jLabel1.setVisible(true); 342 343 sendButton.setText(Bundle.getMessage("SinglePacketSend")); 344 sendButton.setVisible(true); 345 sendButton.setToolTipText(Bundle.getMessage("SinglePacketSendTt")); 346 347 packetTextField.setToolTipText(Bundle.getMessage("SinglePacketText")); 348 packetTextField.setMaximumSize(packetTextField.getPreferredSize()); 349 350 pane1.add(jLabel1); 351 pane1.add(packetTextField); 352 pane1.add(sendButton); 353 pane1.add(Box.createVerticalGlue()); 354 355 sendButton.addActionListener(this::sendButtonActionPerformed); 356 357 outer.add(Box.createHorizontalGlue()); 358 outer.add(pane1); 359 outer.add(Box.createHorizontalGlue()); 360 return outer; 361 } 362 363 @Override 364 public String getHelpTarget() { 365 return "package.jmri.jmrix.openlcb.swing.send.OpenLcbCanSendFrame"; // NOI18N 366 } 367 368 @Override 369 public String getTitle() { 370 if (memo != null) { 371 return (memo.getUserName() + " " + Bundle.getMessage("Title")); 372 } 373 return Bundle.getMessage("Title"); 374 } 375 376 JComponent addLineLabel(String text) { 377 return addLineLabel(text, null); 378 } 379 380 JComponent addLineLabel(String text, JComponent c) { 381 JLabel lab = new JLabel(text); 382 JPanel p = new JPanel(); 383 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); 384 if (c != null) { 385 p.add(lab, BorderLayout.EAST); 386 if (c instanceof JTextField) { 387 int height = lab.getMinimumSize().height+4; 388 int width = c.getMinimumSize().width; 389 Dimension d = new Dimension(width, height); 390 c.setMaximumSize(d); 391 } 392 p.add(c); 393 } else { 394 p.add(lab, BorderLayout.EAST); 395 } 396 p.add(Box.createHorizontalGlue()); 397 return p; 398 } 399 400 public void sendButtonActionPerformed(java.awt.event.ActionEvent e) { 401 String input = packetTextField.getText(); 402 // TODO check input + feedback on error. Too easy to cause NPE 403 CanMessage m = createPacket(input); 404 log.debug("sendButtonActionPerformed: {}",m); 405 tc.sendCanMessage(m, this); 406 } 407 408 public void sendCimPerformed(java.awt.event.ActionEvent e) { 409 String data = "[10700" + srcAliasField.getText() + "]"; // NOI18N 410 log.debug("sendCimPerformed: |{}|",data); 411 CanMessage m = createPacket(data); 412 log.debug("sendCimPerformed"); 413 tc.sendCanMessage(m, this); 414 } 415 416 NodeID destNodeID() { 417 return nodeSelector.getSelectedNodeID(); 418 } 419 420 EventID eventID() { 421 return new EventID(jmri.util.StringUtil.bytesFromHexString(sendEventField.getText() 422 .replace(".", " "))); 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 final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(OpenLcbCanSendPane.class); 711 712}