001package jmri.jmrix.loconet;
002
003import jmri.Sensor;
004import jmri.implementation.AbstractSensor;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Extend jmri.AbstractSensor for LocoNet layouts.
010 * <p>
011 * Some of the message formats used in this class are Copyright Digitrax, Inc.
012 * and used with permission as part of the JMRI project. That permission does
013 * not extend to uses in other software products. If you wish to use this code,
014 * algorithm or these message formats outside of JMRI, please contact Digitrax
015 * Inc for separate permission.
016 *
017 * @author Bob Jacobsen Copyright (C) 2001
018 */
019public class LnSensor extends AbstractSensor  {
020
021    private LnSensorAddress a;
022
023    public LnSensor(String systemName, String userName, LnTrafficController tc, String prefix) {
024        super(systemName, userName);
025        this.tc = tc;
026        init(systemName, prefix);
027    }
028
029    public LnSensor(String systemName, LnTrafficController tc, String prefix) {
030        super(systemName);
031        this.tc = tc;
032        init(systemName, prefix);
033    }
034
035    LnTrafficController tc;
036
037    /**
038     * Common initialization for both constructors
039     */
040    private void init(String systemName, String prefix) {
041        // store address forms
042        a = new LnSensorAddress(systemName, prefix);
043        if (log.isDebugEnabled()) {
044            log.debug("create address {}", a);
045        }
046    }
047
048    /**
049     * Request an update on status by sending a LocoNet message.
050     * The only known way to do this from LocoNet is to request the
051     * status of _all_ devices, which is here considered too
052     * heavyweight.
053     * See LnSensorManager.updateAll()
054     */
055    @Override
056    public void requestUpdateFromLayout() {
057    }
058
059    /**
060     * User request to set the state, which means that we need to broadcast the
061     * new state over the loconet so that other attached devices. The incoming message
062     * will in turn, be processed by the SensorManager.
063     */
064    @Override
065    public void setKnownState(int s) throws jmri.JmriException {
066        // send OPC_INPUT_REP with new state to this address
067        LocoNetMessage l = new LocoNetMessage(4);
068        l.setOpCode(LnConstants.OPC_INPUT_REP);
069        a.insertAddress(l);
070        // set state
071        if ((s == Sensor.ACTIVE) ^ _inverted) {
072            l.setElement(2, l.getElement(2) | 0x10);
073        } // otherwise is already OK
074        l.setElement(2, l.getElement(2) | 0x40);
075        // send
076        tc.sendLocoNetMessage(l);
077    }
078
079    /**
080     * implementing classes will typically have a function/listener to get
081     * updates from the layout, which will then call public void
082     * firePropertyChange(String propertyName, Object oldValue, Object newValue)
083     * _once_ if anything has changed state (or set the commanded state
084     * directly)
085     *
086     * @param l LocoNet message from manager.
087     */
088    public void messageFromManager(LocoNetMessage l) {
089        // parse message type
090        switch (l.getOpCode()) {
091            case LnConstants.OPC_INPUT_REP: {               /* page 9 of LocoNet PE */
092
093                int sw1 = l.getElement(1);
094                int sw2 = l.getElement(2);
095                if (a.matchAddress(sw1, sw2)) {
096                    // save the state
097                    boolean state = ((sw2 & 0x10) != 0) ^ _inverted;
098                    if (log.isDebugEnabled()) {
099                        log.debug("INPUT_REP received with valid address, old state {} new packet {}", getRawState(), state); // NOI18N
100                    }
101                    if (state && getRawState() != Sensor.ACTIVE) {
102                        if (log.isDebugEnabled()) {
103                            log.debug("Set ACTIVE"); // NOI18N
104                        }
105                        setOwnState(Sensor.ACTIVE);
106                    } else if ((!state) && getRawState() != Sensor.INACTIVE) {
107                        if (log.isDebugEnabled()) {
108                            log.debug("Set INACTIVE"); // NOI18N
109                        }
110                        setOwnState(Sensor.INACTIVE);
111                    }
112                }
113                return;
114            }
115            default:
116                return;
117        }
118        // reach here only in error
119    }
120
121    private final static Logger log = LoggerFactory.getLogger(LnSensor.class);
122
123}