001package jmri.jmrix.nce; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006import jmri.NmraPacket; 007 008/* 009 010 From NCE System notes for version March 1, 2007 011 012 New 0xAD command sends accessory or signal packets. 013 This command can also issue NCE macros 014 Command Format: 0xAD <addr_h> <addr_l> <op_1> <data_1> 015 Addr_h and Addr_l are the accessory/signal address as a 016 normal binary number (NOT in DCC format). 017 Ex: Accessory Address 1 = 0x00 0x01 (hi byte first) 018 Ex: Accessory Address 2 = 0x00 0x02 (hi byte first) 019 Ex: Accessory Address 513 = 0x02 0x01 (hi byte first) 020 NOTE: accy/signal address 0 is not a valid address 021 022 Op_1 Data_1 Operation description 023 01 0-255 NCE macro number 0-255 024 02 0-255 Duplicate of Op_1 command 01 025 03 0 Accessory Normal direction (ON) 026 04 0 Accessory Reverse direction (OFF) 027 05 0-1f Signal Aspect 0-31 028 06-7f reserved reserved 029 030 Returns: ! = success 031 1 = bad accy/signal address 032 033 0xA2 sends speed or function packets to a locomotive. 034 035 Command Format: 0xA2 <addr_h> <addr_l> <op_1> <data_1> 036 Addr_h and Addr_l are the loco address in DCC format. 037 If a long address is in use, bits 6 and 7 of the high byte are set. 038 Example: Long address 3 = 0xc0 0x03 039 Short address 3 = 0x00 0x03 040 041 Op_1 Data_1 Operation description 042 01 0-7f Reverse 28 speed command 043 02 0-7f Forward 28 speed command 044 03 0-7f Reverse 128 speed command 045 04 0-7f Forward 128 speed command 046 05 0 Estop reverse command 047 06 0 Estop forward command 048 07 0-1f Function group 1 (same format as DCC packet for FG1 049 08 0-0f Function group 2 (same format as DCC packet for FG2 050 09 0-0f Function group 3 (same format as DCC packet for FG3 051 0a 0-7f Set reverse consist address for lead loco 052 0b 0-7f Set forward consist address for lead loco 053 0c 0-7f Set reverse consist address for rear loco 054 0d 0-7f Set forward consist address for rear loco 055 0e 0-7f Set reverse consist address for additional loco 056 0f 0-7f Set forward consist address for additional loco 057 10 0 Del loco from consist 058 11 0 Kill consist 059 12 0-9 Set momentum 060 13 0-7f No action, always returns success 061 14 0-7f No action, always returns success 062 15 0-ff Functions 13-20 control (bit 0=F13, bit 7=F20) 063 16 0-ff Functions 21-28 control (bit 0=F21, bit 7=F28) 064 17 0-3f Assign this loco to cab number in data_1 065 18-7f reserved reserved 066 067 Returns: ! = success 068 1 = bad loco address 069 070 */ 071/** 072 * NCE Binary Commands 073 * 074 * Also see NceMessage.java for additional commands 075 * 076 * @author Daniel Boudreau (C) 2007, 2010 077 * @author ken cameron (C) 2013 078 */ 079public class NceBinaryCommand { 080 081// all commands moved to NceMessage 07/17/2018 DAB 082// public static final int NOP_CMD = 0x80; // NCE No Op Command, NCE-USB yes 083// public static final int ASSIGN_CAB_CMD = 0x81; // NCE Assign loco to cab command, NCE-USB no 084// public static final int READ_CLOCK_CMD = 0x82; // NCE read clock command, NCE-USB no 085// public static final int STOP_CLOCK_CMD = 0x83; // NCE stop clock command, NCE-USB no 086// public static final int START_CLOCK_CMD = 0x84; // NCE start clock command, NCE-USB no 087// public static final int SET_CLOCK_CMD = 0x85; // NCE set clock command, NCE-USB no 088// public static final int CLOCK_1224_CMD = 0x86; // NCE change clock 12/24 command, NCE-USB no 089// public static final int CLOCK_RATIO_CMD = 0x87; // NCE set clock ratio command, NCE-USB no 090// public static final int DEQUEUE_CMD = 0x88; // NCE dequeue packets based on loco addr, NCE-USB no 091// public static final int ENABLE_TRACK_CMD = 0x89; // NCE enable track/kill programm track, NCE-USB no 092// public static final int READ_AUI4_CMD = 0x8A; // NCE read status of AUI yy, returns four bytes, NCE-USB no 093// public static final int DISABLE_TRACK_CMD = 0x89; // NCE enable program/kill main track, NCE-USB no 094// public static final int DUMMY_CMD = 0x8C; // NCE Dummy instruction, NCE-USB yes 095// public static final int SPEED_MODE_CMD = 0x8D; // NCE set speed mode, NCE-USB no 096// public static final int WRITE_N_CMD = 0x8E; // NCE write up to 16 bytes of memory command, NCE-USB no 097// public static final int READ16_CMD = 0x8F; // NCE read 16 bytes of memory command, NCE-USB no 098// public static final int DISPLAY3_CMD = 0x90; // NCE write 16 char to cab display line 3, NCE-USB no 099// public static final int DISPLAY4_CMD = 0x91; // NCE write 16 char to cab display line 4, NCE-USB no 100// public static final int DISPLAY2_CMD = 0x92; // NCE write 8 char to cab display line 2 right, NCE-USB no 101// public static final int QUEUE3_TMP_CMD = 0x93; // NCE queue 3 bytes to temp queue, NCE-USB no 102// public static final int QUEUE4_TMP_CMD = 0x94; // NCE queue 4 bytes to temp queue, NCE-USB no 103// public static final int QUEUE5_TMP_CMD = 0x95; // NCE queue 5 bytes to temp queue, NCE-USB no 104// public static final int QUEUE6_TMP_CMD = 0x96; // NCE queue 6 bytes to temp queue, NCE-USB no 105// public static final int WRITE1_CMD = 0x97; // NCE write 1 bytes of memory command, NCE-USB no 106// public static final int WRITE2_CMD = 0x98; // NCE write 2 bytes of memory command, NCE-USB no 107// public static final int WRITE4_CMD = 0x99; // NCE write 4 bytes of memory command, NCE-USB no 108// public static final int WRITE8_CMD = 0x9A; // NCE write 8 bytes of memory command, NCE-USB no 109// public static final int READ_AUI2_CMD = 0x9B; // NCE read status of AUI yy, returns two bytes, NCE-USB >= 1.65 110// public static final int MACRO_CMD = 0x9C; // NCE execute macro n, NCE-USB yes 111// public static final int READ1_CMD = 0x9D; // NCE read 1 byte of memory command, NCE-USB no 112// public static final int PGM_TRK_ON_CMD = 0x9E; // NCE enter program track command, NCE-USB yes 113// public static final int PGM_TRK_OFF_CMD = 0x9F; // NCE exit program track command, NCE-USB yes 114// public static final int PGM_PAGE_WRITE_CMD = 0xA0; // NCE program track, page mode write command, NCE-USB yes 115// public static final int PGM_PAGE_READ_CMD = 0xA1; // NCE program track, page mode read command, NCE-USB yes 116// public static final int LOCO_CMD = 0xA2; // NCE loco control command, NCE-USB yes 117// public static final int QUEUE3_TRK_CMD = 0xA3; // NCE queue 3 bytes to track queue, NCE-USB no 118// public static final int QUEUE4_TRK_CMD = 0xA4; // NCE queue 4 bytes to track queue, NCE-USB no 119// public static final int QUEUE5_TRK_CMD = 0xA5; // NCE queue 5 bytes to track queue, NCE-USB no 120// public static final int PGM_REG_WRITE_CMD = 0xA6; // NCE program track, register mode write command, NCE-USB yes 121// public static final int PGM_REG_READ_CMD = 0xA7; // NCE program track, register mode read command, NCE-USB yes 122// public static final int PGM_DIR_WRITE_CMD = 0xA8; // NCE program track, direct mode write command, NCE-USB yes 123// public static final int PGM_DIR_READ_CMD = 0xA9; // NCE program track, direct mode read command, NCE-USB yes 124// public static final int SW_REV_CMD = 0xAA; // NCE get EPROM revision cmd, Reply Format: VV.MM.mm, NCE-USB yes 125// public static final int RESET_SOFT_CMD = 0xAB; // NCE soft reset command, NCE-USB no 126// public static final int RESET_HARD_CMD = 0xAC; // NCE hard reset command, NCE-USB no 127// public static final int ACC_CMD = 0xAD; // NCE accessory command, NCE-USB yes 128// public static final int OPS_PROG_LOCO_CMD = 0xAE; // NCE ops mode program loco, NCE-USB yes 129// public static final int OPS_PROG_ACCY_CMD = 0xAF; // NCE ops mode program accessories, NCE-USB yes 130// public static final int FACTORY_TEST_CMD = 0xB0; // NCE factory test, NCE-USB yes 131// public static final int USB_SET_CAB_CMD = 0xB1; // NCE set cab address in USB, NCE-USB yes 132// public static final int USB_MEM_POINTER_CMD = 0xB3; // NCE set memory context pointer, NCE-USB >= 1.65 133// public static final int USB_MEM_WRITE_CMD = 0xB4; // NCE write memory, NCE-USB >= 1.65 134// public static final int USB_MEM_READ_CMD = 0xB5; // NCE read memory, NCE-USB >= 1.65 135 136 // NCE Command 0xA2 sends speed or function packets to a locomotive 137 // 0xA2 sub commands speed and functions 138// public static final byte LOCO_CMD_SELECT_LOCO = 0x00; // select loco 139// public static final byte LOCO_CMD_REV_28SPEED = 0x01; // set loco speed 28 steps reverse 140// public static final byte LOCO_CMD_FWD_28SPEED = 0x02; // set loco speed 28 steps forward 141// public static final byte LOCO_CMD_REV_128SPEED = 0x03; // set loco speed 128 steps reverse 142// public static final byte LOCO_CMD_FWD_128SPEED = 0x04; // set loco speed 128 steps forward 143// public static final byte LOCO_CMD_REV_ESTOP = 0x05; // emergency stop reverse 144// public static final byte LOCO_CMD_FWD_ESTOP = 0x06; // emergency stop forward 145// public static final byte LOCO_CMD_FG1 = 0x07; // function group 1 146// public static final byte LOCO_CMD_FG2 = 0x08; // function group 2 147// public static final byte LOCO_CMD_FG3 = 0x09; // function group 3 148// public static final byte LOCO_CMD_FG4 = 0x15; // function group 4 149// public static final byte LOCO_CMD_FG5 = 0x16; // function group 5 150 151 // OxA2 sub commands consist 152// public static final byte LOCO_CMD_REV_CONSIST_LEAD = 0x0A; // reverse consist address for lead loco 153// public static final byte LOCO_CMD_FWD_CONSIST_LEAD = 0x0B; // forward consist address for lead loco 154// public static final byte LOCO_CMD_REV_CONSIST_REAR = 0x0C; // reverse consist address for rear loco 155// public static final byte LOCO_CMD_FWD_CONSIST_REAR = 0x0D; // forward consist address for rear loco 156// public static final byte LOCO_CMD_REV_CONSIST_MID = 0x0E; // reverse consist address for additional loco 157// public static final byte LOCO_CMD_FWD_CONSIST_MID = 0x0F; // forward consist address for additional loco 158// public static final byte LOCO_CMD_DELETE_LOCO_CONSIST = 0x10; // Delete loco from consist 159// public static final byte LOCO_CMD_KILL_CONSIST = 0x11; // Kill consist 160 161 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 162 justification = "Long-standing API, risky to update") 163 public static byte[] accDecoder(int number, boolean closed) { 164 165 if (number < NmraPacket.accIdLowLimit || number > NmraPacket.accIdAltHighLimit) { 166 log.error("invalid NCE accessory address {}", number); 167 return null; 168 } 169 byte op_1; 170 if (closed) { 171 op_1 = 0x03; 172 } else { 173 op_1 = 0x04; 174 } 175 176 int addr_h = number / 256; 177 int addr_l = number & 0xFF; 178 179 byte[] retVal = new byte[5]; 180 retVal[0] = (byte) (NceMessage.SEND_ACC_SIG_MACRO_CMD); // NCE accessory command 181 retVal[1] = (byte) (addr_h); // high address 182 retVal[2] = (byte) (addr_l); // low address 183 retVal[3] = op_1; // command 184 retVal[4] = (byte) 0; // zero out last byte for acc 185 186 return retVal; 187 } 188 189 public static byte[] accMemoryRead(int address) { 190 191 int addr_h = address / 256; 192 int addr_l = address & 0xFF; 193 194 byte[] retVal = new byte[3]; 195 retVal[0] = (byte) (NceMessage.READ16_CMD); // read 16 bytes command 196 retVal[1] = (byte) (addr_h); // high address 197 retVal[2] = (byte) (addr_l); // low address 198 199 return retVal; 200 } 201 202 /** 203 * Read one byte from NCE command station memory 204 * 205 * @param address address to read from 206 * @return binary command to read one byte 207 */ 208 public static byte[] accMemoryRead1(int address) { 209 210 int addr_h = address / 256; 211 int addr_l = address & 0xFF; 212 213 byte[] retVal = new byte[3]; 214 retVal[0] = (byte) (NceMessage.READ1_CMD); // read 1 byte command 215 retVal[1] = (byte) (addr_h); // high address 216 retVal[2] = (byte) (addr_l); // low address 217 218 return retVal; 219 } 220 221 private final static int BUFFER_SIZE_16 = 16; 222 public static byte[] accMemoryWriteN(int address, byte[] data) { 223 224 int addr_h = address / 256; 225 int addr_l = address & 0xFF; 226 227 byte[] retVal = new byte[4 + BUFFER_SIZE_16]; 228 int j = 0; 229 retVal[j++] = (byte) (NceMessage.WRITE_N_CMD); // write n bytes command 230 retVal[j++] = (byte) (addr_h); // high address 231 retVal[j++] = (byte) (addr_l); // low address 232 retVal[j++] = (byte) data.length; // number of bytes to write 233 234 for (int i = 0; i < data.length; i++, j++) { 235 retVal[j] = data[i]; 236 } 237 238 return retVal; 239 } 240 241 private final static int BUFFER_SIZE_8 = 8; 242 public static byte[] accMemoryWrite8(int address, byte[] data) { 243 244 int addr_h = address / 256; 245 int addr_l = address & 0xFF; 246 247 byte[] retVal = new byte[3 + BUFFER_SIZE_8]; 248 int j = 0; 249 retVal[j++] = (byte) (NceMessage.WRITE8_CMD); // write 8 bytes command 250 retVal[j++] = (byte) (addr_h); // high address 251 retVal[j++] = (byte) (addr_l); // low address 252 253 for (int i = 0; i < data.length; i++, j++) { 254 retVal[j] = data[i]; 255 } 256 257 return retVal; 258 } 259 260 private final static int BUFFER_SIZE_4 = 4; 261 public static byte[] accMemoryWrite4(int address, byte[] data) { 262 263 int addr_h = address / 256; 264 int addr_l = address & 0xFF; 265 266 byte[] retVal = new byte[3 + BUFFER_SIZE_4]; 267 int j = 0; 268 retVal[j++] = (byte) (NceMessage.WRITE4_CMD); // write 4 bytes command 269 retVal[j++] = (byte) (addr_h); // high address 270 retVal[j++] = (byte) (addr_l); // low address 271 272 for (int i = 0; i < data.length; i++, j++) { 273 retVal[j] = data[i]; 274 } 275 276 return retVal; 277 } 278 279 private final static int BUFFER_SIZE_2 = 2; 280 public static byte[] accMemoryWrite2(int address, byte[] data) { 281 282 int addr_h = address / 256; 283 int addr_l = address & 0xFF; 284 285 byte[] retVal = new byte[3 + BUFFER_SIZE_2]; 286 int j = 0; 287 retVal[j++] = (byte) (NceMessage.WRITE2_CMD); // write 4 bytes command 288 retVal[j++] = (byte) (addr_h); // high address 289 retVal[j++] = (byte) (addr_l); // low address 290 291 for (int i = 0; i < data.length; i++, j++) { 292 retVal[j] = data[i]; 293 } 294 295 return retVal; 296 } 297 298 public static byte[] accMemoryWrite1(int address, byte data) { 299 300 int addr_h = address / 256; 301 int addr_l = address & 0xFF; 302 303 byte[] retVal = new byte[3 + 1]; 304 retVal[0] = (byte) (NceMessage.WRITE1_CMD); // write 4 bytes command 305 retVal[1] = (byte) (addr_h); // high address 306 retVal[2] = (byte) (addr_l); // low address 307 retVal[3] = data; 308 309 return retVal; 310 } 311 312 public static byte[] accAiu2Read(int cabId) { 313 314 byte[] retVal = new byte[1 + 1]; 315 retVal[0] = (byte) (NceMessage.READ_AUI2_CMD); // write 4 bytes command 316 retVal[1] = (byte) (cabId); // cab address 317 318 return retVal; 319 } 320 321 public static byte[] usbSetCabId(int cab) { 322 323 byte[] retVal = new byte[2]; 324 retVal[0] = (byte) (NceMessage.USB_SET_CAB_CMD); // read N bytes command 325 retVal[1] = (byte) (cab); // cab number 326 327 return retVal; 328 } 329 330 public static byte[] usbMemoryWrite1(byte data) { 331 332 byte[] retVal = new byte[2]; 333 retVal[0] = (byte) (NceMessage.USB_MEM_WRITE_CMD); // write 2 bytes command 334 retVal[1] = (data); // data 335 336 return retVal; 337 } 338 339 public static byte[] usbMemoryRead(int num) { 340 341 byte[] retVal = new byte[2]; 342 retVal[0] = (byte) (NceMessage.USB_MEM_READ_CMD); // read N bytes command 343 retVal[1] = (byte) (num); // byte count 344 345 return retVal; 346 } 347 348 public static byte[] usbMemoryPointer(int cab, int loc) { 349 350 byte[] retVal = new byte[3]; 351 retVal[0] = (byte) (NceMessage.USB_MEM_POINTER_CMD); 352 retVal[1] = (byte) (cab); // cab number 353 retVal[2] = (byte) (loc); // memory offset 354 355 return retVal; 356 } 357 358 public static byte[] accStopClock() { 359 360 byte[] retVal = new byte[1]; 361 retVal[0] = (byte) (NceMessage.STOP_CLOCK_CMD); // stop clock command 362 363 return retVal; 364 } 365 366 public static byte[] accStartClock() { 367 368 byte[] retVal = new byte[1]; 369 retVal[0] = (byte) (NceMessage.START_CLOCK_CMD); // start clock command 370 371 return retVal; 372 } 373 374 public static byte[] accSetClock(int hours, int minutes) { 375 376 byte[] retVal = new byte[3]; 377 retVal[0] = (byte) (NceMessage.SET_CLOCK_CMD); // set clock command 378 retVal[1] = (byte) (hours); // hours 379 retVal[2] = (byte) (minutes); // minutes 380 381 return retVal; 382 } 383 384 public static byte[] accSetClock1224(boolean flag) { 385 386 int bit = 0; 387 if (flag) { 388 bit = 1; 389 } 390 byte[] retVal = new byte[2]; 391 retVal[0] = (byte) (NceMessage.CLOCK_1224_CMD); // set clock 12/24 command 392 retVal[1] = (byte) (bit); // 12 - 0, 24 - 1 393 394 return retVal; 395 } 396 397 public static byte[] accSetClockRatio(int ratio) { 398 399 byte[] retVal = new byte[2]; 400 retVal[0] = (byte) (NceMessage.CLOCK_RATIO_CMD); // set clock command 401 retVal[1] = (byte) (ratio); // fast clock ratio 402 403 return retVal; 404 } 405 406 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value = "PZLA_PREFER_ZERO_LENGTH_ARRAYS", 407 justification = "Long-standing API, risky to update") 408 public static byte[] nceLocoCmd(int locoAddr, byte locoSubCmd, byte locoData) { 409 if (locoSubCmd > 0x17) { 410 log.error("invalid NCE loco command {}", locoSubCmd); 411 return null; 412 } 413 414 int locoAddr_h = locoAddr / 256; 415 int locoAddr_l = locoAddr & 0xFF; 416 417 byte[] retVal = new byte[5]; 418 retVal[0] = (byte) (NceMessage.LOCO_CMD); // NCE Loco command 419 retVal[1] = (byte) (locoAddr_h); // loco high address 420 retVal[2] = (byte) (locoAddr_l); // loco low address 421 retVal[3] = locoSubCmd; // sub command 422 retVal[4] = locoData; // sub data 423 424 return retVal; 425 } 426 427 /** 428 * Create NCE EPROM revision message. The reply format is: 429 * {@literal VV.MM.mm} 430 * 431 * @return the revision message 432 */ 433 public static byte[] getNceEpromRev() { 434 byte[] retVal = new byte[1]; 435 retVal[0] = (byte) (NceMessage.SW_REV_CMD); 436 return retVal; 437 } 438 439 /** 440 * Create a NCE USB compatible ops mode loco message. 441 * 442 * @param tc traffic controller; ignored 443 * @param locoAddr locomotive address 444 * @param cvAddr CV to set 445 * @param cvData value to set CV to 446 * @return ops mode message 447 */ 448 public static byte[] usbOpsModeLoco(NceTrafficController tc, int locoAddr, int cvAddr, int cvData) { 449 450 byte[] retVal = new byte[6]; 451 int locoAddr_h = locoAddr / 256; 452 int locoAddr_l = locoAddr & 0xFF; 453 int cvAddr_h = cvAddr / 256; 454 int cvAddr_l = cvAddr & 0xFF; 455 456 retVal[0] = (byte) (NceMessage.OPS_PROG_LOCO_CMD); // NCE ops mode loco command 457 retVal[1] = (byte) (locoAddr_h); // loco high address 458 retVal[2] = (byte) (locoAddr_l); // loco low address 459 retVal[3] = (byte) (cvAddr_h); // CV high address 460 retVal[4] = (byte) (cvAddr_l); // CV low address 461 retVal[5] = (byte) (cvData); // CV data 462 463 return retVal; 464 } 465 466 /** 467 * Create a NCE USB compatible ops mode accessory message. 468 * 469 * @param accyAddr locomotive address 470 * @param cvAddr CV to set 471 * @param cvData value to set CV to 472 * @return ops mode message 473 */ 474 public static byte[] usbOpsModeAccy(int accyAddr, int cvAddr, int cvData) { 475 476 byte[] retVal = new byte[6]; 477 int accyAddr_h = accyAddr / 256; 478 int accyAddr_l = accyAddr & 0xFF; 479 int cvAddr_h = cvAddr / 256; 480 int cvAddr_l = cvAddr & 0xFF; 481 482 retVal[0] = (byte) (NceMessage.OPS_PROG_ACCY_CMD); // NCE ops mode accy command 483 retVal[1] = (byte) (accyAddr_h); // accy high address 484 retVal[2] = (byte) (accyAddr_l); // accy low address 485 retVal[3] = (byte) (cvAddr_h); // CV high address 486 retVal[4] = (byte) (cvAddr_l); // CV low address 487 retVal[5] = (byte) (cvData); // CV data 488 489 return retVal; 490 } 491 492 private final static Logger log = LoggerFactory.getLogger(NceBinaryCommand.class); 493}