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