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