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