From a27af14e815ef993e9a0c94e5bc8b32dbf989a94 Mon Sep 17 00:00:00 2001 From: Filip Wandzio Date: Wed, 29 Oct 2025 13:29:27 +0100 Subject: Solve baud detection bug, fix wifi searching task scheduling bug, improve documentation, implement additional mqtt topics --- README | 1 - README.md | 2 + firmware/.baud_detected | 1 + firmware/Makefile | 30 +++++++++- firmware/platformio.ini | 2 +- firmware/src/main.c | 152 +++++++++++++++++++++++++++-------------------- firmware/src/mqtt.c | 28 ++++----- firmware/src/wifi_scan.c | 19 ++++-- 8 files changed, 144 insertions(+), 91 deletions(-) delete mode 100644 README create mode 100644 README.md create mode 100644 firmware/.baud_detected diff --git a/README b/README deleted file mode 100644 index 823695c..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -The beginning of my master's thesis project. Here I will test the broad cybersecurity issues of IoT devices, and hopefully solve them. diff --git a/README.md b/README.md new file mode 100644 index 0000000..e380147 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# The beginning of my master's thesis project. +Here I will test the MQTT-related issues of IoT devices, and specify how to solve them properly. diff --git a/firmware/.baud_detected b/firmware/.baud_detected new file mode 100644 index 0000000..be25b30 --- /dev/null +++ b/firmware/.baud_detected @@ -0,0 +1 @@ +115200 diff --git a/firmware/Makefile b/firmware/Makefile index 0fd1699..0595792 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -9,7 +9,29 @@ BUILD_FLAGS = -D WIFI_SSID="\\\"$(WIFI_SSID)\\\"" \ -D WIFI_PASS="\\\"$(WIFI_PASS)\\\"" \ -D MQTT_URI="\\\"$(MQTT_URI)\\\"" -.PHONY: build upload monitor clean debug-flags test +PORT ?= $(shell ls /dev/ttyUSB* /dev/ttyACM* 2>/dev/null | head -n 1) + +ifdef BAUD + BAUD := $(BAUD) +else ifneq ("$(wildcard .baud_detected)","") + BAUD := $(shell cat .baud_detected) +else + BAUD := 115200 +endif + +detect-baud: + @echo "[*] Detecting correct baud rate..." + @if screen -L -dmS test_screen $(PORT) 74880; then \ + sleep 1; \ + grep -q "rst:" screenlog.0 && echo "74880" > .baud_detected || echo "115200" > .baud_detected; \ + rm -f screenlog.0; \ + screen -S test_screen -X quit; \ + else \ + echo "115200" > .baud_detected; \ + fi + @echo "[✓] Set BAUD=$$(cat .baud_detected)" + +.PHONY: build upload monitor clean debug-flags test detect-baud build: @echo "Starting build with SSID=$(WIFI_SSID)" @@ -20,7 +42,11 @@ upload: PLATFORMIO_BUILD_FLAGS="$(BUILD_FLAGS)" pio run -e $(ENV) -t upload monitor: - pio device monitor -e $(ENV) + @PORT=$(PORT); \ + BAUD=$(BAUD); \ + if [ -z "$$PORT" ]; then echo "[ERROR] Port /dev/ttyUSB* or /dev/ttyACM* not found"; exit 1; fi; \ + echo "[*] Opening monitor: $$PORT @ $$BAUD baud"; \ + screen $$PORT $$BAUD clean: pio run -e $(ENV) -t clean diff --git a/firmware/platformio.ini b/firmware/platformio.ini index 4f199c3..b106ca7 100644 --- a/firmware/platformio.ini +++ b/firmware/platformio.ini @@ -5,4 +5,4 @@ framework = espidf monitor_speed = 115200 platform_packages = framework-espidf@3.50500.0 -; board_build.flash_size = 2MB +board_build.flash_size = 2MB diff --git a/firmware/src/main.c b/firmware/src/main.c index 3f186f8..9fa4c61 100644 --- a/firmware/src/main.c +++ b/firmware/src/main.c @@ -1,5 +1,7 @@ #include "esp_event.h" #include "esp_log.h" +#include "esp_netif.h" +#include "esp_sntp.h" #include "esp_system.h" #include "esp_timer.h" #include "nvs_flash.h" @@ -8,21 +10,26 @@ #include "wifi.h" #include +#include + static const char *TAG = "app"; +static EventGroupHandle_t wifi_event_group; +#define WIFI_CONNECTED_BIT BIT0 /** - * @brief Initialize NVS (Non-Volatile Storage) flash storage, handling full or - * incompatible pages. - * - * This function checks the NVS flash storage to ensure that there is enough - * space and that the version of NVS is compatible. If the partition is full or - * incompatible, it will erase the NVS partition and attempt initialization - * again. - * - * @return esp_err_t - * - ESP_OK: Initialization successful. - * - Other error codes if initialization or erasure fails. - */ +* @brief Initialize NVS (Non-Volatile Storage) flash storage, handling full or +* incompatible pages. +* +* This function checks the NVS flash storage to ensure that there is enough +* space and that the version of NVS is compatible. If the partition +is full or +* incompatible, it will erase the NVS partition and attempt initialization +* again. +* +* @return esp_err_t +* - ESP_OK: Initialization successful. +* - Other error codes if initialization or erasure fails. +*/ static esp_err_t nvs_flash_init_check(void) { esp_err_t ret = nvs_flash_init(); @@ -31,13 +38,7 @@ static esp_err_t nvs_flash_init_check(void) ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_LOGW(TAG, "NVS partition is full or incompatible, erasing..."); - ret = nvs_flash_erase(); - - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to erase NVS partition (%s)", - esp_err_to_name(ret)); - return ret; - } + ESP_ERROR_CHECK(nvs_flash_erase()); ret = nvs_flash_init(); } @@ -64,69 +65,88 @@ static esp_err_t nvs_flash_init_check(void) * - ESP_OK: If initialization is successful. * - Other error codes if initialization fails. */ -static esp_err_t init_component(esp_err_t (*init_func)(void), - const char *component_name) +static void wifi_event_handler(void *arg, esp_event_base_t event_base, + int32_t event_id, void *event_data) { - esp_err_t ret = init_func(); - - if (ret != ESP_OK) { - ESP_LOGE(TAG, "Failed to initialize %s (%s)", component_name, - esp_err_to_name(ret)); - return ret; + if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { + esp_wifi_connect(); + } else if (event_base == WIFI_EVENT && + event_id == WIFI_EVENT_STA_DISCONNECTED) { + ESP_LOGW(TAG, "Wi-Fi disconnected, reconnecting..."); + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, WIFI_CONNECTED_BIT); + } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { + ESP_LOGI(TAG, "Wi-Fi connected and got IP!"); + xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_BIT); } - - return ESP_OK; } /** - * @brief Initializes all the essential components for the application. - * - * This function initializes the NVS storage, network interface, and event loop - * in sequence. If any of these components fail to initialize, the function - * returns an error, and the application will stop early. - * - * @return esp_err_t - * - ESP_OK: If all components are successfully initialized. - * - ESP_FAIL: If any component fails to initialize. + * @TODO missing doc */ -esp_err_t init_app_components(void) +static void obtain_time(void) { - if (init_component(nvs_flash_init_check, "NVS") != ESP_OK) { - ESP_LOGE(TAG, "NVS initialization failed, aborting app start."); - return ESP_FAIL; + ESP_LOGI(TAG, "Starting SNTP time sync..."); + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, "pool.ntp.org"); + sntp_init(); + + time_t now = 0; + struct tm timeinfo = {0}; + int retry = 0; + const int retry_count = 10; + + while (timeinfo.tm_year < (2022 - 1900) && ++retry < retry_count) { + ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", + retry, retry_count); + vTaskDelay(pdMS_TO_TICKS(1000)); + time(&now); + localtime_r(&now, &timeinfo); } - if (init_component(esp_netif_init, "network interface") != ESP_OK) - return ESP_FAIL; - - if (init_component(esp_event_loop_create_default, "event loop") != - ESP_OK) - return ESP_FAIL; - - return ESP_OK; + if (timeinfo.tm_year >= (2022 - 1900)) { + char buf[64]; + strftime(buf, sizeof(buf), "%c", &timeinfo); + ESP_LOGI(TAG, "System time synchronized: %s", buf); + } else { + ESP_LOGW(TAG, "Failed to synchronize time."); + } } /** - * @brief Main entry point of the application. - * - * This function is responsible for initializing the core components of the - * application, including the NVS storage, network interface, and event loop. If - * any initialization step fails, the application will log the error and stop. - * - * After initialization, this function will configure the WiFi station and start - * the MQTT client. - */ - +* @brief Main entry point of the application. +* +* This function is responsible for initializing the core components +of the +* application, including the NVS storage, network interface, and event loop. If +* any initialization step fails, the application will log the error +and stop. +* +* After initialization, this function will configure the WiFi station and start +* the MQTT client. +*/ void app_main(void) { - if (init_app_components() != ESP_OK) { - ESP_LOGE(TAG, "App initialization failed, aborting."); - return; - } + ESP_ERROR_CHECK(nvs_flash_init_check()); + ESP_ERROR_CHECK(esp_netif_init()); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + wifi_event_group = xEventGroupCreate(); - ESP_LOGI(TAG, "Initializing WiFi in station mode"); + ESP_LOGI(TAG, "Initializing WiFi (station mode)"); wifi_init_sta(); - ESP_LOGI(TAG, "Starting MQTT client"); + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, + &wifi_event_handler, NULL)); + ESP_ERROR_CHECK(esp_event_handler_register( + IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL)); + + ESP_LOGI(TAG, "Waiting for Wi-Fi connection..."); + xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_BIT, pdFALSE, + pdFALSE, portMAX_DELAY); + + obtain_time(); + + ESP_LOGI(TAG, "Starting MQTT client..."); mqtt_app_start(); } diff --git a/firmware/src/mqtt.c b/firmware/src/mqtt.c index b3553eb..a726534 100644 --- a/firmware/src/mqtt.c +++ b/firmware/src/mqtt.c @@ -11,7 +11,6 @@ static const char *TAG = "mqtt"; static esp_mqtt_client_handle_t client; -// Zliczniki i pomiary static long long last_sent = 0; static long long last_rtt = 0; static long long last_rtt_prev = 0; @@ -20,7 +19,6 @@ static int received_count = 0; static unsigned long tx_bytes = 0; static unsigned long rx_bytes = 0; -// Kanały pomiarów #define TOPIC_RTT "device/metrics/rtt" #define TOPIC_JITTER "device/metrics/jitter" #define TOPIC_LOSS "device/metrics/loss" @@ -29,6 +27,9 @@ static unsigned long rx_bytes = 0; #define TOPIC_NET_TX "device/metrics/net_tx" #define TOPIC_NET_RX "device/metrics/net_rx" +#define TOPIC_IN "device/echo/in" +#define TOPIC_OUT "device/echo/out" + static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { @@ -37,13 +38,12 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, switch (event->event_id) { case MQTT_EVENT_CONNECTED: ESP_LOGI(TAG, "MQTT connected!"); - esp_mqtt_client_subscribe(event->client, PUB_TOPIC, 1); + esp_mqtt_client_subscribe(event->client, TOPIC_IN, 1); break; case MQTT_EVENT_DATA: { char topic[event->topic_len + 1]; char data[event->data_len + 1]; - memcpy(topic, event->topic, event->topic_len); topic[event->topic_len] = '\0'; memcpy(data, event->data, event->data_len); @@ -61,8 +61,9 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, last_rtt_prev = last_rtt; last_rtt = rtt; received_count++; + esp_mqtt_client_publish( - event->client, SUB_TOPIC, data, 0, 1, 0); + event->client, TOPIC_OUT, data, 0, 1, 0); tx_bytes += strlen(data); } } @@ -91,7 +92,7 @@ static void mqtt_test_task(void *pvParameters) last_sent = esp_timer_get_time() / 1000ULL; char msg[32]; snprintf(msg, sizeof(msg), "%lld", last_sent); - esp_mqtt_client_publish(client, PUB_TOPIC, msg, 0, 1, 0); + esp_mqtt_client_publish(client, TOPIC_IN, msg, 0, 1, 0); tx_bytes += strlen(msg); sent_count++; vTaskDelay(pdMS_TO_TICKS(delay_ms)); @@ -106,7 +107,6 @@ static void mqtt_metrics_task(void *pvParameters) long long dt = (now - last_time) / 1000ULL; last_time = now; - // RTT if (last_rtt > 0) { char buf[32]; snprintf(buf, sizeof(buf), "%lld", last_rtt); @@ -115,7 +115,6 @@ static void mqtt_metrics_task(void *pvParameters) tx_bytes += strlen(buf); } - // Jitter if (last_rtt_prev > 0) { long long jitter = llabs(last_rtt - last_rtt_prev); char buf[32]; @@ -125,23 +124,21 @@ static void mqtt_metrics_task(void *pvParameters) tx_bytes += strlen(buf); } - // Packet loss - int loss = sent_count > 0 ? (sent_count - received_count) * - 100 / sent_count - : 0; + int loss = + (sent_count > 0) + ? ((sent_count - received_count) * 100 / sent_count) + : 0; char buf_loss[16]; snprintf(buf_loss, sizeof(buf_loss), "%d", loss); esp_mqtt_client_publish(client, TOPIC_LOSS, buf_loss, 0, 1, 0); tx_bytes += strlen(buf_loss); - // Throughput char buf_thr[16]; snprintf(buf_thr, sizeof(buf_thr), "%d", received_count); esp_mqtt_client_publish(client, TOPIC_THROUGHPUT, buf_thr, 0, 1, 0); tx_bytes += strlen(buf_thr); - // CPU usage UBaseType_t free_heap = xPortGetFreeHeapSize(); UBaseType_t min_free_heap = xPortGetMinimumEverFreeHeapSize(); int cpu_load = @@ -156,16 +153,15 @@ static void mqtt_metrics_task(void *pvParameters) esp_mqtt_client_publish(client, TOPIC_CPU, buf_cpu, 0, 1, 0); tx_bytes += strlen(buf_cpu); - // Network TX/RX bytes char buf_tx[32], buf_rx[32]; snprintf(buf_tx, sizeof(buf_tx), "%lu", tx_bytes); snprintf(buf_rx, sizeof(buf_rx), "%lu", rx_bytes); esp_mqtt_client_publish(client, TOPIC_NET_TX, buf_tx, 0, 1, 0); esp_mqtt_client_publish(client, TOPIC_NET_RX, buf_rx, 0, 1, 0); - // Reset liczniki na kolejny interwał tx_bytes = 0; rx_bytes = 0; + sent_count = 0; received_count = 0; vTaskDelay(pdMS_TO_TICKS(1000)); diff --git a/firmware/src/wifi_scan.c b/firmware/src/wifi_scan.c index 02bb451..07f3dc7 100644 --- a/firmware/src/wifi_scan.c +++ b/firmware/src/wifi_scan.c @@ -12,12 +12,19 @@ #define WIFI_SCAN_TASK_NAME "wifi_scan_task" /** - * @brief Task to perform WiFi scanning asynchronously. + * @brief Asynchronous WiFi scanning task for ESP32 with FreeRTOS. * - * Starts a WiFi scan, polls for scan completion, - * retrieves and logs the found access points, then deletes itself. + * Configures and initiates a non-blocking WiFi scan on the specified or all + * channels, including hidden networks if enabled. Periodically polls for scan + * completion without blocking other tasks, retrieves discovered access points + * up to a defined maximum, and logs each AP's SSID and signal strength (RSSI). * - * @param pvParameter Task parameter (unused). + * After logging, the task self-deletes to free system resources. + * + * This design ensures WiFi scanning runs in the background, preserving system + * responsiveness and maintaining real-time operation in embedded applications. + * + * @param pvParameter Pointer to task parameters (unused). */ static void wifi_scan_task(void *pvParameter) { @@ -36,13 +43,15 @@ static void wifi_scan_task(void *pvParameter) while (true) { uint16_t finished_ap_count = 0; ESP_ERROR_CHECK(esp_wifi_scan_get_ap_num(&finished_ap_count)); - if (finished_ap_count > 0) + if (finished_ap_count > 0) { break; + } vTaskDelay(pdMS_TO_TICKS(WIFI_SCAN_POLL_INTERVAL_MS)); } ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_count, ap_info)); ESP_LOGI("wifi_scan", "Found %d access points:", ap_count); + for (uint16_t ap_index = 0; ap_index < ap_count; ++ap_index) { ESP_LOGI("wifi_scan", "%d: SSID: %s, RSSI: %d", ap_index + 1, ap_info[ap_index].ssid, ap_info[ap_index].rssi); -- cgit v1.2.3