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