001package jmri.jmrix.bidib.swing.mon; 002 003import java.util.List; 004import java.util.LinkedList; 005import java.util.ArrayList; 006import java.util.HashMap; 007import java.util.Map; 008import javax.swing.BoxLayout; 009import javax.swing.JCheckBox; 010import javax.swing.JPanel; 011import jmri.InstanceManager; 012import jmri.UserPreferencesManager; 013import jmri.jmrix.bidib.BiDiBSystemConnectionMemo; 014import jmri.jmrix.bidib.BiDiBTrafficController; 015import jmri.jmrix.bidib.swing.BiDiBPanelInterface; 016import org.bidib.jbidibc.messages.AddressData; 017 018import org.bidib.jbidibc.messages.CRC8; 019import org.bidib.jbidibc.messages.BidibLibrary; //new 020import org.bidib.jbidibc.messages.exception.ProtocolException; //new 021import org.bidib.jbidibc.messages.utils.ByteUtils; //new 022import org.bidib.jbidibc.messages.utils.NodeUtils; 023import org.bidib.jbidibc.messages.base.RawMessageListener; 024import org.bidib.jbidibc.messages.Node; 025import org.bidib.jbidibc.messages.Feature; 026import org.bidib.jbidibc.messages.StringData; 027import org.bidib.jbidibc.messages.enums.AddressTypeEnum; 028import org.bidib.jbidibc.messages.enums.CommandStationProgState; 029import org.bidib.jbidibc.messages.enums.CommandStationPt; 030import org.bidib.jbidibc.messages.enums.LcOutputType; 031import org.bidib.jbidibc.messages.enums.PortModelEnum; 032import org.bidib.jbidibc.messages.message.*; 033 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037/** 038 * Swing action to create and register a MonFrame object. 039 * 040 * @author Bob Jacobsen Copyright (C) 2001, 2008 041 * @author Matthew Harris Copyright (C) 2011 042 * @since 2.11.4 043 * @author Eckart Meyer Copyright (c) 2020-2023 044 */ 045public class BiDiBMonPane extends jmri.jmrix.AbstractMonPane implements BiDiBPanelInterface { 046 047 final java.util.ResourceBundle rb = java.util.ResourceBundle.getBundle("jmri.jmrix.bidib.swing.BiDiBSwingBundle"); // NOI18N 048 049 protected BiDiBTrafficController tc = null; 050 protected BiDiBSystemConnectionMemo memo = null; 051 protected RawMessageListener rawMessageListener = null; 052 private final BidibResponseFactory responseFactory = new BidibResponseFactory(); 053 private String output; 054 private final Map<Long, String> debugStringBuffer = new HashMap<>(); 055 056 private final UserPreferencesManager pm; 057 final JCheckBox suppressDiagMessagesCheckBox = new JCheckBox(); 058 final String suppressDiagMessagesCheck = this.getClass().getName() + ".SuppressDiagMessages"; 059 060 public BiDiBMonPane() { 061 super(); 062 pm = InstanceManager.getDefault(UserPreferencesManager.class); 063 } 064 065// @Override 066// public String getHelpTarget() { 067// // TODO: BiDiB specific help - if we need this 068// return "package.jmri.jmrix.bidib.MonFrame"; // NOI18N 069// } 070 071 @Override 072 public String getTitle() { 073 return (rb.getString("BiDiBMonPaneTitle")); // NOI18N 074 } 075 076 @Override 077 public void dispose() { 078 log.debug("Stopping BiDiB Monitor Panel"); 079 if (rawMessageListener != null) { 080 tc.removeRawMessageListener(rawMessageListener); 081 rawMessageListener = null; 082 } 083 pm.setSimplePreferenceState(suppressDiagMessagesCheck, suppressDiagMessagesCheckBox.isSelected()); 084 super.dispose(); 085 } 086 087 @Override 088 public void init() { 089 } 090 091 @Override 092 protected void addCustomControlPanes(JPanel parent) { 093 094 JPanel p = new JPanel(); 095 p.setLayout(new BoxLayout(p, BoxLayout.X_AXIS)); 096 097 suppressDiagMessagesCheckBox.setText(rb.getString("CheckBoxSuppressDiagMessages")); 098 suppressDiagMessagesCheckBox.setVisible(true); 099 suppressDiagMessagesCheckBox.setSelected(pm.getSimplePreferenceState(suppressDiagMessagesCheck)); 100 p.add(suppressDiagMessagesCheckBox); 101 102 parent.add(p); 103 super.addCustomControlPanes(parent); 104 } 105 106 @Override 107 public void initContext(Object context) { 108 if (context instanceof BiDiBSystemConnectionMemo) { 109 initComponents((BiDiBSystemConnectionMemo) context); 110 } 111 } 112 113 @Override 114 public void initComponents(BiDiBSystemConnectionMemo memo) { 115 log.debug("Starting BiDiB Monitor Panel"); 116 this.memo = memo; 117 tc = memo.getBiDiBTrafficController(); 118 createMonListener(); 119 } 120 121 private boolean suppressMessage(BidibMessageInterface message) { 122 if (suppressDiagMessagesCheckBox.isSelected()) { 123 int type = ByteUtils.getInt(message.getType()); 124 switch (type) { 125 case BidibLibrary.MSG_BOOST_DIAGNOSTIC: 126 case BidibLibrary.MSG_BM_SPEED: 127 case BidibLibrary.MSG_BM_DYN_STATE: 128 case BidibLibrary.MSG_BM_CURRENT: 129 case BidibLibrary.MSG_CS_STATE: 130 case BidibLibrary.MSG_CS_SET_STATE: 131 case BidibLibrary.MSG_LOCAL_PING: 132 case BidibLibrary.MSG_LOCAL_PONG: 133 return true; 134 default: 135 break; 136 } 137 } 138 return false; 139 } 140 141 private void log1Message(BidibMessageInterface message, String line) { 142 Node node = tc.getNodeByAddr(message.getAddr()); 143 if (node != null) { 144 output += String.format(" %010X (%s)", node.getUniqueId() & 0xffffffffffL, node.getStoredString(StringData.INDEX_USERNAME)) + ": "; 145 } 146 else { 147 output += NodeUtils.formatAddress(message.getAddr()) + ": "; 148 } 149 if (rawCheckBox.isSelected()) { 150 output += "[" + ByteUtils.bytesToHex(message.getContent()) + "] " + message.toString() + " "; 151 } 152 output += line + "\n"; 153 154 } 155 protected void logMessage(String prefix, byte[] data, List<BidibMessageInterface> messages, List<String> lines) { 156 output = prefix + " "; 157 if (messages.size() != 1) { 158 if (rawCheckBox.isSelected()) { 159 output += "[" + ByteUtils.bytesToHex(data) + "] "; 160 } 161 output += messages.size() + " Messages:\n"; 162 } 163 if (messages.size() == 1) { 164 log.debug("Monitor: show message: {}", ((BidibMessage)messages.get(0)).getName()); 165 if (suppressMessage(messages.get(0))) { 166 return; 167 } 168 log1Message(messages.get(0), lines.get(0)); 169 } 170 else { 171 for (int i = 0; i < messages.size(); i++) { 172 output += " "; 173 log1Message(messages.get(i), lines.get(i)); 174 } 175 } 176 nextLine(output, null); 177 } 178 179 private String evaluateMessage(final BidibMessageInterface message) { 180 String line = ""; 181 Node node = tc.getNodeByAddr(message.getAddr()); 182 PortModelEnum portModel = PortModelEnum.type; 183 if (node != null) { 184 portModel = tc.getPortModel(node); 185 } 186 int type = ByteUtils.getInt(message.getType()); 187 switch (type) { 188 // received messages 189 case BidibLibrary.MSG_ACCESSORY_STATE: 190 { 191 AccessoryStateResponse m = (AccessoryStateResponse)message; 192 if (m.getAccessoryState().getExecute() == 0) { 193 line = "accessory number: " + m.getAccessoryState().getAccessoryNumber() + ", aspect: " + m.getAccessoryState().getActiveAspect(); 194 } 195 else { 196 line += m.getAccessoryState().toString(); 197 } 198 } 199 break; 200 case BidibLibrary.MSG_BOOST_DIAGNOSTIC: 201 { 202 BoostDiagnosticResponse m = (BoostDiagnosticResponse)message; 203 line = "Voltage: " + m.getVoltage() + " mV, Current: " + m.getCurrent() + " mA, Temperature: " + m.getTemperature() + " °C"; 204 } 205 break; 206 case BidibLibrary.MSG_BOOST_STAT: 207 { 208 BoostStatResponse m = (BoostStatResponse)message; 209 line = "Booster State " + m.getState() + ", control: " + m.getControl(); 210 } 211 break; 212 case BidibLibrary.MSG_BM_ADDRESS: 213 { 214 FeedbackAddressResponse m = (FeedbackAddressResponse)message; 215 line = "mnum: " + m.getDetectorNumber(); 216 line += ", locos: "; 217 List<AddressData> addrList = m.getAddresses(); 218 if (addrList.size() > 0) { 219 for (AddressData addressData : addrList) { 220 //line += String.format("0x%d ", addressData.getAddress() & 0xff); 221 line += addressData + " "; 222 } 223 } 224 } 225 break; 226 case BidibLibrary.MSG_BM_CURRENT: 227 { 228 FeedbackCurrentResponse m = (FeedbackCurrentResponse)message; 229 line = "mnum: " + m.getLocalDetectorAddress() + "current: " + m.getCurrent() + " mA"; 230 } 231 break; 232 case BidibLibrary.MSG_BM_DYN_STATE: 233 { 234 FeedbackDynStateResponse m = (FeedbackDynStateResponse)message; 235 line = "mnum: " + m.getDetectorNumber() + ", decoder: " + m.getAddress() + " "; 236 int dynNumber = m.getDynNumber(); 237 String dynText; 238 switch (dynNumber) { 239 case 1: 240 dynText = rb.getString("BmDynState1"); // NOI18N 241 line += dynText + ": " + m.getDynValue() + "%"; 242 break; 243 case 2: 244 dynText = rb.getString("BmDynState2"); // NOI18N 245 line += dynText + ": " + m.getDynValue() + " °C"; 246 break; 247 case 3: 248 dynText = rb.getString("BmDynState3"); // NOI18N 249 line += dynText + ": " + m.getDynValue() + "%"; 250 break; 251 case 4: 252 dynText = rb.getString("BmDynState4"); // NOI18N 253 line += dynText + ": " + m.getDynValue() + "%"; 254 break; 255 case 5: 256 dynText = rb.getString("BmDynState5"); // NOI18N 257 line += dynText + ": " + m.getDynValue() + "%"; 258 break; 259 case 6: 260 dynText = rb.getString("BmDynState6"); // NOI18N 261 line += dynText + ": " + m.getDynValue() + " mm"; 262 if (m.getTimestamp() != null) { 263 dynText = rb.getString("BmDynStateTimeStamp"); // NOI18N 264 line += ", " + dynText + ": " + m.getTimestamp(); 265 } 266 break; 267 default: 268 log.error("Unexpected case: {}", dynNumber); 269 } 270 } 271 break; 272 case BidibLibrary.MSG_BM_FREE: 273 { 274 FeedbackFreeResponse m = (FeedbackFreeResponse)message; 275 line = "mnum: " + m.getDetectorNumber(); 276 } 277 break; 278 case BidibLibrary.MSG_BM_OCC: 279 { 280 FeedbackOccupiedResponse m = (FeedbackOccupiedResponse)message; 281 line = "mnum: " + m.getDetectorNumber(); 282 } 283 break; 284 case BidibLibrary.MSG_BM_MULTIPLE: 285 { 286 FeedbackMultipleResponse m = (FeedbackMultipleResponse)message; 287 line = "mnum: " + m.getBaseAddress() + ", size: " + m.getSize(); 288 line += ", state bits: "; 289 byte[] stateBits = m.getDetectorData(); 290 if (stateBits.length > 0) { 291 for (int f : stateBits) { 292 line += String.format("0x%02X ", f & 0xff); 293 } 294 } 295 } 296 break; 297 case BidibLibrary.MSG_BM_SPEED: 298 { 299 FeedbackSpeedResponse m = (FeedbackSpeedResponse)message; 300 AddressData addressData = m.getAddress(); 301 line = "Decoder: " + addressData + ", speed: " + m.getSpeed(); 302 } 303 break; 304 case BidibLibrary.MSG_BM_CV: 305 { 306 FeedbackCvResponse m = (FeedbackCvResponse)message; 307 line = m.getAddress().toString() + ", CV" + m.getCvNumber() + " = " + m.getDat(); 308 } 309 break; 310 case BidibLibrary.MSG_CS_DRIVE_STATE: 311 { 312 CommandStationDriveStateResponse m = (CommandStationDriveStateResponse)message; 313 AddressTypeEnum addressTypeEnum = AddressTypeEnum.LOCOMOTIVE_BACKWARD; 314 if ((m.getSpeed() & 0x80) == 0x80) { 315 addressTypeEnum = AddressTypeEnum.LOCOMOTIVE_FORWARD; 316 } 317 AddressData addressData = new AddressData(m.getDecoderAddress(), addressTypeEnum); 318 line = "Decoder: " + addressData + ", speed: " + (m.getSpeed() & 0x7F); 319 line += ", function bits: "; 320// line += String.format("0x%02X ", m.getFunctionBitsF0toF4()); 321 byte[] functionBits = m.getDriveState().getFunctions(); 322 if (functionBits.length > 0) { 323 for (int f : functionBits) { 324 line += String.format("0x%02X ", f & 0xff); 325 } 326 } 327 } 328 break; 329 case BidibLibrary.MSG_CS_DRIVE_MANUAL: 330 { 331 CommandStationDriveManualResponse m = (CommandStationDriveManualResponse)message; 332 AddressTypeEnum addressTypeEnum = AddressTypeEnum.LOCOMOTIVE_BACKWARD; 333 if ((m.getSpeed() & 0x80) == 0x80) { 334 addressTypeEnum = AddressTypeEnum.LOCOMOTIVE_FORWARD; 335 } 336 AddressData addressData = new AddressData(m.getAddress(), addressTypeEnum); 337 line = "Decoder: " + addressData + ", speed: " + (m.getSpeed() & 0x7F); 338 line += ", function bits: "; 339// line += String.format("0x%02X ", m.getFunctionBitsF0toF4()); 340 byte[] functionBits = m.getDriveState().getFunctions(); 341 if (functionBits.length > 0) { 342 for (int f : functionBits) { 343 line += String.format("0x%02X ", f & 0xff); 344 } 345 } 346 } 347 break; 348 case BidibLibrary.MSG_CS_STATE: 349 { 350 CommandStationStateResponse m = (CommandStationStateResponse)message; 351 line = "CS state " + m.getState(); 352 } 353 break; 354 case BidibLibrary.MSG_CS_POM_ACK: 355 { 356 CommandStationPomAcknowledgeResponse m = (CommandStationPomAcknowledgeResponse)message; 357 line = "Addr: " + m.getAddress().toString() + ", Ack: " + m.getAcknState().toString(); 358 } 359 break; 360 case BidibLibrary.MSG_CS_PROG_STATE: 361 { 362 CommandStationProgStateResponse m = (CommandStationProgStateResponse)message; 363 line = m.getState() + " CV" + (m.getCvNumber()); 364 if (m.getState() == CommandStationProgState.PROG_OKAY) { 365 line += " = " + m.getCvData(); 366 } 367 line += ", remaining time: " + (m.getRemainingTime() * 100) + "ms"; 368 } 369 break; 370 case BidibLibrary.MSG_LC_STAT: 371 { 372 LcStatResponse m = (LcStatResponse)message; 373 line = "port " + m.getPortNumber(portModel) + " (" + makePortTypeString(portModel, m.getPortType(portModel)) + "), state: " + (m.getPortStatus()& 0xFF); 374 } 375 break; 376 case BidibLibrary.MSG_LC_NA: 377 { 378 LcNotAvailableResponse m = (LcNotAvailableResponse)message; 379 line = "port " + m.getPortNumber(portModel) + " (" + makePortTypeString(portModel, m.getPortType(portModel)) + "), error code: " + (m.getErrorCode()); 380 } 381 break; 382 case BidibLibrary.MSG_NODETAB_COUNT: 383 { 384 NodeTabCountResponse m = (NodeTabCountResponse)message; 385 line = "count: " + m.getCount(); 386 } 387 break; 388 case BidibLibrary.MSG_FEATURE_COUNT: 389 { 390 FeatureCountResponse m = (FeatureCountResponse)message; 391 line = "count: " + m.getCount(); 392 } 393 break; 394 case BidibLibrary.MSG_FEATURE: 395 { 396 FeatureResponse m = (FeatureResponse)message; 397 Feature f = m.getFeature(); 398 line = f.getFeatureName() + " (" + f.getType() + ") = " + f.getValue(); 399 } 400 break; 401 case BidibLibrary.MSG_STRING: 402 { 403 StringResponse m = (StringResponse)message; 404 // handle debug messages from a node 405 if (m.getStringData().getNamespace() == StringData.NAMESPACE_DEBUG) { 406 String prefix = "===== device"; 407 int stringId = m.getStringData().getIndex(); 408 String value = m.getStringData().getValue(); 409 if (node == null) { 410 log.error("Found node null in MSG_STRING"); 411 break; 412 } 413 long key = (node.getUniqueId() & 0x0000ffffffffffL) | (long)stringId << 40; 414 if (value.charAt(value.length() - 1) == '\n') { 415 String txt = ""; 416 // check if we have previous received imcomplete text 417 if (debugStringBuffer.containsKey(key)) { 418 txt = debugStringBuffer.get(key); 419 debugStringBuffer.remove(key); 420 } 421 txt += value.replace("\n",""); 422 String line2 = ""; 423 switch(stringId) { 424 case StringData.INDEX_DEBUG_STDOUT: 425 line2 += prefix + " stdout: " + txt; 426 break; 427 case StringData.INDEX_DEBUG_STDERR: 428 line2 += prefix + " stderr: " + txt; 429 break; 430 case StringData.INDEX_DEBUG_WARN: 431 if (log.isWarnEnabled()) { 432 line2 += prefix + " WARN: " + txt; 433 } 434 break; 435 case StringData.INDEX_DEBUG_INFO: 436 if (log.isInfoEnabled()) { 437 line2 += prefix + " INFO: " + txt; 438 } 439 break; 440 case StringData.INDEX_DEBUG_DEBUG: 441 if (log.isDebugEnabled()) { 442 line2 += prefix + " DEBUG: " + txt; 443 } 444 break; 445 case StringData.INDEX_DEBUG_TRACE: 446 if (log.isTraceEnabled()) { 447 line2 += prefix + " TRACE: " + txt; 448 } 449 break; 450 default: break; 451 } 452 if (!line2.isEmpty()) { 453 line = line2; 454 } 455 } 456 else { 457 String txt = ""; 458 if (debugStringBuffer.containsKey(key)) { 459 txt = debugStringBuffer.get(key); 460 } 461 debugStringBuffer.put(key, (txt + value)); 462 } 463 } 464 else { 465 if (m.getStringData().getIndex() == 0) { 466 line = "Product Name: " + m.getStringData().getValue(); 467 } 468 else if (m.getStringData().getIndex() == 1) { 469 line = "Username: " + m.getStringData().getValue(); 470 } 471 else { 472 line = "index: " + m.getStringData().getIndex() + ", value: " + m.getStringData().getValue(); 473 } 474 } 475 } 476 break; 477 478 479 // messages to send 480 case BidibLibrary.MSG_ACCESSORY_GET: 481 { 482 AccessoryGetMessage m = (AccessoryGetMessage)message; 483 line = "accessory number: " + m.getAccessoryNumber(); 484 } 485 break; 486 case BidibLibrary.MSG_ACCESSORY_SET: 487 { 488 AccessorySetMessage m = (AccessorySetMessage)message; 489 line = "accessory number: " + m.getAccessoryNumber() + ", set aspect to " + m.getAspect(); 490 } 491 break; 492 case BidibLibrary.MSG_CS_ACCESSORY: 493 { 494 CommandStationAccessoryMessage m = (CommandStationAccessoryMessage)message; 495 line = "CS accessory decoder address: " + m.getDecoderAddress() + ", set aspect to " + m.getAspect(); 496 } 497 break; 498 case BidibLibrary.MSG_CS_DRIVE: 499 { 500 CommandStationDriveMessage m = (CommandStationDriveMessage)message; 501 line = "CS decoder address: " + m.getDecoderAddress() + ", speed: " + m.getSpeed(); 502 line += ", function bits: "; 503 //line += String.format("0x%02X ", m.getFunctionBitsF0toF4()); 504 int[] functionBits = m.getFunctionBits(); 505 if (functionBits.length > 0) { 506 for (int f : functionBits) { 507 line += String.format("0x%02X ", f & 0xff); 508 } 509 } 510 } 511 break; 512 case BidibLibrary.MSG_CS_SET_STATE: 513 { 514 CommandStationSetStateMessage m = (CommandStationSetStateMessage)message; 515 line = "CS set state to " + m.getState(); 516 } 517 break; 518 case BidibLibrary.MSG_CS_POM: 519 { 520 CommandStationPomMessage m = (CommandStationPomMessage)message; 521 line = "OpCode " + ByteUtils.byteToHex(m.getOpCode()) + ", Addr: " + m.getDecoderAddress().toString() + ", CV" + m.getCvNumber(); 522 int op = m.getOpCode(); 523 if (op != 0x00 && op != 0x01 && op != 0x81) { 524 line += " = " + ByteUtils.getCvXValue(m.getData(), 9, m.getData().length - 9); 525 } 526 } 527 break; 528 case BidibLibrary.MSG_CS_PROG: 529 { 530 CommandStationProgMessage m = (CommandStationProgMessage)message; 531 line = m.getOpCode() + " CV" + (m.getCvNumber()); 532 if (m.getOpCode() == CommandStationPt.BIDIB_CS_PROG_RDWR_BIT || m.getOpCode() == CommandStationPt.BIDIB_CS_PROG_WR_BYTE) { 533 line += " = " + m.getCvData(); 534 } 535 } 536 break; 537 case BidibLibrary.MSG_BM_ADDR_GET_RANGE: 538 { 539 FeedbackGetAddressRangeMessage m = (FeedbackGetAddressRangeMessage)message; 540 line = "get feedback status from number " + m.getBegin() + " to " + m.getEnd(); 541 } 542 break; 543 case BidibLibrary.MSG_LC_CONFIG_GET: 544 { 545 LcConfigGetMessage m = (LcConfigGetMessage)message; 546 line = "get port config for port " + m.toString(); 547 } 548 break; 549 case BidibLibrary.MSG_LC_OUTPUT: 550 { 551 LcOutputMessage m = (LcOutputMessage)message; 552 line = "output to port " + m.getOutputNumber(portModel) + " (" + makePortTypeString(portModel, m.getOutputType(portModel)) + "), state: " + (m.getOutputStatus() & 0xFF); 553 } 554 break; 555 556 // - those messages either won't be used at all in JMRI or we just have not done it...: 557 // received messages 558 case BidibLibrary.MSG_BM_CONFIDENCE: 559 case BidibLibrary.MSG_BM_POSITION: 560 case BidibLibrary.MSG_BM_ACCESSORY: //what is this?? 561 case BidibLibrary.MSG_BM_XPOM: 562 case BidibLibrary.MSG_BM_RCPLUS: 563 case BidibLibrary.MSG_ACCESSORY_NOTIFY: 564 case BidibLibrary.MSG_ACCESSORY_PARA: 565 case BidibLibrary.MSG_LC_KEY: 566 case BidibLibrary.MSG_LC_WAIT: 567 case BidibLibrary.MSG_LC_CONFIG: 568 case BidibLibrary.MSG_LC_CONFIGX: 569 case BidibLibrary.MSG_LC_MACRO_PARA: 570 case BidibLibrary.MSG_LC_MACRO: 571 case BidibLibrary.MSG_LC_MACRO_STATE: 572 case BidibLibrary.MSG_STALL: 573 case BidibLibrary.MSG_NODE_NEW: 574 case BidibLibrary.MSG_NODE_LOST: 575 case BidibLibrary.MSG_NODE_NA: 576 case BidibLibrary.MSG_NODETAB: 577 case BidibLibrary.MSG_SYS_ERROR: 578 case BidibLibrary.MSG_SYS_IDENTIFY_STATE: 579 case BidibLibrary.MSG_SYS_PONG: 580 case BidibLibrary.MSG_SYS_MAGIC: 581 case BidibLibrary.MSG_SYS_P_VERSION: 582 case BidibLibrary.MSG_SYS_SW_VERSION: 583 case BidibLibrary.MSG_SYS_UNIQUE_ID: 584 case BidibLibrary.MSG_CS_DRIVE_ACK: 585 case BidibLibrary.MSG_CS_DRIVE_EVENT: 586 case BidibLibrary.MSG_CS_ACCESSORY_ACK: 587 case BidibLibrary.MSG_CS_ACCESSORY_MANUAL: 588 case BidibLibrary.MSG_CS_RCPLUS_ACK: 589 case BidibLibrary.MSG_CS_M4_ACK: 590 case BidibLibrary.MSG_VENDOR_ACK: 591 case BidibLibrary.MSG_VENDOR: 592 case BidibLibrary.MSG_LOCAL_PONG: 593 case BidibLibrary.MSG_LOCAL_BIDIB_UP: 594 case BidibLibrary.MSG_FEATURE_NA: 595 case BidibLibrary.MSG_FW_UPDATE_STAT: 596 case BidibLibrary.MSG_LOGON: 597 // messages to send 598 case BidibLibrary.MSG_ACCESSORY_PARA_GET: 599 case BidibLibrary.MSG_ACCESSORY_PARA_SET: 600 case BidibLibrary.MSG_BOOST_OFF: 601 case BidibLibrary.MSG_BOOST_ON: 602 case BidibLibrary.MSG_BOOST_QUERY: 603 case BidibLibrary.MSG_CS_BIN_STATE: 604 case BidibLibrary.MSG_CS_M4: 605 case BidibLibrary.MSG_CS_QUERY: 606 case BidibLibrary.MSG_CS_RCPLUS: 607 case BidibLibrary.MSG_FEATURE_GETALL: 608 case BidibLibrary.MSG_FEATURE_GET: 609 case BidibLibrary.MSG_FEATURE_GETNEXT: 610 case BidibLibrary.MSG_FEATURE_SET: 611 case BidibLibrary.MSG_BM_GET_CONFIDENCE: 612 case BidibLibrary.MSG_BM_GET_RANGE: 613 case BidibLibrary.MSG_BM_MIRROR_FREE: 614 case BidibLibrary.MSG_BM_MIRROR_MULTIPLE: 615 case BidibLibrary.MSG_BM_MIRROR_OCC: 616 case BidibLibrary.MSG_BM_MIRROR_POSITION: 617 case BidibLibrary.MSG_FW_UPDATE_OP: 618 case BidibLibrary.MSG_LC_CONFIG_SET: 619 case BidibLibrary.MSG_LC_CONFIGX_GET_ALL: 620 case BidibLibrary.MSG_LC_CONFIGX_GET: 621 case BidibLibrary.MSG_LC_CONFIGX_SET: 622 case BidibLibrary.MSG_LC_KEY_QUERY: 623 case BidibLibrary.MSG_LC_MACRO_GET: 624 case BidibLibrary.MSG_LC_MACRO_HANDLE: 625 case BidibLibrary.MSG_LC_MACRO_PARA_GET: 626 case BidibLibrary.MSG_LC_MACRO_PARA_SET: 627 case BidibLibrary.MSG_LC_MACRO_SET: 628 case BidibLibrary.MSG_LC_PORT_QUERY: 629 case BidibLibrary.MSG_LC_PORT_QUERY_ALL: 630 case BidibLibrary.MSG_LOCAL_BIDIB_DOWN: 631 case BidibLibrary.MSG_LOCAL_EMITTER: 632 case BidibLibrary.MSG_LOCAL_PING: 633 case BidibLibrary.MSG_NODE_CHANGED_ACK: 634 case BidibLibrary.MSG_NODETAB_GETALL: 635 case BidibLibrary.MSG_NODETAB_GETNEXT: 636 case BidibLibrary.MSG_STRING_GET: 637 case BidibLibrary.MSG_STRING_SET: 638 case BidibLibrary.MSG_SYS_CLOCK: 639 case BidibLibrary.MSG_SYS_DISABLE: 640 case BidibLibrary.MSG_SYS_ENABLE: 641 case BidibLibrary.MSG_SYS_GET_ERROR: 642 case BidibLibrary.MSG_SYS_GET_P_VERSION: 643 case BidibLibrary.MSG_SYS_GET_SW_VERSION: 644 case BidibLibrary.MSG_SYS_GET_UNIQUE_ID: 645 case BidibLibrary.MSG_SYS_IDENTIFY: 646 case BidibLibrary.MSG_SYS_GET_MAGIC: 647 case BidibLibrary.MSG_SYS_PING: 648 case BidibLibrary.MSG_SYS_RESET: 649 case BidibLibrary.MSG_VENDOR_DISABLE: 650 case BidibLibrary.MSG_VENDOR_ENABLE: 651 case BidibLibrary.MSG_VENDOR_GET: 652 case BidibLibrary.MSG_VENDOR_SET: 653 default: 654 break; 655 } 656 BidibMessage m = (BidibMessage)message; 657 if (type != BidibLibrary.MSG_STRING || !line.isEmpty()) { 658 return (line.isEmpty() ? m.getName() : m.getName() + ": " + line); 659 } 660 else { 661 return ""; 662 } 663 } 664 665 private String makePortModelString(PortModelEnum portModel) { 666 String portModelName = "unknown"; 667 switch (portModel) { 668 case type: 669 portModelName = "type-based"; 670 break; 671 case flat: 672 portModelName = "flat"; 673 break; 674 case flat_extended: 675 portModelName = "flat-extended"; 676 break; 677 default: 678 break; 679 } 680 return portModelName; 681 } 682 683 private String makePortTypeString(PortModelEnum portModel, LcOutputType portType) { 684 String ret = makePortModelString(portModel); 685 if (portModel == PortModelEnum.type) { 686 ret += ", " + portType; 687 } 688 return ret; 689 } 690 691 private List<BidibMessageInterface> splitBidibMessages(byte[] data, boolean checkCRC) throws ProtocolException { 692 log.trace("splitMessages: {}", ByteUtils.bytesToHex(data)); 693 int index = 0; 694 List<BidibMessageInterface> result = new LinkedList<>(); 695 696 while (index < data.length) { 697 int size = ByteUtils.getInt(data[index]) + 1 /* len */; 698 log.trace("Current size: {}", size); 699 700 if (size <= 0) { 701 throw new ProtocolException("cannot split messages, array size is " + size); 702 } 703 704 byte[] message = new byte[size]; 705 706 try { 707 System.arraycopy(data, index, message, 0, message.length); 708 } 709 catch (ArrayIndexOutOfBoundsException ex) { 710 log 711 .warn("Failed to copy, msg.len: {}, size: {}, output.len: {}, index: {}, output: {}", 712 message.length, size, data.length, index, ByteUtils.bytesToHex(data)); 713 throw new ProtocolException("Copy message data to buffer failed."); 714 } 715 result.add(responseFactory.create(message)); 716 index += size; 717 718 if (checkCRC) { 719 // CRC 720 if (index == data.length - 1) { 721 int crc = 0; 722 int crcIndex = 0; 723 for (crcIndex = 0; crcIndex < data.length - 1; crcIndex++) { 724 crc = CRC8.getCrcValue((data[crcIndex] ^ crc) & 0xFF); 725 } 726 if (crc != (data[crcIndex] & 0xFF)) { 727 throw new ProtocolException( 728 "CRC failed: should be " + crc + " but was " + (data[crcIndex] & 0xFF)); 729 } 730 break; 731 } 732 } 733 } 734 735 return result; 736 737 } 738 739 private void createMonListener() { 740 rawMessageListener = new RawMessageListener() { 741 @Override 742 public void notifyReceived(byte[] data) { 743 log.debug("MON received message"); 744 List<String> lines = new ArrayList<>(); 745 List<BidibMessageInterface> messages = new ArrayList<>(); 746 try { 747// Collection<byte[]> messagesData = MessageUtils.splitBidibMessages(data, true); 748// 749// //log.debug("MON: Number of splited messages: {}", messagesData.size()); 750// 751// for (byte[] messageArray : messagesData) { 752// BidibMessageInterface message; 753// try { 754// message = responseFactory.create(messageArray); 755// messages.add(message); 756// String line = evaluateMessage(message); 757// lines.add(line); 758// } 759// catch (ProtocolException ex) { 760// log.error("Illegal BiDiB Message received: {} {}", messageArray, ex); 761// } 762 List<BidibMessageInterface> commandMessages = splitBidibMessages(data, true); 763 for (BidibMessageInterface message : commandMessages) { 764 String line = evaluateMessage(message); 765 //log.debug("**line: \"{}\", isEmpty: {}", line, line.isEmpty()); 766 if (!line.isEmpty()) { 767 messages.add(message); 768 lines.add(line); 769 } 770 } 771 if (messages.size() > 0) { 772 logMessage("<<", data, messages, lines); 773 } 774 } 775 catch (ProtocolException ex) { 776 log.warn("CRC failed.", ex); 777 } 778 } 779 780 @Override 781 public void notifySend(byte[] data) { 782 log.debug("MON sending message"); 783 List<String> lines = new ArrayList<>(); 784 List<BidibMessageInterface> messages = new ArrayList<>(); 785 BidibRequestFactory requestFactory = tc.getBidib().getRootNode().getRequestFactory(); 786 // Note: netBiDiB does NOT use the escape sequence. We must tell the parser not to use them 787 // otherwise a byte could be misinterpreted as an escape character and the parser will fail. 788 requestFactory.setEscapeMagic(!tc.isNetBiDiB()); 789 try { 790 List<BidibMessageInterface> commandMessages = requestFactory.create(data); 791 for (BidibMessageInterface message : commandMessages) { 792 messages.add(message); 793 String line = evaluateMessage(message); 794 lines.add(line); 795 } 796 logMessage(">>", data, messages, lines); 797 } 798 catch (ProtocolException ex) { 799 log.error("Illegal BiDiB Message to send: {}", data, ex); 800 } 801 } 802 }; 803 tc.addRawMessageListener(rawMessageListener); 804 } 805 806 807 /** 808 * Nested class to create one of these using old-style defaults. 809 */ 810// static public class Default extends BiDiBNamedPaneAction { 811// 812// public Default() { 813// super(Bundle.getMessage("MonitorXTitle", "RFID Device"), 814// new JmriJFrameInterface(), 815// BiDiBMonPane.class.getName(), 816// InstanceManager.getDefault(BiDiBSystemConnectionMemo.class)); 817// } 818// } 819 820 private final static Logger log = LoggerFactory.getLogger(BiDiBMonPane.class); 821 822}