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
060    public Z21ConfigFrame(jmri.jmrix.roco.z21.Z21SystemConnectionMemo memo) {
061        super(Bundle.getMessage("Z21ConfigToolMenuItem"));
062        tc = memo.getTrafficController();
063        cs = memo.getRocoZ21CommandStation();
064        getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); // prevents strange stretching of content
065
066        // build sub panel for version and serial number
067        getContentPane().add(getSystemInfoPanel());
068
069        // build sub panel for the flag list.
070        getContentPane().add(getBroadcastFlagsPanel());
071
072        // build sub panel with the read and close buttons
073        JPanel buttonPanel = new JPanel();
074        //buttonPanel.setLayout(new GridLayout(1, 2));
075
076        getSystemInfoButton = new JToggleButton(Bundle.getMessage("GetSystemInfoButtonLabel"));
077        getSystemInfoButton.setToolTipText(Bundle.getMessage("GetSystemInfoButtonToolTip"));
078        closeButton = new JToggleButton(Bundle.getMessage("ButtonClose"));
079        closeButton.setToolTipText(Bundle.getMessage("CloseButtonToolTip"));
080        buttonPanel.add(getSystemInfoButton);
081        buttonPanel.add(closeButton);
082        getContentPane().add(buttonPanel);
083
084        addHelpMenu("package.jmri.jmrix.roco.z21.swing.configtool.ConfigToolFrame", true);
085
086        // and prep for display
087        pack();
088
089        // Add Get SystemInfo button handler
090        getSystemInfoButton.addActionListener((ActionEvent a) -> getSystemInfo());
091
092        // install close button handler
093        closeButton.addActionListener((ActionEvent a) -> {
094            setVisible(false);
095            dispose();
096        });
097
098        if (tc != null) {
099            tc.addz21Listener(this);
100        } else {
101            log.warn("No Z21 connection, panel won't function");
102        }
103    }
104
105    private JPanel getSystemInfoPanel() {
106        JPanel panel = new JPanel();
107        panel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("SystemInformationTitle")));
108        panel.setLayout(new GridLayout(0, 2));
109
110        hardwareVersionLabel = new JLabel(Bundle.getMessage("HardwareVersionLabel"));
111        hardwareVersionTextField = new JTextField("" + cs.getHardwareVersion());
112        hardwareVersionTextField.setEnabled(false);
113        panel.add(hardwareVersionLabel);
114        panel.add(hardwareVersionTextField);
115
116        softwareVersionLabel = new JLabel(Bundle.getMessage("SoftwareVersionLabel"));
117        softwareVersionTextField = new JTextField("" + cs.getSoftwareVersion());
118        softwareVersionTextField.setEnabled(false);
119        panel.add(softwareVersionLabel);
120        panel.add(softwareVersionTextField);
121
122        serialNumLabel = new JLabel(Bundle.getMessage("SerialNumberLabel"));
123        serialNumTextField = new JTextField("" + cs.getSerialNumber());
124        serialNumTextField.setEnabled(false);
125
126        panel.add(serialNumLabel);
127        panel.add(serialNumTextField);
128
129        return panel;
130    }
131
132    private JPanel getBroadcastFlagsPanel() {
133        JPanel panel = new JPanel();
134        panel.setBorder(BorderFactory.createTitledBorder(Bundle.getMessage("BroadcastFlagsTitle")));
135        panel.setLayout(new GridLayout(0, 1));
136
137        xPressNetMessagesCheckBox = new JCheckBox(Bundle.getMessage("XpressNetMessagesFlagLabel"), cs.getXPressNetMessagesFlag());
138        xPressNetMessagesCheckBox.setToolTipText(Bundle.getMessage("XpressNetMessagesFlagToolTip"));
139        panel.add(xPressNetMessagesCheckBox);
140
141        rmBusMessagesCheckBox = new JCheckBox(Bundle.getMessage("RMBusMessagesFlagLabel"), cs.getRMBusMessagesFlag());
142        rmBusMessagesCheckBox.setToolTipText(Bundle.getMessage("RMBusMessagesFlagToolTip"));
143        panel.add(rmBusMessagesCheckBox);
144
145        systemStatusMessagesCheckBox = new JCheckBox(Bundle.getMessage("SystemStatusMessagesFlagLabel"), cs.getSystemStatusMessagesFlag());
146        systemStatusMessagesCheckBox.setToolTipText(Bundle.getMessage("RMBusMessagesFlagToolTip"));
147        panel.add(systemStatusMessagesCheckBox);
148
149        xPressNetLocomotiveMessagesCheckBox = new JCheckBox(Bundle.getMessage("XpressNetLocomotiveMessagesFlagLabel"), cs.getXPressNetLocomotiveMessagesFlag());
150        xPressNetLocomotiveMessagesCheckBox.setToolTipText(Bundle.getMessage("XpressNetLocomotiveMessagesFlagToolTip"));
151        panel.add(xPressNetLocomotiveMessagesCheckBox);
152
153        railComMessagesCheckBox = new JCheckBox(Bundle.getMessage("RailComMessagesFlagLabel"), cs.getRailComMessagesFlag());
154        railComMessagesCheckBox.setToolTipText(Bundle.getMessage("RailComMessagesFlagToolTip"));
155        panel.add(railComMessagesCheckBox);
156
157        railComAutomaticCheckBox = new JCheckBox(Bundle.getMessage("RailComAutomaticFlagLabel"), cs.getRailComAutomaticFlag());
158        railComMessagesCheckBox.setToolTipText(Bundle.getMessage("RailComAutomaticFlagToolTip"));
159        panel.add(railComAutomaticCheckBox);
160
161        locoNetMessagesCheckBox = new JCheckBox(Bundle.getMessage("LocoNetMessagesFlagLabel"), cs.getLocoNetMessagesFlag());
162        locoNetMessagesCheckBox.setToolTipText(Bundle.getMessage("LocoNetMessagesFlagToolTip"));
163        panel.add(locoNetMessagesCheckBox);
164
165        locoNetLocomotiveMessagesCheckBox = new JCheckBox(Bundle.getMessage("LocoNetLocomotiveMessagesFlagLabel"), cs.getLocoNetLocomotiveMessagesFlag());
166        locoNetLocomotiveMessagesCheckBox.setToolTipText(Bundle.getMessage("LocoNetLocomotiveMessagesFlagToolTip"));
167        panel.add(locoNetLocomotiveMessagesCheckBox);
168
169        locoNetTurnoutMessagesCheckBox = new JCheckBox(Bundle.getMessage("LocoNetTurnoutMessagesFlagLabel"), cs.getLocoNetTurnoutMessagesFlag());
170        locoNetTurnoutMessagesCheckBox.setToolTipText(Bundle.getMessage("LocoNetTurnoutMessagesFlagToolTip"));
171        panel.add(locoNetTurnoutMessagesCheckBox);
172
173        locoNetOccupancyMessagesCheckBox = new JCheckBox(Bundle.getMessage("LocoNetOccupancyMessagesFlagLabel"), cs.getLocoNetOccupancyMessagesFlag());
174        locoNetOccupancyMessagesCheckBox.setToolTipText(Bundle.getMessage("LocoNetOccupancyMessagesFlagToolTip"));
175        panel.add(locoNetOccupancyMessagesCheckBox);
176
177        canDetectorCheckBox = new JCheckBox(Bundle.getMessage("canDetectorFlagLabel"), cs.getCanDetectorFlag());
178        canDetectorCheckBox.setToolTipText(Bundle.getMessage("canDetectorFlagToolTip"));
179        panel.add(canDetectorCheckBox);
180
181        setSystemInfoButton = new JToggleButton(Bundle.getMessage("SetSystemInfoButtonLabel"));
182        setSystemInfoButton.setToolTipText(Bundle.getMessage("SetSystemInfoButtonToolTip"));
183
184        // Add Get SystemInfo button handler
185        setSystemInfoButton.addActionListener((ActionEvent a) -> writeSystemInfo());
186        panel.add(setSystemInfoButton);
187
188        return panel;
189    }
190
191    /**
192     * Request command station information.
193     */
194    private void getSystemInfo() {
195        // request the version information
196        tc.sendz21Message(Z21Message.getLanGetHardwareInfoRequestMessage(), this);
197        // request the serial number
198        tc.sendz21Message(Z21Message.getSerialNumberRequestMessage(), this);
199        // request the flags.
200        tc.sendz21Message(Z21Message.getLanGetBroadcastFlagsRequestMessage(), this);
201    }
202
203    /**
204     * Request command station information.
205     */
206    private void writeSystemInfo() {
207        // set the flags in the command station representation based on the
208        // checkboxes.
209        cs.setXPressNetMessagesFlag(xPressNetMessagesCheckBox.isSelected());
210        cs.setRMBusMessagesFlag(rmBusMessagesCheckBox.isSelected());
211        cs.setSystemStatusMessagesFlag(systemStatusMessagesCheckBox.isSelected());
212        cs.setRailComMessagesFlag(railComMessagesCheckBox.isSelected());
213        cs.setRailComAutomaticFlag(railComAutomaticCheckBox.isSelected());
214        cs.setXPressNetLocomotiveMessagesFlag(xPressNetLocomotiveMessagesCheckBox.isSelected());
215        cs.setLocoNetMessagesFlag(locoNetMessagesCheckBox.isSelected());
216        cs.setLocoNetLocomotiveMessagesFlag(locoNetLocomotiveMessagesCheckBox.isSelected());
217        cs.setLocoNetTurnoutMessagesFlag(locoNetTurnoutMessagesCheckBox.isSelected());
218        cs.setLocoNetOccupancyMessagesFlag(locoNetOccupancyMessagesCheckBox.isSelected());
219        cs.setCanDetectorFlag(canDetectorCheckBox.isSelected());
220
221        // send the flags to the command station.
222        tc.sendz21Message(Z21Message.getLanSetBroadcastFlagsRequestMessage(cs.getZ21BroadcastFlags()), this);
223    }
224
225    /**
226     * Listen for responses from the Z21.
227     *
228     * @param zr the reply
229     */
230    @Override
231    public void reply(Z21Reply zr) {
232        switch (zr.getOpCode()) {
233            // handle replies with the serial number
234            case 0x0010:
235                // the serial number is a 32 bit integer stored in little
236                // endian format starting with the 1st databyte (element 4).
237                int serialNo = (zr.getElement(4)&0xff) + ((zr.getElement(5)&0xff) << 8)
238                        + ((zr.getElement(6)&0xff) << 16) + ((zr.getElement(7)&0xff) << 24);
239                cs.setSerialNumber(serialNo);
240                updateSerialNumber();
241                break;
242            // handle replies with the hardware and software version.
243            case 0x001A:
244                // the hardware version is a 32 bit integer stored in little
245                // endian format starting with the 1st databyte (element 4).
246                int hwversion = zr.getElement(4) + (zr.getElement(5) << 8)
247                        + (zr.getElement(6) << 16) + (zr.getElement(7) << 24);
248                cs.setHardwareVersion(hwversion);
249                // the software version is a 32 bit integer stored in little
250                // endian format and written in BCD, starting after the hardware
251                // version (element 8).  The least significant byte is to be
252                // treated as a decimal.
253                float swversion = (zr.getElementBCD(8) / 100.0f)
254                        + (zr.getElementBCD(9))
255                        + (zr.getElementBCD(10) * 100)
256                        + (zr.getElementBCD(11)) * 10000;
257                cs.setSoftwareVersion(swversion);
258                updateVersionInformation();
259                break;
260            // handle replies with the flags.
261            case 0x0051:
262                // the payload is a 32 bit integer stored in little endian format
263                // starting with the 1st databyte (element 4).
264                int flags = zr.getElement(4) + (zr.getElement(5) << 8)
265                        + (zr.getElement(6) << 16) + (zr.getElement(7) << 24);
266                cs.setZ21BroadcastFlags(flags);
267                updateFlagInformation();
268                break;
269            default:
270                // ignore all other message types.
271                log.debug("unhandled op-code received.");
272        }
273    }
274
275    /**
276     * Listen for the messages sent to the Z21.
277     *
278     * @param zm the message to listen for
279     */
280    @Override
281    public void message(Z21Message zm) {
282    }
283
284    @Override
285    public void dispose() {
286        // remove the listener for this object.
287        tc.removez21Listener(this);
288        // take apart the JFrame
289        super.dispose();
290    }
291
292    /**
293     * Read the versions displayed from the command station representation.
294     */
295    private void updateVersionInformation() {
296        hardwareVersionTextField.setText("0x" + java.lang.Integer.toHexString(cs.getHardwareVersion()));
297        softwareVersionTextField.setText("" + cs.getSoftwareVersion());
298    }
299
300    /**
301     * Read the serial number from the command station representation.
302     */
303    private void updateSerialNumber() {
304        serialNumTextField.setText("" + cs.getSerialNumber());
305    }
306
307    /**
308     * Read the flags displayed from the command station representation.
309     */
310    private void updateFlagInformation() {
311        xPressNetMessagesCheckBox.setSelected(cs.getXPressNetMessagesFlag());
312        rmBusMessagesCheckBox.setSelected(cs.getRMBusMessagesFlag());
313        systemStatusMessagesCheckBox.setSelected(cs.getSystemStatusMessagesFlag());
314        xPressNetLocomotiveMessagesCheckBox.setSelected(cs.getXPressNetLocomotiveMessagesFlag());
315        railComMessagesCheckBox.setSelected(cs.getRailComMessagesFlag());
316        locoNetMessagesCheckBox.setSelected(cs.getLocoNetMessagesFlag());
317        locoNetLocomotiveMessagesCheckBox.setSelected(cs.getLocoNetLocomotiveMessagesFlag());
318        locoNetTurnoutMessagesCheckBox.setSelected(cs.getLocoNetTurnoutMessagesFlag());
319        locoNetOccupancyMessagesCheckBox.setSelected(cs.getLocoNetOccupancyMessagesFlag());
320    }
321
322    private final static Logger log = LoggerFactory.getLogger(Z21ConfigFrame.class);
323
324}