001package jmri.jmrix.loconet; 002 003import org.slf4j.Logger; 004import org.slf4j.LoggerFactory; 005 006/** 007 * Base for classes representing a LocoNet communications port. 008 * 009 * @author Bob Jacobsen Copyright (C) 2001, 2002 010 */ 011public abstract class LnPortController extends jmri.jmrix.AbstractSerialPortController { 012 // base class. Implementations will provide InputStream and OutputStream 013 // objects to LnTrafficController classes, who in turn will deal in messages. 014 015 protected LnPortController(LocoNetSystemConnectionMemo connectionMemo) { 016 super(connectionMemo); 017 setManufacturer(LnConnectionTypeList.DIGITRAX); 018 019 allowConnectionRecovery = true; 020 reconnectMaxAttempts = -1; // retry indefinitely 021 } 022 023 /** 024 * Check that this object is ready to operate. This is a question of 025 * configuration, not transient hardware status. 026 */ 027 @Override 028 public abstract boolean status(); 029 030 /** 031 * Can the port accept additional characters? This might go false for short 032 * intervals, but it might also stick off if something goes wrong. 033 * <p> 034 * Provide a default implementation for the MS100, etc. 035 * 036 * @return _always_ true, as we rely on the queueing in the port itself 037 */ 038 public boolean okToSend() { 039 return true; 040 } 041 042 private final java.util.concurrent.locks.Lock lockRecover = 043 new java.util.concurrent.locks.ReentrantLock(); 044 045 protected LnCommandStationType commandStationType = null; 046 047 protected boolean mTurnoutNoRetry = false; 048 protected boolean mTurnoutExtraSpace = false; 049 protected boolean mInterrogateAtStart = true; 050 protected boolean mTranspondingAvailable = false; 051 052 protected boolean mLoconetProtocolAutoDetect = true; 053 054 protected LnCommandStationType[] commandStationTypes = { 055 LnCommandStationType.COMMAND_STATION_DCS100, 056 LnCommandStationType.COMMAND_STATION_DCS240, 057 LnCommandStationType.COMMAND_STATION_DCS240PLUS, 058 LnCommandStationType.COMMAND_STATION_DCS210, 059 LnCommandStationType.COMMAND_STATION_DCS210PLUS, 060 LnCommandStationType.COMMAND_STATION_DCS200, 061 LnCommandStationType.COMMAND_STATION_DCS050, 062 LnCommandStationType.COMMAND_STATION_DCS051, 063 LnCommandStationType.COMMAND_STATION_DCS052, 064 LnCommandStationType.COMMAND_STATION_DB150, 065 LnCommandStationType.COMMAND_STATION_IBX_TYPE_1, 066 LnCommandStationType.COMMAND_STATION_IBX_TYPE_2, 067 LnCommandStationType.COMMAND_STATION_LBPS, 068 LnCommandStationType.COMMAND_STATION_MM}; 069 070 protected String[] commandStationNames; 071 072 { 073 commandStationNames = new String[commandStationTypes.length]; 074 int i = 0; 075 for (LnCommandStationType type : commandStationTypes) { 076 commandStationNames[i++] = type.getName(); 077 } 078 } 079 080 // There are also "PR3 standalone programmer" and "Stand-alone LocoNet" in pr3/PR3Adapter 081 // and "PR2 standalone programmer" in pr2/Pr2Adapter 082 /** 083 * Set config info from a name, which needs to be one of the valid ones. 084 * @param name the name of the command station type 085 */ 086 public void setCommandStationType(String name) { 087 setCommandStationType(LnCommandStationType.getByName(name)); 088 } 089 090 /** 091 * Set config info from the command station type enum. 092 * @param value the LnCommandStationType 093 */ 094 public void setCommandStationType(LnCommandStationType value) { 095 if (value == null) { 096 return; // can happen while switching protocols 097 } 098 log.debug("setCommandStationType: {}", value); // NOI18N 099 commandStationType = value; 100 } 101 102 public void setTurnoutHandling(String value) { 103 if (value.equals("One Only") || value.equals(Bundle.getMessage("HandleOneOnly")) 104 || value.equals("Both") || value.equals(Bundle.getMessage("HandleBoth"))) { 105 mTurnoutNoRetry = true; 106 } 107 log.debug("turnout no retry: {}", mTurnoutNoRetry); // NOI18N 108 if (value.equals("Spread") || value.equals(Bundle.getMessage("HandleSpread")) 109 || value.equals("Both") || value.equals(Bundle.getMessage("HandleBoth"))) { 110 mTurnoutExtraSpace = true; 111 } 112 log.debug("turnout extra space: {}", mTurnoutExtraSpace); // NOI18N 113 } 114 115 public void setTranspondingAvailable(String value) { 116 // default (most common state) is off, so just check for Yes 117 mTranspondingAvailable = (value.equals("Yes") || value.equals(Bundle.getMessage("ButtonYes"))); 118 log.debug("transponding available: {}", mTranspondingAvailable); // NOI18N 119 } 120 121 public void setLoconetProtocolAutoDetect(String value) { 122 // default (most common state) is off, so just check for Yes 123 mLoconetProtocolAutoDetect = (value.equals("Yes") || value.equals(Bundle.getMessage("LoconetProtocolAutoDetect"))); 124 log.debug("Loconet XPSlots: {}", mLoconetProtocolAutoDetect); // NOI18N 125 } 126 127 public void setInterrogateOnStart(String value) { 128 // default (most common state) is on, so just check for No 129 mInterrogateAtStart = !(value.equals("No") || value.equals(Bundle.getMessage("ButtonNo"))); 130 log.debug("tInterrogate on Start: {}", mInterrogateAtStart); // NOI18N 131 } 132 133 @Override 134 public LocoNetSystemConnectionMemo getSystemConnectionMemo() { 135 return (LocoNetSystemConnectionMemo) super.getSystemConnectionMemo(); 136 } 137 138 @Override 139 public final void recover() { 140 if (allowConnectionRecovery && opened) { 141 log.info("Connection lost. Attempting to recover..."); 142 } 143 144 // This method is sometimes called reentrant so to protect from that, 145 // we have a lock. 146 if (lockRecover.tryLock()) { 147 try { 148 super.recover(); 149 } finally { 150 lockRecover.unlock(); 151 } 152 } else { 153 log.warn("Reconnect already running"); 154 } 155 } 156 157 // after reconnect, reattach the packetizer's streams and restart the receive thread 158 @Override 159 protected final void resetupConnection() { 160 LnTrafficController tc = getSystemConnectionMemo().getLnTrafficController(); 161 if (tc instanceof LnPacketizer) { 162 LnPacketizer packets = (LnPacketizer) tc; 163 packets.connectPort(this); 164 packets.restartRcvThread(); 165 } 166 } 167 168 private static final Logger log = LoggerFactory.getLogger(LnPortController.class); 169 170}