001package jmri.jmrix.tams.serialdriver; 002 003import java.io.DataInputStream; 004import java.io.DataOutputStream; 005import java.io.IOException; 006import java.io.InputStream; 007import java.util.Arrays; 008import jmri.jmrix.tams.TamsPortController; 009import jmri.jmrix.tams.TamsSystemConnectionMemo; 010import jmri.jmrix.tams.TamsTrafficController; 011import org.slf4j.Logger; 012import org.slf4j.LoggerFactory; 013import purejavacomm.CommPortIdentifier; 014import purejavacomm.NoSuchPortException; 015import purejavacomm.PortInUseException; 016import purejavacomm.SerialPort; 017import purejavacomm.UnsupportedCommOperationException; 018 019/** 020 * Implements SerialPortAdapter for the TAMS system. 021 * <p> 022 * This connects an TAMS command station via a serial com port. 023 * <p> 024 * Based on work by Bob Jacobsen 025 * 026 * @author Kevin Dickerson Copyright (C) 2012 027 */ 028public class SerialDriverAdapter extends TamsPortController { 029 030 SerialPort activeSerialPort = null; 031 032 public SerialDriverAdapter() { 033 super(new TamsSystemConnectionMemo()); 034 setManufacturer(jmri.jmrix.tams.TamsConnectionTypeList.TAMS); 035 } 036 037 @Override 038 public String openPort(String portName, String appName) { 039 // open the port, check ability to set moderators 040 try { 041 // get and open the primary port 042 CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(portName); 043 try { 044 activeSerialPort = (SerialPort) portID.open(appName, 2000); // name of program, msec to wait 045 } catch (PortInUseException p) { 046 return handlePortBusy(p, portName, log); 047 } 048 049 // try to set it for communication via SerialDriver 050 try { 051 // find the baud rate value, configure comm options 052 int baud = currentBaudNumber(mBaudRate); 053 activeSerialPort.setSerialPortParams(baud, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); 054 } catch (UnsupportedCommOperationException e) { 055 log.error("Cannot set serial parameters on port {}: {}", portName, e.getMessage()); 056 return "Cannot set serial parameters on port " + portName + ": " + e.getMessage(); 057 } 058 059 // Hardware flow control 060 //configureLeadsAndFlowControl(activeSerialPort, SerialPort.FLOWCONTROL_RTSCTS_IN | SerialPort.FLOWCONTROL_RTSCTS_OUT); 061 062 // Xon/Xoff flow control 063 configureLeadsAndFlowControl(activeSerialPort, 0); 064 065 // set timeout 066 try { 067 activeSerialPort.enableReceiveTimeout(50); // Set to 50 was 10 mSec timeout before sending chars 068 log.debug("Serial timeout was observed as: {} {}", activeSerialPort.getReceiveTimeout(), 069 activeSerialPort.isReceiveTimeoutEnabled()); 070 } catch (Exception et) { 071 log.info("failed to set serial timeout: ", et); 072 } 073 // get and save stream 074 serialStream = activeSerialPort.getInputStream(); 075 076 // purge contents, if any 077 purgeStream(serialStream); 078 079 if (log.isInfoEnabled()) { 080 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()); 081 } 082 083 // report status 084 if (log.isInfoEnabled()) { 085 log.info("TAMS {} port opened at {} baud", portName, 086 activeSerialPort.getBaudRate()); 087 } 088 opened = true; 089 090 } catch (NoSuchPortException p) { 091 return handlePortNotFound(p, portName, log); 092 } catch (IOException ex) { 093 log.error("Unexpected exception while opening port {}", portName, ex); 094 return "Unexpected error while opening port " + portName + ": " + ex; 095 } 096 097 return null; // indicates OK return 098 } 099 100 /** 101 * set up all of the other objects to operate with an NCE command station 102 * connected to this port 103 */ 104 @Override 105 public void configure() { 106 TamsTrafficController tc = new TamsTrafficController(); 107 this.getSystemConnectionMemo().setTamsTrafficController(tc); 108 tc.setAdapterMemo(this.getSystemConnectionMemo()); 109 110 tc.connectPort(this); 111 112 this.getSystemConnectionMemo().configureManagers(); 113 } 114 115 // base class methods for the TamsPortController interface 116 @Override 117 public DataInputStream getInputStream() { 118 if (!opened) { 119 log.error("getInputStream called before load(), stream not available"); 120 return null; 121 } 122 return new DataInputStream(serialStream); 123 } 124 125 @Override 126 public DataOutputStream getOutputStream() { 127 if (!opened) { 128 log.error("getOutputStream called before load(), stream not available"); 129 } 130 try { 131 return new DataOutputStream(activeSerialPort.getOutputStream()); 132 } catch (java.io.IOException e) { 133 log.error("getOutputStream exception: ", e); 134 } 135 return null; 136 } 137 138 @Override 139 public boolean status() { 140 return opened; 141 } 142 143 /** 144 * {@inheritDoc} 145 */ 146 @Override 147 public String[] validBaudRates() { 148 return Arrays.copyOf(validSpeeds, validSpeeds.length); 149 } 150 151 /** 152 * {@inheritDoc} 153 */ 154 @Override 155 public int[] validBaudNumbers() { 156 return Arrays.copyOf(validSpeedValues, validSpeedValues.length); 157 } 158 159 private final String[] validSpeeds = new String[]{Bundle.getMessage("Baud57600"), 160 Bundle.getMessage("Baud2400"), Bundle.getMessage("Baud9600"), 161 Bundle.getMessage("Baud19200")}; 162 private final int[] validSpeedValues = new int[]{57600, 2400, 9600, 19200}; 163 164 @Override 165 public int defaultBaudIndex() { 166 return 0; 167 } 168 169 // private control members 170 private boolean opened = false; 171 InputStream serialStream = null; 172 173 private final static Logger log = LoggerFactory.getLogger(SerialDriverAdapter.class); 174 175}