001package jmri.jmrix.loconet.duplexgroup.swing; 002 003import javax.annotation.CheckForNull; 004import jmri.jmrix.loconet.LnConstants; 005import jmri.jmrix.loconet.LocoNetMessage; 006import jmri.jmrix.loconet.LocoNetSystemConnectionMemo; 007import jmri.jmrix.loconet.duplexgroup.LnDplxGrpInfoImplConstants; 008 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012/** 013 * Implements a class to handle message creation and message interpretation of 014 * LocoNet messages associated with IPL. IPL is a mechanism which allows 015 * identification and firmware programming of some types of Digitrax hardware. 016 * 017 * @author B. Milhaupt Copyright 2010, 2011, 2018 018 */ 019public class LnIPLImplementation extends javax.swing.JComponent implements jmri.jmrix.loconet.LocoNetListener { 020 021 /** 022 * Constructor for LnIPMImplementation for a given 023 * LocoNetSystemConnectionMemo as provided by the instantiating 024 * method. 025 * 026 * @param lnMemo LocoNetSystemConnectionMemo for the LocoNet communication 027 * interface 028 */ 029 public LnIPLImplementation(LocoNetSystemConnectionMemo lnMemo) { 030 super(); 031 thisone = this; 032 memo = lnMemo; 033 034 moreInit(); 035 } 036 037 private void moreInit() { 038 waitingForIplReply = false; 039 // connect to the LnTrafficController 040 connect(memo.getLnTrafficController()); 041 042 swingTmrIplQuery = new javax.swing.Timer(LnDplxGrpInfoImplConstants.IPL_QUERY_DELAY, new java.awt.event.ActionListener() { 043 @Override 044 public void actionPerformed(java.awt.event.ActionEvent e) { 045 swingTmrIplQuery.stop(); 046 waitingForIplReply = false; 047 int oldvalue = 9999; 048 int newvalue = 0; 049 thisone.firePropertyChange("LnIPLEndOfDeviceQuery", oldvalue, newvalue); // NOI18N 050 } 051 }); 052 } 053 054 /** 055 * Create a LocoNet packet which queries UR92(s) for Duplex group 056 * identification information. The invoking method is responsible for 057 * sending the message to LocoNet. 058 * 059 * @return a LocoNetMessage containing the packet required to query UR92 060 * device Duplex Group Identity information 061 */ 062 public static final LocoNetMessage createQueryAllIplDevicesPacket() { 063 LocoNetMessage m = new LocoNetMessage(LnConstants.RE_IPL_OP_LEN); 064 // fill in data for an IPL Query of UR92s message 065 m.setElement(0, LnConstants.OPC_PEER_XFER); 066 m.setElement(1, LnConstants.RE_IPL_OP_LEN); 067 m.setElement(2, LnConstants.RE_IPL_IDENTITY_OPERATION); 068 m.setElement(3, LnConstants.RE_IPL_OP_QUERY); 069 m.setElement(4, LnConstants.RE_IPL_MFR_ALL); 070 m.setElement(5, LnConstants.RE_IPL_DIGITRAX_HOST_ALL); 071 m.setElement(6, LnConstants.RE_IPL_DIGITRAX_SLAVE_ALL); 072 m.setElement(7, LnConstants.RE_IPL_MFR_ALL); 073 m.setElement(8, LnConstants.RE_IPL_OP_HFW_QUERY); 074 m.setElement(9, LnConstants.RE_IPL_OP_HSNM_QUERY); 075 m.setElement(10, LnConstants.RE_IPL_OP_SFW_QUERY); 076 m.setElement(11, LnConstants.RE_IPL_OP_HSN0_QUERY); 077 m.setElement(12, LnConstants.RE_IPL_OP_HSN1_QUERY); 078 m.setElement(13, LnConstants.RE_IPL_OP_HSN2_QUERY); 079 m.setElement(14, LnConstants.RE_IPL_OP_SSNM_QUERY); 080 m.setElement(15, LnConstants.RE_IPL__OP_SSN0_QUERY); 081 m.setElement(16, LnConstants.RE_IPL_OP_SSN1_QUERY); 082 m.setElement(17, LnConstants.RE_IPL_OP_SSN2_QUERY); 083 m.setElement(18, LnConstants.RE_IPL_OP_SSN3_QUERY); 084 return m; 085 } 086 087 public void sendIplQueryAllDevices() { 088 jmri.jmrix.loconet.LnTrafficController tc = memo.getLnTrafficController(); 089 tc.sendLocoNetMessage(createQueryAllIplDevicesPacket()); 090 waitingForIplReply = true; 091 } 092 093 /** 094 * Create a LocoNet packet which queries IPL devices by specific host 095 * manufacturer and specific host device type. The invoking method is 096 * responsible for sending the message to LocoNet. 097 * <p> 098 * Note: Different devices may only respond to IPL Identity requests if the 099 * host manufacturer and host type are defined. Others devices will respond 100 * when host manufacturer and host type are left as zero. 101 * 102 * @param hostMfr the host manufacturer number 103 * @param hostDevice the host device type number 104 * @return a LocoNetMessage containing the packet required to request IPL 105 * identity information from devices of the specified host 106 * manufacturer and host device type. 107 */ 108 public static final LocoNetMessage createIplSpecificHostQueryPacket( 109 Integer hostMfr, 110 Integer hostDevice) { 111 LocoNetMessage m = createQueryAllIplDevicesPacket(); 112 m.setElement(4, hostMfr & 0x7F); 113 m.setElement(5, hostDevice & 0x7F); 114 return m; 115 } 116 117 /** 118 * Create a LocoNet packet which queries IPL devices by specific slave 119 * manufacturer and specific slave device type. The invoking method is 120 * responsible for sending the message to LocoNet. 121 * <p> 122 * Note: Some devices have no "slave" device and may not respond to this 123 * message. Other devices may only respond if both manufacturer and device 124 * type information is specified for both host and slave. 125 * 126 * @param slaveMfr the slave manufacturer number 127 * @param slaveDevice the slave device type number 128 * @return a LocoNetMessage containing the packet required to request IPL 129 * identity information from devices of the specified slave 130 * manufacturer and slave device type. 131 */ 132 public static final LocoNetMessage createIplSpecificSlaveQueryPacket( 133 Integer slaveMfr, 134 Integer slaveDevice) { 135 LocoNetMessage m = createQueryAllIplDevicesPacket(); 136 m.setElement(7, slaveMfr & 0x7F); 137 m.setElement(6, slaveDevice & 0x7F); 138 return m; 139 } 140 141 /** 142 * Create a LocoNet packet which queries IPL devices by specific host 143 * manufacturer, specific host device type, specific slave manufacturer and 144 * specific slave device type. The invoking method is responsible for 145 * sending the message to LocoNet. 146 * <p> 147 * Note: Different devices respond differently depending on whether host 148 * and/or slave manufacturer and/or device type information are provided. 149 * 150 * @param hostMfr the host manufacturer number 151 * @param hostDevice the host device type number 152 * @param slaveMfr the slave manufacturer number 153 * @param slaveDevice the slave device type number 154 * @return a LocoNetMessage containing the packet required to request IPL 155 * identity information from devices of the specified host and slave 156 * manufacturers and host and slave device types. 157 */ 158 public static final LocoNetMessage createIplSpecificSlaveQueryPacket( 159 Integer hostMfr, 160 Integer hostDevice, 161 Integer slaveMfr, 162 Integer slaveDevice) { 163 LocoNetMessage m = createQueryAllIplDevicesPacket(); 164 m.setElement(4, hostMfr & 0x7F); 165 m.setElement(5, hostDevice & 0x7F); 166 m.setElement(7, slaveMfr & 0x7F); 167 m.setElement(6, slaveDevice & 0x7F); 168 return m; 169 } 170 171 /** 172 * Create a LocoNet packet which queries UR92 devices for IPL 173 * identification information. The invoking method is responsible for 174 * sending the message to LocoNet. 175 * 176 * @return a LocoNetMessage containing the packet required to query UR92 177 * devices for IPL identification information 178 */ 179 public static final LocoNetMessage createIplUr92QueryPacket() { 180 return createIplSpecificHostQueryPacket( 181 LnConstants.RE_IPL_MFR_DIGITRAX, 182 LnConstants.RE_IPL_DIGITRAX_HOST_UR92); 183 } 184 185 /** 186 * Create a LocoNet packet which queries DT402x throttles for IPL 187 * identification information. The invoking method is responsible for 188 * sending the message to LocoNet. 189 * 190 * @return a LocoNetMessage containing the packet required to query DT402x 191 * devices for IPL identification information 192 */ 193 public static final LocoNetMessage createIplDt402QueryPacket() { 194 return createIplSpecificHostQueryPacket( 195 LnConstants.RE_IPL_MFR_DIGITRAX, 196 LnConstants.RE_IPL_DIGITRAX_HOST_DT402); 197 } 198 199 /** 200 * Create a LocoNet packet which queries (some) UT4 throttles for IPL 201 * identification information. The invoking method is responsible for 202 * sending the message to LocoNet. 203 * <p> 204 * Note that UT4 and UT4R devices may not respond to this query. UT4D 205 * devices may respond to this query. 206 * 207 * @return a LocoNetMessage containing the packet required to query (some) 208 * UT4 devices for IPL identification information 209 */ 210 public static final LocoNetMessage createIplUt4QueryPacket() { 211 return createIplSpecificHostQueryPacket( 212 LnConstants.RE_IPL_MFR_DIGITRAX, 213 LnConstants.RE_IPL_DIGITRAX_HOST_UT4); 214 } 215 216 /** 217 * Create a LocoNet packet which queries DCS51 devices for IPL 218 * identification information. The invoking method is responsible for 219 * sending the message to LocoNet. 220 * 221 * @return a LocoNetMessage containing the packet required to query DCS51 222 * devices for IPL identification information 223 */ 224 public static final LocoNetMessage createIplDcs51QueryPacket() { 225 return createIplSpecificHostQueryPacket( 226 LnConstants.RE_IPL_MFR_DIGITRAX, 227 LnConstants.RE_IPL_DIGITRAX_HOST_DCS51); 228 } 229 230 /** 231 * Create a LocoNet packet which queries DCS52 devices for IPL 232 * identification information. The invoking method is responsible for 233 * sending the message to LocoNet. 234 * 235 * @return a LocoNetMessage containing the packet required to query DCS52 236 * devices for IPL identification information 237 */ 238 public static final LocoNetMessage createIplDcs52QueryPacket() { 239 return createIplSpecificHostQueryPacket( 240 LnConstants.RE_IPL_MFR_DIGITRAX, 241 LnConstants.RE_IPL_DIGITRAX_HOST_DCS52); 242 } 243 244 /** 245 * Create a LocoNet packet which queries PR3 devices for IPL identification 246 * information. The invoking method is responsible for sending the message 247 * to LocoNet. 248 * 249 * @return a LocoNetMessage containing the packet required to query PR3 250 * devices for IPL identification information 251 */ 252 public static final LocoNetMessage createIplPr3QueryPacket() { 253 return createIplSpecificHostQueryPacket( 254 LnConstants.RE_IPL_MFR_DIGITRAX, 255 LnConstants.RE_IPL_DIGITRAX_HOST_PR3); 256 } 257 258 /** 259 * Checks message m to determine if it contains a IPL Identity Report 260 * message. 261 * 262 * @param m LocoNetMessage to be checked for an IPL Identity Query message 263 * @return true if message is report of IPL Identity 264 */ 265 public static final boolean isIplIdentityQueryMessage(LocoNetMessage m) { 266 if ((m.getOpCode() == LnConstants.OPC_PEER_XFER) 267 && (m.getElement(1) == LnConstants.RE_IPL_OP_LEN)) { 268 // Message is a peer-to-peer message of appropriate length for 269 // IPL Report message. Check the individual message type 270 if (m.getElement(2) == LnConstants.RE_IPL_IDENTITY_OPERATION) { 271 // To be sure the message is a IPL Identity Report operation, check the 272 // operation type. 273 if (m.getElement(3) == LnConstants.RE_IPL_OP_QUERY) { 274 return true; 275 } 276 } 277 } 278 return false; 279 } 280 281 /** 282 * Checks message m to determine if it contains a IPL Identity Report 283 * message. 284 * 285 * @param m LocoNet message to check for an IPL Identity Report 286 * @return true if message is report of IPL Identity 287 */ 288 public static final boolean isIplIdentityReportMessage(LocoNetMessage m) { 289 if ((m.getOpCode() == LnConstants.OPC_PEER_XFER) 290 && (m.getElement(1) == LnConstants.RE_IPL_OP_LEN)) { 291 // Message is a peer-to-peer message of appropriate length for 292 // IPL Report message. Check the individual message type 293 if (m.getElement(2) == LnConstants.RE_IPL_IDENTITY_OPERATION) { 294 // To be sure the message is a IPL Identity Report operation, check the 295 // operation type. 296 if (m.getElement(3) == LnConstants.RE_IPL_OP_REPORT) { 297 return true; 298 } 299 } 300 } 301 return false; 302 } 303 304 /** 305 * Check message m to determine if it contains an IPL Identity Report 306 * message for a specific host manufacturer and specific host device type. 307 * 308 * @param m message to analyse 309 * @param hostMfr the host manufacturer number 310 * @param hostDevice the host device type number 311 * @return true if message is report of UR92 IPL Identity 312 */ 313 public static final boolean isIplSpecificIdentityReportMessage(LocoNetMessage m, 314 Integer hostMfr, Integer hostDevice) { 315 if (!isIplIdentityReportMessage(m)) { 316 return false; 317 } 318 if ((m.getElement(4) == (hostMfr & 0x7F)) 319 && (m.getElement(5) == (hostDevice & 0x7F))) { 320 return true; 321 } 322 return false; 323 } 324 325 /** 326 * Check message m to determine if it contains a UR92 IPL Identity Report 327 * message. 328 * 329 * @param m message to analyse 330 * @return true if message is report of UR92 IPL Identity 331 */ 332 public static final boolean isIplUr92IdentityReportMessage(LocoNetMessage m) { 333 return isIplSpecificIdentityReportMessage(m, 334 LnConstants.RE_IPL_MFR_DIGITRAX, 335 LnConstants.RE_IPL_DIGITRAX_HOST_UR92); 336 } 337 338 /** 339 * Check message m to determine if it contains a DT402 IPL Identity Report 340 * message. 341 * 342 * @param m message to analyse 343 * @return true if message is report of DT402 IPL Identity 344 */ 345 public static final boolean isIplDt402IdentityReportMessage(LocoNetMessage m) { 346 return isIplSpecificIdentityReportMessage(m, 347 LnConstants.RE_IPL_MFR_DIGITRAX, 348 LnConstants.RE_IPL_DIGITRAX_HOST_DT402); 349 } 350 351 /** 352 * Check message m to determine if it contains a UT4 IPL Identity Report 353 * message. 354 * 355 * @param m message to analyse 356 * @return true if message is report of UT4 IPL Identity 357 */ 358 public static final boolean isIplUt4IdentityReportMessage(LocoNetMessage m) { 359 return isIplSpecificIdentityReportMessage(m, 360 LnConstants.RE_IPL_MFR_DIGITRAX, 361 LnConstants.RE_IPL_DIGITRAX_HOST_UT4); 362 } 363 364 /** 365 * Check message m to determine if it contains a DSC51 IPL Identity Report 366 * message. 367 * 368 * @param m message to analyse 369 * @return true if message is report of DCS51 IPL Identity 370 */ 371 public static final boolean isIplDcs51IdentityReportMessage(LocoNetMessage m) { 372 return isIplSpecificIdentityReportMessage(m, 373 LnConstants.RE_IPL_MFR_DIGITRAX, 374 LnConstants.RE_IPL_DIGITRAX_HOST_DCS51); 375 } 376 377 /** 378 * Check message m to determine if it contains a DSC52 IPL Identity Report 379 * message. 380 * 381 * @param m message to analyse 382 * @return true if message is report of DCS52 IPL Identity 383 */ 384 public static final boolean isIplDcs52IdentityReportMessage(LocoNetMessage m) { 385 return isIplSpecificIdentityReportMessage(m, 386 LnConstants.RE_IPL_MFR_DIGITRAX, 387 LnConstants.RE_IPL_DIGITRAX_HOST_DCS52); 388 } 389 390 /** 391 * Check message m to determine if it contains a UR93 IPL Identity Report 392 * message. 393 * 394 * @param m message to analyse 395 * @return true if message is report of UR92 IPL Identity 396 */ 397 public static final boolean isIplUr93IdentityReportMessage(LocoNetMessage m) { 398 return isIplSpecificIdentityReportMessage(m, 399 LnConstants.RE_IPL_MFR_DIGITRAX, 400 LnConstants.RE_IPL_DIGITRAX_HOST_UR93); 401 } 402 403 /** 404 * Check message m to determine if it contains a PR3 IPL Identity Report 405 * message. 406 * 407 * @param m message to analyse 408 * @return true if message is report of PR3 IPL Identity 409 */ 410 public static final boolean isIplPr3IdentityReportMessage(LocoNetMessage m) { 411 return isIplSpecificIdentityReportMessage(m, 412 LnConstants.RE_IPL_MFR_DIGITRAX, 413 LnConstants.RE_IPL_DIGITRAX_HOST_PR3); 414 } 415 416 public static final boolean isIplDt402DIdentityReportMessage(LocoNetMessage m) { 417 if (!isIplDt402IdentityReportMessage(m)) { 418 return false; 419 } 420 if (!isIplRf24SlaveIdentityReportMessage(m)) { 421 return false; 422 } else { 423 return true; 424 } 425 } 426 427 public static final boolean isIplUt4DIdentityReportMessage(LocoNetMessage m) { 428 if (!isIplUt4IdentityReportMessage(m)) { 429 return false; 430 } 431 if (!isIplRf24SlaveIdentityReportMessage(m)) { 432 return false; 433 } else { 434 return true; 435 } 436 } 437 438 public static final boolean isIplPr4IdentityReportMessage(LocoNetMessage m) { 439 return isIplSpecificIdentityReportMessage(m, 440 LnConstants.RE_IPL_MFR_DIGITRAX, 441 LnConstants.RE_IPL_DIGITRAX_HOST_PR4); 442 } 443 444 public static final boolean isIplBxp88IdentityReportMessage(LocoNetMessage m) { 445 return isIplSpecificIdentityReportMessage(m, 446 LnConstants.RE_IPL_MFR_DIGITRAX, 447 LnConstants.RE_IPL_DIGITRAX_HOST_BXP88); 448 } 449 450 public static final boolean isIplLnwiIdentityReportMessage(LocoNetMessage m) { 451 return isIplSpecificIdentityReportMessage(m, 452 LnConstants.RE_IPL_MFR_DIGITRAX, 453 LnConstants.RE_IPL_DIGITRAX_HOST_LNWI); 454 } 455 456 public static final boolean isIplDcs240IdentityReportMessage(LocoNetMessage m) { 457 return isIplSpecificIdentityReportMessage(m, 458 LnConstants.RE_IPL_MFR_DIGITRAX, 459 LnConstants.RE_IPL_DIGITRAX_HOST_DCS240); 460 } 461 462 public static final boolean isIplDcs210IdentityReportMessage(LocoNetMessage m) { 463 return isIplSpecificIdentityReportMessage(m, 464 LnConstants.RE_IPL_MFR_DIGITRAX, 465 LnConstants.RE_IPL_DIGITRAX_HOST_DCS210); 466 } 467 468 public static final boolean isIplDcs210PlusIdentityReportMessage(LocoNetMessage m) { 469 return isIplSpecificIdentityReportMessage(m, 470 LnConstants.RE_IPL_MFR_DIGITRAX, 471 LnConstants.RE_IPL_DIGITRAX_HOST_DCS210PLUS); 472 } 473 474 public static final boolean isIplDcs240PlusIdentityReportMessage(LocoNetMessage m) { 475 return isIplSpecificIdentityReportMessage(m, 476 LnConstants.RE_IPL_MFR_DIGITRAX, 477 LnConstants.RE_IPL_DIGITRAX_HOST_DCS240PLUS); 478 } 479 480 public static final boolean isIplDt500DIdentityReportMessage(LocoNetMessage m) { 481 if (!isIplDt500IdentityReportMessage(m)) { 482 return false; 483 } 484 if (!isIplRf24SlaveIdentityReportMessage(m)) { 485 return false; 486 } else { 487 return true; 488 } 489 } 490 491 /** 492 * Check message m to determine if it contains a DT500 IPL Identity Report 493 * message. 494 * 495 * @param m message to analyse 496 * @return true if message is report of DT500 IPL Identity 497 */ 498 public static final boolean isIplDt500IdentityReportMessage(LocoNetMessage m) { 499 return isIplSpecificIdentityReportMessage(m, 500 LnConstants.RE_IPL_MFR_DIGITRAX, 501 LnConstants.RE_IPL_DIGITRAX_HOST_DT500); 502 } 503 504 /** 505 * Determine if message is IPL Identity Report with RF24 as slave device. 506 * 507 * @param m message to analyse 508 * @return true if m contains IPL Identity Report with RF24 as slave, else 509 * false 510 */ 511 private static final boolean isIplRf24SlaveIdentityReportMessage(LocoNetMessage m) { 512 if ((extractIplIdentitySlaveManufacturer(m) == LnConstants.RE_IPL_MFR_DIGITRAX) 513 && (extractIplIdentitySlaveDevice(m) == LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24)) { 514 return true; 515 } else { 516 return false; 517 } 518 } 519 520 /** 521 * Extract the IPL Host manufacturer and Device information from m and 522 * return the interpreted information as a String. 523 * 524 * @param m LocoNet Message containg the IPL Identity report 525 * @return String containing the interpreted IPL Host Manufacturer and 526 * Device. If m is not a valid IPL Identity report, returns null. 527 */ 528 public static final String extractInterpretedIplHostDevice(LocoNetMessage m) { 529 if (!isIplIdentityReportMessage(m)) { 530 return null; 531 } 532 if (isIplDt402DIdentityReportMessage(m)) { 533 return interpretHostManufacturerDevice( 534 LnConstants.RE_IPL_MFR_DIGITRAX, 535 LnConstants.RE_IPL_DIGITRAX_HOST_DT402, 536 LnConstants.RE_IPL_MFR_DIGITRAX, 537 LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24); 538 } 539 if (isIplUt4DIdentityReportMessage(m)) { 540 return interpretHostManufacturerDevice( 541 LnConstants.RE_IPL_MFR_DIGITRAX, 542 LnConstants.RE_IPL_DIGITRAX_HOST_UT4, 543 LnConstants.RE_IPL_MFR_DIGITRAX, 544 LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24); 545 } 546 if (isIplDt500DIdentityReportMessage(m)) { 547 return interpretHostManufacturerDevice( 548 LnConstants.RE_IPL_MFR_DIGITRAX, 549 LnConstants.RE_IPL_DIGITRAX_HOST_DT500, 550 LnConstants.RE_IPL_MFR_DIGITRAX, 551 LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24); 552 } 553 if (isIplUr92IdentityReportMessage(m)) { 554 return interpretHostManufacturerDevice( 555 LnConstants.RE_IPL_MFR_DIGITRAX, 556 LnConstants.RE_IPL_DIGITRAX_HOST_UR92, 557 LnConstants.RE_IPL_MFR_DIGITRAX, 558 LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24); 559 } 560 561 return interpretHostManufacturerDevice(extractIplIdentityHostManufacturer(m), extractIplIdentityHostDevice(m)); 562 } 563 564 /** 565 * Extract the IPL Slave manufacturer and Device information from m. 566 * 567 * @param m IPL Identity message 568 * @return String containing the interpreted IPL Slave Manufacturer and 569 * Device. If m is not a valid IPL Identity report, returns null. 570 */ 571 public static final String extractInterpretedIplSlaveDevice(LocoNetMessage m) { 572 if (!isIplIdentityReportMessage(m)) { 573 return null; 574 } 575 return interpretSlaveManufacturerDevice(extractIplIdentitySlaveManufacturer(m), extractIplIdentitySlaveDevice(m)); 576 577 } 578 579 /** 580 * Get the IPL host manufacturer number from an IPL Identity report 581 * message. 582 * <p> 583 * The invoking method should ensure that message m is an IPL Identity 584 * message before invoking this method. 585 * 586 * @param m IPL Identity message 587 * @return Integer containing the IPL host manufacturer number 588 */ 589 public static final Integer extractIplIdentityHostManufacturer(LocoNetMessage m) { 590 return m.getElement(4); 591 } 592 593 /** 594 * Get the host device number from an IPL Identity report message. 595 * <p> 596 * The invoking method should ensure that message m is is an IPL Identity 597 * message before invoking this method. 598 * 599 * @param m IPL Identity message 600 * @return Integer containing the IPL device number 601 */ 602 public static final Integer extractIplIdentityHostDevice(LocoNetMessage m) { 603 return m.getElement(5); 604 } 605 606 /** 607 * Get the slave manufacturer number from an IPL Identity report 608 * message. 609 * <p> 610 * The invoking method should ensure that message m is is an IPL Identity 611 * message before invoking this method. 612 * <p> 613 * NOTE: Not all IPL-capable devices implement a slave manufacturer number. 614 * 615 * @param m IPL Identity message 616 * @return Integer containing the IPL slave manufacturer number 617 */ 618 public static final Integer extractIplIdentitySlaveManufacturer(LocoNetMessage m) { 619 return m.getElement(7); 620 } 621 622 /** 623 * Get the slave device number from an IPL Identity report message. 624 * <p> 625 * The invoking method should ensure that message m is is an IPL Identity 626 * message before invoking this method. 627 * <p> 628 * NOTE: Not all IPL-capable devices implement a slave device number. 629 * 630 * @param m IPL Identity message 631 * @return Integer containing the IPL slave device number 632 */ 633 public static final Integer extractIplIdentitySlaveDevice(LocoNetMessage m) { 634 return m.getElement(6); 635 } 636 637 /** 638 * Get the host firmware revision number from an IPL Identity report 639 * message. 640 * <p> 641 * The invoking method should ensure that message m is is an IPL Identity 642 * message before invoking this method. 643 * <p> 644 * NOTE: Not all IPL-capable devices implement a host firmware revision 645 * number. 646 * 647 * @param m IPL Identity message 648 * @return String containing the IPL host firmware revision in the format 649 * x.y 650 */ 651 public static final String extractIplIdentityHostFrimwareRev(LocoNetMessage m) { 652 StringBuilder s = new StringBuilder(); 653 s.append(Integer.toString((m.getElement(8) & 0x78) >> 3)); 654 s.append("."); 655 s.append(Integer.toString((m.getElement(8) & 0x07))); 656 return s.toString(); 657 } 658 659 /** 660 * Get the host firmware revision number from an IPL Identity report 661 * message. 662 * <p> 663 * The invoking method should ensure that message m is is an IPL Identity 664 * message before invoking this method.. 665 * <p> 666 * NOTE: Not all IPL-capable devices implement a host firmware revision 667 * number. 668 * 669 * @param m IPL Identity message 670 * @return Integer containing the IPL host firmware revision 671 */ 672 public static final Integer extractIplIdentityHostFrimwareRevNum(LocoNetMessage m) { 673 return (m.getElement(8)); 674 } 675 676 /** 677 * Get the Slave firmware revision number from an IPL Identity report 678 * message. 679 * <p> 680 * The invoking method should ensure that message m is is an IPL Identity 681 * message before invoking this method.. 682 * <p> 683 * NOTE: Not all IPL-capable devices implement a Slave firmware revision 684 * number. 685 * 686 * @param m IPL Identity message 687 * @return Integer containing the IPL Slave firmware revision 688 */ 689 public static final Integer extractIplIdentitySlaveFrimwareRevNum(LocoNetMessage m) { 690 return ((m.getElement(10) & 0x7F) + ((m.getElement(9) & 0x1) << 7)); 691 } 692 693 /** 694 * Get the slave firmware revision number from an IPL Identity report 695 * message. 696 * <p> 697 * The invoking method should ensure that message m is is an IPL Identity 698 * message before invoking this method.. 699 * <p> 700 * NOTE: Not all IPL-capable devices implement a slave firmware revision 701 * number. 702 * 703 * @param m IPL Identity message 704 * @return String containing the IPL slave firmware revision in the format 705 * x.y 706 */ 707 public static final String extractIplIdentitySlaveFrimwareRev(LocoNetMessage m) { 708 StringBuilder s = new StringBuilder(); 709 s.append(Integer.toString(((m.getElement(10) & 0x78) >> 3) + ((m.getElement(9) & 0x1) << 4))); 710 s.append("."); 711 s.append(Integer.toString((m.getElement(10) & 0x07))); 712 return s.toString(); 713 } 714 715 /** 716 * Get the host serial number from an IPL Identity report message. 717 * <p> 718 * The invoking method should ensure that message m is is an IPL Identity 719 * message before invoking this method.. 720 * <p> 721 * NOTE: Not all IPL-capable devices implement a host serial number. 722 * 723 * @param m IPL Identity message 724 * @return Long containing the IPL host serial number 725 */ 726 public static final Long extractIplIdentityHostSerialNumber(LocoNetMessage m) { 727 Long sn; 728 Integer di_f1; 729 di_f1 = m.getElement(9); 730 sn = (long) (m.getElement(11) + ((di_f1 & 0x2) << 6)); 731 sn += (((long) m.getElement(12)) << 8) + (((long) di_f1 & 0x4) << 13); 732 sn += (((long) m.getElement(13)) << 16) + (((long) di_f1 & 0x8) << 20); 733 return sn; 734 } 735 736 /** 737 * Get the slave serial number from an IPL Identity report message. 738 * <p> 739 * The invoking method should ensure that message m is is an IPL Identity 740 * message before invoking this method. 741 * <p> 742 * NOTE: Not all IPL-capable devices implement a slave serial number. 743 * 744 * @param m IPL Identity message 745 * @return Long containing the IPL slave serial number 746 */ 747 public static final Long extractIplIdentitySlaveSerialNumber(LocoNetMessage m) { 748 Long sn; 749 Integer di_f2; 750 di_f2 = m.getElement(14); 751 sn = (long) (m.getElement(15) + ((di_f2 & 0x1) << 7)); 752 sn += (((long) m.getElement(16)) << 8) + (((long) di_f2 & 0x2) << 14); 753 sn += (((long) m.getElement(17)) << 16) + (((long) di_f2 & 0x4) << 21); 754 sn += (((long) m.getElement(18)) << 24) + (((long) di_f2 & 0x8) << 28); 755 return sn; 756 } 757 758 /** 759 * Interpret IPL Identity Host Manufacturer and Host Device number as a 760 * string. 761 * <p> 762 * NOTE: Some IPL-capable devices cannot be completely determined based 763 * solely on Host Manufacturer number and Host Device number. 764 * <p> 765 * NOTE: Some members of a device family do not support IPL. An interpreted 766 * IPL Host Manufacturer number and Host Device number might imply that all 767 * members do support IPL. As an example, UT4 and UT4R devices do not appear 768 * to support IPL, while UT4D appears to support IPL. This method will 769 * return "Digitrax UT4(x)" in response to appropriate Host Manufacturer 770 * number and appropriate Host Device number. 771 * 772 * @param hostMfr host manufacturer number 773 * @param hostDevice host device number 774 * @param slaveMfr slave manufacturer number 775 * @param slaveDevice slave device number 776 * @return String containing Manufacturer name and Device model. 777 */ 778 public static final String interpretHostManufacturerDevice(Integer hostMfr, Integer hostDevice, 779 Integer slaveMfr, Integer slaveDevice) { 780 int manuf = hostMfr & 0x7f; 781 int device = hostDevice & 0x7f; 782 int slave = slaveDevice & 0x7f; 783 int smanuf = slaveMfr & 0x7f; 784 String mfgName = getManufacturer(manuf); 785 String devName = getDeviceName(manuf, device, smanuf, slave); 786 if (mfgName == null) { 787 log.debug("Unknown Unknown Host Manufacturer/Device [{}]",Integer.toHexString(manuf)); 788 return "Unknown Host Manufacturer/Device"; 789 } else if (devName == null) { 790 log.debug("Unknown Device Manufacturer[{}] Device[{}] Slave manufacturer[{}] Slave device[{}]", 791 Integer.toHexString(manuf), 792 Integer.toHexString(device), 793 Integer.toHexString(smanuf), 794 Integer.toHexString(slave)); 795 return mfgName+" Unknown Device"; 796 } 797 return mfgName+" "+devName; 798 } 799 800 /** 801 * Interpret IPL Identity Host Manufacturer and Host Device number as a 802 * string. 803 * <p> 804 * NOTE: Some IPL-capable devices cannot be completely determined based 805 * solely on Host Manufacturer number and Host Device number. 806 * <p> 807 * NOTE: Some members of a device family do not support IPL. An interpreted 808 * IPL Host Manufacturer number and Host Device number might imply that all 809 * members do support IPL. As an example, UT4 and UT4R devices do not appear 810 * to support IPL, while UT4D appears to support IPL. This method will 811 * return "Digitrax UT4(x)" in response to appropriate Host Manufacturer 812 * number and appropriate Host Device number. 813 * 814 * @param hostMfr host manufacturer number 815 * @param hostDevice host device number 816 * @return String containing Manufacturer name and Device model. 817 */ 818 public static final String interpretHostManufacturerDevice(Integer hostMfr, Integer hostDevice) { 819 return interpretHostManufacturerDevice(hostMfr, hostDevice, 0, 0); 820 } 821 822 /** 823 * Interpret IPL Identity Slave Manufacturer and Slave Device number as a 824 * string. 825 * <p> 826 * NOTE: Some IPL-capable devices may not be completely determined based 827 * solely on Slave Manufacturer number and Slave Device number. 828 * 829 * @param slaveMfr slave manufacturer number 830 * @param slaveDevice slave device number 831 * @return String containing Slave Manufacturer name and Device model. 832 */ 833 public static final String interpretSlaveManufacturerDevice(Integer slaveMfr, Integer slaveDevice) { 834 String s; 835 s = "Unknown Slave Manufacturer/Device"; 836 int sMfr = slaveMfr & 0x7f; 837 int sDevice = slaveDevice & 0x7F; 838 switch (sMfr) { 839 case LnConstants.RE_IPL_MFR_DIGITRAX: { 840 switch (sDevice) { 841 case LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24: 842 s = "Digitrax RF24"; // NOI18N 843 break; 844 default: 845 s = "Digitrax (unknown Slave Device)"; 846 break; 847 } 848 break; 849 } 850 case LnConstants.RE_IPL_MFR_RR_CIRKITS: { 851 s = "RR-CirKits (unknown Slave Device)"; 852 break; 853 } 854 default: 855 break; 856 } 857 return s; 858 } 859 LnIPLImplementation thisone; 860 private LocoNetSystemConnectionMemo memo; 861 862 /** 863 * Connect this instance's LocoNetListener to the LocoNet Traffic Controller. 864 * 865 * @param t a LocoNet Traffic Controller 866 */ 867 public void connect(jmri.jmrix.loconet.LnTrafficController t) { 868 if (t != null) { 869 // connect to the LnTrafficController 870 t.addLocoNetListener(~0, this); 871 } 872 } 873 private javax.swing.Timer swingTmrIplQuery; 874 875 /** 876 * Break connection with the LnTrafficController and stop timers. 877 */ 878 public void dispose() { 879 if (swingTmrIplQuery != null) { 880 swingTmrIplQuery.stop(); 881 } 882 if (memo.getLnTrafficController() != null) { 883 memo.getLnTrafficController().removeLocoNetListener(~0, this); 884 } 885 } 886 887 /** 888 * Process all incoming LocoNet messages to look for IPL operations. Ignores 889 * all other LocoNet messages. 890 * 891 * @param m incoming LocoNet message to be examined 892 */ 893 @Override 894 public void message(LocoNetMessage m) { 895 896 if (handleMessageIplDeviceQuery(m)) { 897 return; 898 } else if (handleMessageIplDeviceReport(m)) { 899 return; 900 } 901 902 return; 903 } 904 905 private boolean handleMessageIplDeviceQuery(LocoNetMessage m) { 906 if (isIplIdentityQueryMessage(m)) { 907 Integer deviceType = 256 * extractIplIdentityHostManufacturer(m) 908 + extractIplIdentityHostDevice(m); 909 int oldvalue = 99999; 910 int newvalue = deviceType; 911 thisone.firePropertyChange("IplDeviceTypeQuery", oldvalue, newvalue); // NOI18N 912 if (waitingForIplReply == true) { 913 swingTmrIplQuery.restart(); 914 } 915 return true; 916 } 917 return false; 918 } 919 920 private boolean handleMessageIplDeviceReport(LocoNetMessage m) { 921 if (isIplIdentityReportMessage(m)) { 922 Integer deviceType = 256 * extractIplIdentityHostManufacturer(m) 923 + extractIplIdentityHostDevice(m); 924 int oldvalue = 99999; 925 int newvalue = deviceType; 926 thisone.firePropertyChange("IplDeviceTypeReport", oldvalue, newvalue); // NOI18N 927 if (waitingForIplReply == true) { 928 waitingForIplReply = false; 929 swingTmrIplQuery.stop(); 930 } 931 return true; 932 } 933 return false; 934 } 935 public boolean isIplQueryTimerRunning() { 936 return swingTmrIplQuery.isRunning(); 937 } 938 939 public static boolean isValidMfgDevice(int mfg, int deviceType) { 940 return (LnIPLImplementation.interpretHostManufacturerDevice(mfg, deviceType) 941 .compareTo("Unknown Host Manufacturer/Device") 942 != 0); 943 } 944 945 /** 946 * provides string representation for an IPL manufacturer number 947 * @param manuf IPL device manufacturer code number 948 * @return manufacturer name, or null if no known manufacturer name 949 */ 950 @CheckForNull 951 public static String getManufacturer(int manuf) { 952 switch (manuf) { 953 case LnConstants.RE_IPL_MFR_DIGITRAX: 954 return LnConstants.DIGITRAX_STRING; 955 case LnConstants.RE_IPL_MFR_RR_CIRKITS: 956 return LnConstants.RR_CIRKITS_STRING; 957 default: 958 return null; 959 } 960 } 961 962 @CheckForNull 963 public static String getDeviceName(int manuf, int device, int slaveManuf, int slave) { 964 if (getManufacturer(manuf) == null) { 965 return null; 966 } 967 for (DeviceTypes t: DeviceTypes.values()) { 968 if ((manuf == t.getManufacturer()) && 969 (device == t.getDeviceIdNumber()) && 970 (slaveManuf == t.getSlaveManufacturer()) && 971 (slave == t.getSlaveDeviceIdNumber())) { 972 return t.getDeviceName(); 973 } 974 } 975 return null; 976 } 977 978 public enum DeviceTypes { 979 UT4D(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_UT4, 980 LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24, 981 LnConstants.DIGITRAX_STRING, "UT4D"), // NOI18N 982 UT4X(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_UT4, 983 0,0, 984 LnConstants.DIGITRAX_STRING, "UT4(x)"), // NOI18N 985 DCS51(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DCS51, 986 0,0,LnConstants.DIGITRAX_STRING, "DCS51"), // NOI18N 987 DCS52(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DCS52, 988 0,0,LnConstants.DIGITRAX_STRING, "DCS52"), // NOI18N 989 DT402D(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DT402, 990 LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24, 991 LnConstants.DIGITRAX_STRING, "DT402D"), // NOI18N 992 DT402X(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DT402, 993 0,0, LnConstants.DIGITRAX_STRING, "DT402(x)"), // NOI18N 994 PR3(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_PR3, 995 0,0, LnConstants.DIGITRAX_STRING, "PR3"), // NOI18N 996 UR92(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_UR92, 997 LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24, 998 LnConstants.DIGITRAX_STRING, "UR92"), // NOI18N 999 DB210OPTO(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DB210OPTO, 1000 0,0, LnConstants.DIGITRAX_STRING, "DB210Opto"), // NOI18N 1001 DB210(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DB210, 1002 0,0, LnConstants.DIGITRAX_STRING, "DB210"), // NOI18N 1003 DB220(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DB220, 1004 0,0, LnConstants.DIGITRAX_STRING, "DB220"), // NOI18N 1005 PR4(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_PR4, 1006 0,0, LnConstants.DIGITRAX_STRING, "PR4"), // NOI18N 1007 BXP88(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_BXP88, 1008 0,0, LnConstants.DIGITRAX_STRING, "BXP88"), // NOI18N 1009 LNWI(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_LNWI, 1010 0,0, LnConstants.DIGITRAX_STRING, "LNWI"), // NOI18N 1011 DCS210(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DCS210, 1012 0,0, LnConstants.DIGITRAX_STRING, "DCS210"), // NOI18N 1013 DCS240(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DCS240, 1014 0,0, LnConstants.DIGITRAX_STRING, "DCS240"), // NOI18N 1015 DT500D(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DT500, 1016 LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_SLAVE_RF24, 1017 LnConstants.DIGITRAX_STRING, "DT500D"), // NOI18N 1018 DT500X(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DT500, 1019 0,0, LnConstants.DIGITRAX_STRING, "DT500(x)"), // NOI18N 1020 DT602X(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DT602, 1021 0,0, LnConstants.DIGITRAX_STRING, "DT602(x)"), // NOI18N 1022 BXPA1(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_BXPA1, 1023 0,0, LnConstants.DIGITRAX_STRING, "BXPA1"), // NOI18N 1024 DCS210plus(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DCS210PLUS, 1025 0,0, LnConstants.DIGITRAX_STRING, "DCS210+"), // NOI18N 1026 DCS240plus(LnConstants.RE_IPL_MFR_DIGITRAX, LnConstants.RE_IPL_DIGITRAX_HOST_DCS240PLUS, 1027 0,0, LnConstants.DIGITRAX_STRING, "DCS240+"), // NOI18N 1028 RR_CKTS_TC64(LnConstants.RE_IPL_MFR_RR_CIRKITS, LnConstants.RE_IPL_RRCIRKITS_HOST_TC64, 1029 0,0, LnConstants.RR_CIRKITS_STRING, "TC-64"), 1030 RR_CKTS_TC_MKII(LnConstants.RE_IPL_MFR_RR_CIRKITS, LnConstants.RE_IPL_RRCIRKITS_HOST_TC64_MKII, 1031 0,0, LnConstants.RR_CIRKITS_STRING, "TC-64 Mk-II"), 1032 RR_CKTS_LNCP(LnConstants.RE_IPL_MFR_RR_CIRKITS, LnConstants.RE_IPL_RRCIRKITS_HOST_LNCP, 1033 0,0, LnConstants.RR_CIRKITS_STRING, "LNCP"), 1034 RR_CKTS_MOTORMan(LnConstants.RE_IPL_MFR_RR_CIRKITS, LnConstants.RE_IPL_RRCIRKITS_HOST_MOTORMAN, 1035 0,0, LnConstants.RR_CIRKITS_STRING, "MotorMan"), 1036 RR_CKTS_MOTORMANII(LnConstants.RE_IPL_MFR_RR_CIRKITS, LnConstants.RE_IPL_RRCIRKITS_HOST_MOTORMAN_II, 1037 0,0, LnConstants.RR_CIRKITS_STRING, "MotorMan-II"), 1038 RR_CKTS_SIGNALMAN(LnConstants.RE_IPL_MFR_RR_CIRKITS, LnConstants.RE_IPL_RRCIRKITS_HOST_SIGNALMAN, 1039 0,0, LnConstants.RR_CIRKITS_STRING, "SignalMan"), 1040 RR_CKTS_TOWERMAN(LnConstants.RE_IPL_MFR_RR_CIRKITS, LnConstants.RE_IPL_RRCIRKITS_HOST_TOWERMAN, 1041 0,0, LnConstants.RR_CIRKITS_STRING, "TowerMan"), 1042 RR_CKTS_WATCHMAN(LnConstants.RE_IPL_MFR_RR_CIRKITS, LnConstants.RE_IPL_RRCIRKITS_HOST_WATCHMAN, 1043 0,0, LnConstants.RR_CIRKITS_STRING, "WatchMan"); 1044 1045 private int manufacturer; 1046 private int deviceIdNumber; 1047 private int slaveManufacturer; 1048 private int slaveDeviceIdNumber; 1049 private String manufacturerName; 1050 private String deviceName; 1051 1052 private DeviceTypes(int mfg, int devId, int slaveMfg, int slaveDevId, 1053 String mfgName, String devName) { 1054 this.manufacturer = mfg & 0x7f; 1055 this.deviceIdNumber = devId & 0x7f; 1056 this.slaveManufacturer = slaveMfg & 0x7f; 1057 this.slaveDeviceIdNumber = slaveDevId & 0x7f; 1058 this.manufacturerName = mfgName; 1059 this.deviceName = devName; 1060 } 1061 public final int getManufacturer() { 1062 return manufacturer; 1063 } 1064 public final int getDeviceIdNumber() { 1065 return deviceIdNumber; 1066 } 1067 public final int getSlaveManufacturer() { 1068 return slaveManufacturer; 1069 } 1070 public final int getSlaveDeviceIdNumber() { 1071 return slaveDeviceIdNumber; 1072 } 1073 public final boolean isDeviceMatch(int mfg, int devId, int slaveMfg, int slaveDevId) { 1074 return (mfg==manufacturer) && (devId == deviceIdNumber) && 1075 (slaveMfg == slaveManufacturer) && (slaveDevId == slaveDeviceIdNumber); 1076 } 1077 public final boolean isDeviceMatch(int mfg, int devId) { 1078 return isDeviceMatch(mfg, devId, 0, 0); 1079 } 1080 public final String getManufacturerName() { 1081 return manufacturerName; 1082 } 1083 public final String getDeviceName() { 1084 return deviceName; 1085 } 1086 } 1087 1088 private boolean waitingForIplReply; 1089 1090 private final static Logger log = LoggerFactory.getLogger(LnIPLImplementation.class); 1091}