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