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