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}