Task-Driven, powersaving trial written, must test.
This commit is contained in:
@@ -1,3 +1,6 @@
|
|||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
#include "BLE.hpp"
|
#include "BLE.hpp"
|
||||||
#include "NimBLEDevice.h"
|
#include "NimBLEDevice.h"
|
||||||
#include "WiFi.hpp"
|
#include "WiFi.hpp"
|
||||||
@@ -6,7 +9,6 @@
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "bmHTTP.hpp"
|
#include "bmHTTP.hpp"
|
||||||
#include <freertos/queue.h>
|
|
||||||
#include "setup.hpp"
|
#include "setup.hpp"
|
||||||
#include "esp_mac.h"
|
#include "esp_mac.h"
|
||||||
|
|
||||||
@@ -26,6 +28,10 @@ static std::string UNAME = "";
|
|||||||
// Global pointers to characteristics for notification support
|
// Global pointers to characteristics for notification support
|
||||||
std::atomic<NimBLECharacteristic*> ssidListChar = nullptr;
|
std::atomic<NimBLECharacteristic*> ssidListChar = nullptr;
|
||||||
std::atomic<NimBLECharacteristic*> connectConfirmChar = nullptr;
|
std::atomic<NimBLECharacteristic*> connectConfirmChar = nullptr;
|
||||||
|
|
||||||
|
// Forward declarations
|
||||||
|
bool attemptUseWiFiCreds();
|
||||||
|
bool tokenCheck();
|
||||||
std::atomic<NimBLECharacteristic*> authConfirmChar = nullptr;
|
std::atomic<NimBLECharacteristic*> authConfirmChar = nullptr;
|
||||||
std::atomic<NimBLECharacteristic*> credsChar = nullptr;
|
std::atomic<NimBLECharacteristic*> credsChar = nullptr;
|
||||||
std::atomic<NimBLECharacteristic*> tokenChar = nullptr;
|
std::atomic<NimBLECharacteristic*> tokenChar = nullptr;
|
||||||
@@ -382,7 +388,7 @@ bool attemptUseWiFiCreds() {
|
|||||||
if (!wifiConnect) {
|
if (!wifiConnect) {
|
||||||
// notify errored
|
// notify errored
|
||||||
notifyConnectionStatus(false);
|
notifyConnectionStatus(false);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
nvs_handle_t WiFiHandle;
|
nvs_handle_t WiFiHandle;
|
||||||
@@ -391,7 +397,7 @@ bool attemptUseWiFiCreds() {
|
|||||||
printf("ERROR Saving Credentials\n");
|
printf("ERROR Saving Credentials\n");
|
||||||
// notify errored
|
// notify errored
|
||||||
notifyConnectionStatus(false);
|
notifyConnectionStatus(false);
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
err = nvs_set_str(WiFiHandle, ssidTag, tmpSSID.c_str());
|
err = nvs_set_str(WiFiHandle, ssidTag, tmpSSID.c_str());
|
||||||
@@ -404,9 +410,11 @@ bool attemptUseWiFiCreds() {
|
|||||||
if (err == ESP_OK) {
|
if (err == ESP_OK) {
|
||||||
// notify connected
|
// notify connected
|
||||||
notifyConnectionStatus(true);
|
notifyConnectionStatus(true);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// notify connected
|
// notify errored
|
||||||
notifyConnectionStatus(false);
|
notifyConnectionStatus(false);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2,8 +2,9 @@
|
|||||||
#include "esp_eap_client.h"
|
#include "esp_eap_client.h"
|
||||||
#include "cJSON.h" // Native replacement for ArduinoJson
|
#include "cJSON.h" // Native replacement for ArduinoJson
|
||||||
#include "BLE.hpp"
|
#include "BLE.hpp"
|
||||||
|
#include "esp_wifi_he.h"
|
||||||
|
|
||||||
std::atomic<bool> WiFi::authFailed{false};
|
TaskHandle_t WiFi::awaitConnectHandle = NULL;
|
||||||
EventGroupHandle_t WiFi::s_wifi_event_group = NULL;
|
EventGroupHandle_t WiFi::s_wifi_event_group = NULL;
|
||||||
esp_netif_t* WiFi::netif = NULL;
|
esp_netif_t* WiFi::netif = NULL;
|
||||||
esp_event_handler_instance_t WiFi::instance_any_id = NULL;
|
esp_event_handler_instance_t WiFi::instance_any_id = NULL;
|
||||||
@@ -36,12 +37,16 @@ void WiFi::event_handler(void* arg, esp_event_base_t event_base,
|
|||||||
case WIFI_REASON_AUTH_FAIL: // Reason 202
|
case WIFI_REASON_AUTH_FAIL: // Reason 202
|
||||||
case WIFI_REASON_HANDSHAKE_TIMEOUT: // Reason 204
|
case WIFI_REASON_HANDSHAKE_TIMEOUT: // Reason 204
|
||||||
printf("ERROR: Likely Wrong Password!\n");
|
printf("ERROR: Likely Wrong Password!\n");
|
||||||
authFailed = true;
|
if (awaitConnectHandle != NULL) {
|
||||||
|
xTaskNotify(awaitConnectHandle, false, eSetValueWithOverwrite);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WIFI_REASON_NO_AP_FOUND: // Reason 201
|
case WIFI_REASON_NO_AP_FOUND: // Reason 201
|
||||||
printf("ERROR: SSID Not Found\n");
|
printf("ERROR: SSID Not Found\n");
|
||||||
authFailed = true;
|
if (awaitConnectHandle != NULL) {
|
||||||
|
xTaskNotify(awaitConnectHandle, false, eSetValueWithOverwrite);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WIFI_REASON_ASSOC_LEAVE: // Reason 8 - Manual disconnect
|
case WIFI_REASON_ASSOC_LEAVE: // Reason 8 - Manual disconnect
|
||||||
@@ -51,11 +56,13 @@ void WiFi::event_handler(void* arg, esp_event_base_t event_base,
|
|||||||
case WIFI_REASON_ASSOC_FAIL: // Reason 203 (Can be AP busy/rate limiting)
|
case WIFI_REASON_ASSOC_FAIL: // Reason 203 (Can be AP busy/rate limiting)
|
||||||
printf("Association failed, will retry...\n");
|
printf("Association failed, will retry...\n");
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000)); // Wait 1 second before retry to avoid rate limiting
|
vTaskDelay(pdMS_TO_TICKS(1000)); // Wait 1 second before retry to avoid rate limiting
|
||||||
|
esp_netif_dhcpc_start(netif);
|
||||||
esp_wifi_connect();
|
esp_wifi_connect();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
printf("Retrying...\n");
|
printf("Retrying...\n");
|
||||||
|
esp_netif_dhcpc_start(netif);
|
||||||
esp_wifi_connect();
|
esp_wifi_connect();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -72,7 +79,11 @@ void WiFi::event_handler(void* arg, esp_event_base_t event_base,
|
|||||||
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||||
printf("Got IP: " IPSTR "\n", IP2STR(&event->ip_info.ip));
|
printf("Got IP: " IPSTR "\n", IP2STR(&event->ip_info.ip));
|
||||||
|
esp_netif_dhcpc_stop(netif);
|
||||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||||
|
if (awaitConnectHandle != NULL) {
|
||||||
|
xTaskNotify(awaitConnectHandle, true, eSetValueWithOverwrite);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,6 +119,7 @@ void WiFi::init() {
|
|||||||
|
|
||||||
ESP_ERROR_CHECK(esp_wifi_start());
|
ESP_ERROR_CHECK(esp_wifi_start());
|
||||||
xEventGroupWaitBits(s_wifi_event_group, WIFI_STARTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
|
xEventGroupWaitBits(s_wifi_event_group, WIFI_STARTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
|
||||||
|
awaitConnectHandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- CHECK STATUS ---
|
// --- CHECK STATUS ---
|
||||||
@@ -170,19 +182,46 @@ bool WiFi::attemptConnect(const std::string ssid, const std::string uname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WiFi::awaitConnected() {
|
bool WiFi::awaitConnected() {
|
||||||
authFailed = false;
|
awaitConnectHandle = xTaskGetCurrentTaskHandle();
|
||||||
if (esp_wifi_connect() != ESP_OK) return false;
|
if (esp_wifi_connect() != ESP_OK) {
|
||||||
|
awaitConnectHandle = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t attempts = 0;
|
uint32_t status;
|
||||||
while (!isConnected() && attempts < 20) {
|
uint8_t MAX_TIMEOUT = 10; //seconds
|
||||||
if (authFailed) {
|
if (xTaskNotifyWait(0, ULONG_MAX, &status, pdMS_TO_TICKS(MAX_TIMEOUT * 1000)) == pdTRUE) {
|
||||||
|
awaitConnectHandle = NULL;
|
||||||
|
if (!status) {
|
||||||
printf("SSID/Password was wrong! Aborting connection attempt.\n");
|
printf("SSID/Password was wrong! Aborting connection attempt.\n");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
vTaskDelay(500);
|
} else {
|
||||||
attempts++;
|
// Timeout - check if connected anyway
|
||||||
|
awaitConnectHandle = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isConnected()) {
|
||||||
|
esp_wifi_set_ps(WIFI_PS_MIN_MODEM);
|
||||||
|
uint8_t protocol_bitmap = 0;
|
||||||
|
esp_err_t err = esp_wifi_get_protocol(WIFI_IF_STA, &protocol_bitmap);
|
||||||
|
|
||||||
|
if (err == ESP_OK && (protocol_bitmap & WIFI_PROTOCOL_11AX)) {
|
||||||
|
// WiFi 6 (802.11ax) - Use Target Wake Time (TWT) for power saving
|
||||||
|
wifi_twt_setup_config_t twt_config = {
|
||||||
|
.setup_cmd = TWT_REQUEST,
|
||||||
|
.trigger = true,
|
||||||
|
.flow_type = 0, // Announced
|
||||||
|
.flow_id = 0,
|
||||||
|
.wake_invl_expn = 12, // Exponent for interval
|
||||||
|
.min_wake_dura = 255, // ~65ms (unit is 256 microseconds)
|
||||||
|
.wake_invl_mant = 14648, // Mantissa (mant * 2^exp = 60,000,000 us = 60s)
|
||||||
|
.timeout_time_ms = 5000,
|
||||||
|
};
|
||||||
|
esp_wifi_sta_itwt_setup(&twt_config);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
if (isConnected()) return true;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,8 +229,6 @@ bool WiFi::awaitConnected() {
|
|||||||
void WiFi::scanAndUpdateSSIDList() {
|
void WiFi::scanAndUpdateSSIDList() {
|
||||||
printf("Starting WiFi Scan...\n");
|
printf("Starting WiFi Scan...\n");
|
||||||
|
|
||||||
// 1. Start Scan (Blocking Mode = true)
|
|
||||||
// In blocking mode, this function waits here until scan is done (~2 seconds)
|
|
||||||
esp_wifi_sta_enterprise_disable();
|
esp_wifi_sta_enterprise_disable();
|
||||||
esp_wifi_disconnect();
|
esp_wifi_disconnect();
|
||||||
|
|
||||||
@@ -222,7 +259,13 @@ void WiFi::processScanResults() {
|
|||||||
printf("Heap allocation error in processScanResults\n");
|
printf("Heap allocation error in processScanResults\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_count, ap_list));
|
|
||||||
|
esp_err_t err = esp_wifi_scan_get_ap_records(&ap_count, ap_list);
|
||||||
|
if (err != ESP_OK) {
|
||||||
|
printf("Failed to get scan records\n");
|
||||||
|
free(ap_list);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 3. Build JSON using cJSON
|
// 3. Build JSON using cJSON
|
||||||
cJSON *root = cJSON_CreateArray();
|
cJSON *root = cJSON_CreateArray();
|
||||||
@@ -255,3 +298,23 @@ void WiFi::processScanResults() {
|
|||||||
cJSON_Delete(root); // This deletes all children (items) too
|
cJSON_Delete(root); // This deletes all children (items) too
|
||||||
free(json_string); // cJSON_Print allocates memory, you must free it
|
free(json_string); // cJSON_Print allocates memory, you must free it
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool WiFi::attemptDHCPrenewal() {
|
||||||
|
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||||
|
esp_netif_dhcpc_start(netif);
|
||||||
|
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
|
||||||
|
WIFI_CONNECTED_BIT,
|
||||||
|
pdFALSE,
|
||||||
|
pdFALSE,
|
||||||
|
pdMS_TO_TICKS(4000));
|
||||||
|
|
||||||
|
if (bits & WIFI_CONNECTED_BIT) {
|
||||||
|
printf("renewal success");
|
||||||
|
// Stop the client again to save power.
|
||||||
|
esp_netif_dhcpc_stop(netif);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
printf("DHCP Renewal failed. Reconnecting Wi-Fi...\n");
|
||||||
|
esp_wifi_disconnect();
|
||||||
|
return awaitConnected();
|
||||||
|
}
|
||||||
@@ -14,9 +14,10 @@ class WiFi {
|
|||||||
const std::string password, const wifi_auth_mode_t authMode);
|
const std::string password, const wifi_auth_mode_t authMode);
|
||||||
static bool isConnected();
|
static bool isConnected();
|
||||||
static void scanAndUpdateSSIDList();
|
static void scanAndUpdateSSIDList();
|
||||||
|
static bool attemptDHCPrenewal();
|
||||||
private:
|
private:
|
||||||
|
static TaskHandle_t awaitConnectHandle;
|
||||||
static void processScanResults();
|
static void processScanResults();
|
||||||
static std::atomic<bool> authFailed;
|
|
||||||
static bool awaitConnected();
|
static bool awaitConnected();
|
||||||
static esp_event_handler_instance_t instance_any_id;
|
static esp_event_handler_instance_t instance_any_id;
|
||||||
static esp_event_handler_instance_t instance_got_ip;
|
static esp_event_handler_instance_t instance_got_ip;
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
#include "bmEvents.hpp"
|
|
||||||
#include <portmacro.h>
|
|
||||||
#include <freertos/projdefs.h>
|
|
||||||
|
|
||||||
// blueprint for sending events... maybe I never use this. We'll see.
|
|
||||||
// bool send_app_event(app_event_t *event, QueueHandle_t event_queue) {
|
|
||||||
// if (event_queue == NULL) return false;
|
|
||||||
|
|
||||||
// // A. Are we in an Interrupt Service Routine (Hardware context)?
|
|
||||||
// if (xPortInIsrContext()) {
|
|
||||||
// BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
||||||
|
|
||||||
// // Use the "FromISR" version
|
|
||||||
// BaseType_t result = xQueueSendFromISR(event_queue, event, &xHigherPriorityTaskWoken);
|
|
||||||
|
|
||||||
// // This is crucial for "Instant Wakeup"
|
|
||||||
// if (result == pdPASS) portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
||||||
// return (result == pdPASS);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // B. Are we in a Standard Task (WiFi/BLE Callback context)?
|
|
||||||
// else {
|
|
||||||
// // Use the standard version
|
|
||||||
// // 10 ticks wait time is arbitrary; allows a small buffer if queue is full
|
|
||||||
// return (xQueueSend(event_queue, event, pdMS_TO_TICKS(10)) == pdPASS);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// blueprint for deleting more complex event queues
|
|
||||||
// void deinit_BLE_event_queue(QueueHandle_t& event_queue) {
|
|
||||||
// if (event_queue != NULL) {
|
|
||||||
// app_event_t temp_event;
|
|
||||||
// while (xQueueReceive(event_queue, &temp_event, 0) == pdTRUE) {
|
|
||||||
// if (temp_event.data != NULL) free(temp_event.data);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// vQueueDelete(event_queue);
|
|
||||||
|
|
||||||
// event_queue = NULL;
|
|
||||||
|
|
||||||
// printf("Event queue deleted.\n");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
#ifndef BM_EVENTS_H
|
|
||||||
#define BM_EVENTS_H
|
|
||||||
#include <freertos/queue.h>
|
|
||||||
|
|
||||||
// bool send_app_event(app_event_t *event);
|
|
||||||
|
|
||||||
// void deinit_event_queue(QueueHandle_t& event_queue);
|
|
||||||
|
|
||||||
// // 1. Event Types: The "What"
|
|
||||||
// typedef enum {
|
|
||||||
// EVENT_BUTTON_PRESSED,
|
|
||||||
// EVENT_WIFI_CONNECTED,
|
|
||||||
// EVENT_WIFI_DISCONNECTED,
|
|
||||||
// EVENT_BLE_DATA_RECEIVED,
|
|
||||||
// EVENT_TIMER_TICK
|
|
||||||
// } event_type_t;
|
|
||||||
|
|
||||||
// // 2. The Message Structure: The "Payload"
|
|
||||||
// typedef struct {
|
|
||||||
// event_type_t type;
|
|
||||||
// void *data; // Optional: Pointer to data (buffer, string, etc.)
|
|
||||||
// int data_len; // Optional: Length of data
|
|
||||||
// } app_event_t;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -63,6 +63,59 @@ bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse) {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool httpPOST(std::string endpoint, std::string token, cJSON* postData, cJSON* &JSONresponse) {
|
||||||
|
std::string url = urlBase + endpoint;
|
||||||
|
std::string responseBuffer = "";
|
||||||
|
|
||||||
|
// Convert JSON object to string
|
||||||
|
char* postString = cJSON_PrintUnformatted(postData);
|
||||||
|
if (postString == NULL) {
|
||||||
|
printf("Failed to serialize JSON for POST\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_http_client_config_t config = {};
|
||||||
|
config.url = url.c_str();
|
||||||
|
config.method = HTTP_METHOD_POST;
|
||||||
|
config.event_handler = _http_event_handler;
|
||||||
|
config.user_data = &responseBuffer;
|
||||||
|
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);
|
||||||
|
|
||||||
|
// Set headers
|
||||||
|
std::string authHeader = "Bearer " + token;
|
||||||
|
esp_http_client_set_header(client, "Authorization", authHeader.c_str());
|
||||||
|
esp_http_client_set_header(client, "Content-Type", "application/json");
|
||||||
|
|
||||||
|
// Set POST data
|
||||||
|
esp_http_client_set_post_field(client, postString, strlen(postString));
|
||||||
|
|
||||||
|
// Perform request
|
||||||
|
esp_err_t err = esp_http_client_perform(client);
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
if (err == ESP_OK) {
|
||||||
|
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));
|
||||||
|
|
||||||
|
if (status_code == 200 || status_code == 201) {
|
||||||
|
printf("Response: %s\n", responseBuffer.c_str());
|
||||||
|
JSONresponse = cJSON_Parse(responseBuffer.c_str());
|
||||||
|
if (JSONresponse) success = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("HTTP POST failed: %s\n", esp_err_to_name(err));
|
||||||
|
}
|
||||||
|
|
||||||
|
free(postString);
|
||||||
|
esp_http_client_cleanup(client);
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
void deleteWiFiAndTokenDetails() {
|
void deleteWiFiAndTokenDetails() {
|
||||||
nvs_handle_t wifiHandle;
|
nvs_handle_t wifiHandle;
|
||||||
if (nvs_open(nvsWiFi, NVS_READWRITE, &wifiHandle) == ESP_OK) {
|
if (nvs_open(nvsWiFi, NVS_READWRITE, &wifiHandle) == ESP_OK) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
extern std::string webToken;
|
extern std::string webToken;
|
||||||
|
|
||||||
bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse);
|
bool httpGET(std::string endpoint, std::string token, cJSON* &JSONresponse);
|
||||||
|
bool httpPOST(std::string endpoint, std::string token, cJSON* postData, cJSON* &JSONresponse);
|
||||||
|
|
||||||
void deleteWiFiAndTokenDetails();
|
void deleteWiFiAndTokenDetails();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,16 @@
|
|||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
#include "calibration.hpp"
|
#include "calibration.hpp"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
|
#include "socketIO.hpp"
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
// Static member definitions
|
||||||
|
std::atomic<bool> Calibration::calibrated{false};
|
||||||
|
std::atomic<int32_t> Calibration::UpTicks{0};
|
||||||
|
std::atomic<int32_t> Calibration::DownTicks{0};
|
||||||
|
TaskHandle_t calibTaskHandle = NULL;
|
||||||
|
|
||||||
void Calibration::init() {
|
void Calibration::init() {
|
||||||
nvs_handle_t calibHandle;
|
nvs_handle_t calibHandle;
|
||||||
@@ -110,3 +120,45 @@ uint8_t Calibration::convertToAppPos(int32_t ticks) {
|
|||||||
int8_t retVal = (ticks - DownTicks) * 10 / (UpTicks - DownTicks);
|
int8_t retVal = (ticks - DownTicks) * 10 / (UpTicks - DownTicks);
|
||||||
return (retVal < 0) ? 0 : ((retVal > 10) ? 10 : retVal);
|
return (retVal < 0) ? 0 : ((retVal > 10) ? 10 : retVal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool calibrate() {
|
||||||
|
calibTaskHandle = xTaskGetCurrentTaskHandle();
|
||||||
|
printf("Connecting to Socket.IO server for calibration...\n");
|
||||||
|
initSocketIO();
|
||||||
|
|
||||||
|
// Wait for device_init message from server with timeout
|
||||||
|
int timeout_count = 0;
|
||||||
|
const int MAX_TIMEOUT = 60; // seconds
|
||||||
|
|
||||||
|
uint32_t status;
|
||||||
|
// Wait for notification with timeout
|
||||||
|
if (xTaskNotifyWait(0, ULONG_MAX, &status, pdMS_TO_TICKS(MAX_TIMEOUT * 1000)) == pdTRUE) {
|
||||||
|
// Notification received within timeout
|
||||||
|
if (status) {
|
||||||
|
printf("Connected successfully, awaiting destroy command\n");
|
||||||
|
xTaskNotifyWait(0, ULONG_MAX, &status, portMAX_DELAY);
|
||||||
|
calibTaskHandle = NULL;
|
||||||
|
if (status == 2) { // calibration complete
|
||||||
|
printf("Calibration process complete\n");
|
||||||
|
stopSocketIO();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else { // unexpected disconnect
|
||||||
|
printf("Disconnected unexpectedly!\n");
|
||||||
|
stopSocketIO();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
calibTaskHandle = NULL;
|
||||||
|
printf("Connection failed! Returning to setup.\n");
|
||||||
|
stopSocketIO();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Timeout reached
|
||||||
|
calibTaskHandle = NULL;
|
||||||
|
printf("Timeout waiting for device_init - connection failed\n");
|
||||||
|
stopSocketIO();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#ifndef CALIBRATION_H
|
#ifndef CALIBRATION_H
|
||||||
#define CALIBRATION_H
|
#define CALIBRATION_H
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include "encoder.hpp"
|
#include "encoder.hpp"
|
||||||
|
|
||||||
@@ -19,4 +21,7 @@ class Calibration {
|
|||||||
static std::atomic<bool> calibrated;
|
static std::atomic<bool> calibrated;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern TaskHandle_t calibTaskHandle;
|
||||||
|
bool calibrate();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
172
include/mainEventLoop.cpp
Normal file
172
include/mainEventLoop.cpp
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
#include "mainEventLoop.hpp"
|
||||||
|
#include "calibration.hpp"
|
||||||
|
#include "setup.hpp"
|
||||||
|
#include "servo.hpp"
|
||||||
|
#include "bmHTTP.hpp"
|
||||||
|
#include "cJSON.h"
|
||||||
|
#include "encoder.hpp"
|
||||||
|
#include "WiFi.hpp"
|
||||||
|
|
||||||
|
TaskHandle_t wakeTaskHandle = NULL;
|
||||||
|
|
||||||
|
void wakeTimer(void* pvParameters) {
|
||||||
|
while (1) {
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(60000));
|
||||||
|
main_event_type_t evt = EVENT_REQUEST_POS;
|
||||||
|
xQueueSend(main_event_queue, &evt, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool postServoPos(uint8_t currentAppPos) {
|
||||||
|
// Create POST data
|
||||||
|
cJSON* posData = cJSON_CreateObject();
|
||||||
|
cJSON_AddNumberToObject(posData, "port", 1);
|
||||||
|
cJSON_AddNumberToObject(posData, "pos", currentAppPos);
|
||||||
|
|
||||||
|
// Send position update
|
||||||
|
cJSON* response = nullptr;
|
||||||
|
bool success = httpPOST("position", webToken, posData, response);
|
||||||
|
cJSON_Delete(posData);
|
||||||
|
|
||||||
|
if (success && response != nullptr) {
|
||||||
|
// Parse await_calib from response
|
||||||
|
cJSON* awaitCalibItem = cJSON_GetObjectItem(response, "await_calib");
|
||||||
|
bool awaitCalib = false;
|
||||||
|
if (cJSON_IsBool(awaitCalibItem)) {
|
||||||
|
awaitCalib = awaitCalibItem->valueint != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Position update sent: %d, await_calib=%d\n", currentAppPos, awaitCalib);
|
||||||
|
cJSON_Delete(response);
|
||||||
|
|
||||||
|
if (awaitCalib) {
|
||||||
|
Calibration::clearCalibrated();
|
||||||
|
if (!calibrate()) {
|
||||||
|
if (!WiFi::attemptDHCPrenewal())
|
||||||
|
setupAndCalibrate();
|
||||||
|
else {
|
||||||
|
if (!calibrate()) {
|
||||||
|
printf("ERROR OCCURED: EVEN AFTER SETUP, SOCKET OPENING FAIL\n");
|
||||||
|
setupAndCalibrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool getServoPos() {
|
||||||
|
cJSON* response = nullptr;
|
||||||
|
bool success = httpGET("position", webToken, response);
|
||||||
|
|
||||||
|
if (success && response != NULL) {
|
||||||
|
// Check if response is an array
|
||||||
|
if (cJSON_IsArray(response)) {
|
||||||
|
int arraySize = cJSON_GetArraySize(response);
|
||||||
|
|
||||||
|
// Condition 1: More than one object in array
|
||||||
|
if (arraySize > 1) {
|
||||||
|
printf("Multiple peripherals detected, entering setup.\n");
|
||||||
|
cJSON_Delete(response);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// Condition 2: Check peripheral_number in first object
|
||||||
|
else if (arraySize > 0) {
|
||||||
|
cJSON *firstObject = cJSON_GetArrayItem(response, 0);
|
||||||
|
if (firstObject != NULL) {
|
||||||
|
cJSON *peripheralNum = cJSON_GetObjectItem(firstObject, "peripheral_number");
|
||||||
|
if (cJSON_IsNumber(peripheralNum) && peripheralNum->valueint != 1) {
|
||||||
|
printf("Peripheral number is not 1, entering setup.\n");
|
||||||
|
cJSON_Delete(response);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
printf("Verified new token!\n");
|
||||||
|
|
||||||
|
cJSON *awaitCalib = cJSON_GetObjectItem(firstObject, "await_calib");
|
||||||
|
if (cJSON_IsBool(awaitCalib)) {
|
||||||
|
if (awaitCalib->valueint) {
|
||||||
|
Calibration::clearCalibrated();
|
||||||
|
if (!calibrate()) {
|
||||||
|
if (!WiFi::attemptDHCPrenewal())
|
||||||
|
setupAndCalibrate();
|
||||||
|
else {
|
||||||
|
if (!calibrate()) {
|
||||||
|
printf("ERROR OCCURED: EVEN AFTER SETUP, SOCKET OPENING FAIL\n");
|
||||||
|
setupAndCalibrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cJSON* pos = cJSON_GetObjectItem(firstObject, "last_pos");
|
||||||
|
runToAppPos(pos->valueint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cJSON_Delete(response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
QueueHandle_t main_event_queue = NULL;
|
||||||
|
|
||||||
|
void mainEventLoop() {
|
||||||
|
main_event_queue = xQueueCreate(10, sizeof(main_event_type_t));
|
||||||
|
main_event_type_t received_event_type;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (xQueueReceive(main_event_queue, &received_event_type, portMAX_DELAY)) {
|
||||||
|
if (received_event_type == EVENT_CLEAR_CALIB) {
|
||||||
|
Calibration::clearCalibrated();
|
||||||
|
if (!calibrate()) {
|
||||||
|
if (!WiFi::attemptDHCPrenewal())
|
||||||
|
setupAndCalibrate();
|
||||||
|
else {
|
||||||
|
if (!calibrate()) {
|
||||||
|
printf("ERROR OCCURED: EVEN AFTER SETUP, SOCKET OPENING FAIL\n");
|
||||||
|
setupAndCalibrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (received_event_type == EVENT_SAVE_POS) {
|
||||||
|
servoSavePos();
|
||||||
|
|
||||||
|
uint8_t currentAppPos = Calibration::convertToAppPos(topEnc->getCount());
|
||||||
|
|
||||||
|
if (!postServoPos(currentAppPos)) {
|
||||||
|
printf("Failed to send position update\n");
|
||||||
|
if (!WiFi::attemptDHCPrenewal()) {
|
||||||
|
setupAndCalibrate();
|
||||||
|
postServoPos(currentAppPos);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!postServoPos(currentAppPos)) {
|
||||||
|
printf("renewed dhcp successfully, but still failed to post\n");
|
||||||
|
setupAndCalibrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (received_event_type == EVENT_REQUEST_POS) {
|
||||||
|
if (!getServoPos()) {
|
||||||
|
printf("Failed to send position update\n");
|
||||||
|
if (!WiFi::attemptDHCPrenewal()) {
|
||||||
|
setupAndCalibrate();
|
||||||
|
getServoPos();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (!getServoPos()) {
|
||||||
|
printf("renewed dhcp successfully, but still failed to post\n");
|
||||||
|
setupAndCalibrate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
}
|
||||||
21
include/mainEventLoop.hpp
Normal file
21
include/mainEventLoop.hpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef BM_EVENTS_H
|
||||||
|
#define BM_EVENTS_H
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/queue.h"
|
||||||
|
|
||||||
|
// Event Types
|
||||||
|
typedef enum {
|
||||||
|
EVENT_CLEAR_CALIB,
|
||||||
|
EVENT_SAVE_POS,
|
||||||
|
EVENT_REQUEST_POS
|
||||||
|
} main_event_type_t;
|
||||||
|
|
||||||
|
void mainEventLoop();
|
||||||
|
|
||||||
|
extern QueueHandle_t main_event_queue;
|
||||||
|
|
||||||
|
void wakeTimer(void* pvParameters);
|
||||||
|
|
||||||
|
extern TaskHandle_t wakeTaskHandle;
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
#include "servo.hpp"
|
#include "servo.hpp"
|
||||||
#include "driver/ledc.h"
|
#include "driver/ledc.h"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include <freertos/FreeRTOS.h>
|
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "socketIO.hpp"
|
#include "socketIO.hpp"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
|
#include "mainEventLoop.hpp"
|
||||||
|
|
||||||
std::atomic<bool> calibListen{false};
|
std::atomic<bool> calibListen{false};
|
||||||
std::atomic<int32_t> baseDiff{0};
|
std::atomic<int32_t> baseDiff{0};
|
||||||
@@ -12,8 +14,6 @@ std::atomic<int32_t> target{0};
|
|||||||
|
|
||||||
std::atomic<bool> runningManual{false};
|
std::atomic<bool> runningManual{false};
|
||||||
std::atomic<bool> runningServer{false};
|
std::atomic<bool> runningServer{false};
|
||||||
std::atomic<bool> clearCalibFlag{false};
|
|
||||||
std::atomic<bool> savePosFlag{false};
|
|
||||||
std::atomic<bool> startLess{false};
|
std::atomic<bool> startLess{false};
|
||||||
|
|
||||||
void servoInit() {
|
void servoInit() {
|
||||||
@@ -142,8 +142,10 @@ void initMainLoop() {
|
|||||||
|
|
||||||
void IRAM_ATTR watchdogCallback(void* arg) {
|
void IRAM_ATTR watchdogCallback(void* arg) {
|
||||||
if (runningManual || runningServer) {
|
if (runningManual || runningServer) {
|
||||||
// if we're trying to move and our timer ran out, we need to recalibrate
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
clearCalibFlag = true;
|
main_event_type_t evt = EVENT_CLEAR_CALIB;
|
||||||
|
BaseType_t result = xQueueSendFromISR(main_event_queue, &evt, &xHigherPriorityTaskWoken);
|
||||||
|
if (result == pdPASS) portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
topEnc->pauseWatchdog();
|
topEnc->pauseWatchdog();
|
||||||
|
|
||||||
// get ready for recalibration by clearing all these listeners
|
// get ready for recalibration by clearing all these listeners
|
||||||
@@ -155,7 +157,10 @@ void IRAM_ATTR watchdogCallback(void* arg) {
|
|||||||
else {
|
else {
|
||||||
// if no movement is running, we're fine
|
// if no movement is running, we're fine
|
||||||
// save current servo-encoder position for reinitialization
|
// save current servo-encoder position for reinitialization
|
||||||
savePosFlag = true;
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
main_event_type_t evt = EVENT_SAVE_POS;
|
||||||
|
BaseType_t result = xQueueSendFromISR(main_event_queue, &evt, &xHigherPriorityTaskWoken);
|
||||||
|
if (result == pdPASS) portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
}
|
}
|
||||||
// clear running flags
|
// clear running flags
|
||||||
runningManual = false;
|
runningManual = false;
|
||||||
|
|||||||
@@ -10,8 +10,6 @@
|
|||||||
#define manual 0
|
#define manual 0
|
||||||
|
|
||||||
extern std::atomic<bool> calibListen;
|
extern std::atomic<bool> calibListen;
|
||||||
extern std::atomic<bool> clearCalibFlag;
|
|
||||||
extern std::atomic<bool> savePosFlag;
|
|
||||||
|
|
||||||
extern Encoder* topEnc;
|
extern Encoder* topEnc;
|
||||||
extern Encoder* bottomEnc;
|
extern Encoder* bottomEnc;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "setup.hpp"
|
#include "setup.hpp"
|
||||||
#include "BLE.hpp"
|
#include "BLE.hpp"
|
||||||
#include "WiFi.hpp"
|
#include "WiFi.hpp"
|
||||||
@@ -5,17 +6,31 @@
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "bmHTTP.hpp"
|
#include "bmHTTP.hpp"
|
||||||
#include "socketIO.hpp"
|
#include "socketIO.hpp"
|
||||||
|
#include "calibration.hpp"
|
||||||
|
|
||||||
TaskHandle_t setupTaskHandle = NULL;
|
TaskHandle_t setupTaskHandle = NULL;
|
||||||
|
|
||||||
|
std::atomic<bool> awaitCalibration{false};
|
||||||
|
|
||||||
void initialSetup() {
|
void initialSetup() {
|
||||||
printf("Entered Setup\n");
|
printf("Entered Setup\n");
|
||||||
NimBLEAdvertising* pAdv = initBLE();
|
initBLE();
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
||||||
|
setupTaskHandle = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupLoop(void *pvParameters) {
|
void setupAndCalibrate() {
|
||||||
TaskHandle_t parent_handle = (TaskHandle_t)pvParameters;
|
while (1) {
|
||||||
|
setupLoop();
|
||||||
|
if (awaitCalibration) {
|
||||||
|
if (calibrate()) break;
|
||||||
|
}
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setupLoop() {
|
||||||
|
setupTaskHandle = xTaskGetCurrentTaskHandle();
|
||||||
bool initSuccess = false;
|
bool initSuccess = false;
|
||||||
while(!initSuccess) {
|
while(!initSuccess) {
|
||||||
nvs_handle_t WiFiHandle;
|
nvs_handle_t WiFiHandle;
|
||||||
@@ -31,7 +46,9 @@ void setupLoop(void *pvParameters) {
|
|||||||
// Make the RGB LED a certain color (Blue?)
|
// Make the RGB LED a certain color (Blue?)
|
||||||
nvs_close(WiFiHandle);
|
nvs_close(WiFiHandle);
|
||||||
initialSetup();
|
initialSetup();
|
||||||
} else if (WiFiPrefsError == ESP_OK) {
|
continue;
|
||||||
|
}
|
||||||
|
else if (WiFiPrefsError == ESP_OK) {
|
||||||
char ssid[ssidSize];
|
char ssid[ssidSize];
|
||||||
nvs_get_str(WiFiHandle, ssidTag, ssid, &ssidSize);
|
nvs_get_str(WiFiHandle, ssidTag, ssid, &ssidSize);
|
||||||
char pw[pwSize];
|
char pw[pwSize];
|
||||||
@@ -41,6 +58,7 @@ void setupLoop(void *pvParameters) {
|
|||||||
// Make RGB LED certain color (Blue?)
|
// Make RGB LED certain color (Blue?)
|
||||||
printf("Found credentials, failed to connect.\n");
|
printf("Found credentials, failed to connect.\n");
|
||||||
initialSetup();
|
initialSetup();
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf("Connected to WiFi from NVS credentials\n");
|
printf("Connected to WiFi from NVS credentials\n");
|
||||||
@@ -55,31 +73,86 @@ void setupLoop(void *pvParameters) {
|
|||||||
// Use permanent device token to connect to Socket.IO
|
// Use permanent device token to connect to Socket.IO
|
||||||
// The server will verify the token during connection handshake
|
// The server will verify the token during connection handshake
|
||||||
webToken = std::string(token);
|
webToken = std::string(token);
|
||||||
printf("Connecting to Socket.IO server with saved token...\n");
|
cJSON* response = nullptr;
|
||||||
statusResolved = false;
|
initSuccess = httpGET("position", webToken, response);
|
||||||
initSocketIO();
|
|
||||||
|
|
||||||
// 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 (timeout_count >= MAX_TIMEOUT) {
|
|
||||||
printf("Timeout waiting for device_init - connection failed\n");
|
|
||||||
stopSocketIO();
|
|
||||||
initSuccess = false;
|
|
||||||
initialSetup();
|
|
||||||
} else {
|
|
||||||
initSuccess = connected;
|
|
||||||
if (!initSuccess) {
|
if (!initSuccess) {
|
||||||
printf("Device authentication failed - entering setup\n");
|
|
||||||
initialSetup();
|
initialSetup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
initSuccess = false;
|
||||||
|
|
||||||
|
if (response != NULL) {
|
||||||
|
// Check if response is an array
|
||||||
|
if (cJSON_IsArray(response)) {
|
||||||
|
int arraySize = cJSON_GetArraySize(response);
|
||||||
|
|
||||||
|
// Condition 1: More than one object in array
|
||||||
|
if (arraySize > 1) {
|
||||||
|
printf("Multiple peripherals detected, entering setup.\n");
|
||||||
|
cJSON_Delete(response);
|
||||||
|
initialSetup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Condition 2: Check peripheral_number in first object
|
||||||
|
else if (arraySize > 0) {
|
||||||
|
cJSON *firstObject = cJSON_GetArrayItem(response, 0);
|
||||||
|
if (firstObject != NULL) {
|
||||||
|
cJSON *peripheralNum = cJSON_GetObjectItem(firstObject, "peripheral_number");
|
||||||
|
if (cJSON_IsNumber(peripheralNum) && peripheralNum->valueint != 1) {
|
||||||
|
printf("Peripheral number is not 1, entering setup.\n");
|
||||||
|
cJSON_Delete(response);
|
||||||
|
initialSetup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Valid single peripheral with number 1, continue with normal flow
|
||||||
|
initSuccess = true;
|
||||||
|
printf("Verified new token!\n");
|
||||||
|
|
||||||
|
cJSON *awaitCalib = cJSON_GetObjectItem(firstObject, "await_calib");
|
||||||
|
if (cJSON_IsBool(awaitCalib)) awaitCalibration = awaitCalib->valueint;
|
||||||
|
cJSON_Delete(response);
|
||||||
|
if (!awaitCalibration) {
|
||||||
|
// Create calibration status object
|
||||||
|
cJSON* calibPostObj = cJSON_CreateObject();
|
||||||
|
cJSON_AddNumberToObject(calibPostObj, "port", 1);
|
||||||
|
cJSON_AddBoolToObject(calibPostObj, "calibrated", Calibration::getCalibrated());
|
||||||
|
|
||||||
|
// Send calibration status to server
|
||||||
|
cJSON* calibResponse = nullptr;
|
||||||
|
bool calibSuccess = httpPOST("report_calib_status", webToken, calibPostObj, calibResponse);
|
||||||
|
|
||||||
|
if (calibSuccess && calibResponse != NULL) {
|
||||||
|
printf("Calibration status reported successfully\n");
|
||||||
|
cJSON_Delete(calibResponse);
|
||||||
|
} else {
|
||||||
|
printf("Failed to report calibration status\n");
|
||||||
|
}
|
||||||
|
cJSON_Delete(calibPostObj);
|
||||||
|
if (!Calibration::getCalibrated()) awaitCalibration = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
printf("null object\n");
|
||||||
|
cJSON_Delete(response);
|
||||||
|
initialSetup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("no items in array\n");
|
||||||
|
cJSON_Delete(response);
|
||||||
|
initialSetup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Response not array\n");
|
||||||
|
cJSON_Delete(response);
|
||||||
|
initialSetup();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else printf("Failed to parse JSON response\n");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf("Token read unsuccessful, entering setup.\n");
|
printf("Token read unsuccessful, entering setup.\n");
|
||||||
@@ -103,6 +176,5 @@ void setupLoop(void *pvParameters) {
|
|||||||
initialSetup();
|
initialSetup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xTaskNotifyGive(parent_handle);
|
setupTaskHandle = NULL; // Clear handle on function exit (safety)
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,16 @@
|
|||||||
#ifndef SETUP_H
|
#ifndef SETUP_H
|
||||||
#define SETUP_H
|
#define SETUP_H
|
||||||
|
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
extern TaskHandle_t setupTaskHandle;
|
extern TaskHandle_t setupTaskHandle;
|
||||||
extern SemaphoreHandle_t Setup_Complete_Semaphore;
|
extern std::atomic<bool> awaitCalibration;
|
||||||
|
|
||||||
void initialSetup();
|
void initialSetup();
|
||||||
void setupLoop(void *pvParameters);
|
void setupLoop();
|
||||||
|
|
||||||
|
void setupAndCalibrate();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -11,9 +11,7 @@
|
|||||||
|
|
||||||
static esp_socketio_client_handle_t io_client;
|
static esp_socketio_client_handle_t io_client;
|
||||||
static esp_socketio_packet_handle_t tx_packet = NULL;
|
static esp_socketio_packet_handle_t tx_packet = NULL;
|
||||||
|
static bool stopSocketFlag = false;
|
||||||
std::atomic<bool> statusResolved{true};
|
|
||||||
std::atomic<bool> connected{false};
|
|
||||||
|
|
||||||
// Event handler for Socket.IO events
|
// Event handler for Socket.IO events
|
||||||
static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
||||||
@@ -65,8 +63,8 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark connection as failed
|
// Mark connection as failed
|
||||||
connected = false;
|
if (calibTaskHandle != NULL)
|
||||||
statusResolved = true;
|
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
||||||
}
|
}
|
||||||
// Handle device_init event
|
// Handle device_init event
|
||||||
else if (strcmp(eventName->valuestring, "device_init") == 0) {
|
else if (strcmp(eventName->valuestring, "device_init") == 0) {
|
||||||
@@ -91,25 +89,18 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
// TODO: UPDATE MOTOR/ENCODER STATES BASED ON THIS, as well as the successive websocket updates.
|
// TODO: UPDATE MOTOR/ENCODER STATES BASED ON THIS, as well as the successive websocket updates.
|
||||||
printf(" Port %d: pos=%d\n", port, lastPos);
|
printf(" Port %d: pos=%d\n", port, lastPos);
|
||||||
if (port != 1) printf("ERROR: NON-1 PORT RECEIVED\n");
|
if (port != 1) printf("ERROR: NON-1 PORT RECEIVED\n");
|
||||||
// Report back actual calibration status from device
|
|
||||||
else {
|
|
||||||
bool deviceCalibrated = Calibration::getCalibrated();
|
|
||||||
emitCalibStatus(deviceCalibrated);
|
|
||||||
printf(" Reported calibrated=%d for port %d\n", deviceCalibrated, port);
|
|
||||||
runToAppPos(lastPos);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now mark as connected
|
// Now mark as connected
|
||||||
connected = true;
|
if (calibTaskHandle != NULL)
|
||||||
statusResolved = true;
|
xTaskNotify(calibTaskHandle, true, eSetValueWithOverwrite);
|
||||||
} else {
|
} else {
|
||||||
printf("Device authentication failed\n");
|
printf("Device authentication failed\n");
|
||||||
Calibration::clearCalibrated();
|
Calibration::clearCalibrated();
|
||||||
deleteWiFiAndTokenDetails();
|
deleteWiFiAndTokenDetails();
|
||||||
connected = false;
|
if (calibTaskHandle != NULL)
|
||||||
statusResolved = true;
|
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,8 +116,8 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
}
|
}
|
||||||
Calibration::clearCalibrated();
|
Calibration::clearCalibrated();
|
||||||
deleteWiFiAndTokenDetails();
|
deleteWiFiAndTokenDetails();
|
||||||
connected = false;
|
if (calibTaskHandle != NULL)
|
||||||
statusResolved = true;
|
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle calib_start event
|
// Handle calib_start event
|
||||||
@@ -188,13 +179,21 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!servoCompleteCalib()) emitCalibError("Completion failed");
|
if (!servoCompleteCalib()) emitCalibError("Completion failed");
|
||||||
else emitCalibDone();
|
else {
|
||||||
|
emitCalibDone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle user_stage1_complete event
|
// Handle calib_done_ack event
|
||||||
|
else if (strcmp(eventName->valuestring, "calib_done_ack") == 0) {
|
||||||
|
printf("Server acknowledged calibration completion - safe to disconnect\n");
|
||||||
|
stopSocketFlag = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle cancel_calib event
|
||||||
else if (strcmp(eventName->valuestring, "cancel_calib") == 0) {
|
else if (strcmp(eventName->valuestring, "cancel_calib") == 0) {
|
||||||
printf("Canceling calibration process...\n");
|
printf("Canceling calibration process...\n");
|
||||||
cJSON *data = cJSON_GetArrayItem(json, 1);
|
cJSON *data = cJSON_GetArrayItem(json, 1);
|
||||||
@@ -211,37 +210,6 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle server position change (manual or scheduled)
|
|
||||||
else if (strcmp(eventName->valuestring, "posUpdates") == 0) {
|
|
||||||
printf("Received position update from server\n");
|
|
||||||
cJSON *updateList = cJSON_GetArrayItem(json, 1);
|
|
||||||
|
|
||||||
if (cJSON_IsArray(updateList)) {
|
|
||||||
int updateCount = cJSON_GetArraySize(updateList);
|
|
||||||
printf("Processing %d position update(s)\n", updateCount);
|
|
||||||
|
|
||||||
for (int i = 0; i < updateCount; i++) {
|
|
||||||
cJSON *update = cJSON_GetArrayItem(updateList, i);
|
|
||||||
cJSON *periphNum = cJSON_GetObjectItem(update, "periphNum");
|
|
||||||
cJSON *pos = cJSON_GetObjectItem(update, "pos");
|
|
||||||
|
|
||||||
if (periphNum && cJSON_IsNumber(periphNum) &&
|
|
||||||
pos && cJSON_IsNumber(pos)) {
|
|
||||||
int port = periphNum->valueint;
|
|
||||||
int position = pos->valueint;
|
|
||||||
|
|
||||||
if (port != 1)
|
|
||||||
printf("ERROR: Received position update for non-1 port: %d\n", port);
|
|
||||||
else {
|
|
||||||
printf("Position update: position %d\n", position);
|
|
||||||
runToAppPos(position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else printf("Invalid position update format\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -293,8 +261,8 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
connected = false;
|
if (calibTaskHandle != NULL)
|
||||||
statusResolved = true;
|
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,19 +270,22 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
// Handle WebSocket-level disconnections
|
// Handle WebSocket-level disconnections
|
||||||
if (data->websocket_event_id == WEBSOCKET_EVENT_DISCONNECTED) {
|
if (data->websocket_event_id == WEBSOCKET_EVENT_DISCONNECTED) {
|
||||||
printf("WebSocket disconnected\n");
|
printf("WebSocket disconnected\n");
|
||||||
connected = false;
|
if (calibTaskHandle != NULL)
|
||||||
statusResolved = true;
|
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
||||||
|
}
|
||||||
|
if (stopSocketFlag) {
|
||||||
|
if (calibTaskHandle != NULL)
|
||||||
|
xTaskNotify(calibTaskHandle, 2, eSetValueWithOverwrite);
|
||||||
|
stopSocketFlag = false; // Clear flag after notifying once
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string uriString = std::string("ws") + (secureSrv ? "s" : "") + "://" + srvAddr + "/socket.io/?EIO=4&transport=websocket";
|
const std::string uriString = std::string("ws") + (secureSrv ? "s" : "") + "://" + srvAddr + "/socket.io/?EIO=4&transport=websocket";
|
||||||
void initSocketIO() {
|
void initSocketIO() {
|
||||||
|
stopSocketFlag = false; // Reset flag for new connection
|
||||||
// Prepare the Authorization Header (Bearer format)
|
// Prepare the Authorization Header (Bearer format)
|
||||||
std::string authHeader = "Authorization: Bearer " + webToken + "\r\n";
|
std::string authHeader = "Authorization: Bearer " + webToken + "\r\n";
|
||||||
|
|
||||||
statusResolved = false;
|
|
||||||
connected = false;
|
|
||||||
|
|
||||||
esp_socketio_client_config_t config = {};
|
esp_socketio_client_config_t config = {};
|
||||||
config.websocket_config.uri = uriString.c_str();
|
config.websocket_config.uri = uriString.c_str();
|
||||||
config.websocket_config.headers = authHeader.c_str();
|
config.websocket_config.headers = authHeader.c_str();
|
||||||
@@ -338,8 +309,6 @@ void stopSocketIO() {
|
|||||||
esp_socketio_client_destroy(io_client);
|
esp_socketio_client_destroy(io_client);
|
||||||
io_client = NULL;
|
io_client = NULL;
|
||||||
tx_packet = NULL;
|
tx_packet = NULL;
|
||||||
connected = false;
|
|
||||||
statusResolved = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,6 @@
|
|||||||
#define SOCKETIO_HPP
|
#define SOCKETIO_HPP
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
extern std::atomic<bool> statusResolved;
|
|
||||||
extern std::atomic<bool> connected;
|
|
||||||
|
|
||||||
// Initialize Socket.IO client and connect to server
|
// Initialize Socket.IO client and connect to server
|
||||||
void initSocketIO();
|
void initSocketIO();
|
||||||
|
|
||||||
|
|||||||
14
src/main.cpp
14
src/main.cpp
@@ -9,17 +9,12 @@
|
|||||||
#include "encoder.hpp"
|
#include "encoder.hpp"
|
||||||
#include "calibration.hpp"
|
#include "calibration.hpp"
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
|
#include "mainEventLoop.hpp"
|
||||||
|
|
||||||
// Global encoder instances
|
// Global encoder instances
|
||||||
Encoder* topEnc = new Encoder(ENCODER_PIN_A, ENCODER_PIN_B);
|
Encoder* topEnc = new Encoder(ENCODER_PIN_A, ENCODER_PIN_B);
|
||||||
Encoder* bottomEnc = new Encoder(InputEnc_PIN_A, InputEnc_PIN_B);
|
Encoder* bottomEnc = new Encoder(InputEnc_PIN_A, InputEnc_PIN_B);
|
||||||
|
|
||||||
// Global encoder pointers (used by servo.cpp)
|
|
||||||
|
|
||||||
void MainTask(void *pvParameters) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void mainApp() {
|
void mainApp() {
|
||||||
esp_err_t ret = nvs_flash_init(); // change to secure init logic soon!!
|
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
|
// 2. If NVS is full or corrupt (common after flashing new code), erase and retry
|
||||||
@@ -37,8 +32,11 @@ void mainApp() {
|
|||||||
bottomEnc->init();
|
bottomEnc->init();
|
||||||
servoInit();
|
servoInit();
|
||||||
|
|
||||||
xTaskCreate(setupLoop, "Setup", 8192, xTaskGetCurrentTaskHandle(), 5, &setupTaskHandle);
|
setupAndCalibrate();
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
|
||||||
|
xTaskCreate(wakeTimer, "wakeTimer", 1024, NULL, 5, &wakeTaskHandle);
|
||||||
|
|
||||||
|
mainEventLoop();
|
||||||
|
|
||||||
// TOMORROW!!!
|
// TOMORROW!!!
|
||||||
// statusResolved = false;
|
// statusResolved = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user