blob: 8bef9f29256754d05bf5306004a688d83d44e5b8 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05002/* Copyright (c) FIRST 2008-2016. All Rights Reserved. */
Brian Silverman26e4e522015-12-17 01:56:40 -05003/* Open Source Software - may be modified and shared by FRC teams. The code */
Brian Silverman1a675112016-02-20 20:42:49 -05004/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
Brian Silverman26e4e522015-12-17 01:56:40 -05006/*----------------------------------------------------------------------------*/
7
8#include "Timer.h"
9
10#include <time.h>
11
12#include "simulation/simTime.h"
13#include "Utility.h"
14
15
16// Internal stuff
17#include "simulation/SimFloatInput.h"
18#include "simulation/MainNode.h"
19namespace wpilib { namespace internal {
20 double simTime = 0;
21 std::condition_variable time_wait;
22 std::mutex time_wait_mutex;
23
24 void time_callback(const msgs::ConstFloat64Ptr &msg) {
25 simTime = msg->data();
26 time_wait.notify_all();
27 }
28}}
29
30/**
31 * Pause the task for a specified time.
32 *
33 * Pause the execution of the program for a specified period of time given in seconds.
34 * Motors will continue to run at their last assigned values, and sensors will continue to
35 * update. Only the task containing the wait will pause until the wait time is expired.
36 *
37 * @param seconds Length of time to pause, in seconds.
38 */
39void Wait(double seconds)
40{
41 if (seconds < 0.0) return;
42
43 double start = wpilib::internal::simTime;
44
45 std::unique_lock<std::mutex> lock(wpilib::internal::time_wait_mutex);
46 while ((wpilib::internal::simTime - start) < seconds) {
47 wpilib::internal::time_wait.wait(lock);
48 }
49}
50
51/*
52 * Return the FPGA system clock time in seconds.
53 * This is deprecated and just forwards to Timer::GetFPGATimestamp().
54 * @returns Robot running time in seconds.
55 */
56double GetClock()
57{
58 return Timer::GetFPGATimestamp();
59}
60
61/**
62 * @brief Gives real-time clock system time with nanosecond resolution
63 * @return The time, just in case you want the robot to start autonomous at 8pm on Saturday (except in simulation).
64*/
65double GetTime()
66{
67 return Timer::GetFPGATimestamp(); // The epoch starts when Gazebo starts
68}
69
70//for compatibility with msvc12--see C2864
71const double Timer::kRolloverTime = (1ll << 32) / 1e6;
72/**
73 * Create a new timer object.
74 *
75 * Create a new timer object and reset the time to zero. The timer is initially not running and
76 * must be started.
77 */
78Timer::Timer()
79 : m_startTime (0.0)
80 , m_accumulatedTime (0.0)
81 , m_running (false)
82{
83 //Creates a semaphore to control access to critical regions.
84 //Initially 'open'
85 Reset();
86}
87
88/**
89 * Get the current time from the timer. If the clock is running it is derived from
90 * the current system clock the start time stored in the timer class. If the clock
91 * is not running, then return the time when it was last stopped.
92 *
93 * @return unsigned Current time value for this timer in seconds
94 */
95double Timer::Get() const
96{
97 double result;
98 double currentTime = GetFPGATimestamp();
99
100 std::lock_guard<priority_mutex> sync(m_mutex);
101 if(m_running)
102 {
103 // This math won't work if the timer rolled over (71 minutes after boot).
104 // TODO: Check for it and compensate.
105 result = (currentTime - m_startTime) + m_accumulatedTime;
106 }
107 else
108 {
109 result = m_accumulatedTime;
110 }
111
112 return result;
113}
114
115/**
116 * Reset the timer by setting the time to 0.
117 *
118 * Make the timer startTime the current time so new requests will be relative to now
119 */
120void Timer::Reset()
121{
122 std::lock_guard<priority_mutex> sync(m_mutex);
123 m_accumulatedTime = 0;
124 m_startTime = GetFPGATimestamp();
125}
126
127/**
128 * Start the timer running.
129 * Just set the running flag to true indicating that all time requests should be
130 * relative to the system clock.
131 */
132void Timer::Start()
133{
134 std::lock_guard<priority_mutex> sync(m_mutex);
135 if (!m_running)
136 {
137 m_startTime = GetFPGATimestamp();
138 m_running = true;
139 }
140}
141
142/**
143 * Stop the timer.
144 * This computes the time as of now and clears the running flag, causing all
145 * subsequent time requests to be read from the accumulated time rather than
146 * looking at the system clock.
147 */
148void Timer::Stop()
149{
150 double temp = Get();
151
152 std::lock_guard<priority_mutex> sync(m_mutex);
153 if (m_running)
154 {
155 m_accumulatedTime = temp;
156 m_running = false;
157 }
158}
159
160/**
161 * Check if the period specified has passed and if it has, advance the start
162 * time by that period. This is useful to decide if it's time to do periodic
163 * work without drifting later by the time it took to get around to checking.
164 *
165 * @param period The period to check for (in seconds).
166 * @return If the period has passed.
167 */
168bool Timer::HasPeriodPassed(double period)
169{
170 if (Get() > period)
171 {
172 std::lock_guard<priority_mutex> sync(m_mutex);
173 // Advance the start time by the period.
174 // Don't set it to the current time... we want to avoid drift.
175 m_startTime += period;
176 return true;
177 }
178 return false;
179}
180
181/*
182 * Return the FPGA system clock time in seconds.
183 *
184 * Return the time from the FPGA hardware clock in seconds since the FPGA
185 * started.
186 * Rolls over after 71 minutes.
187 * @returns Robot running time in seconds.
188 */
189double Timer::GetFPGATimestamp()
190{
191 // FPGA returns the timestamp in microseconds
192 // Call the helper GetFPGATime() in Utility.cpp
193 return wpilib::internal::simTime;
194}
195
196/*
197 * Not in a match.
198 */
199double Timer::GetMatchTime()
200{
201 return Timer::GetFPGATimestamp();
202}
203
204// Internal function that reads the PPC timestamp counter.
205extern "C"
206{
207 uint32_t niTimestamp32(void);
208 uint64_t niTimestamp64(void);
209}