blob: 1acc7a5548b4f9a9ee9542ef99451be6b1ae87a7 [file] [log] [blame]
James Zheng6df8bb52024-11-27 23:38:47 +00001#include "failsafe_logger.hpp"
2
3#include <chrono>
Ed Tanousf8b6e552025-06-27 13:27:50 -07004#include <cstdint>
James Zheng6df8bb52024-11-27 23:38:47 +00005#include <iostream>
Ed Tanousf8b6e552025-06-27 13:27:50 -07006#include <string>
James Zheng6df8bb52024-11-27 23:38:47 +00007
8namespace pid_control
9{
10
11void FailsafeLogger::outputFailsafeLog(
12 const int64_t zoneId, const bool newFailsafeState,
Ed Tanousd2768c52025-06-26 11:42:57 -070013 const std::string& location, const std::string& reason)
James Zheng6df8bb52024-11-27 23:38:47 +000014{
15 // Remove outdated log entries.
16 const auto now = std::chrono::high_resolution_clock::now();
17 uint64_t nowMs = std::chrono::duration_cast<std::chrono::milliseconds>(
18 now.time_since_epoch())
19 .count();
20 // Limit the log output in 1 second.
21 constexpr uint64_t secondInMS = 1000; // 1 second in milliseconds
22 while (!_logTimestamps.empty() &&
23 nowMs - _logTimestamps.front() >= secondInMS)
24 {
25 _logTimestamps.pop_front();
26 }
27
28 // There is a failsafe state change, clear the logs in current state.
29 bool originFailsafeState = _currentFailsafeState;
30 if (newFailsafeState != _currentFailsafeState)
31 {
32 _logsInCurrentState.clear();
33 _currentFailsafeState = newFailsafeState;
34 }
35 // Do not output the log if the capacity is reached, or if the log is
36 // already encountered in the current state.
37 std::string locationReason = location + " @ " + reason;
38 if (_logTimestamps.size() >= _logMaxCountPerSecond ||
39 !_logsInCurrentState.contains(locationReason))
40 {
41 return;
42 }
43 _logsInCurrentState.insert(locationReason);
44
45 // Only output the log if the zone enters, stays in, or leaves failsafe
46 // mode. No need to output the log if the zone stays in non-failsafe mode.
47 if (newFailsafeState)
48 {
49 std::cerr << "Zone `" << zoneId
50 << "` is in failsafe mode.\t\tWith update at `" << location
51 << "`: " << reason << "\n";
52 }
53 else if (!newFailsafeState && originFailsafeState)
54 {
55 std::cerr << "Zone `" << zoneId
56 << "` leaves failsafe mode.\t\tWith update at `" << location
57 << "`: " << reason << "\n";
58 }
59
60 _logTimestamps.push_back(nowMs);
61}
62
63} // namespace pid_control