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