001package jmri.jmrix.lenz;
002
003import java.util.EnumSet;
004import java.util.HashMap;
005
006import jmri.LocoAddress;
007import jmri.SpeedStepMode;
008import jmri.jmrix.AbstractThrottleManager;
009
010/**
011 * XNet implementation of a ThrottleManager based on the
012 * AbstractThrottleManager.
013 *
014 * @author Paul Bender Copyright (C) 2002-2004
015 * @navassoc 1 - * jmri.jmrix.lenz.XNetThrottle
016 */
017public class XNetThrottleManager extends AbstractThrottleManager implements XNetListener {
018
019    protected final HashMap<LocoAddress, XNetThrottle> throttles = new HashMap<>(5);
020
021    protected XNetTrafficController tc;
022
023    /**
024     * Constructor.
025     * @param memo system connection.
026     */
027    public XNetThrottleManager(XNetSystemConnectionMemo memo) {
028        super(memo);
029        // connect to the TrafficManager
030        tc = memo.getXNetTrafficController();
031
032        // Register to listen for throttle messages
033        tc.addXNetListener(XNetInterface.THROTTLE, this);
034    }
035
036    /**
037     * Request a new throttle object be created for the address, and let the
038     * throttle listeners know about it.
039     * {@inheritDoc}
040     */
041    @Override
042    public void requestThrottleSetup(LocoAddress address, boolean control) {
043        XNetThrottle throttle;
044        log.debug("Requesting Throttle: {}", address);
045        // range check for LH200 and Compact/Commander
046        if (tc.getCommandStation().getCommandStationType() == 0x01 ||
047            tc.getCommandStation().getCommandStationType() == 0x02 ) {
048            if(address.getNumber()>=100) {
049               String typeString = Bundle.getMessage(tc.getCommandStation().getCommandStationType() == 0x01?"CSTypeLH200":"CSTypeCompact");
050               failedThrottleRequest(address,Bundle.getMessage("ThrottleErrorCSTwoDigit",typeString));
051               return;
052            }
053        }
054        if (throttles.containsKey(address)) {
055            notifyThrottleKnown(throttles.get(address), address);
056        } else {
057            throttle = new XNetThrottle((XNetSystemConnectionMemo) adapterMemo, address, tc);
058            throttles.put(address, throttle);
059            notifyThrottleKnown(throttle, address);
060        }
061    }
062
063    /**
064     * XpressNet based systems DO NOT use the Dispatch Function.
065     * @return false always.
066     */
067    @Override
068    public boolean hasDispatchFunction() {
069        return false;
070    }
071
072    /**
073     * XpressNet based systems can have multiple throttles for the same
074     * device.
075     * <p>
076     * {@inheritDoc}
077     */
078    @Override
079    protected boolean singleUse() {
080        return false;
081    }
082
083    /**
084     * Address 100 and above is a long address.
085     */
086    @Override
087    public boolean canBeLongAddress(int address) {
088        return isLongAddress(address);
089    }
090
091    /**
092     * Address 99 and below is a short address.
093     */
094    @Override
095    public boolean canBeShortAddress(int address) {
096        return !isLongAddress(address);
097    }
098
099    /**
100     * Are there any ambiguous addresses (short vs long) on this system?
101     */
102    @Override
103    public boolean addressTypeUnique() {
104        return true;
105    }
106
107    /**
108     * Local method for deciding short/long address
109     * @param num address to examine
110     * @return true if can be long address
111     */
112    protected static boolean isLongAddress(int num) {
113        return (num >= 100);
114    }
115
116    /**
117     * What speed modes are supported by this system? value should be xor of
118     * possible modes specifed by the DccThrottle interface XpressNet supports
119     * 14,27,28 and 128 speed step modes
120     */
121    @Override
122    public EnumSet<SpeedStepMode> supportedSpeedModes() {
123        return EnumSet.of(SpeedStepMode.NMRA_DCC_128
124                , SpeedStepMode.NMRA_DCC_28
125                , SpeedStepMode.NMRA_DCC_27
126                , SpeedStepMode.NMRA_DCC_14);
127    }
128
129    /**
130     * Handle incoming messages for throttles.
131     */
132    @Override
133    public void message(XNetReply r) {
134        // We want to check to see if a throttle has taken over an address
135        if (r.getElement(0) == XNetConstants.LOCO_INFO_RESPONSE) {
136            if (r.getElement(1) == XNetConstants.LOCO_NOT_AVAILABLE) {
137                // This is a take over message.  If we know about this throttle,
138                // send the message on.
139                LocoAddress address = new jmri.DccLocoAddress(r.getThrottleMsgAddr(),
140                        isLongAddress(r.getThrottleMsgAddr()));
141                if (throttles.containsKey(address)) {
142                    throttles.get(address).message(r);
143                }
144            }
145        }
146
147    }
148
149    /**
150     * Listen for the messages to the LI100/LI101.
151     */
152    @Override
153    public void message(XNetMessage l) {
154    }
155
156    /**
157     * Handle a timeout notification.
158     */
159    @Override
160    public void notifyTimeout(XNetMessage msg) {
161    }
162
163    @Override
164    public boolean disposeThrottle(jmri.DccThrottle t, jmri.ThrottleListener l) {
165        if (super.disposeThrottle(t, l)) {
166            if(!(t instanceof XNetThrottle)) {
167               throw new IllegalArgumentException("Attempt to dispose non-XpressNet Throttle");
168            }
169            XNetThrottle lnt = (XNetThrottle) t;
170            lnt.throttleDispose();
171            return true;
172        }
173        return false;
174    }
175
176    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(XNetThrottleManager.class);
177
178}