#include "meter_parser.h" #include "meter_health.h" #include #include #include #include #include static std::string frame(const char *energy_line = "1-0:1.8.0*255(001234.567*kWh)", const char *seconds = "00000064", bool terminator = true) { std::string value = "/DD3HIL\r\n0-0:96.8.0*255("; value += seconds; value += ")\r\n"; if (energy_line) { value += energy_line; value += "\r\n"; } value += "1-0:16.7.0*255(000950*W)\r\n"; value += "1-0:36.7.0*255(000500*W)\r\n"; value += "1-0:56.7.0*255(000450*W)\r\n"; value += "1-0:76.7.0*255(000000*W)\r\n"; if (terminator) value += "!\r\n"; return value; } static MeterParseResult parse(const std::string &telegram) { MeterParseResult result = {}; meter_parser_parse(telegram.data(), telegram.size(), result); return result; } int main() { MeterHealthState health_state = {}; MeterHealthEvaluation health = meter_health_evaluate(health_state, false, UINT32_MAX, 15000); assert(!health.ok && health.fault_started && !health.recovered); health = meter_health_evaluate(health_state, false, UINT32_MAX, 15000); assert(!health.ok && !health.fault_started && !health.recovered); health = meter_health_evaluate(health_state, true, 100, 15000); assert(health.ok && !health.fault_started && health.recovered); health = meter_health_evaluate(health_state, true, 15001, 15000); assert(!health.ok && health.fault_started && !health.recovered); MeterParseResult valid = parse(frame()); assert(valid.valid); assert(valid.status == MeterParseStatus::Valid); assert(valid.fields_mask == METER_REQUIRED_FIELDS_MASK); assert(valid.meter_seconds_valid && valid.meter_seconds == 100); assert(fabsf(valid.energy_total_kwh - 1234.567f) < 0.001f); MeterParseResult wh = parse(frame("1-0:1.8.0*255(1234567*Wh)")); assert(wh.valid); assert(fabsf(wh.energy_total_kwh - 1234.567f) < 0.001f); MeterParseResult missing = parse(frame(nullptr)); assert(!missing.valid && missing.status == MeterParseStatus::MissingRequired); MeterParseResult bad_seconds = parse(frame(nullptr, "GGGGGGGG")); assert(!bad_seconds.valid && bad_seconds.status == MeterParseStatus::InvalidMeterSeconds); MeterParseResult bad_unit = parse(frame("1-0:1.8.0*255(1234*J)")); assert(!bad_unit.valid && bad_unit.status == MeterParseStatus::MalformedValue); MeterParseResult no_end = parse(frame(nullptr, "00000064", false)); assert(!no_end.valid && no_end.status == MeterParseStatus::MissingTerminator); MeterParseResult false_prefix = parse(frame("X1-0:1.8.0*255(1234*kWh)")); assert(!false_prefix.valid && false_prefix.status == MeterParseStatus::MissingRequired); MeterFrameCollector collector = {}; meter_frame_collector_init(collector); uint32_t now = 0; for (char c : std::string("/truncated\r\n")) { meter_frame_collector_feed(collector, c, now += 20); } std::string recovery = frame(); assert(meter_frame_collector_feed(collector, recovery[0], now += 20) == MeterFrameEvent::Resync); MeterFrameEvent event = MeterFrameEvent::None; for (size_t i = 1; i < recovery.size(); ++i) { event = meter_frame_collector_feed(collector, recovery[i], now += 20); if (event == MeterFrameEvent::Complete) break; } assert(event == MeterFrameEvent::Complete); MeterParseResult recovered = {}; assert(meter_parser_parse(collector.buffer, collector.length, recovered)); meter_frame_collector_init(collector); meter_frame_collector_feed(collector, '/', 10); assert(meter_frame_collector_check_timeout(collector, 1510, 1500) == MeterFrameEvent::None); assert(meter_frame_collector_check_timeout(collector, 1511, 1500) == MeterFrameEvent::Timeout); meter_frame_collector_init(collector); meter_frame_collector_feed(collector, '/', 0); event = MeterFrameEvent::None; for (size_t i = 0; i < METER_FRAME_MAX; ++i) { event = meter_frame_collector_feed(collector, 'A', static_cast(i + 1)); if (event == MeterFrameEvent::Overflow) break; } assert(event == MeterFrameEvent::Overflow); puts("meter parser and collector tests passed"); return 0; }