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