001package jmri.jmrix.maple;
002
003import jmri.jmrix.AbstractMRListener;
004import jmri.jmrix.AbstractMRMessage;
005import jmri.jmrix.AbstractNode;
006import org.slf4j.Logger;
007import org.slf4j.LoggerFactory;
008
009/**
010 * Models a serial node, consisting of one Maple Systems HMI touch screen panel.
011 * <p>
012 * Nodes are numbered ala the Station number, from 1 to 99.
013 * <p>
014 * The array of sensor states is used to update sensor known state only when
015 * there's a change on the serial bus. This allows for the sensor state to be
016 * updated within the program, keeping this updated state until the next change
017 * on the serial bus. E.g. you can manually change a state via an icon, and not
018 * have it change back the next time that node is polled.
019 *
020 * @author Bob Jacobsen Copyright (C) 2003, 2008
021 * @author Bob Jacobsen, Dave Duchamp, multiNode extensions, 2004
022 * @author Bob Jacobsen, Dave Duchamp, revised for Maple, 2009
023 */
024public class SerialNode extends AbstractNode {
025
026    /**
027     * Maximum number of sensors for Maple.
028     */
029    static final int MAXSENSORS = 1000;
030
031    // class constants
032    // node definition instance variables (must persist between runs)
033    // protected int pulseWidth = 500;    // Pulse width for pulsed turnout control (milliseconds)
034    private int _address = 0;
035
036    // operational instance variables (should not be preserved between runs)
037
038    /**
039     * Assumes a node address of 1, and a node type of 0.
040     * If this constructor is used, actual node address must be set using setNodeAddress.
041     * @param tc serial traffic controller.
042     */
043    public SerialNode(SerialTrafficController tc) {
044        this(1, 0, tc);
045    }
046
047    /**
048     * Create a new SerialNode and initialize default instance variables.
049     *
050     * @param address Address of node on serial bus (0-99)
051     * @param type 0 (ignored)
052     * @param tc system traffic controller.
053     */
054    public SerialNode(int address, int type, SerialTrafficController tc) {
055        // set address 
056        setNodeAddress(address);
057        _address = address;
058        // register this node
059        tc.registerNode(this);
060    }
061
062    /**
063     * Get state of Sensors.
064     *
065     * @return 'true' since at least one sensor is defined
066     */
067    @Override
068    public boolean getSensorsActive() {
069        return true;
070    }
071
072    /**
073     * Check valid node address, must match value configured in the Maple HMI.
074     *
075     * @param address node ID, allowed values are 1-99
076     * @return true if in valid range
077     */
078    @Override
079    protected boolean checkNodeAddress(int address) {
080        return (address > 0) && (address <= 99);
081    }
082
083    /**
084     * Get this node's address.
085     * @return node address.
086     */
087    public int getAddress() {
088        return _address;
089    }
090
091    /**
092     * Create an Initialization packet (SerialMessage) for this
093     * node.
094     * <p>
095     * Note: Maple Systems devices do not need initialization. This is here
096     * for completion.
097     */
098    @Override
099    public AbstractMRMessage createInitPacket() {
100        return null;
101    }
102
103    /**
104     * Create a Transmit packet (SerialMessage). Not used in Maple.
105     */
106    @Override
107    public AbstractMRMessage createOutPacket() {
108        return null;
109    }
110
111    boolean warned = false;
112
113    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings( value = "SLF4J_FORMAT_SHOULD_BE_CONST",
114        justification = "only logging 1st warning string passed")
115    void warn(String s) {
116        if (warned) {
117            return;
118        }
119        warned = true;
120        log.warn(s);
121    }
122
123    int timeout = 0;
124
125    /**
126     * {@inheritDoc}
127     *
128     * @return true if initialization required
129     */
130    @Override
131    public boolean handleTimeout(AbstractMRMessage m, AbstractMRListener l) {
132        // increment timeout count
133        timeout++;
134        log.warn("Poll of node {} timed out. Timeout count = {}", _address, timeout);
135        return false;
136    }
137
138    @Override
139    public void resetTimeout(AbstractMRMessage m) {
140        if (timeout > 0) {
141            log.debug("Reset {} timeout count", timeout);
142        }
143        timeout = 0;
144    }
145
146    public int getTimeoutCount() {
147        return timeout;
148    }
149
150    private final static Logger log = LoggerFactory.getLogger(SerialNode.class);
151
152}