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.*;
012import org.slf4j.Logger;
013import org.slf4j.LoggerFactory;
014
015/**
016 * Node Variable edit frame for a SPROG DCC [Pi-]SPROG 3 [v2|Plus] module
017 *
018 * @author Andrew Crosland Copyright (C) 2021
019 */
020public class Sprog3PlusEditNVPane extends AbstractEditNVPane {
021    
022    private CmdStaFlags [] csFlags = new CmdStaFlags[4];
023    
024    private final UpdateNV cmdStaNoUpdateFn = new UpdateCmdStaNo();
025    private final UpdateNV canIdUpdateFn = new UpdateCanId();
026    private final UpdateNV nodeNumberUpdateFn = new UpdateNodeNumber();
027    private final UpdateNV currentLimitUpdateFn = new UpdateCurrentLimit();
028    private final UpdateNV accyPktUpdateFn = new UpdateAccyCount();
029    private final UpdateNV nnMapUpdateFn = new UpdateNnMap();
030    private final UpdateNV preambleUpdateFn = new UpdatePreamble();
031    private final UpdateNV powerModeUpdateFn = new UpdatePowerMode();
032    private final UpdateNV meterUpdateFn = new UpdateMeter();
033    private final UpdateNV flagUpdateFn = new UpdateFlags();
034    
035    private TitledSpinner cmdStaNoSpinner;
036    private JComboBox<String> powerModeList ;
037    private TitledSpinner mainSpinner;
038    private TitledSpinner progSpinner;
039    private TitledSpinner accyPktSpinner;
040    private JRadioButton meter;
041    private TitledSpinner nnMapDccSpinner;
042    private JRadioButton setup;
043    private TitledSpinner canIdSpinner;
044    private TitledSpinner nodeNumberSpinner;
045    private TitledSpinner preambleSpinner;
046    private JRadioButton disable ;
047            
048    protected String flagTitleStrings[] = new String[] {
049        Bundle.getMessage("UserFlags"),
050        Bundle.getMessage("OperationsFlags"),
051        Bundle.getMessage("DebugFlags"),
052        Bundle.getMessage("UserFlags2")
053    };
054
055    protected String flagStrings[][] = new String[][] {
056        // User
057        {Bundle.getMessage("Reserved"),
058            Bundle.getMessage("PermitSteal"),
059            Bundle.getMessage("PermitShare"),
060            Bundle.getMessage("Reserved"),
061            Bundle.getMessage("MapEvents"),
062            Bundle.getMessage("StopOnTimeout"),
063            Bundle.getMessage("StartOfDay"),
064            Bundle.getMessage("AutoPower")},
065        // Ops
066        {Bundle.getMessage("Reserved"),
067            Bundle.getMessage("Reserved"),
068            Bundle.getMessage("Reserved"),
069            Bundle.getMessage("ZtcMode"),
070            Bundle.getMessage("AllStopTrackOff"),
071            Bundle.getMessage("BluelineMode"),
072            Bundle.getMessage("AckSensitivity"),
073            Bundle.getMessage("Reserved")},
074        // Debug
075        {Bundle.getMessage("Reserved"),
076            Bundle.getMessage("Reserved"),
077            Bundle.getMessage("Reserved"),
078            Bundle.getMessage("Reserved"),
079            Bundle.getMessage("Reserved"),
080            Bundle.getMessage("Reserved"),
081            Bundle.getMessage("Reserved"),
082            Bundle.getMessage("Reserved")},
083        // User 2
084        {Bundle.getMessage("MapEventsOffset"),
085            Bundle.getMessage("Reserved"),
086            Bundle.getMessage("Reserved"),
087            Bundle.getMessage("Reserved"),
088            Bundle.getMessage("Reserved"),
089            Bundle.getMessage("Reserved"),
090            Bundle.getMessage("Reserved"),
091            Bundle.getMessage("Reserved")
092        }};
093
094    protected String flagTtStrings[][] = new String[][] {
095        // User
096        {Bundle.getMessage("ReservedTt"),
097            Bundle.getMessage("PermitStealTt"),
098            Bundle.getMessage("PermitShareTt"),
099            Bundle.getMessage("ReservedTt"),
100            Bundle.getMessage("MapEventsTt"),
101            Bundle.getMessage("StopOnTimeoutTt"),
102            Bundle.getMessage("StartOfDayTt"),
103            Bundle.getMessage("AutoPowerTt")},
104        // Ops
105        {Bundle.getMessage("ReservedTt"),
106            Bundle.getMessage("ReservedTt"),
107            Bundle.getMessage("ReservedTt"),
108            Bundle.getMessage("ZtcModeTt"),
109            Bundle.getMessage("AllStopTrackOffTt"),
110            Bundle.getMessage("BluelineModeTt"),
111            Bundle.getMessage("AckSensitivityTt"),
112            Bundle.getMessage("ReservedTt")},
113        // Debug
114        {Bundle.getMessage("ReservedTt"),
115            Bundle.getMessage("ReservedTt"),
116            Bundle.getMessage("ReservedTt"),
117            Bundle.getMessage("ReservedTt"),
118            Bundle.getMessage("ReservedTt"),
119            Bundle.getMessage("ReservedTt"),
120            Bundle.getMessage("ReservedTt"),
121            Bundle.getMessage("ReservedTt")},
122        // User 2
123        {Bundle.getMessage("MapEventsOffsetTt"),
124            Bundle.getMessage("ReservedTt"),
125            Bundle.getMessage("ReservedTt"),
126            Bundle.getMessage("ReservedTt"),
127            Bundle.getMessage("ReservedTt"),
128            Bundle.getMessage("ReservedTt"),
129            Bundle.getMessage("ReservedTt"),
130            Bundle.getMessage("ReservedTt")
131        }};
132
133    protected Sprog3PlusEditNVPane(CbusNodeNVTableDataModel dataModel, CbusNode node) {
134        super(dataModel, node);
135    }
136    
137    /** {@inheritDoc} */
138    @Override
139    public AbstractEditNVPane getContent() {
140        
141        JTabbedPane tabbedPane = new JTabbedPane();
142        
143        JPanel cmdStaPane = new CmdStaPane();
144        JPanel dccPane = new DccPane();
145        JPanel cbusPane = new CbusPane();
146        tabbedPane.addTab(Bundle.getMessage("CmdSta"), cmdStaPane);
147        tabbedPane.addTab("DCC", dccPane);
148        tabbedPane.addTab("CBUS Diagnostics", cbusPane);
149        
150        JScrollPane scroll = new JScrollPane(tabbedPane);
151        add(scroll);
152        
153        return this;
154    }
155
156    /** {@inheritDoc} */
157    @Override
158    public void tableChanged(TableModelEvent e) {
159        if (e.getType() == TableModelEvent.UPDATE) {
160            int row = e.getFirstRow();
161            int nv = row + 1;
162            int value = getSelectValue8(nv);
163            log.debug("sprog3plus gui table changed NV: {} Value: {}", nv, value);
164            
165            switch (nv) {
166                case Sprog3PlusPaneProvider.CMD_STATION_NUMBER:
167                    cmdStaNoSpinner.setValue(value);
168                    break;
169                    
170                case Sprog3PlusPaneProvider.USER_FLAGS:
171                    csFlags[0].setFlags(value);
172                    break;
173                    
174                case Sprog3PlusPaneProvider.OPERATIONS_FLAGS:
175                    csFlags[1].setFlags(value);
176                    break;
177                    
178                case Sprog3PlusPaneProvider.DEBUG_FLAGS:
179                    csFlags[2].setFlags(value);
180                    break;
181                            
182                case Sprog3PlusPaneProvider.USER_FLAGS_2:
183                    csFlags[3].setFlags(value);
184                    break;
185                            
186                case Sprog3PlusPaneProvider.PROG_TRACK_POWER_MODE:
187                    // Do nothing if nothing has changed, else causes an endless
188                    // round of gui update, table update, ...
189                    if (value != powerModeList.getSelectedIndex()) {
190                        powerModeList.setSelectedIndex(value);
191                    }
192                    break;
193                    
194                case Sprog3PlusPaneProvider.PROG_TRACK_CURRENT_LIMIT:
195                    double progLimit = (double)value/100;
196                    progSpinner.setValue(progLimit);
197                    break;
198                
199                case Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT_LIMIT:
200                    double mainLimit = (double)value/100;
201                    mainSpinner.setValue(mainLimit);
202                    break;
203                    
204                case Sprog3PlusPaneProvider.ACCY_PACKET_REPEAT_COUNT:
205                    accyPktSpinner.setValue(value);
206                    break;
207                    
208                case Sprog3PlusPaneProvider.MULTIMETER_MODE:
209                    meter.setSelected(value != 0);
210                    break;
211                    
212                case Sprog3PlusPaneProvider.NN_MAP_DCC_HI:
213                case Sprog3PlusPaneProvider.NN_MAP_DCC_LO:
214                    nnMapDccSpinner.setValue(getSelectValue16(Sprog3PlusPaneProvider.NN_MAP_DCC_HI,
215                            Sprog3PlusPaneProvider.NN_MAP_DCC_LO, 0, 65535));
216                    break;
217                    
218                case Sprog3PlusPaneProvider.SETUP:
219                    setup.setSelected(value != 0);
220                    break;
221                    
222                case Sprog3PlusPaneProvider.CANID:
223                    canIdSpinner.setValue(value);
224                    break;
225                    
226                case Sprog3PlusPaneProvider.NN_HI:
227                case Sprog3PlusPaneProvider.NN_LO:
228                    nodeNumberSpinner.setValue(getSelectValue16(Sprog3PlusPaneProvider.NN_HI, 
229                            Sprog3PlusPaneProvider.NN_LO,
230                            Sprog3PlusPaneProvider.MIN_NN,
231                            Sprog3PlusPaneProvider.MAX_NN));
232                    break;
233                    
234                case Sprog3PlusPaneProvider.DCC_PREAMBLE:
235                    preambleSpinner.setValue(value);
236                    break;
237                    
238                case Sprog3PlusPaneProvider.CAN_DISABLE:
239                    disable.setEnabled(value != 0);
240                    break;
241
242                case Sprog3PlusPaneProvider.INPUT_VOLTAGE:
243                case Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT:
244                case Sprog3PlusPaneProvider.PROG_TRACK_CURRENT:
245                case Sprog3PlusPaneProvider.MAIN_HIGH_WATER_MARK:
246                case Sprog3PlusPaneProvider.PROG_HIGH_WATER_MARK:
247                    // These read-only NVs are not preented in the edit GUI as they can be displayed on meters
248                    break;
249                    
250                default:
251                    // Not used, or row was -1
252//                    log.debug("Update unknown NV {}", nv);
253                    
254            }
255        }
256    }
257    
258    /**
259     * Update the command station number
260     */
261    protected class UpdateCmdStaNo implements UpdateNV {
262        
263        /** {@inheritDoc} */
264        @Override
265        public void setNewVal(int index) {
266            int cmdStaNo = cmdStaNoSpinner.getIntegerValue();
267            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
268            _dataModel.setValueAt(cmdStaNo, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
269        }
270    }
271        
272    /**
273     * Update the Flags
274     */
275    protected class UpdateFlags implements UpdateNV {
276        
277        /** {@inheritDoc} */
278        @Override
279        public void setNewVal(int index) {
280            int flags = csFlags[index].getFlags();
281            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
282            _dataModel.setValueAt(flags, csFlags[index].getNv() - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
283        }
284    }
285        
286    /**
287     * Update the CAN ID
288     * 
289     * For debug only, CAN ID is not normally set this way
290     */
291    protected class UpdateCanId implements UpdateNV {
292        
293        /** {@inheritDoc} */
294        @Override
295        public void setNewVal(int index) {
296            int canId = canIdSpinner.getIntegerValue();
297            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
298            _dataModel.setValueAt(canId, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
299        }
300    }
301        
302    /**
303     * Update the node number
304     * 
305     * For debug only, CAN ID is not normally set this way
306     */
307    protected class UpdateNodeNumber implements UpdateNV {
308        
309        /** {@inheritDoc} */
310        @Override
311        public void setNewVal(int index) {
312            int nn = nodeNumberSpinner.getIntegerValue();
313            int nnHi = nn/256;
314            int nnLo = nn%256;
315            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
316            _dataModel.setValueAt(nnHi, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
317            _dataModel.setValueAt(nnLo, index, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
318        }
319    }
320    
321    /**
322     * Update the multi meter events setting
323     */
324    protected class UpdateMeter implements UpdateNV {
325        
326        /** {@inheritDoc} */
327        @Override
328        public void setNewVal(int index) {
329            int mode = meter.isSelected() ? 1 : 0;
330            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
331            _dataModel.setValueAt(mode, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
332        }
333    }
334    
335    /**
336     * Update a current Limit
337     */
338    protected class UpdateCurrentLimit implements UpdateNV {
339        
340        /** {@inheritDoc} */
341        @Override
342        public void setNewVal(int index) {
343            int limit;
344            double fLimit;
345            if (index == Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT_LIMIT) {
346                fLimit = mainSpinner.getDoubleValue();
347            } else {
348                fLimit = progSpinner.getDoubleValue();
349            }
350            // Limit to 10mA precision
351            limit = (int)(fLimit*100 + 0.5);
352            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
353            _dataModel.setValueAt(limit, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
354        }
355    }
356    
357    /**
358     * Update the number of times a DCC accessory packet is repeated
359     */
360    protected class UpdateAccyCount implements UpdateNV {
361        
362        /** {@inheritDoc} */
363        @Override
364        public void setNewVal(int index) {
365            int cnt = accyPktSpinner.getIntegerValue();
366            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
367            _dataModel.setValueAt(cnt, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
368        }
369    }
370
371    /**
372     * Update the Node Number of events to be mapped to DCC accessory commands
373     */
374    protected class UpdateNnMap implements UpdateNV {
375        
376        /** {@inheritDoc} */
377        @Override
378        public void setNewVal(int index) {
379            int mapNn = nnMapDccSpinner.getIntegerValue();
380            int mapNnHi = mapNn/256;
381            int mapNnLo = mapNn%256;
382            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
383            _dataModel.setValueAt(mapNnHi, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
384            _dataModel.setValueAt(mapNnLo, index, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
385        }
386    }
387
388    /**
389     * Update the number of DCC packet preamble bits
390     */
391    protected class UpdatePreamble implements UpdateNV {
392        
393        /** {@inheritDoc} */
394        @Override
395        public void setNewVal(int index) {
396            int pre = preambleSpinner.getIntegerValue();
397            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
398            _dataModel.setValueAt(pre, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
399        }
400    }
401    
402    /**
403     * Update the command station power mode
404     */
405    protected class UpdatePowerMode implements UpdateNV {
406        
407        /** {@inheritDoc} */
408        @Override
409        public void setNewVal(int index) {
410            log.debug("UpdatePowerMode.setNewVal()");
411            int mode = powerModeList.getSelectedIndex();
412            // Note that changing the data model will result in tableChanged() being called, which can manipulate the buttons, etc
413            _dataModel.setValueAt(mode, index - 1, CbusNodeNVTableDataModel.NV_SELECT_COLUMN);
414        }
415    }
416    
417    public class CmdStaPane extends JPanel {
418
419        /**
420         * Panel to display command station NVs
421         */
422        public CmdStaPane() {
423            super();
424
425            JPanel gridPane = new JPanel(new GridBagLayout());
426            GridBagConstraints c = new GridBagConstraints();
427            c.fill = GridBagConstraints.HORIZONTAL;
428
429            int flagPanels = 3;
430            if (_node.getNodeParamManager().isFwEqualOrNewer(2, 'e', 2)) {
431                flagPanels = 4;
432            }
433            JPanel [] flagPane = new JPanel[flagPanels];
434            
435            int [] flagNvs = {Sprog3PlusPaneProvider.USER_FLAGS,
436                Sprog3PlusPaneProvider.OPERATIONS_FLAGS,
437                Sprog3PlusPaneProvider.DEBUG_FLAGS,
438                Sprog3PlusPaneProvider.USER_FLAGS_2};
439            
440            for (int i = 0; i < flagPanels; i++) {
441                csFlags[i] = new CmdStaFlags(i, flagNvs[i], flagTitleStrings[i], flagStrings[i], flagTtStrings[i], flagUpdateFn);
442                csFlags[i].setFlags(getSelectValue8(flagNvs[i]));
443                flagPane[i] = csFlags[i].getContents();
444            }
445            
446            String powerModeStrings [] = new String[] {Bundle.getMessage("ProgOffMode"),
447                Bundle.getMessage("ProgOnMode"),
448                Bundle.getMessage("ProgArMode")
449            };
450            
451            c.weightx = 1;
452            c.weighty = 1;
453            c.gridx = 0;
454            c.gridy = 0;
455
456            // x = 1
457            cmdStaNoSpinner = new TitledSpinner(Bundle.getMessage("CmdStaNo"), Sprog3PlusPaneProvider.CMD_STATION_NUMBER, cmdStaNoUpdateFn);
458            cmdStaNoSpinner.setToolTip(Bundle.getMessage("CmdStaNoTt"));
459            cmdStaNoSpinner.init(0, 0, 255, 1);
460            gridPane.add(cmdStaNoSpinner, c);
461            c.gridy++;
462            
463            c.gridwidth = flagPanels;
464            powerModeList = new JComboBox<>(powerModeStrings);
465            powerModeList.setSelectedIndex(getSelectValue8(Sprog3PlusPaneProvider.PROG_TRACK_POWER_MODE));
466            powerModeList.addActionListener((ActionEvent e) -> {
467                pwrModeActionListener(e);
468            });
469            gridPane.add(powerModeList, c);
470            c.gridwidth = 1;
471            c.gridy++;
472            
473            meter = new JRadioButton(Bundle.getMessage("Multimeter"));
474            meter.setSelected(false);
475            meter.setToolTipText(Bundle.getMessage("MultimeterTt"));
476            meter.addActionListener((ActionEvent e) -> {
477                meterActionListener(e);
478            });
479            gridPane.add(meter, c);
480            c.gridy++;
481            
482            mainSpinner = new TitledSpinner(Bundle.getMessage("MainLimit"), Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT_LIMIT, currentLimitUpdateFn);
483            mainSpinner.setToolTip(Bundle.getMessage("MainLimitTt"));
484            mainSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.MAIN_TRACK_CURRENT_LIMIT, 100)/100.0, 1.0, 2.5, 0.01);
485            gridPane.add(mainSpinner, c);
486            c.gridx++;
487            
488            progSpinner = new TitledSpinner(Bundle.getMessage("ProgLimit"), Sprog3PlusPaneProvider.PROG_TRACK_CURRENT_LIMIT, currentLimitUpdateFn);
489            progSpinner.setToolTip(Bundle.getMessage("ProgLimitTt"));
490            progSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.PROG_TRACK_CURRENT_LIMIT, 100)/100.0, 1.0, 2.5, 0.01);
491            gridPane.add(progSpinner, c);
492            
493            c.gridy++;
494            c.gridx = 0;
495            
496            for (int i = 0; i < flagPanels; i++) {
497                gridPane.add(flagPane[i], c);
498                c.gridx++;
499            }
500            
501            add(gridPane);
502        }
503        
504        /**
505         * Action listener for the command station power mode
506         * 
507         * @param e the action event
508         */
509        protected void pwrModeActionListener(ActionEvent e) {
510            log.debug("pwrModeActionListener()");
511            powerModeUpdateFn.setNewVal(Sprog3PlusPaneProvider.PROG_TRACK_POWER_MODE);
512        }
513        
514        /**
515         * Action listener for multimeter nmode selection
516         * 
517         * @param e the action event
518         */
519        protected void meterActionListener(ActionEvent e) {
520            meterUpdateFn.setNewVal(Sprog3PlusPaneProvider.MULTIMETER_MODE);
521        }
522    }
523    
524    /**
525     * Panel to display DCC related NVs
526     */
527    public class DccPane extends JPanel {
528        public DccPane() {
529            super();
530
531            JPanel gridPane = new JPanel(new GridBagLayout());
532            GridBagConstraints c = new GridBagConstraints();
533            c.fill = GridBagConstraints.HORIZONTAL;
534
535            c.weightx = 1;
536            c.weighty = 1;
537            c.gridx = 0;
538            c.gridy = 0;
539            
540            accyPktSpinner = new TitledSpinner(Bundle.getMessage("AccyPktCnt"), Sprog3PlusPaneProvider.ACCY_PACKET_REPEAT_COUNT, accyPktUpdateFn);
541            accyPktSpinner.setToolTip(Bundle.getMessage("AccyPktCntTt"));
542            accyPktSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.ACCY_PACKET_REPEAT_COUNT, 1), 1, 7, 1);
543            gridPane.add(accyPktSpinner, c);
544            c.gridy++;
545            
546            nnMapDccSpinner = new TitledSpinner(Bundle.getMessage("NnMapDcc"), Sprog3PlusPaneProvider.NN_MAP_DCC_HI, nnMapUpdateFn);
547            nnMapDccSpinner.setToolTip(Bundle.getMessage("NnMapDccTt"));
548            int nn = getSelectValue16(Sprog3PlusPaneProvider.NN_MAP_DCC_HI, Sprog3PlusPaneProvider.NN_MAP_DCC_LO, 0, 65535);
549            nnMapDccSpinner.init(nn, 0, 65535, 1);
550            gridPane.add(nnMapDccSpinner, c);
551            c.gridy++;
552            
553            gridPane.add(nnMapDccSpinner, c);
554            c.gridy++;
555
556            preambleSpinner = new TitledSpinner(Bundle.getMessage("DccPreambles"), Sprog3PlusPaneProvider.DCC_PREAMBLE, preambleUpdateFn);
557            preambleSpinner.setToolTip(Bundle.getMessage("DccPreamblesTt"));
558            preambleSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.DCC_PREAMBLE, 14), 14, 32, 1);
559            gridPane.add(preambleSpinner, c);
560                    
561            add(gridPane);
562        }
563    }
564    
565    /**
566     * Panel to display CBUS operation related NVs
567     */
568    public class CbusPane extends JPanel {
569        public CbusPane() {
570            super();
571
572            JPanel gridPane = new JPanel(new GridBagLayout());
573            GridBagConstraints c = new GridBagConstraints();
574            c.fill = GridBagConstraints.HORIZONTAL;
575
576            c.weightx = 1;
577            c.weighty = 1;
578            c.gridx = 0;
579            c.gridy = 0;
580
581            canIdSpinner = new TitledSpinner(Bundle.getMessage("CanId"), Sprog3PlusPaneProvider.CANID, canIdUpdateFn);
582            canIdSpinner.setToolTip(Bundle.getMessage("CanIdTt"));
583            canIdSpinner.init(getSelectValue8(Sprog3PlusPaneProvider.CANID, Sprog3PlusPaneProvider.MIN_CANID, Sprog3PlusPaneProvider.MAX_CANID), 100, 127, 1);
584            gridPane.add(canIdSpinner, c);
585            c.gridy++;
586
587            nodeNumberSpinner = new TitledSpinner(Bundle.getMessage("NodeNumber"), Sprog3PlusPaneProvider.NN_HI, nodeNumberUpdateFn);
588            nodeNumberSpinner.setToolTip(Bundle.getMessage("NodeNumberTt"));
589            int nn = getSelectValue16(Sprog3PlusPaneProvider.NN_HI, Sprog3PlusPaneProvider.NN_LO, Sprog3PlusPaneProvider.MIN_NN, Sprog3PlusPaneProvider.MAX_NN);
590            nodeNumberSpinner.init(nn, 65520, 65534, 1);
591            gridPane.add(nodeNumberSpinner, c);
592            c.gridy++;
593            
594            setup = new JRadioButton("SetupMode");
595            setup.setSelected(false);
596            setup.setToolTipText(Bundle.getMessage("SetupModeTt"));
597            gridPane.add(setup, c);
598            c.gridy++;
599            
600            disable = new JRadioButton("DisableCan");
601            disable.setSelected(false);
602            disable.setToolTipText(Bundle.getMessage("DisableCanTt"));
603            gridPane.add(disable, c);
604            c.gridy++;
605            
606            add(gridPane);
607        }
608    }
609    
610    private final static Logger log = LoggerFactory.getLogger(Sprog3PlusEditNVPane.class);
611
612}