001package jmri.jmrix.loconet.locoio; 002 003import java.beans.PropertyChangeEvent; 004import javax.swing.JButton; 005import javax.swing.JLabel; 006import javax.swing.JTextField; 007import jmri.jmrix.loconet.LnConstants; 008import org.slf4j.Logger; 009import org.slf4j.LoggerFactory; 010 011/** 012 * Basic Configurer for LocoIO hardware. 013 * Marked Legacy/Deprecated since 2017 version 4.12. 014 * <p> 015 * This code derives the SV values from the user-selected mode and address; this 016 * is different from earlier versions where the user was expected to do the 017 * derivation manually. This derivation is complicated by the fact that the 018 * "mode" SV[port.0] in the LocoIO doesn't fully specify the operation being 019 * done - additional bits in "v2" SV[port.2] are also used. For example, 0x80 is 020 * both turnout closed and turnout high. We read and write the mode SV _last_ to 021 * handle this. 022 * <p> 023 * The "addr" field is constructed from (or causes the construction of, 024 * depending on whether we are reading or writing...) value1 and value2. In 025 * particular, value2 requires knowledge of the mode being set. When "capturing" 026 * a turnout address (where we don't have a mode setting) we presume that the 027 * address seen in the OPC_SW_REQ packet is for a fixed contact, and interpret 028 * the bits in that context. 029 * <p> 030 * The timeout code is modelled after that in jmri.jmrix.AbstractProgrammer, 031 * though there are significant modifications. 032 * 033 * @author Bob Jacobsen Copyright (C) 2001 034 */ 035public class LocoIOTableModel 036 extends javax.swing.table.AbstractTableModel 037 implements java.beans.PropertyChangeListener { 038 039 private LocoIOData liodata; 040 private boolean inHex; 041 //private String maxSizeMode = ""; 042 043 /** 044 * Define the number of rows in the table, which is also the number of 045 * "channels" in a single LocoIO unit. 046 */ 047 private int _numRows = 16; 048 049 /** 050 * Define the contents of the individual columns. 051 */ 052 public static final int PINCOLUMN = 0; // pin number 053 public static final int MODECOLUMN = 1; // what makes this happen? 054 public static final int ADDRCOLUMN = 2; // what address is involved? 055 public static final int SV0COLUMN = 3; // SV config code 056 public static final int SV1COLUMN = 4; // SV Value1 057 public static final int SV2COLUMN = 5; // SV Value2 058 public static final int CAPTURECOLUMN = 6; // "capture" button 059 public static final int READCOLUMN = 7; // "read" button 060 public static final int WRITECOLUMN = 8; // "write" button 061 public static final int HIGHESTCOLUMN = WRITECOLUMN + 1; 062 063 private final String[] msg = new String[_numRows]; 064 065 /** 066 * Reference to the JTextField which should receive status info. 067 */ 068 private JTextField status = null; 069 070 /* 071 * Reference to JLabel for firmware version. 072 */ 073 //private JLabel firmware = null; 074 //private JLabel locobuffer = null; 075 /** 076 * Primary constructor. Initializes all the arrays. 077 * @param ldata the data. 078 */ 079 public LocoIOTableModel(LocoIOData ldata) { 080 super(); 081 082 inHex = true; 083 // references to external resources 084 liodata = ldata; 085 ldata.addPropertyChangeListener(this); 086 } 087 088 @Override 089 public void propertyChange(PropertyChangeEvent evt) { 090 // String s = "LocoIOTableModel: " + evt.getPropertyName() + " := " + evt.getNewValue() + " from " + evt.getSource(); 091 if (evt.getPropertyName().equals("PortChange")) { // NOI18N 092 Integer i = (Integer) evt.getNewValue(); 093 int v = i; 094 // log.debug("{} ROW = {}", i, v); 095 fireTableRowsUpdated(v, v); 096 } 097 } 098 099 // basic methods for AbstractTableModel implementation 100 @Override 101 public int getRowCount() { 102 return _numRows; 103 } 104 105 @Override 106 public int getColumnCount() { 107 return HIGHESTCOLUMN; 108 } 109 110 @Override 111 public String getColumnName(int col) { 112 switch (col) { 113 case PINCOLUMN: 114 return Bundle.getMessage("ColumnPort"); 115 case MODECOLUMN: 116 return Bundle.getMessage("ColumnAction"); 117 case ADDRCOLUMN: 118 return Bundle.getMessage("AddressCol"); 119 case SV0COLUMN: 120 return "SV"; // NOI18N 121 case SV1COLUMN: 122 return "Value1"; // NOI18N 123 case SV2COLUMN: 124 return "Value2"; // NOI18N 125 case CAPTURECOLUMN: 126 return ""; 127 case READCOLUMN: 128 return ""; 129 case WRITECOLUMN: 130 return ""; 131 default: 132 return "unknown"; // NOI18N 133 } 134 } 135 136 @Override 137 public Class<?> getColumnClass(int col) { 138 switch (col) { 139 case PINCOLUMN: 140 return String.class; 141 case MODECOLUMN: 142 return String.class; 143 case ADDRCOLUMN: 144 return String.class; 145 case SV0COLUMN: 146 return String.class; 147 case SV1COLUMN: 148 return String.class; 149 case SV2COLUMN: 150 return String.class; 151 case CAPTURECOLUMN: 152 return JButton.class; 153 case READCOLUMN: 154 return JButton.class; 155 case WRITECOLUMN: 156 return JButton.class; 157 default: 158 return null; 159 } 160 } 161 162 @Override 163 public boolean isCellEditable(int row, int col) { 164 switch (col) { 165 case PINCOLUMN: 166 return false; 167 case MODECOLUMN: 168 return true; 169 case ADDRCOLUMN: 170 return true; 171 case SV0COLUMN: 172 return false; 173 case SV1COLUMN: 174 return false; 175 case SV2COLUMN: 176 return false; 177 case CAPTURECOLUMN: 178 return true; 179 case READCOLUMN: 180 return true; 181 case WRITECOLUMN: 182 return true; 183 default: 184 return false; 185 } 186 } 187 188 @Override 189 public Object getValueAt(int row, int col) { 190 switch (col) { 191 case PINCOLUMN: 192 return Integer.toString(row + 1); // Ports 1 to 16 193 case MODECOLUMN: 194 return liodata.getMode(row); 195 case ADDRCOLUMN: 196 return (liodata.getAddr(row) == 0 ? ("<" + Bundle.getMessage("None").toLowerCase() + ">") : Integer.toString(liodata.getAddr(row))); 197 case SV0COLUMN: 198 return (inHex) ? "0x" + Integer.toHexString(liodata.getSV(row)) : "" + liodata.getSV(row); 199 case SV1COLUMN: 200 return (inHex) ? "0x" + Integer.toHexString(liodata.getV1(row)) : "" + liodata.getV1(row); 201 case SV2COLUMN: 202 return (inHex) ? "0x" + Integer.toHexString(liodata.getV2(row)) : "" + liodata.getV2(row); 203 case CAPTURECOLUMN: 204 return Bundle.getMessage("ButtonCapture"); 205 case READCOLUMN: 206 return Bundle.getMessage("ButtonRead"); 207 case WRITECOLUMN: 208 return Bundle.getMessage("ButtonWrite"); 209 default: 210 return "unknown"; // NOI18N 211 } 212 } 213 214 public int getPreferredWidth(int col) { 215 switch (col) { 216 case PINCOLUMN: 217 return new JLabel(" 16 ").getPreferredSize().width; // NOI18N 218 case MODECOLUMN: 219 return new JLabel("1234567890123456789012345678901234567890").getPreferredSize().width; // NOI18N 220 case ADDRCOLUMN: 221 return new JLabel(getColumnName(ADDRCOLUMN)).getPreferredSize().width; 222 case SV0COLUMN: 223 case SV1COLUMN: 224 case SV2COLUMN: 225 return new JLabel(" 0xFF ").getPreferredSize().width; // NOI18N 226 case CAPTURECOLUMN: 227 return new JButton(Bundle.getMessage("ButtonCapture")).getPreferredSize().width; 228 case READCOLUMN: 229 return new JButton(Bundle.getMessage("ButtonRead")).getPreferredSize().width; 230 case WRITECOLUMN: 231 return new JButton(Bundle.getMessage("ButtonWrite")).getPreferredSize().width; 232 default: 233 return new JLabel(" <unknown> ").getPreferredSize().width; 234 } 235 } 236 237 @Override 238 public void setValueAt(Object value, int row, int col) { 239 if (col == MODECOLUMN) { 240 if (liodata.getLocoIOModeList().isValidModeValue(value)) { 241 liodata.setMode(row, (String) value); 242 liodata.setLIM(row, (String) value); 243 LocoIOMode l = liodata.getLIM(row); 244 if (l != null) { 245 liodata.setSV(row, l.getSV()); 246 liodata.setV1(row, l, liodata.getAddr(row)); 247 liodata.setV2(row, l, liodata.getAddr(row)); 248 249 msg[row] = "Packet: " + LnConstants.OPC_NAME(l.getOpCode()) + " " // NOI18N 250 + Integer.toHexString(liodata.getV1(row)) + " " 251 + Integer.toHexString(liodata.getV2(row)) + " <CHK>"; // NOI18N 252 if (status != null) { 253 status.setText(msg[row]); 254 } 255 fireTableRowsUpdated(row, row); 256 } 257 } 258 } else if (col == ADDRCOLUMN) { 259 int a; 260 if (((String) (value)).startsWith("0x")) { 261 a = Integer.valueOf(((String) value).substring(2), 16); 262 } else { 263 try { 264 a = Integer.valueOf((String) value, 10); 265 } catch (NumberFormatException ne) { 266 log.warn("Enter a hex or decimal number for the Port Address first"); 267 return; 268 } 269 } 270 if (a < 1) { 271 a = 1; 272 } 273 if (a > 0xFFF) { 274 a = 0xFFF; 275 } 276 liodata.setAddr(row, a); 277 // ignore default start-up entry, created in #getValueAt(int, int) 278 if (!(("<" + Bundle.getMessage("None").toLowerCase() + ">").equals(liodata.getMode(row)))) { 279 LocoIOMode l = liodata.getLIM(row); 280 liodata.setV1(row, l, a); 281 liodata.setV2(row, l, a); 282 283 int opcode = (l == null) ? 0 : l.getOpCode(); 284 msg[row] = "Packet: " + LnConstants.OPC_NAME(opcode) // NOI18N 285 + " " + Integer.toHexString(liodata.getV1(row)) 286 + " " + Integer.toHexString(liodata.getV2(row)) 287 + " <CHK>"; // NOI18N 288 289 if (status != null) { 290 status.setText(msg[row]); 291 } 292 } else { 293 log.warn("Select an option from the Mode drop down first"); 294 } 295 fireTableRowsUpdated(row, row); 296 } else if (col == CAPTURECOLUMN) { 297 // start a capture operation 298 liodata.captureValues(row); 299 } else if (col == READCOLUMN) { 300 // start a read operation 301 liodata.readValues(row); 302 303 } else if (col == WRITECOLUMN) { 304 // start a write operation 305 liodata.writeValues(row); 306 } 307 } 308 309 // public static String[] getValidOnModes() { return validmodes.getValidModes(); } 310 public void dispose() { 311 log.debug("dispose"); // NOI18N 312 } 313 314 private final static Logger log = LoggerFactory.getLogger(LocoIOTableModel.class); 315 316}