001package jmri.jmrix.cmri.serial; 002 003import java.util.Arrays; 004import jmri.JmriException; 005import jmri.Sensor; 006import jmri.jmrix.AbstractMRListener; 007import jmri.jmrix.AbstractMRMessage; 008import jmri.jmrix.AbstractNode; 009import jmri.jmrix.cmri.serial.serialmon.SerialFilterFrame; 010 011/** 012 * Models a serial C/MRI node, consisting of a (S)USIC and attached cards. 013 * <p> 014 * Nodes are numbered ala the UA number, from 1 to 63. Node number 1 carries 015 * sensors 1 to 999, node 2 1001 to 1999 etc. 016 * <p> 017 * The array of sensor states is used to update sensor known state only when 018 * there's a change on the serial bus. This allows for the sensor state to be 019 * updated within the program, keeping this updated state until the next change 020 * on the serial bus. E.g. you can manually change a state via an icon, and not 021 * have it change back the next time that node is polled. 022 * <p> 023 * The SMINI is defined as having 1 input and 2 outputs cards.<br> 024 * USIC/SUSIC nodes can have 0-63 inputs and 0-63 output cards, but no more than 025 * 64 total cards. 026 * 027 * A CPNODE (Control Point Node) is defined as having 2 inputs and 2 outputs //c2 028 * on the node board and 0-128 bits of input or output (in 8 bit increments) 029 * for added I/O extender cards IOX16,IOX32. 030 * 031 * A CPMEGA (Open Source Node) is defined as having 8 bytes of input or output //c2 032 * on the node board and 0-128 bits of input or output (in 8 bit increments) 033 * for added I/O extender cards IOX16,IOX32. 034 * 035 * @author Bob Jacobsen Copyright (C) 2003, 2008 036 * @author Bob Jacobsen, Dave Duchamp, multiNode extensions, 2004 037 * @author Chuck Catania, cpNode Extensions 2013, 2014, 2015, 2016 038*/ 039public class SerialNode extends AbstractNode { 040 041 /** 042 * Maximum number of sensors a node can carry. 043 * <p> 044 * Note this is less than a current SUSIC motherboard can have, but should 045 * be sufficient for all reasonable layouts. 046 * <p> 047 * Must be less than, and is general one less than, 048 * {@link SerialSensorManager#SENSORSPERUA} 049 */ 050 static final int MAXSENSORS = 999; 051 052 static public final int MAXSEARCHLIGHTBYTES = 48; 053 static public final int MAXCARDLOCATIONBYTES = 64; 054 055 // class constants 056 public static final int SMINI = 1; // SMINI node type 057 public static final int USIC_SUSIC = 2; // USIC/SUSIC node type 058 public static final int CPNODE = 3; // cpNode Control Point (Arduino) node type c2 059 public static final int CPMEGA = 4; // Open Source Node (OSN) e.g Mega2560 R3 c2 060 061 public static final int NDP_USICSUSIC24 = 78; // 'N' USIC/SUSIC 24 bit cards 062 public static final int NDP_USICSUSIC32 = 88; // 'X' USIC/SUSIC 32 bit cards 063 public static final int NDP_SMINI = 77; // 'M' SMINI 24 bit cards 064 public static final int NDP_CPNODE = 67; // 'C' CPNODE 8 bit cards 065 public static final int NDP_CPMEGA = 79; // 'O' CPMEGA 8 bit cards 066 067 public static final byte INPUT_CARD = 1; // USIC/SUSIC input card type for specifying location 068 public static final byte OUTPUT_CARD = 2; // USIC/SUSIC output card type for specifying location 069 public static final byte NO_CARD = 0; // USIC/SUSIC unused location 070 071 // node definition instance variables (must persist between runs) 072 protected int nodeType = SMINI; // See above 073 protected int bitsPerCard = 24; // 24 for SMINI and USIC, 24 or 32 for SUSIC 074 protected int transmissionDelay = 0; // DL, delay between bytes on Receive (units of 10 microsec.) 075 protected int pulseWidth = 500; // Pulse width for pulsed turnout control (milliseconds) 076 protected int num2LSearchLights = 0; // SMINI only, 'NS' number of two lead bicolor signals 077 protected byte[] locSearchLightBits = new byte[MAXSEARCHLIGHTBYTES]; // SMINI only, 0 = not searchlight LED, 078 // 1 = searchlight LED, 2*NS bits must be set to 1 079 protected byte[] cardTypeLocation = new byte[MAXCARDLOCATIONBYTES]; // Varys on USIC/SUSIC. There must numInputCards bytes set to 080 // INPUT_CARD, and numOutputCards set to OUTPUT_CARD, with 081 // the remaining locations set to NO_CARD. All 082 // NO_CARD locations must be at the end of the array. The 083 // array is indexed by card address. 084 // operational instance variables (should not be preserved between runs) 085 086 // cpNode/Open Source Node variables c2 087 public static final int INITMSGLEN = 12; 088 public static final int NUMCMRINETOPTS = 16; 089 public static final int NUMCPNODEOPTS = 16; 090 protected int cmrinetOptions[] = new int[NUMCMRINETOPTS]; // CMRInet options stored as 16 binary digits 091 protected int cpnodeOptions[] = new int[NUMCPNODEOPTS]; // cpNode options stored as 16 binary digits 092 093 protected String cmriNodeDesc = ""; // CMRI node name for display 094 protected int pollListPosition = 0; 095 096 public int pollStatus = 1; 097 public static final int POLLSTATUS_ERROR = 0; 098 public static final int POLLSTATUS_IDLE = 1; 099 public static final int POLLSTATUS_POLLING = 2; 100 public static final int POLLSTATUS_TIMEOUT = 3; 101 public static final int POLLSTATUS_INIT = 4; 102 103 // CMRInet options stored in XML 104 public static final int optbitNet_AUTOPOLL = 0; 105 public static final int optbitNet_USECMRIX = 1; 106 public static final int optbitNet_USEBCC = 2; 107 public static final int optbitNet_BIT8 = 8; 108 public static final int optbitNet_BIT15 = 15; 109 110 // cpNode/osNode options in initialization message 111 public static final int optbitNode_USECMRIX = 0; 112 public static final int optbitNode_SENDEOT = 1; 113 public static final int optbitNode_USEBCC = 2; 114 public static final int optbitNode_BIT8 = 8; 115 public static final int optbitNode_BIT15 = 15; 116 117 protected byte[] outputArray = new byte[256]; // current values of the output bits for this node 118 protected boolean hasActiveSensors = false; // 'true' if there are active Sensors for this node 119 protected int lastUsedSensor = 0; // grows as sensors defined 120 protected Sensor[] sensorArray = new Sensor[MAXSENSORS + 1]; 121 protected int[] sensorLastSetting = new int[MAXSENSORS + 1]; 122 protected int[] sensorTempSetting = new int[MAXSENSORS + 1]; 123 124 protected boolean monitorNodePackets = true; 125 protected boolean[] monitorPacketBits = new boolean[SerialFilterFrame.numMonPkts]; 126 127 /** 128 * Assumes a node address of 0, and a node type of SMINI. 129 * If this constructor 130 * is used, actual node address must be set using setNodeAddress, and actual 131 * node type using 'setNodeType' 132 * @param tc system connection traffic controller. 133 */ 134 public SerialNode(SerialTrafficController tc) { 135 this(0, SMINI,tc); 136 } 137 138 /** 139 * Creates a new SerialNode and initialize default instance variables. 140 * @param address Address of node on CMRI serial bus (0-127). 141 * @param type Node type, e.g. SMINI or USIC_SUSIC. 142 * @param tc system connection traffic controller. 143 */ 144 public SerialNode(int address, int type, SerialTrafficController tc) { 145 // set address and type and check validity 146 setNodeAddress(address); 147 setNodeType(type); 148 // set default values for other instance variables 149 bitsPerCard = 24; 150 transmissionDelay = 0; 151 num2LSearchLights = 0; 152 for (int i = 0; i < MAXSEARCHLIGHTBYTES; i++) { 153 locSearchLightBits[i] = 0; 154 } 155 // note: setNodeType initialized cardTypeLocation[]; 156 // clear the Sensor arrays 157 for (int i = 0; i < MAXSENSORS + 1; i++) { 158 sensorArray[i] = null; 159 sensorLastSetting[i] = Sensor.UNKNOWN; 160 sensorTempSetting[i] = Sensor.UNKNOWN; 161 } 162 // clear all output bits 163 for (int i = 0; i < 256; i++) { 164 outputArray[i] = 0; 165 } 166 // initialize other operational instance variables 167 setMustSend(); 168 setOptNet_AUTOPOLL(1); // always start with polling enabled 169 hasActiveSensors = false; 170 // register this node 171 tc.registerNode(this); 172 } 173 174 public int getNum2LSearchLights() { 175 return num2LSearchLights; 176 } 177 178 public void setNum2LSearchLights(int n) { 179 num2LSearchLights = n; 180 } 181 182 public byte[] getLocSearchLightBits() { 183 return Arrays.copyOf(locSearchLightBits, locSearchLightBits.length); 184 } 185 186 public void setLocSearchLightBits(int num, int value) { 187 locSearchLightBits[num] = (byte) (value & 0xFF); 188 } 189 190 public byte[] getCardTypeLocation() { 191 return Arrays.copyOf(cardTypeLocation, cardTypeLocation.length); 192 } 193 194 public void setCardTypeLocation(int num, int value) { 195 // Validate the input 196 if ((num < 0) || (num >= MAXCARDLOCATIONBYTES)) { 197 log.error("setCardTypeLocation - invalid num (index) - {}", num); 198 return; 199 } 200 int val = value & 0xFF; 201 if ((val != NO_CARD) && (val != INPUT_CARD) && (val != OUTPUT_CARD)) { 202 log.error("setCardTypeLocation - invalid value - {}", val); 203 return; 204 } 205 // Set the card type 206 cardTypeLocation[num] = (byte) (val); 207 } 208 209 /** 210 * Set a single output bit. 211 * @param bitNumber bit number, bits are numbered from 1 (not 0). 212 * @param state true for 0, false for 1. 213 */ 214 public void setOutputBit(int bitNumber, boolean state) { 215 // locate in the outputArray 216 int byteNumber = (bitNumber - 1) / 8; 217 // validate that this byte number is defined 218 if (byteNumber > (numOutputCards() * (bitsPerCard / 8))) { 219 warn("Output bit out-of-range for defined node"); 220 } 221 if (byteNumber >= 256) { 222 byteNumber = 255; 223 } 224 // update the byte 225 byte bit = (byte) (1 << ((bitNumber - 1) % 8)); 226 byte oldByte = outputArray[byteNumber]; 227 if (state) { 228 outputArray[byteNumber] &= (~bit); 229 } else { 230 outputArray[byteNumber] |= bit; 231 } 232 // check for change, necessitating a send 233 if (oldByte != outputArray[byteNumber]) { 234 setMustSend(); 235 } 236 } 237 238 /** 239 * Get the current state of a single output bit. 240 * @param bitNumber bit number, bits are numbered from 1 (not 0). 241 * @return true for 0, false for 1. 242 */ 243 public boolean getOutputBit(int bitNumber) { 244 // locate in the outputArray 245 int byteNumber = (bitNumber - 1) / 8; 246 // validate that this byte number is defined 247 if (byteNumber > (numOutputCards() * (bitsPerCard / 8))) { 248 warn("Output bit out-of-range for defined node"); 249 } 250 if (byteNumber >= 256) { 251 byteNumber = 255; 252 } 253 // update the byte 254 byte bit = (byte) (1 << ((bitNumber - 1) % 8)); 255 byte testByte = outputArray[byteNumber]; 256 testByte &= bit; 257 if (testByte == 0) { 258 return (true); 259 } else { 260 return (false); 261 } 262 } 263 264 /** 265 * Get state of Sensor polling. Note: returns 'true' if at least one sensor 266 * is active for this node 267 */ 268 @Override 269 public boolean getSensorsActive() { 270 return hasActiveSensors; 271 } 272 273 /** 274 * Set state of Sensor polling. 275 * Used to disable polling for test purposes only. 276 * @param flag true to set active flag, else false. 277 */ 278 public void setSensorsActive(boolean flag) { 279 hasActiveSensors = flag; 280 } 281 282 /** 283 * Get number of input cards. 284 * @return number of input cards. 285 */ 286 public int numInputCards() { 287 int result = 0; 288 for (int i = 0; i < cardTypeLocation.length; i++) { 289 if (cardTypeLocation[i] == INPUT_CARD) { 290 result++; 291 } 292 } 293 294/* 295 // check consistency 296 if (nodeType == SMINI && result != 1) { 297 warn("C/MRI SMINI node with " + result + " input cards"); 298 } 299 if (nodeType == USIC_SUSIC && result >= MAXCARDLOCATIONBYTES) { 300 warn("C/MRI USIC/SUSIC node with " + result + " input cards"); 301*/ 302 switch (nodeType) //c2 303 { 304 case SMINI: if (result!=1) 305 { 306 warn("SMINI with "+result+" INPUT cards"); 307 } 308 break; 309 case USIC_SUSIC: if(result>=MAXCARDLOCATIONBYTES) 310 warn("USIC/SUSIC node with "+result+" INPUT cards"); 311 break; 312 case CPNODE: if(result<2) //c2 313 warn("CPNODE node with "+result+" INPUT cards"); 314 break; 315 case CPMEGA: if(result<1) //c2 316 warn("CPMEGA node with "+result+" INPUT cards"); 317 break; 318 default: 319 break; 320 } 321 322 323 return result; 324 } 325 326 /** 327 * Get number of output cards. 328 * @return number of output cards. 329 */ 330 public int numOutputCards() { 331 int result = 0; 332 for (int i = 0; i < cardTypeLocation.length; i++) { 333 if (cardTypeLocation[i] == OUTPUT_CARD) { 334 result++; 335 } 336 } 337/* 338 // check consistency 339 if (nodeType == SMINI && result != 2) { 340 warn("C/MRI SMINI node with " + result + " output cards"); 341 } 342 if (nodeType == USIC_SUSIC && result >= MAXCARDLOCATIONBYTES) { 343 warn("C/MRI USIC/SUSIC node with " + result + " output cards"); 344 } 345*/ 346 switch (nodeType) //c2 347 { 348 case SMINI: if (result!=2) 349 { 350 warn("SMINI with "+result+" OUTPUT cards"); 351 } 352 break; 353 case USIC_SUSIC: 354 if(result>=MAXCARDLOCATIONBYTES) 355 warn("USIC/SUSIC node with "+result+" OUTPUT cards"); 356 break; 357 case CPNODE: //c2 358 if(result<2) 359 warn("CPNODE node with "+result+" OUTPUT cards"); 360 break; 361 case CPMEGA: //c2 362 if(result<1) 363 warn("CPMEGA node with "+result+" OUTPUT cards"); 364 break; 365 default: 366 } 367 368 return result; 369 } 370 371 /** 372 * Get node type Current types are: SMINI, USIC_SUSIC, 373 * @return node type, e.g. USIC_SUSIC. 374 */ 375 public int getNodeType() { 376 return (nodeType); 377 } 378 379 /** 380 * Set node type. 381 * <p> 382 * Current types are: SMINI, USIC_SUSIC 383 * For SMINI, also sets cardTypeLocation[] and bitsPerCard. 384 * For USIC_SUSIC, also clears cardTypeLocation. 385 * @param type node type, e.g. USIC_SUSIC. 386 */ 387 public void setNodeType(int type) { 388 389/* if (type == SMINI) { 390 nodeType = type; 391 bitsPerCard = 24; 392 // set cardTypeLocation for SMINI 393 cardTypeLocation[0] = OUTPUT_CARD; 394 cardTypeLocation[1] = OUTPUT_CARD; 395 cardTypeLocation[2] = INPUT_CARD; 396 for (int i = 3; i < MAXCARDLOCATIONBYTES; i++) { 397 cardTypeLocation[i] = NO_CARD; 398 } 399 } else if (type == USIC_SUSIC) { 400 nodeType = type; 401 // clear cardTypeLocations 402 for (int i = 0; i < MAXCARDLOCATIONBYTES; i++) { 403 cardTypeLocation[i] = NO_CARD; 404 } 405 } // here recognize other node types 406 else { 407 log.error("Bad node type - " + Integer.toString(type)); 408 } 409*/ 410 switch(type) //c2 411 { 412 case SMINI: 413 nodeType = type; 414 bitsPerCard = 24; 415 // set cardTypeLocation for SMINI 416 cardTypeLocation[0] = OUTPUT_CARD; 417 cardTypeLocation[1] = OUTPUT_CARD; 418 cardTypeLocation[2] = INPUT_CARD; 419 for (int i=3;i<MAXCARDLOCATIONBYTES;i++) 420 { 421 cardTypeLocation[i] = NO_CARD; 422 } 423 break; 424 case USIC_SUSIC: 425 nodeType = type; 426 // clear cardTypeLocations 427 for (int i=0;i<MAXCARDLOCATIONBYTES;i++) 428 { 429 cardTypeLocation[i] = NO_CARD; 430 } 431 break; 432 case CPNODE: //c2 433 nodeType = type; 434 bitsPerCard = 8; 435 436 // set cardTypeLocation for CPNODE. First four bytes are onboard 437 cardTypeLocation[0] = INPUT_CARD; 438 cardTypeLocation[1] = INPUT_CARD; 439 cardTypeLocation[2] = OUTPUT_CARD; 440 cardTypeLocation[3] = OUTPUT_CARD; 441 for (int i=4;i<MAXCARDLOCATIONBYTES;i++) 442 { 443 cardTypeLocation[i] = NO_CARD; 444 } 445 break; 446 447 case CPMEGA: //c2 448 nodeType = type; 449 bitsPerCard = 8; 450 451 // set cardTypeLocation for CPMEGA. First eight bytes are onboard 452 cardTypeLocation[0] = INPUT_CARD; 453 cardTypeLocation[1] = NO_CARD; 454 cardTypeLocation[2] = NO_CARD; 455 cardTypeLocation[3] = NO_CARD; 456 cardTypeLocation[4] = NO_CARD; 457 cardTypeLocation[5] = NO_CARD; 458 cardTypeLocation[6] = NO_CARD; 459 cardTypeLocation[7] = NO_CARD; 460 for (int i=8;i<MAXCARDLOCATIONBYTES;i++) 461 { 462 cardTypeLocation[i] = NO_CARD; 463 } 464 break; 465 466// here recognize other node types 467 default: 468 log.error("Bad node type - {}", Integer.toString(type)); 469 } 470 471 } 472 473 /** 474 * Get number of bits per card. 475 * @return number of bits per card. 476 */ 477 public int getNumBitsPerCard() { 478 return (bitsPerCard); 479 } 480 481 /** 482 * Set number of bits per card. 483 * @param bits number of bits. 484 */ 485 public void setNumBitsPerCard(int bits) { 486 if ((bits == 24) || (bits == 32) || (bits == 16) || (bits == 8)) { 487 bitsPerCard = bits; 488 } else { 489 log.warn("unexpected number of bits per card: {}", Integer.toString(bits)); 490 bitsPerCard = bits; 491 } 492 } 493 494 /** 495 * Get CMRInet options. 496 * @param optionbit option index. 497 * @return option value: meaning depends on option 498 */ 499 public int getCMRInetOpts(int optionbit) { return (cmrinetOptions[optionbit]); } 500 public void setCMRInetOpts(int optionbit,int val) { cmrinetOptions[optionbit] = (byte)val; } 501 public boolean isCMRInetBit(int optionbit) { return (cmrinetOptions[optionbit] == 1); } 502 503 /** 504 * Get cpNode options. 505 * @param optionbit option index. 506 * @return option value: meaning depends on option 507 */ 508 public int getcpnodeOpts(int optionbit) { return (cpnodeOptions[optionbit]); } 509 public void setcpnodeOpts(int optionbit,int val) { cpnodeOptions[optionbit] = (byte)val; } 510 public boolean iscpnodeBit(int optionbit) { return (cpnodeOptions[optionbit] == 1); } 511 512 /* 513 * get and set specific option bits. 514 * Network Option Bits 515 */ 516 517 /** 518 * Get if Autopoll bit set. 519 * @return true if set, else false. 520 */ 521 public boolean getOptNet_AUTOPOLL() { 522 var retval = cmrinetOptions[optbitNet_AUTOPOLL] == 1; 523 log.trace("getOptNet_AUTOPOLL() is {}", retval); 524 return (retval); 525 } 526 527 public boolean getOptNet_USECMRIX() { return (cmrinetOptions[optbitNet_USECMRIX] == 1); } 528 public boolean getOptNet_USEBCC() { return (cmrinetOptions[optbitNet_USEBCC] == 1); } 529 public boolean getOptNet_BIT8() { return (cmrinetOptions[optbitNet_BIT8] == 1); } 530 public boolean getOptNet_BIT15() { return (cmrinetOptions[optbitNet_BIT15] == 1); } 531 532 /** 533 * update Autopoll bit 534 * @param val 1 sets autopoll on, 0 sets it off 535 */ 536 public void setOptNet_AUTOPOLL(int val) { 537 log.trace("setOptNet_AUTOPOLL({})", val); 538 cmrinetOptions[optbitNet_AUTOPOLL] = (byte)val; 539 } 540 541 public void setOptNet_USECMRIX(int val) { cmrinetOptions[optbitNet_USECMRIX] = (byte)val; } 542 public void setOptNet_USEBCC(int val) { cmrinetOptions[optbitNet_USEBCC] = (byte)val; } 543 public void setOptNet_BIT8(int val) { cmrinetOptions[optbitNet_BIT8] = (byte)val; } 544 public void setOptNet_BIT15(int val) { cmrinetOptions[optbitNet_BIT15] = (byte)val; } 545 546 public int getOptNet_byte0() {return cmrinetOptions[0];} 547 public int getOptNet_byte1() {return cmrinetOptions[1];} 548 549 /* 550 * Node Option Bits. 551 */ 552 553 /** 554 * Get Node Option SENDEOT. 555 * @return true if SENDEOT, else false. 556 */ 557 public boolean getOptNode_SENDEOT() { return (cpnodeOptions[optbitNode_SENDEOT] == 1); } 558 public boolean getOptNode_USECMRIX() { return (cpnodeOptions[optbitNode_USECMRIX] == 1); } 559 public boolean getOptNode_USEBCC() { return (cpnodeOptions[optbitNode_USEBCC] == 1); } 560 public boolean getOptNode_BIT8() { return (cpnodeOptions[optbitNode_BIT8] == 1); } 561 public boolean getOptNode_BIT15() { return (cpnodeOptions[optbitNode_BIT15] == 1); } 562 563 public void setOptNode_SENDEOT(int val) { cpnodeOptions[optbitNode_SENDEOT] = (byte)val; } 564 public void setOptNode_USECMRIX(int val) { cpnodeOptions[optbitNode_USECMRIX] = (byte)val; } 565 public void setOptNode_USEBCC(int val) { cpnodeOptions[optbitNode_USEBCC] = (byte)val; } 566 public void setOptNode_BIT8(int val) { cpnodeOptions[optbitNode_BIT8] = (byte)val; } 567 public void setOptNode_BIT15(int val) { cpnodeOptions[optbitNode_BIT15] = (byte)val; } 568 569 public int getOptNode_byte0() {return cpnodeOptions[0];} 570 public int getOptNode_byte1() {return cpnodeOptions[1];} 571 572 /** 573 * Get node description. 574 * @return node description. 575 */ 576 public String getcmriNodeDesc() { return cmriNodeDesc; } 577 578 public void setcmriNodeDesc(String nodeDesc) { cmriNodeDesc = nodeDesc; } 579 580 /** 581 * Get cpNode poll list position. 582 * @return poll list position. 583 */ 584 public int getPollListPosition() { return pollListPosition; } 585 586 public void setPollListPosition(int pos) { pollListPosition = pos; } 587 588 /** 589 * Get cpNode polling status. 590 * @return true if polling status flag set, else false. 591 */ 592 public int getPollStatus() { return pollStatus; } 593 594 public void setPollStatus(int status) { pollStatus = status; } 595 596 /** 597 * Check cpNode polling enabled state. 598 * @return true if polling is enabled. 599 */ 600 public boolean getPollingEnabled() { return (cmrinetOptions[optbitNet_AUTOPOLL] == 1); } 601 602 public void setPollingEnabled(boolean isEnabled) 603 { 604 if(isEnabled) 605 cmrinetOptions[optbitNet_AUTOPOLL] = 1; 606 else 607 cmrinetOptions[optbitNet_AUTOPOLL] = 0; 608 } 609 610 /** 611 * Get packet monitoring for the node . 612 * @return true if packet monitoring flag set true, else false. 613 */ 614 public boolean getMonitorNodePackets() { return monitorNodePackets; } 615 616 public void setMonitorNodePackets(boolean onoff) { monitorNodePackets = onoff; } 617 618 /** 619 * Set the specific packet monitoring enable bit. 620 * @param pktTypeBit index. 621 * @param onoff true enables, false disabled. 622 */ 623 public void setMonitorPacketBit(int pktTypeBit, boolean onoff) { 624 monitorPacketBits[pktTypeBit] = onoff; 625 } 626 627 public boolean getMonitorPacketBit(int pktTypeBit) 628 { 629 return monitorPacketBits[pktTypeBit]; 630 } 631 632 /** 633 * Check valid node address, must match value in dip switches (0 - 127). 634 * {@inheritDoc} 635 */ 636 @Override 637 protected boolean checkNodeAddress(int address) { 638 return (address >= 0) && (address < 128); 639 } 640 641 /** 642 * Get transmission delay. 643 * @return delay, ms. 644 */ 645 public int getTransmissionDelay() { 646 return (transmissionDelay); 647 } 648 649 /** 650 * Set transmission delay. 651 * <p> 652 * two bytes are used, so range is 0-65,535. If delay is 653 * out of range, it is restricted to the allowable range. 654 * @param delay - delay between bytes on receive (units of 655 * 10 microsec.) 656 */ 657 public void setTransmissionDelay(int delay) { 658 if ((delay < 0) || (delay > 65535)) { 659 log.warn("transmission delay out of 0-65535 range: {}", Integer.toString(delay)); 660 if (delay < 0) { 661 delay = 0; 662 } 663 if (delay > 65535) { 664 delay = 65535; 665 } 666 } 667 transmissionDelay = delay; 668 } 669 670 /** 671 * Get pulse width. 672 * Used with pulsed turnout control. 673 * @return pulse width, ms. 674 */ 675 public int getPulseWidth() { 676 return (pulseWidth); 677 } 678 679 /** 680 * Set pulse width. 681 * @param width width of pulse used for pulse controlled turnout 682 * control (millisec.) Note: Pulse width must be between 100 and 10000 683 * milliseconds. If width is out of range, it is restricted to the allowable 684 * range 685 */ 686 public void setPulseWidth(int width) { 687 if ((width < 100) || (width > 10000)) { 688 log.warn("pulse width out of 100 - 10000 range: {}", Integer.toString(width)); 689 if (width < 100) { 690 width = 100; 691 } 692 if (width > 10000) { 693 width = 10000; 694 } 695 } 696 pulseWidth = width; 697 } 698 699 /** 700 * Set the type of one card. 701 * 702 * @param address address recognized for this card by 703 * the node hardware. for USIC_SUSIC address set in card's dip switches (0 - 704 * 63) 705 * @param type INPUT_CARD, OUTPUT_CARD, or NO_CARD 706 */ 707 public void setCardTypeByAddress(int address, int type) { 708 // validate address 709 if ((address < 0) || (address > 63)) { 710 log.error("illegal card address: {}", Integer.toString(address)); 711 return; 712 } 713 // validate type 714 if ((type != OUTPUT_CARD) && (type != INPUT_CARD) && (type != NO_CARD)) { 715 log.error("illegal card type: {}", Integer.toString(type)); 716 cardTypeLocation[address] = NO_CARD; 717 return; 718 } 719 // check node type/location restrictions 720 if ((nodeType == SMINI) && (((address > 2) && (type != NO_CARD)) 721 || ((address == 2) && (type != INPUT_CARD)) 722 || ((address < 2) && (type != OUTPUT_CARD)))) { 723 log.error("illegal card type/address specification for SMINI"); 724 return; 725 } 726// here add type/location restrictions for other types of card 727 cardTypeLocation[address] = (byte) type; 728 } 729 730 /** 731 * Test for OUTPUT_CARD type. 732 * 733 * @param cardNum index number. 734 * @return true if card with 'cardNum' is an output card. false if card 735 * is not an output card, or if 'cardNum' is out of range. 736 */ 737 public boolean isOutputCard(int cardNum) { 738 if (cardNum > 63) { 739 warn("isOutputCard - cardNum out of range"); 740 return (false); 741 } 742 if (nodeType == SMINI) { 743 if ((cardNum == 0) || (cardNum == 1)) { 744 return (true); 745 } else { 746 return (false); 747 } 748 } 749 return (cardTypeLocation[cardNum] == OUTPUT_CARD); 750 } 751 752 /** 753 * Test for INPUT_CARD type. 754 * @param cardNum index number. 755 * @return true if card with 'cardNum' is an input card, 756 * false if card is not an input card, or if 'cardNum' is out 757 * of range. 758 */ 759 public boolean isInputCard(int cardNum) { 760 if (cardNum > 63) { 761 warn("isInputCard - cardNum out of range"); 762 return (false); 763 } 764 if (nodeType == SMINI) { 765 if (cardNum == 2) { 766 return (true); 767 } else { 768 return (false); 769 } 770 } 771 return (cardTypeLocation[cardNum] == INPUT_CARD); 772 } 773 774 /** 775 * Get 'Output Card Index'. 776 * <p> 777 * Can be used to locate this card's 778 * bytes in an output message. Array is ordered by increasing node address. 779 * @param cardNum index number. 780 * @return the index this output card would have in 781 * an array of output cards for this node. 782 */ 783 public int getOutputCardIndex(int cardNum) { 784 if (nodeType == SMINI) { 785 if ((cardNum == 0) || (cardNum == 1)) { 786 return (cardNum); 787 } 788 } else { 789 int index = 0; 790 for (int i = 0; i < cardTypeLocation.length; i++) { 791 if (cardTypeLocation[i] == OUTPUT_CARD) { 792 if (i == cardNum) { 793 return (index); 794 } else { 795 index++; 796 } 797 } 798 } 799 } 800 // Here if error - cardNum is not an 801 warn("input card to getOutputCardIndex is not an Output Card"); 802 return (0); 803 } 804 805 /** 806 * Get 'Input Card Index'. 807 * <p> 808 * Can be used to locate this card's bytes in an receive message. 809 * Array is ordered by increasing node address. 810 * @param cardNum index number. 811 * @return the index this input card would have in an 812 * array of input cards for this node. 813 * 814 */ 815 public int getInputCardIndex(int cardNum) { 816 if (nodeType == SMINI) { 817 if (cardNum == 2) { 818 return (0); 819 } 820 } else { 821 int index = 0; 822 for (int i = 0; i < cardTypeLocation.length; i++) { 823 if (cardTypeLocation[i] == INPUT_CARD) { 824 if (i == cardNum) { 825 return (index); 826 } else { 827 index++; 828 } 829 } 830 } 831 } 832 // Here if error - cardNum is not an 833 warn("input card to getOutputCardIndex is not an Output Card"); 834 return (0); 835 } 836 837 /** 838 * Set location of SearchLightBits (SMINI only). 839 * @param bit - bitNumber of the low 840 * bit of an oscillating search light bit pair 841 * <p> 842 * Bits are numbered from 0. 843 * Two bits are set by each call - bit and bit + 1. If either bit is 844 * already set, an error is logged and no bits are set. 845 */ 846 public void set2LeadSearchLight(int bit) { 847 // check for SMINI 848// if other types of CMRI nodes allow oscillating search lights, modify this method 849 if (nodeType != SMINI) { 850 log.error("Invalid setting of Searchlights bits - not SMINI node"); 851 return; 852 } 853 // validate bit number range 854 if ((bit < 0) || (bit > 46)) { 855 log.error("Invalid bit number when setting SMINI Searchlights bits: {}", Integer.toString(bit)); 856 return; 857 } 858 // validate that bits are not already set 859 if ((locSearchLightBits[bit] != 0) || (locSearchLightBits[bit + 1] != 0)) { 860 log.error("bit number for SMINI Searchlights bits already set: {}", Integer.toString(bit)); 861 return; 862 } 863 // set the bits 864 locSearchLightBits[bit] = 1; 865 locSearchLightBits[bit + 1] = 1; 866 num2LSearchLights++; 867 } 868 869 /** 870 * Clear location of SearchLightBits (SMINI only). 871 * @param bit - bitNumber of the low 872 * bit of an oscillating search light bit pair 873 * <p> 874 * Notes: Bits are numbered from 875 * 0 Two bits are cleared by each call - bit and bit + 1. If either bit is 876 * already clear, an error is logged and no bits are set. 877 */ 878 public void clear2LeadSearchLight(int bit) { 879 // check for SMINI 880// if other types of CMRI nodes allow oscillating search lights, modify this method 881 if (nodeType != SMINI) { 882 log.error("Invalid setting of Searchlights bits - not SMINI node"); 883 return; 884 } 885 // validate bit number range 886 if ((bit < 0) || (bit > 46)) { 887 log.error("Invalid bit number when setting SMINI Searchlights bits: {}", Integer.toString(bit)); 888 return; 889 } 890 // validate that bits are not already clear 891 if ((locSearchLightBits[bit] != 1) || (locSearchLightBits[bit + 1] != 1)) { 892 log.error("bit number for SMINI Searchlights bits already clear: {}", Integer.toString(bit)); 893 return; 894 } 895 // set the bits 896 locSearchLightBits[bit] = 0; 897 locSearchLightBits[bit + 1] = 0; 898 num2LSearchLights--; 899 } 900 901 /** 902 * Query SearchLightBits by bit number (SMINI only). 903 * @param bit bitNumber of the either bit of an oscillating search light bit pair. 904 * @return true if bit is an oscillating SearchLightBit, otherwise false. 905 */ 906 public boolean isSearchLightBit(int bit) { 907 // check for SMINI 908// if other types of CMRI nodes allow oscillating search lights, modify this method 909 if (nodeType != SMINI) { 910 log.error("Invalid query of Searchlights bits - not SMINI node"); 911 return (false); 912 } 913 // validate bit number range 914 if ((bit < 0) || (bit > 47)) { 915 log.error("Invalid bit number in query of SMINI Searchlights bits: {}", Integer.toString(bit)); 916 return (false); 917 } 918 if (locSearchLightBits[bit] == 1) { 919 return (true); 920 } 921 return (false); 922 } 923 924 /** 925 * Create an Initialization packet (SerialMessage) for this node 926 */ 927 @Override 928 public AbstractMRMessage createInitPacket() { 929 // Assemble initialization byte array from node information 930 int nInitBytes = 4; 931 byte[] initBytes = new byte[20]; 932 int code = 0; 933 // set node definition parameter 934/* 935 if (nodeType == SMINI) { 936 initBytes[0] = 77; // 'M' 937 } else if (nodeType == USIC_SUSIC) { 938 if (bitsPerCard == 24) { 939 initBytes[0] = 78; // 'N' 940 } else if (bitsPerCard == 32) { 941 initBytes[0] = 88; // 'X' 942 } 943 } 944*/ 945 switch(nodeType) //c2 946 { 947 case SMINI: initBytes[0] = NDP_SMINI; // 'M' 948 break; 949 950 case USIC_SUSIC: if (bitsPerCard==24) initBytes[0] = NDP_USICSUSIC24; // 'N' 951 else 952 if (bitsPerCard==32) initBytes[0] = NDP_USICSUSIC32; // 'X' 953 break; 954 case CPNODE: initBytes[0] = NDP_CPNODE; // 'C' c2 955 break; 956 case CPMEGA: initBytes[0] = NDP_CPMEGA; // 'O' c2 957 break; 958 959 default: 960 } 961 962// Here add code for other type of card 963 // add Transmission Delay bytes (same for SMINI and USIC/SUSIC) 964 int firstByte = transmissionDelay / 256; 965 int secondByte = transmissionDelay - (firstByte * 256); 966 if (firstByte > 255) { 967 firstByte = 255; 968 } 969 initBytes[1] = (byte) firstByte; 970 initBytes[2] = (byte) secondByte; 971/* 972 // SMINI specific part of initialization byte array 973 if (nodeType == SMINI) { 974 initBytes[3] = (byte) num2LSearchLights; 975 if (num2LSearchLights > 0) { 976 // Set up searchlight LED bit codes 977 for (int i = 0, j = 0; i < 6; i++, j += 8) { 978 code = locSearchLightBits[j]; 979 code = code + (locSearchLightBits[j + 1] * 2); 980 code = code + (locSearchLightBits[j + 2] * 4); 981 code = code + (locSearchLightBits[j + 3] * 8); 982 code = code + (locSearchLightBits[j + 4] * 16); 983 code = code + (locSearchLightBits[j + 5] * 32); 984 code = code + (locSearchLightBits[j + 6] * 64); 985 code = code + (locSearchLightBits[j + 7] * 128); 986 initBytes[nInitBytes] = (byte) code; 987 nInitBytes++; 988 } 989 } 990 } // USIC/SUSIC specific part of initialization byte array 991 else if (nodeType == USIC_SUSIC) { 992 int numCards = numInputCards() + numOutputCards(); 993 int numFours = numCards / 4; 994 if ((numCards - (numFours * 4)) > 0) { 995 numFours++; // Round up if not even multiple 996 } 997 initBytes[3] = (byte) numFours; 998 for (int i = 0, j = 0; i < numFours; i++, j += 4) { 999 code = cardTypeLocation[j]; 1000 code = code + (cardTypeLocation[j + 1] * 4); 1001 code = code + (cardTypeLocation[j + 2] * 16); 1002 code = code + (cardTypeLocation[j + 3] * 64); 1003 initBytes[nInitBytes] = (byte) code; 1004 nInitBytes++; 1005 } 1006 } 1007*/ 1008 // SMINI specific part of initialization byte array 1009 switch (nodeType) //c2 1010 { 1011 case SMINI: 1012 initBytes[3] = (byte)num2LSearchLights; 1013 if (num2LSearchLights>0) 1014 { 1015 // Set up searchlight LED bit codes 1016 for (int i=0,j=0;i<6;i++,j+=8) 1017 { 1018 code = locSearchLightBits[j]; 1019 code = code + (locSearchLightBits[j+1]*2); 1020 code = code + (locSearchLightBits[j+2]*4); 1021 code = code + (locSearchLightBits[j+3]*8); 1022 code = code + (locSearchLightBits[j+4]*16); 1023 code = code + (locSearchLightBits[j+5]*32); 1024 code = code + (locSearchLightBits[j+6]*64); 1025 code = code + (locSearchLightBits[j+7]*128); 1026 initBytes[nInitBytes] = (byte)code; 1027 nInitBytes ++; 1028 } 1029 } 1030 break; 1031 1032 // USIC/SUSIC specific part of initialization byte array 1033 case USIC_SUSIC: 1034 int numCards = numInputCards() + numOutputCards(); 1035 int numFours = numCards/4; 1036 if ( (numCards-(numFours*4)) > 0) numFours ++; // Round up if not even multiple 1037 initBytes[3] = (byte)numFours; 1038 for (int i=0,j=0;i<numFours;i++,j+=4) 1039 { 1040 code = cardTypeLocation[j]; 1041 code = code + (cardTypeLocation[j+1] * 4); 1042 code = code + (cardTypeLocation[j+2] * 16); 1043 code = code + (cardTypeLocation[j+3] * 64); 1044 initBytes[nInitBytes] = (byte)code; 1045 nInitBytes ++; 1046 } 1047 break; 1048 1049 /* CPNODE specific part of initialization byte array 1050 * The I message has the node configuration options following the 1051 * DL bytes, followed by the defined number of I/O cards. 1052 * 0 1 2 3 4 5 6 7 - 12 1053 * <NDP><dH><dL><cpOPTS1><cpOPTS2><cpNI><cpNO> <rfe 8> 1054 */ 1055 case CPNODE: 1056 nInitBytes = 3; 1057 // ------------------------- 1058 // Pack the two option bytes 1059 // ------------------------- 1060 for (int i=0,j=0;i<2;i++,j+=8) 1061 { 1062 code = cpnodeOptions[j]; 1063 code = code + (cpnodeOptions[j+1]*2); 1064 code = code + (cpnodeOptions[j+2]*4); 1065 code = code + (cpnodeOptions[j+3]*8); 1066 code = code + (cpnodeOptions[j+4]*16); 1067 code = code + (cpnodeOptions[j+5]*32); 1068 code = code + (cpnodeOptions[j+6]*64); 1069 code = code + (cpnodeOptions[j+7]*128); 1070 initBytes[nInitBytes] = (byte)code; 1071 nInitBytes++; 1072 } 1073 // ------------------------------------- 1074 // Configured input and output byte count 1075 // ------------------------------------- 1076 initBytes[nInitBytes++] = (byte)numInputCards(); 1077 initBytes[nInitBytes++] = (byte)numOutputCards(); 1078 1079 // -------------------------- 1080 // future to be defined bytes 1081 // -------------------------- 1082 for (int i=nInitBytes; i<INITMSGLEN+1; i++) 1083 { 1084 initBytes[i] = (byte)0xFF; 1085 nInitBytes++; 1086 } 1087 1088 break; 1089 1090 /* CPMEGA specific part of initialization byte array 1091 * The I message has the node configuration options following the 1092 * DL bytes, followed by the defined number of I/O cards. 1093 * 0 1 2 3 4 5 6 7 - 12 1094 * <NDP><dH><dL><cpOPTS1><cpOPTS2><cpNI><cpNO> <rfe 8> 1095 */ 1096 case CPMEGA: 1097 nInitBytes = 3; 1098 // ------------------------- 1099 // Pack the two option bytes 1100 // ------------------------- 1101 for (int i=0,j=0;i<2;i++,j+=8) 1102 { 1103 code = cpnodeOptions[j]; 1104 code = code + (cpnodeOptions[j+1]*2); 1105 code = code + (cpnodeOptions[j+2]*4); 1106 code = code + (cpnodeOptions[j+3]*8); 1107 code = code + (cpnodeOptions[j+4]*16); 1108 code = code + (cpnodeOptions[j+5]*32); 1109 code = code + (cpnodeOptions[j+6]*64); 1110 code = code + (cpnodeOptions[j+7]*128); 1111 initBytes[nInitBytes] = (byte)code; 1112 nInitBytes++; 1113 } 1114 // ------------------------------------- 1115 // Configured input and output byte count 1116 // ------------------------------------- 1117 initBytes[nInitBytes++] = (byte)numInputCards(); 1118 initBytes[nInitBytes++] = (byte)numOutputCards(); 1119 1120 // -------------------------- 1121 // future to be defined bytes 1122 // -------------------------- 1123 for (int i=nInitBytes; i<INITMSGLEN+1; i++) 1124 { 1125 initBytes[i] = (byte)0xFF; 1126 nInitBytes++; 1127 } 1128 1129 break; 1130 1131 default: 1132 log.error("Invalid node type ({}) in SerialNode Init Message", nodeType); 1133 1134 } 1135 1136// here add specific initialization for other type of card 1137 1138 // count the number of DLE's to be inserted 1139 int nDLE = 0; 1140 for (int i = 1; i < nInitBytes; i++) { 1141 if ((initBytes[i] == 2) || (initBytes[i] == 3) || (initBytes[i] == 16)) { 1142 nDLE++; 1143 } 1144 } 1145 1146 // create a Serial message and add initialization bytes 1147 SerialMessage m = new SerialMessage(nInitBytes + nDLE + 2); 1148 m.setElement(0, getNodeAddress() + 65); // node address 1149 m.setElement(1, 73); // 'I' 1150 // add initialization bytes 1151 int k = 2; 1152 for (int i = 0; i < nInitBytes; i++) { 1153 // perform C/MRI required DLE processing 1154 if ((initBytes[i] == 2) || (initBytes[i] == 3) || (initBytes[i] == 16)) { 1155 m.setElement(k, 16); // DLE 1156 k++; 1157 } 1158 // add initialization byte 1159 m.setElement(k, initBytes[i]); 1160 k++; 1161 } 1162 return m; 1163 } 1164 1165 /** 1166 * Create an Transmit packet (SerialMessage) 1167 */ 1168 @Override 1169 public AbstractMRMessage createOutPacket() { 1170 // Count the number of DLE's to be inserted 1171 int nOutBytes = numOutputCards() * (bitsPerCard / 8); 1172 int nDLE = 0; 1173 byte[] oA; // current values of the output bits for this node 1174 1175 oA = outputArray.clone(); 1176 1177 for (int i = 0; i < nOutBytes; i++) { 1178 if ((oA[i] == 2) || (oA[i] == 3) || (oA[i] == 16)) { 1179 nDLE++; 1180 } 1181 } 1182 // Create a Serial message and add initial bytes 1183 SerialMessage m = new SerialMessage(nOutBytes + nDLE + 2); 1184 m.setElement(0, getNodeAddress() + 65); // node address 1185 m.setElement(1, 84); // 'T' 1186 // Add output bytes 1187 int k = 2; 1188 for (int i = 0; i < nOutBytes; i++) { 1189 // perform C/MRI required DLE processing 1190 if ((oA[i] == 2) || (oA[i] == 3) || (oA[i] == 16)) { 1191 m.setElement(k, 16); // DLE 1192 k++; 1193 } 1194 // add output byte 1195 m.setElement(k, oA[i]); 1196 k++; 1197 } 1198 return m; 1199 } 1200 boolean warned = false; 1201 1202 void warn(String s) { 1203 if (warned) { 1204 return; 1205 } 1206 warned = true; 1207 log.warn("C/MRI - {}", s); 1208 } 1209 1210 /** 1211 * Use the contents of the poll reply to mark changes 1212 * 1213 * @param l Reply to a poll operation 1214 */ 1215 public void markChanges(SerialReply l) { 1216 try { 1217 for (int i = 0; i <= lastUsedSensor; i++) { 1218 if (sensorArray[i] == null) { 1219 continue; // skip ones that don't exist 1220 } 1221 int loc = i / 8; 1222 if (loc + 2 >= l.getNumDataElements()) { 1223 continue; // skip this one as not in data, so not changed 1224 } 1225 int bit = i % 8; 1226 boolean value = (((l.getElement(loc + 2) >> bit) & 0x01) == 1) ^ sensorArray[i].getInverted(); // byte 2 is first of data 1227 1228 // if (log.isDebugEnabled()) log.debug("markChanges loc="+loc+" bit="+bit+" is "+value+ 1229 // " tempSetting is "+((sensorTempSetting[i] == Sensor.ACTIVE)?"active ":"inactive ")+ 1230 // "lastSetting is "+((sensorLastSetting[i] == Sensor.ACTIVE)?"active ":"inactive ") 1231 // ); 1232 if (value) { 1233 // considered ACTIVE 1234 if (((sensorTempSetting[i] == Sensor.ACTIVE) 1235 || (sensorTempSetting[i] == Sensor.UNKNOWN)) 1236 && (sensorLastSetting[i] != Sensor.ACTIVE)) { // see comment at top; allows persistent local changes 1237 sensorLastSetting[i] = Sensor.ACTIVE; 1238 sensorArray[i].setKnownState(Sensor.ACTIVE); 1239 // log.debug("set active"); 1240 } 1241 // save for next time 1242 sensorTempSetting[i] = Sensor.ACTIVE; 1243 ((SerialSensor)sensorArray[i]).lastStateFromLayout = Sensor.ACTIVE; 1244 } else { 1245 // considered INACTIVE 1246 if (((sensorTempSetting[i] == Sensor.INACTIVE) 1247 || (sensorTempSetting[i] == Sensor.UNKNOWN)) 1248 && (sensorLastSetting[i] != Sensor.INACTIVE)) { // see comment at top; allows persistent local changes 1249 sensorLastSetting[i] = Sensor.INACTIVE; 1250 sensorArray[i].setKnownState(Sensor.INACTIVE); 1251 // log.debug("set inactive"); 1252 } 1253 // save for next time 1254 sensorTempSetting[i] = Sensor.INACTIVE; 1255 ((SerialSensor)sensorArray[i]).lastStateFromLayout = Sensor.INACTIVE; 1256 } 1257 } 1258 } catch (JmriException e) { 1259 log.error("exception in markChanges", e); 1260 } 1261 } 1262 1263 /** 1264 * The numbers here are 0 to MAXSENSORS, not 1 to MAXSENSORS. 1265 * 1266 * @param s Sensor object 1267 * @param i 0 to MAXSENSORS number of sensor's input bit on this node 1268 */ 1269 public void registerSensor(Sensor s, int i) { 1270 // validate the sensor ordinal 1271 if ((i < 0) || (i > ((numInputCards() * bitsPerCard) - 1)) || (i > MAXSENSORS)) { 1272 log.error("Unexpected sensor ordinal in registerSensor: {}", Integer.toString(i + 1)); 1273 return; 1274 } 1275 hasActiveSensors = true; 1276 if (sensorArray[i] == null) { 1277 sensorArray[i] = s; 1278 if (lastUsedSensor < i) { 1279 lastUsedSensor = i; 1280 } 1281 } else { 1282 // multiple registration of the same sensor 1283 log.warn("multiple registration of same sensor: CS{}", Integer.toString((getNodeAddress() * SerialSensorManager.SENSORSPERUA) + i + 1)); // TODO multichar prefix 1284 } 1285 } 1286 1287 int timeout = 0; 1288 1289 /** 1290 * @return true if polling active and currently OK 1291 */ 1292 public boolean isPollingOK() { 1293 return timeout == 0; 1294 } 1295 1296 /** 1297 * 1298 * @return true if initialization required 1299 */ 1300 @Override 1301 public boolean handleTimeout(AbstractMRMessage m, AbstractMRListener l) { 1302 timeout++; 1303 // normal to timeout in response to init, output 1304 if (m.getElement(1) != 0x50) { 1305 return false; 1306 } 1307 1308 // see how many polls missed 1309 if (log.isDebugEnabled()) { 1310 log.warn("Timeout to poll for UA={}: consecutive timeouts: {}", getNodeAddress(), timeout); 1311 } 1312 1313 if (timeout > 5) { // enough, reinit 1314 // reset timeout count to one to give polls another try 1315 // but not zero because that means operating OK 1316 timeout = 1; 1317 // reset poll and send control so will retry initialization 1318 setMustSend(); 1319 1320 // force sensors to UNKNOWN, including callbacks; might take some time 1321 for (int i = 0; i <= lastUsedSensor; i++) { 1322 if (sensorArray[i] != null) { 1323 sensorLastSetting[i] = Sensor.UNKNOWN; 1324 sensorTempSetting[i] = Sensor.UNKNOWN; 1325 try { 1326 sensorArray[i].setKnownState(Sensor.UNKNOWN); 1327 } catch (jmri.JmriException e) { 1328 log.error("unexpected exception setting sensor i={} on node {}", i, getNodeAddress(), e); 1329 } 1330 } 1331 } 1332 return true; // tells caller to force init 1333 } else { 1334 return false; 1335 } 1336 } 1337 1338 @Override 1339 public void resetTimeout(AbstractMRMessage m) { 1340 if (timeout > 0) { 1341 log.debug("Reset {} timeout count", timeout); 1342 } 1343 timeout = 0; 1344 } 1345 1346 private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SerialNode.class); 1347}