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