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