001package jmri.jmrix.qsi.serialdriver;
002
003import java.io.DataInputStream;
004import java.io.DataOutputStream;
005import java.io.IOException;
006import java.io.InputStream;
007
008import jmri.jmrix.qsi.QsiPortController;
009import jmri.jmrix.qsi.QsiSystemConnectionMemo;
010import jmri.jmrix.qsi.QsiTrafficController;
011
012import org.slf4j.Logger;
013import org.slf4j.LoggerFactory;
014
015import purejavacomm.CommPortIdentifier;
016import purejavacomm.NoSuchPortException;
017import purejavacomm.PortInUseException;
018import purejavacomm.UnsupportedCommOperationException;
019
020/**
021 * Implements SerialPortAdapter for the QSI system.
022 * <p>
023 * This connects an QSI command station via a serial com port. Also used for the
024 * USB QSI, which appears to the computer as a serial port. Normally controlled
025 * by the SerialDriverFrame class.
026 * <p>
027 * The current implementation only handles the 19,200 baud rate, and does not
028 * use any other options at configuration time.
029 *
030 * @author Bob Jacobsen Copyright (C) 2001, 2002
031 */
032public class SerialDriverAdapter extends QsiPortController {
033
034    public SerialDriverAdapter() {
035        super(new QsiSystemConnectionMemo());
036        this.manufacturerName = jmri.jmrix.qsi.QSIConnectionTypeList.QSI;
037    }
038
039    purejavacomm.SerialPort activeSerialPort = null;
040
041    @Override
042    public String openPort(String portName, String appName) {
043        // open the port, check ability to set moderators
044        try {
045            // get and open the primary port
046            CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(portName);
047            try {
048                activeSerialPort = (purejavacomm.SerialPort) portID.open(appName, 2000);  // name of program, msec to wait
049            } catch (PortInUseException p) {
050                return handlePortBusy(p, portName, log);
051            }
052
053            // try to set it for communication via SerialDriver
054            try {
055                activeSerialPort.setSerialPortParams(19200,
056                        purejavacomm.SerialPort.DATABITS_8,
057                        purejavacomm.SerialPort.STOPBITS_1,
058                        purejavacomm.SerialPort.PARITY_NONE);
059            } catch (UnsupportedCommOperationException e) {
060                log.error("Cannot set serial parameters on port {}: {}", portName, e.getMessage());
061                return "Cannot set serial parameters on port " + portName + ": " + e.getMessage();
062            }
063
064            // disable flow control; hardware lines used for signaling, XON/XOFF might appear in data
065            configureLeadsAndFlowControl(activeSerialPort, 0);
066
067            // set timeout
068            // activeSerialPort.enableReceiveTimeout(1000);
069            log.debug("Serial timeout was observed as: {} {}", activeSerialPort.getReceiveTimeout(),
070                    activeSerialPort.isReceiveTimeoutEnabled());
071
072            // get and save stream
073            serialStream = activeSerialPort.getInputStream();
074
075            // purge contents, if any
076            purgeStream(serialStream);
077
078            // report status?
079            if (log.isInfoEnabled()) {
080                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());
081            }
082            opened = true;
083
084        } catch (NoSuchPortException p) {
085            return handlePortNotFound(p, portName, log);
086        } catch (IOException ex) {
087            log.error("Unexpected exception while opening port {}", portName, ex);
088            return "Unexpected error while opening port " + portName + ": " + ex;
089        }
090        return null; // indicates OK return
091    }
092
093    public void setHandshake(int mode) {
094        try {
095            activeSerialPort.setFlowControlMode(mode);
096        } catch (UnsupportedCommOperationException ex) {
097            log.error("Unexpected exception while setting COM port handshake mode", ex);
098        }
099    }
100
101    /**
102     * Set up all of the other objects to operate with an QSI command station
103     * connected to this port
104     */
105    @Override
106    public void configure() {
107
108        this.getSystemConnectionMemo().setQsiTrafficController(new QsiTrafficController());
109        // connect to the traffic controller
110        this.getSystemConnectionMemo().getQsiTrafficController().connectPort(this);
111
112        this.getSystemConnectionMemo().configureManagers();
113
114        sinkThread = new Thread(this.getSystemConnectionMemo().getQsiTrafficController());
115        sinkThread.start();
116
117        // jmri.InstanceManager.setThrottleManager(new jmri.jmrix.qsi.QsiThrottleManager());
118    }
119
120    private Thread sinkThread;
121
122    // base class methods for the QsiPortController interface
123    @Override
124    public DataInputStream getInputStream() {
125        if (!opened) {
126            log.error("getInputStream called before load(), stream not available");
127            return null;
128        }
129        return new DataInputStream(serialStream);
130    }
131
132    @Override
133    public DataOutputStream getOutputStream() {
134        if (!opened) {
135            log.error("getOutputStream called before load(), stream not available");
136        }
137        try {
138            return new DataOutputStream(activeSerialPort.getOutputStream());
139        } catch (java.io.IOException e) {
140            log.error("getOutputStream exception: ", e);
141        }
142        return null;
143    }
144
145    @Override
146    public boolean status() {
147        return opened;
148    }
149
150    /**
151     * {@inheritDoc}
152     *
153     * Currently only 19,200 bps
154     */
155    @Override
156    public String[] validBaudRates() {
157        return new String[]{"19,200 bps"};
158    }
159
160    /**
161     * {@inheritDoc}
162     */
163    @Override
164    public int[] validBaudNumbers() {
165        return new int[]{19200};
166    }
167
168    @Override
169    public int defaultBaudIndex() {
170        return 0;
171    }
172
173    private boolean opened = false;
174    InputStream serialStream = null;
175
176    private final static Logger log = LoggerFactory.getLogger(SerialDriverAdapter.class);
177
178}