001package jmri.jmrix.loconet; 002 003import java.util.Comparator; 004import java.util.ResourceBundle; 005import javax.annotation.Nonnull; 006 007import jmri.*; 008import jmri.jmrix.ConfiguringSystemConnectionMemo; 009import jmri.jmrix.DefaultSystemConnectionMemo; 010import jmri.jmrix.debugthrottle.DebugThrottleManager; 011import jmri.jmrix.loconet.swing.LnComponentFactory; 012import jmri.jmrix.swing.ComponentFactory; 013import jmri.managers.DefaultProgrammerManager; 014import jmri.util.NamedBeanComparator; 015 016import org.slf4j.Logger; 017import org.slf4j.LoggerFactory; 018 019/** 020 * Lightweight class to denote that a system is active, and provide general 021 * information. 022 * <p> 023 * Objects of specific subtypes are registered in the instance manager to 024 * activate their particular system. 025 * 026 * @author Bob Jacobsen Copyright (C) 2010 027 */ 028public class LocoNetSystemConnectionMemo extends DefaultSystemConnectionMemo implements ConfiguringSystemConnectionMemo { 029 030 /** 031 * Must manually register() after construction is complete. 032 * @param lt Traffic controller to be used 033 * @param sm Slot Manager to be used 034 */ 035 public LocoNetSystemConnectionMemo(LnTrafficController lt, SlotManager sm) { 036 super("L", "LocoNet"); // NOI18N 037 this.lt = lt; 038 039 this.sm = sm; // doesn't full register, but fine for this purpose. 040 041 // self-registration is deferred until the command station type is set below 042 043 // create and register the ComponentFactory for the GUI 044 InstanceManager.store(cf = new LnComponentFactory(this), 045 ComponentFactory.class); 046 } 047 048 /** 049 * Must manually register() after construction is complete. 050 */ 051 public LocoNetSystemConnectionMemo() { 052 this("L", "LocoNet"); // NOI18N 053 } 054 055 public LocoNetSystemConnectionMemo(@Nonnull String prefix, @Nonnull String name) { 056 super(prefix, name); // NOI18N 057 058 // create and register the ComponentFactory for the GUI 059 InstanceManager.store(cf = new LnComponentFactory(this), 060 ComponentFactory.class); 061 } 062 063 /** 064 * Do both the default parent 065 * {@link jmri.SystemConnectionMemo} registration, 066 * and register this specific type. 067 */ 068 @Override 069 public void register() { 070 super.register(); // registers general type 071 InstanceManager.store(this, LocoNetSystemConnectionMemo.class); // also register as specific type 072 } 073 074 ComponentFactory cf = null; 075 private LnTrafficController lt; 076 protected LocoNetThrottledTransmitter tm; 077 private SlotManager sm; 078 private LncvDevicesManager lncvdm = null; 079 private LnMessageManager lnm = null; 080 081 /** 082 * Provide access to the SlotManager for this particular connection. 083 * 084 * @return the slot manager or null if no valid slot manager is available 085 */ 086 public SlotManager getSlotManager() { 087 if (sm == null) { 088 log.debug("slot manager is null, but there should always be a valid SlotManager", new Exception("Traceback")); 089 } 090 return sm; 091 } 092 093 /** 094 * Provide access to the TrafficController for this particular connection. 095 * 096 * @return the LocoNet-specific TrafficController 097 */ 098 public LnTrafficController getLnTrafficController() { 099 if (lt == null) { 100 setLnTrafficController(new LnPacketizer(this)); // default to Packetizer TrafficController 101 log.debug("Auto create of LnTrafficController for initial configuration"); 102 } 103 return lt; 104 } 105 106 public void setLnTrafficController(LnTrafficController lt) { 107 this.lt = lt; 108 } 109 110 public LnMessageManager getLnMessageManager() { 111 // create when needed 112 if (lnm == null) { 113 lnm = new LnMessageManager(getLnTrafficController()); 114 } 115 return lnm; 116 } 117 118 public DefaultProgrammerManager getProgrammerManager() { 119 return (DefaultProgrammerManager) classObjectMap.computeIfAbsent(DefaultProgrammerManager.class,(Class<?> c) -> new LnProgrammerManager(this)); 120 } 121 122 public void setProgrammerManager(DefaultProgrammerManager p) { 123 store(p,DefaultProgrammerManager.class); 124 } 125 126 public void setLncvDevicesManager(LncvDevicesManager lncvdm) { 127 this.lncvdm = lncvdm; 128 } 129 130 protected boolean mTurnoutNoRetry = false; 131 protected boolean mTurnoutExtraSpace = false; 132 protected boolean mInterrogateAtStart = true; 133 134 /** 135 * Configure the programming manager and "command station" objects. 136 * 137 * @param type Command station type, used to configure various 138 * operations 139 * @param mTurnoutNoRetry Is the user configuration set for no turnout 140 * operation retries? 141 * @param mTurnoutExtraSpace Is the user configuration set for extra time 142 * between turnout operations? 143 * @param mTranspondingAvailable Is the layout configured to provide 144 * transopnding reports 145 * @param mInterrogate Send interrogate messages at start up 146 * @param mLoconetProtocolAutoDetect Do we automatically detect the protocol to use or force LocoNet 1.1 147 */ 148 public void configureCommandStation(LnCommandStationType type, boolean mTurnoutNoRetry, 149 boolean mTurnoutExtraSpace, boolean mTranspondingAvailable, 150 boolean mInterrogate, boolean mLoconetProtocolAutoDetect) { 151 152 // store arguments 153 this.mTurnoutNoRetry = mTurnoutNoRetry; 154 this.mTurnoutExtraSpace = mTurnoutExtraSpace; 155 this.mInterrogateAtStart = mInterrogate; 156 157 // create and install SlotManager 158 if (sm != null) { 159 log.error("Installing SlotManager twice", new Exception("TraceBack")); 160 } 161 sm = type.getSlotManager(lt); 162 if (sm != null) { 163 sm.setThrottledTransmitter(tm, mTurnoutNoRetry); 164 165 sm.setCommandStationType(type); 166 sm.setSystemConnectionMemo(this); 167 sm.setTranspondingAvailable(mTranspondingAvailable); 168 sm.setLoconetProtocolAutoDetect(mLoconetProtocolAutoDetect); 169 170 // store as CommandStation object 171 InstanceManager.store(sm, jmri.CommandStation.class); 172 store(sm, jmri.CommandStation.class); 173 } 174 175 } 176 177 /** 178 * Configure the common managers for LocoNet connections. This puts the 179 * common manager config in one place. 180 */ 181 @Override 182 public void configureManagers() { 183 184 tm = new LocoNetThrottledTransmitter(getLnTrafficController(), mTurnoutExtraSpace); 185 log.debug("ThrottleTransmitted configured with: {}", mTurnoutExtraSpace); 186 if (sm != null) { 187 sm.setThrottledTransmitter(tm, mTurnoutNoRetry); 188 log.debug("set turnout retry: {}", mTurnoutNoRetry); 189 } 190 191 InstanceManager.store(getPowerManager(), PowerManager.class); 192 193 InstanceManager.setSensorManager( 194 getSensorManager()); 195 196 InstanceManager.setTurnoutManager( 197 getTurnoutManager()); 198 199 InstanceManager.setLightManager( 200 getLightManager()); 201 202 InstanceManager.setDefault(StringIOManager.class, getStringIOManager()); 203 204 InstanceManager.setThrottleManager( 205 getThrottleManager()); 206 207 DefaultProgrammerManager programmerManager = getProgrammerManager(); 208 209 if (programmerManager.isAddressedModePossible()) { 210 store(programmerManager, AddressedProgrammerManager.class); 211 InstanceManager.store(programmerManager, AddressedProgrammerManager.class); 212 } 213 if (programmerManager.isGlobalProgrammerAvailable()) { 214 store(getProgrammerManager(), GlobalProgrammerManager.class); 215 InstanceManager.store(getProgrammerManager(), GlobalProgrammerManager.class); 216 } 217 218 InstanceManager.setReporterManager(getReporterManager()); 219 220 InstanceManager.setDefault(CabSignalManager.class,getCabSignalManager()); 221 222 setConsistManager(new LocoNetConsistManager(this)); 223 224 setLncvDevicesManager(new jmri.jmrix.loconet.LncvDevicesManager(this)); 225 226 ClockControl cc = getClockControl(); 227 228 InstanceManager.setDefault(ClockControl.class, cc); 229 230 getIdTagManager(); 231 232 // register this SystemConnectionMemo to connect to rest of system 233 register(); 234 235 // This must be done after the memo is registered 236 getPredefinedMeters(); 237 238 // This must be done after the memo is registered 239 getThrottleStringIO(); 240 } 241 242 public LnPowerManager getPowerManager() { 243 if (getDisabled()) { 244 return null; 245 } 246 return (LnPowerManager) classObjectMap.computeIfAbsent(PowerManager.class,(Class<?> c) -> new LnPowerManager(this)); 247 } 248 249 public ThrottleManager getThrottleManager() { 250 if (getSlotManager() != null) { 251 log.debug("GetThrottleManager for {}", getSlotManager().getCommandStationType()); 252 } 253 if (getDisabled()) { 254 return null; 255 } 256 ThrottleManager throttleManager = get(ThrottleManager.class); 257 if (throttleManager == null && getSlotManager() != null) { 258 // ask command station type for specific throttle manager 259 LnCommandStationType cmdstation = getSlotManager().getCommandStationType(); 260 log.debug("getThrottleManager constructs for {}", cmdstation.getName()); 261 throttleManager = cmdstation.getThrottleManager(this); 262 log.debug("result was type {}", throttleManager.getClass()); 263 store(throttleManager,ThrottleManager.class); 264 } 265 return throttleManager; 266 } 267 268 public void setThrottleManager(ThrottleManager t) { 269 store(t,ThrottleManager.class); 270 } 271 272 public LnTurnoutManager getTurnoutManager() { 273 if (getDisabled()) { 274 return null; 275 } 276 return (LnTurnoutManager) classObjectMap.computeIfAbsent(TurnoutManager.class,(Class<?> c) -> new LnTurnoutManager(this, tm, mTurnoutNoRetry)); 277 } 278 279 public LnClockControl getClockControl() { 280 if (getDisabled()) { 281 return null; 282 } 283 return (LnClockControl) classObjectMap.computeIfAbsent(ClockControl.class,(Class<?> c) -> new LnClockControl(this)); 284 } 285 286 public LnReporterManager getReporterManager() { 287 if (getDisabled()) { 288 return null; 289 } 290 return (LnReporterManager) classObjectMap.computeIfAbsent(ReporterManager.class, (Class<?> c) -> new LnReporterManager(this)); 291 } 292 293 public LnSensorManager getSensorManager() { 294 if (getDisabled()) { 295 return null; 296 } 297 return (LnSensorManager) classObjectMap.computeIfAbsent(SensorManager.class, (Class<?> c) -> new LnSensorManager(this, mInterrogateAtStart)); 298 } 299 300 public LnLightManager getLightManager() { 301 if (getDisabled()) { 302 return null; 303 } 304 return (LnLightManager) classObjectMap.computeIfAbsent(LightManager.class, (Class<?> c) -> new LnLightManager(this)); 305 } 306 307 public LncvDevicesManager getLncvDevicesManager() { 308 if (getDisabled()) { 309 return null; 310 } 311 if (lncvdm == null) { 312 setLncvDevicesManager(new LncvDevicesManager(this)); 313 log.debug("Auto create of LncvDevicesManager for initial configuration"); 314 } 315 return lncvdm; 316 } 317 318 public LnStringIOManager getStringIOManager() { 319 if (getDisabled()) { 320 return null; 321 } 322 return (LnStringIOManager) classObjectMap.computeIfAbsent(StringIOManager.class, (Class<?> c) -> new LnStringIOManager(this)); 323 } 324 325 protected LnPredefinedMeters predefinedMeters; 326 327 public LnPredefinedMeters getPredefinedMeters() { 328 if (getDisabled()) { 329 log.warn("Aborting getPredefinedMeters account is disabled!"); 330 return null; 331 } 332// switch (getSlotManager().commandStationType) { 333// case COMMAND_STATION_USB_DCS240_ALONE: 334// case COMMAND_STATION_DCS240: 335// case COMMAND_STATION_DCS210: 336// case COMMAND_STATION_USB_DCS52_ALONE: 337// case COMMAND_STATION_DCS052: 338// break; 339// default: 340// // The command station does not support these meters 341// return null; 342// } 343 if (predefinedMeters == null) { 344 predefinedMeters = new LnPredefinedMeters(this); 345 } 346 return predefinedMeters; 347 } 348 349 LnThrottleStringIO throttleStringIO; 350 351 public void getThrottleStringIO() { 352 if (getDisabled()) { 353 log.warn("Aborting getThrottleStringIO account is disabled!"); 354 return; 355 } 356 if (throttleStringIO == null) { 357 throttleStringIO = new LnThrottleStringIO(this); 358 InstanceManager.getDefault(jmri.StringIOManager.class) 359 .register(throttleStringIO); 360 } 361 } 362 363 @Override 364 protected ResourceBundle getActionModelResourceBundle() { 365 return ResourceBundle.getBundle("jmri.jmrix.loconet.LocoNetActionListBundle"); 366 } 367 368 @Override 369 public <B extends NamedBean> Comparator<B> getNamedBeanComparator(Class<B> type) { 370 return new NamedBeanComparator<>(); 371 } 372 373 // yes, tagManager is static. Tags can move between system connections. 374 // when readers are not all on the same LocoNet 375 // this manager is loaded on demand. 376 static TranspondingTagManager tagManager; 377 378 static public TranspondingTagManager getIdTagManager() { 379 synchronized (LocoNetSystemConnectionMemo.class) { // since tagManager can be null, can't synch on that 380 if (tagManager == null) { 381 tagManager = new TranspondingTagManager(); 382 InstanceManager.setIdTagManager(tagManager); 383 } 384 return tagManager; 385 } 386 } 387 388 public LnCabSignalManager getCabSignalManager() { 389 return (LnCabSignalManager) classObjectMap.computeIfAbsent(CabSignalManager.class,(Class<?> c) -> new LnCabSignalManager(this)); 390 } 391 392 @Override 393 public void dispose() { 394 if (throttleStringIO != null) { 395 throttleStringIO = null; 396 } 397 if (predefinedMeters != null) { 398 predefinedMeters.dispose(); 399 } 400 InstanceManager.deregister(this, LocoNetSystemConnectionMemo.class); 401 if (cf != null) { 402 InstanceManager.deregister(cf, ComponentFactory.class); 403 cf = null; 404 } 405 ThrottleManager throttleManager = get(ThrottleManager.class); 406 if (throttleManager != null) { 407 if (throttleManager instanceof LnThrottleManager) { 408 InstanceManager.deregister(((LnThrottleManager) throttleManager), LnThrottleManager.class); 409 } else if (throttleManager instanceof DebugThrottleManager) { 410 InstanceManager.deregister(((DebugThrottleManager) throttleManager), DebugThrottleManager.class); 411 } 412 deregister(throttleManager,ThrottleManager.class); 413 } 414 415 if (tm != null){ 416 tm.dispose(); 417 tm = null; 418 } 419 if (sm != null){ 420 sm.dispose(); 421 sm = null; 422 } 423 if (lt != null){ 424 lt.dispose(); 425 lt = null; 426 } 427 super.dispose(); 428 } 429 430 private final static Logger log = LoggerFactory.getLogger(LocoNetSystemConnectionMemo.class); 431 432}