001package jmri.jmrix.nce.cab; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004import java.awt.Dimension; 005import java.awt.GridBagConstraints; 006import java.awt.GridBagLayout; 007import java.awt.event.ActionEvent; 008import java.text.MessageFormat; 009import java.util.Calendar; 010import javax.swing.BoxLayout; 011import javax.swing.JButton; 012import javax.swing.JCheckBox; 013import javax.swing.JComponent; 014import javax.swing.JLabel; 015import javax.swing.JPanel; 016import javax.swing.JScrollPane; 017import javax.swing.JTable; 018import javax.swing.ListSelectionModel; 019import javax.swing.ScrollPaneConstants; 020import javax.swing.table.AbstractTableModel; 021import javax.swing.table.TableCellEditor; 022import javax.swing.table.TableColumn; 023import javax.swing.table.TableColumnModel; 024import jmri.jmrix.nce.NceBinaryCommand; 025import jmri.jmrix.nce.NceCmdStationMemory; 026import jmri.jmrix.nce.NceMessage; 027import jmri.jmrix.nce.NceReply; 028import jmri.jmrix.nce.NceSystemConnectionMemo; 029import jmri.jmrix.nce.NceTrafficController; 030import jmri.util.table.ButtonEditor; 031import jmri.util.table.ButtonRenderer; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035/** 036 * Frame to display NCE cabs 037 * <p> 038 * Note, NCE bit layout MSB = bit 7, LSB = bit 0. 039 * <p> 040 * From Jim Scorse at NCE: 041 * <p> 042 * Each cab has a 256 byte "context page" in system RAM These pages start at 043 * 0x8000 in system RAM with Cab 0 at 0x8800, cab 1 at 0x8900, Cab 2 at 0x8a00, 044 * etc. (PH5 0x3C00) 045 * <p> 046 * Below is a list of offsets (in decimal) into the cab context page for useful 047 * memory locations. 048 * <p> 049 * For example if you want to know the current speed of cab address 2's 050 * currently selected loco look at memory location 0x8a00 + 32 dec (0x20). This 051 * will be address 0x8a20. 052 * <p> 053 * <br> 054 * To determine if a cab is active (plugged in at any point this session) you 055 * will need to look at the byte "FLAGS1" (offset 101) 056 * <p> 057 * If bit 1 of FLAGS1 = 1 then the cab has been talked to at least once by the 058 * command station. 059 * <p> 060 * Bits 0 and 7 indicate the type of cab being use this session at this cab 061 * address 062 * <p> 063 * Bit 7,0 = 0,0 Procab or other cab with an LCD display (type A) Bit 7,0 = 0,1 064 * Cab04 other cab without an LCD (type B) Bit 7,0 = 1,0 USB or similar device 065 * (type C) Bit 7,0 = 1,1 AIU or similar device (type D) 066 * <p> 067 * <br> 068 * CAB_BASE EQU 0 ; LCD_TOP_LINE EQU 0 ;16 chars (in ASCII) for top line of LCD 069 * LCD_BOT_LINE EQU 16 ;16 chars (in ASCII) for bottom line of LCD 070 * <p> 071 * CURR_SPEED EQU 32 ;this cab's current speed ADDR_H EQU 33 ;loco address, high 072 * byte ADDR_L EQU 34 ;loco address, low byte FLAGS EQU 35 ;bit 0 - Do not use 073 * ;bit 1 - 1=128 speed mode, 0=28 speed mode ;bit 2 - 1=forward, 0=reverse ;bit 074 * 3 - Do not use ;bit 4 - Do not use ;bit 5 - Do not use ;bit 6 - Do not use 075 * ;bit 7 - 1=rear loco of consist is active address use reverse speeds 076 * <p> 077 * FUNCTION_L EQU 36 ;bit 0 = function 1, 1=on, 0=off ;bit 1 = function 2, 1=on, 078 * 0=off ;bit 2 = function 3, 1=on, 0=off ;bit 3 = function 4, 1=on, 0=off ;bit 079 * 4 = headlight, 1=on, 0=off 080 * <p> 081 * FUNCTION_H EQU 37 ;bit 0 = function 5, 1=on, 0=off ;bit 1 = function 6, 1=on, 082 * 0=off ;bit 2 = function 7, 1=on, 0=off ;bit 3 = function 8, 1=on, 0=off ;bit 083 * 4 = function 9, 1=on, 0=off ;bit 5 = function 10, 1=on, 0=off ;bit 6 = 084 * function 11, 1=on, 0=off ;bit 7 = function 12, 1=on, 0=off 085 * <p> 086 * ALIAS EQU 38 ;If loco is in consist this is the consist address 087 * <p> 088 * <br> 089 * FUNC13_20 EQU 82 ;bit map of current functions (bit 0=F13) FUNC21_28 EQU 83 090 * ;bit map of current functions (bit 0=F21) 091 * <p> 092 * ACC_AD_H EQU 90 ;current accessory address high byte ACC_AD_L EQU 91 ;current 093 * accessory address low byte 094 * <p> 095 * ;lower nibble bit 0 =1 if setup advanced consist in process 096 * <p> 097 * FLAGS2 EQU 93 ;bit 0 = \ ;bit 1 = {@literal >}Number of recalls for this cab 098 * ;bit 2 = / 1-6 valid ;bit 3 = 1=refresh LCD on ProCab ;bit 4 = Do not use 099 * ;bit 5 = Do not use ;bit 6 = Do not use ;bit 7 = Do not use 100 * <p> 101 * FLAGS1 EQU 101 ;bit0 - 0 = type a or type C cab, 1 = type b or type d ;bit1 - 102 * 0 = cab type not determined, 1 = it has ;bit2 - 0 = Do not use ;bit3 - 0 = Do 103 * not use ;bit4 - 0 = Do not use ;bit5 - 0 = Do not use ;bit6 - 0 = Do not use 104 * ;bit7 - 0 = type a or type b cab, 1=type c or d Writing zero to FLAGS1 will 105 * remove the cab from the 'active' list 106 * 107 * @author Dan Boudreau Copyright (C) 2009, 2010 108 * @author Ken Cameron Copyright (C) 2012, 2013, 2023 109 */ 110public class NceShowCabPanel extends jmri.jmrix.nce.swing.NcePanel implements jmri.jmrix.nce.NceListener { 111 112 private int replyLen = 0; // expected byte length 113 private int waiting = 0; // to catch responses not 114 // intended for this module 115 private int minCabNum = -1; // either the USB or serial size depending on what we connect to 116 private int maxCabNum = -1; // either the USB or serial size depending on what we connect to 117 118 private static final int FIRST_TIME_SLEEP = 3000; // delay first operation to let panel build 119 120 private static final int CAB_LINE_LEN = 16; // display line length of 16 bytes 121 private static final int CAB_MAX_CABDATA = 66; // Size for arrays. One more than the highest cab number 122 123 Thread nceCabUpdateThread; 124 Thread autoRefreshThread; 125 126 private final int[] cabFlag1Array = new int[CAB_MAX_CABDATA]; 127 private final Calendar[] cabLastChangeArray = new Calendar[CAB_MAX_CABDATA]; 128 private final int[] cabSpeedArray = new int[CAB_MAX_CABDATA]; 129 private final int[] cabFlagsArray = new int[CAB_MAX_CABDATA]; 130 private final int[] cabLocoArray = new int[CAB_MAX_CABDATA]; 131 private final boolean[] cabLongShortArray = new boolean[CAB_MAX_CABDATA]; 132 private final int[] cabConsistArray = new int[CAB_MAX_CABDATA]; 133 private final int[] cabF0Array = new int[CAB_MAX_CABDATA]; 134 private final int[] cabF5Array = new int[CAB_MAX_CABDATA]; 135 private final int[] cabF13Array = new int[CAB_MAX_CABDATA]; 136 private final int[] cabF21Array = new int[CAB_MAX_CABDATA]; 137 private final int[][] cabLine1Array = new int[CAB_MAX_CABDATA][CAB_LINE_LEN]; 138 private final int[][] cabLine2Array = new int[CAB_MAX_CABDATA][CAB_LINE_LEN]; 139 140 private boolean purgeRequested = false; 141 private boolean updateRequested = false; 142 private int purgeCabId = -1; 143 144 // member declarations 145 JLabel textNumber = new JLabel(Bundle.getMessage("Number")); 146 JLabel textCab = new JLabel(Bundle.getMessage("Type")); 147 JLabel textAddrType = new JLabel(Bundle.getMessage("AddrType")); 148 JLabel textAddress = new JLabel(Bundle.getMessage("Loco")); 149 JLabel textSpeed = new JLabel(Bundle.getMessage("Speed")); 150 JLabel textConsist = new JLabel(Bundle.getMessage("Consist")); 151 JLabel textConsistPos = new JLabel(Bundle.getMessage("ConsistPos")); 152 JLabel textFunctions = new JLabel(Bundle.getMessage("Functions")); 153 JLabel textDisplay1 = new JLabel(Bundle.getMessage("Display1")); 154 JLabel textDisplay2 = new JLabel(Bundle.getMessage("Display2")); 155 JLabel textReply = new JLabel(Bundle.getMessage("Reply")); 156 JLabel textStatus = new JLabel(""); 157 JLabel textLastUsed = new JLabel(Bundle.getMessage("LastUsed")); 158 159 // major buttons 160 JButton refreshButton = new JButton(Bundle.getMessage("Refresh")); 161 162 // check boxes 163 JCheckBox checkBoxShowAllCabs = new JCheckBox(Bundle.getMessage("CheckBoxLabelShowAllCabs")); 164 // JCheckBox checkBoxShowDisplayText = new JCheckBox(Bundle.getMessage("CheckBoxLabelShowDisplayText")); 165 // JCheckBox checkBoxShowAllFunctions = new JCheckBox(Bundle.getMessage("CheckBoxLabelShowAllFunctions")); 166 JCheckBox checkBoxAutoRefresh = new JCheckBox(Bundle.getMessage("CheckBoxLabelAutoRefresh")); 167 168 static class DataRow { 169 170 int cabNumber; 171 String cabType; 172 String longShort; 173 int locoAddress; 174 int locoSpeed; 175 String locoDir; 176 String mode; 177 int consist; 178 String consistPos; 179 boolean F0; 180 boolean F1; 181 boolean F2; 182 boolean F3; 183 boolean F4; 184 boolean F5; 185 boolean F6; 186 boolean F7; 187 boolean F8; 188 boolean F9; 189 boolean F10; 190 boolean F11; 191 boolean F12; 192 boolean F13; 193 boolean F14; 194 boolean F15; 195 boolean F16; 196 boolean F17; 197 boolean F18; 198 boolean F19; 199 boolean F20; 200 boolean F21; 201 boolean F22; 202 boolean F23; 203 boolean F24; 204 boolean F25; 205 boolean F26; 206 boolean F27; 207 boolean F28; 208 String text1; 209 String text2; 210 String lastChange; 211 } 212 213 DataRow[] cabData = new DataRow[CAB_MAX_CABDATA]; 214 215 NceCabTableModel cabModel = new NceCabTableModel(cabData); 216 JTable cabTable = new JTable(cabModel); 217 218 private NceTrafficController tc = null; 219 220 public NceShowCabPanel() { 221 super(); 222 } 223 224 /** 225 * {@inheritDoc} 226 */ 227 @Override 228 public void initContext(Object context) { 229 if (context instanceof NceSystemConnectionMemo) { 230 initComponents((NceSystemConnectionMemo) context); 231 } 232 } 233 234 /** 235 * {@inheritDoc} 236 */ 237 @Override 238 public String getHelpTarget() { 239 return "package.jmri.jmrix.nce.cab.NceShowCabFrame"; 240 } 241 242 /** 243 * {@inheritDoc} 244 */ 245 @Override 246 public String getTitle() { 247 StringBuilder x = new StringBuilder(); 248 if (memo != null) { 249 x.append(memo.getUserName()); 250 } else { 251 x.append("NCE_"); 252 } 253 x.append(": "); 254 x.append(Bundle.getMessage("Title")); 255 return x.toString(); 256 } 257 258 /** 259 * {@inheritDoc} 260 */ 261 @Override 262 public void initComponents(NceSystemConnectionMemo m) { 263 this.memo = m; 264 this.tc = m.getNceTrafficController(); 265 266 // fill in cab array 267 minCabNum = tc.csm.getCabMin(); 268 maxCabNum = tc.csm.getCabMax(); 269 for (int i = minCabNum; i <= maxCabNum; i++) { 270 cabData[i] = new DataRow(); 271 } 272 // the following code sets the frame's initial state 273 274 setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); 275 276 JPanel p1 = new JPanel(); 277 p1.setLayout(new GridBagLayout()); 278 p1.setPreferredSize(new Dimension(1000, 40)); 279 // row 1 280 refreshButton.setToolTipText(Bundle.getMessage("RefreshToolTip")); 281 addButtonAction(refreshButton); 282 283 checkBoxShowAllCabs.setToolTipText(Bundle.getMessage("CheckBoxAllCabsToolTip")); 284 checkBoxShowAllCabs.setSelected(false); 285 addCheckBoxAction(checkBoxShowAllCabs); 286 287 // checkBoxShowAllFunctions.setToolTipText(Bundle.getMessage("CheckBoxShowAllFunctionsToolTip")); 288 // checkBoxShowAllFunctions.setSelected(true); 289 // checkBoxShowAllFunctions.setEnabled(false); 290 // checkBoxShowDisplayText.setToolTipText(Bundle.getMessage("CheckBoxShowDisplayToolTip")); 291 // checkBoxShowDisplayText.setSelected(true); 292 // checkBoxShowDisplayText.setEnabled(false); 293 checkBoxAutoRefresh.setToolTipText(Bundle.getMessage("CheckBoxAutoRefreshToolTip")); 294 checkBoxAutoRefresh.setSelected(false); 295 addCheckBoxAction(checkBoxAutoRefresh); 296 297 addItem(p1, refreshButton, 2, 1); 298 addItem(p1, checkBoxAutoRefresh, 3, 1); 299 addItem(p1, checkBoxShowAllCabs, 4, 1); 300 // addItem(p1, checkBoxShowAllFunctions, 6, 1); 301 addItem(p1, textStatus, 2, 2); 302 // addItem(p1, checkBoxShowDisplayText, 6, 2); 303 304 JScrollPane cabScrollPane = new JScrollPane(cabTable); 305 cabTable.setFillsViewportHeight(true); 306 cabTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); 307 cabModel.setShowAllCabs(false); 308 cabModel.setShowAllFunctions(true); 309 cabModel.setShowCabDisplay(true); 310 for (int col = 0; col < cabTable.getColumnCount(); col++) { 311 int width = cabModel.getPreferredWidth(col); 312 TableColumn c = cabTable.getColumnModel().getColumn(col); 313 c.setPreferredWidth(width); 314 } 315 cabTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 316 cabScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 317 cabScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 318 setColumnPurgeButton(cabTable, 2); 319 add(p1); 320 add(cabScrollPane); 321 322 // pad out panel 323 cabScrollPane.setVisible(true); 324 325 refreshPanel(); 326 327 } 328 329 // button actions 330 public void buttonActionPerformed(ActionEvent ae) { 331 Object src = ae.getSource(); 332 if (src == refreshButton) { 333 refreshPanel(); 334 } else { 335 log.error("unknown action performed: {}", src); 336 } 337 } 338 339 // checkboxes 340 public void checkBoxActionPerformed(java.awt.event.ActionEvent ae) { 341 Object src = ae.getSource(); 342 if (src == checkBoxShowAllCabs) { 343 cabModel.setShowAllCabs(checkBoxShowAllCabs.isSelected()); 344 refreshPanel(); 345 } else if (src == checkBoxAutoRefresh) { 346 autoRefreshPanel(); 347 } else { 348 log.error("unknown checkbox action performed: {}", src); 349 } 350 } 351 352 @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(value="SLF4J_SIGN_ONLY_FORMAT", 353 justification="I18N of log message") 354 public void purgeCab(int cab) { 355 if (cab < minCabNum || cab > maxCabNum) { 356 log.error("{}{}", Bundle.getMessage("ErrorValueRange"), cab); 357 return; 358 } 359 // if id is active 360 int act = cabFlag1Array[cab] & NceCmdStationMemory.FLAGS1_MASK_CABISACTIVE; 361 if (act != NceCmdStationMemory.FLAGS1_CABISACTIVE) { 362 log.error("purgeCab: {}{}", Bundle.getMessage("ErrorCabNotActive"), cab); 363 } 364 // clear bit for active and cab type details 365 cabFlag1Array[cab] = 0; 366 processMemory(true, true, cab); 367 } 368 369 /** 370 * Refresh cab display every 4 seconds. 371 */ 372 private void autoRefreshPanel() { 373 if (checkBoxAutoRefresh.isSelected()) { 374 autoRefreshThread = new Thread(new Runnable() { 375 @Override 376 public void run() { 377 while (true) { 378 refreshPanel(); 379 synchronized (this) { 380 try { 381 wait(4000); // 4 seconds 382 } catch (InterruptedException e) { 383 break; 384 } 385 } 386 } 387 } 388 }); 389 autoRefreshThread.setName("NCE Show Cabs Auto Refresh"); 390 autoRefreshThread.setPriority(Thread.MIN_PRIORITY); 391 autoRefreshThread.start(); 392 } else { 393 autoRefreshThread.interrupt(); 394 } 395 } 396 397 private void refreshPanel() { 398 processMemory(false, true, -1); 399 } 400 401 private void processMemory(boolean doPurge, boolean doUpdate, int cabId) { 402 if (doPurge) { 403 purgeRequested = true; 404 purgeCabId = cabId; 405 } 406 if (doUpdate) { 407 updateRequested = true; 408 } 409 // Set up a separate thread to access CS memory 410 if (nceCabUpdateThread != null && nceCabUpdateThread.isAlive()) { 411 return; // thread is already running 412 } 413 textStatus.setText(Bundle.getMessage("StatusProcessingMemory")); 414 nceCabUpdateThread = new Thread(new Runnable() { 415 @Override 416 public void run() { 417 if (tc.getUsbSystem() == NceTrafficController.USB_SYSTEM_NONE) { 418 if (purgeRequested) { 419 cabPurgeSerial(); 420 } 421 if (updateRequested) { 422 cabUpdateSerial(); 423 } 424 } else { 425 if (purgeRequested) { 426 cabPurgeUsb(); 427 } 428 if (updateRequested) { 429 cabUpdateUsb(); 430 } 431 } 432 } 433 }); 434 nceCabUpdateThread.setName(Bundle.getMessage("ThreadTitle")); 435 nceCabUpdateThread.setPriority(Thread.MIN_PRIORITY); 436 nceCabUpdateThread.start(); 437 } 438 439 private boolean firstTime = false; // wait for panel to display 440 441 public void cabPurgeSerial() { 442 if (purgeCabId <= minCabNum || purgeCabId >= maxCabNum) { 443 log.error("purgeCabId out of range: {}", purgeCabId); 444 } 445 if (firstTime) { 446 try { 447 Thread.sleep(FIRST_TIME_SLEEP); // wait for panel to display 448 } catch (InterruptedException e) { 449 log.error("Thread unexpectedly interrupted", e); 450 } 451 } 452 453 firstTime = false; 454 // clear bit for active and cab type details 455 cabFlag1Array[purgeCabId] = 0; 456 writeCabMemory1(purgeCabId, tc.csm.getCabIdxFlag1(), 0); 457 if (!waitNce()) { 458 return; 459 } 460 textStatus.setText(MessageFormat.format(Bundle.getMessage("StatusCabPurged"), purgeCabId)); 461 } 462 463 public void cabPurgeUsb() { 464 if (purgeCabId <= minCabNum || purgeCabId >= maxCabNum) { 465 log.error("purgeCabId out of range: {}", purgeCabId); 466 } 467 if (firstTime) { 468 try { 469 Thread.sleep(FIRST_TIME_SLEEP); // wait for panel to display 470 } catch (InterruptedException e) { 471 log.error("Thread unexpectedly interrupted", e); 472 } 473 } 474 475 firstTime = false; 476 // clear bit for active and cab type details 477 cabFlag1Array[purgeCabId] = 0; 478 setUsbCabMemoryPointer(purgeCabId, tc.csm.getCabIdxFlag1()); 479 if (!waitNce()) { 480 return; 481 } 482 writeUsbCabMemory1(0); 483 if (!waitNce()) { 484 return; 485 } 486 textStatus.setText(MessageFormat.format(Bundle.getMessage("StatusCabPurged"), purgeCabId)); 487 } 488 489 // Thread to update cab info, allows the use of sleep or wait, for serial connection 490 private void cabUpdateSerial() { 491 492 if (firstTime) { 493 try { 494 Thread.sleep(FIRST_TIME_SLEEP); // wait for panel to display 495 } catch (InterruptedException e) { 496 log.error("Thread unexpectedly interrupted", e); 497 } 498 } 499 500 firstTime = false; 501 int cabsFound = 0; 502 // build table of cabs 503 for (int currCabId = minCabNum; currCabId <= maxCabNum; currCabId++) { 504 505 textStatus.setText(MessageFormat.format(Bundle.getMessage("StatusProcessingCabId"), currCabId)); 506 cabData[currCabId].cabNumber = currCabId; 507 int foundChange = 0; 508 recChar = -1; 509 // create cab type by reading the FLAGS1 byte 510 readCabMemory1(currCabId, tc.csm.getCabIdxFlag1()); 511 if (!waitNce()) { 512 return; 513 } 514 log.debug("ID = {} Read flag1 character {}", currCabId, recChar); 515 // test it really changed 516 if (recChar != -1) { 517 // save value for purge 518 if (recChar != cabFlag1Array[currCabId]) { 519 foundChange++; 520 if (log.isDebugEnabled()) { 521 log.debug("{}: Flag1 {}<->{}", currCabId, recChar, cabFlag1Array[currCabId]); 522 } 523 } 524 cabFlag1Array[currCabId] = recChar; 525 if ((recChar & NceCmdStationMemory.FLAGS1_MASK_CABISACTIVE) != NceCmdStationMemory.FLAGS1_CABISACTIVE) { 526 // not active slot 527 continue; 528 } 529 if (currCabId >= 1 || !checkBoxShowAllCabs.isSelected()) { 530 cabsFound++; 531 } 532 int cabType = recChar & NceCmdStationMemory.FLAGS1_MASK_CABTYPE; // mask off don't care bits 533 if (currCabId == minCabNum) { 534 cabData[currCabId].cabType = Bundle.getMessage("TypeSerial"); 535 } else if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_DISPLAY) { 536 cabData[currCabId].cabType = Bundle.getMessage("TypeProCab"); 537 } else if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_NODISP) { 538 cabData[currCabId].cabType = Bundle.getMessage("TypeCab04"); // Cab04 or Cab06 539 } else if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_USB) { 540 cabData[currCabId].cabType = Bundle.getMessage("TypeUSB"); // USB or Mini-Panel 541 } else if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_AIU) { 542 cabData[currCabId].cabType = Bundle.getMessage("TypeAIU"); 543 } else { 544 cabData[currCabId].cabType = Bundle.getMessage("TypeUnknownCab") + ": " + recChar; 545 } 546 547 cabData[currCabId].cabNumber = currCabId; 548 if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_AIU) { 549 // get the AIU data and map it to the function bits 550 readAiuData(currCabId); 551 if (!waitNce()) { 552 return; 553 } 554 processAiuData(currCabId, recChars); 555 // } else if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_USB) { 556 // I don't have anything to do for the USB at this time 557 } else { 558 // read 16 bytes of memory, we'll use 7 of the 16 559 readCabMemory16(currCabId, NceCmdStationMemory.CAB_CURR_SPEED); 560 if (!waitNce()) { 561 return; 562 } 563 // read the Speed byte 564 int readChar = recChars[0]; 565 if (cabSpeedArray[currCabId] != readChar) { 566 foundChange++; 567 if (log.isDebugEnabled()) { 568 log.debug("{}: Speed {}<->{}", currCabId, readChar, cabSpeedArray[currCabId]); 569 } 570 } 571 cabSpeedArray[currCabId] = readChar; 572 log.debug("Read speed character {}", readChar); 573 cabData[currCabId].locoSpeed = readChar; 574 575 // read the FLAGS byte 576 readChar = recChars[NceCmdStationMemory.CAB_FLAGS - NceCmdStationMemory.CAB_CURR_SPEED]; 577 if (cabFlagsArray[currCabId] != readChar) { 578 foundChange++; 579 if (log.isDebugEnabled()) { 580 log.debug("{}: Flags {}<->{}", currCabId, readChar, cabFlagsArray[currCabId]); 581 } 582 } 583 cabFlagsArray[currCabId] = readChar; 584 int direction = readChar & 0x04; 585 if (direction > 0) { 586 cabData[currCabId].locoDir = Bundle.getMessage("DirForward"); 587 } else { 588 cabData[currCabId].locoDir = Bundle.getMessage("DirReverse"); 589 } 590 int mode = readChar & 0x02; 591 // USB doesn't use the 28/128 bit 592 cabData[currCabId].mode = ""; 593 if (cabType != NceCmdStationMemory.FLAGS1_CABTYPE_USB) { 594 if (mode > 0) { 595 cabData[currCabId].mode = "128"; 596 } else { 597 cabData[currCabId].mode = "28"; 598 } 599 } 600 601 // create loco address, read the high address byte 602 readChar = recChars[NceCmdStationMemory.CAB_ADDR_H - NceCmdStationMemory.CAB_CURR_SPEED]; 603 log.debug("Read address high character {}", readChar); 604 int locoAddress = (readChar & 0x3F) * 256; 605 boolean aType = ((readChar & 0xC0) == 0xC0); 606 if (cabLongShortArray[currCabId] != aType) { 607 foundChange++; 608 if (log.isDebugEnabled()) { 609 log.debug("{}: Long {}<->{}", currCabId, aType, cabLongShortArray[currCabId]); 610 } 611 } 612 cabLongShortArray[currCabId] = aType; 613 if (aType) { 614 cabData[currCabId].longShort = Bundle.getMessage("IsLongAddr"); 615 } else { 616 cabData[currCabId].longShort = Bundle.getMessage("IsShortAddr"); 617 } 618 // read the low address byte 619 readChar = recChars[NceCmdStationMemory.CAB_ADDR_L - NceCmdStationMemory.CAB_CURR_SPEED]; 620 log.debug("Read address low character {}", readChar); 621 locoAddress = locoAddress + (readChar & 0xFF); 622 if (cabLocoArray[currCabId] != locoAddress) { 623 foundChange++; 624 if (log.isDebugEnabled()) { 625 log.debug("{}: Loco {}<->{}", currCabId, locoAddress, cabLocoArray[currCabId]); 626 } 627 } 628 cabLocoArray[currCabId] = locoAddress; 629 cabData[currCabId].locoAddress = locoAddress; 630 631 // create consist address 632 readChar = recChars[NceCmdStationMemory.CAB_ALIAS - NceCmdStationMemory.CAB_CURR_SPEED]; 633 if (cabConsistArray[currCabId] != readChar) { 634 foundChange++; 635 if (log.isDebugEnabled()) { 636 log.debug("{}: Consist {}<->{}", currCabId, readChar, cabConsistArray[currCabId]); 637 } 638 } 639 cabConsistArray[currCabId] = readChar; 640 cabData[currCabId].consist = readChar; 641 642 // show consist position if relevant 643 int pos = cabFlagsArray[currCabId] & NceCmdStationMemory.FLAGS_MASK_CONSIST_REAR; 644 cabData[currCabId].consistPos = ""; 645 if (cabConsistArray[currCabId] != 0) { 646 if (pos > 0) { 647 cabData[currCabId].consistPos = Bundle.getMessage("IsRear"); 648 } else { 649 cabData[currCabId].consistPos = Bundle.getMessage("IsLead"); 650 } 651 } 652 653 // get the functions 0-4 values 654 readChar = recChars[NceCmdStationMemory.CAB_FUNC_L - NceCmdStationMemory.CAB_CURR_SPEED]; 655 if (cabF0Array[currCabId] != readChar) { 656 foundChange++; 657 if (log.isDebugEnabled()) { 658 log.debug("{}: F0 {}<->{}", currCabId, readChar, cabF0Array[currCabId]); 659 } 660 } 661 cabF0Array[currCabId] = readChar; 662 log.debug("Function low character {}", readChar); 663 procFunctions0_4(currCabId, readChar); 664 665 // get the functions 5-12 values 666 readChar = recChars[NceCmdStationMemory.CAB_FUNC_H - NceCmdStationMemory.CAB_CURR_SPEED]; 667 if (cabF5Array[currCabId] != readChar) { 668 foundChange++; 669 if (log.isDebugEnabled()) { 670 log.debug("{}: F5 {}<->{}", currCabId, readChar, cabF5Array[currCabId]); 671 } 672 } 673 cabF5Array[currCabId] = readChar; 674 log.debug("Function high character {}", readChar); 675 procFunctions5_12(currCabId, readChar); 676 677 // get the functions 13-20 values 678 readCabMemory1(currCabId, tc.csm.getCabIdxFunct13_20()); 679 if (!waitNce()) { 680 return; 681 } 682 if (cabF13Array[currCabId] != recChar) { 683 foundChange++; 684 if (log.isDebugEnabled()) { 685 log.debug("{}: F13 {}<->{}", currCabId, recChar, cabF13Array[currCabId]); 686 } 687 } 688 cabF13Array[currCabId] = recChar; 689 procFunctions13_20(currCabId, recChar); 690 691 // get the functions 21-28 values 692 readCabMemory1(currCabId, tc.csm.getCabIdxFunct21_28()); 693 if (!waitNce()) { 694 return; 695 } 696 if (cabF21Array[currCabId] != recChar) { 697 foundChange++; 698 if (log.isDebugEnabled()) { 699 log.debug("{}: F21 {}<->{}", currCabId, recChar, cabF21Array[currCabId]); 700 } 701 } 702 cabF21Array[currCabId] = recChar; 703 procFunctions21_28(currCabId, recChar); 704 705 // get the display values 706 readCabMemory16(currCabId, NceCmdStationMemory.CAB_LINE_1); 707 if (!waitNce()) { 708 return; 709 } 710 StringBuilder text1 = new StringBuilder(); 711 StringBuilder debug1 = new StringBuilder(); 712 for (int i = 0; i < CAB_LINE_LEN; i++) { 713 if (cabLine1Array[currCabId][i] != recChars[i]) { 714 foundChange++; 715 if (log.isDebugEnabled()) { 716 log.debug("{}: CabLine1[{}] {}<->{}", currCabId, i, recChars[i], cabLine1Array[currCabId][i]); 717 } 718 } 719 cabLine1Array[currCabId][i] = recChars[i]; 720 if (recChars[i] >= 0x20 && recChars[i] <= 0x7F) { 721 text1.append((char) recChars[i]); 722 } else { 723 text1.append(" "); 724 } 725 debug1.append(" ").append(recChars[i]); 726 } 727 cabData[currCabId].text1 = text1.toString(); 728 log.debug("TextLine1Debug: {}", debug1); 729 730 readCabMemory16(currCabId, NceCmdStationMemory.CAB_LINE_2); 731 if (!waitNce()) { 732 return; 733 } 734 StringBuilder text2 = new StringBuilder(); 735 StringBuilder debug2 = new StringBuilder(); 736 for (int i = 0; i < CAB_LINE_LEN; i++) { 737 if (cabLine2Array[currCabId][i] != recChars[i]) { 738 foundChange++; 739 if (log.isDebugEnabled()) { 740 log.debug("{}: CabLine2[{}] {}<->{}", currCabId, i, recChars[i], cabLine2Array[currCabId][i]); 741 } 742 } 743 cabLine2Array[currCabId][i] = recChars[i]; 744 if (recChars[i] >= 0x20 && recChars[i] <= 0x7F) { 745 text2.append((char) recChars[i]); 746 } else { 747 text2.append(" "); 748 } 749 debug2.append(" ").append(recChars[i]); 750 } 751 cabData[currCabId].text2 = text2.toString(); 752 log.debug("TextLine2Debug: {}", debug2); 753 754 Calendar now = Calendar.getInstance(); 755 if (foundChange > 0 || cabLastChangeArray[currCabId] == null) { 756 cabLastChangeArray[currCabId] = now; 757 StringBuilder txt = new StringBuilder(); 758 int h = cabLastChangeArray[currCabId].get(Calendar.HOUR_OF_DAY); 759 int m = cabLastChangeArray[currCabId].get(Calendar.MINUTE); 760 int s = cabLastChangeArray[currCabId].get(Calendar.SECOND); 761 if (h < 10) { 762 txt.append("0"); 763 } 764 txt.append(h); 765 txt.append(":"); 766 if (m < 10) { 767 txt.append("0"); 768 } 769 txt.append(m); 770 txt.append(":"); 771 if (s < 10) { 772 txt.append("0"); 773 } 774 txt.append(s); 775 cabData[currCabId].lastChange = txt.toString(); 776 } 777 } 778 } 779 } 780 781 textStatus.setText(Bundle.getMessage("StatusProcessingDone") 782 + ". " 783 + MessageFormat.format(Bundle.getMessage("StatusCabsFound"), cabsFound)); 784 cabModel.fireTableDataChanged(); 785 this.setVisible(true); 786 this.repaint(); 787 } 788 789 // Thread to update cab info, allows the use of sleep or wait, for NCE-USB connection 790 private void cabUpdateUsb() { 791 792 if (firstTime) { 793 try { 794 Thread.sleep(FIRST_TIME_SLEEP); // wait for panel to display 795 } catch (InterruptedException e) { 796 log.error("Thread unexpectedly interrupted", e); 797 } 798 } 799 800 firstTime = false; 801 int cabsFound = 0; 802 // build table of cabs 803 for (int currCabId = minCabNum; currCabId <= maxCabNum; currCabId++) { 804 805 textStatus.setText(MessageFormat.format(Bundle.getMessage("StatusProcessingCabId"), currCabId)); 806 cabData[currCabId].cabNumber = currCabId; 807 int foundChange = 0; 808 recChar = -1; 809 // create cab type by reading the FLAGS1 byte 810 setUsbCabMemoryPointer(currCabId, tc.csm.getCabIdxFlag1()); 811 if (!waitNce()) { 812 return; 813 } 814 readUsbCabMemoryN(1); 815 if (!waitNce()) { 816 return; 817 } 818 log.debug("ID = {} Read flag1 character {}", currCabId, recChar); 819 // test it really changed 820 if (recChar != -1) { 821 // save value for purge 822 if (recChar != cabFlag1Array[currCabId]) { 823 foundChange++; 824 if (log.isDebugEnabled()) { 825 log.debug("{}: Flag1 {}<->{}", currCabId, recChar, cabFlag1Array[currCabId]); 826 } 827 } 828 cabFlag1Array[currCabId] = recChar; 829 if ((recChar & NceCmdStationMemory.FLAGS1_MASK_CABISACTIVE) != NceCmdStationMemory.FLAGS1_CABISACTIVE) { 830 // not active slot 831 continue; 832 } 833 if (currCabId >= 1 || !checkBoxShowAllCabs.isSelected()) { 834 cabsFound++; 835 } 836 837 int cabType = recChar & NceCmdStationMemory.FLAGS1_MASK_CABTYPE; // mask off don't care bits 838 if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_DISPLAY) { 839 cabData[currCabId].cabType = Bundle.getMessage("TypeProCab"); 840 } else if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_NODISP) { 841 cabData[currCabId].cabType = Bundle.getMessage("TypeCab04"); // Cab04 or Cab06 842 } else if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_USB) { 843 cabData[currCabId].cabType = Bundle.getMessage("TypeUSB"); // USB or Mini-Panel 844 } else if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_AIU) { 845 cabData[currCabId].cabType = Bundle.getMessage("TypeAIU"); 846 } else { 847 cabData[currCabId].cabType = Bundle.getMessage("TypeUnknownCab") + ": " + recChar; 848 } 849 850 cabData[currCabId].cabNumber = currCabId; 851 if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_AIU) { 852 // get the AIU data and map it to the function bits 853 readAiuData(currCabId); 854 if (!waitNce()) { 855 return; 856 } 857 processAiuData(currCabId, recChars); 858 // } else if (cabType == NceCmdStationMemory.FLAGS1_CABTYPE_USB) { 859 // I don't have anything to do for the USB at this time 860 } else { 861 setUsbCabMemoryPointer(currCabId, NceCmdStationMemory.CAB_CURR_SPEED); 862 if (!waitNce()) { 863 return; 864 } 865 // read the Speed byte 866 readUsbCabMemoryN(1); 867 if (!waitNce()) { 868 return; 869 } 870 int readChar = recChar; 871 if (cabSpeedArray[currCabId] != readChar) { 872 foundChange++; 873 if (log.isDebugEnabled()) { 874 log.debug("{}: Speed {}<->{}", currCabId, readChar, cabSpeedArray[currCabId]); 875 } 876 } 877 cabSpeedArray[currCabId] = readChar; 878 log.debug("Read speed character {}", readChar); 879 cabData[currCabId].locoSpeed = readChar; 880 881 // create loco address, read the high address byte 882 readUsbCabMemoryN(1); 883 if (!waitNce()) { 884 return; 885 } 886 readChar = recChar; 887 log.debug("Read address high character {}", readChar); 888 int locoAddress = (readChar & 0x3F) * 256; 889 boolean aType = ((readChar & 0xC0) == 0xC0); 890 if (cabLongShortArray[currCabId] != aType) { 891 foundChange++; 892 if (log.isDebugEnabled()) { 893 log.debug("{}: Long {}<->{}", currCabId, aType, cabLongShortArray[currCabId]); 894 } 895 } 896 cabLongShortArray[currCabId] = aType; 897 if (aType) { 898 cabData[currCabId].longShort = Bundle.getMessage("IsLongAddr"); 899 } else { 900 cabData[currCabId].longShort = Bundle.getMessage("IsShortAddr"); 901 } 902 // read the low address byte 903 readUsbCabMemoryN(1); 904 if (!waitNce()) { 905 return; 906 } 907 readChar = recChar; 908 log.debug("Read address low character {}", readChar); 909 locoAddress = locoAddress + (readChar & 0xFF); 910 if (cabLocoArray[currCabId] != locoAddress) { 911 foundChange++; 912 if (log.isDebugEnabled()) { 913 log.debug("{}: Loco {}<->{}", currCabId, locoAddress, cabLocoArray[currCabId]); 914 } 915 } 916 cabLocoArray[currCabId] = locoAddress; 917 cabData[currCabId].locoAddress = locoAddress; 918 919 // read the FLAGS byte 920 readUsbCabMemoryN(1); 921 if (!waitNce()) { 922 return; 923 } 924 readChar = recChar; 925 if (cabFlagsArray[currCabId] != readChar) { 926 foundChange++; 927 if (log.isDebugEnabled()) { 928 log.debug("{}: Flags {}<->{}", currCabId, readChar, cabFlagsArray[currCabId]); 929 } 930 } 931 cabFlagsArray[currCabId] = readChar; 932 int direction = readChar & 0x04; 933 if (direction > 0) { 934 cabData[currCabId].locoDir = Bundle.getMessage("DirForward"); 935 } else { 936 cabData[currCabId].locoDir = Bundle.getMessage("DirReverse"); 937 } 938 int mode = readChar & 0x02; 939 // USB doesn't use the 28/128 bit 940 cabData[currCabId].mode = ""; 941 if (cabType != NceCmdStationMemory.FLAGS1_CABTYPE_USB) { 942 if (mode > 0) { 943 cabData[currCabId].mode = "128"; 944 } else { 945 cabData[currCabId].mode = "28"; 946 } 947 } 948 949 // get the functions 0-4 values 950 readUsbCabMemoryN(1); 951 if (!waitNce()) { 952 return; 953 } 954 readChar = recChar; 955 if (cabF0Array[currCabId] != readChar) { 956 foundChange++; 957 if (log.isDebugEnabled()) { 958 log.debug("{}: F0 {}<->{}", currCabId, readChar, cabF0Array[currCabId]); 959 } 960 } 961 cabF0Array[currCabId] = readChar; 962 if (log.isDebugEnabled()) { 963 log.debug("Function low character {}", readChar); 964 } 965 procFunctions0_4(currCabId, readChar); 966 967 // get the functions 5-12 values 968 readUsbCabMemoryN(1); 969 if (!waitNce()) { 970 return; 971 } 972 readChar = recChar; 973 if (cabF5Array[currCabId] != readChar) { 974 foundChange++; 975 if (log.isDebugEnabled()) { 976 log.debug("{}: F5 {}<->{}", currCabId, readChar, cabF5Array[currCabId]); 977 } 978 } 979 cabF5Array[currCabId] = readChar; 980 log.debug("Function high character {}", readChar); 981 procFunctions5_12(currCabId, readChar); 982 983 // read consist address 984 readUsbCabMemoryN(1); 985 if (!waitNce()) { 986 return; 987 } 988 readChar = recChar; 989 if (cabConsistArray[currCabId] != readChar) { 990 foundChange++; 991 if (log.isDebugEnabled()) { 992 log.debug("{}: Consist {}<->{}", currCabId, readChar, cabConsistArray[currCabId]); 993 } 994 } 995 cabConsistArray[currCabId] = readChar; 996 cabData[currCabId].consist = readChar; 997 998 // show consist position if relevant 999 int pos = cabFlagsArray[currCabId] & NceCmdStationMemory.FLAGS_MASK_CONSIST_REAR; 1000 cabData[currCabId].consistPos = ""; 1001 if (cabConsistArray[currCabId] != 0) { 1002 if (pos > 0) { 1003 cabData[currCabId].consistPos = Bundle.getMessage("IsRear"); 1004 } else { 1005 cabData[currCabId].consistPos = Bundle.getMessage("IsLead"); 1006 } 1007 } 1008 1009 // get the functions 13-20 values 1010 setUsbCabMemoryPointer(currCabId, tc.csm.getCabIdxFunct13_20()); 1011 if (!waitNce()) { 1012 return; 1013 } 1014 readUsbCabMemoryN(1); 1015 if (!waitNce()) { 1016 return; 1017 } 1018 if (cabF13Array[currCabId] != recChar) { 1019 foundChange++; 1020 if (log.isDebugEnabled()) { 1021 log.debug("{}: F13 {}<->{}", currCabId, recChar, cabF13Array[currCabId]); 1022 } 1023 } 1024 cabF13Array[currCabId] = recChar; 1025 procFunctions13_20(currCabId, recChar); 1026 1027 // get the functions 20-28 values 1028 setUsbCabMemoryPointer(currCabId, tc.csm.getCabIdxFunct21_28()); 1029 if (!waitNce()) { 1030 return; 1031 } 1032 readUsbCabMemoryN(1); 1033 if (!waitNce()) { 1034 return; 1035 } 1036 if (cabF21Array[currCabId] != recChar) { 1037 foundChange++; 1038 if (log.isDebugEnabled()) { 1039 log.debug("{}: F21 {}<->{}", currCabId, recChar, cabF21Array[currCabId]); 1040 } 1041 } 1042 cabF21Array[currCabId] = recChar; 1043 procFunctions21_28(currCabId, recChar); 1044 1045 // get the display values 1046 setUsbCabMemoryPointer(currCabId, NceCmdStationMemory.CAB_LINE_1); 1047 if (!waitNce()) { 1048 return; 1049 } 1050 readUsbCabMemoryN(4); 1051 if (!waitNce()) { 1052 return; 1053 } 1054 StringBuilder text1 = new StringBuilder(); 1055 StringBuilder debug1 = new StringBuilder(); 1056 int ptrData; 1057 int ptrCabLine = 0; 1058 for (ptrData = 0; ptrData < 4; ptrData++, ptrCabLine++) { 1059 if (cabLine1Array[currCabId][ptrCabLine] != recChars[ptrData]) { 1060 foundChange++; 1061 if (log.isDebugEnabled()) { 1062 log.debug("{}: CabLine1[{}] {}<->{}", currCabId, ptrCabLine, recChars[ptrData], cabLine1Array[currCabId][ptrCabLine]); 1063 } 1064 } 1065 cabLine1Array[currCabId][ptrCabLine] = recChars[ptrData]; 1066 if (recChars[ptrData] >= 0x20 && recChars[ptrData] <= 0x7F) { 1067 text1.append((char) recChars[ptrData]); 1068 } else { 1069 text1.append(" "); 1070 } 1071 debug1.append(" ").append(recChars[ptrData]); 1072 } 1073 readUsbCabMemoryN(4); 1074 if (!waitNce()) { 1075 return; 1076 } 1077 for (ptrData = 0; ptrData < 4; ptrData++, ptrCabLine++) { 1078 if (cabLine1Array[currCabId][ptrCabLine] != recChars[ptrData]) { 1079 foundChange++; 1080 if (log.isDebugEnabled()) { 1081 log.debug("{}: CabLine1[{}] {}<->{}", currCabId, ptrCabLine, recChars[ptrData], cabLine1Array[currCabId][ptrCabLine]); 1082 } 1083 } 1084 cabLine1Array[currCabId][ptrCabLine] = recChars[ptrData]; 1085 if (recChars[ptrData] >= 0x20 && recChars[ptrData] <= 0x7F) { 1086 text1.append((char) recChars[ptrData]); 1087 } else { 1088 text1.append(" "); 1089 } 1090 debug1.append(" ").append(recChars[ptrData]); 1091 } 1092 readUsbCabMemoryN(4); 1093 if (!waitNce()) { 1094 return; 1095 } 1096 for (ptrData = 0; ptrData < 4; ptrData++, ptrCabLine++) { 1097 if (cabLine1Array[currCabId][ptrCabLine] != recChars[ptrData]) { 1098 foundChange++; 1099 if (log.isDebugEnabled()) { 1100 log.debug("{}: CabLine1[{}] {}<->{}", currCabId, ptrCabLine, recChars[ptrData], cabLine1Array[currCabId][ptrCabLine]); 1101 } 1102 } 1103 cabLine1Array[currCabId][ptrCabLine] = recChars[ptrData]; 1104 if (recChars[ptrData] >= 0x20 && recChars[ptrData] <= 0x7F) { 1105 text1.append((char) recChars[ptrData]); 1106 } else { 1107 text1.append(" "); 1108 } 1109 debug1.append(" ").append(recChars[ptrData]); 1110 } 1111 readUsbCabMemoryN(4); 1112 if (!waitNce()) { 1113 return; 1114 } 1115 for (ptrData = 0; ptrData < 4; ptrData++, ptrCabLine++) { 1116 if (cabLine1Array[currCabId][ptrCabLine] != recChars[ptrData]) { 1117 foundChange++; 1118 if (log.isDebugEnabled()) { 1119 log.debug("{}: CabLine1[{}] {}<->{}", currCabId, ptrCabLine, recChars[ptrData], cabLine1Array[currCabId][ptrCabLine]); 1120 } 1121 } 1122 cabLine1Array[currCabId][ptrCabLine] = recChars[ptrData]; 1123 if (recChars[ptrData] >= 0x20 && recChars[ptrData] <= 0x7F) { 1124 text1.append((char) recChars[ptrData]); 1125 } else { 1126 text1.append(" "); 1127 } 1128 debug1.append(" ").append(recChars[ptrData]); 1129 } 1130 cabData[currCabId].text1 = text1.toString(); 1131 log.debug("TextLine1Debug: {}", debug1); 1132 1133 readUsbCabMemoryN(4); 1134 if (!waitNce()) { 1135 return; 1136 } 1137 StringBuilder text2 = new StringBuilder(); 1138 StringBuilder debug2 = new StringBuilder(); 1139 ptrCabLine = 0; 1140 for (ptrData = 0; ptrData < 4; ptrData++, ptrCabLine++) { 1141 if (cabLine2Array[currCabId][ptrCabLine] != recChars[ptrData]) { 1142 foundChange++; 1143 if (log.isDebugEnabled()) { 1144 log.debug("{}: CabLine2[{}] {}<->{}", currCabId, ptrCabLine, recChars[ptrData], cabLine2Array[currCabId][ptrCabLine]); 1145 } 1146 } 1147 cabLine2Array[currCabId][ptrCabLine] = recChars[ptrData]; 1148 if (recChars[ptrData] >= 0x20 && recChars[ptrData] <= 0x7F) { 1149 text2.append((char) recChars[ptrData]); 1150 } else { 1151 text2.append(" "); 1152 } 1153 debug2.append(" ").append(recChars[ptrData]); 1154 } 1155 readUsbCabMemoryN(4); 1156 if (!waitNce()) { 1157 return; 1158 } 1159 for (ptrData = 0; ptrData < 4; ptrData++, ptrCabLine++) { 1160 if (cabLine2Array[currCabId][ptrCabLine] != recChars[ptrData]) { 1161 foundChange++; 1162 if (log.isDebugEnabled()) { 1163 log.debug("{}: CabLine2[{}] {}<->{}", currCabId, ptrCabLine, recChars[ptrData], cabLine2Array[currCabId][ptrCabLine]); 1164 } 1165 } 1166 cabLine2Array[currCabId][ptrCabLine] = recChars[ptrData]; 1167 if (recChars[ptrData] >= 0x20 && recChars[ptrData] <= 0x7F) { 1168 text2.append((char) recChars[ptrData]); 1169 } else { 1170 text2.append(" "); 1171 } 1172 debug2.append(" ").append(recChars[ptrData]); 1173 } 1174 readUsbCabMemoryN(4); 1175 if (!waitNce()) { 1176 return; 1177 } 1178 for (ptrData = 0; ptrData < 4; ptrData++, ptrCabLine++) { 1179 if (cabLine2Array[currCabId][ptrCabLine] != recChars[ptrData]) { 1180 foundChange++; 1181 if (log.isDebugEnabled()) { 1182 log.debug("{}: CabLine2[{}] {}<->{}", currCabId, ptrCabLine, recChars[ptrData], cabLine2Array[currCabId][ptrCabLine]); 1183 } 1184 } 1185 cabLine2Array[currCabId][ptrCabLine] = recChars[ptrData]; 1186 if (recChars[ptrData] >= 0x20 && recChars[ptrData] <= 0x7F) { 1187 text2.append((char) recChars[ptrData]); 1188 } else { 1189 text2.append(" "); 1190 } 1191 debug2.append(" ").append(recChars[ptrData]); 1192 } 1193 readUsbCabMemoryN(4); 1194 if (!waitNce()) { 1195 return; 1196 } 1197 for (ptrData = 0; ptrData < 4; ptrData++, ptrCabLine++) { 1198 if (cabLine2Array[currCabId][ptrCabLine] != recChars[ptrData]) { 1199 foundChange++; 1200 if (log.isDebugEnabled()) { 1201 log.debug("{}: CabLine2[{}] {}<->{}", currCabId, ptrCabLine, recChars[ptrData], cabLine2Array[currCabId][ptrCabLine]); 1202 } 1203 } 1204 cabLine2Array[currCabId][ptrCabLine] = recChars[ptrData]; 1205 if (recChars[ptrData] >= 0x20 && recChars[ptrData] <= 0x7F) { 1206 text2.append((char) recChars[ptrData]); 1207 } else { 1208 text2.append(" "); 1209 } 1210 debug2.append(" ").append(recChars[ptrData]); 1211 } 1212 cabData[currCabId].text2 = text2.toString(); 1213 log.debug("TextLine2Debug: {}", debug2); 1214 1215 // add log time stamp 1216 Calendar now = Calendar.getInstance(); 1217 if (foundChange > 0 || cabLastChangeArray[currCabId] == null) { 1218 cabLastChangeArray[currCabId] = now; 1219 StringBuilder txt = new StringBuilder(); 1220 int h = cabLastChangeArray[currCabId].get(Calendar.HOUR_OF_DAY); 1221 int m = cabLastChangeArray[currCabId].get(Calendar.MINUTE); 1222 int s = cabLastChangeArray[currCabId].get(Calendar.SECOND); 1223 if (h < 10) { 1224 txt.append("0"); 1225 } 1226 txt.append(h); 1227 txt.append(":"); 1228 if (m < 10) { 1229 txt.append("0"); 1230 } 1231 txt.append(m); 1232 txt.append(":"); 1233 if (s < 10) { 1234 txt.append("0"); 1235 } 1236 txt.append(s); 1237 cabData[currCabId].lastChange = txt.toString(); 1238 } 1239 } 1240 } 1241 } 1242 1243 textStatus.setText(Bundle.getMessage("StatusProcessingDone") 1244 + ". " 1245 + MessageFormat.format(Bundle.getMessage("StatusCabsFound"), cabsFound)); 1246 cabModel.fireTableDataChanged(); 1247 this.setVisible(true); 1248 this.repaint(); 1249 } 1250 1251 /** 1252 * Process for functions F0-F4. 1253 * <p> 1254 */ 1255 private void procFunctions0_4(int currCabId, int c) { 1256 cabData[currCabId].F0 = (c & NceCmdStationMemory.FUNC_L_F0) != 0; 1257 cabData[currCabId].F1 = (c & NceCmdStationMemory.FUNC_L_F1) != 0; 1258 cabData[currCabId].F2 = (c & NceCmdStationMemory.FUNC_L_F2) != 0; 1259 cabData[currCabId].F3 = (c & NceCmdStationMemory.FUNC_L_F3) != 0; 1260 cabData[currCabId].F4 = (c & NceCmdStationMemory.FUNC_L_F4) != 0; 1261 } 1262 1263 /** 1264 * Process for functions 5 through 12. 1265 * <p> 1266 */ 1267 private void procFunctions5_12(int currCabId, int c) { 1268 cabData[currCabId].F5 = (c & NceCmdStationMemory.FUNC_H_F5) != 0; 1269 cabData[currCabId].F6 = (c & NceCmdStationMemory.FUNC_H_F6) != 0; 1270 cabData[currCabId].F7 = (c & NceCmdStationMemory.FUNC_H_F7) != 0; 1271 cabData[currCabId].F8 = (c & NceCmdStationMemory.FUNC_H_F8) != 0; 1272 cabData[currCabId].F9 = (c & NceCmdStationMemory.FUNC_H_F9) != 0; 1273 cabData[currCabId].F10 = (c & NceCmdStationMemory.FUNC_H_F10) != 0; 1274 cabData[currCabId].F11 = (c & NceCmdStationMemory.FUNC_H_F11) != 0; 1275 cabData[currCabId].F12 = (c & NceCmdStationMemory.FUNC_H_F12) != 0; 1276 } 1277 1278 /** 1279 * Process char for functions 13-20. 1280 * <p> 1281 */ 1282 private void procFunctions13_20(int currCabId, int c) { 1283 cabData[currCabId].F13 = (c & NceCmdStationMemory.FUNC_H_F13) != 0; 1284 cabData[currCabId].F14 = (c & NceCmdStationMemory.FUNC_H_F14) != 0; 1285 cabData[currCabId].F15 = (c & NceCmdStationMemory.FUNC_H_F15) != 0; 1286 cabData[currCabId].F16 = (c & NceCmdStationMemory.FUNC_H_F16) != 0; 1287 cabData[currCabId].F17 = (c & NceCmdStationMemory.FUNC_H_F17) != 0; 1288 cabData[currCabId].F18 = (c & NceCmdStationMemory.FUNC_H_F18) != 0; 1289 cabData[currCabId].F19 = (c & NceCmdStationMemory.FUNC_H_F19) != 0; 1290 cabData[currCabId].F20 = (c & NceCmdStationMemory.FUNC_H_F20) != 0; 1291 } 1292 1293 /** 1294 * Process char for functions 21-28. 1295 * <p> 1296 */ 1297 private void procFunctions21_28(int currCabId, int c) { 1298 cabData[currCabId].F21 = (c & NceCmdStationMemory.FUNC_H_F21) != 0; 1299 cabData[currCabId].F22 = (c & NceCmdStationMemory.FUNC_H_F22) != 0; 1300 cabData[currCabId].F23 = (c & NceCmdStationMemory.FUNC_H_F23) != 0; 1301 cabData[currCabId].F24 = (c & NceCmdStationMemory.FUNC_H_F24) != 0; 1302 cabData[currCabId].F25 = (c & NceCmdStationMemory.FUNC_H_F25) != 0; 1303 cabData[currCabId].F26 = (c & NceCmdStationMemory.FUNC_H_F26) != 0; 1304 cabData[currCabId].F27 = (c & NceCmdStationMemory.FUNC_H_F27) != 0; 1305 cabData[currCabId].F28 = (c & NceCmdStationMemory.FUNC_H_F28) != 0; 1306 } 1307 1308 private void processAiuData(int currCabId, int[] ptr) { 1309 cabData[currCabId].F1 = (ptr[1] & 0x01) == 0; 1310 cabData[currCabId].F2 = (ptr[1] & 0x02) == 0; 1311 cabData[currCabId].F3 = (ptr[1] & 0x04) == 0; 1312 cabData[currCabId].F4 = (ptr[1] & 0x08) == 0; 1313 cabData[currCabId].F5 = (ptr[1] & 0x10) == 0; 1314 cabData[currCabId].F6 = (ptr[1] & 0x20) == 0; 1315 cabData[currCabId].F7 = (ptr[1] & 0x40) == 0; 1316 cabData[currCabId].F8 = (ptr[1] & 0x80) == 0; 1317 cabData[currCabId].F9 = (ptr[0] & 0x01) == 0; 1318 cabData[currCabId].F10 = (ptr[0] & 0x02) == 0; 1319 cabData[currCabId].F11 = (ptr[0] & 0x04) == 0; 1320 cabData[currCabId].F12 = (ptr[0] & 0x08) == 0; 1321 cabData[currCabId].F13 = (ptr[0] & 0x10) == 0; 1322 cabData[currCabId].F14 = (ptr[0] & 0x20) == 0; 1323 } 1324 1325 // puts the thread to sleep while we wait for the read CS memory to complete 1326 private boolean waitNce() { 1327 int count = 100; 1328 log.debug("Going to sleep"); 1329 while (waiting > 0) { 1330 synchronized (this) { 1331 try { 1332 wait(100); 1333 } catch (InterruptedException e) { 1334 //nothing to see here, move along 1335 } 1336 } 1337 count--; 1338 if (count < 0) { 1339 textStatus.setText(Bundle.getMessage("ErrorTitle")); 1340 return false; 1341 } 1342 } 1343 log.debug("awake!"); 1344 return true; 1345 } 1346 1347 @Override 1348 public void message(NceMessage m) { 1349 } // ignore replies 1350 1351 // response from read 1352 int recChar = 0; 1353 int[] recChars = new int[16]; 1354 1355 @SuppressFBWarnings(value = "NN_NAKED_NOTIFY", justification = "Thread wait from main transfer loop") 1356 @Override 1357 public void reply(NceReply r) { 1358 log.debug("Receive character"); 1359 if (waiting <= 0) { 1360 log.error("unexpected response. Len: {} code: {}", r.getNumDataElements(), r.getElement(0)); 1361 return; 1362 } 1363 waiting--; 1364 if (r.getNumDataElements() != replyLen) { 1365 textStatus.setText(Bundle.getMessage("ErrorTitle")); 1366 return; 1367 } 1368 // Read one byte 1369 if (replyLen == NceMessage.REPLY_1) { 1370 // Looking for proper response 1371 recChar = r.getElement(0); 1372 } 1373 // Read two byte 1374 if (replyLen == NceMessage.REPLY_2) { 1375 // Looking for proper response 1376 for (int i = 0; i < NceMessage.REPLY_2; i++) { 1377 recChars[i] = r.getElement(i); 1378 } 1379 } 1380 // Read four byte 1381 if (replyLen == NceMessage.REPLY_4) { 1382 // Looking for proper response 1383 for (int i = 0; i < NceMessage.REPLY_4; i++) { 1384 recChars[i] = r.getElement(i); 1385 } 1386 } 1387 // Read 16 bytes 1388 if (replyLen == NceMessage.REPLY_16) { 1389 // Looking for proper response 1390 for (int i = 0; i < NceMessage.REPLY_16; i++) { 1391 recChars[i] = r.getElement(i); 1392 } 1393 } 1394 // wake up thread 1395 synchronized (this) { 1396 notify(); 1397 } 1398 } 1399 1400 // Write 1 byte of NCE cab memory 1401 private void writeCabMemory1(int cabNum, int offset, int value) { 1402 int nceCabAddr = getNceCabAddr(cabNum, offset); 1403 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1404 waiting++; 1405 byte[] bl = NceBinaryCommand.accMemoryWrite1(nceCabAddr, (byte) value); 1406 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_1); 1407 tc.sendNceMessage(m, this); 1408 } 1409 1410 // Reads 1 byte of NCE cab memory 1411 private void readCabMemory1(int cabNum, int offset) { 1412 int nceCabAddr = getNceCabAddr(cabNum, offset); 1413 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1414 waiting++; 1415 byte[] bl = NceBinaryCommand.accMemoryRead1(nceCabAddr); 1416 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_1); 1417 tc.sendNceMessage(m, this); 1418 } 1419 1420 // Reads 16 bytes of NCE cab memory 1421 private void readCabMemory16(int cabNum, int offset) { 1422 int nceCabAddr = getNceCabAddr(cabNum, offset); 1423 replyLen = NceMessage.REPLY_16; // Expect 16 byte response 1424 waiting++; 1425 byte[] bl = NceBinaryCommand.accMemoryRead(nceCabAddr); 1426 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_16); 1427 tc.sendNceMessage(m, this); 1428 } 1429 1430 // get address from cab id and offset 1431 private int getNceCabAddr(int cabNum, int offset) { 1432 int nceCabAddr; 1433 if (cabNum <= maxCabNum) { 1434 nceCabAddr = (cabNum * tc.csm.getCabSize()) + tc.csm.getCabAddr() + offset; 1435 } else { 1436 nceCabAddr = tc.csm.getCabAddr() + offset; 1437 } 1438 return nceCabAddr; 1439 } 1440 1441 // USB set cab memory pointer 1442 private void setUsbCabMemoryPointer(int cab, int offset) { 1443 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1444 waiting++; 1445 byte[] bl = NceBinaryCommand.usbMemoryPointer(cab, offset); 1446 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_1); 1447 tc.sendNceMessage(m, this); 1448 } 1449 1450 // USB Read N bytes of NCE cab memory 1451 private void readUsbCabMemoryN(int num) { 1452 switch (num) { 1453 case 1: 1454 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1455 break; 1456 case 2: 1457 replyLen = NceMessage.REPLY_2; // Expect 2 byte response 1458 break; 1459 case 4: 1460 replyLen = NceMessage.REPLY_4; // Expect 4 byte response 1461 break; 1462 default: 1463 log.error("Invalid usb read byte count"); 1464 return; 1465 } 1466 waiting++; 1467 byte[] bl = NceBinaryCommand.usbMemoryRead((byte) num); 1468 NceMessage m = NceMessage.createBinaryMessage(tc, bl, replyLen); 1469 tc.sendNceMessage(m, this); 1470 } 1471 1472 // USB Write 1 byte of NCE cab memory 1473 private void writeUsbCabMemory1(int value) { 1474 replyLen = NceMessage.REPLY_1; // Expect 1 byte response 1475 waiting++; 1476 byte[] bl = NceBinaryCommand.usbMemoryWrite1((byte) value); 1477 NceMessage m = NceMessage.createBinaryMessage(tc, bl, NceMessage.REPLY_1); 1478 tc.sendNceMessage(m, this); 1479 } 1480 1481 // USB Read AIU 1482 private void readAiuData(int cabId) { 1483 replyLen = NceMessage.REPLY_2; // Expect 2 byte response 1484 waiting++; 1485 byte[] bl = NceBinaryCommand.accAiu2Read(cabId); 1486 NceMessage m = NceMessage.createBinaryMessage(tc, bl, replyLen); 1487 tc.sendNceMessage(m, this); 1488 } 1489 1490 protected void addItem(JPanel p, JComponent c, int x, int y) { 1491 GridBagConstraints gc = new GridBagConstraints(); 1492 gc.gridx = x; 1493 gc.gridy = y; 1494 gc.weightx = 100.0; 1495 gc.weighty = 100.0; 1496 p.add(c, gc); 1497 } 1498 1499 protected void addItemLeft(JPanel p, JComponent c, int x, int y) { 1500 GridBagConstraints gc = new GridBagConstraints(); 1501 gc.gridx = x; 1502 gc.gridy = y; 1503 gc.weightx = 100.0; 1504 gc.weighty = 100.0; 1505 gc.anchor = GridBagConstraints.WEST; 1506 p.add(c, gc); 1507 } 1508 1509 protected void addItemTop(JPanel p, JComponent c, int x, int y) { 1510 GridBagConstraints gc = new GridBagConstraints(); 1511 gc.gridx = x; 1512 gc.gridy = y; 1513 gc.weightx = 100.0; 1514 gc.weighty = 100.0; 1515 gc.anchor = GridBagConstraints.NORTH; 1516 p.add(c, gc); 1517 } 1518 1519 private void addButtonAction(JButton b) { 1520 b.addActionListener(new java.awt.event.ActionListener() { 1521 @Override 1522 public void actionPerformed(java.awt.event.ActionEvent e) { 1523 buttonActionPerformed(e); 1524 } 1525 }); 1526 } 1527 1528 private void addCheckBoxAction(JCheckBox b) { 1529 b.addActionListener(new java.awt.event.ActionListener() { 1530 @Override 1531 public void actionPerformed(java.awt.event.ActionEvent e) { 1532 checkBoxActionPerformed(e); 1533 } 1534 }); 1535 } 1536 1537 void setColumnPurgeButton(JTable table, int column) { 1538 TableColumnModel tcm = table.getColumnModel(); 1539 // install the button renderers & editors in this column 1540 ButtonRenderer buttonRenderer = new ButtonRenderer(); 1541 tcm.getColumn(column).setCellRenderer(buttonRenderer); 1542 TableCellEditor buttonEditor = new ButtonEditor(new JButton(Bundle.getMessage("ButtonPurgeCab"))); 1543 tcm.getColumn(column).setCellEditor(buttonEditor); 1544 // ensure the table rows, columns have enough room for buttons 1545 table.setRowHeight(new JButton(" " + cabModel.getValueAt(1, column)).getPreferredSize().height); 1546 table.getColumnModel().getColumn(column) 1547 .setPreferredWidth(new JButton(Bundle.getMessage("ButtonPurgeCab")).getPreferredSize().width + 1); 1548 } 1549 1550 @Override 1551 public void dispose() { 1552 cabModel = null; 1553 cabData = null; 1554 if (autoRefreshThread != null) { 1555 autoRefreshThread.interrupt(); 1556 } 1557 super.dispose(); 1558 } 1559 1560 class NceCabTableModel extends AbstractTableModel { 1561 1562 DataRow[] cabData; 1563 1564 NceCabTableModel(DataRow[] cabDataPtr) { 1565 this.cabData = cabDataPtr; 1566 } 1567 1568 private final String[] columnNames1LineText = { 1569 Bundle.getMessage("ColHeaderCabId"), 1570 Bundle.getMessage("ColHeaderType"), 1571 Bundle.getMessage("ColHeaderPurge"), 1572 Bundle.getMessage("ColHeaderLongShort"), 1573 Bundle.getMessage("ColHeaderLoco"), 1574 Bundle.getMessage("ColHeaderSpeed"), 1575 Bundle.getMessage("ColHeaderDir"), 1576 Bundle.getMessage("ColHeaderMode"), 1577 Bundle.getMessage("ColHeaderConsist"), 1578 Bundle.getMessage("ColHeaderConsistPos"), 1579 Bundle.getMessage("ColHeaderF0"), 1580 Bundle.getMessage("ColHeaderF1"), 1581 Bundle.getMessage("ColHeaderF2"), 1582 Bundle.getMessage("ColHeaderF3"), 1583 Bundle.getMessage("ColHeaderF4"), 1584 Bundle.getMessage("ColHeaderF5"), 1585 Bundle.getMessage("ColHeaderF6"), 1586 Bundle.getMessage("ColHeaderF7"), 1587 Bundle.getMessage("ColHeaderF8"), 1588 Bundle.getMessage("ColHeaderF9"), 1589 Bundle.getMessage("ColHeaderF10"), 1590 Bundle.getMessage("ColHeaderF11"), 1591 Bundle.getMessage("ColHeaderF12"), 1592 Bundle.getMessage("ColHeaderF13"), 1593 Bundle.getMessage("ColHeaderF14"), 1594 Bundle.getMessage("ColHeaderF15"), 1595 Bundle.getMessage("ColHeaderF16"), 1596 Bundle.getMessage("ColHeaderF17"), 1597 Bundle.getMessage("ColHeaderF18"), 1598 Bundle.getMessage("ColHeaderF19"), 1599 Bundle.getMessage("ColHeaderF20"), 1600 Bundle.getMessage("ColHeaderF21"), 1601 Bundle.getMessage("ColHeaderF22"), 1602 Bundle.getMessage("ColHeaderF23"), 1603 Bundle.getMessage("ColHeaderF24"), 1604 Bundle.getMessage("ColHeaderF25"), 1605 Bundle.getMessage("ColHeaderF26"), 1606 Bundle.getMessage("ColHeaderF27"), 1607 Bundle.getMessage("ColHeaderF28"), 1608 Bundle.getMessage("ColHeaderText1"), 1609 Bundle.getMessage("ColHeaderText2"), 1610 Bundle.getMessage("ColHeaderLastUsed") 1611 }; 1612 1613 private boolean showAllCabs = false; 1614 private boolean showAllFunctions = false; 1615 private boolean showCabDisplay = false; 1616 1617 @Override 1618 public int getColumnCount() { 1619 return columnNames1LineText.length; 1620 } 1621 1622 @Override 1623 public int getRowCount() { 1624 int activeRows = 0; 1625 if (!getShowAllCabs()) { 1626 for (int i = minCabNum; i <= maxCabNum; i++) { 1627 if ((cabFlag1Array[i] 1628 & NceCmdStationMemory.FLAGS1_MASK_CABISACTIVE) == NceCmdStationMemory.FLAGS1_CABISACTIVE) { 1629 activeRows++; 1630 } 1631 } 1632 } else { 1633 activeRows = maxCabNum - minCabNum + 1; 1634 } 1635 return activeRows; 1636 } 1637 1638 /** 1639 * Return cabId for row number. 1640 * 1641 * @param row row for cab information 1642 * @return cab id 1643 */ 1644 protected int getCabIdForRow(int row) { 1645 int activeRows = -1; 1646 if (!getShowAllCabs()) { 1647 for (int i = minCabNum; i <= maxCabNum; i++) { 1648 if ((cabFlag1Array[i] 1649 & NceCmdStationMemory.FLAGS1_MASK_CABISACTIVE) == NceCmdStationMemory.FLAGS1_CABISACTIVE) { 1650 activeRows++; 1651 if (row == activeRows) { 1652 return i; 1653 } 1654 } 1655 } 1656 return -1; 1657 } else { 1658 return row + minCabNum; 1659 } 1660 } 1661 1662 @Override 1663 public String getColumnName(int col) { 1664 return columnNames1LineText[col]; 1665 } 1666 1667 @Override 1668 public Object getValueAt(int row, int col) { 1669 int cabId = getCabIdForRow(row); 1670 if (cabId == -1 && !getShowAllCabs()) { 1671 return null; // no active rows 1672 } 1673 if (cabId < minCabNum || cabId > maxCabNum) { 1674 log.error("getCabIdForRow({}) returned {}", row, cabId); 1675 return null; 1676 } 1677 DataRow r = cabData[cabId]; 1678 boolean activeCab = (cabFlag1Array[cabId] 1679 & NceCmdStationMemory.FLAGS1_MASK_CABISACTIVE) == NceCmdStationMemory.FLAGS1_CABISACTIVE; 1680 if (r == null) { 1681 return null; 1682 } 1683 if (!activeCab && (col != 0)) { 1684 return null; 1685 } 1686 switch (col) { 1687 case 0: 1688 return r.cabNumber; 1689 case 1: 1690 return r.cabType; 1691 case 2: 1692 return Bundle.getMessage("ButtonPurgeCab"); 1693 case 3: 1694 return r.longShort; 1695 case 4: 1696 return r.locoAddress; 1697 case 5: 1698 return r.locoSpeed; 1699 case 6: 1700 return r.locoDir; 1701 case 7: 1702 return r.mode; 1703 case 8: 1704 return r.consist; 1705 case 9: 1706 return r.consistPos; 1707 case 10: 1708 return r.F0; 1709 case 11: 1710 return r.F1; 1711 case 12: 1712 return r.F2; 1713 case 13: 1714 return r.F3; 1715 case 14: 1716 return r.F4; 1717 case 15: 1718 return r.F5; 1719 case 16: 1720 return r.F6; 1721 case 17: 1722 return r.F7; 1723 case 18: 1724 return r.F8; 1725 case 19: 1726 return r.F9; 1727 case 20: 1728 return r.F10; 1729 case 21: 1730 return r.F11; 1731 case 22: 1732 return r.F12; 1733 case 23: 1734 return r.F13; 1735 case 24: 1736 return r.F14; 1737 case 25: 1738 return r.F15; 1739 case 26: 1740 return r.F16; 1741 case 27: 1742 return r.F17; 1743 case 28: 1744 return r.F18; 1745 case 29: 1746 return r.F19; 1747 case 30: 1748 return r.F20; 1749 case 31: 1750 return r.F21; 1751 case 32: 1752 return r.F22; 1753 case 33: 1754 return r.F23; 1755 case 34: 1756 return r.F24; 1757 case 35: 1758 return r.F25; 1759 case 36: 1760 return r.F26; 1761 case 37: 1762 return r.F27; 1763 case 38: 1764 return r.F28; 1765 case 39: 1766 return r.text1; 1767 case 40: 1768 return r.text2; 1769 case 41: 1770 return r.lastChange; 1771 default: 1772 log.error("Unhandled column number: {}", col); 1773 break; 1774 } 1775 return null; 1776 } 1777 1778 @Override 1779 public void setValueAt(Object value, int row, int col) { 1780 int cabId = getCabIdForRow(row); 1781 if (col == 2) { 1782 purgeCab(cabId); 1783 } 1784 } 1785 1786 @Override 1787 public Class<?> getColumnClass(int c) { 1788 if (c == 0 || c == 4 || c == 5 || c == 8) { 1789 return Integer.class; 1790 } else if (c == 1 || c == 3 || c == 6 || c == 7 || c == 9 || (c >= 39 && c <= 41)) { 1791 return String.class; 1792 } else if (c >= 10 && c <= 38) { 1793 return Boolean.class; 1794 } else if (c == 2) { 1795 return JButton.class; 1796 } else { 1797 return null; 1798 } 1799 } 1800 1801 public int getPreferredWidth(int col) { 1802 int width = new JLabel(columnNames1LineText[col]).getPreferredSize().width + 10; 1803 // log.debug("Column {} width {} name {}", col, width, columnNames1LineText[col]); 1804 return width; 1805 } 1806 1807 @Override 1808 public boolean isCellEditable(int row, int col) { 1809 return col == 2; 1810 } 1811 1812 public boolean getShowAllCabs() { 1813 return this.showAllCabs; 1814 } 1815 1816 public void setShowAllCabs(boolean b) { 1817 this.showAllCabs = b; 1818 } 1819 1820 public boolean getShowAllFunctions() { 1821 return this.showAllFunctions; 1822 } 1823 1824 public void setShowAllFunctions(boolean b) { 1825 this.showAllFunctions = b; 1826 } 1827 1828 public boolean getShowCabDisplay() { 1829 return this.showCabDisplay; 1830 } 1831 1832 public void setShowCabDisplay(boolean b) { 1833 this.showCabDisplay = b; 1834 } 1835 1836 } 1837 1838 /** 1839 * Nested class to create one of these using old-style defaults. 1840 */ 1841 static public class Default extends jmri.jmrix.nce.swing.NceNamedPaneAction { 1842 1843 public Default() { 1844 super("Open NCE Cabs Monitor", 1845 new jmri.util.swing.sdi.JmriJFrameInterface(), 1846 NceShowCabPanel.class.getName(), 1847 jmri.InstanceManager.getDefault(NceSystemConnectionMemo.class)); 1848 } 1849 } 1850 1851 private final static Logger log = LoggerFactory.getLogger(NceShowCabPanel.class); 1852}