001package jmri.jmrix.bidib;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004
005import java.util.EnumSet;
006import java.util.HashMap;
007import jmri.DccLocoAddress;
008import jmri.DccThrottle;
009import jmri.LocoAddress;
010import jmri.SpeedStepMode;
011import jmri.ThrottleListener;
012import jmri.jmrix.AbstractThrottleManager;
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016/**
017 * BiDiB implementation of a ThrottleManager.
018 * <P>
019 * @author Bob Jacobsen Copyright (C) 2001
020 * @author Eckart Meyer Copyright (C) 2019
021 */
022public class BiDiBThrottleManager extends AbstractThrottleManager {
023
024    /**
025     * Constructor.
026     * @param memo system connection memo
027     */
028    public BiDiBThrottleManager(BiDiBSystemConnectionMemo memo) {
029        super(memo);
030        this.tc = memo.getBiDiBTrafficController();
031        this.prefix = memo.getSystemPrefix();
032    }
033
034    //protected HashMap<LocoAddress, BiDiBThrottle> throttles = new HashMap<LocoAddress, BiDiBThrottle>();
035    protected HashMap<LocoAddress, BiDiBThrottle> throttles = new HashMap<>();
036    BiDiBTrafficController tc = null;
037    String prefix = "";
038
039    @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST",justification = "Cast safe by design")
040    @Override
041    public void requestThrottleSetup(LocoAddress a, boolean control) {
042        DccLocoAddress address = (DccLocoAddress) a;
043        BiDiBThrottle throttle;
044        log.debug("request BiDiBThrottle for {}", address);
045        // the BiDiB protocol doesn't require an interaction with the command
046        // station for this, so immediately trigger the callback.
047        
048        // We have our own throttle list here to save the loco data when no throttle
049        // is active - JMRI completely forgets loco data after removing the last throttle
050        // for that loco (see AbstactThottleManager, HasMap addressThrottles)
051        // Perhaps we could fiddle with the dipose methods, but there is no example from
052        // other throttle manager. Instead, we use the variant from DCC++ here.
053        
054        if (throttles.containsKey(address)) {
055            log.debug("BiDiB throttle found.");
056            throttle = throttles.get(address);
057            notifyThrottleKnown(throttle, address);
058            throttle.requestState(); //try to get loco state from command station
059        } else {
060            log.debug("create new BiDiB throttle.");
061            throttle = new BiDiBThrottle((BiDiBSystemConnectionMemo) adapterMemo, address);
062            throttles.put(address, throttle);
063            notifyThrottleKnown(throttle, address);
064        }
065    }
066
067    /*
068     * BiDiB based systems can have multiple throttles for the same 
069     * device
070     */
071    @Override
072    protected boolean singleUse() {
073        return false;
074    }
075
076    /**
077     * Addresses 0-10239 can be long
078     *
079     */
080    @Override
081    public boolean canBeLongAddress(int address) {
082        return ((address >= 0) && (address <= 10239));
083    }
084
085    /**
086     * The short addresses 1-127 are available
087     *
088     */
089    @Override
090    public boolean canBeShortAddress(int address) {
091        return ((address >= 1) && (address <= 127));
092    }
093
094    /**
095     * Are there any ambiguous addresses (short vs long) on this system?
096     */
097    @Override
098    public boolean addressTypeUnique() {
099        return true;
100    }
101
102//    @Override
103//    public int supportedSpeedModes() {
104//        return (DccThrottle.SpeedStepMode128 | DccThrottle.SpeedStepMode28 | DccThrottle.SpeedStepMode14);
105//        //return (DccThrottle.SpeedStepMode14 );
106//    }
107    @Override
108    public EnumSet<SpeedStepMode> supportedSpeedModes() {
109        return EnumSet.of(SpeedStepMode.NMRA_DCC_128
110                , SpeedStepMode.NMRA_DCC_28
111                , SpeedStepMode.NMRA_DCC_14);
112    }
113
114/// just to see what happens...
115    @Override
116    public void dispatchThrottle(DccThrottle t, ThrottleListener l) {
117        log.debug("BiDiBThrottleManager.dispatchThrottle: {}, {}", t, l);
118        super.dispatchThrottle(t, l);
119    }
120
121    // called when "Release" button is pressed an also when Throttle window is close.
122    @Override
123    public void releaseThrottle(DccThrottle t, ThrottleListener l) {
124        log.debug("BiDiBThrottleManager.releaseThrottle: {}, {}", t, l);
125        super.releaseThrottle(t, l);
126    }
127///
128    
129    /**
130     * {@inheritDoc}
131     */
132    @SuppressFBWarnings(value = "BC_UNCONFIRMED_CAST",justification = "Cast safe by design")
133    @Override
134    public boolean disposeThrottle(jmri.DccThrottle t, jmri.ThrottleListener l) {
135        if (super.disposeThrottle(t, l)) {
136            BiDiBThrottle bt = (BiDiBThrottle) t;
137            bt.throttleDispose();
138            //throttles.remove(bt.locoAddress);//TEST - so a new instance will be created next time
139            return true;
140        }
141        return false;
142    }
143
144    private final static Logger log = LoggerFactory.getLogger(BiDiBThrottleManager.class);
145
146}