001package jmri.jmrix.loconet.locostats.swing;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004import java.awt.event.ActionEvent;
005import javax.swing.BoxLayout;
006import javax.swing.JButton;
007import javax.swing.JLabel;
008import javax.swing.JPanel;
009import javax.swing.JTextField;
010import jmri.jmrix.loconet.LocoNetSystemConnectionMemo;
011import jmri.jmrix.loconet.locostats.LocoBufferIIStatus;
012import jmri.jmrix.loconet.locostats.LocoNetInterfaceStatsListener;
013import jmri.jmrix.loconet.locostats.LocoStatsFunc;
014import jmri.jmrix.loconet.locostats.PR2Status;
015import jmri.jmrix.loconet.locostats.PR3MS100ModeStatus;
016import jmri.jmrix.loconet.locostats.RawStatus;
017import jmri.jmrix.loconet.swing.LnPanel;
018import jmri.util.JmriJFrame;
019import jmri.util.ThreadingUtil;
020import org.slf4j.Logger;
021import org.slf4j.LoggerFactory;
022
023/**
024 * Panel displaying LocoNet interface status information.
025 * <p>
026 * The LocoBuffer family from RR-CirKits and the PRn family from Digitrax use
027 * different formats for the status message. This class detects this from the
028 * reply contents, and displays different panes depending on which message was
029 * received. If the format is not recognised, a raw display format is used.
030 * <p>
031 * Moved from loconet.locobuffer.LocoBufferStatsFrame
032 * <p>
033 * Some of the message formats used in this class are Copyright Digitrax, Inc.
034 * and used with permission as part of the JMRI project. That permission does
035 * not extend to uses in other software products. If you wish to use this code,
036 * algorithm or these message formats outside of JMRI, please contact Digitrax
037 * Inc for separate permission.
038 *
039 * @author Alex Shepherd Copyright (C) 2003
040 * @author Bob Jacobsen Copyright (C) 2008, 2010
041 * @since 2.1.5
042 */
043public class LocoStatsPanel extends LnPanel implements LocoNetInterfaceStatsListener {
044
045    JPanel lb2Panel;
046    JPanel rawPanel;
047    JPanel pr2Panel;
048    JPanel ms100Panel;
049    boolean updateRequestPending = false;
050
051    LocoStatsFunc stats;
052
053    /**
054     * Provides a path to the help html for this tool
055     *
056     * @return path
057     */
058    @Override
059    public String getHelpTarget() {
060        return "package.jmri.jmrix.loconet.locostats.LocoStatsFrame"; // NOI18N
061    }
062
063    /**
064     * Provides the string for the title of the window
065     *
066     * This is pulled from the properties file for the LocoNet menu entry for
067     * this tool, to ensure consistency between the menu and the window title.
068     *
069     * @return an internationalized string containing the tool's LocoNet menu name
070     */
071    @Override
072    public String getTitle() {
073        return getTitle(Bundle.getMessage("MenuItemLocoStats"));
074    }
075
076    /**
077     * Constructor
078     */
079    public LocoStatsPanel() {
080        super();
081    }
082
083    /**
084     * GUI initializations
085     */
086    @Override
087    public void initComponents() {
088        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
089
090        // add GUI items
091        rawPanel = new JPanel();
092        rawPanel.setLayout(new BoxLayout(rawPanel, BoxLayout.X_AXIS));
093        rawPanel.add(new JLabel(Bundle.getMessage("LabelRawData")));
094        rawPanel.add(r1);
095        rawPanel.add(r2);
096        rawPanel.add(r3);
097        rawPanel.add(r4);
098        rawPanel.add(r5);
099        rawPanel.add(r6);
100        rawPanel.add(r7);
101        rawPanel.add(r8);
102
103        lb2Panel = new JPanel();
104        lb2Panel.setLayout(new BoxLayout(lb2Panel, BoxLayout.X_AXIS));
105        lb2Panel.add(new JLabel(Bundle.getMessage("LabelVersion")));
106        lb2Panel.add(version);
107        lb2Panel.add(new JLabel(Bundle.getMessage("LabelBreaks")));
108        breaks.setPreferredSize(version.getPreferredSize());
109        lb2Panel.add(breaks);
110        lb2Panel.add(new JLabel(Bundle.getMessage("LabelErrors")));
111        errors.setPreferredSize(version.getPreferredSize());
112        lb2Panel.add(errors);
113
114        pr2Panel = new JPanel();
115        pr2Panel.setLayout(new BoxLayout(pr2Panel, BoxLayout.X_AXIS));
116        pr2Panel.add(new JLabel(Bundle.getMessage("LabelSerialNumber")));
117        pr2Panel.add(serial);
118        pr2Panel.add(new JLabel(Bundle.getMessage("LabelPR2Status")));
119        pr2Panel.add(status);
120        pr2Panel.add(new JLabel(Bundle.getMessage("LabelCurrent")));
121        pr2Panel.add(current);
122        pr2Panel.add(new JLabel(Bundle.getMessage("LabelHardwareVersion")));
123        pr2Panel.add(hardware);
124        pr2Panel.add(new JLabel(Bundle.getMessage("LabelSoftwareVersion")));
125        pr2Panel.add(software);
126
127        ms100Panel = new JPanel();
128        ms100Panel.setLayout(new BoxLayout(ms100Panel, BoxLayout.X_AXIS));
129        ms100Panel.add(new JLabel(Bundle.getMessage("LabelGoodCnt")));
130        ms100Panel.add(goodMsgCnt);
131        ms100Panel.add(new JLabel(Bundle.getMessage("LabelBadCnt")));
132        ms100Panel.add(badMsgCnt);
133        ms100Panel.add(new JLabel(Bundle.getMessage("LabelMS100Status")));
134        ms100Panel.add(ms100status);
135
136        add(rawPanel);
137        add(lb2Panel);
138        add(pr2Panel);
139        add(ms100Panel);
140
141        JPanel panel = new JPanel();
142        panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
143        add(updateButton);
144        add(panel);
145
146        // install "update" button handler
147        updateButton.addActionListener((ActionEvent a) -> {
148            requestUpdate();
149        });
150
151        // and prep for display
152        lb2Panel.setVisible(false);
153        rawPanel.setVisible(true);
154        pr2Panel.setVisible(false);
155        ms100Panel.setVisible(false);
156        revalidate();
157
158        // will connect when memo is available
159    }
160
161    /**
162     * Configure LocoNet connection
163     *
164     * @param memo  specifies which LocoNet connection is used by this tool
165     */
166    @Override
167    public void initComponents(LocoNetSystemConnectionMemo memo) {
168        super.initComponents(memo);
169
170        stats = new LocoStatsFunc(memo);
171        stats.addLocoNetInterfaceStatsListener(this);
172
173        // request interface data from interface device
174        requestUpdate();
175    }
176
177    /**
178     * Destructor
179     */
180    @Override
181    public void dispose() {
182        // unregister listener
183        stats.removeLocoNetInterfaceStatsListener(this);
184    }
185
186    /**
187     * Send LocoNet request for interface status.
188     *
189     * Performs the send from the "Layout" thread, to avoid GUI-related
190     * threading problems.
191     */
192    public void requestUpdate() {
193        // Invoke the LocoNet request send on the layout thread, not the GUI thread!
194        // Note - there is no guarantee that the LocoNet message will be sent
195        // before execution returns to this method (but it might).
196        ThreadingUtil.runOnLayoutEventually(()->{  stats.sendLocoNetInterfaceStatusQueryMessage(); });
197        updateRequestPending = true;
198        log.debug("Sending a ping");
199    }
200
201    JTextField r1 = new JTextField(5);
202    JTextField r2 = new JTextField(5);
203    JTextField r3 = new JTextField(5);
204    JTextField r4 = new JTextField(5);
205    JTextField r5 = new JTextField(5);
206    JTextField r6 = new JTextField(5);
207    JTextField r7 = new JTextField(5);
208    JTextField r8 = new JTextField(5);
209
210    JTextField serial = new JTextField(6);
211    JTextField status = new JTextField(5);
212    JTextField current = new JTextField(4);
213    JTextField hardware = new JTextField(2);
214    JTextField software = new JTextField(3);
215
216    JTextField goodMsgCnt = new JTextField(5);
217    JTextField badMsgCnt = new JTextField(5);
218    JTextField ms100status = new JTextField(6);
219
220    JTextField version = new JTextField(8);
221    JTextField breaks = new JTextField(6);
222    JTextField errors = new JTextField(6);
223
224
225    JButton updateButton = new JButton(Bundle.getMessage("ButtonTextUpdate"));
226
227    /**
228     * Listener for LocoNet Interface Status changes
229     *
230     * @param o a LocoNetStatus object
231     */
232    @Override
233    @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST_OF_RETURN_VALUE", justification = "GUI elements are created such that cast to JmriJFrame this is accurate")
234    public void notifyChangedInterfaceStatus(Object o) {
235        log.debug("Update is being handled:{}", o.toString());  // NOI18N
236        if (!updateRequestPending) {
237            return;
238        }
239
240        if (o.getClass() == LocoBufferIIStatus.class) {
241            LocoBufferIIStatus s = (LocoBufferIIStatus) o;
242            version.setText((Integer.toHexString(s.version)));
243            breaks.setText((Integer.toString(s.breaks)));
244            errors.setText((Integer.toString(s.errors)));
245            lb2Panel.setVisible(true);
246            rawPanel.setVisible(false);
247            ms100Panel.setVisible(false);
248            pr2Panel.setVisible(false);
249            ((JmriJFrame) getRootPane().getParent()).setPreferredSize(null);
250            ((JmriJFrame) getRootPane().getParent()).pack();
251        } else if (o.getClass() == PR2Status.class) {
252            PR2Status s = (PR2Status) o;
253            serial.setText(Integer.toString(s.serial));
254            status.setText(Integer.toString(s.status));
255            current.setText(Integer.toString(s.current));
256            hardware.setText(Integer.toString(s.hardware));
257            software.setText(Integer.toString(s.software));
258            lb2Panel.setVisible(false);
259            rawPanel.setVisible(false);
260            ms100Panel.setVisible(true);
261            pr2Panel.setVisible(true);
262            ((JmriJFrame) getRootPane().getParent()).setPreferredSize(null);
263            ((JmriJFrame) getRootPane().getParent()).pack();
264        } else if (o.getClass() == PR3MS100ModeStatus.class) {
265            PR3MS100ModeStatus s = (PR3MS100ModeStatus) o;
266            goodMsgCnt.setText(Integer.toString(s.goodMsgCnt));
267            badMsgCnt.setText(Integer.toString(s.badMsgCnt));
268            ms100status.setText(Integer.toString(s.ms100status));
269            lb2Panel.setVisible(false);
270            rawPanel.setVisible(false);
271            ms100Panel.setVisible(true);
272            pr2Panel.setVisible(true);
273            ((JmriJFrame) getRootPane().getParent()).setPreferredSize(null);
274            ((JmriJFrame) getRootPane().getParent()).pack();
275        } else if (o.getClass() == RawStatus.class) {
276            RawStatus s = (RawStatus)o;
277            r1.setText(Integer.toString(s.raw[0]));
278            r2.setText(Integer.toString(s.raw[1]));
279            r3.setText(Integer.toString(s.raw[2]));
280            r4.setText(Integer.toString(s.raw[3]));
281            r5.setText(Integer.toString(s.raw[4]));
282            r6.setText(Integer.toString(s.raw[5]));
283            r7.setText(Integer.toString(s.raw[6]));
284            r8.setText(Integer.toString(s.raw[7]));
285            lb2Panel.setVisible(false);
286            rawPanel.setVisible(true);
287            ms100Panel.setVisible(false);
288            pr2Panel.setVisible(false);
289            ((JmriJFrame) getRootPane().getParent()).setPreferredSize(null);
290            ((JmriJFrame) getRootPane().getParent()).pack();
291            }
292        }
293
294    private final static Logger log = LoggerFactory.getLogger(LocoStatsPanel.class);
295
296}