Rework test mode to use normal LoRa batching and ACK flow
This commit is contained in:
19
src/main.cpp
19
src/main.cpp
@@ -11,7 +11,6 @@
|
|||||||
#include "receiver_pipeline.h"
|
#include "receiver_pipeline.h"
|
||||||
#include "sd_logger.h"
|
#include "sd_logger.h"
|
||||||
#include "sender_state_machine.h"
|
#include "sender_state_machine.h"
|
||||||
#include "test_mode.h"
|
|
||||||
#include "time_manager.h"
|
#include "time_manager.h"
|
||||||
#include "web_server.h"
|
#include "web_server.h"
|
||||||
#include "wifi_manager.h"
|
#include "wifi_manager.h"
|
||||||
@@ -136,24 +135,6 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
#ifdef ENABLE_TEST_MODE
|
|
||||||
if (g_role == DeviceRole::Sender) {
|
|
||||||
test_sender_loop(g_short_id, g_device_id);
|
|
||||||
display_tick();
|
|
||||||
watchdog_kick();
|
|
||||||
delay(50);
|
|
||||||
} else {
|
|
||||||
test_receiver_loop(g_receiver_shared.sender_statuses, NUM_SENDERS, g_short_id);
|
|
||||||
mqtt_loop();
|
|
||||||
web_server_loop();
|
|
||||||
display_set_receiver_status(g_receiver_shared.ap_mode, wifi_is_connected() ? wifi_get_ssid().c_str() : "AP", mqtt_is_connected());
|
|
||||||
display_tick();
|
|
||||||
watchdog_kick();
|
|
||||||
delay(50);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (g_role == DeviceRole::Sender) {
|
if (g_role == DeviceRole::Sender) {
|
||||||
g_sender_state_machine.loop();
|
g_sender_state_machine.loop();
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "display_ui.h"
|
#include "display_ui.h"
|
||||||
|
#include "json_codec.h"
|
||||||
#include "lora_transport.h"
|
#include "lora_transport.h"
|
||||||
#include "mqtt_client.h"
|
#include "mqtt_client.h"
|
||||||
#include "payload_codec.h"
|
#include "payload_codec.h"
|
||||||
@@ -77,6 +78,18 @@ static uint8_t bit_count32(uint32_t value) {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool mqtt_publish_sample(const MeterData &data) {
|
||||||
|
#ifdef ENABLE_TEST_MODE
|
||||||
|
String payload;
|
||||||
|
if (!meterDataToJson(data, payload)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return mqtt_publish_test(data.device_id, payload);
|
||||||
|
#else
|
||||||
|
return mqtt_publish_state(data);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
struct BatchRxState {
|
struct BatchRxState {
|
||||||
bool active;
|
bool active;
|
||||||
uint16_t batch_id;
|
uint16_t batch_id;
|
||||||
@@ -470,7 +483,7 @@ static void receiver_loop() {
|
|||||||
|
|
||||||
web_server_set_last_batch(static_cast<uint8_t>(sender_idx), samples, count);
|
web_server_set_last_batch(static_cast<uint8_t>(sender_idx), samples, count);
|
||||||
for (size_t s = 0; s < count; ++s) {
|
for (size_t s = 0; s < count; ++s) {
|
||||||
mqtt_publish_state(samples[s]);
|
mqtt_publish_sample(samples[s]);
|
||||||
}
|
}
|
||||||
g_sender_statuses[sender_idx].last_data = samples[count - 1];
|
g_sender_statuses[sender_idx].last_data = samples[count - 1];
|
||||||
g_sender_statuses[sender_idx].last_update_ts_utc = samples[count - 1].ts_utc;
|
g_sender_statuses[sender_idx].last_update_ts_utc = samples[count - 1].ts_utc;
|
||||||
|
|||||||
@@ -145,6 +145,10 @@ static uint32_t g_build_invalid = 0;
|
|||||||
static constexpr uint32_t METER_SAMPLE_MAX_AGE_MS = 15000;
|
static constexpr uint32_t METER_SAMPLE_MAX_AGE_MS = 15000;
|
||||||
static constexpr uint32_t METER_TIME_DELTA_TOLERANCE_S = 2;
|
static constexpr uint32_t METER_TIME_DELTA_TOLERANCE_S = 2;
|
||||||
static constexpr int64_t METER_TIME_ANCHOR_DRIFT_TOLERANCE_S = 2;
|
static constexpr int64_t METER_TIME_ANCHOR_DRIFT_TOLERANCE_S = 2;
|
||||||
|
#ifdef ENABLE_TEST_MODE
|
||||||
|
static uint32_t g_test_meter_last_emit_ms = 0;
|
||||||
|
static uint32_t g_test_meter_tick = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct MeterSampleEvent {
|
struct MeterSampleEvent {
|
||||||
MeterData data;
|
MeterData data;
|
||||||
@@ -350,6 +354,27 @@ static bool parse_meter_frame_sample(const char *frame, size_t frame_len, MeterD
|
|||||||
return meter_parse_frame(frame, frame_len, parsed);
|
return meter_parse_frame(frame, frame_len, parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ENABLE_TEST_MODE
|
||||||
|
static bool generate_test_meter_sample(uint32_t now_ms, MeterData &parsed) {
|
||||||
|
if (g_test_meter_last_emit_ms != 0 && now_ms - g_test_meter_last_emit_ms < METER_SAMPLE_INTERVAL_MS) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
g_test_meter_last_emit_ms = now_ms;
|
||||||
|
g_test_meter_tick++;
|
||||||
|
|
||||||
|
parsed = {};
|
||||||
|
parsed.valid = true;
|
||||||
|
parsed.meter_seconds_valid = true;
|
||||||
|
parsed.meter_seconds = MIN_ACCEPTED_EPOCH_UTC + g_test_meter_tick;
|
||||||
|
parsed.energy_total_kwh = static_cast<float>(g_test_meter_tick) / 1000.0f; // 1 Wh step per sample.
|
||||||
|
parsed.phase_power_w[0] = static_cast<float>(g_test_meter_tick);
|
||||||
|
parsed.phase_power_w[1] = static_cast<float>(g_test_meter_tick);
|
||||||
|
parsed.phase_power_w[2] = static_cast<float>(g_test_meter_tick);
|
||||||
|
parsed.total_power_w = parsed.phase_power_w[0] + parsed.phase_power_w[1] + parsed.phase_power_w[2];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
static void meter_queue_push_latest(const MeterSampleEvent &event) {
|
static void meter_queue_push_latest(const MeterSampleEvent &event) {
|
||||||
if (!g_meter_sample_queue) {
|
if (!g_meter_sample_queue) {
|
||||||
@@ -374,6 +399,20 @@ static void meter_queue_push_latest(const MeterSampleEvent &event) {
|
|||||||
static void meter_reader_task_entry(void *arg) {
|
static void meter_reader_task_entry(void *arg) {
|
||||||
(void)arg;
|
(void)arg;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
#ifdef ENABLE_TEST_MODE
|
||||||
|
MeterData test_sample = {};
|
||||||
|
uint32_t now_ms = millis();
|
||||||
|
if (!generate_test_meter_sample(now_ms, test_sample)) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(5));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
MeterSampleEvent event = {};
|
||||||
|
event.data = test_sample;
|
||||||
|
event.rx_ms = now_ms;
|
||||||
|
meter_queue_push_latest(event);
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *frame = nullptr;
|
const char *frame = nullptr;
|
||||||
size_t frame_len = 0;
|
size_t frame_len = 0;
|
||||||
if (!meter_poll_frame(frame, frame_len)) {
|
if (!meter_poll_frame(frame, frame_len)) {
|
||||||
@@ -438,6 +477,14 @@ static void meter_reader_pump(uint32_t now_ms) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ENABLE_TEST_MODE
|
||||||
|
MeterData test_sample = {};
|
||||||
|
if (generate_test_meter_sample(now_ms, test_sample)) {
|
||||||
|
set_last_meter_sample(test_sample, now_ms);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
|
||||||
const char *frame = nullptr;
|
const char *frame = nullptr;
|
||||||
size_t frame_len = 0;
|
size_t frame_len = 0;
|
||||||
if (!meter_poll_frame(frame, frame_len)) {
|
if (!meter_poll_frame(frame, frame_len)) {
|
||||||
@@ -1498,6 +1545,10 @@ bool SenderStateMachine::begin(const SenderStateMachineConfig &config) {
|
|||||||
g_time_acquired = false;
|
g_time_acquired = false;
|
||||||
g_sender_faults_reset_after_first_sync = false;
|
g_sender_faults_reset_after_first_sync = false;
|
||||||
g_sender_faults_reset_hour_utc = UINT32_MAX;
|
g_sender_faults_reset_hour_utc = UINT32_MAX;
|
||||||
|
#ifdef ENABLE_TEST_MODE
|
||||||
|
g_test_meter_last_emit_ms = 0;
|
||||||
|
g_test_meter_tick = 0;
|
||||||
|
#endif
|
||||||
update_battery_cache();
|
update_battery_cache();
|
||||||
sender_transition(SenderPhase::Syncing, "begin");
|
sender_transition(SenderPhase::Syncing, "begin");
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
Reference in New Issue
Block a user