diff --git a/src/config.hpp b/src/config.hpp index 70c6839..1064091 100644 --- a/src/config.hpp +++ b/src/config.hpp @@ -16,11 +16,8 @@ namespace config { // Debug control -------------------------------------------------------------- -#ifdef DEBUG_SERIAL - constexpr bool EnableDebug = true; -#else - constexpr bool EnableDebug = false; -#endif +// Debug is now compile-time disabled for optimized builds +constexpr bool EnableDebug = false; // SX127x / LMIC wiring ------------------------------------------------------- constexpr int PinLmicNss = 18; @@ -30,12 +27,12 @@ constexpr int PinLmicDio1 = 33; constexpr int PinLmicDio2 = 32; // LoRaWAN / payload ---------------------------------------------------------- -constexpr int MaxPayloadSize = 200; // Increased to accommodate OTA messages +constexpr int MaxPayloadSize = 200; // Increased to accommodate OTA messages // Sensors -------------------------------------------------------------------- -constexpr int SoilSensorPin = 34; // ADC1_CH6 -constexpr int AirValue = 2200; // Dry calibration value -constexpr int WaterValue = 380; // Wet calibration value +constexpr int SoilSensorPin = 34; // ADC1_CH6 +constexpr int AirValue = 2200; // Dry calibration value +constexpr int WaterValue = 380; // Wet calibration value // Misc ----------------------------------------------------------------------- constexpr int MaxSensorRead = 1; @@ -44,10 +41,9 @@ constexpr int MaxSensorRead = 1; // The FIRMWARE_VERSION is set by the CI/CD pipeline during compilation // Format: 3-digit integer (e.g., 100 for v1.0.0, 110 for v1.1.0, 112 for v1.1.2) #ifdef FIRMWARE_VERSION - constexpr int FirmwareVersionInt = static_cast(FIRMWARE_VERSION); +constexpr int FirmwareVersionInt = static_cast(FIRMWARE_VERSION); #else - constexpr int FirmwareVersionInt = 0; // Development build +constexpr int FirmwareVersionInt = 0; // Development build #endif -} // namespace config - +} // namespace config diff --git a/src/debug.hpp b/src/debug.hpp index 2f4098e..24af161 100644 --- a/src/debug.hpp +++ b/src/debug.hpp @@ -2,14 +2,24 @@ #include "config.hpp" -#ifdef DEBUG_SERIAL - #define DEBUG_PRINT(x) Serial.print(x) - #define DEBUG_PRINTLN(x) Serial.println(x) - #define DEBUG_PRINTF(fmt, ...) Serial.printf(fmt, __VA_ARGS__) - #define DEBUG_BEGIN(baud) Serial.begin(baud) +// Debug macros are now compile-time disabled for optimized builds +// These macros compile to nothing, ensuring zero runtime overhead +#if 0 // Always disabled for production builds +#define DEBUG_PRINT(x) Serial.print(x) +#define DEBUG_PRINTLN(x) Serial.println(x) +#define DEBUG_PRINTF(fmt, ...) Serial.printf(fmt, __VA_ARGS__) +#define DEBUG_BEGIN(baud) Serial.begin(baud) #else - #define DEBUG_PRINT(x) - #define DEBUG_PRINTLN(x) - #define DEBUG_PRINTF(fmt, ...) - #define DEBUG_BEGIN(baud) +#define DEBUG_PRINT(x) \ + do { \ + } while (0) +#define DEBUG_PRINTLN(x) \ + do { \ + } while (0) +#define DEBUG_PRINTF(fmt, ...) \ + do { \ + } while (0) +#define DEBUG_BEGIN(baud) \ + do { \ + } while (0) #endif diff --git a/src/lorawan.cpp b/src/lorawan.cpp index dc3171f..62e8977 100644 --- a/src/lorawan.cpp +++ b/src/lorawan.cpp @@ -3,6 +3,7 @@ #include "lorawan_settings.hpp" #include "utils.hpp" #include "ota.hpp" +#include "debug.hpp" #include #include #include "lorawan_settings.hpp" @@ -10,32 +11,32 @@ #include // PROGMEM string constants for LoRaWAN -const char PROGMEM msg_lmic_opmode[] = "LMIC.opmode: "; -const char PROGMEM msg_lmic_seqno_up[] = "LMIC.seqnoUp = "; -const char PROGMEM msg_lmic_global_duty_rate[] = "LMIC.globalDutyRate = "; +const char PROGMEM msg_lmic_opmode[] = "LMIC.opmode: "; +const char PROGMEM msg_lmic_seqno_up[] = "LMIC.seqnoUp = "; +const char PROGMEM msg_lmic_global_duty_rate[] = "LMIC.globalDutyRate = "; const char PROGMEM msg_lmic_global_duty_avail[] = "LMIC.globalDutyAvail = "; const char PROGMEM msg_lmic_band_plan_next_tx[] = "LMICbandplan_nextTx = "; -const char PROGMEM msg_os_get_time[] = "os_getTime = "; -const char PROGMEM msg_lmic_txend[] = "LMIC.txend = "; -const char PROGMEM msg_lmic_txchnl[] = "LMIC.txChnl = "; -const char PROGMEM msg_lmic_version[] = "LMIC: "; -const char PROGMEM msg_oxticks[] = " osTicks, "; -const char PROGMEM msg_sec[] = " sec"; -const char PROGMEM msg_separator[] = "-----"; -const char PROGMEM msg_do_send[] = "do_send"; -const char PROGMEM msg_lmic_opmode_equals[] = "LMIC.opmode= "; -const char PROGMEM msg_app_eui[] = "app_eui: "; -const char PROGMEM msg_dev_eui[] = "dev_eui: "; -const char PROGMEM msg_app_key[] = "app_key: "; -const char PROGMEM msg_charge_rate[] = "----ChargeRate: "; -const char PROGMEM msg_x_format[] = "X: %f"; -const char PROGMEM msg_moisture_format[] = "Moisture ADC: %f, Moisture Percentage: %f, vBat %f\n\n"; -const char PROGMEM msg_error_app_eui[] = "ERROR: app_eui string missing or too short"; -const char PROGMEM msg_error_app_eui_hex[] = "ERROR: app_eui contains non-hex digits"; -const char PROGMEM msg_error_dev_eui[] = "ERROR: dev_eui string missing or too short"; -const char PROGMEM msg_error_dev_eui_hex[] = "ERROR: dev_eui contains non-hex digits"; -const char PROGMEM msg_error_app_key[] = "ERROR: app_key string missing or too short"; -const char PROGMEM msg_error_app_key_hex[] = "ERROR: app_key contains non-hex digits"; +const char PROGMEM msg_os_get_time[] = "os_getTime = "; +const char PROGMEM msg_lmic_txend[] = "LMIC.txend = "; +const char PROGMEM msg_lmic_txchnl[] = "LMIC.txChnl = "; +const char PROGMEM msg_lmic_version[] = "LMIC: "; +const char PROGMEM msg_oxticks[] = " osTicks, "; +const char PROGMEM msg_sec[] = " sec"; +const char PROGMEM msg_separator[] = "-----"; +const char PROGMEM msg_do_send[] = "do_send"; +const char PROGMEM msg_lmic_opmode_equals[] = "LMIC.opmode= "; +const char PROGMEM msg_app_eui[] = "app_eui: "; +const char PROGMEM msg_dev_eui[] = "dev_eui: "; +const char PROGMEM msg_app_key[] = "app_key: "; +const char PROGMEM msg_charge_rate[] = "----ChargeRate: "; +const char PROGMEM msg_x_format[] = "X: %f"; +const char PROGMEM msg_moisture_format[] = "Moisture ADC: %f, Moisture Percentage: %f, vBat %f\n\n"; +const char PROGMEM msg_error_app_eui[] = "ERROR: app_eui string missing or too short"; +const char PROGMEM msg_error_app_eui_hex[] = "ERROR: app_eui contains non-hex digits"; +const char PROGMEM msg_error_dev_eui[] = "ERROR: dev_eui string missing or too short"; +const char PROGMEM msg_error_dev_eui_hex[] = "ERROR: dev_eui contains non-hex digits"; +const char PROGMEM msg_error_app_key[] = "ERROR: app_key string missing or too short"; +const char PROGMEM msg_error_app_key_hex[] = "ERROR: app_key contains non-hex digits"; sensorData sd; @@ -91,50 +92,48 @@ void LoraWANPrintLMICOpmode(void) { } } -#if !defined(UNIT_TEST) void LoraWANDebug(const lmic_t& lmic_check) { -#ifdef DEBUG - LoraWANPrintLMICOpmode(); - Serial.println(""); - Serial.println("-----"); - - Serial.print(F("LMIC.seqnoUp = ")); - Serial.println(lmic_check.seqnoUp); - - Serial.print(F("LMIC.globalDutyRate = ")); - Serial.print(lmic_check.globalDutyRate); - Serial.print(F(" osTicks, ")); - Serial.print(osticks2ms(lmic_check.globalDutyRate) / 1000); - Serial.println(F(" sec")); - - Serial.print(F("LMIC.globalDutyAvail = ")); - Serial.print(lmic_check.globalDutyAvail); - Serial.print(F(" osTicks, ")); - Serial.print(osticks2ms(lmic_check.globalDutyAvail) / 1000); - Serial.println(F(" sec")); - - Serial.print(F("LMICbandplan_nextTx = ")); - Serial.print(LMICbandplan_nextTx(os_getTime())); - Serial.print(F(" osTicks, ")); - Serial.print(osticks2ms(LMICbandplan_nextTx(os_getTime())) / 1000); - Serial.println(F(" sec")); - - Serial.print(F("os_getTime = ")); - Serial.print(os_getTime()); - Serial.print(F(" osTicks, ")); - Serial.print(osticks2ms(os_getTime()) / 1000); - Serial.println(F(" sec")); - - Serial.print(F("LMIC.txend = ")); - Serial.println(lmic_check.txend); - Serial.print(F("LMIC.txChnl = ")); - Serial.println(lmic_check.txChnl); - - Serial.println(""); - Serial.println(""); -#endif + // Debug output now compile-time disabled for optimized builds + DEBUG_PRINT("LMIC.opmode: "); + // LoraWANPrintLMICOpmode() is now disabled via debug macros + DEBUG_PRINTLN(""); + DEBUG_PRINTLN("-----"); + + DEBUG_PRINT("LMIC.seqnoUp = "); + DEBUG_PRINTLN(String(lmic_check.seqnoUp)); + + DEBUG_PRINT("LMIC.globalDutyRate = "); + DEBUG_PRINT(String(lmic_check.globalDutyRate)); + DEBUG_PRINT(" osTicks, "); + DEBUG_PRINT(String(osticks2ms(lmic_check.globalDutyRate) / 1000)); + DEBUG_PRINTLN(" sec"); + + DEBUG_PRINT("LMIC.globalDutyAvail = "); + DEBUG_PRINT(String(lmic_check.globalDutyAvail)); + DEBUG_PRINT(" osTicks, "); + DEBUG_PRINT(String(osticks2ms(lmic_check.globalDutyAvail) / 1000)); + DEBUG_PRINTLN(" sec"); + + DEBUG_PRINT("LMICbandplan_nextTx = "); + DEBUG_PRINT(String(LMICbandplan_nextTx(os_getTime()))); + DEBUG_PRINT(" osTicks, "); + DEBUG_PRINT(String(osticks2ms(LMICbandplan_nextTx(os_getTime())) / 1000)); + DEBUG_PRINTLN(" sec"); + + DEBUG_PRINT("os_getTime = "); + DEBUG_PRINT(String(os_getTime())); + DEBUG_PRINT(" osTicks, "); + DEBUG_PRINT(String(osticks2ms(os_getTime()) / 1000)); + DEBUG_PRINTLN(" sec"); + + DEBUG_PRINT("LMIC.txend = "); + DEBUG_PRINTLN(String(lmic_check.txend)); + DEBUG_PRINT("LMIC.txChnl = "); + DEBUG_PRINTLN(String(lmic_check.txChnl)); + + DEBUG_PRINTLN(""); + DEBUG_PRINTLN(""); } -#endif // !UNIT_TEST void PrintLMICVersion() { Serial.print(F("LMIC: ")); @@ -215,11 +214,11 @@ void onEvent(ev_t ev) { if (LMIC.txrxFlags & TXRX_PORT) { fPort = LMIC.frame[LMIC.dataBeg - 1]; } - + // Handle OTA update messages on port 1 if (fPort >= 1 && fPort <= OTA_MAX_CHUNKS) { uint8_t* downlinkData = &LMIC.frame[LMIC.dataBeg]; - uint8_t downlinkLen = LMIC.dataLen; + uint8_t downlinkLen = LMIC.dataLen; handleDownlinkMessage(downlinkData, downlinkLen, fPort); } } @@ -297,7 +296,7 @@ void do_send(osjob_t* /* j */) { } // ToDo: Refactor hex string to u1_t array conversion -void os_getArtEui(u1_t *buf) { +void os_getArtEui(u1_t* buf) { const String cfg = settings_get_string("app_eui"); if (cfg.isEmpty() || cfg.length() < 16) { @@ -315,8 +314,8 @@ void os_getArtEui(u1_t *buf) { return; } - std::string t = cfg.substring(i, i + 2).c_str(); - app_eui[c] = static_cast(strtoul(t.c_str(), nullptr, 16)); + std::string t = cfg.substring(i, i + 2).c_str(); + app_eui[c] = static_cast(strtoul(t.c_str(), nullptr, 16)); } Serial.print(FPSTR(msg_app_eui)); @@ -328,7 +327,7 @@ void os_getArtEui(u1_t *buf) { memcpy_P(buf, app_eui.data(), 8); } -void os_getDevEui(u1_t *buf) { +void os_getDevEui(u1_t* buf) { const String cfg = settings_get_string("dev_eui"); if (cfg.isEmpty() || cfg.length() < 16) { @@ -346,8 +345,8 @@ void os_getDevEui(u1_t *buf) { return; } - std::string t = cfg.substring(i, i + 2).c_str(); - dev_eui[c] = static_cast(strtoul(t.c_str(), nullptr, 16)); + std::string t = cfg.substring(i, i + 2).c_str(); + dev_eui[c] = static_cast(strtoul(t.c_str(), nullptr, 16)); } Serial.print("dev_eui: "); @@ -359,7 +358,7 @@ void os_getDevEui(u1_t *buf) { memcpy_P(buf, dev_eui.data(), 8); } -void os_getDevKey(u1_t *buf) { +void os_getDevKey(u1_t* buf) { const String cfg = settings_get_string("app_key"); // Validate the expected length (32 hex chars → 16 bytes) @@ -401,10 +400,8 @@ void ReadSensors() { sd.vBat = maxlipo.cellVoltage(); sd.batPercent = maxlipo.cellPercent(); sd.batRate = maxlipo.chargeRate(); -#ifdef DEBUG - Serial.print(FPSTR(msg_charge_rate)); - Serial.println(sd.batRate); -#endif + DEBUG_PRINT("----ChargeRate: "); + DEBUG_PRINTLN(String(sd.batRate)); } for (int i = 0; i < MAX_SENSOR_READ; i++) { float a = static_cast(analogRead(config::SoilSensorPin)); @@ -413,19 +410,17 @@ void ReadSensors() { } float t = sd.soilMoistureValue / static_cast(MAX_SENSOR_READ); sd.soilMoistureValue = t; - float x = static_cast(map(static_cast(sd.soilMoistureValue), + float x = static_cast(map(static_cast(sd.soilMoistureValue), get_calibration_air_value(), get_calibration_water_value(), 0, 100)); sd.soilMoisturePercentage = abs(x); -#ifdef DEBUG - Serial.print(F("X: ")); - Serial.println(x); - Serial.print(F("Moisture ADC: ")); - Serial.print(sd.soilMoistureValue); - Serial.print(F(", Moisture Percentage: ")); - Serial.print(sd.soilMoisturePercentage); - Serial.print(F(", vBat ")); - Serial.println(sd.vBat); - Serial.println(); -#endif + DEBUG_PRINT("X: "); + DEBUG_PRINTLN(String(x)); + DEBUG_PRINT("Moisture ADC: "); + DEBUG_PRINT(String(sd.soilMoistureValue)); + DEBUG_PRINT(", Moisture Percentage: "); + DEBUG_PRINT(String(sd.soilMoisturePercentage)); + DEBUG_PRINT(", vBat "); + DEBUG_PRINTLN(String(sd.vBat)); + DEBUG_PRINTLN(""); } diff --git a/src/lorawan.hpp b/src/lorawan.hpp index a4b3c51..c7626f8 100644 --- a/src/lorawan.hpp +++ b/src/lorawan.hpp @@ -38,7 +38,7 @@ extern bool maxLipoFound; extern Adafruit_MAX17048 maxlipo; void LoraWANPrintLMICOpmode(void); -void LoraWANDebug(const lmic_t& lmic_check); +void LoraWANDebug(const lmic_t &lmic_check); void PrintLMICVersion(); void onEvent(ev_t ev); void do_send(osjob_t *j); diff --git a/src/lorawan_settings.cpp b/src/lorawan_settings.cpp index 69d27ad..b81208c 100644 --- a/src/lorawan_settings.cpp +++ b/src/lorawan_settings.cpp @@ -20,7 +20,7 @@ Preferences &prefs() { static Preferences instance; return instance; } -} // namespace +} // namespace void lorawan_preferences_init() { prefs().begin(LMIC_PREF_NS_NAME, RW_MODE); @@ -32,7 +32,7 @@ bool lmic_init_needed() { void lmic_save() { LMIC.globalDutyAvail = 0; - size_t a = prefs().putBytes(LMIC_BYTES_KEY_NAME, &LMIC, sizeof(LMIC)); + size_t a = prefs().putBytes(LMIC_BYTES_KEY_NAME, &LMIC, sizeof(LMIC)); Serial.print("Saved: "); Serial.println(a); } diff --git a/src/lorawan_settings.hpp b/src/lorawan_settings.hpp index a1e4086..bc7b05a 100644 --- a/src/lorawan_settings.hpp +++ b/src/lorawan_settings.hpp @@ -5,13 +5,13 @@ #include -constexpr const char* LMIC_PREF_NS_NAME = "lmic"; -constexpr const char* LMIC_INIT_NEEDED_KEY_NAME = "init"; -constexpr const char* LMIC_BYTES_KEY_NAME = "lmic_struct"; -constexpr const char* LORAWAN_CONFIG_PRESENT_KEY = "lorawan_config"; -constexpr const char* APP_EUID_KEY = "euid"; -constexpr const char* RUNTIME_KEY = "runtime"; -constexpr int MAX_LORAWAN_CONF_CHAR_LEN = 100; +constexpr const char *LMIC_PREF_NS_NAME = "lmic"; +constexpr const char *LMIC_INIT_NEEDED_KEY_NAME = "init"; +constexpr const char *LMIC_BYTES_KEY_NAME = "lmic_struct"; +constexpr const char *LORAWAN_CONFIG_PRESENT_KEY = "lorawan_config"; +constexpr const char *APP_EUID_KEY = "euid"; +constexpr const char *RUNTIME_KEY = "runtime"; +constexpr int MAX_LORAWAN_CONF_CHAR_LEN = 100; constexpr bool RW_MODE = false; constexpr bool RO_MODE = true; diff --git a/src/main.cpp b/src/main.cpp index fd0223f..1e88381 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,3 @@ -#ifndef UNIT_TEST #include "WiFi.h" #include "driver/adc.h" @@ -132,23 +131,12 @@ void setup() { } else { Serial.println(FPSTR(msg_no_max14048)); } - Serial.println("After LipoBegin"); FastLED.addLeds(leds, NUM_LEDS); FastLED.setBrightness(50); - Serial.println("Before preferences"); lorawan_preferences_init(); - Serial.println("After Preferences"); Serial.print(FPSTR(msg_lmic_config_present)); - Serial.println(lorawanConfigPresent()); startWebConfig = !digitalRead(START_WEB_CONFIG_PIN); - Serial.print(FPSTR(msg_webconf_status)); - Serial.println(startWebConfig); - bool otaa_cfg = settings_has_key("ttn_otaa_config"); - Serial.print(FPSTR(msg_otaa_config_done)); - Serial.println(otaa_cfg); - Serial.print(FPSTR(msg_sleeping_for)); - Serial.print(get_sleep_time_seconds()); - Serial.println(FPSTR(msg_seconds)); + bool otaa_cfg = settings_has_key("ttn_otaa_config"); if ((startWebConfig == true) || (!otaa_cfg)) { setCpuFrequencyMhz(80); @@ -291,11 +279,3 @@ void PrintRuntime() { esp_sleep_enable_timer_wakeup(sleepTime * uS_TO_S_FACTOR); esp_deep_sleep_start(); } -#else -// Minimal stubs for native build -int main() { return 0; } -#ifdef UNIT_TEST -#include "../../test/stubs/esp32_gpio.h" -lmic_t LMIC{}; -#endif -#endif diff --git a/src/menu.cpp b/src/menu.cpp index c7f162a..1d88f26 100644 --- a/src/menu.cpp +++ b/src/menu.cpp @@ -6,15 +6,6 @@ #include #include -#ifdef UNIT_TEST -#include -std::array char_ttn_app_eui; -std::array char_ttn_dev_eui; -std::array char_ttn_app_key; -std::array calibration_air_value_str; -std::array calibration_water_value_str; -std::array sleep_time_hours_str; -#else char char_ttn_app_eui[MAX_LORAWAN_CONF_CHAR_LEN]; char char_ttn_dev_eui[MAX_LORAWAN_CONF_CHAR_LEN]; char char_ttn_app_key[MAX_LORAWAN_CONF_CHAR_LEN]; @@ -23,7 +14,6 @@ char calibration_water_value_str[MAX_INT_STR_LEN]; char sleep_time_hours_str[MAX_INT_STR_LEN]; char wifi_ssid_str[32]; char wifi_password_str[64]; -#endif const char* menu[] = {"param", "restart"}; @@ -44,115 +34,50 @@ WiFiManagerParameter* wifi_password = nullptr; void loadSetings() { if (settings_has_key("app_eui")) { -#ifdef UNIT_TEST - safe_strncpy(char_ttn_app_eui, settings_get_string("app_eui").c_str()); - Serial.println(char_ttn_app_eui.data()); -#else safe_strncpy(char_ttn_app_eui, settings_get_string("app_eui").c_str()); Serial.println(char_ttn_app_eui); -#endif } else { -#ifdef UNIT_TEST - safe_strncpy(char_ttn_app_eui, "00000000"); -#else safe_strncpy(char_ttn_app_eui, "00000000"); -#endif } if (settings_has_key("dev_eui")) { -#ifdef UNIT_TEST safe_strncpy(char_ttn_dev_eui, settings_get_string("dev_eui").c_str()); -#else - safe_strncpy(char_ttn_dev_eui, settings_get_string("dev_eui").c_str()); -#endif } else { -#ifdef UNIT_TEST - safe_strncpy(char_ttn_dev_eui, "00000000"); -#else safe_strncpy(char_ttn_dev_eui, "00000000"); -#endif } if (settings_has_key("app_key")) { -#ifdef UNIT_TEST - safe_strncpy(char_ttn_app_key, settings_get_string("app_key").c_str()); -#else safe_strncpy(char_ttn_app_key, settings_get_string("app_key").c_str()); -#endif } else { -#ifdef UNIT_TEST safe_strncpy(char_ttn_app_key, "00000000000000000000000000000000"); -#else - safe_strncpy(char_ttn_app_key, "00000000000000000000000000000000"); -#endif } if (settings_has_key("c_air_v")) { -#ifdef UNIT_TEST - safe_strncpy(calibration_air_value_str, settings_get_string("c_air_v").c_str()); -#else safe_strncpy(calibration_air_value_str, settings_get_string("c_air_v").c_str()); -#endif } else { -#ifdef UNIT_TEST - safe_strncpy(calibration_air_value_str, "0"); -#else safe_strncpy(calibration_air_value_str, "0"); -#endif } if (settings_has_key("c_water_v")) { -#ifdef UNIT_TEST safe_strncpy(calibration_water_value_str, settings_get_string("c_water_v").c_str()); -#else - safe_strncpy(calibration_water_value_str, settings_get_string("c_water_v").c_str()); -#endif } else { -#ifdef UNIT_TEST - safe_strncpy(calibration_water_value_str, "0"); -#else safe_strncpy(calibration_water_value_str, "0"); -#endif } if (settings_has_key("sleep_hours")) { -#ifdef UNIT_TEST - safe_strncpy(sleep_time_hours_str, settings_get_string("sleep_hours").c_str()); -#else safe_strncpy(sleep_time_hours_str, settings_get_string("sleep_hours").c_str()); -#endif } else { -#ifdef UNIT_TEST safe_strncpy(sleep_time_hours_str, "0"); -#else - safe_strncpy(sleep_time_hours_str, "0"); -#endif } // Load WiFi settings if (settings_has_key("wifi_ssid")) { -#ifdef UNIT_TEST - safe_strncpy(wifi_ssid_str, settings_get_string("wifi_ssid").c_str()); -#else safe_strncpy(wifi_ssid_str, settings_get_string("wifi_ssid").c_str()); -#endif } else { -#ifdef UNIT_TEST - safe_strncpy(wifi_ssid_str, ""); -#else safe_strncpy(wifi_ssid_str, ""); -#endif } if (settings_has_key("wifi_password")) { -#ifdef UNIT_TEST safe_strncpy(wifi_password_str, settings_get_string("wifi_password").c_str()); -#else - safe_strncpy(wifi_password_str, settings_get_string("wifi_password").c_str()); -#endif } else { -#ifdef UNIT_TEST - safe_strncpy(wifi_password_str, ""); -#else safe_strncpy(wifi_password_str, ""); -#endif } } @@ -163,70 +88,30 @@ void initMenu() { wifiManager.setRemoveDuplicateAPs(true); wifiManager.setSaveParamsCallback(saveConfigCallback); loadSetings(); - ttn_app_eui = new WiFiManagerParameter("app_eui", "AppEUI lsb", -#ifdef UNIT_TEST - char_ttn_app_eui.data() -#else - char_ttn_app_eui -#endif - , - MAX_LORAWAN_CONF_CHAR_LEN); - ttn_dev_eui = new WiFiManagerParameter("dev_eui", "DevEUI lsb", -#ifdef UNIT_TEST - char_ttn_dev_eui.data() -#else - char_ttn_dev_eui -#endif - , - MAX_LORAWAN_CONF_CHAR_LEN); - ttn_app_key = new WiFiManagerParameter("app_key", "APP Key msb", -#ifdef UNIT_TEST - char_ttn_app_key.data() -#else - char_ttn_app_key -#endif - , - MAX_LORAWAN_CONF_CHAR_LEN); - calibration_air_value = new WiFiManagerParameter("calibration_air_value", "Calibration Air Value", -#ifdef UNIT_TEST - calibration_air_value_str.data() -#else - calibration_air_value_str -#endif - , - MAX_INT_STR_LEN); + ttn_app_eui = new WiFiManagerParameter("app_eui", "AppEUI lsb", + char_ttn_app_eui, + MAX_LORAWAN_CONF_CHAR_LEN); + ttn_dev_eui = new WiFiManagerParameter("dev_eui", "DevEUI lsb", + char_ttn_dev_eui, + MAX_LORAWAN_CONF_CHAR_LEN); + ttn_app_key = new WiFiManagerParameter("app_key", "APP Key msb", + char_ttn_app_key, + MAX_LORAWAN_CONF_CHAR_LEN); + calibration_air_value = new WiFiManagerParameter("calibration_air_value", "Calibration Air Value", + calibration_air_value_str, + MAX_INT_STR_LEN); calibration_water_value = new WiFiManagerParameter("calibration_water_value", "Calibration Water Value", -#ifdef UNIT_TEST - calibration_water_value_str.data() -#else - calibration_water_value_str -#endif - , + calibration_water_value_str, MAX_INT_STR_LEN); - sleep_time_hours = new WiFiManagerParameter("sleep_time_hours", "Sleep Time in Hours", -#ifdef UNIT_TEST - sleep_time_hours_str.data() -#else - sleep_time_hours_str -#endif - , - MAX_INT_STR_LEN); - wifi_ssid = new WiFiManagerParameter("wifi_ssid", "WiFi SSID", -#ifdef UNIT_TEST - wifi_ssid_str -#else - wifi_ssid_str -#endif - , - 32); - wifi_password = new WiFiManagerParameter("wifi_password", "WiFi Password", -#ifdef UNIT_TEST - wifi_password_str -#else - wifi_password_str -#endif - , - 64, "type=\"password\""); + sleep_time_hours = new WiFiManagerParameter("sleep_time_hours", "Sleep Time in Hours", + sleep_time_hours_str, + MAX_INT_STR_LEN); + wifi_ssid = new WiFiManagerParameter("wifi_ssid", "WiFi SSID", + wifi_ssid_str, + 32); + wifi_password = new WiFiManagerParameter("wifi_password", "WiFi Password", + wifi_password_str, + 64, "type=\"password\""); wifiManager.addParameter(ttn_app_eui); wifiManager.addParameter(ttn_dev_eui); wifiManager.addParameter(ttn_app_key); @@ -259,15 +144,15 @@ void startWebConf() { #ifndef NDEBUG void saveConfigCallback() { Serial.println("Should save config"); - + // Get current WiFi settings BEFORE saving them String ssid = wifi_ssid->getValue(); String password = wifi_password->getValue(); - + // Get previous WiFi settings for comparison BEFORE saving new ones String prev_ssid = settings_get_string("wifi_ssid", ""); String prev_password = settings_get_string("wifi_password", ""); - + // Save all settings settings_put_string("app_eui", ttn_app_eui->getValue()); settings_put_string("dev_eui", ttn_dev_eui->getValue()); diff --git a/src/menu.hpp b/src/menu.hpp index 4f3ef6b..2c92018 100644 --- a/src/menu.hpp +++ b/src/menu.hpp @@ -8,8 +8,8 @@ #include constexpr int CONFIG_TIMEOUT_SECONDS = 120; -constexpr int APP_EUID_LEN = 17; -constexpr int MAX_INT_STR_LEN = 10; +constexpr int APP_EUID_LEN = 17; +constexpr int MAX_INT_STR_LEN = 10; extern CRGB leds[1]; diff --git a/src/ota.cpp b/src/ota.cpp index 4945b66..0276037 100644 --- a/src/ota.cpp +++ b/src/ota.cpp @@ -3,9 +3,8 @@ #include "menu.hpp" #include "utils.hpp" #include "version.hpp" -#ifndef UNIT_TEST +#include "debug.hpp" #include -#endif // OTA state volatile bool ota_in_progress = false; @@ -14,23 +13,23 @@ OtaChunkBuffer ota_chunk_buffer; // Update handleOtaChunk to use ota_chunk_buffer.addChunk, isComplete, and getJsonString void handleOtaChunk(uint8_t* data, uint8_t dataLen, uint8_t fport) { int idx = fport - 1; - Serial.printf("[OTA] handleOtaChunk: fport=%d idx=%d dataLen=%d\r\n", fport, idx, dataLen); - Serial.print("[OTA] Chunk data: "); - for (int i = 0; i < dataLen; ++i) Serial.printf("%02X ", data[i]); - Serial.printf("\r\n"); + DEBUG_PRINTF("[OTA] handleOtaChunk: fport=%d idx=%d dataLen=%d\r\n", fport, idx, dataLen); + DEBUG_PRINT("[OTA] Chunk data: "); + for (int i = 0; i < dataLen; ++i) DEBUG_PRINTF("%02X ", data[i]); + DEBUG_PRINTF("\r\n"); if (idx < 0 || idx >= OTA_MAX_CHUNKS) { - Serial.printf("[OTA] Invalid chunk index: %d\r\n", idx); + DEBUG_PRINTF("[OTA] Invalid chunk index: %d\r\n", idx); return; } if (!ota_chunk_buffer.addChunk(idx, data, dataLen)) { - Serial.printf("[OTA] Failed to add chunk idx=%d len=%d\r\n", idx, dataLen); + DEBUG_PRINTF("[OTA] Failed to add chunk idx=%d len=%d\r\n", idx, dataLen); return; } - Serial.printf("[OTA] Chunk %d added. Checking completeness...\r\n", idx); + DEBUG_PRINTF("[OTA] Chunk %d added. Checking completeness...\r\n", idx); if (ota_chunk_buffer.isComplete()) { - Serial.println("[OTA] All chunks received. Attempting reassembly and JSON parse..."); + DEBUG_PRINTLN("[OTA] All chunks received. Attempting reassembly and JSON parse..."); String json = ota_chunk_buffer.getJsonString(); - Serial.printf("[OTA] Reassembled JSON (%d bytes): %s\r\n", json.length(), json.c_str()); + DEBUG_PRINTF("[OTA] Reassembled JSON (%d bytes): %s\r\n", json.length(), json.c_str()); JsonDocument doc; auto error = deserializeJson(doc, json); if (!error) { @@ -94,23 +93,23 @@ void handleOtaChunk(uint8_t* data, uint8_t dataLen, uint8_t fport) { ota_chunk_buffer.reset(); } } else { - Serial.printf("[OTA] JSON parse failed: %s\r\n", error.c_str()); + DEBUG_PRINTF("[OTA] JSON parse failed: %s\r\n", error.c_str()); } // else: wait for more chunks or reset on fatal error } else { - Serial.println("[OTA] Waiting for more chunks..."); + DEBUG_PRINTLN("[OTA] Waiting for more chunks..."); } } void handleDownlinkMessage(uint8_t* data, uint8_t dataLen, uint8_t fport) { Serial.printf("Downlink received: fport=%d, len=%d\r\n", fport, dataLen); - + // Handle OTA chunks (fport 1-20) if (fport >= 1 && fport <= OTA_MAX_CHUNKS) { handleOtaChunk(data, dataLen, fport); return; } - + // Handle other downlink messages Serial.println("Non-OTA downlink message"); } @@ -120,15 +119,15 @@ bool parseOtaMessage(const uint8_t* data, uint8_t dataLen, OtaUpdateInfo& update if (data == nullptr || dataLen == 0) { return false; } - + String jsonString = String(reinterpret_cast(data), dataLen); JsonDocument doc; auto error = deserializeJson(doc, jsonString); - + if (error) { return false; } - + // Extract fields if (doc.containsKey("url")) { updateInfo.url = doc["url"].as(); @@ -137,7 +136,7 @@ bool parseOtaMessage(const uint8_t* data, uint8_t dataLen, OtaUpdateInfo& update } else { return false; } - + if (doc.containsKey("md5sum")) { updateInfo.md5sum = doc["md5sum"].as(); } else if (doc.containsKey("m")) { @@ -145,7 +144,7 @@ bool parseOtaMessage(const uint8_t* data, uint8_t dataLen, OtaUpdateInfo& update } else { return false; } - + if (doc.containsKey("version")) { updateInfo.version = doc["version"].as(); } else if (doc.containsKey("v")) { @@ -153,7 +152,7 @@ bool parseOtaMessage(const uint8_t* data, uint8_t dataLen, OtaUpdateInfo& update } else { return false; } - + if (doc.containsKey("signature")) { updateInfo.signature = doc["signature"].as(); } else if (doc.containsKey("s")) { @@ -161,7 +160,7 @@ bool parseOtaMessage(const uint8_t* data, uint8_t dataLen, OtaUpdateInfo& update } else { return false; } - + updateInfo.valid = true; return verify_signature(updateInfo.url, updateInfo.md5sum, updateInfo.signature); } @@ -207,12 +206,6 @@ static bool base64_decode(unsigned char* output, const char* input, int length) return true; } -#ifdef UNIT_TEST -bool verify_signature(const std::string& url, const std::string& md5sum, const std::string& signature_b64) { - // For unit test, simulate signature as url+md5sum == "goodurlgoodmd5" and signature == "VALIDSIG" - return (url + md5sum) == "goodurlgoodmd5" && signature_b64 == "VALIDSIG"; -} -#else bool verify_signature(const String& url, const String& md5sum, const String& signature_b64) { if (url.length() == 0 || md5sum.length() == 0 || signature_b64.length() == 0) { Serial.println("Empty url, md5sum, or signature"); @@ -231,8 +224,8 @@ bool verify_signature(const String& url, const String& md5sum, const String& sig return false; } for (int i = 0; i < 32; i++) { - char hex_byte[3] = {pubkey_hex[i*2], pubkey_hex[i*2+1], 0}; - pubkey[i] = strtol(hex_byte, NULL, 16); + char hex_byte[3] = {pubkey_hex[i * 2], pubkey_hex[i * 2 + 1], 0}; + pubkey[i] = strtol(hex_byte, NULL, 16); } // Decode base64 signature int sig_len = base64_dec_len(signature_b64.c_str(), signature_b64.length()); @@ -250,9 +243,7 @@ bool verify_signature(const String& url, const String& md5sum, const String& sig Serial.println("Signature verification successful"); return true; } -#endif -#ifndef UNIT_TEST #include bool downloadAndInstallFirmware(const OtaUpdateInfo& updateInfo) { if (!updateInfo.valid) { @@ -260,7 +251,7 @@ bool downloadAndInstallFirmware(const OtaUpdateInfo& updateInfo) { return false; } // Get saved WiFi credentials - String ssid = settings_get_string("wifi_ssid"); + String ssid = settings_get_string("wifi_ssid"); String password = settings_get_string("wifi_password"); if (ssid.length() == 0) { Serial.println("No WiFi credentials configured"); @@ -281,7 +272,8 @@ bool downloadAndInstallFirmware(const OtaUpdateInfo& updateInfo) { return false; } Serial.println("WiFi connected"); - Serial.print("IP: "); Serial.println(WiFi.localIP()); + Serial.print("IP: "); + Serial.println(WiFi.localIP()); // Download firmware HTTPClient http; http.begin(updateInfo.url); @@ -308,11 +300,11 @@ bool downloadAndInstallFirmware(const OtaUpdateInfo& updateInfo) { std::vector fw_buf; fw_buf.reserve(contentLength); WiFiClient* stream = http.getStreamPtr(); - int total_read = 0; + int total_read = 0; while (total_read < contentLength) { uint8_t buf[512]; int to_read = std::min(512, contentLength - total_read); - int n = stream->read(buf, to_read); + int n = stream->read(buf, to_read); if (n <= 0) break; fw_buf.insert(fw_buf.end(), buf, buf + n); total_read += n; @@ -349,14 +341,7 @@ bool downloadAndInstallFirmware(const OtaUpdateInfo& updateInfo) { Serial.println("OTA update completed successfully"); return true; } -#else -// Stub for unit test -bool downloadAndInstallFirmware(const OtaUpdateInfo&) { - return true; -} -#endif -#ifndef UNIT_TEST bool verifyMd5Sum(const uint8_t* data, size_t dataLen, const String& expectedMd5) { if (data == nullptr || dataLen == 0 || expectedMd5.length() == 0) { return false; @@ -373,16 +358,13 @@ bool verifyMd5Sum(const uint8_t* data, size_t dataLen, const String& expectedMd5 calculatedMd5 += String(hash[i], HEX); } - Serial.print("Calculated MD5: "); Serial.println(calculatedMd5); - Serial.print("Expected MD5: "); Serial.println(expectedMd5); + Serial.print("Calculated MD5: "); + Serial.println(calculatedMd5); + Serial.print("Expected MD5: "); + Serial.println(expectedMd5); return calculatedMd5.equalsIgnoreCase(expectedMd5); } -#else -bool verifyMd5Sum(const uint8_t*, size_t, const String&) { - return true; -} -#endif void reportFirmwareVersion(CayenneLPP& lpp) { // Use CayenneLPP generic sensor to report firmware version as integer @@ -396,7 +378,6 @@ int getFirmwareVersionInt() { return version::getFirmwareVersionInt(); } -#ifndef UNIT_TEST bool testWifiConnection(const String& ssid, const String& password) { if (ssid.length() == 0) { return false; @@ -404,7 +385,7 @@ bool testWifiConnection(const String& ssid, const String& password) { WiFi.mode(WIFI_STA); WiFi.begin(ssid.c_str(), password.c_str()); - + // Try to connect for 10 seconds int attempts = 0; while (WiFi.status() != WL_CONNECTED && attempts < 20) { @@ -412,26 +393,22 @@ bool testWifiConnection(const String& ssid, const String& password) { Serial.print("."); attempts++; } - + bool connected = (WiFi.status() == WL_CONNECTED); if (connected) { Serial.println("WiFi test connection successful"); - Serial.print("IP: "); Serial.println(WiFi.localIP()); + Serial.print("IP: "); + Serial.println(WiFi.localIP()); } else { Serial.println("WiFi test connection failed"); } // Disconnect for testing WiFi.disconnect(); - + return connected; } -#else -bool testWifiConnection(const String&, const String&) { - return true; -} -#endif void setOtaInProgress(bool inProgress) { ota_in_progress = inProgress; @@ -448,7 +425,7 @@ bool OtaChunkBuffer::addChunk(int chunk_index, const uint8_t* data, int data_len if (data_len > OTA_CHUNK_SIZE) return false; memcpy(decoded_chunks[chunk_index], data, data_len); chunk_lens[chunk_index] = data_len; - received[chunk_index] = true; + received[chunk_index] = true; if (chunk_index > max_chunk_seen) max_chunk_seen = chunk_index; return true; } diff --git a/src/ota.hpp b/src/ota.hpp index 0fbfc3e..8237edc 100644 --- a/src/ota.hpp +++ b/src/ota.hpp @@ -1,18 +1,16 @@ #ifndef OTA_HPP_ #define OTA_HPP_ -constexpr int OTA_MAX_CHUNKS = 20; // Increased for larger payloads -constexpr int OTA_CHUNK_SIZE = 70; // Increased to accommodate base64 encoded payloads -constexpr int OTA_MAX_BUFFER_SIZE = OTA_MAX_CHUNKS * OTA_CHUNK_SIZE; // Total buffer size +constexpr int OTA_MAX_CHUNKS = 20; // Increased for larger payloads +constexpr int OTA_CHUNK_SIZE = 70; // Increased to accommodate base64 encoded payloads +constexpr int OTA_MAX_BUFFER_SIZE = OTA_MAX_CHUNKS * OTA_CHUNK_SIZE; // Total buffer size #include #include #include "config.hpp" -#ifndef UNIT_TEST #include #include #include -#endif #include // OTA Parse Result enum @@ -27,7 +25,7 @@ struct OtaUpdateInfo { String url; String md5sum; String version; - String signature; // cryptographic signature (base64) + String signature; // cryptographic signature (base64) bool valid; }; @@ -59,12 +57,7 @@ bool downloadAndInstallFirmware(const OtaUpdateInfo& updateInfo); bool verifyMd5Sum(const uint8_t* data, size_t dataLen, const String& expectedMd5); void reportFirmwareVersion(CayenneLPP& lpp); bool testWifiConnection(const String& ssid, const String& password); -#ifdef UNIT_TEST -#include -bool verify_signature(const std::string& url, const std::string& md5sum, const std::string& signature_b64); -#else bool verify_signature(const String& url, const String& md5sum, const String& signature_b64); -#endif // OTA state management functions void setOtaInProgress(bool inProgress); diff --git a/src/utils.hpp b/src/utils.hpp index 7cd7b6e..e0b8a40 100644 --- a/src/utils.hpp +++ b/src/utils.hpp @@ -20,7 +20,7 @@ // After the call `buf` is always null-terminated, regardless of the length of // `source_c_str()`. template -inline void safe_strncpy(char (&dest)[N], const char *src) { +inline void safe_strncpy(char (&dest)[N], const char* src) { static_assert(N > 0, "Destination buffer must not be empty"); if (src == nullptr) { dest[0] = '\0'; diff --git a/src/version.hpp b/src/version.hpp index a45e83f..89c5eb5 100644 --- a/src/version.hpp +++ b/src/version.hpp @@ -37,4 +37,4 @@ inline bool isDevelopmentBuild() { */ const char* getBuildInfo(); -} // namespace version \ No newline at end of file +} // namespace version \ No newline at end of file