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 protected static final int SHORT_TIMEOUT = 10000; // worst case is when loading the first panel 128 129 public static final int REPLY_1 = 1; // reply length of 1 byte 130 public static final int REPLY_2 = 2; // reply length of 2 bytes 131 public static final int REPLY_3 = 3; // reply length of 3 bytes 132 public static final int REPLY_4 = 4; // reply length of 4 bytes 133 public static final int REPLY_16 = 16; // reply length of 16 bytes 134 135 public static char NCE_OKAY = '!'; 136 137 public NceMessage() { 138 super(); 139 } 140 141 // create a new one 142 public NceMessage(int i) { 143 super(i); 144 } 145 146 // copy one 147 public NceMessage(@Nonnull NceMessage m) { 148 super(m); 149 replyLen = m.replyLen; 150 } 151 152 // from String 153 public NceMessage(@Nonnull String m) { 154 super(m); 155 } 156 157 // default to expecting one reply character 158 int replyLen = 1; 159 160 /** 161 * Set the number of characters expected back from the command station. Used 162 * in binary mode, where there's no end-of-reply string to look for. 163 * 164 * @param len length of expected reply 165 */ 166 public void setReplyLen(int len) { 167 replyLen = len; 168 } 169 170 public int getReplyLen() { 171 return replyLen; 172 } 173 174 // diagnose format 175 public boolean isKillMain() { 176 if (isBinary()) { 177 return getOpCode() == KILL_MAIN_CMD; 178 } else { 179 return getOpCode() == 'K'; 180 } 181 } 182 183 public boolean isEnableMain() { 184 if (isBinary()) { 185 return getOpCode() == ENABLE_MAIN_CMD; 186 } else { 187 return getOpCode() == 'E'; 188 } 189 } 190 191 // static methods to return a formatted message 192 public static NceMessage getEnableMain(NceTrafficController tc) { 193 // this command isn't supported by the NCE USB 194 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE) { 195 log.error("attempt to send unsupported binary command ENABLE_MAIN_CMD to NCE USB"); 196 return null; 197 } 198 NceMessage m = new NceMessage(1); 199 if (tc.getCommandOptions() >= NceTrafficController.OPTION_1999) { 200 m.setBinary(true); 201 m.setReplyLen(1); 202 m.setOpCode(ENABLE_MAIN_CMD); 203 } else { 204 m.setBinary(false); 205 m.setOpCode('E'); 206 } 207 return m; 208 } 209 210 public static NceMessage getKillMain(NceTrafficController tc) { 211 // this command isn't supported by the NCE USB 212 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE) { 213 log.error("attempt to send unsupported binary command KILL_MAIN_CMD to NCE USB"); 214 return null; 215 } 216 NceMessage m = new NceMessage(1); 217 if (tc.getCommandOptions() >= NceTrafficController.OPTION_1999) { 218 m.setBinary(true); 219 m.setReplyLen(REPLY_1); 220 m.setOpCode(KILL_MAIN_CMD); 221 } else { 222 m.setBinary(false); 223 m.setOpCode('K'); 224 } 225 return m; 226 } 227 228 /** 229 * enter programming track mode 230 * 231 * @param tc controller for the associated connection 232 * @return a new message to enter programming track mode 233 */ 234 @Nonnull 235 public static NceMessage getProgMode(@Nonnull NceTrafficController tc) { 236 // test if supported on current connection 237 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE && 238 (tc.getCmdGroups() & NceTrafficController.CMDS_PROGTRACK) != NceTrafficController.CMDS_PROGTRACK) { 239 log.error("attempt to send unsupported binary command ENTER_PROG_CMD to NCE USB"); 240 // return null; 241 } 242 NceMessage m = new NceMessage(1); 243 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 244 tc.setNceProgMode(true); 245 m.setBinary(true); 246 m.setReplyLen(REPLY_1); 247 m.setOpCode(ENTER_PROG_CMD); 248 m.setTimeout(SHORT_TIMEOUT); 249 } else { 250 m.setBinary(false); 251 m.setOpCode('M'); 252 m.setTimeout(SHORT_TIMEOUT); 253 } 254 return m; 255 } 256 257 /** 258 * Apparently the binary "exitProgrammingMode" command can crash the command 259 * station if the EPROM was built before 2006. This method uses a state flag 260 * ({@link NceTrafficController#getNceProgMode}) to detect whether a command 261 * to enter program mode has been generated, and presumably sent, when using 262 * the later EPROMS. 263 * 264 * @param tc controller for the associated connection 265 * @return a new message to exit programming track mode 266 */ 267 @CheckForNull 268 public static NceMessage getExitProgMode(@Nonnull NceTrafficController tc) { 269 NceMessage m = new NceMessage(1); 270 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 271 // Sending exit programming mode binary can crash pre 2006 EPROMs 272 // assumption is that program mode hasn't been entered, so exit without 273 // sending command 274 if (tc.getNceProgMode() == false) { 275 return null; 276 } 277 // not supported by USB connected to SB3 or PH 278 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 279 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 280 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 281 log.error("attempt to send unsupported binary command EXIT_PROG_CMD to NCE USB"); 282 // return null; 283 } 284 tc.setNceProgMode(false); 285 m.setBinary(true); 286 m.setReplyLen(REPLY_1); 287 m.setOpCode(EXIT_PROG_CMD); 288 m.setTimeout(SHORT_TIMEOUT); 289 } else { 290 m.setBinary(false); 291 m.setOpCode('X'); 292 m.setTimeout(SHORT_TIMEOUT); 293 } 294 return m; 295 } 296 297 /** 298 * Read Paged mode CV on programming track. 299 * 300 * @param tc controller for the associated connection 301 * @param cv the CV to read 302 * @return a new message to read a CV 303 */ 304 @Nonnull 305 public static NceMessage getReadPagedCV(@Nonnull NceTrafficController tc, int cv) { 306 // test if supported on current connection 307 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE && 308 (tc.getCmdGroups() & NceTrafficController.CMDS_PROGTRACK) != NceTrafficController.CMDS_PROGTRACK) { 309 log.error("attempt to send unsupported binary command READ_PAGED_CV_CMD to NCE USB"); 310 // return null; 311 } 312 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 313 NceMessage m = new NceMessage(3); 314 m.setBinary(true); 315 m.setReplyLen(REPLY_2); 316 m.setOpCode(READ_PAGED_CV_CMD); 317 m.setElement(1, (cv >> 8)); 318 m.setElement(2, (cv & 0x0FF)); 319 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 320 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 321 return m; 322 } else { 323 NceMessage m = new NceMessage(4); 324 m.setBinary(false); 325 m.setOpCode('R'); 326 m.addIntAsThree(cv, 1); 327 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 328 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 329 return m; 330 } 331 } 332 333 /** 334 * Write paged mode CV to programming track. 335 * 336 * @param tc controller for the associated connection 337 * @param cv CV to write 338 * @param val value to write to cv 339 * @return a new message to write a CV 340 */ 341 @Nonnull 342 public static NceMessage getWritePagedCV(@Nonnull NceTrafficController tc, int cv, int val) { 343 // test if supported on current connection 344 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE && 345 (tc.getCmdGroups() & NceTrafficController.CMDS_PROGTRACK) != NceTrafficController.CMDS_PROGTRACK) { 346 log.error("attempt to send unsupported binary command WRITE_PAGED_CV_CMD to NCE USB"); 347 // return null; 348 } 349 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 350 NceMessage m = new NceMessage(4); 351 m.setBinary(true); 352 m.setReplyLen(REPLY_1); 353 m.setOpCode(WRITE_PAGED_CV_CMD); 354 m.setElement(1, cv >> 8); 355 m.setElement(2, cv & 0xFF); 356 m.setElement(3, val); 357 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 358 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 359 return m; 360 } else { 361 NceMessage m = new NceMessage(8); 362 m.setBinary(false); 363 m.setOpCode('P'); 364 m.addIntAsThree(cv, 1); 365 m.setElement(4, ' '); 366 m.addIntAsThree(val, 5); 367 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 368 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 369 return m; 370 } 371 } 372 373 @CheckForNull 374 public static NceMessage getReadRegister(@Nonnull NceTrafficController tc, int reg) { 375 // not supported by USB connected to SB3 or PH 376 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 377 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 378 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 379 log.error("attempt to send unsupported binary command READ_REG_CMD to NCE USB"); 380 return null; 381 } 382 if (reg > 8) { 383 log.error("register number too large: {}", reg); 384 } 385 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 386 NceMessage m = new NceMessage(2); 387 m.setBinary(true); 388 m.setReplyLen(REPLY_2); 389 m.setOpCode(READ_REG_CMD); 390 m.setElement(1, reg); 391 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 392 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 393 return m; 394 } else { 395 NceMessage m = new NceMessage(2); 396 m.setBinary(false); 397 m.setOpCode('V'); 398 String s = "" + reg; 399 m.setElement(1, s.charAt(s.length() - 1)); 400 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 401 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 402 return m; 403 } 404 } 405 406 public static NceMessage getWriteRegister(NceTrafficController tc, int reg, int val) { 407 // not supported by USB connected to SB3 or PH 408 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 409 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 410 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 411 log.error("attempt to send unsupported binary command WRITE_REG_CMD to NCE USB"); 412 return null; 413 } 414 if (reg > 8) { 415 log.error("register number too large: {}", reg); 416 } 417 if (tc.getCommandOptions() >= NceTrafficController.OPTION_2006) { 418 NceMessage m = new NceMessage(3); 419 m.setBinary(true); 420 m.setReplyLen(REPLY_1); 421 m.setOpCode(WRITE_REG_CMD); 422 m.setElement(1, reg); 423 m.setElement(2, val); 424 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 425 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 426 return m; 427 } else { 428 NceMessage m = new NceMessage(6); 429 m.setBinary(false); 430 m.setOpCode('S'); 431 String s = "" + reg; 432 m.setElement(1, s.charAt(s.length() - 1)); 433 m.setElement(2, ' '); 434 m.addIntAsThree(val, 3); 435 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 436 m.setTimeout(NCE_PAGED_CV_TIMEOUT); 437 return m; 438 } 439 } 440 441 public static NceMessage getReadDirectCV(NceTrafficController tc, int cv) { 442 // not supported by USB connected to SB3 or PH 443 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 444 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 445 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 446 log.error("attempt to send unsupported binary command READ_DIR_CV_CMD to NCE USB"); 447 return null; 448 } 449 if (tc.getCommandOptions() < NceTrafficController.OPTION_2006) { 450 log.error("getReadDirectCV with option {}", tc.getCommandOptions()); 451 return null; 452 } 453 NceMessage m = new NceMessage(3); 454 m.setBinary(true); 455 m.setReplyLen(REPLY_2); 456 m.setOpCode(READ_DIR_CV_CMD); 457 m.setElement(1, (cv >> 8)); 458 m.setElement(2, (cv & 0x0FF)); 459 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 460 m.setTimeout(NCE_DIRECT_CV_TIMEOUT); 461 return m; 462 } 463 464 public static NceMessage getWriteDirectCV(NceTrafficController tc, int cv, int val) { 465 // not supported by USB connected to SB3 or PH 466 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB3 || 467 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_SB5 || 468 tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_POWERPRO) { 469 log.error("attempt to send unsupported binary command WRITE_DIR_CV_CMD to NCE USB"); 470 return null; 471 } 472 if (tc.getCommandOptions() < NceTrafficController.OPTION_2006) { 473 log.error("getWriteDirectCV with option {}", tc.getCommandOptions()); 474 } 475 NceMessage m = new NceMessage(4); 476 m.setBinary(true); 477 m.setReplyLen(REPLY_1); 478 m.setOpCode(WRITE_DIR_CV_CMD); 479 m.setElement(1, cv >> 8); 480 m.setElement(2, cv & 0xFF); 481 m.setElement(3, val); 482 m.setNeededMode(jmri.jmrix.AbstractMRTrafficController.PROGRAMINGMODE); 483 m.setTimeout(NCE_DIRECT_CV_TIMEOUT); 484 return m; 485 } 486 487 public static NceMessage getEpromVersion(NceTrafficController tc) { 488 byte[] bl = NceBinaryCommand.getNceEpromRev(); 489 NceMessage m = NceMessage.createBinaryMessage(tc, bl, REPLY_3); 490 return m; 491 } 492 493 public static NceMessage sendLocoCmd(NceTrafficController tc, int locoAddr, byte locoSubCmd, byte locoData) { 494 byte[] bl = NceBinaryCommand.nceLocoCmd(locoAddr, locoSubCmd, locoData); 495 NceMessage m = NceMessage.createBinaryMessage(tc, bl, REPLY_1); 496 return m; 497 } 498 499 public static NceMessage sendPacketMessage(NceTrafficController tc, byte[] bytes) { 500 NceMessage m = sendPacketMessage(tc, bytes, 2); 501 return m; 502 } 503 504 public static NceMessage sendPacketMessage(NceTrafficController tc, byte[] bytes, int retries) { 505 // this command isn't supported by the NCE USB 506 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE) { 507 log.error("attempt to send unsupported sendPacketMessage to NCE USB cmd: 0x{}", Integer.toHexString(SENDn_BYTES_CMD + bytes.length)); 508 return null; 509 } 510 if (tc.getCommandOptions() >= NceTrafficController.OPTION_1999) { 511 if (bytes.length < 3 || bytes.length > 6) { 512 log.error("Send of NCE track packet too short or long:{} packet:{}", Integer.toString(bytes.length), Arrays.toString(bytes)); 513 } 514 NceMessage m = new NceMessage(2 + bytes.length); 515 m.setBinary(true); 516 m.setTimeout(SHORT_TIMEOUT); 517 m.setReplyLen(1); 518 int i = 0; // counter to make it easier to format the message 519 520 m.setElement(i++, SENDn_BYTES_CMD + bytes.length); 521 m.setElement(i++, retries); // send this many retries. 522 for (int j = 0; j < bytes.length; j++) { 523 m.setElement(i++, bytes[j] & 0xFF); 524 } 525 return m; 526 } else { 527 NceMessage m = new NceMessage(5 + 3 * bytes.length); 528 m.setBinary(false); 529 int i = 0; // counter to make it easier to format the message 530 531 m.setElement(i++, 'S'); // "S C02 " means sent it twice 532 m.setElement(i++, ' '); 533 m.setElement(i++, 'C'); 534 m.setElement(i++, '0'); 535 m.setElement(i++, '2'); 536 537 for (int j = 0; j < bytes.length; j++) { 538 m.setElement(i++, ' '); 539 m.addIntAsTwoHex(bytes[j] & 0xFF, i); 540 i = i + 2; 541 } 542 m.setTimeout(SHORT_TIMEOUT); 543 return m; 544 } 545 } 546 547 public static NceMessage createBinaryMessage(NceTrafficController tc, byte[] bytes) { 548 return createBinaryMessage(tc, bytes, REPLY_1); 549 } 550 551 public static NceMessage createBinaryMessage(NceTrafficController tc, byte[] bytes, int replyLen) { 552 if (tc.getCommandOptions() < NceTrafficController.OPTION_2004) { 553 log.error("Attempt to send NCE command to EPROM built before 2004"); 554 } 555 if (bytes.length < 1 || bytes.length > 20) { 556 log.error("NCE command message length error:{}", bytes.length); 557 } 558 559 NceMessage m = new NceMessage(bytes.length); 560 m.setBinary(true); 561 m.setReplyLen(replyLen); 562 m.setTimeout(SHORT_TIMEOUT); 563 564 for (int j = 0; j < bytes.length; j++) { 565 m.setElement(j, bytes[j] & 0xFF); 566 } 567 return m; 568 } 569 570 public static NceMessage queuePacketMessage(NceTrafficController tc, byte[] bytes) { 571 // this command isn't supported by the NCE USB 572 if (tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE) { 573 log.error("attempt to send unsupported queuePacketMessage to NCE USB"); 574 return null; 575 } 576 if (tc.getCommandOptions() >= NceTrafficController.OPTION_1999) { 577 if (bytes.length < 3 || bytes.length > 6) { 578 log.error("Queue of NCE track packet too long:{} packet :{}", Integer.toString(bytes.length), Arrays.toString(bytes)); 579 } 580 NceMessage m = new NceMessage(1 + bytes.length); 581 m.setBinary(true); 582 m.setReplyLen(REPLY_1); 583 int i = 0; // counter to make it easier to format the message 584 585 m.setElement(i++, QUEUEn_BYTES_CMD + bytes.length); 586 for (int j = 0; j < bytes.length; j++) { 587 m.setElement(i++, bytes[j] & 0xFF); 588 } 589 return m; 590 } else { 591 NceMessage m = new NceMessage(1 + 3 * bytes.length); 592 m.setBinary(false); 593 int i = 0; // counter to make it easier to format the message 594 595 m.setElement(i++, 'Q'); // "S C02 " means sent it twice 596 597 for (int j = 0; j < bytes.length; j++) { 598 m.setElement(i++, ' '); 599 m.addIntAsTwoHex(bytes[j] & 0xFF, i); 600 i = i + 2; 601 } 602 return m; 603 } 604 } 605 606 public static NceMessage createAccySignalMacroMessage(NceTrafficController tc, int op, int addr, int data) { 607 if (tc.getCommandOptions() < NceTrafficController.OPTION_2004) { 608 log.error("Attempt to send NCE command to EPROM built before 2004"); 609 } 610 NceMessage m = new NceMessage(5); 611 m.setBinary(true); 612 m.setReplyLen(REPLY_1); 613 m.setTimeout(SHORT_TIMEOUT); 614 m.setOpCode(SEND_ACC_SIG_MACRO_CMD); 615 m.setElement(1, (addr >> 8) & 0xFF); 616 m.setElement(2, addr & 0xFF); 617 m.setElement(3, op); 618 m.setElement(4, data); 619 return m; 620 } 621 622 public static NceMessage createAccDecoderPktOpsMode(NceTrafficController tc, int accyAddr, int cvAddr, int cvData) { 623 NceMessage m = new NceMessage(6); 624 m.setBinary(true); 625 m.setReplyLen(REPLY_1); 626 m.setTimeout(SHORT_TIMEOUT); 627 byte[] mess = NceBinaryCommand.usbOpsModeAccy(accyAddr, cvAddr, cvData); 628 m.setOpCode(mess[0]); 629 m.setElement(1, mess[1]); 630 m.setElement(2, mess[2]); 631 m.setElement(3, mess[3]); 632 m.setElement(4, mess[4]); 633 m.setElement(5, mess[5]); 634 return m; 635 } 636 637 /** 638 * {@inheritDoc} 639 */ 640 @Override 641 public String toMonitorString() { 642 return nceMon.displayMessage(this); 643 } 644}