001/** 002 * Consist Manager for use with the LocoNetConsist class for the 003 * consists it builds. 004 * 005 * @author Paul Bender Copyright (C) 2011 006 */ 007package jmri.jmrix.loconet; 008 009import jmri.Consist; 010import jmri.LocoAddress; 011import jmri.DccLocoAddress; 012import jmri.implementation.AbstractConsistManager; 013import jmri.jmrix.loconet.SlotMapEntry.SlotType; 014 015import org.slf4j.Logger; 016import org.slf4j.LoggerFactory; 017 018public class LocoNetConsistManager extends AbstractConsistManager { 019 020 private LocoNetSystemConnectionMemo memo = null; 021 private boolean requestingUpdate = false; 022 023 /** 024 * Constructor - call the constructor for the superclass, and initialize the 025 * consist reader thread, which retrieves consist information from the 026 * command station 027 * 028 * @param lm the LocoNetSystemConnectionMemo to which this object is related 029 */ 030 public LocoNetConsistManager(LocoNetSystemConnectionMemo lm) { 031 super(); 032 this.memo = lm; 033 } 034 035 /** 036 * This implementation does support command station assisted consists, so 037 * return true. 038 * 039 */ 040 @Override 041 public boolean isCommandStationConsistPossible() { 042 return true; 043 } 044 045 /** 046 * Does a CS consist require a separate consist address? 047 * 048 */ 049 @Override 050 public boolean csConsistNeedsSeperateAddress() { 051 return false; 052 } 053 054 /** 055 * Add a new LocoNetConsist with the given address to 056 * consistTable/consistList 057 */ 058 @Override 059 public Consist addConsist(LocoAddress address) { 060 if (! (address instanceof DccLocoAddress)) { 061 throw new IllegalArgumentException("address is not a DccLocoAddress object"); 062 } 063 if (consistTable.containsKey(address)) // no duplicates allowed. 064 { 065 return consistTable.get(address); 066 } 067 LocoNetConsist consist; 068 consist = new LocoNetConsist((DccLocoAddress) address, memo); 069 consistTable.put(address, consist); 070 notifyConsistListChanged(); 071 return consist; 072 } 073 074 /* request an update from the layout, loading 075 * Consists from the command station. 076 * 077 * On a LocoNet command station, the consists are stored in the 078 * slots in an array based tree. Each node in a consist contains 079 * a pointer to the "top" slot in the consist. A top slot is 080 * allowed to be a member of another consist. When this occurs, 081 * it is labeled as a "mid" locomotive. 082 * 083 * This function updates the list of consists by scanning the 084 * slots and adding new "top" slot addresses and removing address 085 * that are no longer "top" locomotives. 086 */ 087 @Override 088 public void requestUpdateFromLayout() { 089 if (!shouldRequestUpdateFromLayout()) { 090 return; 091 } 092 requestingUpdate = true; 093 SlotManager sm = memo.getSlotManager(); 094 095 // in the first pass, check for consists top addresses in the 096 // command station slots. 097 for (int i = 0; i < sm.getNumSlots(); i++) { 098 if (sm.slot(i).getSlotType() == SlotType.LOCO) { 099 LocoNetSlot s = sm.slot(i); 100 DccLocoAddress address = new DccLocoAddress(s.locoAddr(), LnThrottleManager.isLongAddress(s.locoAddr())); 101 if (log.isDebugEnabled()) { 102 log.debug(" Slot {} Address {} consist status {}", i, address, LnConstants.CONSIST_STAT(s.consistStatus())); 103 } 104 if (s.consistStatus() == LnConstants.CONSIST_TOP || s.consistStatus() == LnConstants.CONSIST_MID) { 105 // this is a consist top, add it to the list, if it is not there 106 // already. 107 if (!consistTable.containsKey(address)) { 108 if (log.isDebugEnabled()) { 109 log.debug("Adding Consist with Address {} due to command station read", address); 110 } 111 addConsist(address); 112 getConsist(address).add(address, true); // add the address to the consist. 113 } 114 } 115 } 116 } 117 118 // make a second pass, this time looking for locomotives in a consist. 119 for (int i = 0; i < sm.getNumSlots(); i++) { 120 if (sm.slot(i).getSlotType() == SlotType.LOCO) { 121 LocoNetSlot s = sm.slot(i); 122 DccLocoAddress address = new DccLocoAddress(s.locoAddr(), LnThrottleManager.isLongAddress(s.locoAddr())); 123 if (log.isDebugEnabled()) { 124 log.debug(" Slot {} Address {} consist status {}", i, address, LnConstants.CONSIST_STAT(s.consistStatus())); 125 } 126 if (s.consistStatus() == LnConstants.CONSIST_SUB || s.consistStatus() == LnConstants.CONSIST_MID) { 127 // this is a consist member, add it to the consist in the 128 // slot which it has a pointer to (the slot pointer is stored in 129 // the slot's speed). 130 DccLocoAddress lead = new DccLocoAddress(sm.slot(s.speed()).locoAddr(), LnThrottleManager.isLongAddress(sm.slot(s.speed()).locoAddr())); 131 getConsist(lead).add(address, s.isForward() == sm.slot(s.speed()).isForward()); 132 } 133 } 134 } 135 requestingUpdate = false; 136 } 137 138 @Override 139 protected boolean shouldRequestUpdateFromLayout() { 140 return !requestingUpdate; 141 } 142 private final static Logger log = LoggerFactory.getLogger(LocoNetConsistManager.class); 143}