From 03ca64080c84fcc7f9cdaa9aec33bcd02461c4cb Mon Sep 17 00:00:00 2001 From: pulipakaa24 Date: Thu, 8 Jan 2026 18:14:36 -0600 Subject: [PATCH] revert to non-task-driven, no tangible difference in performance. May change back later. --- include/BLE.cpp | 137 +++++++++++++++++++++++++++++--- include/BLE.hpp | 2 +- include/WiFi.cpp | 12 +-- include/WiFi.hpp | 6 +- include/calibration.cpp | 5 -- include/calibration.hpp | 22 +++--- include/defines.h | 27 ------- include/encoder.cpp | 35 ++++----- include/encoder.hpp | 6 -- include/servo.cpp | 102 +++--------------------- include/servo.hpp | 17 ---- include/setup.cpp | 170 +++++----------------------------------- include/socketIO.cpp | 22 +++--- include/socketIO.hpp | 1 + src/main.cpp | 111 ++++++++++---------------- 15 files changed, 240 insertions(+), 435 deletions(-) diff --git a/include/BLE.cpp b/include/BLE.cpp index ca24e63..713cf0e 100644 --- a/include/BLE.cpp +++ b/include/BLE.cpp @@ -7,16 +7,19 @@ #include #include "bmHTTP.hpp" +std::atomic flag_scan_requested{false}; +std::atomic credsGiven{false}; +std::atomic tokenGiven{false}; std::atomic isBLEClientConnected{false}; std::atomic scanBlock{false}; std::atomic finalAuth{false}; std::mutex dataMutex; wifi_auth_mode_t auth; -std::string SSID = ""; -std::string TOKEN = ""; -std::string PASS = ""; -std::string UNAME = ""; +static std::string SSID = ""; +static std::string TOKEN = ""; +static std::string PASS = ""; +static std::string UNAME = ""; // Global pointers to characteristics for notification support std::atomic ssidListChar = nullptr; @@ -118,12 +121,125 @@ void notifyAuthStatus(bool success) { tmpConfChar->setValue(""); // Clear value after notify } -// BLEtick() removed - replaced by bleSetupTask() in setup.cpp +bool BLEtick(NimBLEAdvertising* pAdvertising) { + printf("BleTick\n"); + if(flag_scan_requested) { + flag_scan_requested = false; + if (!scanBlock) { + scanBlock = true; + printf("Scanning WiFi...\n"); + bmWiFi.scanAndUpdateSSIDList(); + } + else printf("Duplicate scan request\n"); + } + else if (credsGiven) { + std::string tmpSSID; + std::string tmpUNAME; + std::string tmpPASS; + wifi_auth_mode_t tmpAUTH; + { + std::lock_guard lock(dataMutex); + tmpSSID = SSID; + tmpUNAME = UNAME; + tmpPASS = PASS; + tmpAUTH = auth; + credsGiven = false; + } + + bool wifiConnect; + if (tmpAUTH == WIFI_AUTH_WPA2_ENTERPRISE || tmpAUTH == WIFI_AUTH_WPA3_ENTERPRISE) + wifiConnect = bmWiFi.attemptConnect(tmpSSID.c_str(), tmpUNAME.c_str(), tmpPASS.c_str(), tmpAUTH); + else wifiConnect = bmWiFi.attemptConnect(tmpSSID.c_str(), tmpPASS.c_str(), tmpAUTH); + if (!wifiConnect) { + // notify errored + notifyConnectionStatus(false); + return false; + } + + nvs_handle_t WiFiHandle; + esp_err_t err = nvs_open(nvsWiFi, NVS_READWRITE, &WiFiHandle); + if (err != ESP_OK) { + printf("ERROR Saving Credentials\n"); + // notify errored + notifyConnectionStatus(false); + return false; + } + else { + err = nvs_set_str(WiFiHandle, ssidTag, tmpSSID.c_str()); + if (err == ESP_OK) err = nvs_set_str(WiFiHandle, passTag, tmpPASS.c_str()); + if (err == ESP_OK) err = nvs_set_str(WiFiHandle, unameTag, tmpUNAME.c_str()); + if (err == ESP_OK) err = nvs_set_u8(WiFiHandle, authTag, (uint8_t)tmpAUTH); + if (err == ESP_OK) nvs_commit(WiFiHandle); + nvs_close(WiFiHandle); + } + if (err == ESP_OK) { + // notify connected + notifyConnectionStatus(true); + } + else { + // notify connected + notifyConnectionStatus(false); + } + } + else if (tokenGiven) { + tokenGiven = false; + if (!bmWiFi.isConnected()) { + printf("ERROR: token given without WiFi connection\n"); + notifyAuthStatus(false); + return false; + } + + // HTTP request to verify device with token + std::string tmpTOKEN; + { + std::lock_guard lock(dataMutex); + tmpTOKEN = TOKEN; + } + + cJSON *responseRoot; + bool success = httpGET("verify_device", tmpTOKEN, responseRoot); + if (!success) return false; + success = false; + + if (responseRoot != NULL) { + cJSON *tokenItem = cJSON_GetObjectItem(responseRoot, "token"); + if (cJSON_IsString(tokenItem) && tokenItem->valuestring != NULL) { + printf("New token received: %s\n", tokenItem->valuestring); + + // Save token to NVS + nvs_handle_t AuthHandle; + esp_err_t nvs_err = nvs_open(nvsAuth, NVS_READWRITE, &AuthHandle); + if (nvs_err == ESP_OK) { + nvs_err = nvs_set_str(AuthHandle, tokenTag, tokenItem->valuestring); + if (nvs_err == ESP_OK) { + nvs_commit(AuthHandle); + success = true; + webToken = tokenItem->valuestring; + } + else printf("ERROR: could not save webToken to NVS\n"); + nvs_close(AuthHandle); + } + else printf("ERROR: Couldn't open NVS for auth token\n"); + } + cJSON_Delete(responseRoot); + } + else printf("Failed to parse JSON response\n"); + + finalAuth = true; + notifyAuthStatus(success); + if (success) NimBLEDevice::deinit(true); // deinitialize BLE + return success; + } + return false; +} void reset() { esp_wifi_scan_stop(); if (!finalAuth) esp_wifi_disconnect(); scanBlock = false; + flag_scan_requested = false; + credsGiven = false; + tokenGiven = false; } void MyServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) { @@ -179,6 +295,7 @@ void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connI else error = true; if (error) { printf("ERROR: Invalid Auth mode passed in with JSON.\n"); + credsGiven = false; cJSON_Delete(root); return; } @@ -197,13 +314,13 @@ void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connI SSID = ssid->valuestring; PASS = passPresent ? password->valuestring : ""; UNAME = unamePresent ? uname->valuestring : ""; - // Signal via event group instead of flag - xEventGroupSetBits(g_system_events, EVENT_BLE_CREDS_RECEIVED); + credsGiven = tempCredsGiven; // update the global flag. } else printf("ERROR: Did not receive necessary credentials.\n"); cJSON_Delete(root); } else { printf("Failed to parse JSON\n"); + credsGiven = false; } } } @@ -212,16 +329,14 @@ void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connI printf("Received Token: %s\n", val.c_str()); std::lock_guard lock(dataMutex); TOKEN = val; - // Signal via event group instead of flag - xEventGroupSetBits(g_system_events, EVENT_BLE_TOKEN_RECEIVED); + tokenGiven = true; } } else if (pChar == currentRefreshChar) { if (val == "Start") { // Refresh characteristic printf("Refresh Requested\n"); - // Signal via event group instead of flag - xEventGroupSetBits(g_system_events, EVENT_BLE_SCAN_REQUEST); + flag_scan_requested = true; } else if (val == "Done") { printf("Data read complete\n"); diff --git a/include/BLE.hpp b/include/BLE.hpp index 116d96f..8a3d34f 100644 --- a/include/BLE.hpp +++ b/include/BLE.hpp @@ -23,6 +23,6 @@ class MyCharCallbacks : public NimBLECharacteristicCallbacks { }; NimBLEAdvertising* initBLE(); -// BLEtick removed - now using event-driven bleSetupTask +bool BLEtick(NimBLEAdvertising* pAdvertising); #endif \ No newline at end of file diff --git a/include/WiFi.cpp b/include/WiFi.cpp index 3d55bbe..80ca08c 100644 --- a/include/WiFi.cpp +++ b/include/WiFi.cpp @@ -12,6 +12,8 @@ esp_event_handler_instance_t WiFi::instance_got_ip = NULL; #define WIFI_CONNECTED_BIT BIT0 #define WIFI_STARTED_BIT BIT1 +WiFi bmWiFi; + // The Event Handler (The engine room) void WiFi::event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { @@ -117,16 +119,6 @@ bool WiFi::isConnected() { return (bits & WIFI_CONNECTED_BIT); } -// Helper to check if auth mode requires enterprise credentials -bool WiFi::isEnterpriseMode(wifi_auth_mode_t authMode) { - return (authMode == WIFI_AUTH_WPA2_ENTERPRISE || - authMode == WIFI_AUTH_WPA3_ENTERPRISE || - authMode == WIFI_AUTH_WPA2_WPA3_ENTERPRISE || - authMode == WIFI_AUTH_WPA_ENTERPRISE || - authMode == WIFI_AUTH_WPA3_ENT_192 || - authMode == WIFI_AUTH_ENTERPRISE); // Deprecated alias for WPA2 -} - // --- GET IP AS STRING --- std::string WiFi::getIP() { esp_netif_ip_info_t ip_info; diff --git a/include/WiFi.hpp b/include/WiFi.hpp index fb58bff..77bde73 100644 --- a/include/WiFi.hpp +++ b/include/WiFi.hpp @@ -14,10 +14,6 @@ class WiFi { const std::string password, const wifi_auth_mode_t authMode); static bool isConnected(); static void scanAndUpdateSSIDList(); - - // Helper to check if auth mode requires enterprise credentials - static bool isEnterpriseMode(wifi_auth_mode_t authMode); - private: static void processScanResults(); static std::atomic authFailed; @@ -31,4 +27,6 @@ class WiFi { static std::string getIP(); }; +extern WiFi bmWiFi; + #endif \ No newline at end of file diff --git a/include/calibration.cpp b/include/calibration.cpp index 6a27d5d..e472015 100644 --- a/include/calibration.cpp +++ b/include/calibration.cpp @@ -2,11 +2,6 @@ #include "defines.h" #include "nvs_flash.h" -// Define static members -std::atomic Calibration::DownTicks{0}; -std::atomic Calibration::UpTicks{0}; -std::atomic Calibration::calibrated{false}; - void Calibration::init() { nvs_handle_t calibHandle; if (nvs_open(nvsCalib, NVS_READONLY, &calibHandle) == ESP_OK) { diff --git a/include/calibration.hpp b/include/calibration.hpp index ff3b0dc..e862e7e 100644 --- a/include/calibration.hpp +++ b/include/calibration.hpp @@ -5,18 +5,20 @@ class Calibration { public: - static void init(); - static bool beginDownwardCalib(Encoder& topEnc); - static bool completeCalib(Encoder& topEnc); - static int32_t convertToTicks(uint8_t appPos); - static uint8_t convertToAppPos(int32_t ticks); - static bool getCalibrated() {return calibrated;} - static bool clearCalibrated(); - static std::atomic DownTicks; - static std::atomic UpTicks; + void init(); + bool beginDownwardCalib(Encoder& topEnc); + bool completeCalib(Encoder& topEnc); + int32_t convertToTicks(uint8_t appPos); + uint8_t convertToAppPos(int32_t ticks); + bool getCalibrated() {return calibrated;} + bool clearCalibrated(); + std::atomic DownTicks; + std::atomic UpTicks; private: - static std::atomic calibrated; + std::atomic calibrated; }; +extern Calibration calib; + #endif \ No newline at end of file diff --git a/include/defines.h b/include/defines.h index ee4915c..8f482e7 100644 --- a/include/defines.h +++ b/include/defines.h @@ -2,33 +2,6 @@ #define DEFINES_H #include "driver/gpio.h" #include "driver/ledc.h" -#include "freertos/FreeRTOS.h" -#include "freertos/event_groups.h" -#include "freertos/queue.h" -#include "freertos/semphr.h" - -// Task priorities -#define SERVO_TASK_PRIORITY (tskIDLE_PRIORITY + 4) // Highest - real-time control -#define ENCODER_TASK_PRIORITY (tskIDLE_PRIORITY + 3) // High - encoder processing -#define SOCKETIO_TASK_PRIORITY (tskIDLE_PRIORITY + 2) // Medium -#define BLE_TASK_PRIORITY (tskIDLE_PRIORITY + 1) // Low -#define MAIN_TASK_PRIORITY (tskIDLE_PRIORITY + 1) // Low - -// Event bits for system events -#define EVENT_WIFI_CONNECTED BIT0 -#define EVENT_SOCKETIO_CONNECTED BIT1 -#define EVENT_SOCKETIO_DISCONNECTED BIT2 -#define EVENT_CLEAR_CALIB BIT3 -#define EVENT_SAVE_POSITION BIT4 -#define EVENT_BLE_SCAN_REQUEST BIT5 -#define EVENT_BLE_CREDS_RECEIVED BIT6 -#define EVENT_BLE_TOKEN_RECEIVED BIT7 - -// Global synchronization primitives -extern EventGroupHandle_t g_system_events; -extern QueueHandle_t g_servo_command_queue; -extern QueueHandle_t g_encoder_event_queue; -extern SemaphoreHandle_t g_calibration_mutex; #define ccwSpeed 6500 #define cwSpeed 3300 diff --git a/include/encoder.cpp b/include/encoder.cpp index 42773f9..b6df7ec 100644 --- a/include/encoder.cpp +++ b/include/encoder.cpp @@ -3,7 +3,6 @@ #include "esp_log.h" #include "soc/gpio_struct.h" #include "servo.hpp" -#include "defines.h" static const char *TAG = "ENCODER"; @@ -49,32 +48,26 @@ void IRAM_ATTR Encoder::isr_handler(void* arg) if (encoder->last_count_base > 3) { encoder->count += 1; encoder->last_count_base -= 4; - - // DEFER to task via queue instead of direct function calls - encoder_event_t event = { - .count = encoder->count.load(), - .is_top_encoder = (encoder == topEnc) - }; - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - if (g_encoder_event_queue != NULL) { - xQueueSendFromISR(g_encoder_event_queue, &event, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + if (calibListen) servoCalibListen(); + if (encoder->feedWDog) { + esp_timer_stop(encoder->watchdog_handle); + esp_timer_start_once(encoder->watchdog_handle, 500000); + debugLEDTgl(); } + if (encoder->wandListen) servoWandListen(); + if (encoder->serverListen) servoServerListen(); } else if (encoder->last_count_base < 0) { encoder->count -= 1; encoder->last_count_base += 4; - - // DEFER to task via queue instead of direct function calls - encoder_event_t event = { - .count = encoder->count.load(), - .is_top_encoder = (encoder == topEnc) - }; - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - if (g_encoder_event_queue != NULL) { - xQueueSendFromISR(g_encoder_event_queue, &event, &xHigherPriorityTaskWoken); - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); + if (calibListen) servoCalibListen(); + if (encoder->feedWDog) { + esp_timer_stop(encoder->watchdog_handle); + esp_timer_start_once(encoder->watchdog_handle, 500000); + debugLEDTgl(); } + if (encoder->wandListen) servoWandListen(); + if (encoder->serverListen) servoServerListen(); } encoder->last_state_a = current_a; diff --git a/include/encoder.hpp b/include/encoder.hpp index d1e7d2a..a4015b2 100644 --- a/include/encoder.hpp +++ b/include/encoder.hpp @@ -4,12 +4,6 @@ #include #include "esp_timer.h" -// Encoder event structure for queue -typedef struct { - int32_t count; - bool is_top_encoder; -} encoder_event_t; - class Encoder { public: // Shared between ISR and main code diff --git a/include/servo.cpp b/include/servo.cpp index 500b0da..1ff88d4 100644 --- a/include/servo.cpp +++ b/include/servo.cpp @@ -47,7 +47,7 @@ void servoInit() { gpio_set_level(debugLED, 0); // Start with LED off topEnc->count = servoReadPos(); - if (Calibration::getCalibrated()) initMainLoop(); + if (calib.getCalibrated()) initMainLoop(); debugLEDSwitch(1); } @@ -87,7 +87,7 @@ bool servoInitCalib() { bottomEnc->wandListen.store(false, std::memory_order_release); topEnc->wandListen.store(false, std::memory_order_release); topEnc->serverListen.store(false, std::memory_order_release); - if (!Calibration::clearCalibrated()) return false; + if (!calib.clearCalibrated()) return false; if (topEnc == nullptr || bottomEnc == nullptr) { printf("ERROR: CALIBRATION STARTED BEFORE SERVO INITIALIZATION\n"); return false; @@ -117,7 +117,7 @@ bool servoBeginDownwardCalib() { calibListen = false; servoOff(); vTaskDelay(pdMS_TO_TICKS(1000)); - if (!Calibration::beginDownwardCalib(*topEnc)) return false; + if (!calib.beginDownwardCalib(*topEnc)) return false; baseDiff = bottomEnc->getCount() - topEnc->getCount(); calibListen = true; return true; @@ -127,7 +127,7 @@ bool servoCompleteCalib() { calibListen = false; servoOff(); vTaskDelay(pdMS_TO_TICKS(1000)); - if (!Calibration::completeCalib(*topEnc)) return false; + if (!calib.completeCalib(*topEnc)) return false; initMainLoop(); return true; } @@ -139,11 +139,9 @@ void initMainLoop() { } void IRAM_ATTR watchdogCallback(void* arg) { - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - if (runningManual || runningServer) { // if we're trying to move and our timer ran out, we need to recalibrate - xEventGroupSetBitsFromISR(g_system_events, EVENT_CLEAR_CALIB, &xHigherPriorityTaskWoken); + clearCalibFlag = true; topEnc->pauseWatchdog(); // get ready for recalibration by clearing all these listeners @@ -155,13 +153,11 @@ void IRAM_ATTR watchdogCallback(void* arg) { else { // if no movement is running, we're fine // save current servo-encoder position for reinitialization - xEventGroupSetBitsFromISR(g_system_events, EVENT_SAVE_POSITION, &xHigherPriorityTaskWoken); + savePosFlag = true; } // clear running flags runningManual = false; runningServer = false; - - portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } void servoSavePos() { @@ -207,8 +203,8 @@ void servoWandListen() { stopServerRun(); // freeze atomic values - int32_t upBound = Calibration::UpTicks; - int32_t downBound = Calibration::DownTicks; + int32_t upBound = calib.UpTicks; + int32_t downBound = calib.DownTicks; int32_t bottomCount = bottomEnc->getCount(); int32_t topCount = topEnc->getCount(); @@ -261,10 +257,10 @@ void servoServerListen() { void runToAppPos(uint8_t appPos) { // manual control takes precedence over remote control, always. // also do not begin operation if not calibrated; - if (runningManual || !Calibration::getCalibrated()) return; + if (runningManual || !calib.getCalibrated()) return; servoOff(); - target = Calibration::convertToTicks(appPos); // calculate target encoder position + target = calib.convertToTicks(appPos); // calculate target encoder position printf("runToAppPos Called, running to %d from %d", target.load(), topEnc->getCount()); // allow servo position to settle @@ -276,82 +272,4 @@ void runToAppPos(uint8_t appPos) { if (startLess) servoOn(CCW, server); // begin servo movement else servoOn(CW, server); topEnc->serverListen.store(true, std::memory_order_release); // start listening for shutoff point -} - -// Servo control task - processes encoder events and servo commands -void servoControlTask(void* arg) { - encoder_event_t enc_event; - servo_cmd_msg_t cmd; - - printf("Servo control task started\n"); - - while (1) { - // Block waiting for encoder events (higher priority) - if (xQueueReceive(g_encoder_event_queue, &enc_event, pdMS_TO_TICKS(10)) == pdTRUE) { - // Process encoder event (work that was done in ISR before) - - // Handle calibration listening - if (calibListen) { - servoCalibListen(); - } - - // Only process top encoder events for watchdog and listeners - if (enc_event.is_top_encoder) { - // Feed watchdog in task context (not ISR) - if (topEnc->feedWDog) { - esp_timer_stop(topEnc->watchdog_handle); - esp_timer_start_once(topEnc->watchdog_handle, 500000); - debugLEDTgl(); - } - - // Check wand listener - now safe in task context - if (topEnc->wandListen) { - servoWandListen(); - } - - // Check server listener - now safe in task context - if (topEnc->serverListen) { - servoServerListen(); - } - } - - // Only process top encoder events for watchdog and listeners - else { - // Feed watchdog in task context (not ISR) - if (bottomEnc->feedWDog) { - esp_timer_stop(bottomEnc->watchdog_handle); - esp_timer_start_once(bottomEnc->watchdog_handle, 500000); - debugLEDTgl(); - } - - // Check wand listener - now safe in task context - if (bottomEnc->wandListen) { - servoWandListen(); - } - - // Check server listener - now safe in task context - if (bottomEnc->serverListen) { - servoServerListen(); - } - } - } - - // Check for direct servo commands (lower priority) - if (xQueueReceive(g_servo_command_queue, &cmd, 0) == pdTRUE) { - switch (cmd.command) { - case SERVO_CMD_STOP: - servoOff(); - break; - case SERVO_CMD_MOVE_CCW: - servoOn(CCW, cmd.is_manual ? manual : server); - break; - case SERVO_CMD_MOVE_CW: - servoOn(CW, cmd.is_manual ? manual : server); - break; - case SERVO_CMD_MOVE_TO_POSITION: - runToAppPos(cmd.target_position); - break; - } - } - } } \ No newline at end of file diff --git a/include/servo.hpp b/include/servo.hpp index b84b6d7..54b81b2 100644 --- a/include/servo.hpp +++ b/include/servo.hpp @@ -9,20 +9,6 @@ #define server 1 #define manual 0 -// Command structures for servo control -typedef enum { - SERVO_CMD_STOP, - SERVO_CMD_MOVE_CCW, - SERVO_CMD_MOVE_CW, - SERVO_CMD_MOVE_TO_POSITION -} servo_command_t; - -typedef struct { - servo_command_t command; - uint8_t target_position; // For MOVE_TO_POSITION - bool is_manual; // vs server-initiated -} servo_cmd_msg_t; - extern std::atomic calibListen; extern std::atomic clearCalibFlag; extern std::atomic savePosFlag; @@ -52,7 +38,4 @@ void servoWandListen(); void servoServerListen(); void runToAppPos(uint8_t appPos); -// Servo control task -void servoControlTask(void* arg); - #endif \ No newline at end of file diff --git a/include/setup.cpp b/include/setup.cpp index 4792d2e..74dba76 100644 --- a/include/setup.cpp +++ b/include/setup.cpp @@ -5,147 +5,14 @@ #include "defines.h" #include "bmHTTP.hpp" #include "socketIO.hpp" -#include - -// External declarations from BLE.cpp -extern std::mutex dataMutex; -extern wifi_auth_mode_t auth; -extern std::string SSID; -extern std::string PASS; -extern std::string UNAME; -extern std::string TOKEN; -extern std::atomic scanBlock; -extern std::atomic finalAuth; - -// External functions from BLE.cpp -extern void notifyConnectionStatus(bool success); -extern void notifyAuthStatus(bool success); - -// BLE setup task - event-driven instead of polling -void bleSetupTask(void* arg) { - NimBLEAdvertising* pAdvertising = initBLE(); - EventBits_t bits; - - printf("BLE setup task started\n"); - - while (1) { - // Wait for BLE events instead of polling - bits = xEventGroupWaitBits( - g_system_events, - EVENT_BLE_SCAN_REQUEST | EVENT_BLE_CREDS_RECEIVED | EVENT_BLE_TOKEN_RECEIVED, - pdTRUE, // Clear bits on exit - pdFALSE, // Wait for ANY bit (not all) - portMAX_DELAY // Block forever until event - ); - - if (bits & EVENT_BLE_SCAN_REQUEST) { - if (!scanBlock) { - scanBlock = true; - printf("Scanning WiFi...\n"); - WiFi::scanAndUpdateSSIDList(); - } - else printf("Duplicate scan request\n"); - } - - if (bits & EVENT_BLE_CREDS_RECEIVED) { - std::string tmpSSID; - std::string tmpUNAME; - std::string tmpPASS; - wifi_auth_mode_t tmpAUTH; - { - std::lock_guard lock(dataMutex); - tmpSSID = SSID; - tmpUNAME = UNAME; - tmpPASS = PASS; - tmpAUTH = auth; - } - - bool wifiConnect; - if (WiFi::isEnterpriseMode(tmpAUTH)) - wifiConnect = WiFi::attemptConnect(tmpSSID, tmpUNAME, tmpPASS, tmpAUTH); - else wifiConnect = WiFi::attemptConnect(tmpSSID, tmpPASS, tmpAUTH); - - if (!wifiConnect) { - notifyConnectionStatus(false); - printf("Connection failed\n"); - continue; - } - - nvs_handle_t WiFiHandle; - esp_err_t err = nvs_open(nvsWiFi, NVS_READWRITE, &WiFiHandle); - if (err == ESP_OK) { - esp_err_t saveErr = ESP_OK; - saveErr |= nvs_set_str(WiFiHandle, ssidTag, tmpSSID.c_str()); - saveErr |= nvs_set_u8(WiFiHandle, authTag, (uint8_t)tmpAUTH); - - if (tmpUNAME.length() > 0) - saveErr |= nvs_set_str(WiFiHandle, unameTag, tmpUNAME.c_str()); - if (tmpPASS.length() > 0) - saveErr |= nvs_set_str(WiFiHandle, passTag, tmpPASS.c_str()); - - if (saveErr == ESP_OK) { - nvs_commit(WiFiHandle); - printf("WiFi credentials saved to NVS\n"); - notifyConnectionStatus(true); - } else { - printf("Failed to save WiFi credentials\n"); - notifyConnectionStatus(false); - } - nvs_close(WiFiHandle); - } - } - - if (bits & EVENT_BLE_TOKEN_RECEIVED) { - std::string tmpTOKEN; - { - std::lock_guard lock(dataMutex); - tmpTOKEN = TOKEN; - } - - cJSON* JSONresponse = NULL; - if (httpGET("api/devices/auth", tmpTOKEN, JSONresponse)) { - cJSON *success = cJSON_GetObjectItem(JSONresponse, "success"); - bool authSuccess = cJSON_IsTrue(success); - - if (authSuccess) { - nvs_handle_t authHandle; - if (nvs_open(nvsAuth, NVS_READWRITE, &authHandle) == ESP_OK) { - if (nvs_set_str(authHandle, tokenTag, tmpTOKEN.c_str()) == ESP_OK) { - nvs_commit(authHandle); - printf("Token saved to NVS\n"); - notifyAuthStatus(true); - finalAuth = true; - - // Task complete - delete itself - vTaskDelete(NULL); - } - nvs_close(authHandle); - } - } else { - printf("Token authentication failed\n"); - notifyAuthStatus(false); - } - cJSON_Delete(JSONresponse); - } else { - printf("HTTP request failed\n"); - notifyAuthStatus(false); - } - } - } -} void initialSetup() { printf("Entered Setup\n"); - - // Create BLE setup task instead of polling loop - xTaskCreate(bleSetupTask, "ble_setup", 8192, NULL, BLE_TASK_PRIORITY, NULL); - - // Wait for BLE setup to complete (finalAuth = true) - while (!finalAuth) { + NimBLEAdvertising* pAdv = initBLE(); + + while (!BLEtick(pAdv)) { vTaskDelay(pdMS_TO_TICKS(100)); } - - printf("BLE setup complete\n"); } void setupLoop() { @@ -170,7 +37,7 @@ void setupLoop() { char pw[pwSize]; nvs_get_str(WiFiHandle, passTag, pw, &pwSize); nvs_close(WiFiHandle); - if (!WiFi::attemptConnect(ssid, pw, (wifi_auth_mode_t)authMode)) { + if (!bmWiFi.attemptConnect(ssid, pw, (wifi_auth_mode_t)authMode)) { // Make RGB LED certain color (Blue?) printf("Found credentials, failed to connect.\n"); initialSetup(); @@ -189,28 +56,29 @@ void setupLoop() { // The server will verify the token during connection handshake webToken = std::string(token); printf("Connecting to Socket.IO server with saved token...\n"); + statusResolved = false; initSocketIO(); - // Wait for connection event with timeout - EventBits_t bits = xEventGroupWaitBits( - g_system_events, - EVENT_SOCKETIO_CONNECTED | EVENT_SOCKETIO_DISCONNECTED, - pdTRUE, // Clear on exit - pdFALSE, // Wait for ANY bit - pdMS_TO_TICKS(10000) // 10 second timeout - ); + // Wait for device_init message from server with timeout + int timeout_count = 0; + const int MAX_TIMEOUT = 60; // 10 seconds (20 * 500ms) + while (!statusResolved && timeout_count < MAX_TIMEOUT) { + printf("Waiting for device_init message... (%d/%d)\n", timeout_count, MAX_TIMEOUT); + vTaskDelay(pdMS_TO_TICKS(500)); + timeout_count++; + } - if (bits & EVENT_SOCKETIO_CONNECTED) { + if (timeout_count >= MAX_TIMEOUT) { + printf("Timeout waiting for device_init - connection failed\n"); + stopSocketIO(); + initSuccess = false; + initialSetup(); + } else { initSuccess = connected; if (!initSuccess) { printf("Device authentication failed - entering setup\n"); initialSetup(); } - } else { - printf("Timeout waiting for connection\n"); - stopSocketIO(); - initSuccess = false; - initialSetup(); } } else { diff --git a/include/socketIO.cpp b/include/socketIO.cpp index 81b2200..0bdb530 100644 --- a/include/socketIO.cpp +++ b/include/socketIO.cpp @@ -12,6 +12,7 @@ static esp_socketio_client_handle_t io_client; static esp_socketio_packet_handle_t tx_packet = NULL; +std::atomic statusResolved{true}; std::atomic connected{false}; // Event handler for Socket.IO events @@ -65,7 +66,7 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, // Mark connection as failed connected = false; - xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED); + statusResolved = true; } // Handle device_init event else if (strcmp(eventName->valuestring, "device_init") == 0) { @@ -92,7 +93,7 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, if (port != 1) printf("ERROR: NON-1 PORT RECEIVED\n"); // Report back actual calibration status from device else { - bool deviceCalibrated = Calibration::getCalibrated(); + bool deviceCalibrated = calib.getCalibrated(); emitCalibStatus(deviceCalibrated); printf(" Reported calibrated=%d for port %d\n", deviceCalibrated, port); runToAppPos(lastPos); @@ -102,13 +103,13 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, // Now mark as connected connected = true; - xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_CONNECTED); + statusResolved = true; } else { printf("Device authentication failed\n"); - Calibration::clearCalibrated(); + calib.clearCalibrated(); deleteWiFiAndTokenDetails(); connected = false; - xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED); + statusResolved = true; } } } @@ -122,10 +123,10 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, printf("Server message: %s\n", message->valuestring); } } - Calibration::clearCalibrated(); + calib.clearCalibrated(); deleteWiFiAndTokenDetails(); connected = false; - xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED); + statusResolved = true; } // Handle calib_start event @@ -292,9 +293,8 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, } } - // Signal disconnection via event group connected = false; - xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED); + statusResolved = true; break; } } @@ -303,7 +303,7 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, if (data->websocket_event_id == WEBSOCKET_EVENT_DISCONNECTED) { printf("WebSocket disconnected\n"); connected = false; - xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED); + statusResolved = true; } } @@ -312,6 +312,7 @@ void initSocketIO() { // Prepare the Authorization Header (Bearer format) std::string authHeader = "Authorization: Bearer " + webToken + "\r\n"; + statusResolved = false; connected = false; esp_socketio_client_config_t config = {}; @@ -338,6 +339,7 @@ void stopSocketIO() { io_client = NULL; tx_packet = NULL; connected = false; + statusResolved = false; } } diff --git a/include/socketIO.hpp b/include/socketIO.hpp index 4d3c7f2..9144a4c 100644 --- a/include/socketIO.hpp +++ b/include/socketIO.hpp @@ -2,6 +2,7 @@ #define SOCKETIO_HPP #include +extern std::atomic statusResolved; extern std::atomic connected; // Initialize Socket.IO client and connect to server diff --git a/src/main.cpp b/src/main.cpp index 4a17883..a1aafe4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,58 +9,67 @@ #include "encoder.hpp" #include "calibration.hpp" -// Global synchronization primitives -EventGroupHandle_t g_system_events = NULL; -QueueHandle_t g_servo_command_queue = NULL; -QueueHandle_t g_encoder_event_queue = NULL; -SemaphoreHandle_t g_calibration_mutex = NULL; - // Global encoder instances Encoder* topEnc = new Encoder(ENCODER_PIN_A, ENCODER_PIN_B); Encoder* bottomEnc = new Encoder(InputEnc_PIN_A, InputEnc_PIN_B); -void mainTask(void* arg) { - EventBits_t bits; +// Global encoder pointers (used by servo.cpp) + +// Global calibration instance +Calibration calib; + +void mainApp() { + esp_err_t ret = nvs_flash_init(); // change to secure init logic soon!! + // 2. If NVS is full or corrupt (common after flashing new code), erase and retry + if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { + ESP_ERROR_CHECK(nvs_flash_erase()); + ret = nvs_flash_init(); + } + ESP_ERROR_CHECK(ret); + + bmWiFi.init(); + calib.init(); - printf("Main task started - event-driven mode\n"); + // Initialize encoders + topEnc->init(); + bottomEnc->init(); + servoInit(); + + setupLoop(); + statusResolved = false; + + int32_t prevCount = topEnc->getCount(); + + // Main loop while (1) { - // Block waiting for ANY event (no polling!) - bits = xEventGroupWaitBits( - g_system_events, - EVENT_SOCKETIO_DISCONNECTED | EVENT_CLEAR_CALIB | EVENT_SAVE_POSITION, - pdTRUE, // Clear bits on exit - pdFALSE, // Wait for ANY bit (not all) - portMAX_DELAY // Block forever - no polling! - ); - - if (bits & EVENT_SOCKETIO_DISCONNECTED) { + // websocket disconnect/reconnect handling + if (statusResolved) { if (!connected) { printf("Disconnected! Beginning setup loop.\n"); stopSocketIO(); setupLoop(); } - else { - printf("Reconnected!\n"); - } + else printf("Reconnected!\n"); + statusResolved = false; } - - if (bits & EVENT_CLEAR_CALIB) { - xSemaphoreTake(g_calibration_mutex, portMAX_DELAY); - Calibration::clearCalibrated(); - xSemaphoreGive(g_calibration_mutex); + + if (clearCalibFlag) { + calib.clearCalibrated(); emitCalibStatus(false); + clearCalibFlag = false; } - - if (bits & EVENT_SAVE_POSITION) { + if (savePosFlag) { servoSavePos(); + savePosFlag = false; // Send position update to server - uint8_t currentAppPos = Calibration::convertToAppPos(topEnc->getCount()); + uint8_t currentAppPos = calib.convertToAppPos(topEnc->getCount()); emitPosHit(currentAppPos); printf("Sent pos_hit: position %d\n", currentAppPos); } + vTaskDelay(pdMS_TO_TICKS(100)); } } @@ -82,44 +91,6 @@ void encoderTest() { } extern "C" void app_main() { - // Initialize NVS first - esp_err_t ret = nvs_flash_init(); - if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { - ESP_ERROR_CHECK(nvs_flash_erase()); - ret = nvs_flash_init(); - } - ESP_ERROR_CHECK(ret); - - // Create synchronization primitives - g_system_events = xEventGroupCreate(); - g_servo_command_queue = xQueueCreate(10, sizeof(servo_cmd_msg_t)); - g_encoder_event_queue = xQueueCreate(50, sizeof(encoder_event_t)); - g_calibration_mutex = xSemaphoreCreateMutex(); - - if (g_system_events == NULL || g_servo_command_queue == NULL || - g_encoder_event_queue == NULL || g_calibration_mutex == NULL) { - printf("ERROR: Failed to create synchronization primitives\n"); - return; - } - - // Initialize hardware - WiFi::init(); - Calibration::init(); - - // Initialize encoders - topEnc->init(); - bottomEnc->init(); - servoInit(); - - // Create servo control task (highest priority - real-time) - xTaskCreate(servoControlTask, "servo_ctrl", 4096, NULL, SERVO_TASK_PRIORITY, NULL); - - // Create main task (lower priority) - xTaskCreate(mainTask, "main", 4096, NULL, MAIN_TASK_PRIORITY, NULL); - - // Run setup loop (this will handle WiFi/SocketIO connection) - setupLoop(); - - // app_main returns, but tasks continue running - printf("app_main complete - tasks running\n"); + mainApp(); + // encoderTest(); } \ No newline at end of file