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; 075 private LnTrafficController lt; 076 protected LocoNetThrottledTransmitter tm; 077 private SlotManager sm; 078 private LncvDevicesManager lncvdm = null; 079 private Lnsv1DevicesManager lnsv1dm = null; 080 private LnMessageManager lnm = null; 081 private Ln7gAccyRoutesManager ln7gAcRtm; 082 083 /** 084 * Provide access to the SlotManager for this particular connection. 085 * 086 * @return the slot manager or null if no valid slot manager is available 087 */ 088 public SlotManager getSlotManager() { 089 if (sm == null) { 090 log.debug("slot manager is null, but there should always be a valid SlotManager", new Exception("Traceback")); 091 } 092 return sm; 093 } 094 095 /** 096 * Provide access to the TrafficController for this particular connection. 097 * 098 * @return the LocoNet-specific TrafficController 099 */ 100 public LnTrafficController getLnTrafficController() { 101 if (lt == null) { 102 setLnTrafficController(new LnPacketizer(this)); // default to Packetizer TrafficController 103 log.debug("Auto create of LnTrafficController for initial configuration"); 104 } 105 return lt; 106 } 107 108 public void setLnTrafficController(LnTrafficController lt) { 109 this.lt = lt; 110 } 111 112 public LnMessageManager getLnMessageManager() { 113 // create when needed 114 if (lnm == null) { 115 lnm = new LnMessageManager(getLnTrafficController()); 116 } 117 return lnm; 118 } 119 120 public DefaultProgrammerManager getProgrammerManager() { 121 return (DefaultProgrammerManager) classObjectMap.computeIfAbsent(DefaultProgrammerManager.class,(Class<?> c) -> new LnProgrammerManager(this)); 122 } 123 124 public void setProgrammerManager(DefaultProgrammerManager p) { 125 store(p,DefaultProgrammerManager.class); 126 } 127 128 public void setLncvDevicesManager(LncvDevicesManager lncvdm) { 129 this.lncvdm = lncvdm; 130 } 131 132 public void setLnsv1DevicesManager(Lnsv1DevicesManager lnsv1dm) { 133 this.lnsv1dm = lnsv1dm; 134 } 135 136 protected boolean mTurnoutNoRetry = false; 137 protected boolean mTurnoutExtraSpace = false; 138 protected boolean mInterrogateAtStart = true; 139 140 /** 141 * Configure the programming manager and "command station" objects. 142 * 143 * @param type Command station type, used to configure various 144 * operations 145 * @param mTurnoutNoRetry Is the user configuration set for no turnout 146 * operation retries? 147 * @param mTurnoutExtraSpace Is the user configuration set for extra time 148 * between turnout operations? 149 * @param mTranspondingAvailable Is the layout configured to provide 150 * transponding reports 151 * @param mInterrogate Send interrogate messages at start up 152 * @param mLoconetProtocolAutoDetect Do we automatically detect the protocol to use or force LocoNet 1.1 153 */ 154 public void configureCommandStation(LnCommandStationType type, boolean mTurnoutNoRetry, 155 boolean mTurnoutExtraSpace, boolean mTranspondingAvailable, 156 boolean mInterrogate, boolean mLoconetProtocolAutoDetect) { 157 158 // store arguments 159 this.mTurnoutNoRetry = mTurnoutNoRetry; 160 this.mTurnoutExtraSpace = mTurnoutExtraSpace; 161 this.mInterrogateAtStart = mInterrogate; 162 163 // create and install SlotManager 164 if (sm != null) { 165 log.error("Installing SlotManager twice", new Exception("TraceBack")); 166 } 167 sm = type.getSlotManager(lt); 168 if (sm != null) { 169 sm.setThrottledTransmitter(tm, mTurnoutNoRetry); 170 171 sm.setCommandStationType(type); 172 sm.setSystemConnectionMemo(this); 173 sm.setTranspondingAvailable(mTranspondingAvailable); 174 sm.setLoconetProtocolAutoDetect(mLoconetProtocolAutoDetect); 175 176 // store as CommandStation object 177 InstanceManager.store(sm, jmri.CommandStation.class); 178 store(sm, jmri.CommandStation.class); 179 } 180 181 } 182 183 /** 184 * Configure the common managers for LocoNet connections. This puts the 185 * common manager config in one place. 186 */ 187 @Override 188 public void configureManagers() { 189 190 tm = new LocoNetThrottledTransmitter(getLnTrafficController(), mTurnoutExtraSpace); 191 log.debug("ThrottleTransmitted configured with: {}", mTurnoutExtraSpace); 192 if (sm != null) { 193 sm.setThrottledTransmitter(tm, mTurnoutNoRetry); 194 log.debug("set turnout retry: {}", mTurnoutNoRetry); 195 } 196 197 InstanceManager.store(getPowerManager(), PowerManager.class); 198 199 InstanceManager.setSensorManager( 200 getSensorManager()); 201 202 InstanceManager.setTurnoutManager( 203 getTurnoutManager()); 204 205 InstanceManager.setLightManager( 206 getLightManager()); 207 208 InstanceManager.setStringIOManager(getStringIOManager()); 209 210 InstanceManager.setThrottleManager( 211 getThrottleManager()); 212 213 DefaultProgrammerManager programmerManager = getProgrammerManager(); 214 215 if (programmerManager.isAddressedModePossible()) { 216 store(programmerManager, AddressedProgrammerManager.class); 217 InstanceManager.store(programmerManager, AddressedProgrammerManager.class); 218 } 219 if (programmerManager.isGlobalProgrammerAvailable()) { 220 store(getProgrammerManager(), GlobalProgrammerManager.class); 221 InstanceManager.store(getProgrammerManager(), GlobalProgrammerManager.class); 222 } 223 224 InstanceManager.setReporterManager(getReporterManager()); 225 226 InstanceManager.setDefault(CabSignalManager.class,getCabSignalManager()); 227 228 setConsistManager(new LocoNetConsistManager(this)); 229 230 setLncvDevicesManager(new jmri.jmrix.loconet.LncvDevicesManager(this)); 231 232 ClockControl cc = getClockControl(); 233 234 InstanceManager.setDefault(ClockControl.class, cc); 235 236 getIdTagManager(); 237 238 // register this SystemConnectionMemo to connect to rest of system 239 register(); 240 241 // This must be done after the memo is registered 242 getPredefinedMeters(); 243 244 // This must be done after the memo is registered 245 getThrottleStringIO(); 246 247 ln7gAcRtm = 248 setLn7gAccyRoutesManager( 249 getLn7gAccyRoutesManager()); 250 log.debug("Established Ln Accy Rt Mgr with memo {}",ln7gAcRtm.getMemo()); 251 252 } 253 254 public LnPowerManager getPowerManager() { 255 if (getDisabled()) { 256 return null; 257 } 258 return (LnPowerManager) classObjectMap.computeIfAbsent(PowerManager.class,(Class<?> c) -> new LnPowerManager(this)); 259 } 260 261 public ThrottleManager getThrottleManager() { 262 if (getSlotManager() != null) { 263 log.debug("GetThrottleManager for {}", getSlotManager().getCommandStationType()); 264 } 265 if (getDisabled()) { 266 return null; 267 } 268 ThrottleManager throttleManager = get(ThrottleManager.class); 269 if (throttleManager == null && getSlotManager() != null) { 270 // ask command station type for specific throttle manager 271 LnCommandStationType cmdstation = getSlotManager().getCommandStationType(); 272 log.debug("getThrottleManager constructs for {}", cmdstation.getName()); 273 throttleManager = cmdstation.getThrottleManager(this); 274 assert throttleManager != null; 275 log.debug("result was type {}", throttleManager.getClass()); 276 store(throttleManager,ThrottleManager.class); 277 } 278 return throttleManager; 279 } 280 281 public void setThrottleManager(ThrottleManager t) { 282 store(t,ThrottleManager.class); 283 } 284 285 public LnTurnoutManager getTurnoutManager() { 286 if (getDisabled()) { 287 return null; 288 } 289 return (LnTurnoutManager) classObjectMap.computeIfAbsent(TurnoutManager.class,(Class<?> c) -> new LnTurnoutManager(this, tm, mTurnoutNoRetry)); 290 } 291 292 public LnClockControl getClockControl() { 293 if (getDisabled()) { 294 return null; 295 } 296 return (LnClockControl) classObjectMap.computeIfAbsent(ClockControl.class,(Class<?> c) -> new LnClockControl(this)); 297 } 298 299 public LnReporterManager getReporterManager() { 300 if (getDisabled()) { 301 return null; 302 } 303 return (LnReporterManager) classObjectMap.computeIfAbsent(ReporterManager.class, (Class<?> c) -> new LnReporterManager(this)); 304 } 305 306 public LnSensorManager getSensorManager() { 307 if (getDisabled()) { 308 return null; 309 } 310 return (LnSensorManager) classObjectMap.computeIfAbsent(SensorManager.class, (Class<?> c) -> new LnSensorManager(this, mInterrogateAtStart)); 311 } 312 313 public LnLightManager getLightManager() { 314 if (getDisabled()) { 315 return null; 316 } 317 return (LnLightManager) classObjectMap.computeIfAbsent(LightManager.class, (Class<?> c) -> new LnLightManager(this)); 318 } 319 320 public Lnsv1DevicesManager getLnsv1DevicesManager() { 321 if (getDisabled()) { 322 return null; 323 } 324 if (lnsv1dm == null) { 325 setLnsv1DevicesManager(new Lnsv1DevicesManager(this)); 326 log.debug("Auto create of Lnsv1DevicesManager for initial configuration"); 327 } 328 return lnsv1dm; 329 } 330 331 public LncvDevicesManager getLncvDevicesManager() { 332 if (getDisabled()) { 333 return null; 334 } 335 if (lncvdm == null) { 336 setLncvDevicesManager(new LncvDevicesManager(this)); 337 log.debug("Auto create of LncvDevicesManager for initial configuration"); 338 } 339 return lncvdm; 340 } 341 342 public LnStringIOManager getStringIOManager() { 343 if (getDisabled()) { 344 return null; 345 } 346 return (LnStringIOManager) classObjectMap.computeIfAbsent(StringIOManager.class, (Class<?> c) -> new LnStringIOManager(this)); 347 } 348 349 public Ln7gAccyRoutesManager setLn7gAccyRoutesManager(Ln7gAccyRoutesManager ln7gaccyrm) { 350 this.ln7gAcRtm = ln7gaccyrm; 351 if (this.ln7gAcRtm != null) { 352 // this can only be true when getDisabled() == false 353 this.ln7gAcRtm.initContext(this); 354 } 355 return this.ln7gAcRtm; 356 } 357 358 public Ln7gAccyRoutesManager getLn7gAccyRoutesManager() { 359 if (getDisabled()) { 360 return null; 361 } 362 return (Ln7gAccyRoutesManager) classObjectMap.computeIfAbsent(Ln7gAccyRoutesManager.class, 363 (Class<?> c) -> new Ln7gAccyRoutesManager()); 364 } 365 366 protected LnPredefinedMeters predefinedMeters; 367 368 public LnPredefinedMeters getPredefinedMeters() { 369 if (getDisabled()) { 370 log.warn("Aborting getPredefinedMeters account is disabled!"); 371 return null; 372 } 373// switch (getSlotManager().commandStationType) { 374// case COMMAND_STATION_USB_DCS240_ALONE: 375// case COMMAND_STATION_DCS240: 376// case COMMAND_STATION_DCS210: 377// case COMMAND_STATION_USB_DCS52_ALONE: 378// case COMMAND_STATION_DCS052: 379// break; 380// default: 381// // The command station does not support these meters 382// return null; 383// } 384 if (predefinedMeters == null) { 385 predefinedMeters = new LnPredefinedMeters(this); 386 } 387 return predefinedMeters; 388 } 389 390 LnThrottleStringIO throttleStringIO; 391 392 public void getThrottleStringIO() { 393 if (getDisabled()) { 394 log.warn("Aborting getThrottleStringIO account is disabled!"); 395 return; 396 } 397 if (throttleStringIO == null) { 398 throttleStringIO = new LnThrottleStringIO(this); 399 InstanceManager.getDefault(jmri.StringIOManager.class) 400 .register(throttleStringIO); 401 } 402 } 403 404 @Override 405 protected ResourceBundle getActionModelResourceBundle() { 406 return ResourceBundle.getBundle("jmri.jmrix.loconet.LocoNetActionListBundle"); 407 } 408 409 @Override 410 public <B extends NamedBean> Comparator<B> getNamedBeanComparator(Class<B> type) { 411 return new NamedBeanComparator<>(); 412 } 413 414 // yes, tagManager is static. Tags can move between system connections. 415 // when readers are not all on the same LocoNet 416 // this manager is loaded on demand. 417 static TranspondingTagManager tagManager; 418 419 static public TranspondingTagManager getIdTagManager() { 420 synchronized (LocoNetSystemConnectionMemo.class) { // since tagManager can be null, can't synch on that 421 if (tagManager == null) { 422 tagManager = new TranspondingTagManager(); 423 InstanceManager.setIdTagManager(tagManager); 424 } 425 return tagManager; 426 } 427 } 428 429 public LnCabSignalManager getCabSignalManager() { 430 return (LnCabSignalManager) classObjectMap.computeIfAbsent(CabSignalManager.class,(Class<?> c) -> new LnCabSignalManager(this)); 431 } 432 433 @Override 434 public void dispose() { 435 if (throttleStringIO != null) { 436 throttleStringIO = null; 437 } 438 if (predefinedMeters != null) { 439 predefinedMeters.dispose(); 440 } 441 LnPowerManager pm = (LnPowerManager) classObjectMap.get(PowerManager.class); 442 InstanceManager.deregister(this, LocoNetSystemConnectionMemo.class); 443 if (cf != null) { 444 InstanceManager.deregister(cf, ComponentFactory.class); 445 cf = null; 446 } 447 ThrottleManager throttleManager = get(ThrottleManager.class); 448 if (throttleManager != null) { 449 if (throttleManager instanceof LnThrottleManager) { 450 InstanceManager.deregister(((LnThrottleManager) throttleManager), LnThrottleManager.class); 451 } else if (throttleManager instanceof DebugThrottleManager) { 452 InstanceManager.deregister(((DebugThrottleManager) throttleManager), DebugThrottleManager.class); 453 } 454 deregister(throttleManager,ThrottleManager.class); 455 } 456 457 if (tm != null){ 458 tm.dispose(); 459 tm = null; 460 } 461 if (sm != null){ 462 sm.dispose(); 463 sm = null; 464 } 465 if (lt != null){ 466 lt.dispose(); 467 lt = null; 468 } 469 if (pm != null){ 470 pm.dispose(); 471 } 472 super.dispose(); 473 } 474 475 private final static Logger log = LoggerFactory.getLogger(LocoNetSystemConnectionMemo.class); 476 477}