001package jmri.jmrix.easydcc;
002
003import java.util.EnumSet;
004import jmri.DccLocoAddress;
005import jmri.LocoAddress;
006import jmri.SpeedStepMode;
007import jmri.jmrix.AbstractThrottleManager;
008import org.slf4j.Logger;
009import org.slf4j.LoggerFactory;
010
011/**
012 * EasyDCC implementation of a ThrottleManager.
013 * <p>
014 * Based on early NCE code.
015 *
016 * @author Bob Jacobsen Copyright (C) 2001, 2005
017 * @author Modified by Kelly Loyd
018 */
019public class EasyDccThrottleManager extends AbstractThrottleManager {
020
021    private EasyDccSystemConnectionMemo _memo = null;
022
023    /**
024     * Constructor
025     * @param memo system connection.
026     */
027    public EasyDccThrottleManager(EasyDccSystemConnectionMemo memo) {
028        super(memo);
029        _memo = memo;
030    }
031
032    @Override
033    public void requestThrottleSetup(LocoAddress address, boolean control) {
034        // Not sure if EasyDcc requires feedback. May need to extend this.
035        /* It appears that the first command sent to the Queue in EasyDcc
036         is 'lost' - so it may be beneficial to send a 'Send' command 
037         just to wake up the command station.
038         This was tested on v418 - also appears as an issue with the
039         radio throttles. 
040         */
041        if (address instanceof DccLocoAddress ) {
042            log.debug("new EasyDccThrottle for {}", address);
043            notifyThrottleKnown(new EasyDccThrottle(_memo, (DccLocoAddress) address), address);
044        }
045        else {
046            log.error("LocoAddress {} is not a DccLocoAddress",address);
047            failedThrottleRequest(address, "LocoAddress " +address+ " is not a DccLocoAddress");
048        }
049    }
050
051    // EasyDcc does not have a 'dispatch' function.
052    @Override
053    public boolean hasDispatchFunction() {
054        return false;
055    }
056
057    /**
058     * Address 100 and above is a long address.
059     */
060    @Override
061    public boolean canBeLongAddress(int address) {
062        return isLongAddress(address);
063    }
064
065    /**
066     * Address 99 and below is a short address.
067     */
068    @Override
069    public boolean canBeShortAddress(int address) {
070        return !isLongAddress(address);
071    }
072
073    /**
074     * Are there any ambiguous addresses (short vs long) on this system?
075     */
076    @Override
077    public boolean addressTypeUnique() {
078        return true;
079    }
080
081    /*
082     * Local method for deciding short/long address.
083     */
084    static boolean isLongAddress(int num) {
085        return (num >= 100);
086    }
087
088    @Override
089    public EnumSet<SpeedStepMode> supportedSpeedModes() {
090        return EnumSet.of(SpeedStepMode.NMRA_DCC_128, SpeedStepMode.NMRA_DCC_28);
091    }
092
093    @Override
094    public boolean disposeThrottle(jmri.DccThrottle t, jmri.ThrottleListener l) {
095        if (super.disposeThrottle(t, l)) {
096            int value = 0;
097            DccLocoAddress address = (DccLocoAddress) t.getLocoAddress();
098            byte[] result = jmri.NmraPacket.speedStep128Packet(address.getNumber(),
099                    address.isLongAddress(), value, t.getIsForward());
100            // KSL 20040409 - this is messy, as I only wanted
101            // the address to be sent.
102            EasyDccMessage m = new EasyDccMessage(7);
103            // for EasyDCC, release the loco.
104            // D = Dequeue
105            // Cx xx (address)
106            int i = 0;  // message index counter
107            m.setElement(i++, 'D');
108
109            if (address.isLongAddress()) {
110                m.setElement(i++, ' ');
111                m.addIntAsTwoHex(result[0] & 0xFF, i);
112                i = i + 2;
113                m.setElement(i++, ' ');
114                m.addIntAsTwoHex(result[1] & 0xFF, i);
115            } else { // short address
116                m.setElement(i++, ' ');
117                m.addIntAsTwoHex(0, i);
118                i = i + 2;
119                m.setElement(i++, ' ');
120                m.addIntAsTwoHex(result[0] & 0xFF, i);
121            }
122
123            _memo.getTrafficController().sendEasyDccMessage(m, null);
124            if (t instanceof EasyDccThrottle) {
125                EasyDccThrottle lnt = (EasyDccThrottle) t;
126                lnt.throttleDispose();
127                return true;
128            }
129            else {
130                log.error("DccThrottle {} is not an EasyDccThrottle",t);
131            }
132        }
133        return false;
134    }
135
136    private final static Logger log = LoggerFactory.getLogger(EasyDccThrottleManager.class);
137
138}