Add frc2::Timer (#1968)

This is a unit-safe version of frc::Timer.
Undo previous (#1815) deprecation of parts of frc::Timer.
This commit is contained in:
Oblarg
2019-10-26 11:21:40 -04:00
committed by Peter Johnson
parent 36ea865edc
commit 73a30182c3
5 changed files with 293 additions and 122 deletions

View File

@@ -17,123 +17,34 @@
namespace frc {
void Wait(double seconds) {
std::this_thread::sleep_for(std::chrono::duration<double>(seconds));
}
void Wait(double seconds) { frc2::Wait(units::second_t(seconds)); }
double GetTime() {
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::system_clock;
return duration_cast<duration<double>>(system_clock::now().time_since_epoch())
.count();
}
double GetTime() { return frc2::GetTime().to<double>(); }
} // namespace frc
using namespace frc;
// for compatibility with msvc12--see C2864
const double Timer::kRolloverTime = (1ll << 32) / 1e6;
const double Timer::kRolloverTime = frc2::Timer::kRolloverTime.to<double>();
Timer::Timer() { Reset(); }
Timer::Timer(const Timer& rhs)
: m_startTime(rhs.m_startTime),
m_accumulatedTime(rhs.m_accumulatedTime),
m_running(rhs.m_running) {}
double Timer::Get() const { return m_timer.Get().to<double>(); }
Timer& Timer::operator=(const Timer& rhs) {
std::scoped_lock lock(m_mutex, rhs.m_mutex);
void Timer::Reset() { m_timer.Reset(); }
m_startTime = rhs.m_startTime;
m_accumulatedTime = rhs.m_accumulatedTime;
m_running = rhs.m_running;
void Timer::Start() { m_timer.Start(); }
return *this;
}
Timer::Timer(Timer&& rhs)
: m_startTime(std::move(rhs.m_startTime)),
m_accumulatedTime(std::move(rhs.m_accumulatedTime)),
m_running(std::move(rhs.m_running)) {}
Timer& Timer::operator=(Timer&& rhs) {
std::scoped_lock lock(m_mutex, rhs.m_mutex);
m_startTime = std::move(rhs.m_startTime);
m_accumulatedTime = std::move(rhs.m_accumulatedTime);
m_running = std::move(rhs.m_running);
return *this;
}
double Timer::Get() const {
double result;
double currentTime = GetFPGATimestamp();
std::scoped_lock lock(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;
}
void Timer::Reset() {
std::scoped_lock lock(m_mutex);
m_accumulatedTime = 0;
m_startTime = GetFPGATimestamp();
}
void Timer::Start() {
std::scoped_lock lock(m_mutex);
if (!m_running) {
m_startTime = GetFPGATimestamp();
m_running = true;
}
}
void Timer::Stop() {
double temp = Get();
std::scoped_lock lock(m_mutex);
if (m_running) {
m_accumulatedTime = temp;
m_running = false;
}
}
void Timer::Stop() { m_timer.Stop(); }
bool Timer::HasPeriodPassed(double period) {
return HasPeriodPassed(units::second_t(period));
}
bool Timer::HasPeriodPassed(units::second_t period) {
if (Get() > period.to<double>()) {
std::scoped_lock lock(m_mutex);
// Advance the start time by the period.
m_startTime += period.to<double>();
// Don't set it to the current time... we want to avoid drift.
return true;
}
return false;
return m_timer.HasPeriodPassed(units::second_t(period));
}
double Timer::GetFPGATimestamp() {
// FPGA returns the timestamp in microseconds
return RobotController::GetFPGATime() * 1.0e-6;
return frc2::Timer::GetFPGATimestamp().to<double>();
}
double Timer::GetMatchTime() {
return DriverStation::GetInstance().GetMatchTime();
return frc2::Timer::GetMatchTime().to<double>();
}

View File

@@ -0,0 +1,137 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. 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 the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#include "frc2/Timer.h"
#include <chrono>
#include <thread>
#include <hal/HAL.h>
#include "frc/DriverStation.h"
#include "frc/RobotController.h"
namespace frc2 {
void Wait(units::second_t seconds) {
std::this_thread::sleep_for(
std::chrono::duration<double>(seconds.to<double>()));
}
units::second_t GetTime() {
using std::chrono::duration;
using std::chrono::duration_cast;
using std::chrono::system_clock;
return units::second_t(
duration_cast<duration<double>>(system_clock::now().time_since_epoch())
.count());
}
} // namespace frc2
using namespace frc2;
// for compatibility with msvc12--see C2864
const units::second_t Timer::kRolloverTime = units::second_t((1ll << 32) / 1e6);
Timer::Timer() { Reset(); }
Timer::Timer(const Timer& rhs)
: m_startTime(rhs.m_startTime),
m_accumulatedTime(rhs.m_accumulatedTime),
m_running(rhs.m_running) {}
Timer& Timer::operator=(const Timer& rhs) {
std::scoped_lock lock(m_mutex, rhs.m_mutex);
m_startTime = rhs.m_startTime;
m_accumulatedTime = rhs.m_accumulatedTime;
m_running = rhs.m_running;
return *this;
}
Timer::Timer(Timer&& rhs)
: m_startTime(std::move(rhs.m_startTime)),
m_accumulatedTime(std::move(rhs.m_accumulatedTime)),
m_running(std::move(rhs.m_running)) {}
Timer& Timer::operator=(Timer&& rhs) {
std::scoped_lock lock(m_mutex, rhs.m_mutex);
m_startTime = std::move(rhs.m_startTime);
m_accumulatedTime = std::move(rhs.m_accumulatedTime);
m_running = std::move(rhs.m_running);
return *this;
}
units::second_t Timer::Get() const {
units::second_t result;
units::second_t currentTime = GetFPGATimestamp();
std::scoped_lock lock(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;
}
void Timer::Reset() {
std::scoped_lock lock(m_mutex);
m_accumulatedTime = 0_s;
m_startTime = GetFPGATimestamp();
}
void Timer::Start() {
std::scoped_lock lock(m_mutex);
if (!m_running) {
m_startTime = GetFPGATimestamp();
m_running = true;
}
}
void Timer::Stop() {
units::second_t temp = Get();
std::scoped_lock lock(m_mutex);
if (m_running) {
m_accumulatedTime = temp;
m_running = false;
}
}
bool Timer::HasPeriodPassed(units::second_t period) {
if (Get() > period) {
std::scoped_lock lock(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;
}
units::second_t Timer::GetFPGATimestamp() {
// FPGA returns the timestamp in microseconds
return units::second_t(frc::RobotController::GetFPGATime()) * 1.0e-6;
}
units::second_t Timer::GetMatchTime() {
return units::second_t(frc::DriverStation::GetInstance().GetMatchTime());
}

View File

@@ -12,11 +12,10 @@
#include <wpi/mutex.h>
#include "frc/Base.h"
#include "frc2/Timer.h"
namespace frc {
using TimerInterruptHandler = void (*)(void* param);
/**
* Pause the task for a specified time.
*
@@ -57,10 +56,10 @@ class Timer {
virtual ~Timer() = default;
Timer(const Timer& rhs);
Timer& operator=(const Timer& rhs);
Timer(Timer&& rhs);
Timer& operator=(Timer&& rhs);
Timer(const Timer& rhs) = default;
Timer& operator=(const Timer& rhs) = default;
Timer(Timer&& rhs) = default;
Timer& operator=(Timer&& rhs) = default;
/**
* Get the current time from the timer. If the clock is running it is derived
@@ -104,19 +103,8 @@ class Timer {
* @param period The period to check for (in seconds).
* @return True if the period has passed.
*/
WPI_DEPRECATED("Use unit-safe HasPeriodPassed method instead.")
bool HasPeriodPassed(double period);
/**
* 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.
* @return True if the period has passed.
*/
bool HasPeriodPassed(units::second_t period);
/**
* Return the FPGA system clock time in seconds.
*
@@ -148,10 +136,7 @@ class Timer {
static const double kRolloverTime;
private:
double m_startTime = 0.0;
double m_accumulatedTime = 0.0;
bool m_running = false;
mutable wpi::mutex m_mutex;
frc2::Timer m_timer;
};
} // namespace frc

View File

@@ -0,0 +1,138 @@
/*----------------------------------------------------------------------------*/
/* Copyright (c) 2008-2019 FIRST. 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 the root directory of */
/* the project. */
/*----------------------------------------------------------------------------*/
#pragma once
#include <units/units.h>
#include <wpi/deprecated.h>
#include <wpi/mutex.h>
#include "frc/Base.h"
namespace frc2 {
/**
* 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(units::second_t seconds);
/**
* @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.
*/
units::second_t GetTime();
/**
* A wrapper for the frc::Timer class that returns unit-typed values.
*/
class Timer {
public:
/**
* 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();
virtual ~Timer() = default;
Timer(const Timer& rhs);
Timer& operator=(const Timer& rhs);
Timer(Timer&& rhs);
Timer& operator=(Timer&& rhs);
/**
* 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
*/
units::second_t Get() const;
/**
* 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 Reset();
/**
* Start the timer running.
*
* Just set the running flag to true indicating that all time requests should
* be relative to the system clock.
*/
void Start();
/**
* 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 Stop();
/**
* 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.
* @return True if the period has passed.
*/
bool HasPeriodPassed(units::second_t period);
/**
* 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.
*/
static units::second_t GetFPGATimestamp();
/**
* Return the approximate match time.
*
* The FMS does not send an official match time to the robots, but does send
* an approximate match time. The value will count down the time remaining in
* the current period (auto or teleop).
*
* Warning: This is not an official time (so it cannot be used to dispute ref
* calls or guarantee that a function will trigger before the match ends).
*
* The Practice Match function of the DS approximates the behavior seen on the
* field.
*
* @return Time remaining in current match period (auto or teleop)
*/
static units::second_t GetMatchTime();
// The time, in seconds, at which the 32-bit FPGA timestamp rolls over to 0
static const units::second_t kRolloverTime;
private:
units::second_t m_startTime = 0_s;
units::second_t m_accumulatedTime = 0_s;
bool m_running = false;
mutable wpi::mutex m_mutex;
};
} // namespace frc2

View File

@@ -12,7 +12,7 @@
#include "CommandBase.h"
#include "CommandHelper.h"
#include "frc/Timer.h"
#include "frc2/Timer.h"
namespace frc2 {
/**
@@ -43,7 +43,7 @@ class WaitCommand : public CommandHelper<CommandBase, WaitCommand> {
bool RunsWhenDisabled() const override;
protected:
frc::Timer m_timer;
Timer m_timer;
private:
units::second_t m_duration;