From 3ccd1705f02a7dc4fc3537560c7feb4b3ff31772 Mon Sep 17 00:00:00 2001 From: pulipakaa24 Date: Wed, 7 Jan 2026 16:53:50 -0600 Subject: [PATCH] tls handling and bug fixes --- include/bmHTTP.cpp | 79 +++++++++++++++++++------------------- include/defines.h | 14 +++++-- include/encoder.cpp | 19 +++++++--- include/servo.cpp | 68 ++++++++++++++++++++++++--------- include/servo.hpp | 3 ++ include/socketIO.cpp | 90 +++++++++++++++++++++++++++++++++++++------- 6 files changed, 191 insertions(+), 82 deletions(-) diff --git a/include/bmHTTP.cpp b/include/bmHTTP.cpp index ed47f24..84d47b4 100644 --- a/include/bmHTTP.cpp +++ b/include/bmHTTP.cpp @@ -2,16 +2,39 @@ #include "esp_http_client.h" #include "nvs_flash.h" #include "defines.h" -#define httpSrv "http://192.168.1.190:3000/" +#include "esp_crt_bundle.h" std::string webToken; +const std::string urlBase = std::string("http") + (secureSrv ? "s" : "") + "://" + srvAddr + "/"; + +esp_err_t _http_event_handler(esp_http_client_event_t *evt) { + switch(evt->event_id) { + case HTTP_EVENT_ON_DATA: { + // Append received data to buffer (handles both chunked and non-chunked) + if (evt->data_len > 0 && evt->user_data != NULL) { + std::string* rxBuffer = (std::string*)evt->user_data; + rxBuffer->append((char*)evt->data, evt->data_len); + } + break; + } + default: + break; + } + return ESP_OK; +} bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse) { - std::string url = std::string(httpSrv) + endpoint; + std::string url = urlBase + endpoint; + std::string responseBuffer = ""; esp_http_client_config_t config = {}; config.url = url.c_str(); - config.method = HTTP_METHOD_GET; + config.event_handler = _http_event_handler; // Attach the bucket + config.user_data = &responseBuffer; // Pass pointer to our string so the handler can write to it + if (secureSrv) { + config.transport_type = HTTP_TRANSPORT_OVER_SSL; + config.crt_bundle_attach = esp_crt_bundle_attach; + } esp_http_client_handle_t client = esp_http_client_init(&config); @@ -20,50 +43,24 @@ bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse) { esp_http_client_set_header(client, "Authorization", authHeader.c_str()); // Open connection and fetch headers - esp_err_t err = esp_http_client_open(client, 0); + esp_err_t err = esp_http_client_perform(client); bool success = false; if (err == ESP_OK) { - int content_length = esp_http_client_fetch_headers(client); - int status_code = esp_http_client_get_status_code(client); - - printf("HTTP Status = %d, content_length = %d\n", status_code, content_length); - - if (status_code == 200 && content_length > 0) { - // Allocate buffer for the response - char *buffer = (char *)malloc(content_length + 1); - if (buffer) { - int total_read = 0; - int read_len; + int status_code = esp_http_client_get_status_code(client); + printf("Status = %d, Content Length = %d\n", status_code, esp_http_client_get_content_length(client)); - // Read the response body - while (total_read < content_length) { - read_len = esp_http_client_read(client, buffer + total_read, content_length - total_read); - if (read_len <= 0) break; - total_read += read_len; + if (status_code == 200) { + printf("Response: %s\n", responseBuffer.c_str()); + JSONresponse = cJSON_Parse(responseBuffer.c_str()); + if (JSONresponse) success = true; } - - buffer[total_read] = '\0'; - printf("Response body: %s\n", buffer); - - JSONresponse = cJSON_Parse(buffer); - success = (JSONresponse != NULL); - - if (!success) { - printf("Failed to parse JSON\n"); - } - - free(buffer); - } else { - printf("Failed to allocate buffer for response\n"); - } + } else { + printf("HTTP GET failed: %s\n", esp_err_to_name(err)); } - - esp_http_client_close(client); - } else printf("HTTP request failed: %s\n", esp_err_to_name(err)); - - esp_http_client_cleanup(client); - return success; + + esp_http_client_cleanup(client); + return success; } void deleteWiFiAndTokenDetails() { diff --git a/include/defines.h b/include/defines.h index e41d3da..8f482e7 100644 --- a/include/defines.h +++ b/include/defines.h @@ -27,14 +27,20 @@ #define nvsServo "SERVO" #define posTag "POS" -#define ENCODER_PIN_A GPIO_NUM_23 -#define ENCODER_PIN_B GPIO_NUM_16 +#define secureSrv true +// #define srvAddr "192.168.1.190:3000" +#define srvAddr "wahwa.com" -#define InputEnc_PIN_A GPIO_NUM_1 -#define InputEnc_PIN_B GPIO_NUM_2 +#define ENCODER_PIN_A GPIO_NUM_23 // d5 +#define ENCODER_PIN_B GPIO_NUM_16 // d6 + +#define InputEnc_PIN_A GPIO_NUM_1 // d1 +#define InputEnc_PIN_B GPIO_NUM_2 // d2 #define servoPin GPIO_NUM_20 #define servoLEDCChannel LEDC_CHANNEL_0 #define servoSwitch GPIO_NUM_17 +#define debugLED GPIO_NUM_22 // d4 + #endif \ No newline at end of file diff --git a/include/encoder.cpp b/include/encoder.cpp index 1687c4c..b6df7ec 100644 --- a/include/encoder.cpp +++ b/include/encoder.cpp @@ -9,7 +9,8 @@ static const char *TAG = "ENCODER"; // Constructor Encoder::Encoder(gpio_num_t pinA, gpio_num_t pinB) : pin_a(pinA), pin_b(pinB), count(0), - last_state_a(0), last_state_b(0), last_count_base(0) {} + last_state_a(0), last_state_b(0), last_count_base(0), + watchdog_handle(nullptr) {} // Static ISR - receives Encoder instance via arg void IRAM_ATTR Encoder::isr_handler(void* arg) @@ -48,7 +49,11 @@ void IRAM_ATTR Encoder::isr_handler(void* arg) encoder->count += 1; encoder->last_count_base -= 4; if (calibListen) servoCalibListen(); - if (encoder->feedWDog) esp_timer_restart(encoder->watchdog_handle, 500000); + 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(); } @@ -56,7 +61,11 @@ void IRAM_ATTR Encoder::isr_handler(void* arg) encoder->count -= 1; encoder->last_count_base += 4; if (calibListen) servoCalibListen(); - if (encoder->feedWDog) esp_timer_restart(encoder->watchdog_handle, 500000); + 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(); } @@ -107,9 +116,9 @@ void Encoder::setupWatchdog() { feedWDog = true; } -void Encoder::pauseWatchdog() { +void IRAM_ATTR Encoder::pauseWatchdog() { + if (watchdog_handle != nullptr) esp_timer_stop(watchdog_handle); feedWDog = false; - if (watchdog_handle != NULL) esp_timer_stop(watchdog_handle); } Encoder::~Encoder() { diff --git a/include/servo.cpp b/include/servo.cpp index edbd87b..1ff88d4 100644 --- a/include/servo.cpp +++ b/include/servo.cpp @@ -41,8 +41,14 @@ void servoInit() { gpio_set_direction(servoSwitch, GPIO_MODE_OUTPUT); gpio_set_level(servoSwitch, 0); // Start with servo power off + // Configure debug LED pin as output + gpio_reset_pin(GPIO_NUM_22); + gpio_set_direction(debugLED, GPIO_MODE_OUTPUT); + gpio_set_level(debugLED, 0); // Start with LED off + topEnc->count = servoReadPos(); if (calib.getCalibrated()) initMainLoop(); + debugLEDSwitch(1); } void servoOn(uint8_t dir, uint8_t manOrServer) { @@ -65,13 +71,22 @@ void servoMainSwitch(uint8_t onOff) { gpio_set_level(servoSwitch, onOff ? 1 : 0); } +void debugLEDSwitch(uint8_t onOff) { + gpio_set_level(debugLED, onOff ? 1 : 0); +} + +void debugLEDTgl() { + static bool onOff = false; + gpio_set_level(debugLED, onOff); + onOff = !onOff; +} + bool servoInitCalib() { topEnc->pauseWatchdog(); - // get ready for calibration by clearing all these listeners - bottomEnc->wandListen = false; - topEnc->wandListen = false; - topEnc->serverListen = false; + 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 (!calib.clearCalibrated()) return false; if (topEnc == nullptr || bottomEnc == nullptr) { printf("ERROR: CALIBRATION STARTED BEFORE SERVO INITIALIZATION\n"); @@ -82,11 +97,20 @@ bool servoInitCalib() { return true; } +void servoCancelCalib() { + calibListen = false; + servoOff(); +} + void servoCalibListen() { int32_t effDiff = (bottomEnc->getCount() - topEnc->getCount()) - baseDiff; if (effDiff > 1) servoOn(CCW, manual); - else if (effDiff < -1) servoOn(CW, manual); - else servoOff(); + else if (effDiff < -1) { + servoOn(CW, manual); + } + else { + servoOff(); + } } bool servoBeginDownwardCalib() { @@ -111,7 +135,7 @@ bool servoCompleteCalib() { void initMainLoop() { topEnc->setupWatchdog(); servoSavePos(); - bottomEnc->wandListen = true; + bottomEnc->wandListen.store(true, std::memory_order_release); } void IRAM_ATTR watchdogCallback(void* arg) { @@ -121,9 +145,9 @@ void IRAM_ATTR watchdogCallback(void* arg) { topEnc->pauseWatchdog(); // get ready for recalibration by clearing all these listeners - bottomEnc->wandListen = false; - topEnc->wandListen = false; - topEnc->serverListen = false; + bottomEnc->wandListen.store(false, std::memory_order_release); + topEnc->wandListen.store(false, std::memory_order_release); + topEnc->serverListen.store(false, std::memory_order_release); servoOff(); } else { @@ -170,7 +194,7 @@ int32_t servoReadPos() { void stopServerRun() { // stop listener and stop running if serverRun is still active. - topEnc->serverListen = false; + topEnc->serverListen.store(false, std::memory_order_release); if (runningServer) servoOff(); } @@ -199,21 +223,27 @@ void servoWandListen() { // if effective difference is 0, stop servo and servo-listener // otherwise, run servo in whichever direction necessary and // ensure servo-listener is active. - if (abs(topCount - upBound) <= 1 || abs(topCount - downBound) <= 1) { + if (topCount >= (MAX(upBound, downBound) - 1) + && effDiff > 1) { // TODO: see whether these margins need to be removed. servoOff(); - topEnc->wandListen = false; + topEnc->wandListen.store(false, std::memory_order_release); + } + else if (topCount <= (MIN(upBound, downBound) + 1) + && effDiff < -1) { + servoOff(); + topEnc->wandListen.store(false, std::memory_order_release); } else if (effDiff > 1) { - topEnc->wandListen = true; + topEnc->wandListen.store(true, std::memory_order_release); servoOn(CCW, manual); } else if (effDiff < -1) { - topEnc->wandListen = true; + topEnc->wandListen.store(true, std::memory_order_release); servoOn(CW, manual); } else { servoOff(); - topEnc->wandListen = false; + topEnc->wandListen.store(false, std::memory_order_release); } } @@ -230,14 +260,16 @@ void runToAppPos(uint8_t appPos) { if (runningManual || !calib.getCalibrated()) return; servoOff(); + 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 vTaskDelay(pdMS_TO_TICKS(500)); int32_t topCount = topEnc->getCount(); - target = calib.convertToTicks(appPos); // calculate target encoder position if (abs(topCount - target) <= 1) return; startLess = topCount < target; if (runningManual) return; // check again before starting remote control if (startLess) servoOn(CCW, server); // begin servo movement else servoOn(CW, server); - topEnc->serverListen = true; // start listening for shutoff point + topEnc->serverListen.store(true, std::memory_order_release); // start listening for shutoff point } \ No newline at end of file diff --git a/include/servo.hpp b/include/servo.hpp index a738004..54b81b2 100644 --- a/include/servo.hpp +++ b/include/servo.hpp @@ -25,6 +25,9 @@ void servoCalibListen(); bool servoInitCalib(); bool servoBeginDownwardCalib(); bool servoCompleteCalib(); +void servoCancelCalib(); +void debugLEDSwitch(uint8_t onOff); +void debugLEDTgl(); void initMainLoop(); void watchdogCallback(void* arg); diff --git a/include/socketIO.cpp b/include/socketIO.cpp index 496a234..0bdb530 100644 --- a/include/socketIO.cpp +++ b/include/socketIO.cpp @@ -6,6 +6,8 @@ #include "cJSON.h" #include "calibration.hpp" #include "servo.hpp" +#include "defines.h" +#include "esp_crt_bundle.h" static esp_socketio_client_handle_t io_client; static esp_socketio_packet_handle_t tx_packet = NULL; @@ -139,8 +141,15 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, emitCalibError("Non-1 Port"); } else { - if (!servoInitCalib()) emitCalibError("Initialization failed"); - else emitCalibStage1Ready(); + printf("Running initCalib...\n"); + if (!servoInitCalib()) { + printf("initCalib returned False\n"); + emitCalibError("Initialization failed"); + } + else { + printf("Ready to calibrate\n"); + emitCalibStage1Ready(); + } } } } @@ -157,11 +166,11 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, printf("Error, non-1 port received for calibration\n"); emitCalibError("Non-1 Port"); } - else { + else { if (!servoBeginDownwardCalib()) emitCalibError("Direction Switch Failed"); else emitCalibStage2Ready(); - } + } } } } @@ -184,6 +193,24 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, } } } + + // Handle user_stage1_complete event + else if (strcmp(eventName->valuestring, "cancel_calib") == 0) { + printf("Canceling calibration process...\n"); + cJSON *data = cJSON_GetArrayItem(json, 1); + if (data) { + cJSON *port = cJSON_GetObjectItem(data, "port"); + if (port && cJSON_IsNumber(port)) { + if (port->valueint != 1) { + printf("Error, non-1 port received for calibration\n"); + emitCalibError("Non-1 Port"); + } + else { + servoCancelCalib(); + } + } + } + } // Handle server position change (manual or scheduled) else if (strcmp(eventName->valuestring, "posUpdates") == 0) { @@ -225,18 +252,47 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, case SOCKETIO_EVENT_ERROR: { printf("Socket.IO Error!\n"); - - // Check WebSocket error details + servoCancelCalib(); esp_websocket_event_data_t *ws_event = data->websocket_event; - if (ws_event && ws_event->error_handle.esp_ws_handshake_status_code != 0) { - printf("HTTP Status: %d\n", ws_event->error_handle.esp_ws_handshake_status_code); - if (ws_event->error_handle.esp_ws_handshake_status_code == 401 || - ws_event->error_handle.esp_ws_handshake_status_code == 403) { - printf("Authentication failed - invalid token\n"); - } + + if (ws_event) { + // 1. Check for TLS/SSL specific errors (Certificate issues) + if (ws_event->error_handle.error_type == WEBSOCKET_ERROR_TYPE_TCP_TRANSPORT) { + + // This prints the "MbedTLS" error code (The low-level crypto library) + // Common codes: -0x2700 (CRT verify failed), -0x7200 (SSL handshake failed) + if (ws_event->error_handle.esp_tls_stack_err != 0) { + printf("TLS/SSL Stack Error: -0x%x\n", -ws_event->error_handle.esp_tls_stack_err); + } + + // 2. Check the Certificate Verification Flags + // If this is non-zero, the certificate was rejected. + if (ws_event->error_handle.esp_tls_cert_verify_flags != 0) { + uint32_t flags = ws_event->error_handle.esp_tls_cert_verify_flags; + printf("Certificate Verification FAILED. Flags: 0x%lx\n", flags); + + // Simple decoder for common flags: + if (flags & (1 << 0)) printf(" - CRT_NOT_TRUSTED (Root CA not found in bundle)\n"); + if (flags & (1 << 1)) printf(" - CRT_BAD_KEY_USAGE\n"); + if (flags & (1 << 2)) printf(" - CRT_EXPIRED (Check your ESP32 system time!)\n"); + if (flags & (1 << 3)) printf(" - CRT_CN_MISMATCH (Domain name doesn't match cert)\n"); + } + } + + // 3. Check for HTTP Handshake errors (401/403/404) + // This happens if SSL worked, but the server rejected your path or token + else if (ws_event->error_handle.error_type == WEBSOCKET_ERROR_TYPE_HANDSHAKE) { + int status = ws_event->error_handle.esp_ws_handshake_status_code; + printf("HTTP Handshake Error: %d\n", status); + + if (status == 401 || status == 403) { + printf("Authentication failed - invalid token\n"); + } else if (status == 404) { + printf("404 Not Found - Check your URI/Path\n"); + } + } } - // Set flags to indicate connection failure connected = false; statusResolved = true; break; @@ -251,6 +307,7 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base, } } +const std::string uriString = std::string("ws") + (secureSrv ? "s" : "") + "://" + srvAddr + "/socket.io/?EIO=4&transport=websocket"; void initSocketIO() { // Prepare the Authorization Header (Bearer format) std::string authHeader = "Authorization: Bearer " + webToken + "\r\n"; @@ -259,8 +316,13 @@ void initSocketIO() { connected = false; esp_socketio_client_config_t config = {}; - config.websocket_config.uri = "ws://192.168.1.190:3000/socket.io/?EIO=4&transport=websocket"; + config.websocket_config.uri = uriString.c_str(); config.websocket_config.headers = authHeader.c_str(); + + if (secureSrv) { + config.websocket_config.transport = WEBSOCKET_TRANSPORT_OVER_SSL; + config.websocket_config.crt_bundle_attach = esp_crt_bundle_attach; + } io_client = esp_socketio_client_init(&config); tx_packet = esp_socketio_client_get_tx_packet(io_client);