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