001package jmri;
002
003import javax.annotation.CheckForNull;
004
005import javax.annotation.Nonnull;
006
007import org.slf4j.Logger;
008import org.slf4j.LoggerFactory;
009
010/**
011 * Utilities for coding/decoding NMRA {@literal S&RP} DCC packets.
012 * <p>
013 * Packets are (now) represented by an array of bytes. Preamble/postamble not
014 * included. Note that this is a data representation, _not_ a representation of
015 * the waveform! But this is a class, which might eventually also form a
016 * representation object.
017 * <p>
018 * This is meant to be a general Java NMRA implementation, so does NOT use JMRI
019 * utilities. In particular, it returns null instead of throwing JmriException
020 * for invalid requests. Callers need to check upstream.
021 * <p>
022 * The function is provided by static member functions; objects of this class
023 * should not be created.
024 * <p>
025 * Note that these functions are structured by packet type, not by what want to
026 * do. E.g. there are functions to create specific packet formats instead of a
027 * general "loco speed packet" routine which figures out which type of packet to
028 * use. Those decisions are to be made somewhere else.
029 * <p>
030 * Range and value checking is intended to be aggressive; if we can check, we
031 * should. Problems are reported as warnings.
032 * <p>
033 * The basic function is to build a packet with proper addressing, etc:
034 * <ul>
035 * <li>oneBytePacket
036 * <li>twoBytePacket
037 * <li>threeBytePacket
038 * <li>fourBytePacket
039 * </ul>
040 * On top of those are built various special-purpose packet formats.
041 * <hr>
042 * This file is part of JMRI.
043 * <p>
044 * JMRI is free software; you can redistribute it and/or modify it under the
045 * terms of version 2 of the GNU General Public License as published by the Free
046 * Software Foundation. See the "COPYING" file for a copy of this license.
047 * <p>
048 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
049 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
050 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
051 *
052 * @author Bob Jacobsen Copyright (C) 2001, 2003
053 */
054@edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS",
055        justification = "null returned is documented in each method to mean no valid result")
056public class NmraPacket {
057
058    static final public int accIdLowLimit = 1;
059    static final public int accIdHighLimit = 2044;
060    static final public int accIdAltHighLimit = 2048;
061
062    /**
063     * Create a packet containing a decoder idle instruction.
064     *
065     * @return the packet as a byte array or null if the address is not valid
066     */
067    @CheckForNull
068    public static byte[] idlePacket() {
069        byte[] retVal;
070        retVal = new byte[3];
071        retVal[0] = (byte) (0xFF);  // address byte for decoder idle
072        retVal[1] = (byte) (0);     // decoder idle instruction
073        retVal[2] = (byte) (0xFF);  // checksum byte
074        return retVal;
075    }
076
077    /**
078     * Create a packet containing a one-byte instruction.
079     *
080     * @param address  the address to send the instruction to
081     * @param longAddr true if address is long, false otherwise
082     * @param byte1    the byte to send as an instruction
083     * @return the packet as a byte array or null if the address is not valid
084     */
085    @CheckForNull
086    public static byte[] oneBytePacket(int address, boolean longAddr, byte byte1) {
087        if (!addressCheck(address, longAddr)) {
088            return null;  // failed!
089        }
090
091        // end sanity check, format output
092        byte[] retVal;
093        if (longAddr) {
094            // long address form
095            retVal = new byte[4];
096            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
097            retVal[1] = (byte) (address & 0xFF);
098            retVal[2] = byte1;
099            retVal[3] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2]);
100        } else {
101            // short address form
102            retVal = new byte[3];
103            retVal[0] = (byte) (address & 0xFF);
104            retVal[1] = byte1;
105            retVal[2] = (byte) (retVal[0] ^ retVal[1]);
106        }
107        return retVal;
108    }
109
110    /**
111     * Create a packet containing a two-byte instruction.
112     *
113     * @param address  the address to send the instruction to
114     * @param longAddr true if address is long, false otherwise
115     * @param byte1    first byte in the instruction
116     * @param byte2    second byte in the instruction
117     * @return the packet as a byte array or null if the address is not valid
118     */
119    @CheckForNull
120    public static byte[] twoBytePacket(int address, boolean longAddr, byte byte1, byte byte2) {
121        if (!addressCheck(address, longAddr)) {
122            return null;  // failed!
123        }
124
125        // end sanity check, format output
126        byte[] retVal;
127        if (longAddr) {
128            // long address form
129            retVal = new byte[5];
130            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
131            retVal[1] = (byte) (address & 0xFF);
132            retVal[2] = byte1;
133            retVal[3] = byte2;
134            retVal[4] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3]);
135        } else {
136            // short address form
137            retVal = new byte[4];
138            retVal[0] = (byte) (address & 0xFF);
139            retVal[1] = byte1;
140            retVal[2] = byte2;
141            retVal[3] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2]);
142        }
143        return retVal;
144    }
145
146    /**
147     * Create a packet containing a three-byte instruction.
148     *
149     * @param address  the address to send the instruction to
150     * @param longAddr true if address is long, false otherwise
151     * @param byte1    first byte in the instruction
152     * @param byte2    second byte in the instruction
153     * @param byte3    third byte in the instruction
154     * @return the packet as a byte array or null if the address is not valid
155     */
156    @CheckForNull
157    public static byte[] threeBytePacket(int address, boolean longAddr, byte byte1, byte byte2, byte byte3) {
158        if (!addressCheck(address, longAddr)) {
159            return null;  // failed!
160        }
161
162        // end sanity check, format output
163        byte[] retVal;
164        if (longAddr) {
165            // long address form
166            retVal = new byte[6];
167            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
168            retVal[1] = (byte) (address & 0xFF);
169            retVal[2] = byte1;
170            retVal[3] = byte2;
171            retVal[4] = byte3;
172            retVal[5] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3] ^ retVal[4]);
173        } else {
174            // short address form
175            retVal = new byte[5];
176            retVal[0] = (byte) (address & 0xFF);
177            retVal[1] = byte1;
178            retVal[2] = byte2;
179            retVal[3] = byte3;
180            retVal[4] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3]);
181        }
182        return retVal;
183    }
184
185    /**
186     * Create a packet containing a four-byte instruction.
187     *
188     * @param address  the address to send the instruction to
189     * @param longAddr true if address is long, false otherwise
190     * @param byte1    first byte in the instruction
191     * @param byte2    second byte in the instruction
192     * @param byte3    third byte in the instruction
193     * @param byte4    forth byte in the instruction
194     * @return the packet as a byte array or null if the address is not valid
195     */
196    @CheckForNull
197    public static byte[] fourBytePacket(int address, boolean longAddr, byte byte1, byte byte2, byte byte3, byte byte4) {
198        if (!addressCheck(address, longAddr)) {
199            return null;  // failed!
200        }
201
202        // end sanity check, format output
203        byte[] retVal;
204        if (longAddr) {
205            // long address form
206            retVal = new byte[7];
207            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
208            retVal[1] = (byte) (address & 0xFF);
209            retVal[2] = byte1;
210            retVal[3] = byte2;
211            retVal[4] = byte3;
212            retVal[5] = byte4;
213            retVal[6] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3] ^ retVal[4] ^ retVal[5]);
214        } else {
215            // short address form
216            retVal = new byte[6];
217            retVal[0] = (byte) (address & 0xFF);
218            retVal[1] = byte1;
219            retVal[2] = byte2;
220            retVal[3] = byte3;
221            retVal[4] = byte4;
222            retVal[5] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3] ^ retVal[4]);
223        }
224        return retVal;
225    }
226
227    public static byte[] accDecoderPkt(int addr, int active, int outputChannel) {
228        // From the NMRA RP:
229        // 0 10AAAAAA 0 1AAACDDD 0 EEEEEEEE 1
230        // Accessory Digital Decoders can be designed to control momentary or
231        // constant-on devices, the duration of time each output is active being controlled
232        // by configuration variables CVs #515 through 518. Bit 3 of the second byte "C" is
233        // used to activate or deactivate the addressed device. (Note if the duration the
234        // device is intended to be on is less than or equal the set duration, no deactivation
235        // is necessary.) Since most devices are paired, the convention is that bit "0" of
236        // the second byte is used to distinguish between which of a pair of outputs the
237        // accessory decoder is activating or deactivating. Bits 1 and 2 of byte two is used
238        // to indicate which of 4 pairs of outputs the packet is controlling. The significant
239        // bits of the 9 bit address are bits 4-6 of the second data byte. By convention
240        // these three bits are in ones complement. The use of bit 7 of the second byte
241        // is reserved for future use.
242
243        // Note that A=1 is the first (lowest) valid address field, and the
244        // largest is 512!  I don't know why this is, but it gets the
245        // right hardware addresses
246        if (addr < 1 || addr > 511) {
247            log.error("invalid address {}", addr);
248            //return null;
249            throw new IllegalArgumentException();
250        }
251        if (active < 0 || active > 1) {
252            log.error("invalid active (C) bit {}", addr);
253            return null;
254        }
255        if (outputChannel < 0 || outputChannel > 7) {
256            log.error("invalid output channel {}", addr);
257            return null;
258        }
259
260        int lowAddr = addr & 0x3F;
261        int highAddr = ((~addr) >> 6) & 0x07;
262
263        byte[] retVal = new byte[3];
264
265        retVal[0] = (byte) (0x80 | lowAddr);
266        retVal[1] = (byte) (0x80 | (highAddr << 4) | (active << 3) | outputChannel & 0x07);
267        retVal[2] = (byte) (retVal[0] ^ retVal[1]);
268
269        return retVal;
270    }
271
272    /**
273     * Provide a basic operations mode accessory CV programming packet.
274     * <br><br>
275     * From the NMRA Standard: Basic Accessory Decoder Packet address for
276     * operations mode programming
277     * <br><br>
278     * 10AAAAAA 0 1AAACDDD
279     * <br><br>
280     * Where DDD is used to indicate the output whose CVs are being modified and
281     * C=1.
282     * <br>
283     * If CDDD= 0000 then the CVs refer to the entire decoder.
284     * <br><br>
285     * The resulting packet would be
286     * <br><br>
287     * {preamble} 10AAAAAA 0 1AAACDDD 0 (1110CCVV 0 VVVVVVVV 0 DDDDDDDD) 0
288     * EEEEEEEE 1
289     *
290     * @param addr          the decoder address
291     * @param active        1 or 0
292     * @param outputChannel the output on the accessory
293     * @param cvNum         the CV
294     * @param data          the data
295     * @return a packet
296     */
297    public static byte[] accDecoderPktOpsMode(int addr, int active, int outputChannel, int cvNum, int data) {
298
299        if (addr < 1 || addr > 511) {
300            log.error("invalid address {}", addr);
301            throw new IllegalArgumentException();
302        }
303        if (active < 0 || active > 1) {
304            log.error("invalid active (C) bit {}", addr);
305            return null;
306        }
307        if (outputChannel < 0 || outputChannel > 7) {
308            log.error("invalid output channel {}", addr);
309            return null;
310        }
311
312        if (cvNum < 1 || cvNum > 1024) {
313            log.error("invalid CV number {}", cvNum);
314            return null;
315        }
316
317        if (data < 0 || data > 255) {
318            log.error("invalid data {}", data);
319            return null;
320        }
321
322        int lowAddr = addr & 0x3F;
323        int highAddr = ((~addr) >> 6) & 0x07;
324//        log.info("addr = {} active = {} outputChannel = {} cvNum = {} data = {}", addr, active, outputChannel, cvNum, data);
325//        log.info("hex lowAddr = {} highAddr = {}", String.format("%H", lowAddr), String.format("%H", highAddr));
326//        log.info("lowAddr = {} highAddr = {}", lowAddr, highAddr);
327
328        int lowCVnum = (cvNum - 1) & 0xFF;
329        int highCVnum = ((cvNum - 1) >> 8) & 0x03;
330
331        byte[] retVal = new byte[6];
332        retVal[0] = (byte) (0x80 | lowAddr);
333        retVal[1] = (byte) (0x80 | (highAddr << 4) | (active << 3) | outputChannel & 0x07);
334        retVal[2] = (byte) (0xEC | highCVnum);
335        retVal[3] = (byte) (lowCVnum);
336        retVal[4] = (byte) (0xFF & data);
337        retVal[5] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3] ^ retVal[4]);
338
339        return retVal;
340    }
341
342    /**
343     * Provide a legacy operations mode accessory CV programming packet via a
344     * simplified interface, given a decoder address.
345     * <br><br>
346     * From the NMRA Standard: The format for Accessory Decoder Configuration
347     * Variable Access Instructions is: {preamble} 0 10AAAAAA 0 0AAA11VV 0
348     * VVVVVVVV 0 DDDDDDDD 0 EEEEEEEE 1 Where: A = Decoder address bits V =
349     * Desired CV address - (CV 513 = 10 00000000) D = Data for CV
350     * <br><br>
351     * This is the old "legacy" format, newer decoders use the "Basic Accessory
352     * Decoder Packet"
353     *
354     * @param decAddr Address of decoder, in the range 1 to 511
355     * @param cvNum   the CV
356     * @param data    the data
357     * @return a packet
358     */
359    public static byte[] accDecPktOpsModeLegacy(int decAddr, int cvNum, int data) {
360
361        if (decAddr < 1 || decAddr > 511) {
362            log.error("invalid address {}", decAddr);
363            return null;
364        }
365
366        if (cvNum < 1 || cvNum > 1024) {
367            log.error("invalid CV number {}", cvNum);
368            return null;
369        }
370
371        if (data < 0 || data > 255) {
372            log.error("invalid data {}", data);
373            return null;
374        }
375
376        int lowAddr = decAddr & 0x3F;
377        int highAddr = ((~decAddr) >> 6) & 0x07;
378
379        int lowCVnum = (cvNum - 1) & 0xFF;
380        int highCVnum = ((cvNum - 1) >> 8) & 0x03;
381
382        byte[] retVal = new byte[5];
383        retVal[0] = (byte) (0x80 | lowAddr);
384        retVal[1] = (byte) (0x0C | (highAddr << 4) | highCVnum);
385        retVal[2] = (byte) (lowCVnum);
386        retVal[3] = (byte) (0xFF & data);
387        retVal[4] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3]);
388
389        return retVal;
390    }
391
392    /**
393     * Create a signal accessory instruction packet.
394     * <p>
395     * From the RP: Extended Accessory Decoder Control Packet Format The
396     * Extended Accessory Decoder Control Packet is included for the purpose of
397     * transmitting aspect control to signal decoders or data bytes to more
398     * complex accessory decoders. Each signal head can display one aspect at a
399     * time.
400     * <p>
401     * {@code {preamble} 0 10AAAAAA 0 0AAA0AA1 0 000XXXXX 0 EEEEEEEE 1}
402     * <p>
403     * XXXXX is for a single head. A value of 00000 for XXXXX indicates the
404     * absolute stop aspect. All other aspects represented by the values for
405     * XXXXX are determined by the signaling system used and the prototype being
406     * modeled.
407     * <p>
408     * Despite this being an NMRA standard, or perhaps because of it, the
409     * addressing is not clear. The other form of packet generated by
410     * {@link #altAccSignalDecoderPkt(int, int)} seems to be the one thats
411     * generally supported by hardware.
412     *
413     * @param outputAddr Address of accessory output, starting with 1 and a
414     *                   maximum of 2044
415     * @param aspect     Aspect Number starting with 0 and a maximum of 31
416     * @return the instruction packet
417     */
418    @Nonnull
419    public static byte[] accSignalDecoderPkt(int outputAddr, int aspect) {
420
421        if (outputAddr < accIdLowLimit || outputAddr > accIdHighLimit) {
422            log.error("invalid signal decoder address {}", outputAddr);
423        }
424
425        outputAddr -= 1; // Make the address 0 based
426        int lowAddr = (outputAddr & 0x03);  // Output Pair Address
427        int boardAddr = (outputAddr >> 2) + 1; // Board Address
428
429        return accSignalDecoderPktCommon(lowAddr, boardAddr, aspect);
430    }
431
432    /**
433     * Provide an extended operations mode accessory CV programming packet via a
434     * simplified interface, given a signal address.
435     * <br><br>
436     * From the NMRA Standard: Extended Decoder Packet address for operations
437     * mode programming
438     * <br><br>
439     * 10AAAAAA 0 0AAA0AA1
440     * <br><br>
441     * <br>
442     * The resulting packet would be
443     * <br><br>
444     * {preamble} 10AAAAAA 0 0AAA0AA1 0 (1110CCVV 0 VVVVVVVV 0 DDDDDDDD) 0
445     * EEEEEEEE 1
446     *
447     * @param addr  the signal address
448     * @param cvNum the CV
449     * @param data  the data
450     * @return a packet
451     */
452    public static byte[] accSignalDecoderPktOpsMode(int addr, int cvNum, int data) {
453
454        if (addr < 1 || addr > 2044) {
455            log.error("invalid address {}", addr);
456            throw new IllegalArgumentException();
457        }
458
459        if (cvNum < 1 || cvNum > 1024) {
460            log.error("invalid CV number {}", cvNum);
461            return null;
462        }
463
464        if (data < 0 || data > 255) {
465            log.error("invalid data {}", data);
466            return null;
467        }
468
469        int outputAddr = addr - 1; // Make the address 0 based
470        int lowAddr = (outputAddr & 0x03);
471        int boardAddr = (outputAddr >> 2) + 1; // Board Address
472        int midAddr = (boardAddr & 0x3F);
473        int highAddr = (~(boardAddr >> 6)) & 0x07;
474
475        int lowCVnum = (cvNum - 1) & 0xFF;
476        int highCVnum = ((cvNum - 1) >> 8) & 0x03;
477
478        byte[] retVal = new byte[6];
479        retVal[0] = (byte) (0x80 | midAddr);
480        retVal[1] = (byte) (0x01 | (highAddr << 4) | (lowAddr << 1));
481        retVal[2] = (byte) (0xEC | highCVnum);
482        retVal[3] = (byte) (lowCVnum);
483        retVal[4] = (byte) (0xFF & data);
484        retVal[5] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3] ^ retVal[4]);
485
486        return retVal;
487    }
488
489    /**
490     * Determine if a packet is an Extended Accessory Decoder Control Packet
491     * otherwise known as a Signal Decoder Packet.
492     * <p>
493     * This inverts the computation done by the
494     * {@link #accSignalDecoderPkt(int, int)} method.
495     *
496     * @param packet a DCC packet to inspect
497     * @return true if a Signal Decoder Packet; false otherwise
498     */
499    public static boolean isAccSignalDecoderPkt(byte[] packet) {
500        if (packet == null || packet.length != 3 && packet.length != 4) {
501            return false;   // allow ECC to be present or not
502        }
503        if ((packet[0] & 0xC0) != 0x80) {
504            return false;
505        }
506        if ((packet[1] & 0x01) != 0x01) {
507            return false;
508        }
509        if ((packet[2] & 0xE0) != 0x00) {
510            return false;
511        }
512        return true;
513    }
514
515    /**
516     * Determine if a packet is a Basic Accessory Decoder Packet address for
517     * operations mode programming.
518     * <p>
519     * This inverts the computation done by the
520     * {@link #accDecPktOpsMode(int, int, int)} method.
521     *
522     * @param packet the packet to test
523     * @return true if the packet is a basic accessory decoder packet address
524     */
525    public static boolean isAccDecoderPktOpsMode(byte[] packet) {
526        if (packet.length != 5 && packet.length != 6) {
527            return false;   // allow ECC to be present or not
528        }
529        if ((packet[0] & 0xC0) != 0x80) {
530            return false;
531        }
532        if (((packet[1] & 0x88) != 0x88) && ((packet[1] & 0x8F) != 0x80)) {
533            return false;
534        }
535        if ((packet[2] & 0xFC) != 0xEC) {
536            return false;
537        }
538        return true;
539    }
540
541    /**
542     * Determine if a packet is a Legacy Accessory Decoder Packet address for
543     * operations mode programming.
544     * <p>
545     * This inverts the computation done by the
546     * {@link #accDecoderPktOpsModeLegacy(int, int, int)} method.
547     *
548     * @param packet the packet to extract the address from
549     * @return the address
550     */
551    public static boolean isAccDecoderPktOpsModeLegacy(byte[] packet) {
552        if (packet.length != 4 && packet.length != 5) {
553            return false;   // allow ECC to be present or not
554        }
555        if ((packet[0] & 0xC0) != 0x80) {
556            return false;
557        }
558        if ((packet[1] & 0x8C) != 0x0C) {
559            return false;
560        }
561        return true;
562    }
563
564    /**
565     * Recover the decoder address from a Legacy Accessory Decoder Packet Ops
566     * Mode Packet.
567     *
568     * @param packet the packet to extract the address from
569     * @return the decoder address
570     */
571    public static int getAccDecPktOpsModeLegacyAddress(byte[] packet) {
572        int midAddr = packet[0] & 0x3f;
573        int hiAddr = ((~packet[1]) & 0x70) >> 4;
574
575        return (hiAddr << 6 | midAddr);
576    }
577
578    /**
579     * Recover the equivalent accessory address from a Legacy Accessory Decoder
580     * Packet Ops Mode Packet.
581     *
582     * @param packet the packet to extract the address from
583     * @return the accessory address
584     */
585    public static int getAccDecoderPktOpsModeLegacyAddress(byte[] packet) {
586        int midAddr = packet[0] & 0x3f;
587        int hiAddr = ((~packet[1]) & 0x70) >> 4;
588
589        int boardAddr = (hiAddr << 6 | midAddr) - 1;
590
591        return ((boardAddr << 2)) + 1;
592    }
593
594    /**
595     * Recover the accessory address from a Basic Accessory Decoder Packet Ops
596     * Mode Packet.
597     *
598     * @param packet the packet to extract the address from
599     * @return the accessory address
600     */
601    public static int getAccDecoderPktOpsModeAddress(byte[] packet) {
602        int midAddr = packet[0] & 0x3f;
603        int lowAddr = (packet[1] & 0x06) >> 1;
604        int hiAddr = ((~packet[1]) & 0x70) >> 4;
605
606        int boardAddr = (hiAddr << 6 | midAddr) - 1;
607
608        return ((boardAddr << 2) | lowAddr) + 1;
609    }
610
611    /**
612     * Recover the equivalent decoder address from a Basic Accessory Decoder
613     * Packet Ops Mode Packet.
614     *
615     * @param packet the packet to extract the address from
616     * @return the decoder address
617     */
618    public static int getAccDecPktOpsModeAddress(byte[] packet) {
619        int lowAddr = packet[0] & 0x3f;
620        int hiAddr = ((~packet[1]) & 0x70) >> 4;
621
622        return (hiAddr << 6 | lowAddr);
623    }
624
625    /**
626     * Recover the 1-based output address from an Extended Accessory Decoder
627     * Control Packet otherwise known as a Signal Decoder Packet.
628     *
629     * @param packet the packet to extract the address from
630     * @return the address
631     */
632    public static int getAccSignalDecoderPktAddress(byte[] packet) {
633        int midAddr = packet[0] & 0x3f;
634        int lowAddr = (packet[1] & 0x0E) >> 1;
635        int hiAddr = ((~packet[1]) & 0x70) >> 4;
636
637        int boardAddr = (hiAddr << 6 | midAddr) - 1;
638
639        return ((boardAddr << 2) | lowAddr) + 1;
640    }
641
642    /**
643     * An alternative interpretation of RP-9.2.1 due to an omission in the
644     * address definition of extended accessory packets. Since there is no such
645     * description for the address bits of the Extended Accessory Decoder
646     * Control Packet, this interpretation assumes that the least significant
647     * bits of the extended packet type are still in bits 1 and 2 of byte two,
648     * see Basic Accessory Packet.
649     *
650     * @param outputAddr Address of accessory output, starting with 1 and a
651     *                   maximum of 2044
652     * @param aspect     Aspect Number starting with 0 and a maximum of 31
653     * @return a packet
654     */
655    @Nonnull
656    public static byte[] altAccSignalDecoderPkt(int outputAddr, int aspect) {
657
658        if (outputAddr < 1 || outputAddr > 2048) {
659            log.error("invalid signal decoder address {}", outputAddr);
660        }
661
662        outputAddr -= 1; // Make the address 0 based
663        int lowAddr = (outputAddr & 0x03);  // Output Pair Address
664        int boardAddr = (outputAddr >> 2); // Board Address
665
666        return accSignalDecoderPktCommon(lowAddr, boardAddr, aspect);
667    }
668
669    /**
670     * Provide an extended operations mode accessory CV programming packet via a
671     * simplified interface, given a signal address, using the alternative
672     * interpretation of S-9.2.1, due to an omission in the address definition
673     * of extended accessory packets.
674     *
675     * @param addr  the signal address
676     * @param cvNum the CV
677     * @param data  the data
678     * @return a packet
679     */
680    public static byte[] altAccSignalDecoderPktOpsMode(int addr, int cvNum, int data) {
681
682        if (addr < 1 || addr > 2044) {
683            log.error("invalid address {}", addr);
684            throw new IllegalArgumentException();
685        }
686
687        if (cvNum < 1 || cvNum > 1024) {
688            log.error("invalid CV number {}", cvNum);
689            return null;
690        }
691
692        if (data < 0 || data > 255) {
693            log.error("invalid data {}", data);
694            return null;
695        }
696
697        int outputAddr = addr - 1; // Make the address 0 based
698        int lowAddr = (outputAddr & 0x03);
699        int boardAddr = (outputAddr >> 2); // Board Address
700        int midAddr = (boardAddr & 0x3F);
701        int highAddr = (~(boardAddr >> 6)) & 0x07;
702
703        int lowCVnum = (cvNum - 1) & 0xFF;
704        int highCVnum = ((cvNum - 1) >> 8) & 0x03;
705
706        byte[] retVal = new byte[6];
707        retVal[0] = (byte) (0x80 | midAddr);
708        retVal[1] = (byte) (0x01 | (highAddr << 4) | (lowAddr << 1));
709        retVal[2] = (byte) (0xEC | highCVnum);
710        retVal[3] = (byte) (lowCVnum);
711        retVal[4] = (byte) (0xFF & data);
712        retVal[5] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3] ^ retVal[4]);
713
714        return retVal;
715    }
716
717    @Nonnull
718    protected static byte[] accSignalDecoderPktCommon(int lowAddr, int boardAddr, int aspect) {
719
720        if (aspect < 0 || aspect > 31) {
721            log.error("invalid signal decoder aspect {}", aspect);
722        }
723
724        int midAddr = boardAddr & 0x3F;
725        int highAddr = ((~boardAddr) >> 6) & 0x07;
726
727        byte[] retVal = new byte[4];
728        retVal[0] = (byte) (0x80 | midAddr);
729        retVal[1] = (byte) (0x01 | (highAddr << 4) | (lowAddr << 1));
730        retVal[2] = (byte) (0x1F & aspect);
731        retVal[3] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2]);
732
733        return retVal;
734    }
735
736    /**
737     * Recover the 1-based output address from an Accessory Decoder Control
738     * Packet, typically considered a turnout control packet
739     *
740     * @param packet the packet to get an address from
741     * @return the accessory decoder address
742     */
743    public static int getAccDecoderPktAddress(byte[] packet) {
744        // case turnout accessory decoder
745        // from Alex Shepherd
746        int boardAddress = (((~packet[1]) & 0x70) << 2) | (packet[0] & 0x3F);
747        int outputAddress = packet[1] & 0x07;
748        int outputIndex = outputAddress >> 1;
749        return (((boardAddress - 1) << 2) | outputIndex) + 1;
750    }
751
752    /**
753     * Provide an accessory control packet via a simplified interface
754     *
755     * @param number Address of accessory output, starting with 1
756     * @param closed true if the output is to be configured to the "closed",
757     *               a.k.a. the "normal" or "unset" position
758     * @return a packet
759     */
760    public static byte[] accDecoderPkt(int number, boolean closed) {
761        // dBit is the "channel" info, least 7 bits, for the packet
762        // The lowest channel bit represents CLOSED (1) and THROWN (0)
763        int dBits = (((number - 1) & 0x03) << 1);  // without the low CLOSED vs THROWN bit
764        dBits = closed ? (dBits | 1) : dBits;
765
766        // aBits is the "address" part of the nmra packet, which starts with 1
767        // 07/01/05 R.Scheffler - Removed the mask, this will allow any 'too high' numbers
768        // through to accDecoderPkt() above which will log the error if out of bounds. If we
769        // mask it here, then the number will 'wrap' without any indication that it did so.
770        int aBits = (number - 1) >> 2;      // Divide by 4 to get the 'base'
771        aBits += 1;                       // Base is +1
772
773        // cBit is the control bit, we're always setting it active
774        int cBit = 1;
775
776        // get the packet
777        return NmraPacket.accDecoderPkt(aBits, cBit, dBits);
778    }
779
780    /**
781     * Provide a basic operations mode accessory CV programming packet via a
782     * simplified interface, given an accessory address.
783     * <br><br>
784     *
785     * @param accAddr Address of accessory, in the range 1 to 2044
786     * @param cvNum   CV number to access
787     * @param data    Data to be written
788     * @return a packet
789     */
790    public static byte[] accDecoderPktOpsMode(int accAddr, int cvNum, int data) {
791        // dBit is the "channel" info, least 7 bits, for the packet
792        // The lowest channel bit represents CLOSED (1) and THROWN (0)
793        int dBits = (((accAddr - 1) & 0x03) << 1) | 1;  // assume CLOSED
794
795        // aBits is the "address" part of the nmra packet, which starts with 1
796        int aBits = (accAddr - 1) >> 2;      // Divide by 4 to get the 'base'
797        aBits += 1;                       // Base is +1
798
799        // cBit is the control bit, we're always setting it active
800        int cBit = 1;
801
802        // get the packet
803        return NmraPacket.accDecoderPktOpsMode(aBits, cBit, dBits, cvNum, data);
804    }
805
806    /**
807     * Provide a basic operations mode accessory CV programming packet via a
808     * simplified interface, given a decoder address.
809     * <br><br>
810     * From the NMRA Standard: Basic Accessory Decoder Packet address for
811     * operations mode programming
812     * <br><br>
813     * 10AAAAAA 0 1AAACDDD
814     * <br><br>
815     * Where DDD is used to indicate the output whose CVs are being modified and
816     * C=1.
817     * <br>
818     * If CDDD= 0000 then the CVs refer to the entire decoder.
819     * <br><br>
820     * Hence this method uses CDDD= 0000.
821     * <br><br>
822     * For programming individual outputs use
823     * {@link #accDecoderPktOpsMode(int accAddr, int cvNum, int data)}
824     * <br><br>
825     *
826     * @param decAddr Address of decoder, in the range 1 to 511
827     * @param cvNum   CV number to access
828     * @param data    Data to be written
829     * @return a packet
830     */
831    public static byte[] accDecPktOpsMode(int decAddr, int cvNum, int data) {
832        // dBit is the "channel" info, least 7 bits, for the packet
833        // The lowest channel bit represents CLOSED (1) and THROWN (0)
834        int dBits = 0;  // dBits is the "channel" info, CDDD= 0000 indicates the entire decoder
835
836        // aBits is the "address" part of the nmra packet, which starts with 1
837        int aBits = decAddr;
838
839        // cBit is the control bit, CDDD= 0000 indicates the entire decoder
840        int cBit = 0;
841
842        // get the packet
843        return NmraPacket.accDecoderPktOpsMode(aBits, cBit, dBits, cvNum, data);
844    }
845
846    /**
847     * Provide a legacy operations mode accessory CV programming packet via a
848     * simplified interface, given an accessory address.
849     * <br><br>
850     * From the NMRA Standard: The format for Accessory Decoder Configuration
851     * Variable Access Instructions is: {preamble} 0 10AAAAAA 0 0AAA11VV 0
852     * VVVVVVVV 0 DDDDDDDD 0 EEEEEEEE 1 Where: A = Decoder address bits V =
853     * Desired CV address - (CV 513 = 10 00000000) D = Data for CV
854     * <br><br>
855     * This is the old "legacy" format, newer decoders use the "Basic Accessory
856     * Decoder Packet"
857     *
858     * @param accAddr Address of accessory, in the range 1 to 2044
859     * @param cvNum   CV number to access
860     * @param data    Data to be written
861     * @return a packet
862     */
863    public static byte[] accDecoderPktOpsModeLegacy(int accAddr, int cvNum, int data) {
864
865        // aBits is the "address" part of the nmra packet, which starts with 1
866        int aBits = (accAddr - 1) >> 2;      // Divide by 4 to get the 'base'
867        aBits += 1;                       // Base is +1
868
869        // get the packet
870        return NmraPacket.accDecPktOpsModeLegacy(aBits, cvNum, data);
871    }
872
873    public static byte[] opsCvWriteByte(int address, boolean longAddr, int cvNum, int data) {
874        log.debug("opswrite {} {} {}", address, cvNum, data);
875
876        if (!addressCheck(address, longAddr)) {
877            return null;  // failed!
878        }
879
880        if (data < 0 || data > 255) {
881            log.error("invalid data {}", data);
882            return null;
883        }
884        if (cvNum < 1 || cvNum > 1024) {
885            log.error("invalid CV number {}", cvNum);
886            return null;
887        }
888
889        // end sanity checks, format output
890        int arg1 = 0xEC + (((cvNum - 1) >> 8) & 0x03);
891        int arg2 = (cvNum - 1) & 0xFF;
892        int arg3 = data & 0xFF;
893
894        return NmraPacket.threeBytePacket(address, longAddr, (byte) arg1, (byte) arg2, (byte) arg3);
895    }
896
897    public static byte[] speedStep128Packet(int address, boolean longAddr, int speed, boolean fwd) {
898        log.debug("128 step packet {} {}", address, speed);
899
900        if (!addressCheck(address, longAddr)) {
901            return null;  // failed!
902        }
903
904        if (speed < 0 || speed > 127) {
905            log.error("invalid speed {}", speed);
906            return null;
907        }
908
909        // end sanity checks, format output
910        byte[] retVal;
911        int arg1 = 0x3F;
912        int arg2 = (speed & 0x7F) | (fwd ? 0x80 : 0);
913
914        if (longAddr) {
915            // long address form
916            retVal = new byte[5];
917            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
918            retVal[1] = (byte) (address & 0xFF);
919            retVal[2] = (byte) arg1;
920            retVal[3] = (byte) arg2;
921            retVal[4] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3]);
922        } else {
923            // short address form
924            retVal = new byte[4];
925            retVal[0] = (byte) (address & 0xFF);
926            retVal[1] = (byte) arg1;
927            retVal[2] = (byte) arg2;
928            retVal[3] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2]);
929        }
930        return retVal;
931    }
932
933    /**
934     * From NMRA RP 9.2.1 [A Crosland 05/02/12] There is an issue with this
935     * method in that it cannot create a 28 step speed packet for maximum speed.
936     * Input speed value in the range 0 - 28 is converted to speed steps, 0,
937     * estop, 1, 2, ..., 27.
938     * <p>
939     * This method should probably be deprecated. It is used only by
940     * NceThrottle.java and EasyDccThrottle.java which themselves have issues in
941     * the way floating point speed values are converted to integer speed steps.
942     * <p>
943     * A speed and direction instruction is used send information to motors
944     * connected to Multi Function Digital Decoders. Instruction "010" indicates
945     * a Speed and Direction Instruction for reverse operation and instruction
946     * "011" indicates a Speed and Direction Instruction for forward operation.
947     * In these instructions the data is used to control speed with bits 0-3
948     * being defined exactly as in S-9.2 Section B. If Bit 1 of CV#29 has a
949     * value of one (1), then bit 4 is used as an intermediate speed step, as
950     * defined in S-9.2, Section B. If Bit 1 of CV#29 has a value of zero (0),
951     * then bit 4 shall 230 be used to control FL4. In this mode, Speed U0000 is
952     * stop, speed U0001 is emergency stop, speed U0010 is the first speed step
953     * and speed U1111 is full speed. This provides 14 discrete speed steps in
954     * each direction.
955     *
956     * @param address  the DCC locomotive address
957     * @param longAddr true if the address is long; false if short
958     * @param speed    the speed from 0-28
959     * @param fwd      true for forward direction; false for reverse
960     * @return the instruction or null if address or speed is invalid
961     */
962    public static byte[] speedStep28Packet(int address, boolean longAddr, int speed, boolean fwd) {
963        log.debug("28 step packet {} {}", address, speed);
964
965        if (!addressCheck(address, longAddr)) {
966            return null;  // failed!
967        }
968
969        if (speed < 0 || speed > 28) {
970            log.error("invalid speed {}", speed);
971            return null;
972        }
973        int speedC = (speed & 0x1F) >> 1;
974        if (speed > 0) {
975            speedC = speedC + 1;
976        }
977        int c = (speed & 0x01) << 4; // intermediate speed step
978
979        speedC = speedC + c;
980
981        // end sanity checks, format output
982        int arg1 = (fwd ? 0x60 : 0x40) | speedC;
983
984        return NmraPacket.oneBytePacket(address, longAddr, (byte) arg1);
985    }
986
987    /**
988     * New version of speedStep28Packet to allow access to the whole range of 28
989     * step speed packets.
990     * <p>
991     * Simply constructs a packet using the 5 bit speed value. This is
992     * consistent with the 128 and 14 step methods which do no further
993     * processing of the speed value.
994     *
995     * @param full     must be true
996     * @param address  DCC address
997     * @param longAddr true if DCC address is long; false if short
998     * @param speed    speed step value 0 - 31 for insertion into DC packet
999     * @param fwd      true for forward direction; false for reverse
1000     * @return the instruction or null if address or speed is invalid
1001     */
1002    @CheckForNull
1003    public static byte[] speedStep28Packet(boolean full, int address, boolean longAddr, int speed, boolean fwd) {
1004        log.debug("28 step packet {} {}", address, speed);
1005
1006        if (!full) {
1007            log.error("invalid method invocation");
1008            return null;    // failed!
1009        }
1010
1011        if (!addressCheck(address, longAddr)) {
1012            return null;  // failed!
1013        }
1014
1015        if (speed < 0 || speed > 31) {
1016            log.error("invalid speed {}", speed);
1017            return null;
1018        }
1019        int speedC = (speed & 0x1F) >> 1;
1020        int c = (speed & 0x01) << 4; // intermediate speed step
1021
1022        speedC = speedC + c;
1023
1024        // end sanity checks, format output
1025        int arg1 = (fwd ? 0x60 : 0x40) | speedC;
1026
1027        return NmraPacket.oneBytePacket(address, longAddr, (byte) arg1);
1028    }
1029
1030    public static byte[] speedStep14Packet(int address, boolean longAddr,
1031            int speed, boolean fwd, boolean F0) {
1032        log.debug("14 step packet {} {} {}", address, speed, F0);
1033
1034        if (speed < 0 || speed > 15) {
1035            log.error("invalid speed {}", speed);
1036            return null;
1037        }
1038
1039        int speedC = (speed & 0xF);
1040
1041        if (F0) {
1042            speedC = speedC + 0x10;
1043        }
1044
1045        // end sanity checks, format output
1046        byte[] retVal;
1047        int arg1 = (fwd ? 0x60 : 0x40) | speedC;
1048
1049        if (longAddr) {
1050            // long address form
1051            retVal = new byte[4];
1052            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
1053            retVal[1] = (byte) (address & 0xFF);
1054            retVal[2] = (byte) arg1;
1055            retVal[3] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3]);
1056        } else {
1057            // short address form
1058            retVal = new byte[3];
1059            retVal[0] = (byte) (address & 0xFF);
1060            retVal[1] = (byte) arg1;
1061            retVal[2] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2]);
1062        }
1063
1064        return retVal;
1065    }
1066
1067    public static byte[] function0Through4Packet(int address, boolean longAddr,
1068            boolean f0, boolean f1, boolean f2, boolean f3, boolean f4) {
1069        log.debug("f0 through f4 packet {}", address);
1070
1071        if (!addressCheck(address, longAddr)) {
1072            return null;  // failed!
1073        }
1074
1075        // end sanity check, format output
1076        byte[] retVal;
1077        int arg1 = 0x80
1078                | (f0 ? 0x10 : 0)
1079                | (f1 ? 0x01 : 0)
1080                | (f2 ? 0x02 : 0)
1081                | (f3 ? 0x04 : 0)
1082                | (f4 ? 0x08 : 0);
1083
1084        if (longAddr) {
1085            // long address form
1086            retVal = new byte[4];
1087            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
1088            retVal[1] = (byte) (address & 0xFF);
1089            retVal[2] = (byte) arg1;
1090            retVal[3] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2]);
1091        } else {
1092            // short address form
1093            retVal = new byte[3];
1094            retVal[0] = (byte) (address & 0xFF);
1095            retVal[1] = (byte) arg1;
1096            retVal[2] = (byte) (retVal[0] ^ retVal[1]);
1097        }
1098        return retVal;
1099    }
1100
1101    public static byte[] function5Through8Packet(int address, boolean longAddr,
1102            boolean f5, boolean f6, boolean f7, boolean f8) {
1103        log.debug("f5 through f8 packet {}", address);
1104
1105        if (!addressCheck(address, longAddr)) {
1106            return null;  // failed!
1107        }
1108
1109        // end sanity check, format output
1110        byte[] retVal;
1111        int arg1 = 0xB0
1112                | (f8 ? 0x08 : 0)
1113                | (f7 ? 0x04 : 0)
1114                | (f6 ? 0x02 : 0)
1115                | (f5 ? 0x01 : 0);
1116
1117        if (longAddr) {
1118            // long address form
1119            retVal = new byte[4];
1120            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
1121            retVal[1] = (byte) (address & 0xFF);
1122            retVal[2] = (byte) arg1;
1123            retVal[3] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2]);
1124        } else {
1125            // short address form
1126            retVal = new byte[3];
1127            retVal[0] = (byte) (address & 0xFF);
1128            retVal[1] = (byte) arg1;
1129            retVal[2] = (byte) (retVal[0] ^ retVal[1]);
1130        }
1131        return retVal;
1132    }
1133
1134    public static byte[] function9Through12Packet(int address, boolean longAddr,
1135            boolean f9, boolean f10, boolean f11, boolean f12) {
1136        log.debug("f9 through f12 packet {}", address);
1137
1138        if (!addressCheck(address, longAddr)) {
1139            return null;  // failed!
1140        }
1141
1142        // end sanity check, format output
1143        byte[] retVal;
1144        int arg1 = 0xA0
1145                | (f12 ? 0x08 : 0)
1146                | (f11 ? 0x04 : 0)
1147                | (f10 ? 0x02 : 0)
1148                | (f9 ? 0x01 : 0);
1149
1150        if (longAddr) {
1151            // long address form
1152            retVal = new byte[4];
1153            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
1154            retVal[1] = (byte) (address & 0xFF);
1155            retVal[2] = (byte) arg1;
1156            retVal[3] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2]);
1157        } else {
1158            // short address form
1159            retVal = new byte[3];
1160            retVal[0] = (byte) (address & 0xFF);
1161            retVal[1] = (byte) arg1;
1162            retVal[2] = (byte) (retVal[0] ^ retVal[1]);
1163        }
1164        return retVal;
1165    }
1166
1167    public static byte[] function13Through20Packet(int address, boolean longAddr,
1168            boolean f13, boolean f14, boolean f15, boolean f16,
1169            boolean f17, boolean f18, boolean f19, boolean f20) {
1170        log.debug("f13 through f20 packet {}", address);
1171
1172        if (!addressCheck(address, longAddr)) {
1173            return null;  // failed!
1174        }
1175
1176        // end sanity check, format output
1177        int arg1 = 0xDE;
1178        int arg2 = (f20 ? 0x80 : 0)
1179                | (f19 ? 0x40 : 0)
1180                | (f18 ? 0x20 : 0)
1181                | (f17 ? 0x10 : 0)
1182                | (f16 ? 0x08 : 0)
1183                | (f15 ? 0x04 : 0)
1184                | (f14 ? 0x02 : 0)
1185                | (f13 ? 0x01 : 0);
1186
1187        return NmraPacket.twoBytePacket(address, longAddr, (byte) arg1, (byte) arg2);
1188    }
1189
1190    public static byte[] function21Through28Packet(int address, boolean longAddr,
1191            boolean f21, boolean f22, boolean f23, boolean f24,
1192            boolean f25, boolean f26, boolean f27, boolean f28) {
1193        log.debug("f21 through f28 packet {}", address);
1194
1195        if (!addressCheck(address, longAddr)) {
1196            return null;  // failed!
1197        }
1198
1199        // end sanity check, format output
1200        int arg1 = 0xDF;
1201        int arg2 = (f28 ? 0x80 : 0)
1202                | (f27 ? 0x40 : 0)
1203                | (f26 ? 0x20 : 0)
1204                | (f25 ? 0x10 : 0)
1205                | (f24 ? 0x08 : 0)
1206                | (f23 ? 0x04 : 0)
1207                | (f22 ? 0x02 : 0)
1208                | (f21 ? 0x01 : 0);
1209
1210        return NmraPacket.twoBytePacket(address, longAddr, (byte) arg1, (byte) arg2);
1211    }
1212
1213    // The following function packet definitions are based on "http://normen.railcommunity.de/RCN-212.pdf".
1214
1215    public static byte[] function29Through36Packet(int address, boolean longAddr,
1216            boolean f29, boolean f30, boolean f31, boolean f32,
1217            boolean f33, boolean f34, boolean f35, boolean f36) {
1218        log.debug("f29 through f36 packet {}", address);
1219
1220        if (!addressCheck(address, longAddr)) {
1221            return null;  // failed!
1222        }
1223
1224        // end sanity check, format output
1225        int arg1 = 0xD8;
1226        int arg2 = (f36 ? 0x80 : 0)
1227                | (f35 ? 0x40 : 0)
1228                | (f34 ? 0x20 : 0)
1229                | (f33 ? 0x10 : 0)
1230                | (f32 ? 0x08 : 0)
1231                | (f31 ? 0x04 : 0)
1232                | (f30 ? 0x02 : 0)
1233                | (f29 ? 0x01 : 0);
1234
1235        return NmraPacket.twoBytePacket(address, longAddr, (byte) arg1, (byte) arg2);
1236    }
1237
1238    public static byte[] function37Through44Packet(int address, boolean longAddr,
1239            boolean f37, boolean f38, boolean f39, boolean f40,
1240            boolean f41, boolean f42, boolean f43, boolean f44) {
1241        log.debug("f37 through f44 packet {}", address);
1242
1243        if (!addressCheck(address, longAddr)) {
1244            return null;  // failed!
1245        }
1246
1247        // end sanity check, format output
1248        int arg1 = 0xD9;
1249        int arg2 = (f44 ? 0x80 : 0)
1250                | (f43 ? 0x40 : 0)
1251                | (f42 ? 0x20 : 0)
1252                | (f41 ? 0x10 : 0)
1253                | (f40 ? 0x08 : 0)
1254                | (f39 ? 0x04 : 0)
1255                | (f38 ? 0x02 : 0)
1256                | (f37 ? 0x01 : 0);
1257
1258        return NmraPacket.twoBytePacket(address, longAddr, (byte) arg1, (byte) arg2);
1259    }
1260
1261    public static byte[] function45Through52Packet(int address, boolean longAddr,
1262            boolean f45, boolean f46, boolean f47, boolean f48,
1263            boolean f49, boolean f50, boolean f51, boolean f52) {
1264        log.debug("f45 through f52 packet {}", address);
1265
1266        if (!addressCheck(address, longAddr)) {
1267            return null;  // failed!
1268        }
1269
1270        // end sanity check, format output
1271        int arg1 = 0xDA;
1272        int arg2 = (f52 ? 0x80 : 0)
1273                | (f51 ? 0x40 : 0)
1274                | (f50 ? 0x20 : 0)
1275                | (f49 ? 0x10 : 0)
1276                | (f48 ? 0x08 : 0)
1277                | (f47 ? 0x04 : 0)
1278                | (f46 ? 0x02 : 0)
1279                | (f45 ? 0x01 : 0);
1280
1281        return NmraPacket.twoBytePacket(address, longAddr, (byte) arg1, (byte) arg2);
1282    }
1283
1284    public static byte[] function53Through60Packet(int address, boolean longAddr,
1285            boolean f53, boolean f54, boolean f55, boolean f56,
1286            boolean f57, boolean f58, boolean f59, boolean f60) {
1287        log.debug("f53 through f60 packet {}", address);
1288
1289        if (!addressCheck(address, longAddr)) {
1290            return null;  // failed!
1291        }
1292
1293        // end sanity check, format output
1294        int arg1 = 0xDB;
1295        int arg2 = (f60 ? 0x80 : 0)
1296                | (f59 ? 0x40 : 0)
1297                | (f58 ? 0x20 : 0)
1298                | (f57 ? 0x10 : 0)
1299                | (f56 ? 0x08 : 0)
1300                | (f55 ? 0x04 : 0)
1301                | (f54 ? 0x02 : 0)
1302                | (f53 ? 0x01 : 0);
1303
1304        return NmraPacket.twoBytePacket(address, longAddr, (byte) arg1, (byte) arg2);
1305    }
1306
1307    public static byte[] function61Through68Packet(int address, boolean longAddr,
1308            boolean f61, boolean f62, boolean f63, boolean f64,
1309            boolean f65, boolean f66, boolean f67, boolean f68) {
1310        log.debug("f61 through f68 packet {}", address);
1311
1312        if (!addressCheck(address, longAddr)) {
1313            return null;  // failed!
1314        }
1315
1316        // end sanity check, format output
1317        int arg1 = 0xDC;
1318        int arg2 = (f68 ? 0x80 : 0)
1319                | (f67 ? 0x40 : 0)
1320                | (f66 ? 0x20 : 0)
1321                | (f65 ? 0x10 : 0)
1322                | (f64 ? 0x08 : 0)
1323                | (f63 ? 0x04 : 0)
1324                | (f62 ? 0x02 : 0)
1325                | (f61 ? 0x01 : 0);
1326
1327        return NmraPacket.twoBytePacket(address, longAddr, (byte) arg1, (byte) arg2);
1328    }
1329
1330    /**
1331     * Provide an NMRA analog control instruction.
1332     * <p>
1333     * Note that the NMRA draft of Fall 2004 only defines the value of "1" for
1334     * the "function parameter", calling that the value for "volume control".
1335     * However, DCC systems in the wild have been observed to use 0x7F for the
1336     * function byte for volume control.
1337     *
1338     * @param address  DCC locomotive address
1339     * @param longAddr true if this is a long address, false if short address
1340     * @param function see note above
1341     * @param value    value to be sent in analog control instruction
1342     * @return the instruction or null if the address is not valid
1343     */
1344    public static byte[] analogControl(int address, boolean longAddr,
1345            int function, int value) {
1346
1347        if (!addressCheck(address, longAddr)) {
1348            return null;  // failed!
1349        }
1350
1351        // end sanity check, format output
1352        byte[] retVal;
1353        int arg1 = 0x3D;  // analog instruction tag
1354
1355        if (longAddr) {
1356            // long address form
1357            retVal = new byte[6];
1358            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
1359            retVal[1] = (byte) (address & 0xFF);
1360            retVal[2] = (byte) arg1;
1361            retVal[3] = (byte) (function & 0xFF);
1362            retVal[4] = (byte) (value & 0xFF);
1363            retVal[5] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3] ^ retVal[4]);
1364        } else {
1365            // short address form
1366            retVal = new byte[5];
1367            retVal[0] = (byte) (address & 0xFF);
1368            retVal[1] = (byte) arg1;
1369            retVal[2] = (byte) (function & 0xFF);
1370            retVal[3] = (byte) (value & 0xFF);
1371            retVal[4] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3]);
1372        }
1373        return retVal;
1374    }
1375
1376    /**
1377     * Provide an NMRA consist control instruction
1378     *
1379     * @param address         DCC locomotive address
1380     * @param longAddr        true for a long address, false if short address
1381     * @param consist         the consist address to set for this locomotive;
1382     *                        Send 00 as consist address to remove from consist
1383     * @param directionNormal true if the normal direction of travel for this
1384     *                        address is the normal direction of travel for the
1385     *                        consist
1386     * @return the instruction
1387     */
1388    public static byte[] consistControl(int address, boolean longAddr,
1389            int consist, boolean directionNormal) {
1390
1391        if (!addressCheck(address, longAddr)) {
1392            return null;  // failed!
1393        } else if (!addressCheck(consist, false)) {
1394            return null;  // failed - Consist address is not a short address!
1395        }
1396
1397        // end sanity check, format output
1398        byte[] retVal;
1399        int arg1 = 0x10;  // Consist Control instruction tag
1400        if (directionNormal) {
1401            arg1 |= 0x02;   // Forward Direction
1402        } else {
1403            arg1 |= 0x03;   // Reverse Direction
1404        }
1405        if (longAddr) {
1406            // long address form
1407            retVal = new byte[5];
1408            retVal[0] = (byte) (192 + ((address / 256) & 0x3F));
1409            retVal[1] = (byte) (address & 0xFF);
1410            retVal[2] = (byte) arg1;
1411            retVal[3] = (byte) (consist & 0xFF);
1412            retVal[4] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2] ^ retVal[3]);
1413        } else {
1414            // short address form
1415            retVal = new byte[4];
1416            retVal[0] = (byte) (address & 0xFF);
1417            retVal[1] = (byte) arg1;
1418            retVal[2] = (byte) (consist & 0xFF);
1419            retVal[3] = (byte) (retVal[0] ^ retVal[1] ^ retVal[2]);
1420        }
1421        return retVal;
1422    }
1423
1424    /**
1425     * Check if an address is (possibly) valid, e.g. fits within the NMRA space
1426     * definition
1427     *
1428     * @param address  the address
1429     * @param longAddr true if address is long; false otherwise
1430     * @return true if address is valid; false otherwise
1431     */
1432    static public boolean addressCheck(int address, boolean longAddr) {
1433        if (address < 0) {  // zero is valid broadcast
1434            log.error("invalid address {}", address);
1435            return false;
1436        }
1437        if (longAddr && (address > (255 + (231 - 192) * 256))) {
1438            log.error("invalid address {}", address);
1439            return false;
1440        }
1441        if (!longAddr && (address > 127)) {
1442            log.error("invalid address {}", address);
1443            return false;
1444        }
1445        return true;  // passes test, hence OK
1446    }
1447
1448    public enum DccAddressType {
1449
1450        NO_ADDRESS,
1451        BROADCAST,
1452        IDLE,
1453        LOCO_SHORT_ADDRESS,
1454        LOCO_LONG_ADDRESS,
1455        ACCESSORY_ADDRESS;
1456    }
1457
1458    /**
1459     * Extract the address type from an NMRA packet.
1460     * <p>
1461     * This finds and returns the type of address within a specific packet, e.g.
1462     * "the stationary decoder space".
1463     *
1464     * @param packet the packet
1465     * @return the type or {@link jmri.NmraPacket.DccAddressType#NO_ADDRESS}
1466     */
1467    static public DccAddressType extractAddressType(byte[] packet) {
1468        if (packet[0] == 0x00) {
1469            return DccAddressType.BROADCAST;
1470        }
1471        if ((packet[0] & 0xFF) == 0xFF) {
1472            return DccAddressType.IDLE;
1473        }
1474        if ((0x80 & packet[0]) == 0x00) {
1475            return DccAddressType.LOCO_SHORT_ADDRESS;
1476        }
1477        if ((0xC0 & packet[0]) == 0xC0) {
1478            return DccAddressType.LOCO_LONG_ADDRESS;
1479        }
1480        if ((0xC0 & packet[0]) == 0x80) {
1481            return DccAddressType.ACCESSORY_ADDRESS;
1482        }
1483        return DccAddressType.NO_ADDRESS;
1484    }
1485
1486    /**
1487     * Extract the numerical address from an NMRA packet.
1488     * <p>
1489     * This finds and returns the numerical address within a specific type, e.g.
1490     * "first address within the stationary decoder space".
1491     * <p>
1492     * As a special case, IDLE is returned as -1 instead of 255. Best to check
1493     * the address type first....
1494     * <p>
1495     * <strong>Note:</strong> The decoding is not complete for the
1496     * ACCESSORY_ADDRESS type.
1497     *
1498     * @param packet the packet
1499     * @return the address; -1 is returned if there is no address or the case
1500     *         isn't considered yet
1501     */
1502    static public int extractAddressNumber(byte[] packet) {
1503        switch (extractAddressType(packet)) {
1504            case BROADCAST:
1505                return 0;
1506            case NO_ADDRESS:
1507            case IDLE:
1508                return -1;
1509            case LOCO_SHORT_ADDRESS:
1510                return packet[0] & 0xFF;
1511            case LOCO_LONG_ADDRESS:
1512                return (packet[0] & 0x3F) << 8 | (packet[1] & 0xFF);
1513            case ACCESSORY_ADDRESS:
1514                // case signal packet
1515                if (isAccSignalDecoderPkt(packet)) {
1516                    return getAccSignalDecoderPktAddress(packet);
1517                }
1518
1519                // case turnout accessory decoder
1520                return getAccDecoderPktAddress(packet);
1521            default:
1522                log.error("Unhandled address type {}", extractAddressType(packet));
1523                break;
1524        }
1525        return -1;
1526    }
1527
1528    /**
1529     * Extract the instruction from an NMRA packet.
1530     * <p>
1531     * This finds and returns the instruction byte within a specific type of
1532     * packet/instruction.
1533     *
1534     * @param packet the packet
1535     * @return the instruction or 0
1536     */
1537    static public int extractInstruction(byte[] packet) {
1538        switch (extractAddressType(packet)) {
1539            case BROADCAST:
1540            case NO_ADDRESS:
1541            case IDLE:
1542            case LOCO_SHORT_ADDRESS:
1543                return packet[1] & 0xFF;
1544            case LOCO_LONG_ADDRESS:
1545            case ACCESSORY_ADDRESS:
1546                return packet[2] & 0xFF;
1547            default:
1548                log.warn("Unhandled address type: {}", extractAddressType(packet));
1549        }
1550        return 0;
1551    }
1552
1553    /**
1554     * Convert NMRA packet to a readable form as hexadecimal characters.
1555     *
1556     * @param p the raw packet
1557     * @return the readable packet
1558     * @see jmri.util.StringUtil#hexStringFromBytes(byte[])
1559     */
1560    static public String format(byte[] p) {
1561        return jmri.util.StringUtil.hexStringFromBytes(p);
1562    }
1563
1564    /**
1565     * Convert NMRA packet to human-readable form
1566     * <p>
1567     * Note: Only gives a summary now, should this completely decode?
1568     * <p>
1569     * 2nd Note: The name may be a bad choice, as this is not the .toString()
1570     * method of an object, but rather a procedure that takes a byte-array
1571     * representation of a packet. But the analogy seems not so bad, until we
1572     * have a true class for NmraPackets.
1573     *
1574     * @param p the raw packet
1575     * @return the human-readable form for that packet
1576     * @throws IllegalArgumentException if packet array can't be decoded, e.g.
1577     *                                  is too short or null
1578     */
1579    static public String toString(byte[] p) throws IllegalArgumentException {
1580        if (p == null || p.length == 0) {
1581            throw new IllegalArgumentException("Content required");
1582        }
1583        return Bundle.getMessage("DccToStringFormat", extractAddressType(p), extractInstruction(p), extractAddressNumber(p));
1584    }
1585
1586    /**
1587     * Objects of this class should not be created.
1588     */
1589    private NmraPacket() {
1590    }
1591    private final static Logger log = LoggerFactory.getLogger(NmraPacket.class);
1592}