001package jmri.jmrix.bachrus.serialdriver;
002
003import java.io.DataInputStream;
004import java.io.DataOutputStream;
005import java.io.IOException;
006import java.io.InputStream;
007import java.util.TooManyListenersException;
008import jmri.jmrix.bachrus.SpeedoConnectionTypeList;
009import jmri.jmrix.bachrus.SpeedoPortController;
010import jmri.jmrix.bachrus.SpeedoSystemConnectionMemo;
011import jmri.jmrix.bachrus.SpeedoTrafficController;
012import org.slf4j.Logger;
013import org.slf4j.LoggerFactory;
014import purejavacomm.CommPortIdentifier;
015import purejavacomm.NoSuchPortException;
016import purejavacomm.PortInUseException;
017import purejavacomm.UnsupportedCommOperationException;
018
019/**
020 * Implements SerialPortAdapter for the Bachrus speedo.
021 * <p>
022 * This connects a bachrus speedo reader interface via a serial com port.
023 * Normally controlled by the SerialDriverFrame class.
024 * <p>
025 * The current implementation only handles the 9,600 baud rate, and does not use
026 * any other options at configuration time.
027 *
028 * Updated January 2010 for gnu io (RXTX) - Andrew Berridge. Comments tagged
029 * with "AJB" indicate changes or observations by me
030 *
031 * @author Bob Jacobsen Copyright (C) 2001, 2002
032 * @author Andrew Crosland Copyright (C) 2010
033 */
034public class SerialDriverAdapter extends SpeedoPortController {
035
036    public SerialDriverAdapter() {
037        super(new SpeedoSystemConnectionMemo());
038        setManufacturer(SpeedoConnectionTypeList.BACHRUS);
039        this.getSystemConnectionMemo().setSpeedoTrafficController(new SpeedoTrafficController(this.getSystemConnectionMemo()));
040    }
041
042    purejavacomm.SerialPort activeSerialPort = null;
043
044    @Override
045    public String openPort(String portName, String appName) {
046        // open the port, check ability to set moderators
047        try {
048            // get and open the primary port
049            CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(portName);
050            try {
051                activeSerialPort = (purejavacomm.SerialPort) portID.open(appName, 2000);  // name of program, msec to wait
052            } catch (PortInUseException p) {
053                return handlePortBusy(p, portName, log);
054            }
055
056            // try to set it for communication via SerialDriver
057            try {
058                activeSerialPort.setSerialPortParams(9600,
059                        purejavacomm.SerialPort.DATABITS_8,
060                        purejavacomm.SerialPort.STOPBITS_1,
061                        purejavacomm.SerialPort.PARITY_NONE);
062            } catch (UnsupportedCommOperationException e) {
063                log.error("Cannot set serial parameters on port {}: {}", portName, e.getMessage());
064                return "Cannot set serial parameters on port " + portName + ": " + e.getMessage();
065            }
066
067            // set RTS high, DTR high
068            // disable flow control; hardware lines used for signaling, XON/XOFF might appear in data
069            //AJB: Removed Jan 2010 -
070            //Setting flow control mode to zero kills comms - SPROG doesn't send data
071            //Concern is that will disabling this affect other SPROGs? Serial ones?
072            configureLeadsAndFlowControl(activeSerialPort, 0);
073
074            // set timeout
075            // activeSerialPort.enableReceiveTimeout(1000);
076            log.debug("Serial timeout was observed as: {} {}", activeSerialPort.getReceiveTimeout(), activeSerialPort.isReceiveTimeoutEnabled());
077
078            // get and save stream
079            serialStream = activeSerialPort.getInputStream();
080
081            // purge contents, if any
082            purgeStream(serialStream);
083
084            // report status?
085            if (log.isInfoEnabled()) {
086                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());
087            }
088
089            //AJB - add Sprog Traffic Controller as event listener
090            try {
091                activeSerialPort.addEventListener(this.getSystemConnectionMemo().getTrafficController());
092            } catch (TooManyListenersException e) {
093            }
094            setManufacturer(SpeedoConnectionTypeList.BACHRUS);
095
096            // AJB - activate the DATA_AVAILABLE notifier
097            activeSerialPort.notifyOnDataAvailable(true);
098
099            opened = true;
100
101        } catch (NoSuchPortException p) {
102            return handlePortNotFound(p, portName, log);
103        } catch (IOException ex) {
104            log.error("Unexpected exception while opening port {}", portName, ex);
105            return "Unexpected error while opening port " + portName + ": " + ex;
106        }
107
108        return null; // indicates OK return
109
110    }
111
112    public void setHandshake(int mode) {
113        try {
114            activeSerialPort.setFlowControlMode(mode);
115        } catch (UnsupportedCommOperationException ex) {
116            log.error("Unexpected exception while setting COM port handshake mode", ex);
117        }
118
119    }
120
121    /**
122     * set up all of the other objects to operate with an Sprog command station
123     * connected to this port
124     */
125    @Override
126    public void configure() {
127        // connect to the traffic controller
128        this.getSystemConnectionMemo().getTrafficController().connectPort(this);
129
130        this.getSystemConnectionMemo().configureManagers();
131    }
132
133    // base class methods for the SprogPortController interface
134    @Override
135    public DataInputStream getInputStream() {
136        if (!opened) {
137            log.error("getInputStream called before load(), stream not available");
138            return null;
139        }
140        return new DataInputStream(serialStream);
141    }
142
143    @Override
144    public DataOutputStream getOutputStream() {
145        if (!opened) {
146            log.error("getOutputStream called before load(), stream not available");
147        }
148        try {
149            return new DataOutputStream(activeSerialPort.getOutputStream());
150        } catch (java.io.IOException e) {
151            log.error("getOutputStream exception", e);
152        }
153        return null;
154    }
155
156    @Override
157    public boolean status() {
158        return opened;
159    }
160
161    /**
162     * {@inheritDoc}
163     * Currently only 9,600 bps
164     */
165    @Override
166    public String[] validBaudRates() {
167        return new String[]{"9,600 bps"};
168    }
169
170    /**
171     * {@inheritDoc}
172     */
173    @Override
174    public int[] validBaudNumbers() {
175        return new int[]{9600};
176    }
177
178    @Override
179    public int defaultBaudIndex() {
180        return 0;
181    }
182
183    private boolean opened = false;
184    InputStream serialStream = null;
185
186    private final static Logger log = LoggerFactory.getLogger(SerialDriverAdapter.class);
187
188}