001package jmri.jmrix.nce.packetgen;
002
003import java.awt.Dimension;
004import javax.swing.*;
005
006import jmri.jmrix.nce.NceMessage;
007import jmri.jmrix.nce.NceReply;
008import jmri.jmrix.nce.NceSystemConnectionMemo;
009import jmri.jmrix.nce.NceTrafficController;
010import jmri.util.StringUtil;
011import jmri.util.swing.JmriJOptionPane;
012
013/**
014 * Frame for user input of Nce messages.
015 *
016 * @author Ken Cameron Copyright (C) 2010 derived from:
017 * @author Bob Jacobsen Copyright (C) 2001
018 * @author Dan Boudreau Copyright (C) 2007
019 */
020public class NcePacketGenPanel extends jmri.jmrix.nce.swing.NcePanel implements jmri.jmrix.nce.NceListener {
021
022    javax.swing.JLabel jLabel1 = new javax.swing.JLabel();
023    javax.swing.JLabel jLabel2 = new javax.swing.JLabel();
024    javax.swing.JButton sendButton = new javax.swing.JButton();
025    javax.swing.JTextField packetTextField = new javax.swing.JTextField(20);
026    javax.swing.JCheckBox checkBoxBinCmd = new javax.swing.JCheckBox();
027    javax.swing.JTextField replyLenTextField = new javax.swing.JTextField(2);
028
029    private NceTrafficController tc = null;
030
031    public NcePacketGenPanel() {
032        super();
033    }
034
035    /**
036     * {@inheritDoc}
037     */
038    @Override
039    public void initContext(Object context) {
040        if (context instanceof NceSystemConnectionMemo) {
041            initComponents((NceSystemConnectionMemo) context);
042        }
043    }
044
045    /**
046     * {@inheritDoc}
047     */
048    @Override
049    public String getHelpTarget() {
050        return "package.jmri.jmrix.nce.packetgen.NcePacketGenFrame";
051    }
052
053    /**
054     * {@inheritDoc}
055     */
056    @Override
057    public String getTitle() {
058        StringBuilder x = new StringBuilder();
059        if (memo != null) {
060            x.append(memo.getUserName());
061        } else {
062            x.append("NCE_");
063        }
064        x.append(": ");
065        x.append(Bundle.getMessage("Title"));
066        return x.toString();
067    }
068
069    /**
070     * {@inheritDoc}
071     */
072    @Override
073    public void initComponents(NceSystemConnectionMemo m) {
074        this.memo = m;
075        this.tc = m.getNceTrafficController();
076
077        // the following code sets the frame's initial state
078        jLabel1.setText(Bundle.getMessage("CommandLabel"));
079        jLabel1.setVisible(true);
080
081        sendButton.setText(Bundle.getMessage("MenuItemSendCommand"));
082        sendButton.setVisible(true);
083        sendButton.setToolTipText(Bundle.getMessage("TooltipSendPacket"));
084
085        packetTextField.setText("");
086        packetTextField.setToolTipText(Bundle.getMessage("EnterHexToolTip"));
087        packetTextField.setMaximumSize(new Dimension(packetTextField
088                .getMaximumSize().width, packetTextField.getPreferredSize().height));
089
090        checkBoxBinCmd.setText(Bundle.getMessage("Binary"));
091        checkBoxBinCmd.setVisible(true);
092        checkBoxBinCmd.setToolTipText(Bundle.getMessage("TooltipBinary"));
093        checkBoxBinCmd.setSelected(true);
094
095        jLabel2.setText(Bundle.getMessage("BytesLabel"));
096        jLabel2.setVisible(true);
097
098        replyLenTextField.setVisible(true);
099        replyLenTextField.setMaximumSize(new Dimension(50, replyLenTextField.getPreferredSize().height));
100        replyLenTextField.setToolTipText(Bundle.getMessage("TooltipExpectedBytes"));
101
102        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
103        setPreferredSize(new Dimension(300, 150));
104
105        JPanel command = new JPanel();
106        command.setLayout(new BoxLayout(command, BoxLayout.X_AXIS));
107        command.add(jLabel1);
108        command.add(packetTextField);
109
110        JPanel bytes = new JPanel();
111        bytes.setLayout(new BoxLayout(bytes, BoxLayout.X_AXIS));
112        bytes.add(jLabel2);
113        bytes.add(replyLenTextField);
114
115        add(command);
116        add(checkBoxBinCmd);
117        add(bytes);
118        add(sendButton);
119
120        sendButton.addActionListener(this::sendButtonActionPerformed);
121    }
122
123    public void sendButtonActionPerformed(java.awt.event.ActionEvent e) {
124        String input = packetTextField.getText();
125        // TODO check input + feedback on error. Too easy to cause NPE
126        if (checkBoxBinCmd.isSelected()) {
127            // Binary selected, convert ASCII to hex
128
129            NceMessage m = createPacket(input);
130            if (m == null) {
131                JmriJOptionPane.showMessageDialog(NcePacketGenPanel.this,
132                        Bundle.getMessage("DialogHexOnly"),
133                        Bundle.getMessage("BinaryTitle"),
134                        JmriJOptionPane.ERROR_MESSAGE);
135                return;
136            }
137            m.setBinary(true);
138            int replyLen = getReplyLen(replyLenTextField.getText());
139            if (replyLen > 0) {
140                m.setReplyLen(replyLen);
141            } else {
142                m.setReplyLen(getMessageLength(m.getOpCode()));
143            }
144            tc.sendNceMessage(m, this);
145        } else {
146            // ASCII Mode selected
147
148            NceMessage m = new NceMessage(input.length());
149            for (int i = 0; i < input.length(); i++) {
150                m.setElement(i, input.charAt(i));
151            }
152
153            tc.sendNceMessage(m, this);
154        }
155    }
156
157    /**
158     * {@inheritDoc}
159     */
160    @Override
161    public void message(NceMessage m) {
162    }  // ignore replies
163
164    /**
165     * {@inheritDoc}
166     */
167    @Override
168    public void reply(NceReply r) {
169    } // ignore replies
170
171    NceMessage createPacket(String s) {
172        // gather bytes in result
173        byte[] b;
174        try {
175            b = StringUtil.bytesFromHexString(s);
176        } catch (NumberFormatException e) {
177            return null;
178        }
179        if (b.length == 0) {
180            return null; // no such thing as a zero-length message
181        }
182        NceMessage m = new NceMessage(b.length);
183        for (int i = 0; i < b.length; i++) {
184            m.setElement(i, b[i]);
185        }
186        return m;
187    }
188
189    private int getReplyLen(String s) {
190        // gather bytes in result
191        int b;
192        try {
193            b = Integer.parseInt(s);
194        } catch (NumberFormatException e) {
195            return 0;
196        }
197        return b;
198    }
199
200    // gets the expected number of bytes returned
201    private int getMessageLength(int opcode) {
202        int replyLen;
203        switch (opcode & 0xFF) {
204
205            case 0xAB:
206            case 0xAC:
207                replyLen = 0;
208                break;
209
210            case 0x82:
211            case 0x9B:
212            case 0xA1:
213            case 0xA7:
214            case 0xA9:
215                replyLen = 2;
216                break;
217
218            case 0x8C:
219            case 0xAA:
220                replyLen = 3;
221                break;
222
223            case 0x8A:
224                replyLen = 4;
225                break;
226
227            case 0x8F:
228                replyLen = 16;
229                break;
230            default:
231                replyLen = 1;
232        }
233        return replyLen;
234    }
235
236    /**
237     * Nested class to create one of these using old-style defaults.
238     */
239    static public class Default extends jmri.jmrix.nce.swing.NceNamedPaneAction {
240
241        public Default() {
242            super("Open NCE Send Binary Command",
243                    new jmri.util.swing.sdi.JmriJFrameInterface(),
244                    NcePacketGenPanel.class.getName(),
245                    jmri.InstanceManager.getDefault(NceSystemConnectionMemo.class));
246        }
247    }
248
249}