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