feat: add HIL diagnostics and meter health handling
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include "config.h"
|
||||
|
||||
#ifndef ENABLE_HIL_TRACE
|
||||
#define ENABLE_HIL_TRACE 0
|
||||
#endif
|
||||
enum class HilFault : uint8_t {
|
||||
DropChunk = 0,
|
||||
DuplicateChunk,
|
||||
CorruptChunk,
|
||||
SuppressAck,
|
||||
DelayAck,
|
||||
WrongAckBatch,
|
||||
Count
|
||||
};
|
||||
|
||||
#if ENABLE_HIL_TRACE
|
||||
|
||||
void hil_trace_init(DeviceRole role, uint16_t short_id, int reset_reason);
|
||||
void hil_trace_event(const char *event, const char *fields_json = nullptr);
|
||||
void hil_trace_eventf(const char *event, const char *fields_fmt, ...);
|
||||
void hil_trace_poll_commands();
|
||||
bool hil_fault_take(HilFault fault);
|
||||
uint32_t hil_fault_delay_ms();
|
||||
uint32_t hil_crc32(const uint8_t *data, size_t len);
|
||||
void hil_trace_health(uint8_t queue_depth, uint8_t build_depth, uint8_t retry_count);
|
||||
|
||||
#else
|
||||
|
||||
inline void hil_trace_init(DeviceRole, uint16_t, int) {}
|
||||
inline void hil_trace_event(const char *, const char * = nullptr) {}
|
||||
inline void hil_trace_eventf(const char *, const char *, ...) {}
|
||||
inline void hil_trace_poll_commands() {}
|
||||
inline bool hil_fault_take(HilFault) { return false; }
|
||||
inline uint32_t hil_fault_delay_ms() { return 0; }
|
||||
inline uint32_t hil_crc32(const uint8_t *, size_t) { return 0; }
|
||||
inline void hil_trace_health(uint8_t, uint8_t, uint8_t) {}
|
||||
|
||||
#endif
|
||||
@@ -3,7 +3,22 @@
|
||||
#include <Arduino.h>
|
||||
#include "data_model.h"
|
||||
|
||||
struct MeterDriverStats {
|
||||
uint32_t frames_ok;
|
||||
uint32_t frames_parse_fail;
|
||||
uint32_t rx_overflow;
|
||||
uint32_t rx_timeout;
|
||||
uint32_t bytes_rx;
|
||||
uint32_t last_rx_ms;
|
||||
uint32_t last_good_frame_ms;
|
||||
uint32_t uart_buffer_full;
|
||||
uint32_t uart_fifo_overflow;
|
||||
uint32_t uart_frame_error;
|
||||
uint32_t uart_parity_error;
|
||||
};
|
||||
|
||||
void meter_init();
|
||||
bool meter_read(MeterData &data);
|
||||
bool meter_poll_frame(const char *&frame, size_t &len);
|
||||
bool meter_parse_frame(const char *frame, size_t len, MeterData &data);
|
||||
void meter_get_stats(MeterDriverStats &out);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum class MeterHealthClassification : uint8_t {
|
||||
Fresh = 0,
|
||||
NoData,
|
||||
Stale
|
||||
};
|
||||
|
||||
struct MeterHealthState {
|
||||
bool fault_active;
|
||||
};
|
||||
|
||||
struct MeterHealthEvaluation {
|
||||
bool ok;
|
||||
bool fault_started;
|
||||
bool recovered;
|
||||
MeterHealthClassification classification;
|
||||
};
|
||||
|
||||
MeterHealthEvaluation meter_health_evaluate(MeterHealthState &state,
|
||||
bool has_snapshot,
|
||||
uint32_t age_ms,
|
||||
uint32_t max_age_ms);
|
||||
const char *meter_health_classification_text(MeterHealthClassification classification);
|
||||
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
constexpr size_t METER_FRAME_MAX = 512;
|
||||
constexpr uint8_t METER_REQUIRED_FIELDS_MASK = 0x1f;
|
||||
|
||||
enum class MeterFrameEvent : uint8_t {
|
||||
None = 0,
|
||||
Complete,
|
||||
Timeout,
|
||||
Overflow,
|
||||
Resync
|
||||
};
|
||||
|
||||
struct MeterFrameCollector {
|
||||
char buffer[METER_FRAME_MAX + 1];
|
||||
size_t length;
|
||||
uint32_t last_rx_ms;
|
||||
bool in_frame;
|
||||
};
|
||||
|
||||
void meter_frame_collector_init(MeterFrameCollector &collector);
|
||||
MeterFrameEvent meter_frame_collector_check_timeout(MeterFrameCollector &collector,
|
||||
uint32_t now_ms,
|
||||
uint32_t timeout_ms);
|
||||
MeterFrameEvent meter_frame_collector_feed(MeterFrameCollector &collector,
|
||||
char byte,
|
||||
uint32_t now_ms);
|
||||
|
||||
enum class MeterParseStatus : uint8_t {
|
||||
Valid = 0,
|
||||
Empty,
|
||||
MissingTerminator,
|
||||
LineTooLong,
|
||||
MissingRequired,
|
||||
InvalidMeterSeconds,
|
||||
MalformedValue
|
||||
};
|
||||
|
||||
struct MeterParseResult {
|
||||
float energy_total_kwh;
|
||||
float total_power_w;
|
||||
float phase_power_w[3];
|
||||
uint32_t meter_seconds;
|
||||
uint8_t fields_mask;
|
||||
bool meter_seconds_valid;
|
||||
bool valid;
|
||||
MeterParseStatus status;
|
||||
};
|
||||
|
||||
bool meter_parser_parse(const char *frame, size_t len, MeterParseResult &result);
|
||||
const char *meter_parse_status_text(MeterParseStatus status);
|
||||
Reference in New Issue
Block a user