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