001package jmri.jmrix.can.cbus.swing.modules.sprogdcc; 002 003import java.awt.*; 004import java.awt.event.ActionEvent; 005 006import javax.swing.*; 007import javax.swing.event.TableModelEvent; 008 009import jmri.jmrix.can.cbus.node.CbusNode; 010import jmri.jmrix.can.cbus.node.CbusNodeNVTableDataModel; 011import jmri.jmrix.can.cbus.swing.modules.*; 012 013import org.slf4j.Logger; 014import org.slf4j.LoggerFactory; 015 016/** 017 * Node Variable edit frame for a SPROG DCC Pi-SPROG 3 module 018 * 019 * @author Andrew Crosland Copyright (C) 2022 020 */ 021public class PiSprog3EditNVPane extends AbstractEditNVPane { 022 023 private static final int USER_FLAGS = 0; 024 private static final int OPS_FLAGS = 1; 025 private CmdStaFlags [] csFlags = new CmdStaFlags[2]; 026 027 private final UpdateNV currentLimitUpdateFn = new UpdateCurrentLimit(); 028 private final UpdateNV accyPktUpdateFn = new UpdateAccyCount(); 029 private final UpdateNV preambleUpdateFn = new UpdatePreamble(); 030 private final UpdateNV modeUpdateFn = new UpdatePowerMode(); 031 private final UpdateNV meterUpdateFn = new UpdateMeter(); 032 private final UpdateNV flagUpdateFn = new UpdateFlags(); 033 034 private JComboBox<String> modeList ; 035 private TitledSpinner mainSpinner; 036 private TitledSpinner accyPktSpinner; 037 private JRadioButton meter; 038 private JRadioButton setup; 039 private TitledSpinner preambleSpinner; 040 041 protected String flagTitleStrings[] = new String[] { 042 Bundle.getMessage("UserFlags"), 043 Bundle.getMessage("OperationsFlags") 044 }; 045 046 protected String flagStrings[][] = new String[][] { 047 // User 048 {Bundle.getMessage("Reserved"), 049 Bundle.getMessage("PermitSteal"), 050 Bundle.getMessage("PermitShare"), 051 Bundle.getMessage("Reserved"), 052 Bundle.getMessage("MapEvents"), 053 Bundle.getMessage("StopOnTimeout"), 054 Bundle.getMessage("StartOfDay"), 055 Bundle.getMessage("AutoPower")}, 056 // Ops 057 {Bundle.getMessage("Reserved"), 058 Bundle.getMessage("Reserved"), 059 Bundle.getMessage("Reserved"), 060 Bundle.getMessage("ZtcMode"), 061 Bundle.getMessage("AllStopTrackOff"), 062 Bundle.getMessage("BluelineMode"), 063 Bundle.getMessage("AckSensitivity"), 064 Bundle.getMessage("Reserved") 065 }}; 066 067 protected String flagTtStrings[][] = new String[][] { 068 // User 069 {Bundle.getMessage("ReservedTt"), 070 Bundle.getMessage("PermitStealTt"), 071 Bundle.getMessage("PermitShareTt"), 072 Bundle.getMessage("ReservedTt"), 073 Bundle.getMessage("MapEventsTt"), 074 Bundle.getMessage("StopOnTimeoutTt"), 075 Bundle.getMessage("StartOfDayTt"), 076 Bundle.getMessage("AutoPowerTt")}, 077 // Ops 078 {Bundle.getMessage("ReservedTt"), 079 Bundle.getMessage("ReservedTt"), 080 Bundle.getMessage("ReservedTt"), 081 Bundle.getMessage("ZtcModeTt"), 082 Bundle.getMessage("AllStopTrackOffTt"), 083 Bundle.getMessage("BluelineModeTt"), 084 Bundle.getMessage("AckSensitivityTt"), 085 Bundle.getMessage("ReservedTt") 086 }}; 087 088 protected PiSprog3EditNVPane(CbusNodeNVTableDataModel dataModel, CbusNode node) { 089 super(dataModel, node); 090 } 091 092 /** {@inheritDoc} */ 093 @Override 094 public AbstractEditNVPane getContent() { 095 096 JTabbedPane tabbedPane = new JTabbedPane(); 097 098 JPanel cmdStaPane = new CmdStaPane(); 099 JPanel dccPane = new DccPane(); 100 JPanel cbusPane = new CbusPane(); 101 tabbedPane.addTab(Bundle.getMessage("CmdSta"), cmdStaPane); 102 tabbedPane.addTab("DCC", dccPane); 103 tabbedPane.addTab("CBUS Diagnostics", cbusPane); 104 105 JScrollPane scroll = new JScrollPane(tabbedPane); 106 add(scroll); 107 108 return this; 109 } 110 111 /** {@inheritDoc} */ 112 @Override 113 public void tableChanged(TableModelEvent e) { 114 if (e.getType() == TableModelEvent.UPDATE) { 115 int row = e.getFirstRow(); 116 int nv = row + 1; 117 int value = getSelectValue8(nv); 118 log.debug("pisprog3 gui table changed NV: {} Value: {}", nv, value); 119 120 switch (nv) { 121 case PiSprog3PaneProvider.USER_FLAGS: 122 csFlags[0].setFlags(value); 123 break; 124 125 case PiSprog3PaneProvider.OPERATIONS_FLAGS: 126 csFlags[1].setFlags(value); 127 break; 128 129 case PiSprog3PaneProvider.CMD_STATION_MODE: 130 // Do nothing if nothing has changed, else causes an endless 131 // round of gui update, table update, ... 132 if (value != modeList.getSelectedIndex()) { 133 modeList.setSelectedIndex(value); 134 } 135 break; 136 137 case PiSprog3PaneProvider.CURRENT_LIMIT: 138 double mainLimit = (double)value/100; 139 mainSpinner.setValue(mainLimit); 140 break; 141 142 case PiSprog3PaneProvider.ACCY_PACKET_REPEAT_COUNT: 143 accyPktSpinner.setValue(value); 144 break; 145 146 case PiSprog3PaneProvider.MULTIMETER_MODE: 147 meter.setSelected(value != 0); 148 break; 149 150 case PiSprog3PaneProvider.SETUP: 151 setup.setSelected(value != 0); 152 break; 153 154 case PiSprog3PaneProvider.DCC_PREAMBLE: 155 preambleSpinner.setValue(value); 156 break; 157 158 case PiSprog3PaneProvider.INPUT_VOLTAGE: 159 case PiSprog3PaneProvider.TRACK_CURRENT: 160 // These read-only NVs are not preented in the edit GUI as they can be displayed on meters 161 break; 162 163 default: 164 // Not used, or row was -1 165// log.debug("Update unknown NV {}", nv); 166 167 } 168 } 169 } 170 171 /** 172 * Update the Flags 173 */ 174 protected class UpdateFlags implements UpdateNV { 175 176 /** {@inheritDoc} */ 177 @Override 178 public void setNewVal(int index) { 179 int flags = csFlags[index].getFlags(); 180 // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc 181 _dataModel.setValueAt(flags, csFlags[index].getNv() - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN); 182 } 183 } 184 185 /** 186 * Update the multi meter events setting 187 */ 188 protected class UpdateMeter implements UpdateNV { 189 190 /** {@inheritDoc} */ 191 @Override 192 public void setNewVal(int index) { 193 int mode = meter.isSelected() ? 1 : 0; 194 // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc 195 _dataModel.setValueAt(mode, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN); 196 } 197 } 198 199 /** 200 * Update a current Limit 201 */ 202 protected class UpdateCurrentLimit implements UpdateNV { 203 204 /** {@inheritDoc} */ 205 @Override 206 public void setNewVal(int index) { 207 int limit; 208 double fLimit; 209 fLimit = mainSpinner.getDoubleValue(); 210 // Limit to 10mA precision 211 limit = (int)(fLimit*100 + 0.5); 212 // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc 213 _dataModel.setValueAt(limit, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN); 214 } 215 } 216 217 /** 218 * Update the number of times a DCC accessory packet is repeated 219 */ 220 protected class UpdateAccyCount implements UpdateNV { 221 222 /** {@inheritDoc} */ 223 @Override 224 public void setNewVal(int index) { 225 int cnt = accyPktSpinner.getIntegerValue(); 226 // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc 227 _dataModel.setValueAt(cnt, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN); 228 } 229 } 230 231 /** 232 * Update the number of DCC packet preamble bits 233 */ 234 protected class UpdatePreamble implements UpdateNV { 235 236 /** {@inheritDoc} */ 237 @Override 238 public void setNewVal(int index) { 239 int pre = preambleSpinner.getIntegerValue(); 240 // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc 241 _dataModel.setValueAt(pre, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN); 242 } 243 } 244 245 /** 246 * Update the command station power mode 247 */ 248 protected class UpdatePowerMode implements UpdateNV { 249 250 /** {@inheritDoc} */ 251 @Override 252 public void setNewVal(int index) { 253 log.debug("UpdatePowerMode.setNewVal()"); 254 int mode = modeList.getSelectedIndex(); 255 // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc 256 _dataModel.setValueAt(mode, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN); 257 } 258 } 259 260 public class CmdStaPane extends JPanel { 261 262 /** 263 * Panel to display command station NVs 264 */ 265 public CmdStaPane() { 266 super(); 267 268 JPanel gridPane = new JPanel(new GridBagLayout()); 269 JPanel [] flagPane = new JPanel[2]; 270 GridBagConstraints c = new GridBagConstraints(); 271 c.fill = GridBagConstraints.HORIZONTAL; 272 273 for (int i = 0; i < 2; i++) { 274 csFlags[i] = new CmdStaFlags(i, PiSprog3PaneProvider.USER_FLAGS + i, flagTitleStrings[i], flagStrings[i], flagTtStrings[i], flagUpdateFn); 275 csFlags[i].setFlags(getSelectValue8(PiSprog3PaneProvider.USER_FLAGS + i)); 276 flagPane[i] = csFlags[i].getContents(); 277 } 278 279 String modeStrings [] = new String[] {Bundle.getMessage("ProgMode"), 280 Bundle.getMessage("CmdMode") 281 }; 282 283 c.weightx = 1; 284 c.weighty = 1; 285 c.gridx = 0; 286 c.gridy = 0; 287 288 // x = 1 289 c.gridwidth = 3; 290 modeList = new JComboBox<>(modeStrings); 291 modeList.setSelectedIndex(getSelectValue8(PiSprog3PaneProvider.CMD_STATION_MODE)); 292 modeList.addActionListener((ActionEvent e) -> { 293 modeActionListener(e); 294 }); 295 gridPane.add(modeList, c); 296 c.gridwidth = 1; 297 c.gridy++; 298 299 meter = new JRadioButton(Bundle.getMessage("Multimeter")); 300 meter.setSelected(false); 301 meter.setToolTipText(Bundle.getMessage("MultimeterTt")); 302 meter.addActionListener((ActionEvent e) -> { 303 meterActionListener(e); 304 }); 305 gridPane.add(meter, c); 306 c.gridy++; 307 308 mainSpinner = new TitledSpinner(Bundle.getMessage("MainLimit"), PiSprog3PaneProvider.CURRENT_LIMIT, currentLimitUpdateFn); 309 mainSpinner.setToolTip(Bundle.getMessage("MainLimitTt")); 310 mainSpinner.init(getSelectValue8(PiSprog3PaneProvider.CURRENT_LIMIT, 100)/100.0, 1.0, 2.5, 0.01); 311 gridPane.add(mainSpinner, c); 312 c.gridy++; 313 c.gridx = 0; 314 315 gridPane.add(flagPane[USER_FLAGS], c); 316 c.gridx++; 317 318 gridPane.add(flagPane[OPS_FLAGS], c); 319 c.gridx++; 320 321 add(gridPane); 322 } 323 324 /** 325 * Action listener for the command station power mode 326 * 327 * @param e the action event 328 */ 329 protected void modeActionListener(ActionEvent e) { 330 log.debug("modeActionListener()"); 331 modeUpdateFn.setNewVal(PiSprog3PaneProvider.CMD_STATION_MODE); 332 } 333 334 /** 335 * Action listener for multimeter nmode selection 336 * 337 * @param e the action event 338 */ 339 protected void meterActionListener(ActionEvent e) { 340 meterUpdateFn.setNewVal(PiSprog3PaneProvider.MULTIMETER_MODE); 341 } 342 } 343 344 /** 345 * Panel to display DCC related NVs 346 */ 347 public class DccPane extends JPanel { 348 public DccPane() { 349 super(); 350 351 JPanel gridPane = new JPanel(new GridBagLayout()); 352 GridBagConstraints c = new GridBagConstraints(); 353 c.fill = GridBagConstraints.HORIZONTAL; 354 355 c.weightx = 1; 356 c.weighty = 1; 357 c.gridx = 0; 358 c.gridy = 0; 359 360 accyPktSpinner = new TitledSpinner(Bundle.getMessage("AccyPktCnt"), PiSprog3PaneProvider.ACCY_PACKET_REPEAT_COUNT, accyPktUpdateFn); 361 accyPktSpinner.setToolTip(Bundle.getMessage("AccyPktCntTt")); 362 accyPktSpinner.init(getSelectValue8(PiSprog3PaneProvider.ACCY_PACKET_REPEAT_COUNT, 1), 1, 7, 1); 363 gridPane.add(accyPktSpinner, c); 364 c.gridy++; 365 366 preambleSpinner = new TitledSpinner(Bundle.getMessage("DccPreambles"), PiSprog3PaneProvider.DCC_PREAMBLE, preambleUpdateFn); 367 preambleSpinner.setToolTip(Bundle.getMessage("DccPreamblesTt")); 368 preambleSpinner.init(getSelectValue8(PiSprog3PaneProvider.DCC_PREAMBLE, 14), 14, 32, 1); 369 gridPane.add(preambleSpinner, c); 370 371 add(gridPane); 372 } 373 } 374 375 /** 376 * Panel to display CBUS operation related NVs 377 */ 378 public class CbusPane extends JPanel { 379 public CbusPane() { 380 super(); 381 382 JPanel gridPane = new JPanel(new GridBagLayout()); 383 GridBagConstraints c = new GridBagConstraints(); 384 c.fill = GridBagConstraints.HORIZONTAL; 385 386 c.weightx = 1; 387 c.weighty = 1; 388 c.gridx = 0; 389 c.gridy = 0; 390 391 setup = new JRadioButton("SetupMode"); 392 setup.setSelected(false); 393 setup.setToolTipText(Bundle.getMessage("SetupModeTt")); 394 gridPane.add(setup, c); 395 c.gridy++; 396 397 add(gridPane); 398 } 399 } 400 401 private final static Logger log = LoggerFactory.getLogger(PiSprog3EditNVPane.class); 402 403}