001package jmri.jmrix.ztc.ztc611; 002 003import java.io.DataInputStream; 004import java.io.DataOutputStream; 005import java.io.IOException; 006import java.io.InputStream; 007import java.util.Arrays; 008import jmri.jmrix.lenz.LenzCommandStation; 009import jmri.jmrix.lenz.XNetInitializationManager; 010import jmri.jmrix.lenz.XNetSerialPortController; 011import jmri.jmrix.lenz.XNetTrafficController; 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 * Provide access to XpressNet via a ZTC611 connected via an FTDI virtual comm 022 * port. 023 * 024 * @author Bob Jacobsen Copyright (C) 2002 025 * @author Paul Bender, Copyright (C) 2003-2017 026 */ 027public class ZTC611Adapter extends XNetSerialPortController { 028 029 public ZTC611Adapter() { 030 super(); 031 option1Name = "FlowControl"; // NOI18N 032 options.put(option1Name, new Option(Bundle.getMessage("XconnectionUsesLabel", Bundle.getMessage("CSTypeZtc640")), validOption1)); 033 } 034 035 @Override 036 public String openPort(String portName, String appName) { 037 // open the port in XpressNet mode, check ability to set moderators 038 try { 039 // get and open the primary port 040 CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(portName); 041 try { 042 activeSerialPort = (SerialPort) portID.open(appName, 2000); // name of program, msec to wait 043 } catch (PortInUseException p) { 044 return handlePortBusy(p, portName, log); 045 } 046 // try to set it for XNet 047 try { 048 setSerialPort(); 049 } catch (UnsupportedCommOperationException e) { 050 log.error("Cannot set serial parameters on port {}: {}", portName, e.getMessage()); 051 return "Cannot set serial parameters on port " + portName + ": " + e.getMessage(); 052 } 053 054 // set timeout 055 activeSerialPort.enableReceiveTimeout(10); 056 log.debug("Serial timeout was observed as: {} {}", activeSerialPort.getReceiveTimeout(), 057 activeSerialPort.isReceiveTimeoutEnabled()); 058 059 // get and save stream 060 serialStream = activeSerialPort.getInputStream(); 061 062 // purge contents, if any 063 purgeStream(serialStream); 064 065 // report status? 066 if (log.isInfoEnabled()) { 067 // report now 068 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()); 069 } 070 if (log.isDebugEnabled()) { 071 // report additional status 072 log.debug(" port flow control shows {}", activeSerialPort.getFlowControlMode() == SerialPort.FLOWCONTROL_RTSCTS_OUT ? "hardware flow control" : "no flow control"); // NOI18N 073 074 // log events 075 setPortEventLogging(activeSerialPort); 076 } 077 078 opened = true; 079 080 } catch (NoSuchPortException p) { 081 return handlePortNotFound(p, portName, log); 082 } catch (IOException ex) { 083 log.error("IO exception while opening port {}", portName, ex); 084 return "IO Exception while opening port " + portName + ": " + ex; 085 } catch (UnsupportedCommOperationException ucex) { 086 log.error("unsupported Comm Operation exception while opening port {}", portName, ucex); 087 return "Unsupported Comm Exception while opening port " + portName + ": " + ucex; 088 } 089 090 return null; // normal operation 091 } 092 093 /** 094 * set up all of the other objects to operate with a ZTC611 connected to 095 * this port 096 */ 097 @Override 098 public void configure() { 099 // connect to a packetizing traffic controller 100 XNetTrafficController packets = new ZTC611XNetPacketizer(new LenzCommandStation()); 101 packets.connectPort(this); 102 103 // start operation 104 // packets.startThreads(); 105 this.getSystemConnectionMemo().setXNetTrafficController(packets); 106 new XNetInitializationManager() 107 .memo(this.getSystemConnectionMemo()) 108 .setDefaults() 109 .turnoutManager(ZTC611XNetTurnoutManager.class) 110 .init(); 111 } 112 113 // base class methods for the XNetSerialPortController interface 114 @Override 115 public DataInputStream getInputStream() { 116 if (!opened) { 117 log.error("getInputStream called before load(), stream not available"); 118 return null; 119 } 120 return new DataInputStream(serialStream); 121 } 122 123 @Override 124 public DataOutputStream getOutputStream() { 125 if (!opened) { 126 log.error("getOutputStream called before load(), stream not available"); 127 } 128 try { 129 return new DataOutputStream(activeSerialPort.getOutputStream()); 130 } catch (IOException e) { 131 log.error("getOutputStream exception: {}", e.getMessage()); 132 } 133 return null; 134 } 135 136 @Override 137 public boolean status() { 138 return opened; 139 } 140 141 /** 142 * Local method to do specific configuration. 143 * 144 * @throws UnsupportedCommOperationException if there is an error 145 * configuring the port 146 */ 147 protected void setSerialPort() throws UnsupportedCommOperationException { 148 // find the baud rate value, configure comm options 149 int baud = currentBaudNumber(mBaudRate); 150 activeSerialPort.setSerialPortParams(baud, 151 SerialPort.DATABITS_8, 152 SerialPort.STOPBITS_1, 153 SerialPort.PARITY_NONE); 154 155 // find and configure flow control 156 int flow = 0; // default, but also deftaul for getOptionState(option1Name) 157 if (!getOptionState(option1Name).equals(validOption1[0])) { 158 flow = SerialPort.FLOWCONTROL_RTSCTS_OUT; 159 } 160 configureLeadsAndFlowControl(activeSerialPort, flow); 161 } 162 163 /** 164 * {@inheritDoc} 165 */ 166 @Override 167 public String[] validBaudRates() { 168 return Arrays.copyOf(validSpeeds, validSpeeds.length); 169 } 170 171 /** 172 * {@inheritDoc} 173 */ 174 @Override 175 public int[] validBaudNumbers() { 176 return Arrays.copyOf(validSpeedValues, validSpeedValues.length); 177 } 178 179 protected final String[] validSpeeds = new String[]{Bundle.getMessage("Baud9600")}; 180 protected final int[] validSpeedValues = new int[]{19200}; 181 182 @Override 183 public int defaultBaudIndex() { 184 return 0; 185 } 186 187 // meanings are assigned to these above, so make sure the order is consistent 188 protected final String[] validOption1 = new String[]{Bundle.getMessage("FlowOptionNoRecomm"), Bundle.getMessage("FlowOptionHw")}; 189 190 private boolean opened = false; 191 InputStream serialStream = null; 192 193 private final static Logger log = LoggerFactory.getLogger(ZTC611Adapter.class); 194 195}