001package jmri.jmrix.powerline.cm11;
002
003import java.io.DataInputStream;
004import java.io.DataOutputStream;
005import java.io.IOException;
006import java.io.InputStream;
007import java.util.Arrays;
008import jmri.jmrix.powerline.SerialPortController;
009import jmri.jmrix.powerline.SerialTrafficController;
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012import purejavacomm.CommPortIdentifier;
013import purejavacomm.NoSuchPortException;
014import purejavacomm.PortInUseException;
015import purejavacomm.SerialPort;
016import purejavacomm.UnsupportedCommOperationException;
017
018/**
019 * Provide access to Powerline devices via a serial com port.
020 * Derived from the Oaktree code.
021 *
022 * @author Bob Jacobsen Copyright (C) 2006, 2007, 2008
023 * @author Ken Cameron, (C) 2009, sensors from poll replies Converted to
024 * multiple connection
025 * @author kcameron Copyright (C) 2011
026 */
027public class SpecificDriverAdapter extends SerialPortController {
028
029    SerialPort activeSerialPort = null;
030
031    public SpecificDriverAdapter() {
032        super(new SpecificSystemConnectionMemo());
033    }
034
035    @Override
036    public String openPort(String portName, String appName) {
037        try {
038            // get and open the primary port
039            CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(portName);
040            try {
041                activeSerialPort = (SerialPort) portID.open(appName, 2000);  // name of program, msec to wait
042            } catch (PortInUseException p) {
043                return handlePortBusy(p, portName, log);
044            }
045            // try to set it for serial
046            try {
047                setSerialPort();
048            } catch (UnsupportedCommOperationException e) {
049                log.error("Cannot set serial parameters on port {}: {}", portName, e.getMessage());
050                return "Cannot set serial parameters on port " + portName + ": " + e.getMessage();
051            }
052
053            // set framing (end) character
054            try {
055                log.debug("Serial framing was observed as: {} {}", activeSerialPort.isReceiveFramingEnabled(),
056                        activeSerialPort.getReceiveFramingByte());
057            } catch (Exception ef) {
058                log.debug("failed to set serial framing: ", ef);
059            }
060
061            // set timeout; framing should work before this anyway
062            try {
063                activeSerialPort.enableReceiveTimeout(10);
064                log.debug("Serial timeout was observed as: {} {}", activeSerialPort.getReceiveTimeout(),
065                        activeSerialPort.isReceiveTimeoutEnabled());
066            } catch (Exception et) {
067                log.info("failed to set serial timeout: ", et);
068            }
069
070            // get and save stream
071            serialStream = activeSerialPort.getInputStream();
072
073            // purge contents, if any
074            purgeStream(serialStream);
075
076            // report status?
077            if (log.isInfoEnabled()) {
078                // report now
079                log.info("{} port opened at {} baud with DTR: {} RTS: {} DSR: {} CTS: {}  CD: {}", portName, activeSerialPort.getBaudRate(), activeSerialPort.isDTR(), activeSerialPort.isRTS(), activeSerialPort.isDSR(), activeSerialPort.isCTS(), activeSerialPort.isCD());
080            }
081            if (log.isDebugEnabled()) {
082                // report additional status
083                log.debug(" port flow control shows {}", // NOI18N
084                        (activeSerialPort.getFlowControlMode() == SerialPort.FLOWCONTROL_RTSCTS_OUT ? "hardware flow control" : "no flow control")); // NOI18N
085
086                // log events
087                setPortEventLogging(activeSerialPort);
088            }
089
090            opened = true;
091
092        } catch (NoSuchPortException p) {
093            return handlePortNotFound(p, portName, log);
094        } catch (IOException ex) {
095            log.error("Unexpected exception while opening port {}: ", portName, ex);
096            return "Unexpected error while opening port " + portName + ": " + ex;
097        }
098
099        return null; // normal operation
100    }
101
102    /**
103     * set up all of the other objects to operate connected to this port
104     */
105    @Override
106    public void configure() {
107        SerialTrafficController tc = null;
108        // create a CM11 port controller
109        //adaptermemo = new jmri.jmrix.powerline.cm11.SpecificSystemConnectionMemo();
110        tc = new SpecificTrafficController(this.getSystemConnectionMemo());
111
112        // connect to the traffic controller
113        this.getSystemConnectionMemo().setTrafficController(tc);
114        tc.setAdapterMemo(this.getSystemConnectionMemo());
115        this.getSystemConnectionMemo().configureManagers();
116        tc.connectPort(this);
117        // Configure the form of serial address validation for this connection
118        this.getSystemConnectionMemo().setSerialAddress(new jmri.jmrix.powerline.SerialAddress(this.getSystemConnectionMemo()));
119    }
120
121    /**
122     * {@inheritDoc}
123     */
124    @Override
125    public String[] validBaudRates() {
126        return Arrays.copyOf(validSpeeds, validSpeeds.length);
127    }
128
129    /**
130     * {@inheritDoc}
131     */
132    @Override
133    public int[] validBaudNumbers() {
134        return Arrays.copyOf(validSpeedValues, validSpeedValues.length);
135    }
136
137    // base class methods for the SerialPortController 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.getMessage());
156        }
157        return null;
158    }
159
160    @Override
161    public boolean status() {
162        return opened;
163    }
164    // private control members
165    private boolean opened = false;
166    InputStream serialStream = null;
167
168    /**
169     * Local method to do specific port configuration.
170     *
171     * @throws purejavacomm.UnsupportedCommOperationException invalid connection or options
172     */
173    protected void setSerialPort() throws UnsupportedCommOperationException {
174        // find the baud rate value, configure comm options
175        int baud = currentBaudNumber(mBaudRate);
176
177        activeSerialPort.setSerialPortParams(baud, SerialPort.DATABITS_8,
178                SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
179
180        // find and configure flow control
181        int flow = SerialPort.FLOWCONTROL_NONE; // default
182        configureLeadsAndFlowControl(activeSerialPort, flow);
183    }
184
185    protected String[] validSpeeds = new String[]{Bundle.getMessage("BaudAutomatic")};
186    protected int[] validSpeedValues = new int[]{4800};
187
188    @Override
189    public int defaultBaudIndex() {
190        return 0;
191    }
192
193    private final static Logger log = LoggerFactory.getLogger(SpecificDriverAdapter.class);
194
195}