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