001package jmri.jmrix.can.cbus.swing.modules.merg;
002
003
004import java.awt.*;
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
013//import org.slf4j.Logger;
014//import org.slf4j.LoggerFactory;
015
016/**
017 * Node Variable edit frame for a MERG CANACC8 CBUS module
018 *
019 * @author Andrew Crosland Copyright (C) 2021
020 */
021public class CanCmdEditNVPane extends AbstractEditNVPane {
022    
023    private static final int USER_FLAGS = 0;
024    private static final int OPS_FLAGS = 1;
025    private static final int DEBUG_FLAGS = 2;
026    private CmdStaFlags [] csFlags = new CmdStaFlags[3];
027    
028    private final UpdateNV cmdStaNoUpdateFn = new UpdateCmdStaNo();
029    private final UpdateNV currentLimitUpdateFn = new UpdateCurrentLimit();
030    private final UpdateNV nnMapUpdateFn = new UpdateNnMap();
031    private final UpdateNV flagUpdateFn = new UpdateFlags();
032    private final UpdateNV sodDelayUpdateFn = new UpdateSodDelay();
033    private final UpdateNV intervalUpdateFn = new UpdateInterval();
034    private final UpdateNV ackUpdateFn = new UpdateAck();
035    private final UpdateNV multUpdateFn = new UpdateMult();
036    private final UpdateNV walkaboutUpdateFn = new UpdateWalkabout();
037    
038    private TitledSpinner cmdStaNoSpinner;
039    private TitledSpinner mainSpinner;
040    private TitledSpinner progSpinner;
041    private TitledSpinner nnMapDccSpinner;
042    private TitledSpinner sodDelaySpinner;
043    private TitledSpinner intervalSpinner;
044    private TitledSpinner ackSpinner;
045    private TitledSpinner multSpinner;
046    private TitledSpinner walkaboutSpinner;
047            
048    protected String flagTitleStrings[] = new String[] {
049        Bundle.getMessage("UserFlags"),
050        Bundle.getMessage("OperationsFlags"),
051        Bundle.getMessage("DebugFlags")
052    };
053
054    protected String flagStrings[][] = new String[][] {
055        // User
056        {Bundle.getMessage("Silent"),
057            Bundle.getMessage("PermitSteal"),
058            Bundle.getMessage("PermitShare"),
059            Bundle.getMessage("PermitEvReset"),
060            Bundle.getMessage("MapEvents"),
061            Bundle.getMessage("StopOnTimeout"),
062            Bundle.getMessage("StartOfDay"),
063            Bundle.getMessage("Reserved")},
064        // Ops
065        {Bundle.getMessage("JumperControl"),
066            Bundle.getMessage("MainOnBoard"),
067            Bundle.getMessage("AnalogDetect"),
068            Bundle.getMessage("ZtcMode"),
069            Bundle.getMessage("AllStopTrackOff"),
070            Bundle.getMessage("Reserved"),
071            Bundle.getMessage("Reserved"),
072            Bundle.getMessage("Reserved")},
073        // Debug
074        {Bundle.getMessage("PriPkts"),
075            Bundle.getMessage("SpdPkts"),
076            Bundle.getMessage("FnPkts"),
077            Bundle.getMessage("ServicePkts"),
078            Bundle.getMessage("AccyPkts"),
079            Bundle.getMessage("Reserved"),
080            Bundle.getMessage("Reserved"),
081            Bundle.getMessage("Reserved")
082        }};
083
084    protected String flagTtStrings[][] = new String[][] {
085        // User
086        {Bundle.getMessage("SilentTt"),
087            Bundle.getMessage("PermitStealTt"),
088            Bundle.getMessage("PermitShareTt"),
089            Bundle.getMessage("PermitEvResetTt"),
090            Bundle.getMessage("MapEventsTt"),
091            Bundle.getMessage("StopOnTimeoutTt"),
092            Bundle.getMessage("StartOfDayTt"),
093            Bundle.getMessage("ReservedTt")},
094        // Ops
095        {Bundle.getMessage("JumperControlTt"),
096            Bundle.getMessage("MainOnBoardTt"),
097            Bundle.getMessage("AnalogDetectTt"),
098            Bundle.getMessage("ZtcModeTt"),
099            Bundle.getMessage("AllStopTrackOffTt"),
100            Bundle.getMessage("ReservedTt"),
101            Bundle.getMessage("ReservedTt"),
102            Bundle.getMessage("ReservedTt")},
103        // Debug
104        {Bundle.getMessage("PriPktsTt"),
105            Bundle.getMessage("SpdPktsTt"),
106            Bundle.getMessage("FnPktsTt"),
107            Bundle.getMessage("ServicePktsTt"),
108            Bundle.getMessage("AccyPktsTt"),
109            Bundle.getMessage("ReservedTt"),
110            Bundle.getMessage("ReservedTt"),
111            Bundle.getMessage("ReservedTt")
112        }};
113
114    protected CanCmdEditNVPane(CbusNodeNVTableDataModel dataModel, CbusNode node) {
115        super(dataModel, node);
116    }
117    
118    /** {@inheritDoc} */
119    @Override
120    public AbstractEditNVPane getContent() {
121        
122        JTabbedPane tabbedPane = new JTabbedPane();
123        
124        JPanel cmdStaPane = new CmdStaPane();
125        JPanel dccPane = new DccPane();
126        JPanel cbusPane = new CbusPane();
127        tabbedPane.addTab(Bundle.getMessage("CmdSta"), cmdStaPane);
128        tabbedPane.addTab("DCC", dccPane);
129        tabbedPane.addTab("CBUS", cbusPane);
130        
131        JScrollPane scroll = new JScrollPane(tabbedPane);
132        add(scroll);
133        
134        return this;
135    }
136
137    /** {@inheritDoc} */
138    @Override
139    public void tableChanged(TableModelEvent e) {
140        if (e.getType() == TableModelEvent.UPDATE) {
141            int row = e.getFirstRow();
142            int nv = row + 1;
143            int value = getSelectValue8(nv);
144            
145            switch (nv) {
146                case CanCmdPaneProvider.CMD_STATION_NUMBER:
147                    cmdStaNoSpinner.setValue(value);
148                    break;
149                    
150                case CanCmdPaneProvider.USER_FLAGS:
151                    csFlags[0].setFlags(value);
152                    break;
153                    
154                case CanCmdPaneProvider.OPERATIONS_FLAGS:
155                    csFlags[1].setFlags(value);
156                    break;
157                    
158                case CanCmdPaneProvider.DEBUG_FLAGS:
159                    csFlags[2].setFlags(value);
160                    break;
161                            
162                case CanCmdPaneProvider.PROG_TRACK_CURRENT_LIMIT:
163                    progSpinner.setValue(value);
164                    break;
165                
166                case CanCmdPaneProvider.MAIN_TRACK_CURRENT_LIMIT:
167                    mainSpinner.setValue(value);
168                    break;
169                    
170                case CanCmdPaneProvider.NN_MAP_DCC_HI:
171                case CanCmdPaneProvider.NN_MAP_DCC_LO:
172                    nnMapDccSpinner.setValue(getSelectValue16(CanCmdPaneProvider.NN_MAP_DCC_HI,
173                            CanCmdPaneProvider.NN_MAP_DCC_LO,
174                            CanCmdPaneProvider.MIN_NN,
175                            CanCmdPaneProvider.MAX_NN));
176                    break;
177                    
178                case CanCmdPaneProvider.WALKABOUT_TIMEOUT:
179                    walkaboutSpinner.setValue(value);
180                    break;
181                    
182                case CanCmdPaneProvider.CURRENT_MULTIPLIER:
183                    multSpinner.setValue(value);
184                    break;
185                    
186                case CanCmdPaneProvider.INC_CURRENT_FOR_ACK:
187                    ackSpinner.setValue(value);
188                    break;
189                    
190                case CanCmdPaneProvider.SEND_CURRENT_INTERVAL:
191                    intervalSpinner.setValue(value);
192                    break;
193                    
194                case CanCmdPaneProvider.SOD_DELAY:
195                    sodDelaySpinner.setValue(value);
196                    break;
197                    
198                case CanCmdPaneProvider.UNUSED_NV10:
199                case CanCmdPaneProvider.UNUSED_NV15:
200                case CanCmdPaneProvider.UNUSED_NV16:
201                    // Not currently used on CANCMD
202                    break;
203                    
204                default:
205                    // Not used, or row was -1
206//                    log.debug("Update unknown NV {}", nv);
207            }
208        }
209    }
210    
211    /**
212     * Update the command station number
213     */
214    protected class UpdateCmdStaNo implements UpdateNV {
215        
216        /** {@inheritDoc} */
217        @Override
218        public void setNewVal(int index) {
219            int cmdStaNo = cmdStaNoSpinner.getIntegerValue();
220            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
221            _dataModel.setValueAt(cmdStaNo, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
222        }
223    }
224        
225    /**
226     * Update the Flags
227     */
228    protected class UpdateFlags implements UpdateNV {
229        
230        /** {@inheritDoc} */
231        @Override
232        public void setNewVal(int index) {
233            int flags = csFlags[index].getFlags();
234            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
235            _dataModel.setValueAt(flags, csFlags[index].getNv() - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
236        }
237    }
238        
239    /**
240     * Update a current Limit
241     */
242    protected class UpdateCurrentLimit implements UpdateNV {
243        
244        /** {@inheritDoc} */
245        @Override
246        public void setNewVal(int index) {
247            // CANCMD current limits are raw A/D values ( 0 - 255 ), the current in mA
248            // is the raw value multiplied by the current multiplier NV, so no scaling here.
249            int limit;
250            if (index == CanCmdPaneProvider.MAIN_TRACK_CURRENT_LIMIT) {
251                limit = mainSpinner.getIntegerValue();
252            } else {
253                limit = progSpinner.getIntegerValue();
254            }
255            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
256            _dataModel.setValueAt(limit, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
257        }
258    }
259    
260    /**
261     * Update the Node Number of events to be mapped to DCC accessory commands
262     */
263    protected class UpdateNnMap implements UpdateNV {
264        
265        /** {@inheritDoc} */
266        @Override
267        public void setNewVal(int index) {
268            int mapNn = nnMapDccSpinner.getIntegerValue();
269            int mapNnHi = mapNn/256;
270            int mapNnLo = mapNn%256;
271            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
272            _dataModel.setValueAt(mapNnHi, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
273            _dataModel.setValueAt(mapNnLo, index, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
274        }
275    }
276
277    protected class UpdateSodDelay implements UpdateNV {
278        
279        /** {@inheritDoc} */
280        @Override
281        public void setNewVal(int index) {
282            int sodDelay = sodDelaySpinner.getIntegerValue();
283            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
284            _dataModel.setValueAt(sodDelay, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
285        }
286    }
287    
288    protected class UpdateInterval implements UpdateNV {
289        
290        /** {@inheritDoc} */
291        @Override
292        public void setNewVal(int index) {
293            int interval = intervalSpinner.getIntegerValue();
294            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
295            _dataModel.setValueAt(interval, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
296        }
297    }
298    
299    protected class UpdateAck implements UpdateNV {
300        
301        /** {@inheritDoc} */
302        @Override
303        public void setNewVal(int index) {
304            int ack = ackSpinner.getIntegerValue();
305            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
306            _dataModel.setValueAt(ack, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
307        }
308    }
309    
310    protected class UpdateMult implements UpdateNV {
311        
312        /** {@inheritDoc} */
313        @Override
314        public void setNewVal(int index) {
315            int mult = multSpinner.getIntegerValue();
316            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
317            _dataModel.setValueAt(mult, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
318        }
319    }
320    
321    protected class UpdateWalkabout implements UpdateNV {
322        
323        /** {@inheritDoc} */
324        @Override
325        public void setNewVal(int index) {
326            int delay = walkaboutSpinner.getIntegerValue();
327            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
328            _dataModel.setValueAt(delay, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
329        }
330    }
331    
332    public class CmdStaPane extends JPanel {
333
334        /**
335         * Panel to display command station NVs
336         */
337        public CmdStaPane() {
338            super();
339
340            JPanel gridPane = new JPanel(new GridBagLayout());
341            JPanel [] flagPane = new JPanel[3];
342            GridBagConstraints c = new GridBagConstraints();
343            c.fill = GridBagConstraints.HORIZONTAL;
344
345            for (int i = 0; i < 3; i++) {
346                csFlags[i] = new CmdStaFlags(i, CanCmdPaneProvider.USER_FLAGS + i, flagTitleStrings[i], flagStrings[i], flagTtStrings[i], flagUpdateFn);
347                csFlags[i].setFlags(getSelectValue8(CanCmdPaneProvider.USER_FLAGS + i));
348                flagPane[i] = csFlags[i].getContents();
349            }
350            
351            c.weightx = 1;
352            c.weighty = 1;
353            c.gridx = 0;
354            c.gridy = 0;
355
356            // x = 1
357            cmdStaNoSpinner = new TitledSpinner(Bundle.getMessage("CmdStaNo"), CanCmdPaneProvider.CMD_STATION_NUMBER, cmdStaNoUpdateFn);
358            cmdStaNoSpinner.setToolTip(Bundle.getMessage("CmdStaNoTt"));
359            cmdStaNoSpinner.init(0, 0, 255, 1);
360            gridPane.add(cmdStaNoSpinner, c);
361            c.gridy++;
362            
363            walkaboutSpinner = new TitledSpinner(Bundle.getMessage("WalkaboutTimeout"), CanCmdPaneProvider.WALKABOUT_TIMEOUT, walkaboutUpdateFn);
364            walkaboutSpinner.setToolTip(Bundle.getMessage("WalkaboutTimeoutTt"));
365            walkaboutSpinner.init(getSelectValue8(CanCmdPaneProvider.WALKABOUT_TIMEOUT, 1), 1, 255, 1);
366            gridPane.add(walkaboutSpinner, c);
367            c.gridy++;
368            
369            multSpinner = new TitledSpinner(Bundle.getMessage("CurrentMultiplier"), CanCmdPaneProvider.CURRENT_MULTIPLIER, multUpdateFn);
370            multSpinner.setToolTip(Bundle.getMessage("CurrentMultiplierTt"));
371            multSpinner.init(getSelectValue8(CanCmdPaneProvider.CURRENT_MULTIPLIER, 1), 1, 255, 1);
372            gridPane.add(multSpinner, c);
373            c.gridy++;
374            
375            ackSpinner = new TitledSpinner(Bundle.getMessage("IncCurrentForAck"), CanCmdPaneProvider.INC_CURRENT_FOR_ACK, ackUpdateFn);
376            ackSpinner.setToolTip(Bundle.getMessage("IncCurrentForAckTt"));
377            ackSpinner.init(getSelectValue8(CanCmdPaneProvider.INC_CURRENT_FOR_ACK, 1), 1, 255, 1);
378            gridPane.add(ackSpinner, c);
379            c.gridy++;
380            
381            intervalSpinner = new TitledSpinner(Bundle.getMessage("SendCurrentInterval"), CanCmdPaneProvider.SEND_CURRENT_INTERVAL, intervalUpdateFn);
382            intervalSpinner.setToolTip(Bundle.getMessage("SendCurrentIntervalTt"));
383            intervalSpinner.init(getSelectValue8(CanCmdPaneProvider.SEND_CURRENT_INTERVAL), 0, 255, 1);
384            gridPane.add(intervalSpinner, c);
385            c.gridy++;
386            
387            c.gridwidth = 3;
388            
389            mainSpinner = new TitledSpinner(Bundle.getMessage("CanCmdMainLimit"), CanCmdPaneProvider.MAIN_TRACK_CURRENT_LIMIT, currentLimitUpdateFn);
390            mainSpinner.setToolTip(Bundle.getMessage("CanCmdMainLimitTt"));
391            mainSpinner.init(getSelectValue8(CanCmdPaneProvider.MAIN_TRACK_CURRENT_LIMIT, 1), 1, 255, 1);
392            gridPane.add(mainSpinner, c);
393            c.gridy++;
394            
395            progSpinner = new TitledSpinner(Bundle.getMessage("CanCmdProgLimit"), CanCmdPaneProvider.PROG_TRACK_CURRENT_LIMIT, currentLimitUpdateFn);
396            progSpinner.setToolTip(Bundle.getMessage("CanCmdProgLimitTt"));
397            progSpinner.init(getSelectValue8(CanCmdPaneProvider.PROG_TRACK_CURRENT_LIMIT, 1), 1, 255, 1);
398            gridPane.add(progSpinner, c);
399            c.gridy++;
400            c.gridx = 0;
401
402            gridPane.add(flagPane[USER_FLAGS], c);
403            c.gridx++;
404            
405            gridPane.add(flagPane[OPS_FLAGS], c);
406            c.gridx++;
407
408            gridPane.add(flagPane[DEBUG_FLAGS], c);
409            c.gridx++;
410
411            add(gridPane);
412        }
413    }
414    
415    /**
416     * Panel to display DCC related NVs
417     */
418    public class DccPane extends JPanel {
419        public DccPane() {
420            super();
421
422            JPanel gridPane = new JPanel(new GridBagLayout());
423            GridBagConstraints c = new GridBagConstraints();
424            c.fill = GridBagConstraints.HORIZONTAL;
425
426            c.weightx = 1;
427            c.weighty = 1;
428            c.gridx = 0;
429            c.gridy = 0;
430            
431            c.gridy++;
432            
433            nnMapDccSpinner = new TitledSpinner(Bundle.getMessage("NnMapDcc"), CanCmdPaneProvider.NN_MAP_DCC_HI, nnMapUpdateFn);
434            nnMapDccSpinner.setToolTip(Bundle.getMessage("NnMapDccTt"));
435            int nn = getSelectValue16(CanCmdPaneProvider.NN_MAP_DCC_HI, CanCmdPaneProvider.NN_MAP_DCC_LO, CanCmdPaneProvider.MIN_NN, CanCmdPaneProvider.MAX_NN);
436            nnMapDccSpinner.init(nn, 0, 65535, 1);
437            gridPane.add(nnMapDccSpinner, c);
438            c.gridy++;
439            
440            gridPane.add(nnMapDccSpinner, c);
441            c.gridy++;
442
443            add(gridPane);
444        }
445    }
446    
447    /**
448     * Panel to display CBUS operation related NVs
449     */
450    public class CbusPane extends JPanel {
451        public CbusPane() {
452            super();
453
454            JPanel gridPane = new JPanel(new GridBagLayout());
455            GridBagConstraints c = new GridBagConstraints();
456            c.fill = GridBagConstraints.HORIZONTAL;
457
458            c.weightx = 1;
459            c.weighty = 1;
460            c.gridx = 0;
461            c.gridy = 0;
462
463            sodDelaySpinner = new TitledSpinner(Bundle.getMessage("SodDelay"), CanCmdPaneProvider.SOD_DELAY, sodDelayUpdateFn);
464            sodDelaySpinner.setToolTip(Bundle.getMessage("SodDelayTt"));
465            sodDelaySpinner.init(getSelectValue8(CanCmdPaneProvider.SOD_DELAY), 0, 255, 1);
466            gridPane.add(sodDelaySpinner, c);
467            c.gridy++;
468
469            add(gridPane);
470        }
471    }
472    
473    //private static final Logger log = LoggerFactory.getLogger(CanCmdEditNVPane.class);
474
475}