blob: 53631e778f83042c00afc5efca15dedfd9466fb6 [file] [log] [blame]
/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2008. All Rights Reserved.
*/
/* Open Source Software - may be modified and shared by FRC teams. The code */
/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
/*----------------------------------------------------------------------------*/
#include "Timer.h"
#include <time.h>
#include "HAL/HAL.hpp"
#include "Utility.h"
#include <iostream>
/**
* Pause the task for a specified time.
*
* Pause the execution of the program for a specified period of time given in
* seconds.
* Motors will continue to run at their last assigned values, and sensors will
* continue to
* update. Only the task containing the wait will pause until the wait time is
* expired.
*
* @param seconds Length of time to pause, in seconds.
*/
void Wait(double seconds) {
if (seconds < 0.0) return;
delaySeconds(seconds);
}
/**
* Return the FPGA system clock time in seconds.
* This is deprecated and just forwards to Timer::GetFPGATimestamp().
* @return Robot running time in seconds.
*/
double GetClock() { return Timer::GetFPGATimestamp(); }
/**
* @brief Gives real-time clock system time with nanosecond resolution
* @return The time, just in case you want the robot to start autonomous at 8pm
* on Saturday.
*/
double GetTime() {
struct timespec tp;
clock_gettime(CLOCK_REALTIME, &tp);
double realTime = (double)tp.tv_sec + (double)((double)tp.tv_nsec * 1e-9);
return (realTime);
}
//for compatibility with msvc12--see C2864
const double Timer::kRolloverTime = (1ll << 32) / 1e6;
/**
* Create a new timer object.
*
* Create a new timer object and reset the time to zero. The timer is initially
* not running and
* must be started.
*/
Timer::Timer() {
// Creates a semaphore to control access to critical regions.
// Initially 'open'
Reset();
}
/**
* Get the current time from the timer. If the clock is running it is derived
* from
* the current system clock the start time stored in the timer class. If the
* clock
* is not running, then return the time when it was last stopped.
*
* @return Current time value for this timer in seconds
*/
double Timer::Get() const {
double result;
double currentTime = GetFPGATimestamp();
std::lock_guard<priority_mutex> sync(m_mutex);
if (m_running) {
// If the current time is before the start time, then the FPGA clock
// rolled over. Compensate by adding the ~71 minutes that it takes
// to roll over to the current time.
if (currentTime < m_startTime) {
currentTime += kRolloverTime;
}
result = (currentTime - m_startTime) + m_accumulatedTime;
} else {
result = m_accumulatedTime;
}
return result;
}
/**
* Reset the timer by setting the time to 0.
*
* Make the timer startTime the current time so new requests will be relative to
* now
*/
void Timer::Reset() {
std::lock_guard<priority_mutex> sync(m_mutex);
m_accumulatedTime = 0;
m_startTime = GetFPGATimestamp();
}
/**
* Start the timer running.
* Just set the running flag to true indicating that all time requests should be
* relative to the system clock.
*/
void Timer::Start() {
std::lock_guard<priority_mutex> sync(m_mutex);
if (!m_running) {
m_startTime = GetFPGATimestamp();
m_running = true;
}
}
/**
* Stop the timer.
* This computes the time as of now and clears the running flag, causing all
* subsequent time requests to be read from the accumulated time rather than
* looking at the system clock.
*/
void Timer::Stop() {
double temp = Get();
std::lock_guard<priority_mutex> sync(m_mutex);
if (m_running) {
m_accumulatedTime = temp;
m_running = false;
}
}
/**
* Check if the period specified has passed and if it has, advance the start
* time by that period. This is useful to decide if it's time to do periodic
* work without drifting later by the time it took to get around to checking.
*
* @param period The period to check for (in seconds).
* @return True if the period has passed.
*/
bool Timer::HasPeriodPassed(double period) {
if (Get() > period) {
std::lock_guard<priority_mutex> sync(m_mutex);
// Advance the start time by the period.
m_startTime += period;
// Don't set it to the current time... we want to avoid drift.
return true;
}
return false;
}
/**
* Return the FPGA system clock time in seconds.
*
* Return the time from the FPGA hardware clock in seconds since the FPGA
* started.
* Rolls over after 71 minutes.
* @returns Robot running time in seconds.
*/
double Timer::GetFPGATimestamp() {
// FPGA returns the timestamp in microseconds
// Call the helper GetFPGATime() in Utility.cpp
return GetFPGATime() * 1.0e-6;
}
// Internal function that reads the PPC timestamp counter.
extern "C" {
uint32_t niTimestamp32(void);
uint64_t niTimestamp64(void);
}