Fix sender stale sample reuse and add append helper
This commit is contained in:
95
src/main.cpp
95
src/main.cpp
@@ -55,6 +55,10 @@ struct BatchBuffer {
|
||||
uint16_t batch_id;
|
||||
bool batch_id_valid;
|
||||
uint8_t count;
|
||||
uint16_t attempt_count;
|
||||
uint16_t valid_count;
|
||||
uint16_t invalid_count;
|
||||
FaultType last_error;
|
||||
MeterData samples[METER_BATCH_MAX_SAMPLES];
|
||||
};
|
||||
|
||||
@@ -93,9 +97,14 @@ static uint32_t g_sender_rx_reject_log_ms = 0;
|
||||
static MeterData g_last_meter_data = {};
|
||||
static bool g_last_meter_valid = false;
|
||||
static uint32_t g_last_meter_rx_ms = 0;
|
||||
static uint32_t g_last_meter_seq = 0;
|
||||
static uint32_t g_last_meter_seq_used = 0;
|
||||
static uint32_t g_meter_stale_seconds = 0;
|
||||
static bool g_time_acquired = false;
|
||||
static uint32_t g_last_sync_request_ms = 0;
|
||||
static uint32_t g_build_attempts = 0;
|
||||
static uint32_t g_build_valid = 0;
|
||||
static uint32_t g_build_invalid = 0;
|
||||
|
||||
static void watchdog_kick();
|
||||
|
||||
@@ -207,6 +216,10 @@ static void batch_queue_enqueue(const MeterData *samples, uint8_t count) {
|
||||
slot.batch_id = 0;
|
||||
slot.batch_id_valid = false;
|
||||
slot.count = count;
|
||||
slot.attempt_count = static_cast<uint16_t>(g_build_attempts);
|
||||
slot.valid_count = static_cast<uint16_t>(g_build_valid);
|
||||
slot.invalid_count = static_cast<uint16_t>(g_build_invalid);
|
||||
slot.last_error = g_sender_last_error;
|
||||
for (uint8_t i = 0; i < count; ++i) {
|
||||
slot.samples[i] = samples[i];
|
||||
}
|
||||
@@ -214,6 +227,28 @@ static void batch_queue_enqueue(const MeterData *samples, uint8_t count) {
|
||||
g_batch_count++;
|
||||
}
|
||||
|
||||
static void reset_build_counters() {
|
||||
g_build_attempts = 0;
|
||||
g_build_valid = 0;
|
||||
g_build_invalid = 0;
|
||||
}
|
||||
|
||||
static bool append_meter_sample(const MeterData &data, bool meter_ok) {
|
||||
if (!meter_ok) {
|
||||
g_build_invalid++;
|
||||
return false;
|
||||
}
|
||||
g_last_sample_ts_utc = data.ts_utc;
|
||||
g_build_samples[g_build_count++] = data;
|
||||
g_build_valid++;
|
||||
if (g_build_count >= METER_BATCH_MAX_SAMPLES) {
|
||||
batch_queue_enqueue(g_build_samples, g_build_count);
|
||||
g_build_count = 0;
|
||||
reset_build_counters();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t last_sample_ts() {
|
||||
if (g_last_sample_ts_utc == 0) {
|
||||
uint32_t now_utc = time_get_utc();
|
||||
@@ -482,6 +517,15 @@ static bool prepare_inflight_from_queue() {
|
||||
batch->batch_id = g_batch_id;
|
||||
batch->batch_id_valid = true;
|
||||
}
|
||||
if (SERIAL_DEBUG_MODE) {
|
||||
serial_debug_printf("batch: id=%u desired=%u attempts=%u valid=%u invalid=%u err_last=%u",
|
||||
batch->batch_id,
|
||||
static_cast<unsigned>(METER_BATCH_MAX_SAMPLES),
|
||||
static_cast<unsigned>(batch->attempt_count),
|
||||
static_cast<unsigned>(batch->valid_count),
|
||||
static_cast<unsigned>(batch->invalid_count),
|
||||
static_cast<unsigned>(batch->last_error));
|
||||
}
|
||||
g_inflight_count = batch->count;
|
||||
g_inflight_batch_id = batch->batch_id;
|
||||
for (uint8_t i = 0; i < g_inflight_count; ++i) {
|
||||
@@ -587,6 +631,15 @@ static bool send_sync_request() {
|
||||
g_inflight_sync_request = true;
|
||||
g_inflight_count = 0;
|
||||
g_inflight_batch_id = g_batch_id;
|
||||
if (SERIAL_DEBUG_MODE && g_build_attempts > 0) {
|
||||
serial_debug_printf("batch: id=%u desired=%u attempts=%u valid=%u invalid=%u err_last=%u sync=1",
|
||||
g_inflight_batch_id,
|
||||
static_cast<unsigned>(METER_BATCH_MAX_SAMPLES),
|
||||
static_cast<unsigned>(g_build_attempts),
|
||||
static_cast<unsigned>(g_build_valid),
|
||||
static_cast<unsigned>(g_build_invalid),
|
||||
static_cast<unsigned>(g_sender_last_error));
|
||||
}
|
||||
bool ok = send_inflight_batch(time_get_utc());
|
||||
if (ok) {
|
||||
g_last_sent_batch_id = g_inflight_batch_id;
|
||||
@@ -791,6 +844,9 @@ static void sender_loop() {
|
||||
g_last_meter_valid = true;
|
||||
g_last_meter_rx_ms = now_ms;
|
||||
g_meter_stale_seconds = 0;
|
||||
g_last_meter_seq++;
|
||||
} else {
|
||||
g_last_meter_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -799,8 +855,15 @@ static void sender_loop() {
|
||||
MeterData data = {};
|
||||
data.short_id = g_short_id;
|
||||
strncpy(data.device_id, g_device_id, sizeof(data.device_id));
|
||||
data.energy_total_kwh = NAN;
|
||||
data.total_power_w = NAN;
|
||||
data.phase_power_w[0] = NAN;
|
||||
data.phase_power_w[1] = NAN;
|
||||
data.phase_power_w[2] = NAN;
|
||||
|
||||
bool meter_ok = g_last_meter_valid;
|
||||
g_build_attempts++;
|
||||
// Avoid reusing stale meter frames: only accept new parsed data once per sample.
|
||||
bool meter_ok = g_last_meter_valid && (g_last_meter_seq != g_last_meter_seq_used);
|
||||
if (meter_ok) {
|
||||
data.energy_total_kwh = g_last_meter_data.energy_total_kwh;
|
||||
data.total_power_w = g_last_meter_data.total_power_w;
|
||||
@@ -809,6 +872,7 @@ static void sender_loop() {
|
||||
data.phase_power_w[2] = g_last_meter_data.phase_power_w[2];
|
||||
uint32_t age_ms = now_ms - g_last_meter_rx_ms;
|
||||
g_meter_stale_seconds = age_ms >= 1000 ? (age_ms / 1000) : 0;
|
||||
g_last_meter_seq_used = g_last_meter_seq;
|
||||
} else {
|
||||
g_meter_stale_seconds++;
|
||||
}
|
||||
@@ -825,11 +889,17 @@ static void sender_loop() {
|
||||
data.ts_utc = time_get_utc();
|
||||
data.valid = meter_ok;
|
||||
|
||||
g_last_sample_ts_utc = data.ts_utc;
|
||||
g_build_samples[g_build_count++] = data;
|
||||
if (g_build_count >= METER_BATCH_MAX_SAMPLES) {
|
||||
batch_queue_enqueue(g_build_samples, g_build_count);
|
||||
g_build_count = 0;
|
||||
bool appended = append_meter_sample(data, meter_ok);
|
||||
if (SERIAL_DEBUG_MODE) {
|
||||
serial_debug_printf("sample: i=%lu ok=%u appended=%u e_kwh=%.3f p1=%.1f p2=%.1f p3=%.1f ms=%lu",
|
||||
static_cast<unsigned long>(g_build_attempts),
|
||||
meter_ok ? 1U : 0U,
|
||||
appended ? 1U : 0U,
|
||||
static_cast<double>(data.energy_total_kwh),
|
||||
static_cast<double>(data.phase_power_w[0]),
|
||||
static_cast<double>(data.phase_power_w[1]),
|
||||
static_cast<double>(data.phase_power_w[2]),
|
||||
static_cast<unsigned long>(now_ms));
|
||||
}
|
||||
display_set_last_meter(data);
|
||||
display_set_last_read(meter_ok, data.ts_utc);
|
||||
@@ -837,7 +907,18 @@ static void sender_loop() {
|
||||
|
||||
if (!g_batch_ack_pending && now_ms - g_last_send_ms >= METER_SEND_INTERVAL_MS) {
|
||||
g_last_send_ms = now_ms;
|
||||
send_meter_batch(last_sample_ts());
|
||||
if (g_build_count > 0) {
|
||||
batch_queue_enqueue(g_build_samples, g_build_count);
|
||||
g_build_count = 0;
|
||||
reset_build_counters();
|
||||
}
|
||||
if (g_batch_count > 0) {
|
||||
send_meter_batch(last_sample_ts());
|
||||
} else if (g_build_attempts > 0) {
|
||||
if (send_sync_request()) {
|
||||
reset_build_counters();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!g_batch_ack_pending && now_ms - g_last_sync_request_ms >= SYNC_REQUEST_INTERVAL_MS) {
|
||||
|
||||
Reference in New Issue
Block a user