001package jmri.jmrix.nce.macro; 002 003import java.awt.*; 004 005import javax.swing.*; 006 007import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 008import jmri.InstanceManager; 009import jmri.jmrix.nce.*; 010import jmri.util.swing.JmriJOptionPane; 011 012/** 013 * Frame for user edit of NCE macros NCE macros are stored in Command Station 014 * (CS) memory starting at address xC800 (PH5 0x6000). Each macro consists of 20 015 * bytes. The last macro 255 is at address xDBEC. 016 * <p> 017 * Macro addr 0 xC800 018 * <p> 019 * Macro addr 1 xC814 020 * <p> 021 * Macro addr 2 xC828 022 * <p> 023 * Macro addr 3 xC83C 024 * <p> 025 * . . . . 026 * <p> 027 * Macro addr 255 xDBEC 028 * <p> 029 * Each macro can close or throw up to ten accessories. Macros can also be 030 * linked together. Two bytes (16 bit word) define an accessory address and 031 * command, or the address of the next macro to be executed. If the upper byte 032 * of the macro data word is xFF, then the next byte contains the address of the 033 * next macro to be executed by the NCE CS. For example, xFF08 means link to 034 * macro 8. NCE uses the NMRA DCC accessory decoder packet format for the word 035 * definition of their macros. 036 * <p> 037 * Macro data byte: bit 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 038 * <p> 039 * _ _ _ _ _ _ _ _ _ _ _ 1 0 A A A A A A 1 A A A C D D D 040 * <p> 041 * addr bit 7 6 5 4 3 2 10 9 8 1 0 turnout T 042 * <p> 043 * By convention, MSB address bits 10 - 8 are one's complement. NCE macros 044 * always set the C bit to 1. The LSB "D" (0) determines if the accessory is to 045 * be thrown (0) or closed (1). The next two bits "D D" are the LSBs of the 046 * accessory address. Note that NCE display addresses are 1 greater than NMRA 047 * DCC. Note that address bit 2 isn't supposed to be inverted, but it is the way 048 * NCE implemented their macros. Examples: 81F8 = accessory 1 thrown 9FFC = 049 * accessory 123 thrown B5FD = accessory 211 close BF8F = accessory 2044 close 050 * FF10 = link macro 16 051 * <p> 052 * Updated for including the USB 7.* for 1.65 command station Variables found on 053 * cab context page 14 (Cab address 14) macro table 0xE00-0xEFF, cab address = 054 * 0x0E 16 entries of 16 bytes organized as: 055 * <p> 056 * macro 0, high byte, low byte - 7 more times (8 accy commands total) 057 * <p> 058 * macro 1, high byte, low byte - 7 more times (8 accy commands total) 059 * <p> 060 * . . . . 061 * <p> 062 * macro 16, high byte, low byte - 7 more times (8 accy commands total) 063 * 064 * @author Dan Boudreau Copyright (C) 2007, 2024 065 * @author Ken Cameron Copyright (C) 2013, 2023 066 */ 067public class NceMacroEditPanel extends jmri.jmrix.nce.swing.NcePanel implements jmri.jmrix.nce.NceListener { 068 069 private NceTrafficController tc = null; 070 private int memBase; 071 private int maxNumMacros; 072 private int macroSize; 073 private boolean isUsb; 074 075 private int macroNum = 0; // macro being worked 076 private int replyLen = 0; // expected byte length 077 private int waiting = 0; // to catch responses not intended for this module 078 // private static final int firstTimeSleep = 3000; // delay first operation to let panel build 079 // private final boolean firstTime = true; // wait for panel to display 080 081 private static final String QUESTION = Bundle.getMessage("Add");// The three possible states for a turnout 082 private static final String CLOSED = InstanceManager.turnoutManagerInstance().getClosedText(); 083 private static final String THROWN = InstanceManager.turnoutManagerInstance().getThrownText(); 084 private static final String CLOSED_NCE = Bundle.getMessage("Normal"); 085 private static final String THROWN_NCE = Bundle.getMessage("Reverse"); 086 087 private static final String DELETE = Bundle.getMessage("Delete"); 088 089 private static final String EMPTY = Bundle.getMessage("empty"); // One of two accessory states 090 private static final String ACCESSORY = Bundle.getMessage("accessory"); 091 092 private static final String LINK = Bundle.getMessage("LinkMacro");// Line 10 alternative to Delete 093 094 private static final int FAILED = -1; 095 096 Thread nceMemoryThread; 097 private boolean readRequested = false; 098 private boolean writeRequested = false; 099 100 private boolean macroSearchInc = false; // next search 101 private boolean macroSearchDec = false; // previous search 102 private boolean macroValid = false; // when true, NCE CS has responded to macro read 103 private boolean macroModified = false; // when true, macro has been modified by user 104 105 // member declarations 106 JLabel textMacro = new JLabel(Bundle.getMessage("MacroLabel")); 107 JLabel textReply = new JLabel(Bundle.getMessage("ReplyLabel")); 108 JLabel macroReply = new JLabel(); 109 110 // major buttons 111 JButton previousButton = new JButton(Bundle.getMessage("Previous")); 112 JButton nextButton = new JButton(Bundle.getMessage("Next")); 113 JButton getButton = new JButton(Bundle.getMessage("Get")); 114 JButton saveButton = new JButton(Bundle.getMessage("Save")); 115 JButton backUpButton = new JButton(Bundle.getMessage("Backup")); 116 JButton restoreButton = new JButton(Bundle.getMessage("Restore")); 117 118 // check boxes 119 JCheckBox checkBoxEmpty = new JCheckBox(Bundle.getMessage("EmptyMacro")); 120 JCheckBox checkBoxNce = new JCheckBox(Bundle.getMessage("NCETurnout")); 121 122 // macro text field 123 JTextField macroTextField = new JTextField(4); 124 125 // for padding out panel 126 JLabel space2 = new JLabel(" "); 127 JLabel space3 = new JLabel(" "); 128 JLabel space4 = new JLabel(" "); 129 JLabel space15 = new JLabel(" "); 130 131 // accessory row 1 132 JLabel num1 = new JLabel(); 133 JLabel textAccy1 = new JLabel(); 134 JTextField accyTextField1 = new JTextField(4); 135 JButton cmdButton1 = new JButton(); 136 JButton deleteButton1 = new JButton(); 137 138 // accessory row 2 139 JLabel num2 = new JLabel(); 140 JLabel textAccy2 = new JLabel(); 141 JTextField accyTextField2 = new JTextField(4); 142 JButton cmdButton2 = new JButton(); 143 JButton deleteButton2 = new JButton(); 144 145 // accessory row 3 146 JLabel num3 = new JLabel(); 147 JLabel textAccy3 = new JLabel(); 148 JTextField accyTextField3 = new JTextField(4); 149 JButton cmdButton3 = new JButton(); 150 JButton deleteButton3 = new JButton(); 151 152 // accessory row 4 153 JLabel num4 = new JLabel(); 154 JLabel textAccy4 = new JLabel(); 155 JTextField accyTextField4 = new JTextField(4); 156 JButton cmdButton4 = new JButton(); 157 JButton deleteButton4 = new JButton(); 158 159 // accessory row 5 160 JLabel num5 = new JLabel(); 161 JLabel textAccy5 = new JLabel(); 162 JTextField accyTextField5 = new JTextField(4); 163 JButton cmdButton5 = new JButton(); 164 JButton deleteButton5 = new JButton(); 165 166 // accessory row 6 167 JLabel num6 = new JLabel(); 168 JLabel textAccy6 = new JLabel(); 169 JTextField accyTextField6 = new JTextField(4); 170 JButton cmdButton6 = new JButton(); 171 JButton deleteButton6 = new JButton(); 172 173 // accessory row 7 174 JLabel num7 = new JLabel(); 175 JLabel textAccy7 = new JLabel(); 176 JTextField accyTextField7 = new JTextField(4); 177 JButton cmdButton7 = new JButton(); 178 JButton deleteButton7 = new JButton(); 179 180 // accessory row 8 181 JLabel num8 = new JLabel(); 182 JLabel textAccy8 = new JLabel(); 183 JTextField accyTextField8 = new JTextField(4); 184 JButton cmdButton8 = new JButton(); 185 JButton deleteButton8 = new JButton(); 186 187 // accessory row 9 188 JLabel num9 = new JLabel(); 189 JLabel textAccy9 = new JLabel(); 190 JTextField accyTextField9 = new JTextField(4); 191 JButton cmdButton9 = new JButton(); 192 JButton deleteButton9 = new JButton(); 193 194 // accessory row 10 195 JLabel num10 = new JLabel(); 196 JLabel textAccy10 = new JLabel(); 197 JTextField accyTextField10 = new JTextField(4); 198 JButton cmdButton10 = new JButton(); 199 JButton deleteButton10 = new JButton(); 200 201 public NceMacroEditPanel() { 202 super(); 203 } 204 205 /** 206 * {@inheritDoc} 207 */ 208 @Override 209 public void initContext(Object context) { 210 if (context instanceof NceSystemConnectionMemo) { 211 initComponents((NceSystemConnectionMemo) context); 212 } 213 } 214 215 /** 216 * {@inheritDoc} 217 */ 218 @Override 219 public String getHelpTarget() { 220 return "package.jmri.jmrix.nce.macro.NceMacroEditFrame"; 221 } 222 223 /** 224 * {@inheritDoc} 225 */ 226 @Override 227 public String getTitle() { 228 StringBuilder x = new StringBuilder(); 229 if (memo != null) { 230 x.append(memo.getUserName()); 231 } else { 232 x.append("NCE_"); 233 } 234 x.append(": "); 235 x.append(Bundle.getMessage("TitleEditNCEMacro")); 236 return x.toString(); 237 } 238 239 /** 240 * The minimum frame size for font size 16 241 */ 242 @Override 243 public Dimension getMinimumDimension() { 244 return new Dimension(500, 500); 245 } 246 247 /** 248 * {@inheritDoc} 249 */ 250 @Override 251 public void initComponents(NceSystemConnectionMemo memo) { 252 this.memo = memo; 253 this.tc = memo.getNceTrafficController(); 254 memBase = tc.csm.getMacroAddr(); 255 maxNumMacros = tc.csm.getMacroLimit(); 256 macroSize = tc.csm.getMacroSize(); 257 if ((tc.getUsbSystem() != NceTrafficController.USB_SYSTEM_NONE) && 258 (tc.getCmdGroups() & NceTrafficController.CMDS_MEM) != 0) { 259 isUsb = true; 260 } 261 262 // the following code sets the frame's initial state 263 // default at startup 264 macroReply.setText(Bundle.getMessage("unknown")); 265 macroTextField.setText(""); 266 saveButton.setEnabled(false); 267 268 // load tool tips 269 previousButton.setToolTipText(Bundle.getMessage("toolTipSearchDecrementing")); 270 nextButton.setToolTipText(Bundle.getMessage("toolTipSearchIncrementing")); 271 getButton.setToolTipText(Bundle.getMessage("toolTipReadMacro")); 272 macroTextField.setToolTipText(Bundle.getMessage("toolTipEnterMacro", maxNumMacros - 1)); 273 saveButton.setToolTipText(Bundle.getMessage("toolTipUpdateMacro")); 274 backUpButton.setToolTipText(Bundle.getMessage("toolTipBackUp")); 275 restoreButton.setToolTipText(Bundle.getMessage("toolTipRestore")); 276 checkBoxEmpty.setToolTipText(Bundle.getMessage("toolTipSearchEmpty")); 277 checkBoxNce.setToolTipText(Bundle.getMessage("toolTipUseNce")); 278 279 initAccyFields(); 280 281 setLayout(new GridBagLayout()); 282 283 // Layout the panel by rows 284 // row 0 285 addItem(textMacro, 2, 0); 286 287 // row 1 288 addItem(previousButton, 1, 1); 289 addItem(macroTextField, 2, 1); 290 addItem(nextButton, 3, 1); 291 addItem(checkBoxEmpty, 4, 1); 292 293 // row 2 294 addItem(textReply, 0, 2); 295 addItem(macroReply, 1, 2); 296 addItem(getButton, 2, 2); 297 addItem(checkBoxNce, 4, 2); 298 299 // row 3 padding for looks 300 addItem(space2, 1, 3); 301 addItem(space3, 2, 3); 302 addItem(space4, 3, 3); 303 304 // row 4 RFU 305 int rNum = 5; 306 // row 5 accessory 1 307 addAccyRow(num1, textAccy1, accyTextField1, cmdButton1, deleteButton1, rNum++); 308 309 // row 6 accessory 2 310 addAccyRow(num2, textAccy2, accyTextField2, cmdButton2, deleteButton2, rNum++); 311 312 // row 7 accessory 3 313 addAccyRow(num3, textAccy3, accyTextField3, cmdButton3, deleteButton3, rNum++); 314 315 // row 8 accessory 4 316 addAccyRow(num4, textAccy4, accyTextField4, cmdButton4, deleteButton4, rNum++); 317 318 // row 9 accessory 5 319 addAccyRow(num5, textAccy5, accyTextField5, cmdButton5, deleteButton5, rNum++); 320 321 // row 10 accessory 6 322 addAccyRow(num6, textAccy6, accyTextField6, cmdButton6, deleteButton6, rNum++); 323 324 // row 11 accessory 7 325 addAccyRow(num7, textAccy7, accyTextField7, cmdButton7, deleteButton7, rNum++); 326 327 if (!isUsb) { 328 // row 12 accessory 8 329 addAccyRow(num8, textAccy8, accyTextField8, cmdButton8, deleteButton8, rNum++); 330 331 // row 13 accessory 9 332 addAccyRow(num9, textAccy9, accyTextField9, cmdButton9, deleteButton9, rNum++); 333 } 334 335 // row 14 accessory 10 336 addAccyRow(num10, textAccy10, accyTextField10, cmdButton10, deleteButton10, rNum++); 337 338 // row 15 padding for looks 339 addItem(space15, 2, rNum++); 340 341 // row 16 342 addItem(saveButton, 2, rNum); 343 if (isUsb) { 344 backUpButton.setEnabled(false); 345 restoreButton.setEnabled(false); 346 } 347 addItem(backUpButton, 3, rNum); 348 addItem(restoreButton, 4, rNum); 349 350 // setup buttons 351 addButtonAction(previousButton); 352 addButtonAction(nextButton); 353 addButtonAction(getButton); 354 addButtonAction(saveButton); 355 addButtonAction(backUpButton); 356 addButtonAction(restoreButton); 357 358 // accessory command buttons 359 addButtonCmdAction(cmdButton1); 360 addButtonCmdAction(cmdButton2); 361 addButtonCmdAction(cmdButton3); 362 addButtonCmdAction(cmdButton4); 363 addButtonCmdAction(cmdButton5); 364 addButtonCmdAction(cmdButton6); 365 addButtonCmdAction(cmdButton7); 366 addButtonCmdAction(cmdButton8); 367 addButtonCmdAction(cmdButton9); 368 addButtonCmdAction(cmdButton10); 369 370 // accessory delete buttons 371 addButtonDelAction(deleteButton1); 372 addButtonDelAction(deleteButton2); 373 addButtonDelAction(deleteButton3); 374 addButtonDelAction(deleteButton4); 375 addButtonDelAction(deleteButton5); 376 addButtonDelAction(deleteButton6); 377 addButtonDelAction(deleteButton7); 378 addButtonDelAction(deleteButton8); 379 addButtonDelAction(deleteButton9); 380 addButtonDelAction(deleteButton10); 381 382 // NCE checkbox 383 addCheckBoxAction(checkBoxNce); 384 } 385 386 // Previous, Next, Get, Save, Restore & Backup buttons 387 public void buttonActionPerformed(java.awt.event.ActionEvent ae) { 388 389 // if we're searching ignore user 390 if (macroSearchInc || macroSearchDec) { 391 return; 392 } 393 394 if (ae.getSource() == saveButton) { 395 boolean status = saveMacro(); 396 // was save successful? 397 if (status) { 398 setSaveButton(false); // yes, disable save button 399 } 400 return; 401 } 402 403 if (macroModified) { 404 // warn user that macro has been modified 405 JmriJOptionPane.showMessageDialog(this, 406 Bundle.getMessage("MacroModified"), Bundle.getMessage("NceMacro"), 407 JmriJOptionPane.WARNING_MESSAGE); 408 macroModified = false; // only one warning!!! 409 410 } else { 411 412 setSaveButton(false); // disable save button 413 414 if (ae.getSource() == previousButton) { 415 macroSearchDec = true; 416 macroNum = getMacro(); // check for valid and kick off read process 417 if (macroNum < 0) { // Error user input incorrect 418 macroSearchDec = false; 419 } else { 420 processMemory(true, false, macroNum, null); 421 } 422 } 423 if (ae.getSource() == nextButton) { 424 macroSearchInc = true; 425 macroNum = getMacro(); // check for valid 426 if (macroNum < 0) { // Error user input incorrect 427 macroSearchInc = false; 428 } else { 429 processMemory(true, false, macroNum, null); 430 } 431 } 432 433 if (ae.getSource() == getButton) { 434 // Get Macro 435 macroNum = getMacro(); 436 if (macroNum >= 0) { 437 processMemory(true, false, macroNum, null); 438 } 439 } 440 441 if (!isUsb && (ae.getSource() == backUpButton)) { 442 443 Thread mb = new NceMacroBackup(tc); 444 mb.setName("Macro Backup"); 445 mb.start(); 446 } 447 448 if (!isUsb && (ae.getSource() == restoreButton)) { 449 Thread mr = new NceMacroRestore(tc); 450 mr.setName("Macro Restore"); 451 mr.start(); 452 } 453 } 454 } 455 456 // One of the ten accessory command buttons pressed 457 public void buttonActionCmdPerformed(java.awt.event.ActionEvent ae) { 458 459 // if we're searching ignore user 460 if (macroSearchInc || macroSearchDec) { 461 return; 462 } 463 464 if (ae.getSource() == cmdButton1) { 465 updateAccyCmdPerformed(accyTextField1, cmdButton1, textAccy1, 466 deleteButton1); 467 } 468 if (ae.getSource() == cmdButton2) { 469 updateAccyCmdPerformed(accyTextField2, cmdButton2, textAccy2, 470 deleteButton2); 471 } 472 if (ae.getSource() == cmdButton3) { 473 updateAccyCmdPerformed(accyTextField3, cmdButton3, textAccy3, 474 deleteButton3); 475 } 476 if (ae.getSource() == cmdButton4) { 477 updateAccyCmdPerformed(accyTextField4, cmdButton4, textAccy4, 478 deleteButton4); 479 } 480 if (ae.getSource() == cmdButton5) { 481 updateAccyCmdPerformed(accyTextField5, cmdButton5, textAccy5, 482 deleteButton5); 483 } 484 if (ae.getSource() == cmdButton6) { 485 updateAccyCmdPerformed(accyTextField6, cmdButton6, textAccy6, 486 deleteButton6); 487 } 488 if (ae.getSource() == cmdButton7) { 489 updateAccyCmdPerformed(accyTextField7, cmdButton7, textAccy7, 490 deleteButton7); 491 } 492 if (ae.getSource() == cmdButton8) { 493 updateAccyCmdPerformed(accyTextField8, cmdButton8, textAccy8, 494 deleteButton8); 495 } 496 if (ae.getSource() == cmdButton9) { 497 updateAccyCmdPerformed(accyTextField9, cmdButton9, textAccy9, 498 deleteButton9); 499 } 500 if (ae.getSource() == cmdButton10) { 501 updateAccyCmdPerformed(accyTextField10, cmdButton10, textAccy10, 502 deleteButton10); 503 } 504 } 505 506 // One of ten Delete buttons pressed 507 public void buttonActionDeletePerformed(java.awt.event.ActionEvent ae) { 508 509 // if we're searching ignore user 510 if (macroSearchInc || macroSearchDec) { 511 return; 512 } 513 514 if (ae.getSource() == deleteButton1) { 515 updateAccyDelPerformed(accyTextField1, cmdButton1, textAccy1, 516 deleteButton1); 517 } 518 if (ae.getSource() == deleteButton2) { 519 updateAccyDelPerformed(accyTextField2, cmdButton2, textAccy2, 520 deleteButton2); 521 } 522 if (ae.getSource() == deleteButton3) { 523 updateAccyDelPerformed(accyTextField3, cmdButton3, textAccy3, 524 deleteButton3); 525 } 526 if (ae.getSource() == deleteButton4) { 527 updateAccyDelPerformed(accyTextField4, cmdButton4, textAccy4, 528 deleteButton4); 529 } 530 if (ae.getSource() == deleteButton5) { 531 updateAccyDelPerformed(accyTextField5, cmdButton5, textAccy5, 532 deleteButton5); 533 } 534 if (ae.getSource() == deleteButton6) { 535 updateAccyDelPerformed(accyTextField6, cmdButton6, textAccy6, 536 deleteButton6); 537 } 538 if (ae.getSource() == deleteButton7) { 539 updateAccyDelPerformed(accyTextField7, cmdButton7, textAccy7, 540 deleteButton7); 541 } 542 if (ae.getSource() == deleteButton8) { 543 updateAccyDelPerformed(accyTextField8, cmdButton8, textAccy8, 544 deleteButton8); 545 } 546 if (ae.getSource() == deleteButton9) { 547 updateAccyDelPerformed(accyTextField9, cmdButton9, textAccy9, 548 deleteButton9); 549 } 550 // row ten delete button behaves differently 551 // could be link button 552 if (ae.getSource() == deleteButton10) { 553 554 // is the user trying to link a macro? 555 if (deleteButton10.getText().equals(LINK)) { 556 if (!macroValid) { // Error user input incorrect 557 JmriJOptionPane.showMessageDialog(this, 558 Bundle.getMessage("GetMacroNumber", maxNumMacros - 1), 559 Bundle.getMessage("NceMacro"), 560 JmriJOptionPane.ERROR_MESSAGE); 561 return; 562 } 563 int linkMacro = validMacro(accyTextField10.getText()); 564 if (linkMacro == -1) { 565 JmriJOptionPane.showMessageDialog(this, 566 Bundle.getMessage("EnterMacroNumberLastLine", maxNumMacros - 1), 567 Bundle.getMessage("NceMacro"), 568 JmriJOptionPane.ERROR_MESSAGE); 569 return; 570 } 571 // success, link a macro 572 setSaveButton(true); 573 textAccy10.setText(LINK); 574 cmdButton10.setVisible(false); 575 deleteButton10.setText(DELETE); 576 deleteButton10.setToolTipText(Bundle.getMessage("toolTipRemoveMacroLink")); 577 578 // user wants to delete a accessory address or a link 579 } else { 580 updateAccyDelPerformed(accyTextField10, cmdButton10, textAccy10, 581 deleteButton10); 582 initAccyRow10(); 583 } 584 } 585 } 586 587 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 588 processMemory(true, false, macroNum, null); 589 } 590 591 // gets the user supplied macro number 592 private int getMacro() { 593 // Set all fields to default and build from there 594 initAccyFields(); 595 String m = macroTextField.getText(); 596 if (m.isEmpty()) { 597 m = "0"; 598 } 599 int mN = validMacro(m); 600 if (mN < 0) { 601 macroReply.setText(Bundle.getMessage("error")); 602 JmriJOptionPane.showMessageDialog(this, 603 Bundle.getMessage("EnterMacroNumber", maxNumMacros - 1), 604 Bundle.getMessage("NceMacro"), 605 JmriJOptionPane.ERROR_MESSAGE); 606 macroValid = false; 607 return mN; 608 } 609 if (macroSearchInc || macroSearchDec) { 610 macroReply.setText(Bundle.getMessage("searching")); 611 if (macroSearchInc) { 612 mN++; 613 if (mN >= maxNumMacros) { 614 mN = 0; 615 } 616 } 617 if (macroSearchDec) { 618 mN--; 619 if (mN <= -1) { 620 mN = maxNumMacros - 1; 621 } 622 } 623 } else { 624 macroReply.setText(Bundle.getMessage("waiting")); 625 } 626 627 return mN; 628 } 629 630 /** 631 * Writes all bytes to NCE CS memory as long as there are no user input 632 * errors 633 */ 634 private boolean saveMacro() { 635 byte[] macroAccy = new byte[macroSize]; // NCE Macro data 636 int index = 0; 637 int accyNum = 0; 638 // test the inputs, convert from text 639 accyNum = getAccyRow(macroAccy, index, textAccy1, accyTextField1, cmdButton1); 640 if (accyNum < 0) { 641 return false; //error 642 } 643 if (accyNum > 0) { 644 index += 2; 645 } 646 accyNum = getAccyRow(macroAccy, index, textAccy2, accyTextField2, cmdButton2); 647 if (accyNum < 0) { 648 return false; 649 } 650 if (accyNum > 0) { 651 index += 2; 652 } 653 accyNum = getAccyRow(macroAccy, index, textAccy3, accyTextField3, cmdButton3); 654 if (accyNum < 0) { 655 return false; 656 } 657 if (accyNum > 0) { 658 index += 2; 659 } 660 accyNum = getAccyRow(macroAccy, index, textAccy4, accyTextField4, cmdButton4); 661 if (accyNum < 0) { 662 return false; 663 } 664 if (accyNum > 0) { 665 index += 2; 666 } 667 accyNum = getAccyRow(macroAccy, index, textAccy5, accyTextField5, cmdButton5); 668 if (accyNum < 0) { 669 return false; 670 } 671 if (accyNum > 0) { 672 index += 2; 673 } 674 accyNum = getAccyRow(macroAccy, index, textAccy6, accyTextField6, cmdButton6); 675 if (accyNum < 0) { 676 return false; 677 } 678 if (accyNum > 0) { 679 index += 2; 680 } 681 accyNum = getAccyRow(macroAccy, index, textAccy7, accyTextField7, cmdButton7); 682 if (accyNum < 0) { 683 return false; 684 } 685 if (accyNum > 0) { 686 index += 2; 687 } 688 if (!isUsb) { 689 accyNum = getAccyRow(macroAccy, index, textAccy8, accyTextField8, cmdButton8); 690 if (accyNum < 0) { 691 return false; 692 } 693 if (accyNum > 0) { 694 index += 2; 695 } 696 accyNum = getAccyRow(macroAccy, index, textAccy9, accyTextField9, cmdButton9); 697 if (accyNum < 0) { 698 return false; 699 } 700 if (accyNum > 0) { 701 index += 2; 702 } 703 } 704 accyNum = getAccyRow(macroAccy, index, textAccy10, accyTextField10, cmdButton10); 705 if (accyNum < 0) { 706 JmriJOptionPane.showMessageDialog(this, 707 Bundle.getMessage("EnterMacroNumberLastLine", maxNumMacros - 1), 708 Bundle.getMessage("NceMacro"), 709 JmriJOptionPane.ERROR_MESSAGE); 710 return false; 711 } 712 713 processMemory(false, true, macroNum, macroAccy); 714 return true; 715 } 716 717 private void processMemory(boolean doRead, boolean doWrite, int macroId, byte[] macroArray) { 718 final byte[] macroData = new byte[macroSize]; 719 macroValid = false; 720 readRequested = false; 721 writeRequested = false; 722 723 if (doRead) { 724 readRequested = true; 725 } 726 if (doWrite) { 727 writeRequested = true; 728 System.arraycopy(macroArray, 0, macroData, 0, macroSize); 729 } 730 731 // Set up a separate thread to access CS memory 732 if (nceMemoryThread != null && nceMemoryThread.isAlive()) { 733 return; // thread is already running 734 } 735 nceMemoryThread = new Thread(new Runnable() { 736 @Override 737 public void run() { 738 if (readRequested) { 739 macroNum = macroId; 740 int macroCount = 0; 741 while (true) { 742 int entriesRead = readMacroMemory(macroNum); 743 macroTextField.setText(Integer.toString(macroNum)); 744 if (entriesRead == 0) { 745 // Macro is empty so init the accessory fields 746 initAccyFields(); 747 macroReply.setText(Bundle.getMessage("macroEmpty")); 748 if (checkBoxEmpty.isSelected()) { 749 macroValid = true; 750 macroSearchInc = false; 751 macroSearchDec = false; 752 break; 753 } 754 } else if (entriesRead < 0) { 755 macroReply.setText(Bundle.getMessage("error")); 756 macroValid = false; 757 macroSearchInc = false; 758 macroSearchDec = false; 759 break; 760 } else { 761 macroReply.setText(Bundle.getMessage("macroFound")); 762 if (!checkBoxEmpty.isSelected()) { 763 macroSearchInc = false; 764 macroSearchDec = false; 765 macroValid = true; 766 break; 767 } 768 } 769 if ((macroSearchInc || macroSearchDec) && !macroValid) { 770 macroCount++; 771 if (macroCount > maxNumMacros) { 772 macroSearchInc = false; 773 macroSearchDec = false; 774 break; 775 } 776 macroNum = getMacro(); 777 } 778 if (!(macroSearchInc || macroSearchDec)) { 779 // we were doing a get, not a search 780 macroValid = true; 781 break; 782 } 783 } 784 } 785 if (writeRequested) { 786 writeMacroMemory(macroId, macroData); 787 } 788 } 789 }); 790 nceMemoryThread.setName(Bundle.getMessage("ThreadTitle")); 791 nceMemoryThread.setPriority(Thread.MIN_PRIORITY); 792 nceMemoryThread.start(); 793 } 794 795 // Reads entire macro from NCE memory 796 private int readMacroMemory(int mN) { 797 if (isUsb) { 798 return readUsbMacroMemory(mN); 799 } 800 return readCommandStationMacroMemory(mN); 801 } 802 803 /** 804 * Reads 16 byes of NCE macro memory 805 * 806 * @param mN macro number 807 * @return number of accessory addresses read 808 */ 809 private int readUsbMacroMemory(int mN) { 810 setUsbCabMemoryPointer(memBase, (mN * macroSize)); 811 if (!waitNce()) { 812 return FAILED; 813 } 814 int entriesRead = 0; 815 // 1st word of macro 816 readUsbMemoryN(2); 817 if (!waitNce()) { 818 return FAILED; 819 } 820 int accyAddr = getMacroAccyAdr(recChars); 821 if (accyAddr <= 0) { 822 return entriesRead; 823 } 824 entriesRead++; 825 setAccy(accyAddr, getAccyCmd(recChars), textAccy1, accyTextField1, cmdButton1, 826 deleteButton1); 827 // 2nd word of macro 828 readUsbMemoryN(2); 829 if (!waitNce()) { 830 return FAILED; 831 } 832 accyAddr = getMacroAccyAdr(recChars); 833 if (accyAddr <= 0) { 834 return entriesRead; 835 } 836 entriesRead++; 837 setAccy(accyAddr, getAccyCmd(recChars), textAccy2, accyTextField2, cmdButton2, 838 deleteButton2); 839 // 3rd word of macro 840 readUsbMemoryN(2); 841 if (!waitNce()) { 842 return FAILED; 843 } 844 accyAddr = getMacroAccyAdr(recChars); 845 if (accyAddr <= 0) { 846 return entriesRead; 847 } 848 entriesRead++; 849 setAccy(accyAddr, getAccyCmd(recChars), textAccy3, accyTextField3, cmdButton3, 850 deleteButton3); 851 // 4th word of macro 852 readUsbMemoryN(2); 853 if (!waitNce()) { 854 return FAILED; 855 } 856 accyAddr = getMacroAccyAdr(recChars); 857 if (accyAddr <= 0) { 858 return entriesRead; 859 } 860 entriesRead++; 861 setAccy(accyAddr, getAccyCmd(recChars), textAccy4, accyTextField4, cmdButton4, 862 deleteButton4); 863 // 5th word of macro 864 readUsbMemoryN(2); 865 if (!waitNce()) { 866 return FAILED; 867 } 868 accyAddr = getMacroAccyAdr(recChars); 869 if (accyAddr <= 0) { 870 return entriesRead; 871 } 872 entriesRead++; 873 setAccy(accyAddr, getAccyCmd(recChars), textAccy5, accyTextField5, cmdButton5, 874 deleteButton5); 875 // 6th word of macro 876 readUsbMemoryN(2); 877 if (!waitNce()) { 878 return FAILED; 879 } 880 accyAddr = getMacroAccyAdr(recChars); 881 if (accyAddr <= 0) { 882 return entriesRead; 883 } 884 entriesRead++; 885 setAccy(accyAddr, getAccyCmd(recChars), textAccy6, accyTextField6, cmdButton6, 886 deleteButton6); 887 // 7th word of macro 888 readUsbMemoryN(2); 889 if (!waitNce()) { 890 return FAILED; 891 } 892 accyAddr = getMacroAccyAdr(recChars); 893 if (accyAddr <= 0) { 894 return entriesRead; 895 } 896 entriesRead++; 897 setAccy(accyAddr, getAccyCmd(recChars), textAccy7, accyTextField7, cmdButton7, 898 deleteButton7); 899 // 8th word of macro 900 readUsbMemoryN(2); 901 if (!waitNce()) { 902 return FAILED; 903 } 904 accyAddr = getMacroAccyAdr(recChars); 905 if (accyAddr <= 0) { 906 return entriesRead; 907 } 908 entriesRead++; 909 setAccy(accyAddr, getAccyCmd(recChars), textAccy10, accyTextField10, cmdButton10, 910 deleteButton10); 911 return entriesRead; 912 } 913 914 /** 915 * Reads 20 byes of NCE command station macro memory 916 * 917 * @param mN macro number 918 * @return number of accessory addresses read 919 */ 920 private int readCommandStationMacroMemory(int mN) { 921 int memPtr = memBase + (mN * macroSize); 922 int readPtr = 0; 923 int[] workBuf = new int[2]; 924 int entriesRead = 0; 925 926 // 1st word of macro 927 readSerialMemory16(memPtr); 928 if (!waitNce()) { 929 return FAILED; 930 } 931 workBuf[0] = recChars[readPtr++]; 932 workBuf[1] = recChars[readPtr++]; 933 int accyAddr = getMacroAccyAdr(workBuf); 934 if (accyAddr <= 0) { 935 return entriesRead; 936 } 937 entriesRead++; 938 setAccy(accyAddr, getAccyCmd(workBuf), textAccy1, accyTextField1, cmdButton1, 939 deleteButton1); 940 // 2nd word of macro 941 workBuf[0] = recChars[readPtr++]; 942 workBuf[1] = recChars[readPtr++]; 943 accyAddr = getMacroAccyAdr(workBuf); 944 if (accyAddr <= 0) { 945 return entriesRead; 946 } 947 entriesRead++; 948 setAccy(accyAddr, getAccyCmd(workBuf), textAccy2, accyTextField2, cmdButton2, 949 deleteButton2); 950 // 3rd word of macro 951 workBuf[0] = recChars[readPtr++]; 952 workBuf[1] = recChars[readPtr++]; 953 accyAddr = getMacroAccyAdr(workBuf); 954 if (accyAddr <= 0) { 955 return entriesRead; 956 } 957 entriesRead++; 958 setAccy(accyAddr, getAccyCmd(workBuf), textAccy3, accyTextField3, cmdButton3, 959 deleteButton3); 960 // 4th word of macro 961 workBuf[0] = recChars[readPtr++]; 962 workBuf[1] = recChars[readPtr++]; 963 accyAddr = getMacroAccyAdr(workBuf); 964 if (accyAddr <= 0) { 965 return entriesRead; 966 } 967 entriesRead++; 968 setAccy(accyAddr, getAccyCmd(workBuf), textAccy4, accyTextField4, cmdButton4, 969 deleteButton4); 970 // 5th word of macro 971 workBuf[0] = recChars[readPtr++]; 972 workBuf[1] = recChars[readPtr++]; 973 accyAddr = getMacroAccyAdr(workBuf); 974 if (accyAddr <= 0) { 975 return entriesRead; 976 } 977 entriesRead++; 978 setAccy(accyAddr, getAccyCmd(workBuf), textAccy5, accyTextField5, cmdButton5, 979 deleteButton5); 980 // 6th word of macro 981 workBuf[0] = recChars[readPtr++]; 982 workBuf[1] = recChars[readPtr++]; 983 accyAddr = getMacroAccyAdr(workBuf); 984 if (accyAddr <= 0) { 985 return entriesRead; 986 } 987 entriesRead++; 988 setAccy(accyAddr, getAccyCmd(workBuf), textAccy6, accyTextField6, cmdButton6, 989 deleteButton6); 990 // 7th word of macro 991 workBuf[0] = recChars[readPtr++]; 992 workBuf[1] = recChars[readPtr++]; 993 accyAddr = getMacroAccyAdr(workBuf); 994 if (accyAddr <= 0) { 995 return entriesRead; 996 } 997 entriesRead++; 998 setAccy(accyAddr, getAccyCmd(workBuf), textAccy7, accyTextField7, cmdButton7, 999 deleteButton7); 1000 // 8th word of macro 1001 workBuf[0] = recChars[readPtr++]; 1002 workBuf[1] = recChars[readPtr++]; 1003 accyAddr = getMacroAccyAdr(workBuf); 1004 if (accyAddr <= 0) { 1005 return entriesRead; 1006 } 1007 entriesRead++; 1008 setAccy(accyAddr, getAccyCmd(workBuf), textAccy8, accyTextField8, cmdButton8, 1009 deleteButton8); 1010 1011 // 9th word of macro 1012 memPtr += 16; 1013 readPtr = 0; 1014 readSerialMemory16(memPtr); 1015 if (!waitNce()) { 1016 return FAILED; 1017 } 1018 workBuf[0] = recChars[readPtr++]; 1019 workBuf[1] = recChars[readPtr++]; 1020 accyAddr = getMacroAccyAdr(workBuf); 1021 if (accyAddr <= 0) { 1022 return entriesRead; 1023 } 1024 entriesRead++; 1025 setAccy(accyAddr, getAccyCmd(workBuf), textAccy9, accyTextField9, cmdButton9, 1026 deleteButton9); 1027 // 10th word of macro 1028 workBuf[0] = recChars[readPtr++]; 1029 workBuf[1] = recChars[readPtr++]; 1030 accyAddr = getMacroAccyAdr(workBuf); 1031 if (accyAddr <= 0) { 1032 return entriesRead; 1033 } 1034 entriesRead++; 1035 setAccy(accyAddr, getAccyCmd(workBuf), textAccy10, accyTextField10, cmdButton10, 1036 deleteButton10); 1037 return entriesRead; 1038 } 1039 1040 // Updates the accessory line when the user hits the command button 1041 private void updateAccyCmdPerformed(JTextField accyTextField, JButton cmdButton, JLabel textAccy, 1042 JButton deleteButton) { 1043 if (!macroValid) { // Error user input incorrect 1044 JmriJOptionPane.showMessageDialog(this, 1045 Bundle.getMessage("GetMacroNumber"), Bundle.getMessage("NceMacro"), 1046 JmriJOptionPane.ERROR_MESSAGE); 1047 } else { 1048 String accyText = accyTextField.getText(); 1049 int accyNum = 0; 1050 try { 1051 accyNum = Integer.parseInt(accyText); 1052 } catch (NumberFormatException e) { 1053 accyNum = -1; 1054 } 1055 1056 if (accyNum < 1 || accyNum > 2044) { 1057 JmriJOptionPane.showMessageDialog(this, 1058 Bundle.getMessage("EnterAccessoryNumber"), Bundle.getMessage("NceMacroAddress"), 1059 JmriJOptionPane.ERROR_MESSAGE); 1060 return; 1061 } 1062 1063 String accyCmd = cmdButton.getText(); 1064 1065 // Use JMRI or NCE turnout terminology 1066 if (checkBoxNce.isSelected()) { 1067 1068 if (!accyCmd.equals(THROWN_NCE)) { 1069 cmdButton.setText(THROWN_NCE); 1070 } 1071 if (!accyCmd.equals(CLOSED_NCE)) { 1072 cmdButton.setText(CLOSED_NCE); 1073 } 1074 1075 } else { 1076 1077 if (!accyCmd.equals(THROWN)) { 1078 cmdButton.setText(THROWN); 1079 } 1080 if (!accyCmd.equals(CLOSED)) { 1081 cmdButton.setText(CLOSED); 1082 } 1083 } 1084 1085 setSaveButton(true); 1086 textAccy.setText(ACCESSORY); 1087 deleteButton.setText(DELETE); 1088 deleteButton.setToolTipText(Bundle.getMessage("toolTipRemoveAcessory")); 1089 deleteButton.setEnabled(true); 1090 } 1091 } 1092 1093 // Delete an accessory from the macro 1094 private void updateAccyDelPerformed(JTextField accyTextField, JButton cmdButton, JLabel textAccy, 1095 JButton deleteButton) { 1096 setSaveButton(true); 1097 textAccy.setText(EMPTY); 1098 accyTextField.setText(""); 1099 cmdButton.setText(QUESTION); 1100 deleteButton.setEnabled(false); 1101 } 1102 1103 private int getAccyRow(byte[] b, int i, JLabel textAccy, JTextField accyTextField, JButton cmdButton) { 1104 int accyNum = 0; 1105 if (textAccy.getText().equals(ACCESSORY)) { 1106 accyNum = getAccyNum(accyTextField.getText()); 1107 if (accyNum < 0) { 1108 return accyNum; 1109 } 1110 accyNum = accyNum + 3; // adjust for NCE's way of encoding 1111 int upperByte = (accyNum & 0xFF); 1112 upperByte = (upperByte >> 2) + 0x80; 1113 b[i] = (byte) upperByte; 1114 int lowerByteH = (((accyNum ^ 0x0700) & 0x0700) >> 4);// 3 MSB 1s complement 1115 int lowerByteL = ((accyNum & 0x3) << 1); // 2 LSB 1116 int lowerByte = (lowerByteH + lowerByteL + 0x88); 1117 // adjust for turnout command 1118 if (cmdButton.getText().equals(CLOSED) || cmdButton.getText().equals(CLOSED_NCE)) { 1119 lowerByte++; 1120 } 1121 b[i + 1] = (byte) (lowerByte); 1122 } 1123 if (textAccy.getText().equals(LINK)) { 1124 int macroLink = validMacro(accyTextField.getText()); 1125 if (macroLink < 0) { 1126 return macroLink; 1127 } 1128 b[i] = (byte) 0xFF; // NCE macro link command 1129 b[i + 1] = (byte) macroLink; // link macro number 1130 } 1131 return accyNum; 1132 } 1133 1134 private int getAccyNum(String accyText) { 1135 int accyNum = 0; 1136 try { 1137 accyNum = Integer.parseInt(accyText); 1138 } catch (NumberFormatException e) { 1139 accyNum = -1; 1140 } 1141 if (accyNum < 1 || accyNum > 2044) { 1142 JmriJOptionPane.showMessageDialog(this, 1143 Bundle.getMessage("EnterAccessoryNumber"), Bundle.getMessage("NceMacroAddress"), 1144 JmriJOptionPane.ERROR_MESSAGE); 1145 accyNum = -1; 1146 } 1147 return accyNum; 1148 } 1149 1150 // display save button 1151 private void setSaveButton(boolean display) { 1152 macroModified = display; 1153 saveButton.setEnabled(display); 1154 if (!isUsb) { 1155 backUpButton.setEnabled(!display); 1156 restoreButton.setEnabled(!display); 1157 } 1158 } 1159 1160 // Convert NCE macro hex data to accessory address 1161 // returns 0 if macro address is empty 1162 // returns a negative address if link address 1163 // & loads accessory 10 with link macro 1164 private int getMacroAccyAdr(int[] b) { 1165 int accyAddrL = b[0]; 1166 int accyAddr = 0; 1167 // check for null 1168 if ((accyAddrL == 0) && (b[1] == 0)) { 1169 return accyAddr; 1170 } 1171 // Check to see if link address 1172 if ((accyAddrL & 0xFF) == 0xFF) { 1173 // Link address 1174 accyAddr = b[1]; 1175 linkAccessory10(accyAddr & 0xFF); 1176 accyAddr = -accyAddr; 1177 1178 // must be an accessory address 1179 } else { 1180 accyAddrL = (accyAddrL << 2) & 0xFC; // accessory address bits 7 - 2 1181 int accyLSB = b[1]; 1182 accyLSB = (accyLSB & 0x06) >> 1; // accessory address bits 1 - 0 1183 int accyAddrH = b[1]; 1184 accyAddrH = (0x70 - (accyAddrH & 0x70)) << 4; // One's completent of MSB of address 10 - 8 1185 // & multiply by 16 1186 accyAddr = accyAddrH + accyAddrL + accyLSB - 3; // adjust for the way NCE displays addresses 1187 } 1188 return accyAddr; 1189 } 1190 1191 // whenever link macro is found, put it in the last location 1192 // this makes it easier for the user to edit the macro 1193 private void linkAccessory10(int accyAddr) { 1194 textAccy10.setText(LINK); 1195 accyTextField10.setText(Integer.toString(accyAddr)); 1196 cmdButton10.setVisible(false); 1197 deleteButton10.setText(DELETE); 1198 deleteButton10.setToolTipText(Bundle.getMessage("toolTipRemoveMacroLink")); 1199 } 1200 1201 // loads one row with a macro's accessory address and command 1202 private void setAccy(int accyAddr, String accyCmd, JLabel textAccy, 1203 JTextField accyTextField, JButton cmdButton, JButton deleteButton) { 1204 textAccy.setText(ACCESSORY); 1205 accyTextField.setText(Integer.toString(accyAddr)); 1206 deleteButton.setEnabled(true); 1207 cmdButton.setText(accyCmd); 1208 } 1209 1210 // returns the accessory command 1211 private String getAccyCmd(int[] b) { 1212 int accyCmd = b[1]; 1213 String s = THROWN; 1214 if (checkBoxNce.isSelected()) { 1215 s = THROWN_NCE; 1216 } 1217 accyCmd = accyCmd & 0x01; 1218 if (accyCmd == 0) { 1219 return s; 1220 } else { 1221 s = CLOSED; 1222 if (checkBoxNce.isSelected()) { 1223 s = CLOSED_NCE; 1224 } 1225 } 1226 return s; 1227 } 1228 1229 /** 1230 * Check for valid macro, return number if valid, -1 if not. 1231 * 1232 * @param s string of macro number 1233 * @return mN - int of macro number or -1 if invalid 1234 */ 1235 private int validMacro(String s) { 1236 int mN; 1237 try { 1238 mN = Integer.parseInt(s); 1239 } catch (NumberFormatException e) { 1240 return -1; 1241 } 1242 if (mN < 0 || mN > maxNumMacros - 1) { 1243 return -1; 1244 } else { 1245 return mN; 1246 } 1247 } 1248 1249 /** 1250 * writes bytes of NCE macro memory 1251 */ 1252 private boolean writeMacroMemory(int macroNum, byte[] b) { 1253 if (isUsb) { 1254 setUsbCabMemoryPointer(memBase, (macroNum * macroSize)); 1255 if (!waitNce()) { 1256 return false; 1257 } 1258 // write one byte at a time 1259 for (int i = 0; i < macroSize; i++) { 1260 writeUsbMemory1(b[i]); 1261 if (!waitNce()) { 1262 return false; 1263 } 1264 } 1265 } else { 1266 int nceMemoryAddr = (macroNum * macroSize) + memBase; 1267 // write 16 bytes 1268 byte[] buf = new byte[16]; 1269 for (int i = 0; i < 16; i++) { 1270 buf[i] = b[i]; 1271 } 1272 writeSerialMemoryN(nceMemoryAddr, buf); 1273 if (!waitNce()) { 1274 return false; 1275 } 1276 // write 4 bytes 1277 buf = new byte[4]; 1278 for (int i = 0; i < 4; i++) { 1279 buf[i] = b[i + 16]; 1280 } 1281 writeSerialMemory4(nceMemoryAddr + 16, buf); 1282 if (!waitNce()) { 1283 return false; 1284 } 1285 } 1286 return true; 1287 } 1288 1289 // puts the thread to sleep while we wait for the read CS memory to complete 1290 private boolean waitNce() { 1291 int count = 100; 1292 if (log.isDebugEnabled()) { 1293 log.debug("Going to sleep"); 1294 } 1295 while (waiting > 0) { 1296 synchronized (this) { 1297 try { 1298 wait(100); 1299 } catch (InterruptedException e) { 1300 //nothing to see here, move along 1301 } 1302 } 1303 count--; 1304 if (count < 0) { 1305 macroReply.setText("Error"); 1306 return false; 1307 } 1308 } 1309 if (log.isDebugEnabled()) { 1310 log.debug("awake!"); 1311 } 1312 return true; 1313 } 1314 1315 @Override 1316 public void message(NceMessage m) { 1317 } // ignore replies 1318 1319 /** 1320 * response from read 1321 */ 1322 int recChar = 0; 1323 int[] recChars = new int[16]; 1324 1325 @SuppressFBWarnings(value = "NN_NAKED_NOTIFY", justification = "Thread wait from main transfer loop") 1326 @Override 1327 public void reply(NceReply r) { 1328 if (log.isDebugEnabled()) { 1329 log.debug("Receive character"); 1330 } 1331 if (waiting <= 0) { 1332 log.error("unexpected response. Len: {} code: {}", r.getNumDataElements(), r.getElement(0)); 1333 return; 1334 } 1335 waiting--; 1336 if (r.getNumDataElements() != replyLen) { 1337 macroReply.setText("error"); 1338 return; 1339 } 1340 for (int i = 0; i < replyLen; i++) { 1341 recChars[i] = r.getElement(i); 1342 log.debug("{} recieve: {}", i, String.format("%1X", r.getElement(i))); 1343 } 1344 // wake up thread 1345 synchronized (this) { 1346 notify(); 1347 } 1348 } 1349 1350 // USB set cab memory pointer 1351 private void setUsbCabMemoryPointer(int cab, int offset) { 1352 log.debug("Macro base address: {}, offset: {}", Integer.toHexString(cab), offset); 1353 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1354 waiting++; 1355 byte[] bl = NceBinaryCommand.usbMemoryPointer(cab, offset); 1356 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_1); 1357 tc.sendNceMessage(m, this); 1358 } 1359 1360 // USB Read N bytes of NCE cab memory 1361 private void readUsbMemoryN(int num) { 1362 switch (num) { 1363 case 1: 1364 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1365 break; 1366 case 2: 1367 replyLen = NceMessage.REPLY_2; // Expect 2 byte response 1368 break; 1369 case 4: 1370 replyLen = NceMessage.REPLY_4; // Expect 4 byte response 1371 break; 1372 default: 1373 log.error("Invalid usb read byte count"); 1374 return; 1375 } 1376 waiting++; 1377 byte[] bl = NceBinaryCommand.usbMemoryRead((byte) num); 1378 NceMessage m = NceMessage.createBinaryMessage(tc, bl, replyLen); 1379 tc.sendNceMessage(m, this); 1380 } 1381 1382 /** 1383 * USB Write 1 byte of NCE memory 1384 * 1385 * @param value byte being written+ 1386 */ 1387 private void writeUsbMemory1(byte value) { 1388 log.debug("Write byte: {}", String.format("%2X", value)); 1389 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1390 waiting++; 1391 byte[] bl = NceBinaryCommand.usbMemoryWrite1(value); 1392 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_1); 1393 tc.sendNceMessage(m, this); 1394 } 1395 1396 // Reads 16 bytes of NCE memory 1397 private void readSerialMemory16(int nceCabAddr) { 1398 replyLen = NceMessage.REPLY_16; // Expect 16 byte response 1399 waiting++; 1400 byte[] bl = NceBinaryCommand.accMemoryRead(nceCabAddr); 1401 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_16); 1402 tc.sendNceMessage(m, this); 1403 } 1404 1405 // Write N bytes of NCE memory 1406 private void writeSerialMemoryN(int nceMacroAddr, byte[] b) { 1407 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1408 waiting++; 1409 byte[] bl = NceBinaryCommand.accMemoryWriteN(nceMacroAddr, b); 1410 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_1); 1411 tc.sendNceMessage(m, this); 1412 } 1413 1414 // Write 4 bytes of NCE memory 1415 private void writeSerialMemory4(int nceMacroAddr, byte[] b) { 1416 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1417 waiting++; 1418 byte[] bl = NceBinaryCommand.accMemoryWrite4(nceMacroAddr, b); 1419 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_1); 1420 tc.sendNceMessage(m, this); 1421 } 1422 1423 private void addAccyRow(JComponent col1, JComponent col2, JComponent col3, JComponent col4, JComponent col5, 1424 int row) { 1425 addItem(col1, 0, row); 1426 addItem(col2, 1, row); 1427 addItem(col3, 2, row); 1428 addItem(col4, 3, row); 1429 addItem(col5, 4, row); 1430 } 1431 1432 private void addItem(JComponent c, int x, int y) { 1433 GridBagConstraints gc = new GridBagConstraints(); 1434 gc.gridx = x; 1435 gc.gridy = y; 1436 gc.weightx = 100.0; 1437 gc.weighty = 100.0; 1438 add(c, gc); 1439 } 1440 1441 private void addButtonAction(JButton b) { 1442 b.addActionListener(new java.awt.event.ActionListener() { 1443 @Override 1444 public void actionPerformed(java.awt.event.ActionEvent e) { 1445 buttonActionPerformed(e); 1446 } 1447 }); 1448 } 1449 1450 private void addButtonCmdAction(JButton b) { 1451 b.addActionListener(new java.awt.event.ActionListener() { 1452 @Override 1453 public void actionPerformed(java.awt.event.ActionEvent e) { 1454 buttonActionCmdPerformed(e); 1455 } 1456 }); 1457 } 1458 1459 private void addButtonDelAction(JButton b) { 1460 b.addActionListener(new java.awt.event.ActionListener() { 1461 @Override 1462 public void actionPerformed(java.awt.event.ActionEvent e) { 1463 buttonActionDeletePerformed(e); 1464 } 1465 }); 1466 } 1467 1468 private void addCheckBoxAction(JCheckBox cb) { 1469 cb.addActionListener(new java.awt.event.ActionListener() { 1470 @Override 1471 public void actionPerformed(java.awt.event.ActionEvent e) { 1472 checkBoxActionPerformed(e); 1473 } 1474 }); 1475 } 1476 1477 // initialize accessories 1 to 10 1478 private void initAccyFields() { 1479 initAccyRow(1, num1, textAccy1, accyTextField1, cmdButton1, deleteButton1); 1480 initAccyRow(2, num2, textAccy2, accyTextField2, cmdButton2, deleteButton2); 1481 initAccyRow(3, num3, textAccy3, accyTextField3, cmdButton3, deleteButton3); 1482 initAccyRow(4, num4, textAccy4, accyTextField4, cmdButton4, deleteButton4); 1483 initAccyRow(5, num5, textAccy5, accyTextField5, cmdButton5, deleteButton5); 1484 initAccyRow(6, num6, textAccy6, accyTextField6, cmdButton6, deleteButton6); 1485 initAccyRow(7, num7, textAccy7, accyTextField7, cmdButton7, deleteButton7); 1486 initAccyRow(8, num8, textAccy8, accyTextField8, cmdButton8, deleteButton8); 1487 initAccyRow(9, num9, textAccy9, accyTextField9, cmdButton9, deleteButton9); 1488 initAccyRow(isUsb ? 8 : 10, num10, textAccy10, accyTextField10, cmdButton10, deleteButton10); 1489 } 1490 1491 private void initAccyRow(int row, JLabel num, JLabel textAccy, JTextField accyTextField, JButton cmdButton, 1492 JButton deleteButton) { 1493 num.setText(Integer.toString(row)); 1494 num.setVisible(true); 1495 textAccy.setText(EMPTY); 1496 textAccy.setVisible(true); 1497 cmdButton.setText(QUESTION); 1498 cmdButton.setVisible(true); 1499 cmdButton.setToolTipText(Bundle.getMessage("toolTipSetCommand")); 1500 deleteButton.setText(DELETE); 1501 deleteButton.setVisible(true); 1502 deleteButton.setEnabled(false); 1503 deleteButton.setToolTipText(Bundle.getMessage("toolTipRemoveAcessory")); 1504 accyTextField.setText(""); 1505 accyTextField.setToolTipText(Bundle.getMessage("EnterAccessoryNumber")); 1506 accyTextField.setMaximumSize(new Dimension(accyTextField 1507 .getMaximumSize().width, 1508 accyTextField.getPreferredSize().height)); 1509 if (isUsb && row == 8 || row == 10) { 1510 initAccyRow10(); 1511 } 1512 } 1513 1514 private void initAccyRow10() { 1515 cmdButton10.setVisible(true); 1516 deleteButton10.setText(LINK); 1517 deleteButton10.setEnabled(true); 1518 deleteButton10.setToolTipText(Bundle.getMessage("toolTipLink")); 1519 accyTextField10.setToolTipText(Bundle.getMessage("toolTip10", maxNumMacros - 1)); 1520 } 1521 1522 /** 1523 * Nested class to create one of these using old-style defaults 1524 */ 1525 static public class Default extends jmri.jmrix.nce.swing.NceNamedPaneAction { 1526 1527 public Default() { 1528 super("Open NCE Macro Editor", 1529 new jmri.util.swing.sdi.JmriJFrameInterface(), 1530 NceMacroEditPanel.class.getName(), 1531 jmri.InstanceManager.getDefault(NceSystemConnectionMemo.class)); 1532 } 1533 } 1534 1535 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(NceMacroEditPanel.class); 1536 1537}