1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
|
#include "timer.hpp"
#include <cinttypes>
#include "utils/utils.hpp"
#ifdef EMSCRIPTEN
#include <emscripten/html5.h>
#endif
#ifdef TEST
#define OVERRIDABLE_DURING_TESTING __attribute__((weak))
#else
#define OVERRIDABLE_DURING_TESTING static inline
#endif
OVERRIDABLE_DURING_TESTING uint64_t monotonic_timestamp_ms() {
#ifdef EMSCRIPTEN
return emscripten_get_now();
#else
return 0.0; // TODO: unimplemented
#endif
}
namespace time_const {
static const int64_t MSEC = 1;
static const int64_t SEC = 1000 * MSEC;
static const int64_t MIN = 60 * SEC;
static const int64_t HOUR = 60 * MIN;
};
FreqTimer::FreqTimer() {
clear();
}
static void _append_ratio(std::string & display_val, int64_t & ms, int64_t ratio, bool two_digit = true) {
int64_t amount = ms / ratio;
ms -= amount * ratio;
char buf[3];
if(two_digit) {
snprintf(buf, sizeof(buf), "%02" PRIi64, amount);
} else {
snprintf(buf, sizeof(buf), "%1" PRIi64, amount);
}
display_val.append(buf);
}
std::string FreqTimer::counter_display_value() const {
using namespace time_const;
int64_t ms = time_ms();
std::string display_val;
if(ms < 0) {
display_val.append("+ ");
ms = -ms;
}
if(ms > 99 * HOUR) {
return "MAX TIME EXCEEDED";
}
_append_ratio(display_val, ms, HOUR);
display_val.append(" : ");
_append_ratio(display_val, ms, MIN);
display_val.append(" : ");
_append_ratio(display_val, ms, SEC);
display_val.append(".");
_append_ratio(display_val, ms, 100 * MSEC, false);
return display_val;
}
std::string FreqTimer::record_floor_display() const {
double record_floor = this->record_floor();
std::string record_floor_label;
format_rate(record_floor_label, record_floor);
if(overtime()) {
std::string rec_floor_overtime;
format_rate(rec_floor_overtime, overtime_record_floor());
record_floor_label.append(", ");
record_floor_label.append(rec_floor_overtime);
}
return record_floor_label;
}
void FreqTimer::increment_preset_ms(uint64_t amount_ms) {
if(_state != State::SETTING) {
clear();
}
_preset_ms += amount_ms;
}
void FreqTimer::toggleStart() {
if(_state == State::RUNNING) {
_stop();
} else {
_start();
}
}
bool FreqTimer::has_preset() const {
return _preset_ms != 0;
}
void FreqTimer::reset() {
_time_offset_ms = 0;
_time_start_ms = monotonic_timestamp_ms();
_state = State::RESET;
}
void FreqTimer::clear() {
_time_offset_ms = 0;
_time_start_ms = monotonic_timestamp_ms();
_preset_ms = 0;
_state = State::SETTING;
}
double FreqTimer::record_floor() const {
int64_t ms;
if(has_preset()) {
ms = _preset_ms;
} else {
ms = total_duration_ms();
}
return 60.0e3 / ms;
}
double FreqTimer::overtime_record_floor() const {
return 60.0e3 / total_duration_ms();
}
uint64_t FreqTimer::_duration_since_last_stop_ms() const {
if(_state != State::RUNNING) {
return 0;
}
return monotonic_timestamp_ms() - _time_start_ms;
}
int64_t FreqTimer::time_ms() const {
if (_preset_ms == 0) {
return total_duration_ms();
}
return static_cast<int64_t>(_preset_ms) - total_duration_ms();
}
uint64_t FreqTimer::total_duration_ms() const {
return _time_offset_ms + _duration_since_last_stop_ms();
}
void FreqTimer::_stop() {
_time_offset_ms += _duration_since_last_stop_ms();
_state = State::STOPPED;
}
void FreqTimer::_start() {
_time_start_ms = monotonic_timestamp_ms();
_state = State::RUNNING;
}
|