001package jmri.jmrix.rfid;
002
003import jmri.IdTag;
004import org.slf4j.Logger;
005import org.slf4j.LoggerFactory;
006
007/**
008 * Timeout specific implementation of an RfidSensor.
009 * <p>
010 * Certain RFID readers only send a message when an RFID tag is within the
011 * proximity of the reader - no message is sent when it leaves.
012 * <p>
013 * As a result, this implementation simulates this message using a timeout
014 * mechanism - if no further tags are sensed within a pre-defined time period,
015 * the Sensor state reverts to {@link IdTag#UNSEEN}.
016 * <hr>
017 * This file is part of JMRI.
018 * <p>
019 * JMRI is free software; you can redistribute it and/or modify it under the
020 * terms of version 2 of the GNU General Public License as published by the Free
021 * Software Foundation. See the "COPYING" file for a copy of this license.
022 * <p>
023 * JMRI is distributed in the hope that it will be useful, but WITHOUT ANY
024 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
025 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
026 *
027 * @author Matthew Harris Copyright (C) 2014
028 * @since 3.9.2
029 */
030public class TimeoutRfidSensor extends RfidSensor {
031
032    /**
033     * Timeout in ms
034     */
035    private static final int TIMEOUT = 1000;
036
037    /**
038     * Time when something was last sensed by this object
039     */
040    private long whenLastSensed = 0;
041
042    /**
043     * Reference to the timeout thread for this object
044     */
045    private transient TimeoutThread timeoutThread = null;
046
047    private final boolean logDebug = log.isDebugEnabled();
048
049    public TimeoutRfidSensor(String systemName) {
050        super(systemName);
051    }
052
053    public TimeoutRfidSensor(String systemName, String userName) {
054        super(systemName, userName);
055    }
056
057    @Override
058    public void notify(IdTag t) {
059        super.notify(t);
060        whenLastSensed = System.currentTimeMillis();
061        if (timeoutThread == null) {
062            (timeoutThread = new TimeoutThread()).start();
063        }
064    }
065
066    private void cleanUpTimeout() {
067        if (logDebug) {
068            log.debug("Cleanup timeout thread for {}", mSystemName);
069        }
070        timeoutThread = null;
071    }
072
073    private class TimeoutThread extends Thread {
074
075        TimeoutThread() {
076            super();
077            this.setName("Timeout-" + mSystemName);
078        }
079
080        @Override
081//        @SuppressWarnings("SleepWhileInLoop")
082        public void run() {
083            while ((whenLastSensed + TIMEOUT) > System.currentTimeMillis()) {
084                try {
085                    Thread.sleep(50);
086                } catch (InterruptedException ex) {
087                }
088            }
089            TimeoutRfidSensor.super.notify(null);
090            if (logDebug) {
091                log.debug("Timeout-{}", mSystemName);
092            }
093            cleanUpTimeout();
094        }
095
096    }
097
098    private static final Logger log = LoggerFactory.getLogger(TimeoutRfidSensor.class);
099
100}