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