#include "timer.hpp" #include #include "utils/utils.hpp" #ifdef EMSCRIPTEN #include #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(_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; }