001package jmri.jmrix.can.adapters.lawicell;
002
003import java.io.DataInputStream;
004import java.io.DataOutputStream;
005import java.io.IOException;
006import java.io.InputStream;
007import java.util.Arrays;
008import jmri.jmrix.can.TrafficController;
009import org.slf4j.Logger;
010import org.slf4j.LoggerFactory;
011import purejavacomm.CommPortIdentifier;
012import purejavacomm.NoSuchPortException;
013import purejavacomm.PortInUseException;
014import purejavacomm.SerialPort;
015import purejavacomm.UnsupportedCommOperationException;
016
017/**
018 * Implements SerialPortAdapter for the LAWICELL protocol.
019 *
020 * @author Bob Jacobsen Copyright (C) 2001, 2002, 2008
021 * @author Andrew Crosland Copyright (C) 2008
022 */
023public class SerialDriverAdapter extends PortController {
024
025    SerialPort activeSerialPort = null;
026
027    public SerialDriverAdapter() {
028        super(new jmri.jmrix.can.CanSystemConnectionMemo());
029        option1Name = "Protocol"; // NOI18N
030        options.put(option1Name, new Option(Bundle.getMessage("ConnectionProtocol"),
031                jmri.jmrix.can.ConfigurationManager.getSystemOptions()));
032    }
033
034    @Override
035    public String openPort(String portName, String appName) {
036        // open the port, check ability to set moderators
037        try {
038            // get and open the primary port
039            CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(portName);
040            try {
041                activeSerialPort = (SerialPort) portID.open(appName, 2000);  // name of program, msec to wait
042            } catch (PortInUseException p) {
043                return handlePortBusy(p, portName, log);
044            }
045
046            // try to set it for communication via SerialDriver
047            try {
048                // find the baud rate value, configure comm options
049                int baud = currentBaudNumber(mBaudRate);
050                activeSerialPort.setSerialPortParams(baud, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
051            } catch (UnsupportedCommOperationException e) {
052                log.error("Cannot set serial parameters on port {}: {}", portName, e.getMessage());
053                return "Cannot set serial parameters on port " + portName + ": " + e.getMessage();
054            }
055
056            // disable flow control; hardware lines used for signaling, XON/XOFF might appear in data
057            configureLeadsAndFlowControl(activeSerialPort, 0);
058            activeSerialPort.enableReceiveTimeout(50);  // 50 mSec timeout before sending chars
059
060            // set timeout
061            // activeSerialPort.enableReceiveTimeout(1000);
062            log.debug("Serial timeout was observed as: {} {}", activeSerialPort.getReceiveTimeout(),
063                    activeSerialPort.isReceiveTimeoutEnabled());
064
065            // get and save stream
066            serialStream = activeSerialPort.getInputStream();
067
068            // purge contents, if any
069            purgeStream(serialStream);
070
071            // report status?
072            if (log.isInfoEnabled()) {
073                log.info("{} port opened at {} baud, sees  DTR: {} RTS: {} DSR: {} CTS: {}  CD: {}", portName, activeSerialPort.getBaudRate(), activeSerialPort.isDTR(), activeSerialPort.isRTS(), activeSerialPort.isDSR(), activeSerialPort.isCTS(), activeSerialPort.isCD());
074            }
075
076            opened = true;
077
078        } catch (NoSuchPortException p) {
079            return handlePortNotFound(p, portName, log);
080        } catch (UnsupportedCommOperationException | IOException ex) {
081            log.error("Unexpected exception while opening port {}", portName, ex);
082            return "Unexpected error while opening port " + portName + ": " + ex;
083        }
084
085        return null; // indicates OK return
086    }
087
088    /**
089     * Set up all of the other objects to operate with a CAN RS adapter
090     * connected to this port.
091     */
092    @Override
093    public void configure() {
094
095        // Register the CAN traffic controller being used for this connection
096        TrafficController tc = new LawicellTrafficController();
097        this.getSystemConnectionMemo().setTrafficController(tc);
098
099        // Now connect to the traffic controller
100        log.debug("Connecting port");
101        tc.connectPort(this);
102
103        // send a request for version information, set 125kbps, open channel
104        log.debug("send version request");
105        jmri.jmrix.can.CanMessage m
106                = new jmri.jmrix.can.CanMessage(new int[]{'V', 13, 'S', '4', 13, 'O', 13}, tc.getCanid());
107        m.setTranslated(true);
108        tc.sendCanMessage(m, null);
109
110        // do central protocol-specific configuration
111        this.getSystemConnectionMemo().setProtocol(getOptionState(option1Name));
112
113        this.getSystemConnectionMemo().configureManagers();
114    }
115
116    // base class methods for the PortController interface
117    @Override
118    public DataInputStream getInputStream() {
119        if (!opened) {
120            log.error("getInputStream called before load(), stream not available");
121            return null;
122        }
123        return new DataInputStream(serialStream);
124    }
125
126    @Override
127    public DataOutputStream getOutputStream() {
128        if (!opened) {
129            log.error("getOutputStream called before load(), stream not available");
130        }
131        try {
132            return new DataOutputStream(activeSerialPort.getOutputStream());
133        } catch (java.io.IOException e) {
134            log.error("getOutputStream exception: ", e);
135        }
136        return null;
137    }
138
139    @Override
140    public boolean status() {
141        return opened;
142    }
143
144    /**
145     * {@inheritDoc}
146     */
147    @Override
148    public String[] validBaudRates() {
149        return Arrays.copyOf(validSpeeds, validSpeeds.length);
150    }
151
152    @Override
153    public int[] validBaudNumbers() {
154        return Arrays.copyOf(validSpeedValues, validSpeedValues.length);
155    }
156
157    /**
158     * Migration method.
159     * @return valid baud values.
160     * @deprecated since 4.16
161     */
162    @Deprecated
163    public int[] validBaudValues() {
164        return validBaudNumbers();
165    }
166
167    protected String[] validSpeeds = new String[]{Bundle.getMessage("Baud57600"),
168            Bundle.getMessage("Baud115200"), Bundle.getMessage("Baud230400"),
169            Bundle.getMessage("Baud250000"), Bundle.getMessage("Baud333333"),
170            Bundle.getMessage("Baud460800"), Bundle.getMessage("Baud500000")};
171    protected int[] validSpeedValues = new int[]{57600, 115200, 230400, 250000, 333333, 460800, 500000};
172
173    @Override
174    public int defaultBaudIndex() {
175        return 0;
176    }
177
178    // private control members
179    private boolean opened = false;
180    InputStream serialStream = null;
181
182    private final static Logger log = LoggerFactory.getLogger(SerialDriverAdapter.class);
183
184}