001package jmri.jmrix.openlcb;
002
003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
004import jmri.DccLocoAddress;
005import jmri.LocoAddress;
006import jmri.jmrix.AbstractThrottle;
007import jmri.SystemConnectionMemo;
008import org.openlcb.OlcbInterface;
009import org.openlcb.implementations.throttle.ThrottleImplementation;
010import org.slf4j.Logger;
011import org.slf4j.LoggerFactory;
012
013/**
014 * An implementation of DccThrottle for OpenLCB.
015 *
016 * @author Bob Jacobsen Copyright (C) 2012
017 */
018public class OlcbThrottle extends AbstractThrottle {
019        
020    /**
021     * Constructor
022     * @param address Dcc loco address
023     * @param memo system connection memo
024     */
025    public OlcbThrottle(DccLocoAddress address, SystemConnectionMemo memo) {
026        super(memo);
027        OlcbInterface iface = memo.get(OlcbInterface.class);
028
029        // cache settings. It would be better to read the
030        // actual state, but I don't know how to do this
031        this.speedSetting = 0;
032        // Functions default to false
033        this.isForward = true;
034
035        this.address = address;
036
037        // create OpenLCB library object that does the magic & activate
038        if (iface.getNodeStore() == null) {
039            log.error("Failed to access Mimic Node Store");
040        }
041        if (iface.getDatagramService() == null) {
042            log.error("Failed to access Datagram Service");
043        }
044        if (address instanceof OpenLcbLocoAddress) {
045            oti = new ThrottleImplementation(
046                    ((OpenLcbLocoAddress) address).getNode(),
047                    iface.getNodeStore(),
048                    iface.getDatagramService()
049            );
050        } else {
051            oti = new ThrottleImplementation(
052                    this.address.getNumber(),
053                    this.address.isLongAddress(),
054                    iface.getNodeStore(),
055                    iface.getDatagramService()
056            );
057        }
058        oti.start();
059    }
060
061    final ThrottleImplementation oti;
062
063    final DccLocoAddress address;
064
065    /** 
066     * {@inheritDoc} 
067     */
068    @Override
069    public LocoAddress getLocoAddress() {
070        return address;
071    }
072
073    /** 
074     * {@inheritDoc} 
075     */
076    @Override
077    public String toString() {
078        return getLocoAddress().toString();
079    }
080
081    /**
082     * Set the speed and direction
083     * <p>
084     * This intentionally skips the emergency stop value of 1.
085     *
086     * @param speed Number from 0 to 1; less than zero is emergency stop
087     */
088    @SuppressFBWarnings(value = "FE_FLOATING_POINT_EQUALITY") // OK to compare floating point, notify on any change
089    @Override
090    public void setSpeedSetting(float speed) {
091        float oldSpeed = this.speedSetting;
092        if (speed > 1.0) {
093            log.warn("Speed was set too high: {}", speed);
094        }
095        this.speedSetting = speed;
096
097        // send to OpenLCB
098        if (speed >= 0.0) {
099            oti.setSpeed(speed * 100.0, isForward);
100        } else {
101            oti.doEmergencyStop();
102        }
103
104        // notify 
105        firePropertyChange(SPEEDSETTING, oldSpeed, this.speedSetting);
106        record(speed);
107    }
108
109    /** 
110     * {@inheritDoc} 
111     */
112    @Override
113    public void setIsForward(boolean forward) {
114        boolean old = isForward;
115        isForward = forward;
116        setSpeedSetting(speedSetting);  // send the command
117        firePropertyChange(ISFORWARD, old, isForward);
118    }
119
120    /** 
121     * {@inheritDoc} 
122     */
123    @Override
124    public void setFunction(int functionNum, boolean newState) {
125        updateFunction(functionNum, newState);
126        // send to OpenLCB
127        oti.setFunction(functionNum, (newState ? 1 : 0));
128    }
129
130    /** 
131     * {@inheritDoc} 
132     */
133    @Override
134    protected void throttleDispose() {
135        log.debug("throttleDispose() called");
136        finishRecord();
137    }
138
139    // initialize logging
140    private final static Logger log = LoggerFactory.getLogger(OlcbThrottle.class);
141
142}