001package jmri.jmrix.loconet.locobuffer; 002 003import java.util.Arrays; 004import java.util.Vector; 005import jmri.jmrix.loconet.LnCommandStationType; 006import jmri.jmrix.loconet.LnPacketizer; 007import jmri.jmrix.loconet.LnPacketizerStrict; 008import jmri.jmrix.loconet.LnPortController; 009import jmri.jmrix.loconet.LocoNetSystemConnectionMemo; 010import org.slf4j.Logger; 011import org.slf4j.LoggerFactory; 012 013/** 014 * Provide access to LocoNet via a LocoBuffer attached to a serial com port. 015 * <p> 016 * Normally controlled by the LocoBufferFrame class. 017 * 018 * @author Bob Jacobsen Copyright (C) 2001, 2008, 2010 019 */ 020public class LocoBufferAdapter extends LnPortController { 021 022 public LocoBufferAdapter() { 023 this(new LocoNetSystemConnectionMemo()); 024 } 025 026 public LocoBufferAdapter(LocoNetSystemConnectionMemo adapterMemo) { 027 super(adapterMemo); 028 option1Name = "FlowControl"; // NOI18N 029 option2Name = "CommandStation"; // NOI18N 030 option3Name = "TurnoutHandle"; // NOI18N 031 option4Name = "PacketizerType"; // NOI18N 032 options.put(option1Name, new Option(Bundle.getMessage("XconnectionUsesLabel", Bundle.getMessage("TypeSerial")), validOption1)); // NOI18N 033 options.put(option2Name, new Option(Bundle.getMessage("CommandStationTypeLabel"), getCommandStationListWithStandaloneLN(), false)); // NOI18N 034 options.put(option3Name, new Option(Bundle.getMessage("TurnoutHandling"), 035 new String[]{Bundle.getMessage("HandleNormal"), Bundle.getMessage("HandleSpread"), Bundle.getMessage("HandleOneOnly"), Bundle.getMessage("HandleBoth")})); // I18N 036 options.put(option4Name, new Option(Bundle.getMessage("PacketizerTypeLabel"), packetizerOptions())); // NOI18N 037 options.put("TranspondingPresent", new Option(Bundle.getMessage("TranspondingPresent"), 038 new String[]{Bundle.getMessage("ButtonNo"), Bundle.getMessage("ButtonYes")} )); // NOI18N 039 options.put("InterrogateOnStart", new Option(Bundle.getMessage("InterrogateOnStart"), 040 new String[]{Bundle.getMessage("ButtonYes"), Bundle.getMessage("ButtonNo")} )); // NOI18N 041 options.put("LoconetProtocolAutoDetect", new Option(Bundle.getMessage("LoconetProtocolAutoDetectLabel"), 042 new String[]{Bundle.getMessage("ButtonNo"),Bundle.getMessage("LoconetProtocolAutoDetect")} )); // NOI18N 043 } 044 045 /** 046 * Create a list of possible command stations and append "Standalone LocoNet" 047 * 048 * Note: This is not suitable for use by any class which extends this class if 049 * the hardware interface is part of a command station. 050 * 051 * @return String[] containing the array of command stations, plus "Standalone 052 * LocoNet" 053 */ 054 public String[] getCommandStationListWithStandaloneLN() { 055 String[] result = new String[commandStationNames.length + 1]; 056 for (int i = 0 ; i < result.length-1; ++i) { 057 result[i] = commandStationNames[i]; 058 } 059 result[commandStationNames.length] = LnCommandStationType.COMMAND_STATION_STANDALONE.getName(); 060 return result; 061 } 062 063 Vector<String> portNameVector = null; 064 065 @Override 066 public String openPort(String portName, String appName) { 067 // get and open the primary port 068 currentSerialPort = activatePort(portName, log); 069 if (currentSerialPort == null) { 070 log.error("failed to connect LocoBuffer to {}", portName); 071 return Bundle.getMessage("SerialPortNotFound", portName); 072 } 073 reportOpen(portName); 074 075 // try to set it for communication via SerialDriver 076 // find the baud rate value, configure comm options 077 int baud = currentBaudNumber(mBaudRate); 078 setBaudRate(currentSerialPort, baud); 079 configureLeads(currentSerialPort, true, true); 080 setLocalFlowControl(); 081 082 setComPortTimeouts(currentSerialPort, Blocking.READ_SEMI_BLOCKING, 100); 083 084 // report status 085 reportPortStatus(log, portName); 086 087 opened = true; 088 089 return null; // indicates OK return 090 } 091 092 /** 093 * Allow subtypes to change the opening message 094 * @param portName To appear in message 095 */ 096 protected void reportOpen(String portName) { 097 log.info("Connecting LocoBuffer via {} {}", portName, currentSerialPort); 098 } 099 100 /** 101 * Allow subtypes to change the flow control algorithm 102 */ 103 protected void setLocalFlowControl() { 104 FlowControl flow = FlowControl.RTSCTS; 105 if (getOptionState(option1Name).equals(validOption1[1])) { 106 flow = FlowControl.NONE; 107 } 108 setFlowControl(currentSerialPort, flow); 109 } 110 111 /** 112 * Can the port accept additional characters? The state of CTS determines 113 * this, as there seems to be no way to check the number of queued bytes and 114 * buffer length. This might go false for short intervals, but it might also 115 * stick off if something goes wrong. 116 * 117 * @return an indication of whether the interface is accepting transmit messages. 118 */ 119 @Override 120 public boolean okToSend() { 121 return currentSerialPort.getCTS(); 122 } 123 124 /** 125 * Set up all of the other objects to operate with a LocoBuffer connected to 126 * this port. 127 */ 128 @Override 129 public void configure() { 130 131 setCommandStationType(getOptionState(option2Name)); 132 setTurnoutHandling(getOptionState(option3Name)); 133 setTranspondingAvailable(getOptionState("TranspondingPresent")); 134 setInterrogateOnStart(getOptionState("InterrogateOnStart")); 135 setLoconetProtocolAutoDetect(getOptionState("LoconetProtocolAutoDetect")); 136 // connect to a packetizing traffic controller 137 LnPacketizer packets = getPacketizer(getOptionState(option4Name)); 138 packets.connectPort(this); 139 140 // create memo 141 this.getSystemConnectionMemo().setLnTrafficController(packets); 142 // do the common manager config 143 144 this.getSystemConnectionMemo().configureCommandStation(commandStationType, 145 mTurnoutNoRetry, mTurnoutExtraSpace, mTranspondingAvailable, mInterrogateAtStart, mLoconetProtocolAutoDetect); 146 this.getSystemConnectionMemo().configureManagers(); 147 148 // start operation 149 packets.startThreads(); 150 } 151 152 @Override 153 public boolean status() { 154 return opened; 155 } 156 157 /** 158 * {@inheritDoc} 159 */ 160 @Override 161 public String[] validBaudRates() { 162 return Arrays.copyOf(validSpeeds, validSpeeds.length); 163 } 164 165 /** 166 * {@inheritDoc} 167 */ 168 @Override 169 public int[] validBaudNumbers() { 170 return Arrays.copyOf(validSpeedValues, validSpeedValues.length); 171 } 172 173 protected String[] validSpeeds = new String[]{Bundle.getMessage("Baud19200LB"), Bundle.getMessage("Baud57600LB")}; 174 protected int[] validSpeedValues = new int[]{19200, 57600}; 175 176 @Override 177 public int defaultBaudIndex() { 178 return 0; 179 } 180 181 // meanings are assigned to these above, so make sure the order is consistent 182 protected String[] validOption1 = new String[]{Bundle.getMessage("FlowOptionHwRecomm"), Bundle.getMessage("FlowOptionNo")}; 183 184 /** 185 * Define the readable data and internal code 186 */ 187 private static String[][] packetizers = { {Bundle.getMessage("PacketizerTypelnPacketizer"),"lnPacketizer" }, 188 {Bundle.getMessage("PacketizerTypelnPacketizerStrict"),"lnPacketizerStrict"} }; 189 190 /** 191 * 192 * @return String array of readable choices 193 */ 194 private String[] packetizerOptions() { 195 String[] retval = new String[packetizers.length]; 196 for (int i=0;i < packetizers.length; i++) { 197 retval[i] = packetizers[i][0]; 198 } 199 return retval; 200 } 201 /** 202 * for a given readable choice return internal value 203 * or the default 204 * 205 * @param s string containing ?a packetizer name? 206 * @return internal value 207 */ 208 protected String getPacketizerOption(String s) { 209 for (int i=0;i < packetizers.length; i++) { 210 if (packetizers[i][0].equals(s)) { 211 return packetizers[i][1]; 212 } 213 } 214 return "lnPacketizer"; 215 } 216 /** 217 * 218 * @param s the packetizer to use in its readable form. 219 * @return a LnPacketizer 220 */ 221 protected LnPacketizer getPacketizer(String s) { 222 LnPacketizer packets; 223 String packetSelection = getPacketizerOption(s); 224 switch (packetSelection) { 225 case "lnPacketizer": 226 packets = new LnPacketizer(this.getSystemConnectionMemo()); 227 break; 228 case "lnPacketizerStrict": 229 packets = new LnPacketizerStrict(this.getSystemConnectionMemo()); 230 break; 231 default: 232 packets = new LnPacketizer(this.getSystemConnectionMemo()); 233 log.warn("Using Normal do not understand option [{}]", packetSelection); 234 } 235 return packets; 236 } 237 238 private final static Logger log = LoggerFactory.getLogger(LocoBufferAdapter.class); 239 240}