001package jmri.jmrix.nce; 002 003import java.util.Arrays; 004 005import javax.annotation.CheckForNull; 006import javax.annotation.Nonnull; 007 008import jmri.jmrix.nce.ncemon.NceMonBinary; 009 010/** 011 * Encodes a message to an NCE command station. 012 * <p> 013 * The {@link NceReply} class handles the response from the command station. 014 * <p> 015 * The NCE protocol has "binary" and "ASCII" command sets. Depending on the 016 * version of the EPROM it contains, NCE command stations have different support 017 * for command sets: 018 * <ul> 019 * <li>1999 - All ASCII works. Binary works except for programming. 020 * <li>2004 - ASCII needed for programming, binary for everything else. 021 * <li>2006 - binary needed for everything 022 * </ul> 023 * See the {@link NceTrafficController#setCommandOptions(int)} method for more 024 * information. 025 * <p> 026 * Apparently the binary "exitProgrammingMode" command can crash the command 027 * station if the EPROM was built before 2006. This method uses a state flag 028 * ({@link NceTrafficController#getNceProgMode}) to detect whether a command to 029 * enter program mode has been generated, and presumably sent, when using the 030 * later EPROMS. 031 * 032 * @author Bob Jacobsen Copyright (C) 2001 033 * @author Daniel Boudreau Copyright (C) 2007 034 * @author kcameron Copyright (C) 2014 035 */ 036public class NceMessage extends jmri.jmrix.AbstractMRMessage { 037 038 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NceMessage.class); // called in static block 039 040 public static final int NOP_CMD = 0x80; //NCE NOP command 041 public static final int ASSIGN_CAB_CMD = 0x81; // NCE Assign loco to cab command, NCE-USB no 042 public static final int READ_CLOCK_CMD = 0x82; // NCE read clock command, NCE-USB no 043 public static final int STOP_CLOCK_CMD = 0x83; // NCE stop clock command, NCE-USB no 044 public static final int START_CLOCK_CMD = 0x84; // NCE start clock command, NCE-USB no 045 public static final int SET_CLOCK_CMD = 0x85; // NCE set clock command, NCE-USB no 046 public static final int CLOCK_1224_CMD = 0x86; // NCE change clock 12/24 command, NCE-USB no 047 public static final int CLOCK_RATIO_CMD = 0x87; // NCE set clock ratio command, NCE-USB no 048 public static final int DEQUEUE_CMD = 0x88; // NCE dequeue packets based on loco addr, NCE-USB no 049 050 public static final int READ_AUI4_CMD = 0x8A; // NCE read status of AUI yy, returns four bytes, NCE-USB no 051 052 public static final int DUMMY_CMD = 0x8C; // NCE Dummy instruction, NCE-USB yes 053 public static final int SPEED_MODE_CMD = 0x8D; // NCE set speed mode, NCE-USB no 054 public static final int WRITE_N_CMD = 0x8E; // NCE write up to 16 bytes of memory command, NCE-USB no 055 public static final int READ16_CMD = 0x8F; // NCE read 16 bytes of memory command, NCE-USB no 056 public static final int DISPLAY3_CMD = 0x90; // NCE write 16 char to cab display line 3, NCE-USB no 057 public static final int DISPLAY4_CMD = 0x91; // NCE write 16 char to cab display line 4, NCE-USB no 058 public static final int DISPLAY2_CMD = 0x92; // NCE write 8 char to cab display line 2 right, NCE-USB no 059 public static final int QUEUE3_TMP_CMD = 0x93; // NCE queue 3 bytes to temp queue, NCE-USB no 060 public static final int QUEUE4_TMP_CMD = 0x94; // NCE queue 4 bytes to temp queue, NCE-USB no 061 public static final int QUEUE5_TMP_CMD = 0x95; // NCE queue 5 bytes to temp queue, NCE-USB no 062 public static final int QUEUE6_TMP_CMD = 0x96; // NCE queue 6 bytes to temp queue, NCE-USB no 063 public static final int WRITE1_CMD = 0x97; // NCE write 1 bytes of memory command, NCE-USB no 064 public static final int WRITE2_CMD = 0x98; // NCE write 2 bytes of memory command, NCE-USB no 065 public static final int WRITE4_CMD = 0x99; // NCE write 4 bytes of memory command, NCE-USB no 066 public static final int WRITE8_CMD = 0x9A; // NCE write 8 bytes of memory command, NCE-USB no 067 public static final int READ_AUI2_CMD = 0x9B; // NCE read status of AUI yy, returns two bytes, NCE-USB >= 1.65 068 public static final int MACRO_CMD = 0x9C; // NCE execute macro n, NCE-USB yes 069 public static final int READ1_CMD = 0x9D; // NCE read 1 byte of memory command, NCE-USB no 070 public static final int ENTER_PROG_CMD = 0x9E; //NCE enter programming track mode command 071 public static final int EXIT_PROG_CMD = 0x9F; //NCE exit programming track mode command 072 public static final int WRITE_PAGED_CV_CMD = 0xA0; //NCE write CV paged command 073 public static final int READ_PAGED_CV_CMD = 0xA1; //NCE read CV paged command 074 public static final int LOCO_CMD = 0xA2; // NCE loco control command, NCE-USB yes 075 public static final int QUEUE3_TRK_CMD = 0xA3; // NCE queue 3 bytes to track queue, NCE-USB no 076 public static final int QUEUE4_TRK_CMD = 0xA4; // NCE queue 4 bytes to track queue, NCE-USB no 077 public static final int QUEUE5_TRK_CMD = 0xA5; // NCE queue 5 bytes to track queue, NCE-USB no 078 public static final int WRITE_REG_CMD = 0xA6; //NCE write register command 079 public static final int READ_REG_CMD = 0xA7; //NCE read register command 080 public static final int WRITE_DIR_CV_CMD = 0xA8; //NCE write CV direct command 081 public static final int READ_DIR_CV_CMD = 0xA9; //NCE read CV direct command 082 public static final int SW_REV_CMD = 0xAA; // NCE get EPROM revision cmd, Reply Format: VV.MM.mm, NCE-USB yes 083 public static final int RESET_SOFT_CMD = 0xAB; // NCE soft reset command, NCE-USB no 084 public static final int RESET_HARD_CMD = 0xAC; // NCE hard reset command, NCE-USB no 085 public static final int SEND_ACC_SIG_MACRO_CMD = 0xAD; // NCE send NMRA aspect command 086 public static final int OPS_PROG_LOCO_CMD = 0xAE; // NCE ops mode program loco, NCE-USB yes 087 public static final int OPS_PROG_ACCY_CMD = 0xAF; // NCE ops mode program accessories, NCE-USB yes 088 public static final int FACTORY_TEST_CMD = 0xB0; // NCE factory test, NCE-USB yes 089 public static final int USB_SET_CAB_CMD = 0xB1; // NCE set cab address in USB, NCE-USB yes 090 public static final int USB_MEM_POINTER_CMD = 0xB3; // NCE set memory context pointer, NCE-USB >= 1.65 091 public static final int USB_MEM_WRITE_CMD = 0xB4; // NCE write memory, NCE-USB >= 1.65 092 public static final int USB_MEM_READ_CMD = 0xB5; // NCE read memory, NCE-USB >= 1.65 093 094 // NCE Command 0xA2 sends speed or function packets to a locomotive 095 // 0xA2 sub commands speed and functions 096 public static final byte LOCO_CMD_SELECT_LOCO = 0x00; // select loco 097 public static final byte LOCO_CMD_REV_28SPEED = 0x01; // set loco speed 28 steps reverse 098 public static final byte LOCO_CMD_FWD_28SPEED = 0x02; // set loco speed 28 steps forward 099 public static final byte LOCO_CMD_REV_128SPEED = 0x03; // set loco speed 128 steps reverse 100 public static final byte LOCO_CMD_FWD_128SPEED = 0x04; // set loco speed 128 steps forward 101 public static final byte LOCO_CMD_REV_ESTOP = 0x05; // emergency stop reverse 102 public static final byte LOCO_CMD_FWD_ESTOP = 0x06; // emergency stop forward 103 public static final byte LOCO_CMD_FG1 = 0x07; // function group 1 104 public static final byte LOCO_CMD_FG2 = 0x08; // function group 2 105 public static final byte LOCO_CMD_FG3 = 0x09; // function group 3 106 public static final byte LOCO_CMD_FG4 = 0x15; // function group 4 107 public static final byte LOCO_CMD_FG5 = 0x16; // function group 5 108 109 // OxA2 sub commands consist 110 public static final byte LOCO_CMD_REV_CONSIST_LEAD = 0x0A; // reverse consist address for lead loco 111 public static final byte LOCO_CMD_FWD_CONSIST_LEAD = 0x0B; // forward consist address for lead loco 112 public static final byte LOCO_CMD_REV_CONSIST_REAR = 0x0C; // reverse consist address for rear loco 113 public static final byte LOCO_CMD_FWD_CONSIST_REAR = 0x0D; // forward consist address for rear loco 114 public static final byte LOCO_CMD_REV_CONSIST_MID = 0x0E; // reverse consist address for additional loco 115 public static final byte LOCO_CMD_FWD_CONSIST_MID = 0x0F; // forward consist address for additional loco 116 public static final byte LOCO_CMD_DELETE_LOCO_CONSIST = 0x10; // Delete loco from consist 117 public static final byte LOCO_CMD_KILL_CONSIST = 0x11; // Kill consist 118 119 // The following commands are not supported by the NCE USB 120 public static final int ENABLE_MAIN_CMD = 0x89; //NCE enable main track, kill programming command 121 public static final int KILL_MAIN_CMD = 0x8B; //NCE kill main track, enable programming command 122 public static final int SENDn_BYTES_CMD = 0x90; //NCE send 3 to 6 bytes (0x9n, n = 3-6) command 123 public static final int QUEUEn_BYTES_CMD = 0xA0; //NCE queue 3 to 6 bytes (0xAn, n = 3-6) command 124 125 // some constants 126 protected static final int NCE_PAGED_CV_TIMEOUT = 20000; 127 protected static final int NCE_DIRECT_CV_TIMEOUT = 10000; 128 129 @SuppressWarnings("hiding") // redefines value from super class 130 protected static final int SHORT_TIMEOUT = 10000; // worst case is when loading the first panel 131 132 public static final int REPLY_1 = 1; // reply length of 1 byte 133 public static final int REPLY_2 = 2; // reply length of 2 bytes 134 public static final int REPLY_3 = 3; // reply length of 3 bytes 135 public static final int REPLY_4 = 4; // reply length of 4 bytes 136 public static final int REPLY_16 = 16; // reply length of 16 bytes 137 138 public static char NCE_OKAY = '!'; 139 140 public NceMessage() { 141 super(); 142 } 143 144 // create a new one 145 public NceMessage(int i) { 146 super(i); 147 } 148 149 // copy one 150 public NceMessage(@Nonnull NceMessage m) { 151 super(m); 152 replyLen = m.replyLen; 153 } 154 155 // from String 156 public NceMessage(@Nonnull String m) { 157 super(m); 158 } 159 160 // default to expecting one reply character 161 int replyLen = 1; 162 163 /** 164 * Set the number of characters expected back from the command station. Used 165 * in binary mode, where there's no end-of-reply string to look for. 166 * 167 * @param len length of expected reply 168 */ 169 public void setReplyLen(int len) { 170 replyLen = len; 171 } 172 173 public int getReplyLen() { 174 return replyLen; 175 } 176 177 // diagnose format 178 public boolean isKillMain() { 179 if (isBinary()) { 180 return getOpCode() == KILL_MAIN_CMD; 181 } else { 182 return getOpCode() == 'K'; 183 } 184 } 185 186 public boolean isEnableMain() { 187 if (isBinary()) { 188 return getOpCode() == ENABLE_MAIN_CMD; 189 } else { 190 return getOpCode() == 'E'; 191 } 192 } 193 194 // static methods to return a formatted message 195 public static NceMessage getEnableMain(NceTrafficController tc) { 196 // this command isn't supported by the NCE USB 197 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE) { 198 log.error("attempt to send unsupported binary command ENABLE_MAIN_CMD to NCE USB"); 199 return null; 200 } 201 NceMessage m = new NceMessage(1); 202 if (tc.getCommandOptions() >= NceTrafficController.OPTION_1999) { 203 m.setBinary(true); 204 m.setReplyLen(1); 205 m.setOpCode(ENABLE_MAIN_CMD); 206 } else { 207 m.setBinary(false); 208 m.setOpCode('E'); 209 } 210 return m; 211 } 212 213 public static NceMessage getKillMain(NceTrafficController tc) { 214 // this command isn't supported by the NCE USB 215 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE) { 216 log.error("attempt to send unsupported binary command KILL_MAIN_CMD to NCE USB"); 217 return null; 218 } 219 NceMessage m = new NceMessage(1); 220 if (tc.getCommandOptions() >= NceTrafficController.OPTION_1999) { 221 m.setBinary(true); 222 m.setReplyLen(REPLY_1); 223 m.setOpCode(KILL_MAIN_CMD); 224 } else { 225 m.setBinary(false); 226 m.setOpCode('K'); 227 } 228 return m; 229 } 230 231 /** 232 * enter programming track mode 233 * 234 * @param tc controller for the associated connection 235 * @return a new message to enter programming track mode 236 */ 237 @Nonnull 238 public static NceMessage getProgMode(@Nonnull NceTrafficController tc) { 239 // test if supported on current connection 240 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE && 241 (tc.getCmdGroups() & NceTrafficController.CMDS_PROGTRACK) != NceTrafficController.CMDS_PROGTRACK) { 242 log.error("attempt to send unsupported binary command ENTER_PROG_CMD to NCE USB"); 243 // return null; 244 } 245 NceMessage m = new NceMessage(1); 246 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 247 tc.setNceProgMode(true); 248 m.setBinary(true); 249 m.setReplyLen(REPLY_1); 250 m.setOpCode(ENTER_PROG_CMD); 251 m.setTimeout(SHORT_TIMEOUT); 252 } else { 253 m.setBinary(false); 254 m.setOpCode('M'); 255 m.setTimeout(SHORT_TIMEOUT); 256 } 257 return m; 258 } 259 260 /** 261 * Apparently the binary "exitProgrammingMode" command can crash the command 262 * station if the EPROM was built before 2006. This method uses a state flag 263 * ({@link NceTrafficController#getNceProgMode}) to detect whether a command 264 * to enter program mode has been generated, and presumably sent, when using 265 * the later EPROMS. 266 * 267 * @param tc controller for the associated connection 268 * @return a new message to exit programming track mode 269 */ 270 @CheckForNull 271 public static NceMessage getExitProgMode(@Nonnull NceTrafficController tc) { 272 NceMessage m = new NceMessage(1); 273 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 274 // Sending exit programming mode binary can crash pre 2006 EPROMs 275 // assumption is that program mode hasn't been entered, so exit without 276 // sending command 277 if (tc.getNceProgMode() == false) { 278 return null; 279 } 280 // not supported by USB connected to SB3 or PH 281 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 282 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 283 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 284 log.error("attempt to send unsupported binary command EXIT_PROG_CMD to NCE USB"); 285 // return null; 286 } 287 tc.setNceProgMode(false); 288 m.setBinary(true); 289 m.setReplyLen(REPLY_1); 290 m.setOpCode(EXIT_PROG_CMD); 291 m.setTimeout(SHORT_TIMEOUT); 292 } else { 293 m.setBinary(false); 294 m.setOpCode('X'); 295 m.setTimeout(SHORT_TIMEOUT); 296 } 297 return m; 298 } 299 300 /** 301 * Read Paged mode CV on programming track. 302 * 303 * @param tc controller for the associated connection 304 * @param cv the CV to read 305 * @return a new message to read a CV 306 */ 307 @Nonnull 308 public static NceMessage getReadPagedCV(@Nonnull NceTrafficController tc, int cv) { 309 // test if supported on current connection 310 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE && 311 (tc.getCmdGroups() & NceTrafficController.CMDS_PROGTRACK) != NceTrafficController.CMDS_PROGTRACK) { 312 log.error("attempt to send unsupported binary command READ_PAGED_CV_CMD to NCE USB"); 313 // return null; 314 } 315 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 316 NceMessage m = new NceMessage(3); 317 m.setBinary(true); 318 m.setReplyLen(REPLY_2); 319 m.setOpCode(READ_PAGED_CV_CMD); 320 m.setElement(1, (cv >> 8)); 321 m.setElement(2, (cv & 0x0FF)); 322 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 323 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 324 return m; 325 } else { 326 NceMessage m = new NceMessage(4); 327 m.setBinary(false); 328 m.setOpCode('R'); 329 m.addIntAsThree(cv, 1); 330 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 331 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 332 return m; 333 } 334 } 335 336 /** 337 * Write paged mode CV to programming track. 338 * 339 * @param tc controller for the associated connection 340 * @param cv CV to write 341 * @param val value to write to cv 342 * @return a new message to write a CV 343 */ 344 @Nonnull 345 public static NceMessage getWritePagedCV(@Nonnull NceTrafficController tc, int cv, int val) { 346 // test if supported on current connection 347 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE && 348 (tc.getCmdGroups() & NceTrafficController.CMDS_PROGTRACK) != NceTrafficController.CMDS_PROGTRACK) { 349 log.error("attempt to send unsupported binary command WRITE_PAGED_CV_CMD to NCE USB"); 350 // return null; 351 } 352 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 353 NceMessage m = new NceMessage(4); 354 m.setBinary(true); 355 m.setReplyLen(REPLY_1); 356 m.setOpCode(WRITE_PAGED_CV_CMD); 357 m.setElement(1, cv >> 8); 358 m.setElement(2, cv & 0xFF); 359 m.setElement(3, val); 360 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 361 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 362 return m; 363 } else { 364 NceMessage m = new NceMessage(8); 365 m.setBinary(false); 366 m.setOpCode('P'); 367 m.addIntAsThree(cv, 1); 368 m.setElement(4, ' '); 369 m.addIntAsThree(val, 5); 370 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 371 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 372 return m; 373 } 374 } 375 376 @CheckForNull 377 public static NceMessage getReadRegister(@Nonnull NceTrafficController tc, int reg) { 378 // not supported by USB connected to SB3 or PH 379 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 380 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 381 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 382 log.error("attempt to send unsupported binary command READ_REG_CMD to NCE USB"); 383 return null; 384 } 385 if (reg > 8) { 386 log.error("register number too large: {}", reg); 387 } 388 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 389 NceMessage m = new NceMessage(2); 390 m.setBinary(true); 391 m.setReplyLen(REPLY_2); 392 m.setOpCode(READ_REG_CMD); 393 m.setElement(1, reg); 394 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 395 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 396 return m; 397 } else { 398 NceMessage m = new NceMessage(2); 399 m.setBinary(false); 400 m.setOpCode('V'); 401 String s = "" + reg; 402 m.setElement(1, s.charAt(s.length() - 1)); 403 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 404 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 405 return m; 406 } 407 } 408 409 public static NceMessage getWriteRegister(NceTrafficController tc, int reg, int val) { 410 // not supported by USB connected to SB3 or PH 411 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 412 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 413 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 414 log.error("attempt to send unsupported binary command WRITE_REG_CMD to NCE USB"); 415 return null; 416 } 417 if (reg > 8) { 418 log.error("register number too large: {}", reg); 419 } 420 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 421 NceMessage m = new NceMessage(3); 422 m.setBinary(true); 423 m.setReplyLen(REPLY_1); 424 m.setOpCode(WRITE_REG_CMD); 425 m.setElement(1, reg); 426 m.setElement(2, val); 427 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 428 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 429 return m; 430 } else { 431 NceMessage m = new NceMessage(6); 432 m.setBinary(false); 433 m.setOpCode('S'); 434 String s = "" + reg; 435 m.setElement(1, s.charAt(s.length() - 1)); 436 m.setElement(2, ' '); 437 m.addIntAsThree(val, 3); 438 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 439 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 440 return m; 441 } 442 } 443 444 public static NceMessage getReadDirectCV(NceTrafficController tc, int cv) { 445 // not supported by USB connected to SB3 or PH 446 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 447 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 448 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 449 log.error("attempt to send unsupported binary command READ_DIR_CV_CMD to NCE USB"); 450 return null; 451 } 452 if (tc.getCommandOptions() < NceTrafficController.OPTION_2006) { 453 log.error("getReadDirectCV with option {}", tc.getCommandOptions()); 454 return null; 455 } 456 NceMessage m = new NceMessage(3); 457 m.setBinary(true); 458 m.setReplyLen(REPLY_2); 459 m.setOpCode(READ_DIR_CV_CMD); 460 m.setElement(1, (cv >> 8)); 461 m.setElement(2, (cv & 0x0FF)); 462 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 463 m.setTimeout(NCE_DIRECT_CV_TIMEOUT); 464 return m; 465 } 466 467 public static NceMessage getWriteDirectCV(NceTrafficController tc, int cv, int val) { 468 // not supported by USB connected to SB3 or PH 469 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 470 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 471 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 472 log.error("attempt to send unsupported binary command WRITE_DIR_CV_CMD to NCE USB"); 473 return null; 474 } 475 if (tc.getCommandOptions() < NceTrafficController.OPTION_2006) { 476 log.error("getWriteDirectCV with option {}", tc.getCommandOptions()); 477 } 478 NceMessage m = new NceMessage(4); 479 m.setBinary(true); 480 m.setReplyLen(REPLY_1); 481 m.setOpCode(WRITE_DIR_CV_CMD); 482 m.setElement(1, cv >> 8); 483 m.setElement(2, cv & 0xFF); 484 m.setElement(3, val); 485 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 486 m.setTimeout(NCE_DIRECT_CV_TIMEOUT); 487 return m; 488 } 489 490 public static NceMessage getEpromVersion(NceTrafficController tc) { 491 byte[] bl = NceBinaryCommand.getNceEpromRev(); 492 NceMessage m = NceMessage.createBinaryMessage(tc, bl, REPLY_3); 493 return m; 494 } 495 496 public static NceMessage sendLocoCmd(NceTrafficController tc, int locoAddr, byte locoSubCmd, byte locoData) { 497 byte[] bl = NceBinaryCommand.nceLocoCmd(locoAddr, locoSubCmd, locoData); 498 NceMessage m = NceMessage.createBinaryMessage(tc, bl, REPLY_1); 499 return m; 500 } 501 502 public static NceMessage sendPacketMessage(NceTrafficController tc, byte[] bytes) { 503 NceMessage m = sendPacketMessage(tc, bytes, 2); 504 return m; 505 } 506 507 public static NceMessage sendPacketMessage(NceTrafficController tc, byte[] bytes, int retries) { 508 // this command isn't supported by the NCE USB 509 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE) { 510 log.error("attempt to send unsupported sendPacketMessage to NCE USB cmd: 0x{}", Integer.toHexString(SENDn_BYTES_CMD + bytes.length)); 511 return null; 512 } 513 if (tc.getCommandOptions() >= NceTrafficController.OPTION_1999) { 514 if (bytes.length < 3 || bytes.length > 6) { 515 log.error("Send of NCE track packet too short or long:{} packet:{}", Integer.toString(bytes.length), Arrays.toString(bytes)); 516 } 517 NceMessage m = new NceMessage(2 + bytes.length); 518 m.setBinary(true); 519 m.setTimeout(SHORT_TIMEOUT); 520 m.setReplyLen(1); 521 int i = 0; // counter to make it easier to format the message 522 523 m.setElement(i++, SENDn_BYTES_CMD + bytes.length); 524 m.setElement(i++, retries); // send this many retries. 525 for (int j = 0; j < bytes.length; j++) { 526 m.setElement(i++, bytes[j] & 0xFF); 527 } 528 return m; 529 } else { 530 NceMessage m = new NceMessage(5 + 3 * bytes.length); 531 m.setBinary(false); 532 int i = 0; // counter to make it easier to format the message 533 534 m.setElement(i++, 'S'); // "S C02 " means sent it twice 535 m.setElement(i++, ' '); 536 m.setElement(i++, 'C'); 537 m.setElement(i++, '0'); 538 m.setElement(i++, '2'); 539 540 for (int j = 0; j < bytes.length; j++) { 541 m.setElement(i++, ' '); 542 m.addIntAsTwoHex(bytes[j] & 0xFF, i); 543 i = i + 2; 544 } 545 m.setTimeout(SHORT_TIMEOUT); 546 return m; 547 } 548 } 549 550 public static NceMessage createBinaryMessage(NceTrafficController tc, byte[] bytes) { 551 return createBinaryMessage(tc, bytes, REPLY_1); 552 } 553 554 public static NceMessage createBinaryMessage(NceTrafficController tc, byte[] bytes, int replyLen) { 555 if (tc.getCommandOptions() < NceTrafficController.OPTION_2004) { 556 log.error("Attempt to send NCE command to EPROM built before 2004"); 557 } 558 if (bytes.length < 1 || bytes.length > 20) { 559 log.error("NCE command message length error:{}", bytes.length); 560 } 561 562 NceMessage m = new NceMessage(bytes.length); 563 m.setBinary(true); 564 m.setReplyLen(replyLen); 565 m.setTimeout(SHORT_TIMEOUT); 566 567 for (int j = 0; j < bytes.length; j++) { 568 m.setElement(j, bytes[j] & 0xFF); 569 } 570 return m; 571 } 572 573 public static NceMessage queuePacketMessage(NceTrafficController tc, byte[] bytes) { 574 // this command isn't supported by the NCE USB 575 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE) { 576 log.error("attempt to send unsupported queuePacketMessage to NCE USB"); 577 return null; 578 } 579 if (tc.getCommandOptions() >= NceTrafficController.OPTION_1999) { 580 if (bytes.length < 3 || bytes.length > 6) { 581 log.error("Queue of NCE track packet too long:{} packet :{}", Integer.toString(bytes.length), Arrays.toString(bytes)); 582 } 583 NceMessage m = new NceMessage(1 + bytes.length); 584 m.setBinary(true); 585 m.setReplyLen(REPLY_1); 586 int i = 0; // counter to make it easier to format the message 587 588 m.setElement(i++, QUEUEn_BYTES_CMD + bytes.length); 589 for (int j = 0; j < bytes.length; j++) { 590 m.setElement(i++, bytes[j] & 0xFF); 591 } 592 return m; 593 } else { 594 NceMessage m = new NceMessage(1 + 3 * bytes.length); 595 m.setBinary(false); 596 int i = 0; // counter to make it easier to format the message 597 598 m.setElement(i++, 'Q'); // "S C02 " means sent it twice 599 600 for (int j = 0; j < bytes.length; j++) { 601 m.setElement(i++, ' '); 602 m.addIntAsTwoHex(bytes[j] & 0xFF, i); 603 i = i + 2; 604 } 605 return m; 606 } 607 } 608 609 public static NceMessage createAccySignalMacroMessage(NceTrafficController tc, int op, int addr, int data) { 610 if (tc.getCommandOptions() < NceTrafficController.OPTION_2004) { 611 log.error("Attempt to send NCE command to EPROM built before 2004"); 612 } 613 NceMessage m = new NceMessage(5); 614 m.setBinary(true); 615 m.setReplyLen(REPLY_1); 616 m.setTimeout(SHORT_TIMEOUT); 617 m.setOpCode(SEND_ACC_SIG_MACRO_CMD); 618 m.setElement(1, (addr >> 8) & 0xFF); 619 m.setElement(2, addr & 0xFF); 620 m.setElement(3, op); 621 m.setElement(4, data); 622 return m; 623 } 624 625 public static NceMessage createAccDecoderPktOpsMode(NceTrafficController tc, int accyAddr, int cvAddr, int cvData) { 626 NceMessage m = new NceMessage(6); 627 m.setBinary(true); 628 m.setReplyLen(REPLY_1); 629 m.setTimeout(SHORT_TIMEOUT); 630 byte[] mess = NceBinaryCommand.usbOpsModeAccy(accyAddr, cvAddr, cvData); 631 m.setOpCode(mess[0]); 632 m.setElement(1, mess[1]); 633 m.setElement(2, mess[2]); 634 m.setElement(3, mess[3]); 635 m.setElement(4, mess[4]); 636 m.setElement(5, mess[5]); 637 return m; 638 } 639 640 /** 641 * {@inheritDoc} 642 */ 643 @Override 644 public String toMonitorString() { 645 return NceMonBinary.INSTANCE.displayMessage(this); 646 } 647}