001package jmri.jmrix.roco.z21.swing.configtool;
002
003import java.awt.GridLayout;
004import java.awt.event.ActionEvent;
005import javax.swing.BorderFactory;
006import javax.swing.BoxLayout;
007import javax.swing.JCheckBox;
008import javax.swing.JLabel;
009import javax.swing.JPanel;
010import javax.swing.JTextField;
011import javax.swing.JToggleButton;
012import jmri.jmrix.roco.z21.RocoZ21CommandStation;
013import jmri.jmrix.roco.z21.Z21Listener;
014import jmri.jmrix.roco.z21.Z21Message;
015import jmri.jmrix.roco.z21.Z21Reply;
016import jmri.jmrix.roco.z21.Z21TrafficController;
017import org.slf4j.Logger;
018import org.slf4j.LoggerFactory;
019
020/**
021 * Frame displaying Version information and broadcast flags for Z21 hardware.
022 * <p>
023 * This is a utility for reading the hardware and software versions of your Z21
024 * command station and along with the flags and the serial number.
025 *
026 * @author Paul Bender Copyright (C) 2016
027 */
028public class Z21ConfigFrame extends jmri.util.JmriJFrame implements Z21Listener {
029
030    /**
031     *
032     */
033    private Z21TrafficController tc;
034    private RocoZ21CommandStation cs;
035
036    /* updatable fields and field labels */
037    private final JToggleButton getSystemInfoButton;
038    private JToggleButton setSystemInfoButton;
039    private final JToggleButton closeButton;
040    private JLabel hardwareVersionLabel;
041    private JTextField hardwareVersionTextField;
042    private JLabel softwareVersionLabel;
043    private JTextField softwareVersionTextField;
044    private JLabel serialNumLabel;
045    private JTextField serialNumTextField;
046
047    // flag checkboxes
048    private JCheckBox xPressNetMessagesCheckBox;
049    private JCheckBox rmBusMessagesCheckBox;
050    private JCheckBox systemStatusMessagesCheckBox;
051    private JCheckBox xPressNetLocomotiveMessagesCheckBox;
052    private JCheckBox railComMessagesCheckBox;
053    private JCheckBox locoNetMessagesCheckBox;
054    private JCheckBox locoNetLocomotiveMessagesCheckBox;
055    private JCheckBox locoNetTurnoutMessagesCheckBox;
056    private JCheckBox locoNetOccupancyMessagesCheckBox;
057    private JCheckBox railComAutomaticCheckBox;
058    private JCheckBox canDetectorCheckBox;
059    private JCheckBox canBoosterCheckBox;
060    private JCheckBox fastClockCheckBox;
061
062    public Z21ConfigFrame(jmri.jmrix.roco.z21.Z21SystemConnectionMemo memo) {
063        super(Bundle.getMessage("Z21ConfigToolMenuItem"));
064        tc = memo.getTrafficController();
065        cs = memo.getRocoZ21CommandStation();
066        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); // prevents strange stretching of content
067
068        // build sub panel for version and serial number
069        getContentPane().add(getSystemInfoPanel());
070
071        // build sub panel for the flag list.
072        getContentPane().add(getBroadcastFlagsPanel());
073
074        // build sub panel with the read and close buttons
075        JPanel buttonPanel = new JPanel();
076        //buttonPanel.setLayout(new GridLayout(1, 2));
077
078        getSystemInfoButton = new JToggleButton(Bundle.getMessage("GetSystemInfoButtonLabel"));
079        getSystemInfoButton.setToolTipText(Bundle.getMessage("GetSystemInfoButtonToolTip"));
080        closeButton = new JToggleButton(Bundle.getMessage("ButtonClose"));
081        closeButton.setToolTipText(Bundle.getMessage("CloseButtonToolTip"));
082        buttonPanel.add(getSystemInfoButton);
083        buttonPanel.add(closeButton);
084        getContentPane().add(buttonPanel);
085
086        addHelpMenu("package.jmri.jmrix.roco.z21.swing.configtool.ConfigToolFrame", true);
087
088        // and prep for display
089        pack();
090
091        // Add Get SystemInfo button handler
092        getSystemInfoButton.addActionListener((ActionEvent a) -> getSystemInfo());
093
094        // install close button handler
095        closeButton.addActionListener((ActionEvent a) -> {
096            setVisible(false);
097            dispose();
098        });
099
100        if (tc != null) {
101            tc.addz21Listener(this);
102        } else {
103            log.warn("No Z21 connection, panel won't function");
104        }
105    }
106
107    private JPanel getSystemInfoPanel() {
108        JPanel panel = new JPanel();
109        panel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SystemInformationTitle")));
110        panel.setLayout(new GridLayout(0, 2));
111
112        hardwareVersionLabel = new JLabel(Bundle.getMessage("HardwareVersionLabel"));
113        hardwareVersionTextField = new JTextField("" + cs.getHardwareVersion());
114        hardwareVersionTextField.setEnabled(false);
115        panel.add(hardwareVersionLabel);
116        panel.add(hardwareVersionTextField);
117
118        softwareVersionLabel = new JLabel(Bundle.getMessage("SoftwareVersionLabel"));
119        softwareVersionTextField = new JTextField("" + cs.getSoftwareVersion());
120        softwareVersionTextField.setEnabled(false);
121        panel.add(softwareVersionLabel);
122        panel.add(softwareVersionTextField);
123
124        serialNumLabel = new JLabel(Bundle.getMessage("SerialNumberLabel"));
125        serialNumTextField = new JTextField("" + cs.getSerialNumber());
126        serialNumTextField.setEnabled(false);
127
128        panel.add(serialNumLabel);
129        panel.add(serialNumTextField);
130
131        return panel;
132    }
133
134    private JPanel getBroadcastFlagsPanel() {
135        JPanel panel = new JPanel();
136        panel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BroadcastFlagsTitle")));
137        panel.setLayout(new GridLayout(0, 1));
138
139        JPanel xNetPanel = new JPanel();
140        xNetPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("XNetFlagsTitle")));
141        xNetPanel.setLayout(new GridLayout(0, 2));
142
143        xPressNetMessagesCheckBox = new JCheckBox(Bundle.getMessage("XpressNetMessagesFlagLabel"), cs.getXPressNetMessagesFlag());
144        xPressNetMessagesCheckBox.setToolTipText(Bundle.getMessage("XpressNetMessagesFlagToolTip"));
145        xNetPanel.add(xPressNetMessagesCheckBox);
146
147        xPressNetLocomotiveMessagesCheckBox = new JCheckBox(Bundle.getMessage("XpressNetLocomotiveMessagesFlagLabel"), cs.getXPressNetLocomotiveMessagesFlag());
148        xPressNetLocomotiveMessagesCheckBox.setToolTipText(Bundle.getMessage("XpressNetLocomotiveMessagesFlagToolTip"));
149        xNetPanel.add(xPressNetLocomotiveMessagesCheckBox);
150
151        panel.add(xNetPanel);
152
153        JPanel locoNetPanel = new JPanel();
154        locoNetPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("LocoNetFlagsTitle")));
155        locoNetPanel.setLayout(new GridLayout(0, 2));
156
157        locoNetMessagesCheckBox = new JCheckBox(Bundle.getMessage("LocoNetMessagesFlagLabel"), cs.getLocoNetMessagesFlag());
158        locoNetMessagesCheckBox.setToolTipText(Bundle.getMessage("LocoNetMessagesFlagToolTip"));
159        locoNetPanel.add(locoNetMessagesCheckBox);
160
161        locoNetLocomotiveMessagesCheckBox = new JCheckBox(Bundle.getMessage("LocoNetLocomotiveMessagesFlagLabel"), cs.getLocoNetLocomotiveMessagesFlag());
162        locoNetLocomotiveMessagesCheckBox.setToolTipText(Bundle.getMessage("LocoNetLocomotiveMessagesFlagToolTip"));
163        locoNetPanel.add(locoNetLocomotiveMessagesCheckBox);
164
165        locoNetTurnoutMessagesCheckBox = new JCheckBox(Bundle.getMessage("LocoNetTurnoutMessagesFlagLabel"), cs.getLocoNetTurnoutMessagesFlag());
166        locoNetTurnoutMessagesCheckBox.setToolTipText(Bundle.getMessage("LocoNetTurnoutMessagesFlagToolTip"));
167        locoNetPanel.add(locoNetTurnoutMessagesCheckBox);
168
169        locoNetOccupancyMessagesCheckBox = new JCheckBox(Bundle.getMessage("LocoNetOccupancyMessagesFlagLabel"), cs.getLocoNetOccupancyMessagesFlag());
170        locoNetOccupancyMessagesCheckBox.setToolTipText(Bundle.getMessage("LocoNetOccupancyMessagesFlagToolTip"));
171        locoNetPanel.add(locoNetOccupancyMessagesCheckBox);
172
173        panel.add(locoNetPanel);
174
175        JPanel canPanel = new JPanel();
176        canPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("canFlagsTitle")));
177        canPanel.setLayout(new GridLayout(0, 2));
178
179        canDetectorCheckBox = new JCheckBox(Bundle.getMessage("canDetectorFlagLabel"), cs.getCanDetectorFlag());
180        canDetectorCheckBox.setToolTipText(Bundle.getMessage("canDetectorFlagToolTip"));
181        canPanel.add(canDetectorCheckBox);
182
183        canBoosterCheckBox = new JCheckBox(Bundle.getMessage("canBoosterFlagLabel"), cs.getCanBoosterFlag());
184        canBoosterCheckBox.setToolTipText(Bundle.getMessage("canBoosterFlagToolTip"));
185        canPanel.add(canBoosterCheckBox);
186
187        panel.add(canPanel);
188
189        JPanel systemPanel = new JPanel();
190        systemPanel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SystemFlagsTitle")));
191        systemPanel.setLayout(new GridLayout(0, 2));
192
193        rmBusMessagesCheckBox = new JCheckBox(Bundle.getMessage("RMBusMessagesFlagLabel"), cs.getRMBusMessagesFlag());
194        rmBusMessagesCheckBox.setToolTipText(Bundle.getMessage("RMBusMessagesFlagToolTip"));
195        systemPanel.add(rmBusMessagesCheckBox);
196
197        systemStatusMessagesCheckBox = new JCheckBox(Bundle.getMessage("SystemStatusMessagesFlagLabel"), cs.getSystemStatusMessagesFlag());
198        systemStatusMessagesCheckBox.setToolTipText(Bundle.getMessage("SystemStatusMessagesFlagToolTip"));
199        systemPanel.add(systemStatusMessagesCheckBox);
200
201        railComMessagesCheckBox = new JCheckBox(Bundle.getMessage("RailComMessagesFlagLabel"), cs.getRailComMessagesFlag());
202        railComMessagesCheckBox.setToolTipText(Bundle.getMessage("RailComMessagesFlagToolTip"));
203        systemPanel.add(railComMessagesCheckBox);
204
205        railComAutomaticCheckBox = new JCheckBox(Bundle.getMessage("RailComAutomaticFlagLabel"), cs.getRailComAutomaticFlag());
206        railComMessagesCheckBox.setToolTipText(Bundle.getMessage("RailComAutomaticFlagToolTip"));
207        systemPanel.add(railComAutomaticCheckBox);
208
209        fastClockCheckBox = new JCheckBox(Bundle.getMessage("FastClockFlagLabel"), cs.getFastClockFlag());
210        fastClockCheckBox.setToolTipText(Bundle.getMessage("FastClockFlagToolTip"));
211        systemPanel.add(fastClockCheckBox);
212
213        panel.add(systemPanel);
214
215        setSystemInfoButton = new JToggleButton(Bundle.getMessage("SetSystemInfoButtonLabel"));
216        setSystemInfoButton.setToolTipText(Bundle.getMessage("SetSystemInfoButtonToolTip"));
217
218        // Add Get SystemInfo button handler
219        setSystemInfoButton.addActionListener((ActionEvent a) -> writeSystemInfo());
220        panel.add(setSystemInfoButton);
221
222        return panel;
223    }
224
225    /**
226     * Request command station information.
227     */
228    private void getSystemInfo() {
229        // request the version information
230        tc.sendz21Message(Z21Message.getLanGetHardwareInfoRequestMessage(), this);
231        // request the serial number
232        tc.sendz21Message(Z21Message.getSerialNumberRequestMessage(), this);
233        // request the flags.
234        tc.sendz21Message(Z21Message.getLanGetBroadcastFlagsRequestMessage(), this);
235    }
236
237    /**
238     * Request command station information.
239     */
240    private void writeSystemInfo() {
241        // set the flags in the command station representation based on the
242        // checkboxes.
243        cs.setXPressNetMessagesFlag(xPressNetMessagesCheckBox.isSelected());
244        cs.setRMBusMessagesFlag(rmBusMessagesCheckBox.isSelected());
245        cs.setSystemStatusMessagesFlag(systemStatusMessagesCheckBox.isSelected());
246        cs.setRailComMessagesFlag(railComMessagesCheckBox.isSelected());
247        cs.setRailComAutomaticFlag(railComAutomaticCheckBox.isSelected());
248        cs.setXPressNetLocomotiveMessagesFlag(xPressNetLocomotiveMessagesCheckBox.isSelected());
249        cs.setLocoNetMessagesFlag(locoNetMessagesCheckBox.isSelected());
250        cs.setLocoNetLocomotiveMessagesFlag(locoNetLocomotiveMessagesCheckBox.isSelected());
251        cs.setLocoNetTurnoutMessagesFlag(locoNetTurnoutMessagesCheckBox.isSelected());
252        cs.setLocoNetOccupancyMessagesFlag(locoNetOccupancyMessagesCheckBox.isSelected());
253        cs.setCanDetectorFlag(canDetectorCheckBox.isSelected());
254        cs.setCanBoosterFlag(canBoosterCheckBox.isSelected());
255        cs.setFastClockFlag(fastClockCheckBox.isSelected());
256
257        // send the flags to the command station.
258        tc.sendz21Message(Z21Message.getLanSetBroadcastFlagsRequestMessage(cs.getZ21BroadcastFlags()), this);
259    }
260
261    /**
262     * Listen for responses from the Z21.
263     *
264     * @param zr the reply
265     */
266    @Override
267    public void reply(Z21Reply zr) {
268        switch (zr.getOpCode()) {
269            // handle replies with the serial number
270            case 0x0010:
271                // the serial number is a 32 bit integer stored in little
272                // endian format starting with the 1st databyte (element 4).
273                int serialNo = (zr.getElement(4)&0xff) + ((zr.getElement(5)&0xff) << 8)
274                        + ((zr.getElement(6)&0xff) << 16) + ((zr.getElement(7)&0xff) << 24);
275                cs.setSerialNumber(serialNo);
276                updateSerialNumber();
277                break;
278            // handle replies with the hardware and software version.
279            case 0x001A:
280                // the hardware version is a 32 bit integer stored in little
281                // endian format starting with the 1st databyte (element 4).
282                int hwversion = zr.getElement(4) + (zr.getElement(5) << 8)
283                        + (zr.getElement(6) << 16) + (zr.getElement(7) << 24);
284                cs.setHardwareVersion(hwversion);
285                // the software version is a 32 bit integer stored in little
286                // endian format and written in BCD, starting after the hardware
287                // version (element 8).  The least significant byte is to be
288                // treated as a decimal.
289                float swversion = (zr.getElementBCD(8) / 100.0f)
290                        + (zr.getElementBCD(9))
291                        + (zr.getElementBCD(10) * 100)
292                        + (zr.getElementBCD(11)) * 10000;
293                cs.setSoftwareVersion(swversion);
294                updateVersionInformation();
295                break;
296            // handle replies with the flags.
297            case 0x0051:
298                // the payload is a 32 bit integer stored in little endian format
299                // starting with the 1st databyte (element 4).
300                int flags = zr.getElement(4) + (zr.getElement(5) << 8)
301                        + (zr.getElement(6) << 16) + (zr.getElement(7) << 24);
302                cs.setZ21BroadcastFlags(flags);
303                updateFlagInformation();
304                break;
305            default:
306                // ignore all other message types.
307                log.debug("unhandled op-code received.");
308        }
309    }
310
311    /**
312     * Listen for the messages sent to the Z21.
313     *
314     * @param zm the message to listen for
315     */
316    @Override
317    public void message(Z21Message zm) {
318    }
319
320    @Override
321    public void dispose() {
322        // remove the listener for this object.
323        tc.removez21Listener(this);
324        // take apart the JFrame
325        super.dispose();
326    }
327
328    /**
329     * Read the versions displayed from the command station representation.
330     */
331    private void updateVersionInformation() {
332        hardwareVersionTextField.setText("0x" + java.lang.Integer.toHexString(cs.getHardwareVersion()));
333        softwareVersionTextField.setText("" + cs.getSoftwareVersion());
334    }
335
336    /**
337     * Read the serial number from the command station representation.
338     */
339    private void updateSerialNumber() {
340        serialNumTextField.setText("" + cs.getSerialNumber());
341    }
342
343    /**
344     * Read the flags displayed from the command station representation.
345     */
346    private void updateFlagInformation() {
347        xPressNetMessagesCheckBox.setSelected(cs.getXPressNetMessagesFlag());
348        rmBusMessagesCheckBox.setSelected(cs.getRMBusMessagesFlag());
349        systemStatusMessagesCheckBox.setSelected(cs.getSystemStatusMessagesFlag());
350        xPressNetLocomotiveMessagesCheckBox.setSelected(cs.getXPressNetLocomotiveMessagesFlag());
351        railComMessagesCheckBox.setSelected(cs.getRailComMessagesFlag());
352        locoNetMessagesCheckBox.setSelected(cs.getLocoNetMessagesFlag());
353        locoNetLocomotiveMessagesCheckBox.setSelected(cs.getLocoNetLocomotiveMessagesFlag());
354        locoNetTurnoutMessagesCheckBox.setSelected(cs.getLocoNetTurnoutMessagesFlag());
355        locoNetOccupancyMessagesCheckBox.setSelected(cs.getLocoNetOccupancyMessagesFlag());
356    }
357
358    private final static Logger log = LoggerFactory.getLogger(Z21ConfigFrame.class);
359
360}