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