001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2012. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj.internal;
009
010import edu.wpi.first.wpilibj.DriverStation;
011import edu.wpi.first.wpilibj.Timer;
012import edu.wpi.first.wpilibj.Utility;
013
014/**
015 * Timer objects measure accumulated time in milliseconds.
016 * The timer object functions like a stopwatch. It can be started, stopped, and cleared. When the
017 * timer is running its value counts up in milliseconds. When stopped, the timer holds the current
018 * value. The implementation simply records the time when started and subtracts the current time
019 * whenever the value is requested.
020 */
021public class HardwareTimer implements Timer.StaticInterface {
022    /**
023     * Pause the thread for a specified time. Pause the execution of the
024     * thread for a specified period of time given in seconds. Motors will
025     * continue to run at their last assigned values, and sensors will continue
026     * to update. Only the task containing the wait will pause until the wait
027     * time is expired.
028     *
029     * @param seconds Length of time to pause
030     */
031    @Override
032    public void delay(final double seconds) {
033        try {
034            Thread.sleep((long) (seconds * 1e3));
035        } catch (final InterruptedException e) {
036        }
037    }
038
039    /**
040     * Return the system clock time in seconds. Return the time from the
041     * FPGA hardware clock in seconds since the FPGA started.
042     *
043     * @return Robot running time in seconds.
044     */
045    @Override
046    public double getFPGATimestamp() {
047        return Utility.getFPGATime() / 1000000.0;
048    }
049
050        @Override
051        public double getMatchTime() {
052                return DriverStation.getInstance().getMatchTime();
053        }
054
055        @Override
056        public Timer.Interface newTimer() {
057                return new TimerImpl();
058        }
059
060    class TimerImpl implements Timer.Interface {
061        private long m_startTime;
062        private double m_accumulatedTime;
063        private boolean m_running;
064
065            /**
066             * Create a new timer object.
067             * Create a new timer object and reset the time to zero. The timer is initially not running and
068             * must be started.
069             */
070            public TimerImpl() {
071                reset();
072            }
073
074            private long getMsClock() {
075                return Utility.getFPGATime() / 1000;
076            }
077
078            /**
079             * Get the current time from the timer. If the clock is running it is derived from
080             * the current system clock the start time stored in the timer class. If the clock
081             * is not running, then return the time when it was last stopped.
082             *
083             * @return Current time value for this timer in seconds
084             */
085            public synchronized double get() {
086                if (m_running) {
087                    return ((double) ((getMsClock() - m_startTime) + m_accumulatedTime)) / 1000.0;
088                } else {
089                    return m_accumulatedTime;
090                }
091            }
092
093            /**
094             * Reset the timer by setting the time to 0.
095             * Make the timer startTime the current time so new requests will be relative now
096             */
097            public synchronized void reset() {
098                m_accumulatedTime = 0;
099                m_startTime = getMsClock();
100            }
101
102            /**
103             * Start the timer running.
104             * Just set the running flag to true indicating that all time requests should be
105             * relative to the system clock.
106             */
107            public synchronized void start() {
108                m_startTime = getMsClock();
109                m_running = true;
110            }
111
112            /**
113             * Stop the timer.
114             * This computes the time as of now and clears the running flag, causing all
115             * subsequent time requests to be read from the accumulated time rather than
116             * looking at the system clock.
117             */
118            public synchronized void stop() {
119                final double temp = get();
120                m_accumulatedTime = temp;
121                m_running = false;
122            }
123
124        /**
125         * Check if the period specified has passed and if it has, advance the start
126         * time by that period. This is useful to decide if it's time to do periodic
127         * work without drifting later by the time it took to get around to checking.
128         *
129         * @param period The period to check for (in seconds).
130         * @return If the period has passed.
131         */
132        public synchronized boolean hasPeriodPassed(double period) {
133            if (get() > period) {
134                // Advance the start time by the period.
135                // Don't set it to the current time... we want to avoid drift.
136                m_startTime += period * 1000;
137                return true;
138            }
139            return false;
140        }
141    }
142}