Merge pull request #1 from pulipakaa24/TaskDrivenTrial
Task driven trial
This commit is contained in:
137
include/BLE.cpp
137
include/BLE.cpp
@@ -7,19 +7,16 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "bmHTTP.hpp"
|
#include "bmHTTP.hpp"
|
||||||
|
|
||||||
std::atomic<bool> flag_scan_requested{false};
|
|
||||||
std::atomic<bool> credsGiven{false};
|
|
||||||
std::atomic<bool> tokenGiven{false};
|
|
||||||
std::atomic<bool> isBLEClientConnected{false};
|
std::atomic<bool> isBLEClientConnected{false};
|
||||||
std::atomic<bool> scanBlock{false};
|
std::atomic<bool> scanBlock{false};
|
||||||
std::atomic<bool> finalAuth{false};
|
std::atomic<bool> finalAuth{false};
|
||||||
std::mutex dataMutex;
|
std::mutex dataMutex;
|
||||||
|
|
||||||
wifi_auth_mode_t auth;
|
wifi_auth_mode_t auth;
|
||||||
static std::string SSID = "";
|
std::string SSID = "";
|
||||||
static std::string TOKEN = "";
|
std::string TOKEN = "";
|
||||||
static std::string PASS = "";
|
std::string PASS = "";
|
||||||
static std::string UNAME = "";
|
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;
|
||||||
@@ -121,125 +118,12 @@ void notifyAuthStatus(bool success) {
|
|||||||
tmpConfChar->setValue(""); // Clear value after notify
|
tmpConfChar->setValue(""); // Clear value after notify
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BLEtick(NimBLEAdvertising* pAdvertising) {
|
// BLEtick() removed - replaced by bleSetupTask() in setup.cpp
|
||||||
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<std::mutex> 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<std::mutex> 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() {
|
void reset() {
|
||||||
esp_wifi_scan_stop();
|
esp_wifi_scan_stop();
|
||||||
if (!finalAuth) esp_wifi_disconnect();
|
if (!finalAuth) esp_wifi_disconnect();
|
||||||
scanBlock = false;
|
scanBlock = false;
|
||||||
flag_scan_requested = false;
|
|
||||||
credsGiven = false;
|
|
||||||
tokenGiven = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
|
void MyServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
|
||||||
@@ -295,7 +179,6 @@ void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connI
|
|||||||
else error = true;
|
else error = true;
|
||||||
if (error) {
|
if (error) {
|
||||||
printf("ERROR: Invalid Auth mode passed in with JSON.\n");
|
printf("ERROR: Invalid Auth mode passed in with JSON.\n");
|
||||||
credsGiven = false;
|
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -314,13 +197,13 @@ void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connI
|
|||||||
SSID = ssid->valuestring;
|
SSID = ssid->valuestring;
|
||||||
PASS = passPresent ? password->valuestring : "";
|
PASS = passPresent ? password->valuestring : "";
|
||||||
UNAME = unamePresent ? uname->valuestring : "";
|
UNAME = unamePresent ? uname->valuestring : "";
|
||||||
credsGiven = tempCredsGiven; // update the global flag.
|
// Signal via event group instead of flag
|
||||||
|
xEventGroupSetBits(g_system_events, EVENT_BLE_CREDS_RECEIVED);
|
||||||
}
|
}
|
||||||
else printf("ERROR: Did not receive necessary credentials.\n");
|
else printf("ERROR: Did not receive necessary credentials.\n");
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
} else {
|
} else {
|
||||||
printf("Failed to parse JSON\n");
|
printf("Failed to parse JSON\n");
|
||||||
credsGiven = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,14 +212,16 @@ void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connI
|
|||||||
printf("Received Token: %s\n", val.c_str());
|
printf("Received Token: %s\n", val.c_str());
|
||||||
std::lock_guard<std::mutex> lock(dataMutex);
|
std::lock_guard<std::mutex> lock(dataMutex);
|
||||||
TOKEN = val;
|
TOKEN = val;
|
||||||
tokenGiven = true;
|
// Signal via event group instead of flag
|
||||||
|
xEventGroupSetBits(g_system_events, EVENT_BLE_TOKEN_RECEIVED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pChar == currentRefreshChar) {
|
else if (pChar == currentRefreshChar) {
|
||||||
if (val == "Start") {
|
if (val == "Start") {
|
||||||
// Refresh characteristic
|
// Refresh characteristic
|
||||||
printf("Refresh Requested\n");
|
printf("Refresh Requested\n");
|
||||||
flag_scan_requested = true;
|
// Signal via event group instead of flag
|
||||||
|
xEventGroupSetBits(g_system_events, EVENT_BLE_SCAN_REQUEST);
|
||||||
}
|
}
|
||||||
else if (val == "Done") {
|
else if (val == "Done") {
|
||||||
printf("Data read complete\n");
|
printf("Data read complete\n");
|
||||||
|
|||||||
@@ -23,6 +23,6 @@ class MyCharCallbacks : public NimBLECharacteristicCallbacks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
NimBLEAdvertising* initBLE();
|
NimBLEAdvertising* initBLE();
|
||||||
bool BLEtick(NimBLEAdvertising* pAdvertising);
|
// BLEtick removed - now using event-driven bleSetupTask
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -12,8 +12,6 @@ esp_event_handler_instance_t WiFi::instance_got_ip = NULL;
|
|||||||
#define WIFI_CONNECTED_BIT BIT0
|
#define WIFI_CONNECTED_BIT BIT0
|
||||||
#define WIFI_STARTED_BIT BIT1
|
#define WIFI_STARTED_BIT BIT1
|
||||||
|
|
||||||
WiFi bmWiFi;
|
|
||||||
|
|
||||||
// The Event Handler (The engine room)
|
// The Event Handler (The engine room)
|
||||||
void WiFi::event_handler(void* arg, esp_event_base_t event_base,
|
void WiFi::event_handler(void* arg, esp_event_base_t event_base,
|
||||||
int32_t event_id, void* event_data) {
|
int32_t event_id, void* event_data) {
|
||||||
@@ -119,6 +117,16 @@ bool WiFi::isConnected() {
|
|||||||
return (bits & WIFI_CONNECTED_BIT);
|
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 ---
|
// --- GET IP AS STRING ---
|
||||||
std::string WiFi::getIP() {
|
std::string WiFi::getIP() {
|
||||||
esp_netif_ip_info_t ip_info;
|
esp_netif_ip_info_t ip_info;
|
||||||
|
|||||||
@@ -14,6 +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();
|
||||||
|
|
||||||
|
// Helper to check if auth mode requires enterprise credentials
|
||||||
|
static bool isEnterpriseMode(wifi_auth_mode_t authMode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void processScanResults();
|
static void processScanResults();
|
||||||
static std::atomic<bool> authFailed;
|
static std::atomic<bool> authFailed;
|
||||||
@@ -27,6 +31,4 @@ class WiFi {
|
|||||||
static std::string getIP();
|
static std::string getIP();
|
||||||
};
|
};
|
||||||
|
|
||||||
extern WiFi bmWiFi;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -2,6 +2,11 @@
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
|
|
||||||
|
// Define static members
|
||||||
|
std::atomic<int32_t> Calibration::DownTicks{0};
|
||||||
|
std::atomic<int32_t> Calibration::UpTicks{0};
|
||||||
|
std::atomic<bool> Calibration::calibrated{false};
|
||||||
|
|
||||||
void Calibration::init() {
|
void Calibration::init() {
|
||||||
nvs_handle_t calibHandle;
|
nvs_handle_t calibHandle;
|
||||||
if (nvs_open(nvsCalib, NVS_READONLY, &calibHandle) == ESP_OK) {
|
if (nvs_open(nvsCalib, NVS_READONLY, &calibHandle) == ESP_OK) {
|
||||||
|
|||||||
@@ -5,20 +5,18 @@
|
|||||||
|
|
||||||
class Calibration {
|
class Calibration {
|
||||||
public:
|
public:
|
||||||
void init();
|
static void init();
|
||||||
bool beginDownwardCalib(Encoder& topEnc);
|
static bool beginDownwardCalib(Encoder& topEnc);
|
||||||
bool completeCalib(Encoder& topEnc);
|
static bool completeCalib(Encoder& topEnc);
|
||||||
int32_t convertToTicks(uint8_t appPos);
|
static int32_t convertToTicks(uint8_t appPos);
|
||||||
uint8_t convertToAppPos(int32_t ticks);
|
static uint8_t convertToAppPos(int32_t ticks);
|
||||||
bool getCalibrated() {return calibrated;}
|
static bool getCalibrated() {return calibrated;}
|
||||||
bool clearCalibrated();
|
static bool clearCalibrated();
|
||||||
std::atomic<int32_t> DownTicks;
|
static std::atomic<int32_t> DownTicks;
|
||||||
std::atomic<int32_t> UpTicks;
|
static std::atomic<int32_t> UpTicks;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::atomic<bool> calibrated;
|
static std::atomic<bool> calibrated;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Calibration calib;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -2,6 +2,33 @@
|
|||||||
#define DEFINES_H
|
#define DEFINES_H
|
||||||
#include "driver/gpio.h"
|
#include "driver/gpio.h"
|
||||||
#include "driver/ledc.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 ccwSpeed 6500
|
||||||
#define cwSpeed 3300
|
#define cwSpeed 3300
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
#include "soc/gpio_struct.h"
|
#include "soc/gpio_struct.h"
|
||||||
#include "servo.hpp"
|
#include "servo.hpp"
|
||||||
|
#include "defines.h"
|
||||||
|
|
||||||
static const char *TAG = "ENCODER";
|
static const char *TAG = "ENCODER";
|
||||||
|
|
||||||
@@ -48,26 +49,32 @@ void IRAM_ATTR Encoder::isr_handler(void* arg)
|
|||||||
if (encoder->last_count_base > 3) {
|
if (encoder->last_count_base > 3) {
|
||||||
encoder->count += 1;
|
encoder->count += 1;
|
||||||
encoder->last_count_base -= 4;
|
encoder->last_count_base -= 4;
|
||||||
if (calibListen) servoCalibListen();
|
|
||||||
if (encoder->feedWDog) {
|
// DEFER to task via queue instead of direct function calls
|
||||||
esp_timer_stop(encoder->watchdog_handle);
|
encoder_event_t event = {
|
||||||
esp_timer_start_once(encoder->watchdog_handle, 500000);
|
.count = encoder->count.load(),
|
||||||
debugLEDTgl();
|
.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 (encoder->wandListen) servoWandListen();
|
|
||||||
if (encoder->serverListen) servoServerListen();
|
|
||||||
}
|
}
|
||||||
else if (encoder->last_count_base < 0) {
|
else if (encoder->last_count_base < 0) {
|
||||||
encoder->count -= 1;
|
encoder->count -= 1;
|
||||||
encoder->last_count_base += 4;
|
encoder->last_count_base += 4;
|
||||||
if (calibListen) servoCalibListen();
|
|
||||||
if (encoder->feedWDog) {
|
// DEFER to task via queue instead of direct function calls
|
||||||
esp_timer_stop(encoder->watchdog_handle);
|
encoder_event_t event = {
|
||||||
esp_timer_start_once(encoder->watchdog_handle, 500000);
|
.count = encoder->count.load(),
|
||||||
debugLEDTgl();
|
.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 (encoder->wandListen) servoWandListen();
|
|
||||||
if (encoder->serverListen) servoServerListen();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
encoder->last_state_a = current_a;
|
encoder->last_state_a = current_a;
|
||||||
|
|||||||
@@ -4,6 +4,12 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include "esp_timer.h"
|
#include "esp_timer.h"
|
||||||
|
|
||||||
|
// Encoder event structure for queue
|
||||||
|
typedef struct {
|
||||||
|
int32_t count;
|
||||||
|
bool is_top_encoder;
|
||||||
|
} encoder_event_t;
|
||||||
|
|
||||||
class Encoder {
|
class Encoder {
|
||||||
public:
|
public:
|
||||||
// Shared between ISR and main code
|
// Shared between ISR and main code
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ void servoInit() {
|
|||||||
gpio_set_level(debugLED, 0); // Start with LED off
|
gpio_set_level(debugLED, 0); // Start with LED off
|
||||||
|
|
||||||
topEnc->count = servoReadPos();
|
topEnc->count = servoReadPos();
|
||||||
if (calib.getCalibrated()) initMainLoop();
|
if (Calibration::getCalibrated()) initMainLoop();
|
||||||
debugLEDSwitch(1);
|
debugLEDSwitch(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ bool servoInitCalib() {
|
|||||||
bottomEnc->wandListen.store(false, std::memory_order_release);
|
bottomEnc->wandListen.store(false, std::memory_order_release);
|
||||||
topEnc->wandListen.store(false, std::memory_order_release);
|
topEnc->wandListen.store(false, std::memory_order_release);
|
||||||
topEnc->serverListen.store(false, std::memory_order_release);
|
topEnc->serverListen.store(false, std::memory_order_release);
|
||||||
if (!calib.clearCalibrated()) return false;
|
if (!Calibration::clearCalibrated()) return false;
|
||||||
if (topEnc == nullptr || bottomEnc == nullptr) {
|
if (topEnc == nullptr || bottomEnc == nullptr) {
|
||||||
printf("ERROR: CALIBRATION STARTED BEFORE SERVO INITIALIZATION\n");
|
printf("ERROR: CALIBRATION STARTED BEFORE SERVO INITIALIZATION\n");
|
||||||
return false;
|
return false;
|
||||||
@@ -117,7 +117,7 @@ bool servoBeginDownwardCalib() {
|
|||||||
calibListen = false;
|
calibListen = false;
|
||||||
servoOff();
|
servoOff();
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
if (!calib.beginDownwardCalib(*topEnc)) return false;
|
if (!Calibration::beginDownwardCalib(*topEnc)) return false;
|
||||||
baseDiff = bottomEnc->getCount() - topEnc->getCount();
|
baseDiff = bottomEnc->getCount() - topEnc->getCount();
|
||||||
calibListen = true;
|
calibListen = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -127,7 +127,7 @@ bool servoCompleteCalib() {
|
|||||||
calibListen = false;
|
calibListen = false;
|
||||||
servoOff();
|
servoOff();
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
if (!calib.completeCalib(*topEnc)) return false;
|
if (!Calibration::completeCalib(*topEnc)) return false;
|
||||||
initMainLoop();
|
initMainLoop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -139,9 +139,11 @@ void initMainLoop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IRAM_ATTR watchdogCallback(void* arg) {
|
void IRAM_ATTR watchdogCallback(void* arg) {
|
||||||
|
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||||
|
|
||||||
if (runningManual || runningServer) {
|
if (runningManual || runningServer) {
|
||||||
// if we're trying to move and our timer ran out, we need to recalibrate
|
// if we're trying to move and our timer ran out, we need to recalibrate
|
||||||
clearCalibFlag = true;
|
xEventGroupSetBitsFromISR(g_system_events, EVENT_CLEAR_CALIB, &xHigherPriorityTaskWoken);
|
||||||
topEnc->pauseWatchdog();
|
topEnc->pauseWatchdog();
|
||||||
|
|
||||||
// get ready for recalibration by clearing all these listeners
|
// get ready for recalibration by clearing all these listeners
|
||||||
@@ -153,11 +155,13 @@ 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;
|
xEventGroupSetBitsFromISR(g_system_events, EVENT_SAVE_POSITION, &xHigherPriorityTaskWoken);
|
||||||
}
|
}
|
||||||
// clear running flags
|
// clear running flags
|
||||||
runningManual = false;
|
runningManual = false;
|
||||||
runningServer = false;
|
runningServer = false;
|
||||||
|
|
||||||
|
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||||
}
|
}
|
||||||
|
|
||||||
void servoSavePos() {
|
void servoSavePos() {
|
||||||
@@ -203,8 +207,8 @@ void servoWandListen() {
|
|||||||
stopServerRun();
|
stopServerRun();
|
||||||
|
|
||||||
// freeze atomic values
|
// freeze atomic values
|
||||||
int32_t upBound = calib.UpTicks;
|
int32_t upBound = Calibration::UpTicks;
|
||||||
int32_t downBound = calib.DownTicks;
|
int32_t downBound = Calibration::DownTicks;
|
||||||
int32_t bottomCount = bottomEnc->getCount();
|
int32_t bottomCount = bottomEnc->getCount();
|
||||||
int32_t topCount = topEnc->getCount();
|
int32_t topCount = topEnc->getCount();
|
||||||
|
|
||||||
@@ -257,10 +261,10 @@ void servoServerListen() {
|
|||||||
void runToAppPos(uint8_t appPos) {
|
void runToAppPos(uint8_t appPos) {
|
||||||
// manual control takes precedence over remote control, always.
|
// manual control takes precedence over remote control, always.
|
||||||
// also do not begin operation if not calibrated;
|
// also do not begin operation if not calibrated;
|
||||||
if (runningManual || !calib.getCalibrated()) return;
|
if (runningManual || !Calibration::getCalibrated()) return;
|
||||||
servoOff();
|
servoOff();
|
||||||
|
|
||||||
target = calib.convertToTicks(appPos); // calculate target encoder position
|
target = Calibration::convertToTicks(appPos); // calculate target encoder position
|
||||||
printf("runToAppPos Called, running to %d from %d", target.load(), topEnc->getCount());
|
printf("runToAppPos Called, running to %d from %d", target.load(), topEnc->getCount());
|
||||||
|
|
||||||
// allow servo position to settle
|
// allow servo position to settle
|
||||||
@@ -273,3 +277,68 @@ void runToAppPos(uint8_t appPos) {
|
|||||||
else servoOn(CW, server);
|
else servoOn(CW, server);
|
||||||
topEnc->serverListen.store(true, std::memory_order_release); // start listening for shutoff point
|
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) {
|
||||||
|
int32_t effDiff = (bottomEnc->getCount() - topEnc->getCount()) - baseDiff;
|
||||||
|
if (effDiff > 1) {
|
||||||
|
servoOn(CCW, manual);
|
||||||
|
}
|
||||||
|
else if (effDiff < -1) {
|
||||||
|
servoOn(CW, manual);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
servoOff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_restart(topEnc->watchdog_handle, 500000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check wand listener - now safe in task context
|
||||||
|
if (topEnc->wandListen) {
|
||||||
|
servoWandListen();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check server listener - now safe in task context
|
||||||
|
if (topEnc->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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,20 @@
|
|||||||
#define server 1
|
#define server 1
|
||||||
#define manual 0
|
#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<bool> calibListen;
|
extern std::atomic<bool> calibListen;
|
||||||
extern std::atomic<bool> clearCalibFlag;
|
extern std::atomic<bool> clearCalibFlag;
|
||||||
extern std::atomic<bool> savePosFlag;
|
extern std::atomic<bool> savePosFlag;
|
||||||
@@ -38,4 +52,7 @@ void servoWandListen();
|
|||||||
void servoServerListen();
|
void servoServerListen();
|
||||||
void runToAppPos(uint8_t appPos);
|
void runToAppPos(uint8_t appPos);
|
||||||
|
|
||||||
|
// Servo control task
|
||||||
|
void servoControlTask(void* arg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -5,14 +5,147 @@
|
|||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include "bmHTTP.hpp"
|
#include "bmHTTP.hpp"
|
||||||
#include "socketIO.hpp"
|
#include "socketIO.hpp"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
// 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<bool> scanBlock;
|
||||||
|
extern std::atomic<bool> 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<std::mutex> 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<std::mutex> 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() {
|
void initialSetup() {
|
||||||
printf("Entered Setup\n");
|
printf("Entered Setup\n");
|
||||||
NimBLEAdvertising* pAdv = initBLE();
|
|
||||||
|
|
||||||
while (!BLEtick(pAdv)) {
|
// 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) {
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
printf("BLE setup complete\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupLoop() {
|
void setupLoop() {
|
||||||
@@ -37,7 +170,7 @@ void setupLoop() {
|
|||||||
char pw[pwSize];
|
char pw[pwSize];
|
||||||
nvs_get_str(WiFiHandle, passTag, pw, &pwSize);
|
nvs_get_str(WiFiHandle, passTag, pw, &pwSize);
|
||||||
nvs_close(WiFiHandle);
|
nvs_close(WiFiHandle);
|
||||||
if (!bmWiFi.attemptConnect(ssid, pw, (wifi_auth_mode_t)authMode)) {
|
if (!WiFi::attemptConnect(ssid, pw, (wifi_auth_mode_t)authMode)) {
|
||||||
// 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();
|
||||||
@@ -56,29 +189,28 @@ void setupLoop() {
|
|||||||
// 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");
|
printf("Connecting to Socket.IO server with saved token...\n");
|
||||||
statusResolved = false;
|
|
||||||
initSocketIO();
|
initSocketIO();
|
||||||
|
|
||||||
// Wait for device_init message from server with timeout
|
// Wait for connection event with timeout
|
||||||
int timeout_count = 0;
|
EventBits_t bits = xEventGroupWaitBits(
|
||||||
const int MAX_TIMEOUT = 60; // 10 seconds (20 * 500ms)
|
g_system_events,
|
||||||
while (!statusResolved && timeout_count < MAX_TIMEOUT) {
|
EVENT_SOCKETIO_CONNECTED | EVENT_SOCKETIO_DISCONNECTED,
|
||||||
printf("Waiting for device_init message... (%d/%d)\n", timeout_count, MAX_TIMEOUT);
|
pdTRUE, // Clear on exit
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
pdFALSE, // Wait for ANY bit
|
||||||
timeout_count++;
|
pdMS_TO_TICKS(10000) // 10 second timeout
|
||||||
}
|
);
|
||||||
|
|
||||||
if (timeout_count >= MAX_TIMEOUT) {
|
if (bits & EVENT_SOCKETIO_CONNECTED) {
|
||||||
printf("Timeout waiting for device_init - connection failed\n");
|
|
||||||
stopSocketIO();
|
|
||||||
initSuccess = false;
|
|
||||||
initialSetup();
|
|
||||||
} else {
|
|
||||||
initSuccess = connected;
|
initSuccess = connected;
|
||||||
if (!initSuccess) {
|
if (!initSuccess) {
|
||||||
printf("Device authentication failed - entering setup\n");
|
printf("Device authentication failed - entering setup\n");
|
||||||
initialSetup();
|
initialSetup();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
printf("Timeout waiting for connection\n");
|
||||||
|
stopSocketIO();
|
||||||
|
initSuccess = false;
|
||||||
|
initialSetup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
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;
|
||||||
|
|
||||||
std::atomic<bool> statusResolved{true};
|
|
||||||
std::atomic<bool> connected{false};
|
std::atomic<bool> connected{false};
|
||||||
|
|
||||||
// Event handler for Socket.IO events
|
// Event handler for Socket.IO events
|
||||||
@@ -66,7 +65,7 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
|
|
||||||
// Mark connection as failed
|
// Mark connection as failed
|
||||||
connected = false;
|
connected = false;
|
||||||
statusResolved = true;
|
xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED);
|
||||||
}
|
}
|
||||||
// Handle device_init event
|
// Handle device_init event
|
||||||
else if (strcmp(eventName->valuestring, "device_init") == 0) {
|
else if (strcmp(eventName->valuestring, "device_init") == 0) {
|
||||||
@@ -93,7 +92,7 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
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
|
// Report back actual calibration status from device
|
||||||
else {
|
else {
|
||||||
bool deviceCalibrated = calib.getCalibrated();
|
bool deviceCalibrated = Calibration::getCalibrated();
|
||||||
emitCalibStatus(deviceCalibrated);
|
emitCalibStatus(deviceCalibrated);
|
||||||
printf(" Reported calibrated=%d for port %d\n", deviceCalibrated, port);
|
printf(" Reported calibrated=%d for port %d\n", deviceCalibrated, port);
|
||||||
runToAppPos(lastPos);
|
runToAppPos(lastPos);
|
||||||
@@ -103,13 +102,13 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
|
|
||||||
// Now mark as connected
|
// Now mark as connected
|
||||||
connected = true;
|
connected = true;
|
||||||
statusResolved = true;
|
xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_CONNECTED);
|
||||||
} else {
|
} else {
|
||||||
printf("Device authentication failed\n");
|
printf("Device authentication failed\n");
|
||||||
calib.clearCalibrated();
|
Calibration::clearCalibrated();
|
||||||
deleteWiFiAndTokenDetails();
|
deleteWiFiAndTokenDetails();
|
||||||
connected = false;
|
connected = false;
|
||||||
statusResolved = true;
|
xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,10 +122,10 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
printf("Server message: %s\n", message->valuestring);
|
printf("Server message: %s\n", message->valuestring);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
calib.clearCalibrated();
|
Calibration::clearCalibrated();
|
||||||
deleteWiFiAndTokenDetails();
|
deleteWiFiAndTokenDetails();
|
||||||
connected = false;
|
connected = false;
|
||||||
statusResolved = true;
|
xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle calib_start event
|
// Handle calib_start event
|
||||||
@@ -293,8 +292,9 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Signal disconnection via event group
|
||||||
connected = false;
|
connected = false;
|
||||||
statusResolved = true;
|
xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED);
|
||||||
break;
|
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) {
|
if (data->websocket_event_id == WEBSOCKET_EVENT_DISCONNECTED) {
|
||||||
printf("WebSocket disconnected\n");
|
printf("WebSocket disconnected\n");
|
||||||
connected = false;
|
connected = false;
|
||||||
statusResolved = true;
|
xEventGroupSetBits(g_system_events, EVENT_SOCKETIO_DISCONNECTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,7 +312,6 @@ void initSocketIO() {
|
|||||||
// 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;
|
connected = false;
|
||||||
|
|
||||||
esp_socketio_client_config_t config = {};
|
esp_socketio_client_config_t config = {};
|
||||||
@@ -339,7 +338,6 @@ void stopSocketIO() {
|
|||||||
io_client = NULL;
|
io_client = NULL;
|
||||||
tx_packet = NULL;
|
tx_packet = NULL;
|
||||||
connected = false;
|
connected = false;
|
||||||
statusResolved = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
#define SOCKETIO_HPP
|
#define SOCKETIO_HPP
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
extern std::atomic<bool> statusResolved;
|
|
||||||
extern std::atomic<bool> connected;
|
extern std::atomic<bool> connected;
|
||||||
|
|
||||||
// Initialize Socket.IO client and connect to server
|
// Initialize Socket.IO client and connect to server
|
||||||
|
|||||||
109
src/main.cpp
109
src/main.cpp
@@ -9,67 +9,58 @@
|
|||||||
#include "encoder.hpp"
|
#include "encoder.hpp"
|
||||||
#include "calibration.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
|
// 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* arg) {
|
||||||
|
EventBits_t bits;
|
||||||
|
|
||||||
// Global calibration instance
|
printf("Main task started - event-driven mode\n");
|
||||||
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();
|
|
||||||
|
|
||||||
// Initialize encoders
|
|
||||||
topEnc->init();
|
|
||||||
bottomEnc->init();
|
|
||||||
servoInit();
|
|
||||||
|
|
||||||
setupLoop();
|
|
||||||
|
|
||||||
statusResolved = false;
|
|
||||||
|
|
||||||
int32_t prevCount = topEnc->getCount();
|
|
||||||
|
|
||||||
// Main loop
|
|
||||||
while (1) {
|
while (1) {
|
||||||
// websocket disconnect/reconnect handling
|
// Block waiting for ANY event (no polling!)
|
||||||
if (statusResolved) {
|
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) {
|
||||||
if (!connected) {
|
if (!connected) {
|
||||||
printf("Disconnected! Beginning setup loop.\n");
|
printf("Disconnected! Beginning setup loop.\n");
|
||||||
stopSocketIO();
|
stopSocketIO();
|
||||||
setupLoop();
|
setupLoop();
|
||||||
}
|
}
|
||||||
else printf("Reconnected!\n");
|
else {
|
||||||
statusResolved = false;
|
printf("Reconnected!\n");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clearCalibFlag) {
|
if (bits & EVENT_CLEAR_CALIB) {
|
||||||
calib.clearCalibrated();
|
xSemaphoreTake(g_calibration_mutex, portMAX_DELAY);
|
||||||
|
Calibration::clearCalibrated();
|
||||||
|
xSemaphoreGive(g_calibration_mutex);
|
||||||
emitCalibStatus(false);
|
emitCalibStatus(false);
|
||||||
clearCalibFlag = false;
|
|
||||||
}
|
}
|
||||||
if (savePosFlag) {
|
|
||||||
|
if (bits & EVENT_SAVE_POSITION) {
|
||||||
servoSavePos();
|
servoSavePos();
|
||||||
savePosFlag = false;
|
|
||||||
|
|
||||||
// Send position update to server
|
// Send position update to server
|
||||||
uint8_t currentAppPos = calib.convertToAppPos(topEnc->getCount());
|
uint8_t currentAppPos = Calibration::convertToAppPos(topEnc->getCount());
|
||||||
emitPosHit(currentAppPos);
|
emitPosHit(currentAppPos);
|
||||||
|
|
||||||
printf("Sent pos_hit: position %d\n", currentAppPos);
|
printf("Sent pos_hit: position %d\n", currentAppPos);
|
||||||
}
|
}
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,6 +82,44 @@ void encoderTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void app_main() {
|
extern "C" void app_main() {
|
||||||
mainApp();
|
// Initialize NVS first
|
||||||
// encoderTest();
|
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");
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user