001package jmri.jmrix.can.cbus.swing.console;
002
003import javax.swing.*;
004
005import jmri.jmrix.can.CanMessage;
006import jmri.jmrix.can.CanReply;
007import jmri.jmrix.can.cbus.CbusMessage;
008import jmri.util.swing.JmriJOptionPane;
009import jmri.util.swing.ValidationNotifications;
010
011/**
012 * Frame for CBUS Console
013 *
014 * @author Andrew Crosland Copyright (C) 2008
015 * @author Steve Young Copyright (C) 2018
016 */
017public class CbusConsolePacketPane extends JPanel {
018    
019    private JTextField[] lastRxDataFields;
020    
021    private JPanel rxPacketPane;
022    private JPanel sendPacketPane;
023    
024    private JTextField lastDynPriField;
025    private JTextField lastMinPriField;
026    
027    private JTextField dynPriField;
028    private JTextField minPriField;
029    private JTextField[] dataFields;
030    private JButton sendPacketButton;
031    private JButton dataClearButton;
032    
033    private JButton copyButton;
034    private JCheckBox decimalCheckBox;
035    private JCheckBox rcvdDecimalCheckBox;
036    private final CbusConsolePane _mainPane;
037    
038    public CbusConsolePacketPane(CbusConsolePane mainPane){
039        super();
040        _mainPane = mainPane;
041        
042        initRxPacketPane();
043        initSendPacketPane();
044        initPanel();
045    }
046    
047    private void initPanel(){
048        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
049        add(rxPacketPane);
050        add(sendPacketPane);
051    
052    }
053
054    private void initRxPacketPane() {
055    
056        rcvdDecimalCheckBox = new JCheckBox();
057        rcvdDecimalCheckBox.setText(Bundle.getMessage("ButtonDecimal"));
058        rcvdDecimalCheckBox.setVisible(true);
059        rcvdDecimalCheckBox.setToolTipText(Bundle.getMessage("TooltipDecimal"));
060        rcvdDecimalCheckBox.setSelected(true);
061        
062        // Pane for most recently recived packet
063        rxPacketPane = new JPanel();
064        rxPacketPane.setLayout(new BoxLayout(rxPacketPane, BoxLayout.X_AXIS));
065        rxPacketPane.setBorder(BorderFactory.createTitledBorder(
066            BorderFactory.createEtchedBorder(), Bundle.getMessage("MostRecentPacketTitle")));
067    
068        copyButton = new JButton();
069        copyButton.setText(Bundle.getMessage("ButtonCopy"));
070        copyButton.setVisible(true);
071        copyButton.setToolTipText(Bundle.getMessage("TooltipCopyEvent"));
072        
073        copyButton.addActionListener(this::copyButtonActionPerformed);
074        
075        initRxPriorityFields();
076        
077        initRxTextFields();
078    
079    }
080    
081    private void initSendPacketPane() {
082    
083        decimalCheckBox = new JCheckBox();
084        decimalCheckBox.setText(Bundle.getMessage("ButtonDecimal"));
085        decimalCheckBox.setVisible(true);
086        decimalCheckBox.setToolTipText(Bundle.getMessage("TooltipDecimal"));
087        decimalCheckBox.setSelected(true);
088        
089     // Pane for constructing packet to send
090        sendPacketPane = new JPanel();
091        sendPacketPane.setLayout(new BoxLayout(sendPacketPane, BoxLayout.X_AXIS));
092        sendPacketPane.setBorder(BorderFactory.createTitledBorder(
093            BorderFactory.createEtchedBorder(), Bundle.getMessage("SendPacketTitle")));
094
095        // Construct data fields for Priority and up to 8 bytes
096        dynPriField = new JTextField("2", 4);
097        dynPriField.setToolTipText(Bundle.getMessage("TooltipDynPri"));
098        dynPriField.setBorder(BorderFactory.createTitledBorder(
099            BorderFactory.createEtchedBorder(), Bundle.getMessage("DynPriTitle")));
100        sendPacketPane.add(dynPriField);
101        minPriField = new JTextField("3", 4);
102        minPriField.setToolTipText(Bundle.getMessage("TooltipDinPri03"));
103        minPriField.setBorder(BorderFactory.createTitledBorder(
104            BorderFactory.createEtchedBorder(), Bundle.getMessage("MinPriTitle")));
105        sendPacketPane.add(minPriField);
106        
107        initSendFields();
108    
109    }
110    
111    private void initSendFields() {
112        
113        sendPacketButton = new JButton();
114        dataClearButton = new JButton();
115        
116        setupTextFields(dataFields = new JTextField[8],sendPacketPane);
117        
118        sendPacketPane.add(sendPacketButton);
119        sendPacketPane.add(dataClearButton);
120        sendPacketPane.add(decimalCheckBox);
121        
122        initButtonBorderToolTips();
123        
124        sendPacketButton.addActionListener(this::sendPacketButtonActionPerformed);
125        dataClearButton.addActionListener(this::dataClearButtonActionPerformed);
126        
127    }
128    
129    
130    private void initRxPriorityFields() {
131    
132    // Construct data fields for Priority and up to 8 bytes
133        lastDynPriField = new JTextField("", 4);
134        lastDynPriField.setToolTipText(Bundle.getMessage("TooltipDynPri"));
135        lastDynPriField.setBorder(BorderFactory.createTitledBorder(
136            BorderFactory.createEtchedBorder(), Bundle.getMessage("DynPriTitle")));
137        rxPacketPane.add(lastDynPriField);
138        lastMinPriField = new JTextField("", 4);
139        lastMinPriField.setToolTipText(Bundle.getMessage("TooltipMinPri"));
140        lastMinPriField.setBorder(BorderFactory.createTitledBorder(
141            BorderFactory.createEtchedBorder(), Bundle.getMessage("MinPriTitle")));
142        rxPacketPane.add(lastMinPriField);
143        
144    }
145    
146    
147    private void initRxTextFields() {
148        
149        setupTextFields(lastRxDataFields = new JTextField[8],rxPacketPane);
150        rxPacketPane.add(copyButton);
151        rxPacketPane.add(rcvdDecimalCheckBox);
152    
153    }
154    
155    private void setupTextFields(JTextField[] data, JPanel panelToAdd) {
156        for (int i = 0; i < 8; i++) {
157            data[i] = new JTextField("", 4);
158            if (i == 0) {
159                data[i].setBorder(BorderFactory.createTitledBorder(
160                        BorderFactory.createEtchedBorder(), "d0 (OPC)"));
161                data[i].setToolTipText(Bundle.getMessage("TooltipOpc"));
162            } else {
163                data[i].setBorder(BorderFactory.createTitledBorder(
164                        BorderFactory.createEtchedBorder(), "d" + i));
165                data[i].setToolTipText(Bundle.getMessage("TooltipDbX", i));
166            }
167            panelToAdd.add(data[i]);
168        }
169    }
170    
171    
172    private void copyButtonActionPerformed(java.awt.event.ActionEvent e) {
173        dynPriField.setText(lastDynPriField.getText());
174        minPriField.setText(lastMinPriField.getText());
175        for (int j = 0; j < 8; j++) {
176            dataFields[j].setText(lastRxDataFields[j].getText());
177        }
178    }
179    
180    private void initButtonBorderToolTips(){
181        
182        sendPacketButton.setText(Bundle.getMessage("ButtonSend"));
183        sendPacketButton.setVisible(true);
184        sendPacketButton.setToolTipText(Bundle.getMessage("TooltipSendPacket"));
185
186        dataClearButton.setText(Bundle.getMessage("ButtonClear"));
187        dataClearButton.setVisible(true);
188        dataClearButton.setToolTipText(Bundle.getMessage("TooltipClearFields"));
189    
190    }
191    
192    protected void setLastReceived(CanReply r) {
193    
194        if (rcvdDecimalCheckBox.isSelected()) {
195            lastDynPriField.setText(Integer.toString(CbusMessage.getPri(r) / 4));
196            lastMinPriField.setText(Integer.toString(CbusMessage.getPri(r) & 3));
197        } else {
198            lastDynPriField.setText(Integer.toHexString(CbusMessage.getPri(r) / 4));
199            lastMinPriField.setText(Integer.toHexString(CbusMessage.getPri(r) & 3));
200        }
201        // Pay attention to data length in op-code
202        for (int j = 0; j < (r.getElement(0) >> 5) + 1; j++) {
203            if (rcvdDecimalCheckBox.isSelected()) {
204                lastRxDataFields[j].setText(Integer.toString(r.getElement(j)));
205            } else {
206                lastRxDataFields[j].setText(Integer.toHexString(r.getElement(j)));
207            }
208        }
209    
210    }
211    
212    private void sendPacketButtonActionPerformed(java.awt.event.ActionEvent e) {
213        CanMessage m = new CanMessage(_mainPane.tc.getCanid());
214        int data = ValidationNotifications.parseBinDecHexByte(dynPriField.getText(), 2, decimalCheckBox.isSelected(), Bundle.getMessage("DynPriErrorDialog"),_mainPane);
215        if (data == -1) {
216            return;
217        }
218        int data2 = ValidationNotifications.parseBinDecHexByte(minPriField.getText(), 3, decimalCheckBox.isSelected(), Bundle.getMessage("MinPriErrorDialog"),_mainPane);
219        if (data2 == -1) {
220            return;
221        }
222        m.setHeader(data * 4 + data2);
223        
224        int j;
225        if ((j = setPacketData(m))<1){
226            return;
227        }
228        
229        // Does the number of data match the opcode?
230        // Subtract one as loop variable will have incremented
231        if ((j - 1) != (opcToSend >> 5)) {
232            JmriJOptionPane.showMessageDialog(_mainPane, Bundle.getMessage("OpcCountErrorDialog", (opcToSend >> 5)),
233                    Bundle.getMessage("CbusConsoleTitle"), JmriJOptionPane.ERROR_MESSAGE);
234            return;
235        }
236        m.setNumDataElements(j);
237        
238        _mainPane.tc.sendCanMessage(m, null);
239    }
240    
241    private int opcToSend;
242    
243    private int setPacketData(CanMessage m) {
244    
245        int j;
246        for (j = 0; j < 8; j++) {
247            if (!dataFields[j].getText().isEmpty()) {
248                int data = ValidationNotifications.parseBinDecHexByte(dataFields[j].getText(), 255, decimalCheckBox.isSelected(),
249                        Bundle.getMessage("DbxErrorDialog", j),_mainPane);
250                if (data == -1) {
251                    return -1;
252                }
253                m.setElement(j, data);
254                if (j == 0) {
255                    opcToSend = data; // save OPC(d0) for later
256                }
257            } else {
258                if (j == 0) {
259                    JmriJOptionPane.showMessageDialog(_mainPane, Bundle.getMessage("OpcErrorDialog"),
260                        Bundle.getMessage("CbusConsoleTitle"), JmriJOptionPane.ERROR_MESSAGE);
261                }
262                return j;
263            }
264        }
265        return j;
266    }
267
268    
269    private void dataClearButtonActionPerformed(java.awt.event.ActionEvent e) {
270        dynPriField.setText("2");
271        minPriField.setText("3");
272        for (int i = 0; i < 8; i++) {
273            dataFields[i].setText("");
274        }
275    }
276
277    // private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CbusConsolePacketPane.class);
278}