- Implement periodic WiFi reconnection attempts when stuck in AP mode - Add WIFI_RECONNECT_INTERVAL_MS config (default 60s) for configurable retry frequency - Prevent data loss by automatically attempting to switch back to STA mode - Maintain AP mode for manual configuration if reconnection fails - Track WiFi config and last reconnection attempt time in shared state - Add wifi_try_reconnect_sta() and wifi_restore_ap_mode() helper functions - Log reconnection attempts and results for debugging
158 lines
4.6 KiB
C++
158 lines
4.6 KiB
C++
#include <Arduino.h>
|
|
|
|
#include "app_context.h"
|
|
#include "config.h"
|
|
#include "data_model.h"
|
|
#include "dd3_legacy_core.h"
|
|
#include "display_ui.h"
|
|
#include "lora_transport.h"
|
|
#include "mqtt_client.h"
|
|
#include "payload_codec.h"
|
|
#include "power_manager.h"
|
|
#include "receiver_pipeline.h"
|
|
#include "sd_logger.h"
|
|
#include "sender_state_machine.h"
|
|
#include "time_manager.h"
|
|
#include "web_server.h"
|
|
#include "wifi_manager.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
#include <esp_system.h>
|
|
#include <esp_task_wdt.h>
|
|
#endif
|
|
|
|
static DeviceRole g_role = DeviceRole::Sender;
|
|
static uint16_t g_short_id = 0;
|
|
static char g_device_id[16] = "";
|
|
|
|
static WifiMqttConfig g_cfg;
|
|
static ReceiverSharedState g_receiver_shared = {};
|
|
static SenderStateMachine g_sender_state_machine;
|
|
static ReceiverPipeline g_receiver_pipeline;
|
|
|
|
static void serial_debug_printf(const char *fmt, ...) {
|
|
if (!SERIAL_DEBUG_MODE) {
|
|
return;
|
|
}
|
|
char buf[256];
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vsnprintf(buf, sizeof(buf), fmt, args);
|
|
va_end(args);
|
|
Serial.println(buf);
|
|
}
|
|
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
static void watchdog_init() {
|
|
esp_task_wdt_deinit();
|
|
esp_task_wdt_config_t config = {};
|
|
config.timeout_ms = WATCHDOG_TIMEOUT_SEC * 1000;
|
|
config.idle_core_mask = 0;
|
|
config.trigger_panic = true;
|
|
esp_task_wdt_init(&config);
|
|
esp_task_wdt_add(nullptr);
|
|
}
|
|
|
|
static void watchdog_kick() {
|
|
esp_task_wdt_reset();
|
|
}
|
|
#else
|
|
static void watchdog_init() {}
|
|
static void watchdog_kick() {}
|
|
#endif
|
|
|
|
void setup() {
|
|
Serial.begin(115200);
|
|
delay(200);
|
|
dd3_legacy_core_force_link();
|
|
|
|
#ifdef PAYLOAD_CODEC_TEST
|
|
payload_codec_self_test();
|
|
#endif
|
|
|
|
watchdog_init();
|
|
g_role = detect_role();
|
|
init_device_ids(g_short_id, g_device_id, sizeof(g_device_id));
|
|
|
|
display_set_role(g_role);
|
|
if (SERIAL_DEBUG_MODE) {
|
|
#ifdef ARDUINO_ARCH_ESP32
|
|
serial_debug_printf("boot: reset_reason=%d", static_cast<int>(esp_reset_reason()));
|
|
#endif
|
|
serial_debug_printf("boot: role=%s short_id=%04X dev=%s", g_role == DeviceRole::Sender ? "sender" : "receiver",
|
|
g_short_id, g_device_id);
|
|
}
|
|
|
|
lora_init();
|
|
display_init();
|
|
display_set_self_ids(g_short_id, g_device_id);
|
|
|
|
if (g_role == DeviceRole::Sender) {
|
|
SenderStateMachineConfig sender_cfg = {};
|
|
sender_cfg.short_id = g_short_id;
|
|
sender_cfg.device_id = g_device_id;
|
|
g_sender_state_machine.begin(sender_cfg);
|
|
return;
|
|
}
|
|
|
|
power_receiver_init();
|
|
lora_receive_continuous();
|
|
pinMode(PIN_ROLE, INPUT); // release pulldown before SD uses GPIO14 as SCK
|
|
sd_logger_init();
|
|
wifi_manager_init();
|
|
|
|
ReceiverPipelineConfig receiver_cfg = {};
|
|
receiver_cfg.short_id = g_short_id;
|
|
receiver_cfg.device_id = g_device_id;
|
|
receiver_cfg.shared = &g_receiver_shared;
|
|
g_receiver_pipeline.begin(receiver_cfg);
|
|
|
|
display_set_sender_statuses(g_receiver_shared.sender_statuses, NUM_SENDERS);
|
|
|
|
bool has_cfg = wifi_load_config(g_cfg);
|
|
|
|
// Store WiFi config in shared state for later reconnection attempts
|
|
g_receiver_shared.wifi_config = g_cfg;
|
|
g_receiver_shared.last_wifi_reconnect_attempt_ms = 0;
|
|
|
|
if (has_cfg && wifi_connect_sta(g_cfg)) {
|
|
g_receiver_shared.ap_mode = false;
|
|
time_receiver_init(g_cfg.ntp_server_1.c_str(), g_cfg.ntp_server_2.c_str());
|
|
mqtt_init(g_cfg, g_device_id);
|
|
web_server_set_config(g_cfg);
|
|
web_server_set_sender_faults(g_receiver_shared.sender_faults_remote, g_receiver_shared.sender_last_error_remote);
|
|
web_server_begin_sta(g_receiver_shared.sender_statuses, NUM_SENDERS);
|
|
} else {
|
|
g_receiver_shared.ap_mode = true;
|
|
char ap_ssid[32];
|
|
snprintf(ap_ssid, sizeof(ap_ssid), "%s%04X", AP_SSID_PREFIX, g_short_id);
|
|
wifi_start_ap(ap_ssid, AP_PASSWORD);
|
|
|
|
// Store AP credentials in shared state for potential reconnection fallback
|
|
strncpy(g_receiver_shared.ap_ssid, ap_ssid, sizeof(g_receiver_shared.ap_ssid) - 1);
|
|
g_receiver_shared.ap_ssid[sizeof(g_receiver_shared.ap_ssid) - 1] = '\0';
|
|
strncpy(g_receiver_shared.ap_password, AP_PASSWORD, sizeof(g_receiver_shared.ap_password) - 1);
|
|
g_receiver_shared.ap_password[sizeof(g_receiver_shared.ap_password) - 1] = '\0';
|
|
|
|
if (g_cfg.ntp_server_1.isEmpty()) {
|
|
g_cfg.ntp_server_1 = "pool.ntp.org";
|
|
}
|
|
if (g_cfg.ntp_server_2.isEmpty()) {
|
|
g_cfg.ntp_server_2 = "time.nist.gov";
|
|
}
|
|
web_server_set_config(g_cfg);
|
|
web_server_set_sender_faults(g_receiver_shared.sender_faults_remote, g_receiver_shared.sender_last_error_remote);
|
|
web_server_begin_ap(g_receiver_shared.sender_statuses, NUM_SENDERS);
|
|
}
|
|
}
|
|
|
|
void loop() {
|
|
if (g_role == DeviceRole::Sender) {
|
|
g_sender_state_machine.loop();
|
|
} else {
|
|
g_receiver_pipeline.loop();
|
|
}
|
|
}
|