#pragma once #include #include 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);