001package jmri.jmrix.loconet.slotmon; 002 003import java.time.Instant; 004import java.time.ZoneId; 005import java.time.ZonedDateTime; 006import java.time.format.DateTimeFormatter; 007 008import javax.swing.JButton; 009import javax.swing.JCheckBox; 010import javax.swing.JLabel; 011import javax.swing.JTable; 012import javax.swing.JTextField; 013 014import jmri.Throttle; 015import jmri.jmrix.loconet.LnConstants; 016import jmri.jmrix.loconet.LocoNetMessage; 017import jmri.jmrix.loconet.LocoNetSlot; 018import jmri.jmrix.loconet.LocoNetSystemConnectionMemo; 019import jmri.jmrix.loconet.SlotListener; 020import jmri.jmrix.loconet.SlotMapEntry.SlotType; 021import jmri.util.StringUtil; 022import jmri.util.swing.JmriJOptionPane; 023 024/** 025 * Table data model for display of slot manager contents. 026 * 027 * @author Bob Jacobsen Copyright (C) 2001 028 * @author Jeffrey Machacek 2013 029 */ 030public class SlotMonDataModel extends javax.swing.table.AbstractTableModel implements SlotListener { 031 032/** 033 * ColumnNumber 034 * This enum defines the default column order. 035 * F0COLUMN thru F28COLUMN must be kept in a block and in order. 036 */ 037 enum ColumnNumber {SLOTCOLUMN, 038 ESTOPCOLUMN, 039 ADDRCOLUMN, 040 SPDCOLUMN, 041 TYPECOLUMN, 042 STATCOLUMN, 043 LASTUPDATE, 044 DISPCOLUMN, 045 CONSCOLUMN, 046 CONSISTADDRESS, 047 THROTCOLUMN, 048 JMRITHROTTLECOUNT, 049 DIRCOLUMN, 050 F0COLUMN, 051 F1COLUMN, 052 F2COLUMN, 053 F3COLUMN, 054 F4COLUMN, 055 F5COLUMN, 056 F6COLUMN, 057 F7COLUMN, 058 F8COLUMN, 059 F9COLUMN, 060 F10COLUMN, 061 F11COLUMN, 062 F12COLUMN, 063 F13COLUMN, 064 F14COLUMN, 065 F15COLUMN, 066 F16COLUMN, 067 F17COLUMN, 068 F18COLUMN, 069 F19COLUMN, 070 F20COLUMN, 071 F21COLUMN, 072 F22COLUMN, 073 F23COLUMN, 074 F24COLUMN, 075 F25COLUMN, 076 F26COLUMN, 077 F27COLUMN, 078 F28COLUMN, 079 MAXCOLUMN} 080 081 private int numRows = 128; 082 private int columns; 083 084 private final transient LocoNetSystemConnectionMemo memo; 085 086 SlotMonDataModel(int row, LocoNetSystemConnectionMemo memo) { 087 this.memo = memo; 088 089 // number of columns 090 this.columns = ColumnNumber.MAXCOLUMN.ordinal(); 091 // set number of rows; 092 numRows = row; 093 094 // connect to SlotManager for updates 095 memo.getSlotManager().addSlotListener(SlotMonDataModel.this); 096 097 // start update process 098 memo.getSlotManager().update(); 099 } 100 101 /** 102 * Forces a refresh of the slots 103 */ 104 public void refreshSlots() { 105 memo.getSlotManager().update(); 106 } 107 108 /** 109 * Return the number of rows to be displayed. This can vary depending on 110 * whether only active rows are displayed, and whether the system slots 111 * should be displayed. 112 * <p> 113 * This should probably use a local cache instead of counting/searching each 114 * time. 115 * 116 * @return the number of rows 117 */ 118 @Override 119 public int getRowCount() { 120 return numRows; 121 } 122 123 @Override 124 public int getColumnCount() { 125 return columns; 126 } 127 128 @Override 129 public String getColumnName(int col) { 130 ColumnNumber colorder = ColumnNumber.values()[col]; 131 switch (colorder) { 132 case SLOTCOLUMN: 133 return Bundle.getMessage("SlotCol"); 134 case ESTOPCOLUMN: 135 return Bundle.getMessage("ButtonEstop"); // no heading, as button is clear 136 case ADDRCOLUMN: 137 return Bundle.getMessage("AddressCol"); 138 case SPDCOLUMN: 139 return Bundle.getMessage("SpeedCol"); 140 case TYPECOLUMN: 141 return Bundle.getMessage("StatusCol"); 142 case STATCOLUMN: 143 return Bundle.getMessage("UseCol"); 144 case CONSCOLUMN: 145 return Bundle.getMessage("ConsistedCol"); 146 case CONSISTADDRESS: 147 return Bundle.getMessage("ConsistAddress"); 148 case DIRCOLUMN: 149 return Bundle.getMessage("DirectionCol"); 150 case DISPCOLUMN: 151 return Bundle.getMessage("ButtonRelease"); 152 case F0COLUMN: 153 return Throttle.getFunctionString(0); 154 case F1COLUMN: 155 return Throttle.getFunctionString(1); 156 case F2COLUMN: 157 return Throttle.getFunctionString(2); 158 case F3COLUMN: 159 return Throttle.getFunctionString(3); 160 case F4COLUMN: 161 return Throttle.getFunctionString(4); 162 case F5COLUMN: 163 return Throttle.getFunctionString(5); 164 case F6COLUMN: 165 return Throttle.getFunctionString(6); 166 case F7COLUMN: 167 return Throttle.getFunctionString(7); 168 case F8COLUMN: 169 return Throttle.getFunctionString(8); 170 case F9COLUMN: 171 return Throttle.getFunctionString(9); 172 case F10COLUMN: 173 return Throttle.getFunctionString(10); 174 case F11COLUMN: 175 return Throttle.getFunctionString(11); 176 case F12COLUMN: 177 return Throttle.getFunctionString(12); 178 case F13COLUMN: 179 return Throttle.getFunctionString(13); 180 case F14COLUMN: 181 return Throttle.getFunctionString(14); 182 case F15COLUMN: 183 return Throttle.getFunctionString(15); 184 case F16COLUMN: 185 return Throttle.getFunctionString(16); 186 case F17COLUMN: 187 return Throttle.getFunctionString(17); 188 case F18COLUMN: 189 return Throttle.getFunctionString(18); 190 case F19COLUMN: 191 return Throttle.getFunctionString(19); 192 case F20COLUMN: 193 return Throttle.getFunctionString(20); 194 case F21COLUMN: 195 return Throttle.getFunctionString(21); 196 case F22COLUMN: 197 return Throttle.getFunctionString(22); 198 case F23COLUMN: 199 return Throttle.getFunctionString(23); 200 case F24COLUMN: 201 return Throttle.getFunctionString(24); 202 case F25COLUMN: 203 return Throttle.getFunctionString(25); 204 case F26COLUMN: 205 return Throttle.getFunctionString(26); 206 case F27COLUMN: 207 return Throttle.getFunctionString(27); 208 case F28COLUMN: 209 return Throttle.getFunctionString(28); 210 case THROTCOLUMN: 211 return Bundle.getMessage("ThrottleIDCol"); 212 case JMRITHROTTLECOUNT: 213 return Bundle.getMessage("JMRIThrottleCount"); 214 case LASTUPDATE: 215 return Bundle.getMessage("LastUpdate"); 216 default: 217 return "unknown"; // NOI18N 218 } 219 } 220 221 @Override 222 public Class<?> getColumnClass(int col) { 223 ColumnNumber colorder = ColumnNumber.values()[col]; 224 switch (colorder) { 225 case SLOTCOLUMN: 226 case ADDRCOLUMN: 227 case CONSISTADDRESS: 228 case JMRITHROTTLECOUNT: 229 return Integer.class; 230 case SPDCOLUMN: 231 case TYPECOLUMN: 232 case STATCOLUMN: 233 case CONSCOLUMN: 234 case DIRCOLUMN: 235 case THROTCOLUMN: 236 case LASTUPDATE: 237 return String.class; 238 case ESTOPCOLUMN: 239 case DISPCOLUMN: 240 return JButton.class; 241 case F0COLUMN: 242 case F1COLUMN: 243 case F2COLUMN: 244 case F3COLUMN: 245 case F4COLUMN: 246 case F5COLUMN: 247 case F6COLUMN: 248 case F7COLUMN: 249 case F8COLUMN: 250 case F9COLUMN: 251 case F10COLUMN: 252 case F11COLUMN: 253 case F12COLUMN: 254 case F13COLUMN: 255 case F14COLUMN: 256 case F15COLUMN: 257 case F16COLUMN: 258 case F17COLUMN: 259 case F18COLUMN: 260 case F19COLUMN: 261 case F20COLUMN: 262 case F21COLUMN: 263 case F22COLUMN: 264 case F23COLUMN: 265 case F24COLUMN: 266 case F25COLUMN: 267 case F26COLUMN: 268 case F27COLUMN: 269 case F28COLUMN: 270 return Boolean.class; 271 default: 272 return null; 273 } 274 } 275 276 @Override 277 public boolean isCellEditable(int row, int col) { 278 LocoNetSlot s = memo.getSlotManager().slot(row); 279 ColumnNumber colorder = ColumnNumber.values()[col]; 280 switch (colorder) { 281 case ESTOPCOLUMN: 282 case DISPCOLUMN: 283 case F0COLUMN: 284 case F1COLUMN: 285 case F2COLUMN: 286 case F3COLUMN: 287 case F4COLUMN: 288 case F5COLUMN: 289 case F6COLUMN: 290 case F7COLUMN: 291 case F8COLUMN: 292 case F9COLUMN: 293 case F10COLUMN: 294 case F11COLUMN: 295 case F12COLUMN: 296 case F13COLUMN: 297 case F14COLUMN: 298 case F15COLUMN: 299 case F16COLUMN: 300 case F17COLUMN: 301 case F18COLUMN: 302 case F19COLUMN: 303 case F20COLUMN: 304 case F21COLUMN: 305 case F22COLUMN: 306 case F23COLUMN: 307 case F24COLUMN: 308 case F25COLUMN: 309 case F26COLUMN: 310 case F27COLUMN: 311 case F28COLUMN: 312 // only loco slots to be marked writeable only, system slot are read only 313 return !s.isSystemSlot(); 314 default: 315 return false; 316 } 317 } 318 319 @Override 320 public Object getValueAt(int row, int col) { 321 LocoNetSlot s = memo.getSlotManager().slot(row); 322 String t; 323 if (s == null) { 324 log.error("slot pointer was null for slot row: {} col: {}", row, col); 325 return null; 326 } 327 328 ColumnNumber colorder = ColumnNumber.values()[col]; 329 switch (colorder) { 330 case SLOTCOLUMN: // slot number 331 return row; 332 case ESTOPCOLUMN: 333 return Bundle.getMessage("ButtonEstop"); // will be name of button in default GUI 334 case ADDRCOLUMN: 335 return s.locoAddr(); 336 case SPDCOLUMN: 337 switch (s.consistStatus()) { 338 case LnConstants.CONSIST_TOP: 339 case LnConstants.CONSIST_NO: 340 if (s.speed() == 1) { 341 t = "(estop) 1"; 342 } else { 343 t = " " + s.speed(); 344 } 345 return t.substring(t.length() - 9, t.length()); // 9 comes from length of the "(estop)" prefix 346 case LnConstants.CONSIST_MID: 347 case LnConstants.CONSIST_SUB: 348 return Bundle.getMessage("SlotSpeedConsist"); 349 default: 350 return Bundle.getMessage("StateError"); 351 } 352 case TYPECOLUMN: 353 switch (s.decoderType()) { 354 case LnConstants.DEC_MODE_128A: 355 return "128 step adv"; 356 case LnConstants.DEC_MODE_28A: 357 return " 28 step adv"; 358 case LnConstants.DEC_MODE_128: 359 return "128 step"; 360 case LnConstants.DEC_MODE_14: 361 return " 14 step"; 362 case LnConstants.DEC_MODE_28TRI: 363 return " 28 step trinary"; 364 case LnConstants.DEC_MODE_28: 365 return " 28 step"; 366 default: 367 return Bundle.getMessage("StateUnknown"); 368 } 369 case STATCOLUMN: 370 switch (s.slotStatus()) { 371 case LnConstants.LOCO_IN_USE: 372 return Bundle.getMessage("StateInUse"); 373 case LnConstants.LOCO_IDLE: 374 return Bundle.getMessage("StateIdle"); 375 case LnConstants.LOCO_COMMON: 376 return Bundle.getMessage("StateCommon"); 377 case LnConstants.LOCO_FREE: 378 return Bundle.getMessage("StateFree"); 379 default: 380 return Bundle.getMessage("StateError"); 381 } 382 case CONSCOLUMN: 383 if (s.isSystemSlot()) { 384 // makes no sense to decode 385 return Bundle.getMessage("SlotDataNotApplicable"); 386 } 387 switch (s.consistStatus()) { 388 case LnConstants.CONSIST_MID: 389 if (s.getProtocol() == LnConstants.LOCONETPROTOCOL_TWO) { 390 return Bundle.getMessage("SlotConsistMidX", s.getLeadSlot()); 391 } 392 t = Bundle.getMessage("SlotConsistMidX", s.speed()); 393 return t; 394 case LnConstants.CONSIST_TOP: 395 return Bundle.getMessage("SlotConsistTop"); 396 case LnConstants.CONSIST_SUB: 397 if (s.getProtocol() == LnConstants.LOCONETPROTOCOL_TWO) { 398 return Bundle.getMessage("SlotConsistSubX", s.getLeadSlot()); 399 } 400 t = Bundle.getMessage("SlotConsistSubX", s.speed()); 401 return t; 402 case LnConstants.CONSIST_NO: 403 return Bundle.getMessage("SlotConsistNone"); 404 default: 405 return Bundle.getMessage("StateError"); 406 } 407 case CONSISTADDRESS: 408 if (s.isSystemSlot()) { 409 // makes no sense to decode flag to rendered NA 410 return -1; 411 } 412 switch (s.consistStatus()) { 413 case LnConstants.CONSIST_TOP: 414 return s.locoAddr(); 415 case LnConstants.CONSIST_MID: 416 case LnConstants.CONSIST_SUB: 417 if (s.getProtocol() == LnConstants.LOCONETPROTOCOL_TWO) { 418 return memo.getSlotManager().slot(s.getLeadSlot()).locoAddr(); 419 } 420 return memo.getSlotManager().slot(s.speed()).locoAddr(); 421 case LnConstants.CONSIST_NO: 422 return 0; 423 default: 424 return 0; 425 } 426 case DISPCOLUMN: 427 return Bundle.getMessage("ButtonRelease"); // will be name of button in default GUI 428 case DIRCOLUMN: 429 return s.isForward() ? Bundle.getMessage("DirColForward") : Bundle.getMessage("DirColReverse"); 430 case F0COLUMN: 431 return s.isF0(); 432 case F1COLUMN: 433 return s.isF1(); 434 case F2COLUMN: 435 return s.isF2(); 436 case F3COLUMN: 437 return s.isF3(); 438 case F4COLUMN: 439 return s.isF4(); 440 case F5COLUMN: 441 return s.isF5(); 442 case F6COLUMN: 443 return s.isF6(); 444 case F7COLUMN: 445 return s.isF7(); 446 case F8COLUMN: 447 return s.isF8(); 448 case F9COLUMN: 449 return s.isF9(); 450 case F10COLUMN: 451 return s.isF10(); 452 case F11COLUMN: 453 return s.isF11(); 454 case F12COLUMN: 455 return s.isF12(); 456 case F13COLUMN: 457 return s.isF13(); 458 case F14COLUMN: 459 return s.isF14(); 460 case F15COLUMN: 461 return s.isF15(); 462 case F16COLUMN: 463 return s.isF16(); 464 case F17COLUMN: 465 return s.isF17(); 466 case F18COLUMN: 467 return s.isF18(); 468 case F19COLUMN: 469 return s.isF19(); 470 case F20COLUMN: 471 return s.isF20(); 472 case F21COLUMN: 473 return s.isF21(); 474 case F22COLUMN: 475 return s.isF22(); 476 case F23COLUMN: 477 return s.isF23(); 478 case F24COLUMN: 479 return s.isF24(); 480 case F25COLUMN: 481 return s.isF25(); 482 case F26COLUMN: 483 return s.isF26(); 484 case F27COLUMN: 485 return s.isF27(); 486 case F28COLUMN: 487 return s.isF28(); 488 case THROTCOLUMN: 489 int upper = (s.id() >> 7) & 0x7F; 490 int lower = s.id() & 0x7F; 491 return StringUtil.twoHexFromInt(upper) + " " + StringUtil.twoHexFromInt(lower); 492 case JMRITHROTTLECOUNT: 493 return(memo.getThrottleManager().getThrottleUsageCount(s.locoAddr())); 494 case LASTUPDATE: 495 Instant instant = Instant.ofEpochMilli(s.getLastUpdateTime()); 496 ZonedDateTime dateTime = instant.atZone(ZoneId.systemDefault()); 497 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss"); 498 String formattedDateTime = dateTime.format(formatter); 499 if (s.getSlowScanStartedAt() != 0) { 500 formattedDateTime=Bundle.getMessage("LastUpdateSlowScan",formattedDateTime); 501 } 502 return formattedDateTime; 503 default: 504 log.error("internal state inconsistent with table requst for {} {}", row, col); 505 return null; 506 } 507 } 508 509 public int getPreferredWidth(int col) { 510 ColumnNumber colorder = ColumnNumber.values()[col]; 511 switch (colorder) { 512 case SLOTCOLUMN: 513 case JMRITHROTTLECOUNT: 514 return new JTextField(3).getPreferredSize().width; 515 case ESTOPCOLUMN: 516 return new JButton(Bundle.getMessage("ButtonEstop")).getPreferredSize().width; 517 case ADDRCOLUMN: 518 return new JTextField(5).getPreferredSize().width; 519 case SPDCOLUMN: 520 case STATCOLUMN: 521 return new JTextField(6).getPreferredSize().width; 522 case TYPECOLUMN: 523 return new JTextField(12).getPreferredSize().width; 524 case CONSCOLUMN: 525 return new JTextField(4).getPreferredSize().width; 526 case CONSISTADDRESS: 527 return new JTextField(" 0000 ").getPreferredSize().width; 528 case DIRCOLUMN: 529 // the length of an empty JTextField works on more GUIs 530 int m = Math.max(Bundle.getMessage("DirColForward").length(), Bundle.getMessage("DirColReverse").length()); 531 m = Math.max(m, Bundle.getMessage("DirectionCol").length()); 532 return new JTextField(m).getPreferredSize().width; 533 case DISPCOLUMN: 534 return new JButton(Bundle.getMessage("ButtonRelease")).getPreferredSize().width; 535 case THROTCOLUMN: 536 return new JTextField(7).getPreferredSize().width; 537 case LASTUPDATE: 538 return new JTextField("SS HH:MM:SS ").getPreferredSize().width; 539 case F0COLUMN: 540 case F1COLUMN: 541 case F2COLUMN: 542 case F3COLUMN: 543 case F4COLUMN: 544 case F5COLUMN: 545 case F6COLUMN: 546 case F7COLUMN: 547 case F8COLUMN: 548 case F9COLUMN: 549 case F10COLUMN: 550 case F11COLUMN: 551 case F12COLUMN: 552 case F13COLUMN: 553 case F14COLUMN: 554 case F15COLUMN: 555 case F16COLUMN: 556 case F17COLUMN: 557 case F18COLUMN: 558 case F19COLUMN: 559 case F20COLUMN: 560 case F21COLUMN: 561 case F22COLUMN: 562 case F23COLUMN: 563 case F24COLUMN: 564 case F25COLUMN: 565 case F26COLUMN: 566 case F27COLUMN: 567 case F28COLUMN: 568 // to show checkboxes and Text 569 return Math.max(new JCheckBox().getPreferredSize().width, new JTextField("F99").getPreferredSize().width); 570 default: 571 return new JLabel(" <unknown> ").getPreferredSize().width; // NOI18N 572 } 573 } 574 575 @Override 576 public void setValueAt(Object value, int row, int col) { 577 LocoNetMessage msg; 578 LocoNetSlot s = memo.getSlotManager().slot(row); 579 if (s == null) { 580 log.error("slot pointer was null for slot row: {} col: {}", row, col); 581 return; 582 } 583 584 ColumnNumber colorder = ColumnNumber.values()[col]; 585 switch (colorder) { 586 case ESTOPCOLUMN: 587 log.debug("Start estop in slot {}", row); 588 if ((s.consistStatus() == LnConstants.CONSIST_SUB) 589 || (s.consistStatus() == LnConstants.CONSIST_MID)) { 590 Object[] options = {Bundle.getMessage("ButtonOK"), Bundle.getMessage("ButtonCancel")}; 591 int result = JmriJOptionPane.showOptionDialog(null, 592 Bundle.getMessage("SlotEstopWarning"), 593 Bundle.getMessage("WarningTitle"), 594 JmriJOptionPane.DEFAULT_OPTION, 595 JmriJOptionPane.WARNING_MESSAGE, 596 null, options, options[1]); 597 if ( result != 0 ) { // not array position 0 ButtonOK 598 return; 599 } 600 } 601 msg = s.writeSpeed(1); 602 memo.getLnTrafficController().sendLocoNetMessage(msg); 603 fireTableRowsUpdated(row, row); 604 break; 605 case F0COLUMN: 606 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 607 sendFunctionGroup1(s, col, row); 608 } else { 609 sendExpFunctionGroup1(s, col, row); 610 } 611 fireTableRowsUpdated(row, row); 612 break; 613 case F1COLUMN: 614 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 615 sendFunctionGroup1(s, col, row); 616 } else { 617 sendExpFunctionGroup1(s, col, row); 618 } 619 fireTableRowsUpdated(row, row); 620 break; 621 case F2COLUMN: 622 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 623 sendFunctionGroup1(s, col, row); 624 } else { 625 sendExpFunctionGroup1(s, col, row); 626 } 627 fireTableRowsUpdated(row, row); 628 break; 629 case F3COLUMN: 630 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 631 sendFunctionGroup1(s, col, row); 632 } else { 633 sendExpFunctionGroup1(s, col, row); 634 } 635 fireTableRowsUpdated(row, row); 636 break; 637 case F4COLUMN: 638 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 639 sendFunctionGroup1(s, col, row); 640 } else { 641 sendExpFunctionGroup1(s, col, row); 642 } 643 fireTableRowsUpdated(row, row); 644 break; 645 case F5COLUMN: 646 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 647 sendFunctionGroup2(s, col, row); 648 } else { 649 sendExpFunctionGroup1(s, col, row); 650 } 651 fireTableRowsUpdated(row, row); 652 break; 653 case F6COLUMN: 654 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 655 sendFunctionGroup2(s, col, row); 656 } else { 657 sendExpFunctionGroup1(s, col, row); 658 } 659 fireTableRowsUpdated(row, row); 660 break; 661 case F7COLUMN: 662 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 663 sendFunctionGroup2(s, col, row); 664 } else { 665 sendExpFunctionGroup2(s, col, row); 666 } 667 fireTableRowsUpdated(row, row); 668 break; 669 case F8COLUMN: 670 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 671 sendFunctionGroup2(s, col, row); 672 } else { 673 sendExpFunctionGroup2(s, col, row); 674 } 675 fireTableRowsUpdated(row, row); 676 break; 677 case F9COLUMN: 678 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 679 sendFunctionGroup3(s, col, row); 680 } else { 681 sendExpFunctionGroup2(s, col, row); 682 } 683 fireTableRowsUpdated(row, row); 684 break; 685 case F10COLUMN: 686 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 687 sendFunctionGroup3(s, col, row); 688 } else { 689 sendExpFunctionGroup2(s, col, row); 690 } 691 fireTableRowsUpdated(row, row); 692 break; 693 case F11COLUMN: 694 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 695 sendFunctionGroup3(s, col, row); 696 } else { 697 sendExpFunctionGroup2(s, col, row); 698 } 699 fireTableRowsUpdated(row, row); 700 break; 701 case F12COLUMN: 702 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 703 sendFunctionGroup3(s, col, row); 704 } else { 705 sendExpFunctionGroup2(s, col, row); 706 } 707 fireTableRowsUpdated(row, row); 708 break; 709 case F13COLUMN: 710 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 711 sendFunctionGroup4(s, col, row); 712 } else { 713 sendExpFunctionGroup2(s, col, row); 714 } 715 fireTableRowsUpdated(row, row); 716 break; 717 case F14COLUMN: 718 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 719 sendFunctionGroup4(s, col, row); 720 } else { 721 sendExpFunctionGroup3(s, col, row); 722 } 723 fireTableRowsUpdated(row, row); 724 break; 725 case F15COLUMN: 726 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 727 sendFunctionGroup4(s, col, row); 728 } else { 729 sendExpFunctionGroup3(s, col, row); 730 } 731 fireTableRowsUpdated(row, row); 732 break; 733 case F16COLUMN: 734 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 735 sendFunctionGroup4(s, col, row); 736 } else { 737 sendExpFunctionGroup3(s, col, row); 738 } 739 fireTableRowsUpdated(row, row); 740 break; 741 case F17COLUMN: 742 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 743 sendFunctionGroup4(s, col, row); 744 } else { 745 sendExpFunctionGroup3(s, col, row); 746 } 747 fireTableRowsUpdated(row, row); 748 break; 749 case F18COLUMN: 750 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 751 sendFunctionGroup4(s, col, row); 752 } else { 753 sendExpFunctionGroup3(s, col, row); 754 } 755 fireTableRowsUpdated(row, row); 756 break; 757 case F19COLUMN: 758 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 759 sendFunctionGroup4(s, col, row); 760 } else { 761 sendExpFunctionGroup3(s, col, row); 762 } 763 fireTableRowsUpdated(row, row); 764 break; 765 case F20COLUMN: 766 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 767 sendFunctionGroup4(s, col, row); 768 } else { 769 sendExpFunctionGroup3(s, col, row); 770 } 771 fireTableRowsUpdated(row, row); 772 break; 773 case F21COLUMN: 774 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 775 sendFunctionGroup5(s, col, row); 776 } else { 777 sendExpFunctionGroup4(s, col, row); 778 } 779 fireTableRowsUpdated(row, row); 780 break; 781 case F22COLUMN: 782 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 783 sendFunctionGroup5(s, col, row); 784 } else { 785 sendExpFunctionGroup4(s, col, row); 786 } 787 fireTableRowsUpdated(row, row); 788 break; 789 case F23COLUMN: 790 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 791 sendFunctionGroup5(s, col, row); 792 } else { 793 sendExpFunctionGroup4(s, col, row); 794 } 795 fireTableRowsUpdated(row, row); 796 break; 797 case F24COLUMN: 798 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 799 sendFunctionGroup5(s, col, row); 800 } else { 801 sendExpFunctionGroup4(s, col, row); 802 } 803 fireTableRowsUpdated(row, row); 804 break; 805 case F25COLUMN: 806 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 807 sendFunctionGroup5(s, col, row); 808 } else { 809 sendExpFunctionGroup4(s, col, row); 810 } 811 fireTableRowsUpdated(row, row); 812 break; 813 case F26COLUMN: 814 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 815 sendFunctionGroup5(s, col, row); 816 } else { 817 sendExpFunctionGroup4(s, col, row); 818 } 819 fireTableRowsUpdated(row, row); 820 break; 821 case F27COLUMN: 822 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 823 sendFunctionGroup5(s, col, row); 824 } else { 825 sendExpFunctionGroup4(s, col, row); 826 } 827 fireTableRowsUpdated(row, row); 828 break; 829 case F28COLUMN: 830 if (s.getProtocol() != LnConstants.LOCONETPROTOCOL_TWO) { 831 sendFunctionGroup5(s, col, row); 832 } else { 833 sendExpFunctionGroup4(s, col, row); 834 } 835 fireTableRowsUpdated(row, row); 836 break; 837 case DISPCOLUMN: 838 log.debug("Start freeing slot {}", row); 839 if (s.slotStatus() != LnConstants.LOCO_FREE) { 840 if (s.consistStatus() != LnConstants.CONSIST_NO) { 841 // Freeing a member takes it out of the consist 842 // entirely (i.e., while the slot is LOCO_FREE, it 843 // still reads the former consist information, but 844 // the next time that loco is selected, it comes 845 // back as CONSIST_NO). Freeing the CONSIST_TOP 846 // will kill the entire consist. 847 Object[] options = {Bundle.getMessage("ButtonOK"), Bundle.getMessage("ButtonCancel")}; 848 int result = JmriJOptionPane.showOptionDialog(null, 849 "Freeing a consist member will destroy the consist.\n\nAre you sure you want to do that?", 850 Bundle.getMessage("WarningTitle"), 851 JmriJOptionPane.DEFAULT_OPTION, 852 JmriJOptionPane.WARNING_MESSAGE, 853 null, options, options[1]); 854 if ( result != 0 ) { // not array position 0, ButtonOK 855 return; 856 } 857 } 858 // send status to free 859 memo.getLnTrafficController().sendLocoNetMessage( 860 s.writeStatus(LnConstants.LOCO_FREE)); 861 } else { 862 log.debug("Slot not in use"); 863 } 864 fireTableRowsUpdated(row, row); 865 break; 866 default: 867 // nothing to do if column not recognized 868 break; 869 } 870 } 871 872 //Added by Jeffrey Machacek, date: 2013 873 //changed 8/22/2013 874 public void clearAllSlots() { 875 int count = getRowCount(); 876 877 for (int row = 0; row < (count - 1); row++) { 878 LocoNetSlot s = memo.getSlotManager().slot(row); 879 880 if (s.getSlotType() == SlotType.LOCO 881 && ((s.slotStatus() != LnConstants.LOCO_IN_USE) && (s.consistStatus() == LnConstants.CONSIST_NO))) { 882 log.debug("Freeing {} from slot {}, old status: {}", s.locoAddr(), s.getSlot(), s.slotStatus()); 883 memo.getLnTrafficController().sendLocoNetMessage( 884 s.writeStatus(LnConstants.LOCO_FREE 885 )); 886 fireTableRowsUpdated(row, row); 887 } 888 count = getRowCount(); 889 } 890 } 891 892 /** 893 * Configure a table to have our standard rows and columns. This is 894 * optional, in that other table formats can use this table model. But we 895 * put it here to help keep it consistent. 896 * 897 * @param slotTable the table to configure 898 */ 899 public void configureTable(JTable slotTable) { 900 } 901 902 // methods to communicate with SlotManager 903 @Override 904 public synchronized void notifyChangedSlot(LocoNetSlot s) { 905 // update model from this slot 906 int slotNum = s.getSlot(); 907 int slotStatus2; 908 909 if (slotNum == LnConstants.CFG_SLOT) { 910 slotStatus2 = s.ss2() & 0x78; // Bit 3-6 of SS2 contains SW36-39 of the CFG_SLOT 911 if (slotStatus2 > 0) { 912 memo.getSlotManager().update(); 913 } 914 } else { 915 slotNum = -1; // all rows 916 } 917 918 // notify the JTable object that a row has changed; do that in the Swing thread! 919 javax.swing.SwingUtilities.invokeLater(new Notify(slotNum, this)); 920 } 921 922 private static class Notify implements Runnable { 923 924 private final int _row; 925 javax.swing.table.AbstractTableModel _model; 926 927 public Notify(int row, javax.swing.table.AbstractTableModel model) { 928 _row = row; 929 _model = model; 930 } 931 932 @Override 933 public void run() { 934 if (-1 == _row) { // notify about entire table 935 _model.fireTableDataChanged(); // just that row 936 } else { 937 // notify that _row has changed 938 _model.fireTableRowsUpdated(_row, _row); // just that row 939 } 940 } 941 } 942 943 protected LocoNetSlot getSlot(int row) { 944 return memo.getSlotManager().slot(row); 945 } 946 947 /** 948 * This is a convenience method that makes it easier for classes using this 949 * model to set all in-use slots to emergency stop 950 */ 951 public void estopAll() { 952 for (int slotNum = 0; slotNum < 120; slotNum++) { 953 LocoNetSlot s = memo.getSlotManager().slot(slotNum); 954 if (s.slotStatus() != LnConstants.LOCO_FREE 955 && (s.consistStatus() == LnConstants.CONSIST_NO 956 || s.consistStatus() == LnConstants.CONSIST_TOP) 957 && s.speed() != 1) { 958 // send message to estop this loco 959 LocoNetMessage msg = s.writeSpeed(1) ; // emergency stop 960 memo.getLnTrafficController().sendLocoNetMessage(msg); 961 } 962 } 963 } 964 965 /** 966 * Send the LocoNet message to set the state of locomotive direction and 967 * functions F0, F1, F2, F3, F4 968 * @param slot loconet slot 969 * @param col grid col 970 * @param row grid row 971 */ 972 protected void sendFunctionGroup1(LocoNetSlot slot, int col, int row) { 973 log.debug("F0-F4 change requested {}", row); 974 if (slot == null) { 975 log.error("slot pointer was null for slot row: {} col: {}", row, col); 976 return; 977 } 978 boolean tempF0 = (col == ColumnNumber.F0COLUMN.ordinal()) ? !slot.isF0() : slot.isF0(); 979 boolean tempF1 = (col == ColumnNumber.F1COLUMN.ordinal()) ? !slot.isF1() : slot.isF1(); 980 boolean tempF2 = (col == ColumnNumber.F2COLUMN.ordinal()) ? !slot.isF2() : slot.isF2(); 981 boolean tempF3 = (col == ColumnNumber.F3COLUMN.ordinal()) ? !slot.isF3() : slot.isF3(); 982 boolean tempF4 = (col == ColumnNumber.F4COLUMN.ordinal()) ? !slot.isF4() : slot.isF4(); 983 984 int new_dirf = ((slot.isForward() ? 0 : LnConstants.DIRF_DIR) 985 | (tempF0 ? LnConstants.DIRF_F0 : 0) 986 | (tempF1 ? LnConstants.DIRF_F1 : 0) 987 | (tempF2 ? LnConstants.DIRF_F2 : 0) 988 | (tempF3 ? LnConstants.DIRF_F3 : 0) 989 | (tempF4 ? LnConstants.DIRF_F4 : 0)); 990 991 // set status to 'In Use' if other 992 int status = slot.slotStatus(); 993 if (status != LnConstants.LOCO_IN_USE) { 994 memo.getLnTrafficController().sendLocoNetMessage( 995 slot.writeStatus(LnConstants.LOCO_IN_USE 996 )); 997 } 998 LocoNetMessage msg = new LocoNetMessage(4); 999 msg.setOpCode(LnConstants.OPC_LOCO_DIRF); 1000 msg.setElement(1, slot.getSlot()); 1001 msg.setElement(2, new_dirf); // 1 here is estop 1002 memo.getLnTrafficController().sendLocoNetMessage(msg, true); 1003 // Delay here allows command station time to xmit on the rails. 1004 try { 1005 Thread.sleep(100); 1006 } catch (InterruptedException ex) { 1007 log.error("Interuppted Sleep", ex); 1008 } 1009 // reset status to original value if not previously 'in use' 1010 if (status != LnConstants.LOCO_IN_USE) { 1011 memo.getLnTrafficController().sendLocoNetMessage( 1012 slot.writeStatus(status)); 1013 } 1014 } 1015 1016 /** 1017 * Send the LocoNet message to set the state of functions F5, F6, F7, F8 1018 * @param slot loconet slot 1019 * @param col grid col 1020 * @param row grid row 1021 */ 1022 protected void sendFunctionGroup2(LocoNetSlot slot, int col, int row) { 1023 boolean tempF5 = (col == ColumnNumber.F5COLUMN.ordinal()) ? !slot.isF5() : slot.isF5(); 1024 boolean tempF6 = (col == ColumnNumber.F6COLUMN.ordinal()) ? !slot.isF6() : slot.isF6(); 1025 boolean tempF7 = (col == ColumnNumber.F7COLUMN.ordinal()) ? !slot.isF7() : slot.isF7(); 1026 boolean tempF8 = (col == ColumnNumber.F8COLUMN.ordinal()) ? !slot.isF8() : slot.isF8(); 1027 1028 int new_snd = ((tempF8 ? LnConstants.SND_F8 : 0) 1029 | (tempF7 ? LnConstants.SND_F7 : 0) 1030 | (tempF6 ? LnConstants.SND_F6 : 0) 1031 | (tempF5 ? LnConstants.SND_F5 : 0)); 1032 1033 // set status to 'In Use' if other 1034 int status = slot.slotStatus(); 1035 if (status != LnConstants.LOCO_IN_USE) { 1036 memo.getLnTrafficController().sendLocoNetMessage( 1037 slot.writeStatus(LnConstants.LOCO_IN_USE 1038 )); 1039 } 1040 1041 LocoNetMessage msg = new LocoNetMessage(4); 1042 msg.setOpCode(LnConstants.OPC_LOCO_SND); 1043 msg.setElement(1, slot.getSlot()); 1044 msg.setElement(2, new_snd); // 1 here is estop 1045 memo.getLnTrafficController().sendLocoNetMessage(msg, true); 1046 // Delay here allows command station time to xmit on the rails. 1047 try { 1048 Thread.sleep(100); 1049 } catch (InterruptedException ex) { 1050 log.error("Interuppted Sleep", ex); 1051 } 1052 1053 // reset status to original value if not previously 'in use' 1054 if (status != LnConstants.LOCO_IN_USE) { 1055 memo.getLnTrafficController().sendLocoNetMessage( 1056 slot.writeStatus(status)); 1057 } 1058 } 1059 1060 /** 1061 * Sends Function Group 3 values - F9 thru F12, using an "OPC_IMM_PACKET" LocoNet 1062 * Message. 1063 * @param slot loconet slot 1064 * @param col grid col 1065 * @param row grid row 1066 */ 1067 protected void sendFunctionGroup3(LocoNetSlot slot, int col, int row) { 1068 // LocoNet practice is to send F9-F12 as a DCC packet 1069 boolean tempF9 = (col == ColumnNumber.F9COLUMN.ordinal()) ? !slot.isF9() : slot.isF9(); 1070 boolean tempF10 = (col == ColumnNumber.F10COLUMN.ordinal()) ? !slot.isF10() : slot.isF10(); 1071 boolean tempF11 = (col == ColumnNumber.F11COLUMN.ordinal()) ? !slot.isF11() : slot.isF11(); 1072 boolean tempF12 = (col == ColumnNumber.F12COLUMN.ordinal()) ? !slot.isF12() : slot.isF12(); 1073 byte[] result = jmri.NmraPacket.function9Through12Packet(slot.locoAddr(), (slot.locoAddr() >= 128), 1074 tempF9, tempF10, tempF11, tempF12); 1075 1076 log.debug("sendFunctionGroup3 sending {} to LocoNet slot {}", result, slot.getSlot()); 1077 memo.get(jmri.CommandStation.class).sendPacket(result, 4); // repeat = 4 1078 } 1079 1080 /** 1081 * Sends Function Group 4 values - F13 thru F20, using an "OPC_IMM_PACKET" LocoNet 1082 * Message. 1083 * @param slot loconet slot 1084 * @param col grid col 1085 * @param row grid row 1086 */ 1087 protected void sendFunctionGroup4(LocoNetSlot slot, int col, int row) { 1088 // LocoNet practice is to send F13-F20 as a DCC packet 1089 boolean tempF13 = (col == ColumnNumber.F13COLUMN.ordinal()) ? !slot.isF13() : slot.isF13(); 1090 boolean tempF14 = (col == ColumnNumber.F14COLUMN.ordinal()) ? !slot.isF14() : slot.isF14(); 1091 boolean tempF15 = (col == ColumnNumber.F15COLUMN.ordinal()) ? !slot.isF15() : slot.isF15(); 1092 boolean tempF16 = (col == ColumnNumber.F16COLUMN.ordinal()) ? !slot.isF16() : slot.isF16(); 1093 boolean tempF17 = (col == ColumnNumber.F17COLUMN.ordinal()) ? !slot.isF17() : slot.isF17(); 1094 boolean tempF18 = (col == ColumnNumber.F18COLUMN.ordinal()) ? !slot.isF18() : slot.isF18(); 1095 boolean tempF19 = (col == ColumnNumber.F19COLUMN.ordinal()) ? !slot.isF19() : slot.isF19(); 1096 boolean tempF20 = (col == ColumnNumber.F20COLUMN.ordinal()) ? !slot.isF20() : slot.isF20(); 1097 byte[] result = jmri.NmraPacket.function13Through20Packet(slot.locoAddr(), (slot.locoAddr() >= 128), 1098 tempF13, tempF14, tempF15, tempF16, 1099 tempF17, tempF18, tempF19, tempF20); 1100 1101 log.debug("sendFunctionGroup4 sending {} to LocoNet slot {}", result, slot.getSlot()); 1102 memo.get(jmri.CommandStation.class).sendPacket(result, 4); // repeat = 4 1103 } 1104 1105 /** 1106 * Sends Function Group 5 values - F21 thru F28, using an "OPC_IMM_PACKET" LocoNet 1107 * Message. 1108 * @param slot loconet slot 1109 * @param col grid col 1110 * @param row grid row 1111 */ 1112 protected void sendFunctionGroup5(LocoNetSlot slot, int col, int row) { 1113 // LocoNet practice is to send F21-F28 as a DCC packet 1114 // LocoNet practice is to send F13-F20 as a DCC packet 1115 boolean tempF21 = (col == ColumnNumber.F21COLUMN.ordinal()) ? !slot.isF21() : slot.isF21(); 1116 boolean tempF22 = (col == ColumnNumber.F22COLUMN.ordinal()) ? !slot.isF22() : slot.isF22(); 1117 boolean tempF23 = (col == ColumnNumber.F23COLUMN.ordinal()) ? !slot.isF23() : slot.isF23(); 1118 boolean tempF24 = (col == ColumnNumber.F24COLUMN.ordinal()) ? !slot.isF24() : slot.isF24(); 1119 boolean tempF25 = (col == ColumnNumber.F25COLUMN.ordinal()) ? !slot.isF25() : slot.isF25(); 1120 boolean tempF26 = (col == ColumnNumber.F26COLUMN.ordinal()) ? !slot.isF26() : slot.isF26(); 1121 boolean tempF27 = (col == ColumnNumber.F27COLUMN.ordinal()) ? !slot.isF27() : slot.isF27(); 1122 boolean tempF28 = (col == ColumnNumber.F28COLUMN.ordinal()) ? !slot.isF28() : slot.isF28(); 1123 byte[] result = jmri.NmraPacket.function21Through28Packet(slot.locoAddr(), (slot.locoAddr() >= 128), 1124 tempF21, tempF22, tempF23, tempF24, 1125 tempF25, tempF26, tempF27, tempF28); 1126 1127 log.debug("sendFunctionGroup5 sending {} to LocoNet slot {}", result, slot.getSlot()); 1128 memo.get(jmri.CommandStation.class).sendPacket(result, 4); // repeat = 4 1129 } 1130 1131 /** 1132 * Send the Expanded LocoNet message to set the state of locomotive direction and 1133 * functions F0, F1, F2, F3, F4, F5, F6 1134 * @param slot loconet slot 1135 * @param col grid col 1136 * @param row grid row 1137 */ 1138 protected void sendExpFunctionGroup1(LocoNetSlot slot, int col, int row) { 1139 boolean tempF0 = (col == ColumnNumber.F0COLUMN.ordinal()) ? !slot.isF0() : slot.isF0(); 1140 boolean tempF1 = (col == ColumnNumber.F1COLUMN.ordinal()) ? !slot.isF1() : slot.isF1(); 1141 boolean tempF2 = (col == ColumnNumber.F2COLUMN.ordinal()) ? !slot.isF2() : slot.isF2(); 1142 boolean tempF3 = (col == ColumnNumber.F3COLUMN.ordinal()) ? !slot.isF3() : slot.isF3(); 1143 boolean tempF4 = (col == ColumnNumber.F4COLUMN.ordinal()) ? !slot.isF4() : slot.isF4(); 1144 boolean tempF5 = (col == ColumnNumber.F5COLUMN.ordinal()) ? !slot.isF5() : slot.isF5(); 1145 boolean tempF6 = (col == ColumnNumber.F6COLUMN.ordinal()) ? !slot.isF6() : slot.isF6(); 1146 int new_F0F6 = ((tempF5 ? 0b00100000 : 0) | (tempF6 ? 0b01000000 : 0) 1147 | (tempF0 ? LnConstants.DIRF_F0 : 0) 1148 | (tempF1 ? LnConstants.DIRF_F1 : 0) 1149 | (tempF2 ? LnConstants.DIRF_F2 : 0) 1150 | (tempF3 ? LnConstants.DIRF_F3 : 0) 1151 | (tempF4 ? LnConstants.DIRF_F4 : 0)); 1152 LocoNetMessage msg = new LocoNetMessage(6); 1153 msg.setOpCode(0xd5); 1154 msg.setElement(1, (slot.getSlot() / 128) | 0b00010000 ); 1155 msg.setElement(2,slot.getSlot() & 0b01111111); 1156 msg.setElement(3,slot.id() & 0x7F); 1157 msg.setElement(4, new_F0F6); 1158 memo.getLnTrafficController().sendLocoNetMessage(msg, true); 1159 } 1160 1161 /** 1162 * Send the Expanded LocoNet message to set the state of functions F7, F8, F8, F9, F10, F11, F12, F13 1163 * @param slot loconet slot 1164 * @param col grid col 1165 * @param row grid row 1166 */ 1167 protected void sendExpFunctionGroup2(LocoNetSlot slot, int col, int row) { 1168 boolean tempF7 = (col == ColumnNumber.F7COLUMN.ordinal()) ? !slot.isF7() : slot.isF7(); 1169 boolean tempF8 = (col == ColumnNumber.F8COLUMN.ordinal()) ? !slot.isF8() : slot.isF8(); 1170 boolean tempF9 = (col == ColumnNumber.F9COLUMN.ordinal()) ? !slot.isF9() : slot.isF9(); 1171 boolean tempF10 = (col == ColumnNumber.F10COLUMN.ordinal()) ? !slot.isF10() : slot.isF10(); 1172 boolean tempF11 = (col == ColumnNumber.F11COLUMN.ordinal()) ? !slot.isF11() : slot.isF11(); 1173 boolean tempF12 = (col == ColumnNumber.F12COLUMN.ordinal()) ? !slot.isF12() : slot.isF12(); 1174 boolean tempF13 = (col == ColumnNumber.F13COLUMN.ordinal()) ? !slot.isF13() : slot.isF13(); 1175 int new_F7F13 = ((tempF7 ? 0b00000001 : 0) | (tempF8 ? 0b00000010 : 0) 1176 | (tempF9 ? 0b00000100 : 0) 1177 | (tempF10 ? 0b00001000 : 0) 1178 | (tempF11 ? 0b00010000 : 0) 1179 | (tempF12 ? 0b00100000 : 0) 1180 | (tempF13 ? 0b01000000 : 0)); 1181 LocoNetMessage msg = new LocoNetMessage(6); 1182 msg.setOpCode(0xd5); 1183 msg.setElement(1, (slot.getSlot() / 128) | 0b00011000 ); 1184 msg.setElement(2,slot.getSlot() & 0b01111111); 1185 msg.setElement(3,slot.id() & 0x7F); 1186 msg.setElement(4, new_F7F13); 1187 memo.getLnTrafficController().sendLocoNetMessage(msg, true); 1188 } 1189 1190 /** 1191 * Sends expanded loconet message F14 thru F20 1192 * Message. 1193 * @param slot loconet slot 1194 * @param col grid col 1195 * @param row grid row 1196 */ 1197 protected void sendExpFunctionGroup3(LocoNetSlot slot, int col, int row) { 1198 boolean tempF14 = (col == ColumnNumber.F14COLUMN.ordinal()) ? !slot.isF14() : slot.isF14(); 1199 boolean tempF15 = (col == ColumnNumber.F15COLUMN.ordinal()) ? !slot.isF15() : slot.isF15(); 1200 boolean tempF16 = (col == ColumnNumber.F16COLUMN.ordinal()) ? !slot.isF16() : slot.isF16(); 1201 boolean tempF17 = (col == ColumnNumber.F17COLUMN.ordinal()) ? !slot.isF17() : slot.isF17(); 1202 boolean tempF18 = (col == ColumnNumber.F18COLUMN.ordinal()) ? !slot.isF18() : slot.isF18(); 1203 boolean tempF19 = (col == ColumnNumber.F19COLUMN.ordinal()) ? !slot.isF19() : slot.isF19(); 1204 boolean tempF20 = (col == ColumnNumber.F20COLUMN.ordinal()) ? !slot.isF20() : slot.isF20(); 1205 int new_F14F20 = ((tempF14 ? 0b00000001 : 0) | (tempF15 ? 0b00000010 : 0) 1206 | (tempF16 ? 0b00000100 : 0) 1207 | (tempF17 ? 0b00001000 : 0) 1208 | (tempF18 ? 0b00010000 : 0) 1209 | (tempF19 ? 0b00100000 : 0) 1210 | (tempF20 ? 0b01000000 : 0)); 1211 LocoNetMessage msg = new LocoNetMessage(6); 1212 msg.setOpCode(0xd5); 1213 msg.setElement(1, (slot.getSlot() / 128) | 0b00100000 ); 1214 msg.setElement(2,slot.getSlot() & 0b01111111); 1215 msg.setElement(3,slot.id() & 0x7F); 1216 msg.setElement(4, new_F14F20); 1217 memo.getLnTrafficController().sendLocoNetMessage(msg, true); 1218 } 1219 1220 /** 1221 * Sends Expanded loconet message F21 thru F28 Message. 1222 * @param slot loconet slot 1223 * @param col grid col 1224 * @param row grid row 1225 */ 1226 protected void sendExpFunctionGroup4(LocoNetSlot slot, int col, int row) { 1227 boolean tempF21 = (col == ColumnNumber.F21COLUMN.ordinal()) ? !slot.isF21() : slot.isF21(); 1228 boolean tempF22 = (col == ColumnNumber.F22COLUMN.ordinal()) ? !slot.isF22() : slot.isF22(); 1229 boolean tempF23 = (col == ColumnNumber.F23COLUMN.ordinal()) ? !slot.isF23() : slot.isF23(); 1230 boolean tempF24 = (col == ColumnNumber.F24COLUMN.ordinal()) ? !slot.isF24() : slot.isF24(); 1231 boolean tempF25 = (col == ColumnNumber.F25COLUMN.ordinal()) ? !slot.isF25() : slot.isF25(); 1232 boolean tempF26 = (col == ColumnNumber.F26COLUMN.ordinal()) ? !slot.isF26() : slot.isF26(); 1233 boolean tempF27 = (col == ColumnNumber.F27COLUMN.ordinal()) ? !slot.isF27() : slot.isF27(); 1234 boolean tempF28 = (col == ColumnNumber.F28COLUMN.ordinal()) ? !slot.isF28() : slot.isF28(); 1235 int new_F14F20 = ((tempF21 ? 0b00000001 : 0) | 1236 (tempF22 ? 0b00000010 : 0) | 1237 (tempF23 ? 0b00000100 : 0) | 1238 (tempF24 ? 0b00001000 : 0) | 1239 (tempF25 ? 0b00010000 : 0) | 1240 (tempF26 ? 0b00100000 : 0) | 1241 (tempF27 ? 0b01000000 : 0)); 1242 LocoNetMessage msg = new LocoNetMessage(6); 1243 msg.setOpCode(0xd5); 1244 if (!tempF28) { 1245 msg.setElement(1, (slot.getSlot() / 128) | LnConstants.OPC_EXP_SEND_FUNCTION_GROUP_F21F28_F28OFF); 1246 } else { 1247 msg.setElement(1, (slot.getSlot() / 128) | LnConstants.OPC_EXP_SEND_FUNCTION_GROUP_F21F28_F28ON); 1248 } 1249 msg.setElement(2, slot.getSlot() & 0x7F); 1250 msg.setElement(3, slot.id() & 0x7F); 1251 msg.setElement(4, new_F14F20); 1252 memo.getLnTrafficController().sendLocoNetMessage(msg, true); 1253 } 1254 1255 // gets called on SlotMonPane.dispose 1256 public void dispose() { 1257 memo.getSlotManager().removeSlotListener(this); 1258 } 1259 1260 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(SlotMonDataModel.class); 1261 1262}