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