001package jmri.jmrix.roco.z21;
002
003import jmri.Sensor;
004import jmri.implementation.AbstractSensor;
005import org.slf4j.Logger;
006import org.slf4j.LoggerFactory;
007
008/**
009 * Extend jmri.AbstractSensor for RocoMotion (RM) bus sensors on
010 * the Roco Z21.
011 *
012 * @author Paul Bender Copyright (C) 2018
013 */
014public class Z21RMBusSensor extends AbstractSensor implements Z21Listener {
015
016    private boolean statusRequested = false;
017
018    private int address;
019    private int moduleAddress; /* The result of integer division of the 
020     ( sensor address - 1) by 8 */
021
022    private int bit;   /* a bitmask for the bit of this sensor */
023
024    private String systemName;
025
026    protected Z21TrafficController tc;
027
028    public Z21RMBusSensor(String systemName, String userName, Z21TrafficController controller, String prefix) {
029        super(systemName, userName);
030        tc = controller;
031        init(systemName, prefix);
032    }
033
034    public Z21RMBusSensor(String systemName, Z21TrafficController controller, String prefix) {
035        super(systemName);
036        tc = controller;
037        init(systemName, prefix);
038    }
039
040    /**
041     * Common initialization for all constructors.
042     */
043    private void init(String id, String prefix) {
044        // store address
045        systemName = id;
046        address = Z21RMBusAddress.getBitFromSystemName(systemName, prefix);
047        // calculate the module address and the bit to examine
048        moduleAddress = ((address-1)/ 8);
049        int bitnumber = (address-1) % 8;
050        switch(bitnumber) {
051           case 0:
052               bit = 0x01;
053               break;
054           case 1:
055               bit = 0x02;
056               break;
057           case 2:
058               bit = 0x04;
059               break;
060           case 3:
061               bit = 0x08;
062               break;
063           case 4:
064               bit = 0x10;
065               break;
066           case 5:
067               bit = 0x20;
068               break;
069           case 6:
070               bit = 0x40;
071               break;
072           case 7:
073               bit = 0x80;
074               break;
075           default:
076           // no default action, we have exhausted the possibilities.
077        }
078        log.debug("Created Sensor {} (Module Address {},  contact {})",
079                    systemName, moduleAddress, bitnumber);
080        tc.addz21Listener(this);
081        // Finally, request the current state from the layout.
082        requestUpdateFromLayout();
083    }
084
085    /**
086     * Request an update on status by sending an Z21 message.
087     */
088    @Override
089    public void requestUpdateFromLayout() {
090        Z21Message msg = Z21Message.getLanRMBusGetDataRequestMessage(moduleAddress<=10?0:1); // only two possiblities allowed.
091        synchronized (this) {
092            statusRequested = true;
093        }
094        tc.sendz21Message(msg, this);
095    }
096
097    /**
098     * initmessage is a package protected class which allows the Manger to send
099     * a feedback message at initialization without changing the state of the
100     * sensor with respect to whether or not a feedback request was sent. This
101     * is used only when the sensor is created by on layout feedback.
102     *
103     * @param l the feedback message to send
104     */
105    synchronized void initmessage(Z21Reply l) {
106        boolean oldState = statusRequested;
107        reply(l);
108        statusRequested = oldState;
109    }
110
111    @Override
112    public synchronized void reply(Z21Reply l) {
113        log.debug("received message: {}",l);
114        if (l.isRMBusDataChangedReply()) {
115           if (((l.getElement((moduleAddress<10?5+moduleAddress:5+(moduleAddress-10))) & bit) != 0) ^ _inverted) {
116             setOwnState(Sensor.ACTIVE);
117           } else {
118             setOwnState(Sensor.INACTIVE);
119           }
120        }
121    }
122
123    /**
124     * Listen for the messages to the Z21.
125     */
126    @Override
127    public void message(Z21Message l) {
128    }
129
130    @Override
131    public void dispose() {
132        tc.removez21Listener(this);
133        super.dispose();
134    }
135
136    /**
137     * Package protected routine to get the Sensor Number.
138     * @return Sensor number
139     */
140    int getNumber() {
141        return address;
142    }
143
144    /**
145     * Package protected routine to get the Sensor Base Address.
146     * @return address for this module.
147     */
148    int getModuleAddress() {
149        return moduleAddress;
150    }
151
152    private final static Logger log = LoggerFactory.getLogger(Z21RMBusSensor.class);
153
154}