diff --git a/Software/Software.ino b/Software/Software.ino index dcbc4502..14dbc0e7 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -339,6 +339,15 @@ void init_serial() { #endif // DEBUG_VIA_USB } +void update_overflow(unsigned long currentMillis) { + // Check if millis overflowed + if (currentMillis < lastMillisOverflowCheck) { + // We have overflowed, increase rollover count + datalayer.system.status.millisrolloverCount++; + } + lastMillisOverflowCheck = currentMillis; +} + void check_interconnect_available() { if (datalayer.battery.status.voltage_dV == 0 || datalayer.battery2.status.voltage_dV == 0) { return; // Both voltage values need to be available to start check @@ -519,11 +528,8 @@ void update_calculated_values() { datalayer.battery.status.reported_remaining_capacity_Wh = datalayer.battery2.status.remaining_capacity_Wh; } } - // Check if millis has overflowed. Used in events to keep better track of time - if (currentMillis < lastMillisOverflowCheck) { // Overflow detected - datalayer.system.status.millisrolloverCount++; - } - lastMillisOverflowCheck = currentMillis; + + update_overflow(currentMillis); // Update millis rollover count } void check_reset_reason() { @@ -581,3 +587,9 @@ void check_reset_reason() { break; } } + +uint64_t get_timestamp(unsigned long currentMillis) { + update_overflow(currentMillis); + return (uint64_t)datalayer.system.status.millisrolloverCount * (uint64_t)std::numeric_limits::max() + + (uint64_t)currentMillis; +} diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 8fce33b7..c92b89d1 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -3,13 +3,6 @@ #include "../../../USER_SETTINGS.h" -typedef struct { - EVENTS_ENUM_TYPE event; - uint8_t millisrolloverCount; - uint32_t timestamp; - uint8_t data; -} EVENT_LOG_ENTRY_TYPE; - typedef struct { EVENTS_STRUCT_TYPE entries[EVENT_NOF_EVENTS]; EVENTS_LEVEL_TYPE level; @@ -30,7 +23,6 @@ void init_events(void) { for (uint16_t i = 0; i < EVENT_NOF_EVENTS; i++) { events.entries[i].data = 0; events.entries[i].timestamp = 0; - events.entries[i].millisrolloverCount = 0; events.entries[i].occurences = 0; events.entries[i].MQTTpublished = false; // Not published by default } @@ -155,7 +147,6 @@ void reset_all_events() { events.entries[i].data = 0; events.entries[i].state = EVENT_STATE_INACTIVE; events.entries[i].timestamp = 0; - events.entries[i].millisrolloverCount = 0; events.entries[i].occurences = 0; events.entries[i].MQTTpublished = false; // Not published by default } @@ -396,6 +387,8 @@ EVENTS_LEVEL_TYPE get_event_level(void) { return events.level; } +uint64_t get_timestamp(unsigned long currentMillis); + /* Local functions */ static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) { @@ -416,8 +409,7 @@ static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) { } // We should set the event, update event info - events.entries[event].timestamp = millis(); - events.entries[event].millisrolloverCount = datalayer.system.status.millisrolloverCount; + events.entries[event].timestamp = get_timestamp(millis()); events.entries[event].data = data; // Check if the event is latching events.entries[event].state = latched ? EVENT_STATE_ACTIVE_LATCHED : EVENT_STATE_ACTIVE; @@ -448,17 +440,11 @@ static void update_bms_status(void) { // Function to compare events by timestamp descending bool compareEventsByTimestampDesc(const EventData& a, const EventData& b) { - if (a.event_pointer->millisrolloverCount != b.event_pointer->millisrolloverCount) { - return a.event_pointer->millisrolloverCount > b.event_pointer->millisrolloverCount; - } return a.event_pointer->timestamp > b.event_pointer->timestamp; } // Function to compare events by timestamp ascending bool compareEventsByTimestampAsc(const EventData& a, const EventData& b) { - if (a.event_pointer->millisrolloverCount != b.event_pointer->millisrolloverCount) { - return a.event_pointer->millisrolloverCount < b.event_pointer->millisrolloverCount; - } return a.event_pointer->timestamp < b.event_pointer->timestamp; } diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index 030c505b..86d52ae4 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -129,12 +129,11 @@ typedef enum { } EVENTS_STATE_TYPE; typedef struct { - uint32_t timestamp; // Time in seconds since startup when the event occurred - uint8_t millisrolloverCount; // number of times millis rollovers before timestamp - uint8_t data; // Custom data passed when setting the event, for example cell number for under voltage - uint8_t occurences; // Number of occurrences since startup - EVENTS_LEVEL_TYPE level; // Event level, i.e. ERROR/WARNING... - EVENTS_STATE_TYPE state; // Event state, i.e. ACTIVE/INACTIVE... + uint64_t timestamp; + uint8_t data; // Custom data passed when setting the event, for example cell number for under voltage + uint8_t occurences; // Number of occurrences since startup + EVENTS_LEVEL_TYPE level; // Event level, i.e. ERROR/WARNING... + EVENTS_STATE_TYPE state; // Event state, i.e. ACTIVE/INACTIVE... bool MQTTpublished; } EVENTS_STRUCT_TYPE; diff --git a/Software/src/devboard/webserver/events_html.cpp b/Software/src/devboard/webserver/events_html.cpp index e548bb71..f3dab890 100644 --- a/Software/src/devboard/webserver/events_html.cpp +++ b/Software/src/devboard/webserver/events_html.cpp @@ -1,4 +1,5 @@ #include "events_html.h" +#include #include "../../datalayer/datalayer.h" const char EVENTS_HTML_START[] = R"=====( @@ -10,9 +11,13 @@ const char EVENTS_HTML_END[] = R"=====( button:hover { background-color: #3A4A52; } - + + )====="; +uint64_t get_timestamp(unsigned long currentMillis); + static std::vector order_events; String events_processor(const String& var) { @@ -34,12 +39,13 @@ String events_processor(const String& var) { } // Sort events by timestamp std::sort(order_events.begin(), order_events.end(), compareEventsByTimestampDesc); - unsigned long timestamp_now = millis(); + uint64_t current_timestamp = get_timestamp(millis()); // Generate HTML and debug output for (const auto& event : order_events) { EVENTS_ENUM_TYPE event_handle = event.event_handle; event_pointer = event.event_pointer; + #ifdef DEBUG_LOG logging.println("Showing Event: " + String(get_event_enum_string(event_handle)) + " count: " + String(event_pointer->occurences) + " seconds: " + String(event_pointer->timestamp) + @@ -49,8 +55,8 @@ String events_processor(const String& var) { content.concat("
"); content.concat("
" + String(get_event_enum_string(event_handle)) + "
"); content.concat("
" + String(get_event_level_string(event_handle)) + "
"); - content.concat("
" + String(datalayer.system.status.millisrolloverCount) + ";" + - String(timestamp_now - event_pointer->timestamp) + "
"); + // Frontend expects to see time difference (in ms) from now to event + content.concat("
" + String(current_timestamp - event_pointer->timestamp) + "
"); content.concat("
" + String(event_pointer->occurences) + "
"); content.concat("
" + String(event_pointer->data) + "
"); content.concat("
" + String(get_event_message_string(event_handle)) + "
"); @@ -80,7 +86,7 @@ String events_processor(const String& var) { function showEvent() { document.querySelectorAll(".event").forEach(function (e) { var n = e.querySelector(".sec-ago"); - n && (n.innerText = new Date(Date.now() - (+n.innerText.split(";")[0] * 4294967296 + +n.innerText.split(";")[1])).toLocaleString()); + n && (n.innerText = new Date(Number(BigInt(Date.now()) - BigInt(n.innerText))).toLocaleString()); }); } function askClear() {