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            int limit;
248            double fLimit;
249            if (index == CanCmdPaneProvider.MAIN_TRACK_CURRENT_LIMIT) {
250                fLimit = mainSpinner.getDoubleValue();
251            } else {
252                fLimit = progSpinner.getDoubleValue();
253            }
254            // Limit to 10mA precision
255            limit = (int)(fLimit*100 + 0.5);
256            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
257            _dataModel.setValueAt(limit, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
258        }
259    }
260    
261    /**
262     * Update the Node Number of events to be mapped to DCC accessory commands
263     */
264    protected class UpdateNnMap implements UpdateNV {
265        
266        /** {@inheritDoc} */
267        @Override
268        public void setNewVal(int index) {
269            int mapNn = nnMapDccSpinner.getIntegerValue();
270            int mapNnHi = mapNn/256;
271            int mapNnLo = mapNn%256;
272            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
273            _dataModel.setValueAt(mapNnHi, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
274            _dataModel.setValueAt(mapNnLo, index, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
275        }
276    }
277
278    protected class UpdateSodDelay implements UpdateNV {
279        
280        /** {@inheritDoc} */
281        @Override
282        public void setNewVal(int index) {
283            int sodDelay = sodDelaySpinner.getIntegerValue();
284            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
285            _dataModel.setValueAt(sodDelay, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
286        }
287    }
288    
289    protected class UpdateInterval implements UpdateNV {
290        
291        /** {@inheritDoc} */
292        @Override
293        public void setNewVal(int index) {
294            int interval = intervalSpinner.getIntegerValue();
295            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
296            _dataModel.setValueAt(interval, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
297        }
298    }
299    
300    protected class UpdateAck implements UpdateNV {
301        
302        /** {@inheritDoc} */
303        @Override
304        public void setNewVal(int index) {
305            int ack = ackSpinner.getIntegerValue();
306            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
307            _dataModel.setValueAt(ack, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
308        }
309    }
310    
311    protected class UpdateMult implements UpdateNV {
312        
313        /** {@inheritDoc} */
314        @Override
315        public void setNewVal(int index) {
316            int mult = multSpinner.getIntegerValue();
317            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
318            _dataModel.setValueAt(mult, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
319        }
320    }
321    
322    protected class UpdateWalkabout implements UpdateNV {
323        
324        /** {@inheritDoc} */
325        @Override
326        public void setNewVal(int index) {
327            int delay = multSpinner.getIntegerValue();
328            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
329            _dataModel.setValueAt(delay, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
330        }
331    }
332    
333    public class CmdStaPane extends JPanel {
334
335        /**
336         * Panel to display command station NVs
337         */
338        public CmdStaPane() {
339            super();
340
341            JPanel gridPane = new JPanel(new GridBagLayout());
342            JPanel [] flagPane = new JPanel[3];
343            GridBagConstraints c = new GridBagConstraints();
344            c.fill = GridBagConstraints.HORIZONTAL;
345
346            for (int i = 0; i < 3; i++) {
347                csFlags[i] = new CmdStaFlags(i, CanCmdPaneProvider.USER_FLAGS + i, flagTitleStrings[i], flagStrings[i], flagTtStrings[i], flagUpdateFn);
348                csFlags[i].setFlags(getSelectValue8(CanCmdPaneProvider.USER_FLAGS + i));
349                flagPane[i] = csFlags[i].getContents();
350            }
351            
352            c.weightx = 1;
353            c.weighty = 1;
354            c.gridx = 0;
355            c.gridy = 0;
356
357            // x = 1
358            cmdStaNoSpinner = new TitledSpinner(Bundle.getMessage("CmdStaNo"), CanCmdPaneProvider.CMD_STATION_NUMBER, cmdStaNoUpdateFn);
359            cmdStaNoSpinner.setToolTip(Bundle.getMessage("CmdStaNoTt"));
360            cmdStaNoSpinner.init(0, 0, 255, 1);
361            gridPane.add(cmdStaNoSpinner, c);
362            c.gridy++;
363            
364            walkaboutSpinner = new TitledSpinner(Bundle.getMessage("WalkaboutTimeout"), CanCmdPaneProvider.WALKABOUT_TIMEOUT, walkaboutUpdateFn);
365            walkaboutSpinner.setToolTip(Bundle.getMessage("WalkaboutTimeoutTt"));
366            walkaboutSpinner.init(getSelectValue8(CanCmdPaneProvider.WALKABOUT_TIMEOUT, 1), 1, 60, 255);
367            gridPane.add(walkaboutSpinner, c);
368            c.gridy++;
369            
370            multSpinner = new TitledSpinner(Bundle.getMessage("CurrentMultiplier"), CanCmdPaneProvider.CURRENT_MULTIPLIER, multUpdateFn);
371            multSpinner.setToolTip(Bundle.getMessage("CurrentMultiplierTt"));
372            multSpinner.init(getSelectValue8(CanCmdPaneProvider.CURRENT_MULTIPLIER, 1), 1, 10, 255);
373            gridPane.add(multSpinner, c);
374            c.gridy++;
375            
376            ackSpinner = new TitledSpinner(Bundle.getMessage("IncCurrentForAck"), CanCmdPaneProvider.INC_CURRENT_FOR_ACK, ackUpdateFn);
377            ackSpinner.setToolTip(Bundle.getMessage("IncCurrentForAckTt"));
378            ackSpinner.init(getSelectValue8(CanCmdPaneProvider.INC_CURRENT_FOR_ACK, 1), 1, 3, 255);
379            gridPane.add(ackSpinner, c);
380            c.gridy++;
381            
382            intervalSpinner = new TitledSpinner(Bundle.getMessage("SendCurrentInterval"), CanCmdPaneProvider.SEND_CURRENT_INTERVAL, intervalUpdateFn);
383            intervalSpinner.setToolTip(Bundle.getMessage("SendCurrentIntervalTt"));
384            intervalSpinner.init(getSelectValue8(CanCmdPaneProvider.SEND_CURRENT_INTERVAL), 0, 255, 1);
385            gridPane.add(intervalSpinner, c);
386            c.gridy++;
387            
388            c.gridwidth = 3;
389            
390            mainSpinner = new TitledSpinner(Bundle.getMessage("MainLimit"), CanCmdPaneProvider.MAIN_TRACK_CURRENT_LIMIT, currentLimitUpdateFn);
391            mainSpinner.setToolTip(Bundle.getMessage("MainLimitTt"));
392            mainSpinner.init(getSelectValue8(CanCmdPaneProvider.MAIN_TRACK_CURRENT_LIMIT, 1), 1.0, 96.0, 255.0);
393            gridPane.add(mainSpinner, c);
394            c.gridy++;
395            
396            progSpinner = new TitledSpinner(Bundle.getMessage("ProgLimit"), CanCmdPaneProvider.PROG_TRACK_CURRENT_LIMIT, currentLimitUpdateFn);
397            progSpinner.setToolTip(Bundle.getMessage("ProgLimitTt"));
398            progSpinner.init(getSelectValue8(CanCmdPaneProvider.PROG_TRACK_CURRENT_LIMIT, 1), 1.0, 96.0, 255.0);
399            gridPane.add(progSpinner, c);
400            c.gridy++;
401            c.gridx = 0;
402
403            gridPane.add(flagPane[USER_FLAGS], c);
404            c.gridx++;
405            
406            gridPane.add(flagPane[OPS_FLAGS], c);
407            c.gridx++;
408
409            gridPane.add(flagPane[DEBUG_FLAGS], c);
410            c.gridx++;
411
412            add(gridPane);
413        }
414    }
415    
416    /**
417     * Panel to display DCC related NVs
418     */
419    public class DccPane extends JPanel {
420        public DccPane() {
421            super();
422
423            JPanel gridPane = new JPanel(new GridBagLayout());
424            GridBagConstraints c = new GridBagConstraints();
425            c.fill = GridBagConstraints.HORIZONTAL;
426
427            c.weightx = 1;
428            c.weighty = 1;
429            c.gridx = 0;
430            c.gridy = 0;
431            
432            c.gridy++;
433            
434            nnMapDccSpinner = new TitledSpinner(Bundle.getMessage("NnMapDcc"), CanCmdPaneProvider.NN_MAP_DCC_HI, nnMapUpdateFn);
435            nnMapDccSpinner.setToolTip(Bundle.getMessage("NnMapDccTt"));
436            int nn = getSelectValue16(CanCmdPaneProvider.NN_MAP_DCC_HI, CanCmdPaneProvider.NN_MAP_DCC_LO, CanCmdPaneProvider.MIN_NN, CanCmdPaneProvider.MAX_NN);
437            nnMapDccSpinner.init(nn, 0, 65535, 1);
438            gridPane.add(nnMapDccSpinner, c);
439            c.gridy++;
440            
441            gridPane.add(nnMapDccSpinner, c);
442            c.gridy++;
443
444            add(gridPane);
445        }
446    }
447    
448    /**
449     * Panel to display CBUS operation related NVs
450     */
451    public class CbusPane extends JPanel {
452        public CbusPane() {
453            super();
454
455            JPanel gridPane = new JPanel(new GridBagLayout());
456            GridBagConstraints c = new GridBagConstraints();
457            c.fill = GridBagConstraints.HORIZONTAL;
458
459            c.weightx = 1;
460            c.weighty = 1;
461            c.gridx = 0;
462            c.gridy = 0;
463
464            sodDelaySpinner = new TitledSpinner(Bundle.getMessage("SodDelay"), CanCmdPaneProvider.SOD_DELAY, sodDelayUpdateFn);
465            sodDelaySpinner.setToolTip(Bundle.getMessage("SodDelayTt"));
466            sodDelaySpinner.init(getSelectValue8(CanCmdPaneProvider.SOD_DELAY), 0, 255, 1);
467            gridPane.add(sodDelaySpinner, c);
468            c.gridy++;
469
470            add(gridPane);
471        }
472    }
473    
474    //private final static Logger log = LoggerFactory.getLogger(CanCmdEditNVPane.class);
475
476}