blob: 850b6becfab1b6b4726abb57a959221452d6ce65 [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 "HAL/HAL.hpp"
13#include "Utility.h"
14#include <iostream>
15
16/**
17 * Pause the task for a specified time.
18 *
19 * Pause the execution of the program for a specified period of time given in
20 * seconds.
21 * Motors will continue to run at their last assigned values, and sensors will
22 * continue to
23 * update. Only the task containing the wait will pause until the wait time is
24 * expired.
25 *
26 * @param seconds Length of time to pause, in seconds.
27 */
28void Wait(double seconds) {
29 if (seconds < 0.0) return;
30 delaySeconds(seconds);
31}
32
33/**
34 * Return the FPGA system clock time in seconds.
35 * This is deprecated and just forwards to Timer::GetFPGATimestamp().
36 * @return Robot running time in seconds.
37 */
38double GetClock() { return Timer::GetFPGATimestamp(); }
39
40/**
41 * @brief Gives real-time clock system time with nanosecond resolution
42 * @return The time, just in case you want the robot to start autonomous at 8pm
43 * on Saturday.
44*/
45double GetTime() {
46 struct timespec tp;
47
48 clock_gettime(CLOCK_REALTIME, &tp);
49 double realTime = (double)tp.tv_sec + (double)((double)tp.tv_nsec * 1e-9);
50
51 return (realTime);
52}
53
54//for compatibility with msvc12--see C2864
55const double Timer::kRolloverTime = (1ll << 32) / 1e6;
56/**
57 * Create a new timer object.
58 *
59 * Create a new timer object and reset the time to zero. The timer is initially
60 * not running and
61 * must be started.
62 */
63Timer::Timer() {
64 // Creates a semaphore to control access to critical regions.
65 // Initially 'open'
66 Reset();
67}
68
69/**
70 * Get the current time from the timer. If the clock is running it is derived
71 * from
72 * the current system clock the start time stored in the timer class. If the
73 * clock
74 * is not running, then return the time when it was last stopped.
75 *
76 * @return Current time value for this timer in seconds
77 */
78double Timer::Get() const {
79 double result;
80 double currentTime = GetFPGATimestamp();
81
82 std::lock_guard<priority_mutex> sync(m_mutex);
83 if (m_running) {
84 // If the current time is before the start time, then the FPGA clock
85 // rolled over. Compensate by adding the ~71 minutes that it takes
86 // to roll over to the current time.
87 if (currentTime < m_startTime) {
88 currentTime += kRolloverTime;
89 }
90
91 result = (currentTime - m_startTime) + m_accumulatedTime;
92 } else {
93 result = m_accumulatedTime;
94 }
95
96 return result;
97}
98
99/**
100 * Reset the timer by setting the time to 0.
101 *
102 * Make the timer startTime the current time so new requests will be relative to
103 * now
104 */
105void Timer::Reset() {
106 std::lock_guard<priority_mutex> sync(m_mutex);
107 m_accumulatedTime = 0;
108 m_startTime = GetFPGATimestamp();
109}
110
111/**
112 * Start the timer running.
113 * Just set the running flag to true indicating that all time requests should be
114 * relative to the system clock.
115 */
116void Timer::Start() {
117 std::lock_guard<priority_mutex> sync(m_mutex);
118 if (!m_running) {
119 m_startTime = GetFPGATimestamp();
120 m_running = true;
121 }
122}
123
124/**
125 * Stop the timer.
126 * This computes the time as of now and clears the running flag, causing all
127 * subsequent time requests to be read from the accumulated time rather than
128 * looking at the system clock.
129 */
130void Timer::Stop() {
131 double temp = Get();
132
133 std::lock_guard<priority_mutex> sync(m_mutex);
134 if (m_running) {
135 m_accumulatedTime = temp;
136 m_running = false;
137 }
138}
139
140/**
141 * Check if the period specified has passed and if it has, advance the start
142 * time by that period. This is useful to decide if it's time to do periodic
143 * work without drifting later by the time it took to get around to checking.
144 *
145 * @param period The period to check for (in seconds).
146 * @return True if the period has passed.
147 */
148bool Timer::HasPeriodPassed(double period) {
149 if (Get() > period) {
150 std::lock_guard<priority_mutex> sync(m_mutex);
151 // Advance the start time by the period.
152 m_startTime += period;
153 // Don't set it to the current time... we want to avoid drift.
154 return true;
155 }
156 return false;
157}
158
159/**
160 * Return the FPGA system clock time in seconds.
161 *
162 * Return the time from the FPGA hardware clock in seconds since the FPGA
163 * started.
164 * Rolls over after 71 minutes.
165 * @returns Robot running time in seconds.
166 */
167double Timer::GetFPGATimestamp() {
168 // FPGA returns the timestamp in microseconds
169 // Call the helper GetFPGATime() in Utility.cpp
170 return GetFPGATime() * 1.0e-6;
171}
172
173// Internal function that reads the PPC timestamp counter.
174extern "C" {
175uint32_t niTimestamp32(void);
176uint64_t niTimestamp64(void);
177}