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