001package jmri.jmrix.nce.ncemon; 002 003import java.text.MessageFormat; 004 005import org.slf4j.Logger; 006import org.slf4j.LoggerFactory; 007 008import jmri.jmrix.nce.NceMessage; 009import jmri.jmrix.nce.NceReply; 010import jmri.util.StringUtil; 011 012/** 013 * A utility class for formatting NCE binary command and replies into 014 * human-readable text. The text for the display comes from NCE's Bincmds.txt 015 * published November 2007 and is used with NCE's permission. 016 * 017 * @author Daniel Boudreau Copyright (C) 2012 018 * @author Ken Cameron (C) 2023 019 */ 020public class NceMonBinary { 021 022 public static final NceMonBinary INSTANCE = new NceMonBinary(); 023 024 private static final Logger log = LoggerFactory.getLogger(NceMonBinary.class); 025 026 private static final int REPLY_UNKNOWN = 0; 027 private static final int REPLY_STANDARD = 1; 028 private static final int REPLY_DATA = 2; 029 private static final int REPLY_ENTER_PROGRAMMING_MODE = 3; 030 031 // The standard replies 032 private static final int REPLY_ZERO = '0'; // command not supported 033 private static final int REPLY_ONE = '1'; // loco/accy/signal address out of range 034 private static final int REPLY_TWO = '2'; // cab address or op code out of range 035 private static final int REPLY_THREE = '3';// CV address or data out of range 036 private static final int REPLY_FOUR = '4'; // byte count out of range 037 private static final int REPLY_OK = '!'; // command completed successfully 038 039 private int _replyType = REPLY_UNKNOWN; 040 041 // private constructor since this class is a singleton 042 private NceMonBinary() { 043 } 044 045 /** 046 * Creates a command message for the log, in a human-friendly form if 047 * possible. 048 * 049 * @param m the raw command message 050 * @return the displayable message string 051 */ 052 public String displayMessage(NceMessage m) { 053 return parseMessage(m); 054 } 055 056 private String parseMessage(NceMessage m) { 057 // first check for messages that have a standard reply 058 setReplyType(REPLY_STANDARD); 059 switch (m.getOpCode() & 0xFF) { 060 case (NceMessage.NOP_CMD): 061 return Bundle.getMessage("NOP_CMD"); 062 case (NceMessage.STOP_CLOCK_CMD): 063 return Bundle.getMessage("STOP_CLOCK_CMD"); 064 case (NceMessage.START_CLOCK_CMD): 065 return Bundle.getMessage("START_CLOCK_CMD"); 066 case (NceMessage.SET_CLOCK_CMD): 067 if (m.getNumDataElements() == 3) { 068 return MessageFormat.format(Bundle.getMessage("SET_CLOCK_CMD"), 069 new Object[]{m.getElement(1), m.getElement(2)}); 070 } 071 break; 072 case (NceMessage.CLOCK_1224_CMD): 073 if (m.getNumDataElements() == 2) { 074 String hr = "12"; 075 if (m.getElement(1) == 1) { 076 hr = "24"; 077 } 078 return MessageFormat.format(Bundle.getMessage("CLOCK_1224_CMD"), 079 new Object[]{hr}); 080 } 081 break; 082 case (NceMessage.CLOCK_RATIO_CMD): 083 if (m.getNumDataElements() == 2) { 084 return MessageFormat.format(Bundle.getMessage("CLOCK_RATIO_CMD"), 085 new Object[]{m.getElement(1)}); 086 } 087 break; 088 case (NceMessage.ENABLE_MAIN_CMD): 089 return Bundle.getMessage("ENABLE_MAIN_CMD"); 090 case (NceMessage.KILL_MAIN_CMD): 091 return Bundle.getMessage("KILL_MAIN_CMD"); 092 case (NceMessage.WRITE_N_CMD): 093 if (m.getNumDataElements() == 20) { 094 return MessageFormat.format(Bundle.getMessage("WRITEn_CMD"), 095 new Object[]{m.getElement(3), getAddress(m), getDataBytes(m, 4, 16)}); 096 } 097 break; 098 // Send n bytes commands 0x93 - 0x96 099 case (NceMessage.SENDn_BYTES_CMD + 3): 100 if (m.getNumDataElements() == 5) { 101 return MessageFormat.format(Bundle.getMessage("SENDn_BYTES_CMD"), 102 new Object[]{"3", m.getElement(1), getDataBytes(m, 2, 3)}); 103 } 104 break; 105 case (NceMessage.SENDn_BYTES_CMD + 4): 106 if (m.getNumDataElements() == 6) { 107 return MessageFormat.format(Bundle.getMessage("SENDn_BYTES_CMD"), 108 new Object[]{"4", m.getElement(1), getDataBytes(m, 2, 4)}); 109 } 110 break; 111 case (NceMessage.SENDn_BYTES_CMD + 5): 112 if (m.getNumDataElements() == 7) { 113 return MessageFormat.format(Bundle.getMessage("SENDn_BYTES_CMD"), 114 new Object[]{"5", m.getElement(1), getDataBytes(m, 2, 5)}); 115 } 116 break; 117 case (NceMessage.SENDn_BYTES_CMD + 6): 118 if (m.getNumDataElements() == 8) { 119 return MessageFormat.format(Bundle.getMessage("SENDn_BYTES_CMD"), 120 new Object[]{"6", m.getElement(1), getDataBytes(m, 2, 6)}); 121 } 122 break; 123 case (NceMessage.WRITE1_CMD): 124 if (m.getNumDataElements() == 4) { 125 return MessageFormat.format(Bundle.getMessage("WRITE1_CMD"), 126 new Object[]{getAddress(m), getDataBytes(m, 3, 1)}); 127 } 128 break; 129 case (NceMessage.WRITE2_CMD): 130 if (m.getNumDataElements() == 5) { 131 return MessageFormat.format(Bundle.getMessage("WRITE2_CMD"), 132 new Object[]{getAddress(m), getDataBytes(m, 3, 2)}); 133 } 134 break; 135 case (NceMessage.WRITE4_CMD): 136 if (m.getNumDataElements() == 7) { 137 return MessageFormat.format(Bundle.getMessage("WRITE4_CMD"), 138 new Object[]{getAddress(m), getDataBytes(m, 3, 4)}); 139 } 140 break; 141 case (NceMessage.WRITE8_CMD): 142 if (m.getNumDataElements() == 11) { 143 return MessageFormat.format(Bundle.getMessage("WRITE8_CMD"), 144 new Object[]{getAddress(m), getDataBytes(m, 3, 8)}); 145 } 146 break; 147 case (NceMessage.MACRO_CMD): 148 if (m.getNumDataElements() == 2) { 149 return MessageFormat.format(Bundle.getMessage("MACRO_CMD"), 150 new Object[]{m.getElement(1)}); 151 } 152 break; 153 case (NceMessage.ENTER_PROG_CMD): { 154 setReplyType(REPLY_ENTER_PROGRAMMING_MODE); 155 return Bundle.getMessage("ENTER_PROG_CMD"); 156 } 157 case (NceMessage.EXIT_PROG_CMD): 158 return Bundle.getMessage("EXIT_PROG_CMD"); 159 case (NceMessage.WRITE_PAGED_CV_CMD): 160 if (m.getNumDataElements() == 4) { 161 return MessageFormat.format(Bundle.getMessage("WRITE_PAGED_CV_CMD"), 162 new Object[]{getNumber(m), getDataBytes(m, 3, 1)}); 163 } 164 break; 165 case (NceMessage.LOCO_CMD): 166 if (m.getNumDataElements() == 5) { 167 // byte three is the Op_1 168 switch (m.getElement(3)) { 169 case (0): 170 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_00"), 171 new Object[]{getLocoAddress(m), m.getElement(4)}); 172 case (1): 173 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_01"), 174 new Object[]{getLocoAddress(m), m.getElement(4)}); 175 case (2): 176 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_02"), 177 new Object[]{getLocoAddress(m), m.getElement(4)}); 178 case (3): 179 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_03"), 180 new Object[]{getLocoAddress(m), m.getElement(4)}); 181 case (4): 182 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_04"), 183 new Object[]{getLocoAddress(m), m.getElement(4)}); 184 case (5): 185 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_05"), 186 new Object[]{getLocoAddress(m), m.getElement(4)}); 187 case (6): 188 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_06"), 189 new Object[]{getLocoAddress(m), m.getElement(4)}); 190 case (7): 191 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_07"), 192 new Object[]{getLocoAddress(m), m.getElement(4), getFunctionNumber(m)}); 193 case (8): 194 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_08"), 195 new Object[]{getLocoAddress(m), m.getElement(4), getFunctionNumber(m)}); 196 case (9): 197 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_09"), 198 new Object[]{getLocoAddress(m), m.getElement(4), getFunctionNumber(m)}); 199 case (0x0A): 200 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_0A"), 201 new Object[]{getLocoAddress(m), m.getElement(4)}); 202 case (0x0b): 203 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_0B"), 204 new Object[]{getLocoAddress(m), m.getElement(4)}); 205 case (0x0C): 206 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_0C"), 207 new Object[]{getLocoAddress(m), m.getElement(4)}); 208 case (0x0D): 209 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_0D"), 210 new Object[]{getLocoAddress(m), m.getElement(4)}); 211 case (0x0E): 212 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_0E"), 213 new Object[]{getLocoAddress(m), m.getElement(4)}); 214 case (0x0F): 215 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_0F"), 216 new Object[]{getLocoAddress(m), m.getElement(4)}); 217 case (0x10): 218 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_10"), 219 new Object[]{getLocoAddress(m), m.getElement(4)}); 220 case (0x11): 221 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_11"), 222 new Object[]{getLocoAddress(m), m.getElement(4)}); 223 case (0x12): 224 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_12"), 225 new Object[]{getLocoAddress(m), m.getElement(4)}); 226 case (0x15): 227 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_15"), 228 new Object[]{getLocoAddress(m), m.getElement(4)}); 229 case (0x16): 230 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_16"), 231 new Object[]{getLocoAddress(m), m.getElement(4)}); 232 case (0x17): 233 return MessageFormat.format(Bundle.getMessage("LOCO_CMD_Op1_17"), 234 new Object[]{getLocoAddress(m), m.getElement(4)}); 235 default: 236 log.error("Unhandled loco cmd op1 code: {}", m.getElement(3)); 237 break; 238 } 239 } 240 break; 241 // Queue commands 0xA3 - 0xA5 242 case (NceMessage.QUEUEn_BYTES_CMD + 3): 243 if (m.getNumDataElements() == 5) { 244 return MessageFormat.format(Bundle.getMessage("QUEUEn_BYTES_CMD"), 245 new Object[]{"3", m.getElement(1), getDataBytes(m, 2, 3)}); 246 } 247 break; 248 case (NceMessage.QUEUEn_BYTES_CMD + 4): 249 if (m.getNumDataElements() == 6) { 250 return MessageFormat.format(Bundle.getMessage("QUEUEn_BYTES_CMD"), 251 new Object[]{"4", m.getElement(1), getDataBytes(m, 2, 4)}); 252 } 253 break; 254 case (NceMessage.QUEUEn_BYTES_CMD + 5): 255 if (m.getNumDataElements() == 7) { 256 return MessageFormat.format(Bundle.getMessage("QUEUEn_BYTES_CMD"), 257 new Object[]{"5", m.getElement(1), getDataBytes(m, 2, 5)}); 258 } 259 break; 260 case (NceMessage.WRITE_REG_CMD): 261 if (m.getNumDataElements() == 3) { 262 return MessageFormat.format(Bundle.getMessage("WRITE_REG_CMD"), 263 new Object[]{m.getElement(1), getDataBytes(m, 2, 1)}); 264 } 265 break; 266 case (NceMessage.WRITE_DIR_CV_CMD): 267 if (m.getNumDataElements() == 4) { 268 return MessageFormat.format(Bundle.getMessage("WRITE_DIR_CV_CMD"), 269 new Object[]{getNumber(m), getDataBytes(m, 3, 1)}); 270 } 271 break; 272 case (NceMessage.SEND_ACC_SIG_MACRO_CMD): 273 if (m.getNumDataElements() == 5) { 274 // byte three is the Op_1 275 switch (m.getElement(3)) { 276 case (1): 277 return MessageFormat.format(Bundle.getMessage("ACC_CMD_Op1_01"), 278 new Object[]{m.getElement(4)}); 279 case (3): 280 return MessageFormat.format(Bundle.getMessage("ACC_CMD_Op1_03"), 281 new Object[]{getNumber(m)}); 282 case (4): 283 return MessageFormat.format(Bundle.getMessage("ACC_CMD_Op1_04"), 284 new Object[]{getNumber(m)}); 285 case (5): 286 return MessageFormat.format(Bundle.getMessage("ACC_CMD_Op1_05"), 287 new Object[]{getNumber(m), m.getElement(4)}); 288 default: 289 log.error("Unhandled acc cmd op1 code: {}", m.getElement(3)); 290 break; 291 } 292 } 293 break; 294 case (NceMessage.USB_SET_CAB_CMD): 295 if (m.getNumDataElements() == 2) { 296 return MessageFormat.format(Bundle.getMessage("Usb_Set_Cab_Op1"), 297 new Object[]{m.getElement(1)}); 298 } 299 break; 300 case (NceMessage.USB_MEM_POINTER_CMD): 301 if (m.getNumDataElements() == 3) { 302 return MessageFormat.format(Bundle.getMessage("Usb_Set_Mem_Ptr_Cmd"), 303 new Object[]{m.getElement(1), m.getElement(2)}); 304 } 305 break; 306 case (NceMessage.USB_MEM_WRITE_CMD): 307 if (m.getNumDataElements() == 2) { 308 return MessageFormat.format(Bundle.getMessage("Usb_Mem_Write_Cmd"), 309 new Object[]{m.getElement(1)}); 310 } 311 break; 312 default: 313 // log.debug("Unhandled command code: {} after 1st pass", Integer.toHexString(m.getOpCode() & 0xFF)); 314 break; 315 } 316 // 2nd pass, check for messages that have a data reply 317 setReplyType(REPLY_DATA); 318 switch (m.getOpCode() & 0xFF) { 319 case (NceMessage.READ_CLOCK_CMD): 320 return Bundle.getMessage("READ_CLOCK_CMD"); 321 case (NceMessage.READ_AUI4_CMD): 322 if (m.getNumDataElements() == 2) { 323 return MessageFormat.format(Bundle.getMessage("READ_AUI4_CMD"), 324 new Object[]{m.getElement(1)}); 325 } 326 break; 327 case (NceMessage.DUMMY_CMD): 328 return Bundle.getMessage("DUMMY_CMD"); 329 case (NceMessage.READ16_CMD): 330 if (m.getNumDataElements() == 3) { 331 return MessageFormat.format(Bundle.getMessage("READ16_CMD"), 332 new Object[]{getAddress(m)}); 333 } 334 break; 335 case (NceMessage.USB_MEM_READ_CMD): 336 if (m.getNumDataElements() == 2) { 337 return MessageFormat.format(Bundle.getMessage("Usb_Mem_Read_Cmd"), 338 new Object[]{m.getElement(1)}); 339 } 340 break; 341 case (NceMessage.READ_AUI2_CMD): 342 if (m.getNumDataElements() == 2) { 343 return MessageFormat.format(Bundle.getMessage("READ_AUI2_CMD"), 344 new Object[]{m.getElement(1)}); 345 } 346 break; 347 case (NceMessage.READ1_CMD): 348 if (m.getNumDataElements() == 3) { 349 return MessageFormat.format(Bundle.getMessage("READ1_CMD"), 350 new Object[]{getAddress(m)}); 351 } 352 break; 353 case (NceMessage.READ_PAGED_CV_CMD): 354 if (m.getNumDataElements() == 3) { 355 return MessageFormat.format(Bundle.getMessage("READ_PAGED_CV_CMD"), 356 new Object[]{getNumber(m)}); 357 } 358 break; 359 case (NceMessage.READ_REG_CMD): 360 if (m.getNumDataElements() == 2) { 361 return MessageFormat.format(Bundle.getMessage("READ_REG_CMD"), 362 new Object[]{m.getElement(1)}); 363 } 364 break; 365 case (NceMessage.READ_DIR_CV_CMD): 366 if (m.getNumDataElements() == 3) { 367 return MessageFormat.format(Bundle.getMessage("READ_DIR_CV_CMD"), 368 new Object[]{getNumber(m)}); 369 } 370 break; 371 case (NceMessage.SW_REV_CMD): 372 return Bundle.getMessage("SW_REV_CMD"); 373 default: 374 log.debug("Unhandled command code: {} after 2nd pass", Integer.toHexString(m.getOpCode() & 0xFF)); 375 break; 376 } 377 // this is one we don't know about or haven't coded it up 378 setReplyType(REPLY_UNKNOWN); 379 log.debug("Unhandled command code: {}, display as raw", Integer.toHexString(m.getOpCode() & 0xFF)); 380 return MessageFormat.format(Bundle.getMessage("BIN_CMD"), new Object[]{m.toString()}); 381 } 382 383 /* 384 * Static access needed since there are two instances of this class, one for 385 * transmitting and one for receiving. 386 */ 387 private void setReplyType(int replyType) { 388 _replyType = replyType; 389 } 390 391 private int getReplyType() { 392 return _replyType; 393 } 394 395 private String getAddress(NceMessage m) { 396 return StringUtil.twoHexFromInt(m.getElement(1)) + StringUtil.twoHexFromInt(m.getElement(2)); 397 } 398 399 private String getDataBytes(NceMessage m, int start, int number) { 400 StringBuilder sb = new StringBuilder(" "); 401 for (int i = start; i < start + number; i++) { 402 sb.append(StringUtil.twoHexFromInt(m.getElement(i))).append(" "); 403 } 404 return sb.toString(); 405 } 406 407 private String getNumber(NceMessage m) { 408 return Integer.toString(((m.getElement(1) & 0xFF) << 8) | (m.getElement(2) & 0xFF)); 409 } 410 411 private String getLocoAddress(NceMessage m) { 412 // show address type 413 String appendix = " (short)"; 414 if ((m.getElement(1) & 0xE0) != 0) { 415 appendix = " (long)"; 416 } 417 return Integer.toString(((m.getElement(1) & 0x3F) << 8) | (m.getElement(2) & 0xFF)) + appendix; 418 } 419 420 private String getFunctionNumber(NceMessage m) { 421 // byte three is the Op_1 422 switch (m.getElement(3)) { 423 case (7): { 424 StringBuilder buf = new StringBuilder(); 425 if ((m.getElement(4) & 0x10) != 0) { 426 buf.append(Bundle.getMessage("F0_ON")).append(", "); 427 } else { 428 buf.append(Bundle.getMessage("F0_OFF")).append(", "); 429 } 430 if ((m.getElement(4) & 0x01) != 0) { 431 buf.append(Bundle.getMessage("F1_ON")).append(", "); 432 } else { 433 buf.append(Bundle.getMessage("F1_OFF")).append(", "); 434 } 435 if ((m.getElement(4) & 0x02) != 0) { 436 buf.append(Bundle.getMessage("F2_ON")).append(", "); 437 } else { 438 buf.append(Bundle.getMessage("F2_OFF")).append(", "); 439 } 440 if ((m.getElement(4) & 0x04) != 0) { 441 buf.append(Bundle.getMessage("F3_ON")).append(", "); 442 } else { 443 buf.append(Bundle.getMessage("F3_OFF")).append(", "); 444 } 445 if ((m.getElement(4) & 0x08) != 0) { 446 buf.append(Bundle.getMessage("F4_ON")); 447 } else { 448 buf.append(Bundle.getMessage("F4_OFF")); 449 } 450 return buf.toString(); 451 } 452 case (8): { 453 StringBuilder buf = new StringBuilder(); 454 if ((m.getElement(4) & 0x01) != 0) { 455 buf.append(Bundle.getMessage("F5_ON")).append(", "); 456 } else { 457 buf.append(Bundle.getMessage("F5_OFF")).append(", "); 458 } 459 if ((m.getElement(4) & 0x02) != 0) { 460 buf.append(Bundle.getMessage("F6_ON")).append(", "); 461 } else { 462 buf.append(Bundle.getMessage("F6_OFF")).append(", "); 463 } 464 if ((m.getElement(4) & 0x04) != 0) { 465 buf.append(Bundle.getMessage("F7_ON")).append(", "); 466 } else { 467 buf.append(Bundle.getMessage("F7_OFF")).append(", "); 468 } 469 if ((m.getElement(4) & 0x08) != 0) { 470 buf.append(Bundle.getMessage("F8_ON")); 471 } else { 472 buf.append(Bundle.getMessage("F8_OFF")); 473 } 474 return buf.toString(); 475 } 476 case (9): { 477 StringBuilder buf = new StringBuilder(); 478 if ((m.getElement(4) & 0x01) != 0) { 479 buf.append(Bundle.getMessage("F9_ON")).append(", "); 480 } else { 481 buf.append(Bundle.getMessage("F9_OFF")).append(", "); 482 } 483 if ((m.getElement(4) & 0x02) != 0) { 484 buf.append(Bundle.getMessage("F10_ON")).append(", "); 485 } else { 486 buf.append(Bundle.getMessage("F10_OFF")).append(", "); 487 } 488 if ((m.getElement(4) & 0x04) != 0) { 489 buf.append(Bundle.getMessage("F11_ON")).append(", "); 490 } else { 491 buf.append(Bundle.getMessage("F11_OFF")).append(", "); 492 } 493 if ((m.getElement(4) & 0x08) != 0) { 494 buf.append(Bundle.getMessage("F12_ON")); 495 } else { 496 buf.append(Bundle.getMessage("F12_OFF")); 497 } 498 return buf.toString(); 499 } 500 default: 501 return ("Error"); 502 } 503 } 504 505 /** 506 * Creates a reply message for the log, in a human-friendly form if 507 * possible. 508 * 509 * @param r the raw reply message 510 * @return the displayable message string 511 */ 512 public String displayReply(NceReply r) { 513 return parseReply(r); 514 } 515 516 private String parseReply(NceReply r) { 517 switch (getReplyType()) { 518 case (REPLY_STANDARD): 519 /* 520 * standard reply is a single byte Errors returned: '0'= command 521 * not supported '1'= loco/accy/signal address out of range '2'= 522 * cab address or op code out of range '3'= CV address or data 523 * out of range '4'= byte count out of range '!'= command 524 * completed successfully 525 */ 526 if (r.getNumDataElements() == 1) { 527 switch (r.getOpCode() & 0xFF) { 528 case (REPLY_ZERO): 529 return Bundle.getMessage("NceReplyZero"); 530 case (REPLY_ONE): 531 return Bundle.getMessage("NceReplyOne"); 532 case (REPLY_TWO): 533 return Bundle.getMessage("NceReplyTwo"); 534 case (REPLY_THREE): 535 return Bundle.getMessage("NceReplyThree"); 536 case (REPLY_FOUR): 537 return Bundle.getMessage("NceReplyFour"); 538 case (REPLY_OK): 539 return Bundle.getMessage("NceReplyOK"); 540 default: 541 log.error("Unhandled reply code: {}", Integer.toHexString(r.getOpCode() & 0xFF)); 542 break; 543 } 544 } 545 break; 546 case (REPLY_ENTER_PROGRAMMING_MODE): 547 /* 548 * enter programming mode reply is a single byte '3'= short 549 * circuit '!'= command completed successfully 550 */ 551 if (r.getNumDataElements() == 1) { 552 switch (r.getOpCode() & 0xFF) { 553 case (REPLY_THREE): 554 return Bundle.getMessage("NceReplyThreeProg"); 555 case (REPLY_OK): 556 return Bundle.getMessage("NceReplyOK"); 557 default: 558 log.error("Unhandled programming reply code: {}", 559 Integer.toHexString(r.getOpCode() & 0xFF)); 560 break; 561 } 562 } 563 break; 564 case (REPLY_DATA): 565 break; 566 default: 567 log.debug("Unhandled reply type code1: {}, display as raw", getReplyType()); 568 break; 569 } 570 return MessageFormat.format(Bundle.getMessage("NceReply"), new Object[]{r.toString()}); 571 } 572}