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}