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