001package jmri.jmrix.lenz.li100; 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 LI100 on an attached serial com port. 022 * Normally controlled by the lenz.li100.LI100Frame class. 023 * 024 * @author Bob Jacobsen Copyright (C) 2002 025 * @author Paul Bender, Copyright (C) 2003-2010 026 */ 027public class LI100Adapter extends XNetSerialPortController { 028 029 public LI100Adapter() { 030 super(); 031 option1Name = "FlowControl"; // NOI18N 032 options.put(option1Name, new Option(Bundle.getMessage("XconnectionUsesLabel", 033 Bundle.getMessage("IFTypeLI100")), validOption1)); 034 this.manufacturerName = jmri.jmrix.lenz.LenzConnectionTypeList.LENZ; 035 } 036 037 /** 038 * {@inheritDoc} 039 */ 040 @Override 041 public String openPort(String portName, String appName) { 042 // open the port in XpressNet mode, check ability to set moderators 043 try { 044 // get and open the primary port 045 CommPortIdentifier portID = CommPortIdentifier.getPortIdentifier(portName); 046 try { 047 activeSerialPort = (SerialPort) portID.open(appName, 2000); // name of program, msec to wait 048 } catch (PortInUseException p) { 049 return handlePortBusy(p, portName, log); 050 } 051 // try to set it for XNet 052 try { 053 setSerialPort(); 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 // set timeout 060 try { 061 activeSerialPort.enableReceiveTimeout(10); 062 log.debug("Serial timeout was observed as: {} {}", 063 activeSerialPort.getReceiveTimeout(), 064 activeSerialPort.isReceiveTimeoutEnabled()); 065 } catch (UnsupportedCommOperationException et) { 066 log.info("failed to set serial timeout: ", et); 067 } 068 069 // get and save stream 070 serialStream = activeSerialPort.getInputStream(); 071 072 // purge contents, if any 073 purgeStream(serialStream); 074 075 // report status? 076 if (log.isInfoEnabled()) { 077 // report now 078 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()); 079 } 080 if (log.isDebugEnabled()) { 081 // report additional status 082 log.debug(" port flow control shows {}", // NOI18N 083 (activeSerialPort.getFlowControlMode() == SerialPort.FLOWCONTROL_RTSCTS_OUT ? "hardware flow control" : "no flow control")); // NOI18N 084 085 // log events 086 setPortEventLogging(activeSerialPort); 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; // normal operation 098 } 099 100 /** 101 * Set up all of the other objects to operate with a LI100 connected to this 102 * port. 103 */ 104 @Override 105 public void configure() { 106 // connect to a packetizing traffic controller 107 XNetTrafficController packets = new LI100XNetPacketizer(new LenzCommandStation()); 108 packets.connectPort(this); 109 110 // start operation 111 // packets.startThreads(); 112 this.getSystemConnectionMemo().setXNetTrafficController(packets); 113 114 new XNetInitializationManager() 115 .memo(this.getSystemConnectionMemo()) 116 .setDefaults() 117 .versionCheck() 118 .setTimeout(30000) 119 .programmer(LI100XNetProgrammer.class) 120 .init(); 121 } 122 123 /** 124 * {@inheritDoc} 125 */ 126 @Override 127 public DataInputStream getInputStream() { 128 if (!opened) { 129 log.error("getInputStream called before load(), stream not available"); 130 return null; 131 } 132 return new DataInputStream(serialStream); 133 } 134 135 /** 136 * {@inheritDoc} 137 */ 138 @Override 139 public DataOutputStream getOutputStream() { 140 if (!opened) { 141 log.error("getOutputStream called before load(), stream not available"); 142 } 143 try { 144 return new DataOutputStream(activeSerialPort.getOutputStream()); 145 } catch (java.io.IOException e) { 146 log.error("getOutputStream exception: {}", e.getMessage()); 147 } 148 return null; 149 } 150 151 /** 152 * {@inheritDoc} 153 */ 154 @Override 155 public boolean status() { 156 return opened; 157 } 158 159 /** 160 * Local method to do specific configuration. 161 * @throws UnsupportedCommOperationException if port can't do as asked 162 */ 163 protected void setSerialPort() throws UnsupportedCommOperationException { 164 // find the baud rate value, configure comm options 165 int baud = currentBaudNumber(mBaudRate); 166 activeSerialPort.setSerialPortParams(baud, 167 SerialPort.DATABITS_8, 168 SerialPort.STOPBITS_1, 169 SerialPort.PARITY_NONE); 170 171 // find and configure flow control 172 int flow = SerialPort.FLOWCONTROL_RTSCTS_OUT; // default, but also default for getOptionState(option1Name) 173 if (!getOptionState(option1Name).equals(validOption1[0])) { 174 flow = 0; 175 } 176 configureLeadsAndFlowControl(activeSerialPort, flow); 177 } 178 179 /** 180 * {@inheritDoc} 181 */ 182 @Override 183 public String[] validBaudRates() { 184 return Arrays.copyOf(validSpeeds, validSpeeds.length); 185 } 186 187 /** 188 * {@inheritDoc} 189 */ 190 @Override 191 public int[] validBaudNumbers() { 192 return Arrays.copyOf(validSpeedValues, validSpeedValues.length); 193 } 194 195 protected final String[] validSpeeds = new String[]{Bundle.getMessage("Baud9600")}; 196 protected final int[] validSpeedValues = new int[]{9600}; 197 198 @Override 199 public int defaultBaudIndex() { 200 return 0; 201 } 202 203 // meanings are assigned to these above, so make sure the order is consistent 204 protected final String[] validOption1 = new String[]{Bundle.getMessage("FlowOptionHwRecomm"), Bundle.getMessage("FlowOptionNo")}; 205 206 private boolean opened = false; 207 InputStream serialStream = null; 208 209 private static final Logger log = LoggerFactory.getLogger(LI100Adapter.class); 210 211}