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