001package jmri.jmrix.loconet;
002import java.util.TimerTask;
003
004/**
005 * Provides for LocoNet "Meters" discovery query at connection start-up.
006 * 
007 * This class specifically deals with issues sometimes seen
008 * at JMRI LocoNet connection start-up.
009 *
010 * @author B. Milhaupt     (C) 2020
011 */
012public class LnMeterInitTask {
013
014    boolean _enabled = false;
015    private UpdateTask _intervalTask = null;
016    private final int _sleepInterval;
017    private final LnTrafficController tc;
018
019    /**
020     * Create a task to perform an initial query of LocoNet for devices
021     * which provide data for JMRI Meters.
022     * 
023     * @param tc Traffic Controller used when sending query
024     * @param interval - delay between checks of connection's readiness
025     */
026    public LnMeterInitTask(LnTrafficController tc, int interval) {
027        this.tc = tc;
028       _sleepInterval = interval;
029    }
030
031    /**
032     * Enable the task to begin
033     */
034    protected void enable() {
035        if (!_enabled) {
036            _enabled = true;
037            if(_intervalTask != null) {
038                _intervalTask.enable(true);
039            }
040        }
041    }
042
043    /**
044     * Cancel the task (if it is not already canceled)
045     */
046    protected void disable() {
047        if(_intervalTask != null) {
048            _intervalTask.enable(false);
049        }
050    }
051
052    /**
053     * Initializes timer for send of meters query.
054     *
055     * Cancels any existing task.  Checks delay and
056     * exits if delay is negative.  Establishes a
057     * new task only if delay is greater than 0.
058     */
059    public void initTimer() {
060        if(_intervalTask != null) {
061           _intervalTask.cancel();
062           _intervalTask = null;
063        }
064        if(_sleepInterval < 0){
065           return; // don't start or restart the timer.
066        }
067        _intervalTask = new UpdateTask();
068        log.debug("Starting Initialization Timer");
069        jmri.util.TimerUtil.scheduleAtFixedRate(_intervalTask,
070                _sleepInterval, _sleepInterval);
071    }
072
073    /**
074     * Remove references to and from this object, so that it can eventually be
075     * garbage-collected.
076     */
077    public void dispose(){
078        if ((_intervalTask != null) && (_intervalTask.isEnabled())) {
079           _intervalTask.enable(false);
080        }
081        if (_intervalTask != null) {
082            _intervalTask = null;
083        }
084    }
085
086    /**
087     * Timer task for periodic updates
088     *
089     * Task to check status of the LocoNet connection, and, when it is
090     * ready, send a LocoNet query message.
091     */
092    private class UpdateTask extends TimerTask {
093
094        private boolean _updateTaskIsEnabled;
095
096        public UpdateTask() {
097            super();
098            this._updateTaskIsEnabled = false;
099        }
100
101        /**
102         * Enable or disable the update task
103         * @param val true to enable, false to disable
104         */
105        public void enable(boolean val) {
106            if (!val) {
107                cancel();
108            }
109            _updateTaskIsEnabled = val;
110        }
111
112        /**
113         * get the enable/disable state of the update task
114         * @return true if enabled, else false
115         */
116        public boolean isEnabled() {
117            return _updateTaskIsEnabled;
118        }
119
120        @Override
121        public void run() {
122            if (!_updateTaskIsEnabled) {
123                log.debug("LnMeter initialization timer finds task not enabled.");
124                return;
125            } else if (!tc.status()) {
126                log.debug("LnMeter initialization timer finds connection not ready.");
127                return;
128            }
129            log.debug("LnMeter initialization timer is sending query.");
130            tc.sendLocoNetMessage(new LocoNetMessage(
131                    new int[] {LnConstants.OPC_RQ_SL_DATA, 0x79, 0x01, 0x00}));
132            disable();
133        }
134    }
135
136    private final static org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(LnMeterInitTask.class);
137}