001package jmri.jmrix.lenz.ztc640; 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 ZTC640 connected via an FTDI virtual comm 022 * port. Normally controlled by the lenz.ztc640.ZTC640Frame class. 023 * 024 * @author Bob Jacobsen Copyright (C) 2002 025 * @author Paul Bender, Copyright (C) 2003-2010 026 */ 027public class ZTC640Adapter extends XNetSerialPortController { 028 029 public ZTC640Adapter() { 030 super(); 031 option1Name = "FlowControl"; // NOI18N 032 options.put(option1Name, new Option(Bundle.getMessage("ZTC640ConnectionLabel"), 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 try { 055 // set timeout 056 activeSerialPort.enableReceiveTimeout(10); 057 } catch (UnsupportedCommOperationException ex) { 058 log.error("Cannot set receive timeout on port {}: {}", portName, ex.getMessage()); 059 return "Cannot set receive timeout on port " + portName + ": " + ex.getMessage(); 060 } 061 log.debug("Serial timeout was observed as: {} {}", activeSerialPort.getReceiveTimeout(), 062 activeSerialPort.isReceiveTimeoutEnabled()); 063 064 // get and save stream 065 serialStream = activeSerialPort.getInputStream(); 066 067 // purge contents, if any 068 purgeStream(serialStream); 069 070 // report status? 071 if (log.isInfoEnabled()) { 072 // report now 073 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()); 074 } 075 if (log.isDebugEnabled()) { 076 // report additional status 077 log.debug(" port flow control shows {}", activeSerialPort.getFlowControlMode() == SerialPort.FLOWCONTROL_RTSCTS_OUT ? "hardware flow control" : "no flow control"); // NOI18N 078 079 // log events 080 setPortEventLogging(activeSerialPort); 081 } 082 083 opened = true; 084 085 } catch (NoSuchPortException p) { 086 return handlePortNotFound(p, portName, log); 087 } catch (IOException ex) { 088 log.error("Unexpected exception while opening port {}", portName, ex); 089 return "IO Exception while opening port " + portName + ": " + ex; 090 } 091 092 return null; // normal operation 093 } 094 095 /** 096 * Set up all of the other objects to operate with a ZTC640 connected to 097 * this port. 098 */ 099 @Override 100 public void configure() { 101 // connect to a packetizing traffic controller 102 XNetTrafficController packets = new ZTC640XNetPacketizer(new LenzCommandStation()); 103 packets.connectPort(this); 104 105 this.getSystemConnectionMemo().setXNetTrafficController(packets); 106 new XNetInitializationManager() 107 .memo(this.getSystemConnectionMemo()) 108 .setDefaults() 109 .versionCheck() 110 .setTimeout(30000) 111 .init(); 112 } 113 114 // base class methods for the XNetSerialPortController interface 115 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 (IOException e) { 133 log.error("getOutputStream exception: {}", e.getMessage()); 134 } 135 return null; 136 } 137 138 @Override 139 public boolean status() { 140 return opened; 141 } 142 143 /** 144 * Local method to do specific configuration. 145 * @throws UnsupportedCommOperationException if the underlying port can't comply with the settings 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 int flow = 0; // default, but also default for getOptionState(option1Name) 156 if (!getOptionState(option1Name).equals(validOption1[0])) { 157 flow = SerialPort.FLOWCONTROL_RTSCTS_OUT; 158 } 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("Baud19200")}; 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 InputStream serialStream = null; 191 192 private static final Logger log = LoggerFactory.getLogger(ZTC640Adapter.class); 193 194}