This commit is contained in:
2026-01-10 02:45:26 -06:00
parent 03ca64080c
commit 0fd4db453d
10 changed files with 374 additions and 251 deletions

View File

@@ -6,10 +6,10 @@
#include "defines.h"
#include <mutex>
#include "bmHTTP.hpp"
#include <freertos/queue.h>
#include "setup.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> scanBlock{false};
std::atomic<bool> finalAuth{false};
@@ -29,7 +29,14 @@ std::atomic<NimBLECharacteristic*> credsChar = nullptr;
std::atomic<NimBLECharacteristic*> tokenChar = nullptr;
std::atomic<NimBLECharacteristic*> ssidRefreshChar = nullptr;
static QueueHandle_t BLE_event_queue = NULL;
static TaskHandle_t BLE_manager_task_handle = NULL;
SemaphoreHandle_t BLE_Queue_Shutdown_Semaphore = NULL;
NimBLEAdvertising* initBLE() {
BLE_event_queue = xQueueCreate(10, sizeof(BLE_event_type_t));
xTaskCreate(BLE_manager_task, "BLE", 8192, NULL, 5, &BLE_manager_task_handle);
finalAuth = false;
NimBLEDevice::init("BlindMaster-C6");
@@ -120,126 +127,18 @@ void notifyAuthStatus(bool success) {
tmpConfChar->notify();
tmpConfChar->setValue(""); // Clear value after notify
}
bool BLEtick(NimBLEAdvertising* pAdvertising) {
printf("BleTick\n");
if(flag_scan_requested) {
flag_scan_requested = false;
if (!scanBlock) {
scanBlock = true;
printf("Scanning WiFi...\n");
bmWiFi.scanAndUpdateSSIDList();
}
else printf("Duplicate scan request\n");
}
else if (credsGiven) {
std::string tmpSSID;
std::string tmpUNAME;
std::string tmpPASS;
wifi_auth_mode_t tmpAUTH;
{
std::lock_guard<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() {
BLE_Queue_Shutdown_Semaphore = xSemaphoreCreateBinary();
BLE_event_type_t event_type = EVENT_SHUTDOWN;
xQueueSend(BLE_event_queue, &event_type, portMAX_DELAY);
xSemaphoreTake(BLE_Queue_Shutdown_Semaphore, portMAX_DELAY);
vQueueDelete(BLE_event_queue);
esp_wifi_scan_stop();
if (!finalAuth) esp_wifi_disconnect();
scanBlock = false;
flag_scan_requested = false;
credsGiven = false;
tokenGiven = false;
vSemaphoreDelete(BLE_Queue_Shutdown_Semaphore);
BLE_event_queue = xQueueCreate(10, sizeof(BLE_event_type_t));
xTaskCreate(BLE_manager_task, "BLE", 8192, NULL, 5, &BLE_manager_task_handle);
}
void MyServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
@@ -259,89 +158,231 @@ void MyCharCallbacks::onRead(NimBLECharacteristic* pChar, NimBLEConnInfo& connIn
}
void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connInfo) {
std::string val = pChar->getValue();
std::string uuidStr = pChar->getUUID().toString();
printf("onWrite called! UUID: %s, Value length: %d\n", uuidStr.c_str(), val.length());
// Load atomic pointers for comparison
NimBLECharacteristic* currentCredsChar = credsChar.load();
NimBLECharacteristic* currentTokenChar = tokenChar.load();
NimBLECharacteristic* currentRefreshChar = ssidRefreshChar.load();
// Check which characteristic was written to
if (pChar == currentCredsChar) {
// Credentials JSON characteristic
if (val.length() > 0) {
printf("Received JSON: %s\n", val.c_str());
std::string val = pChar->getValue();
std::string uuidStr = pChar->getUUID().toString();
printf("onWrite called! UUID: %s, Value length: %d\n", uuidStr.c_str(), val.length());
// Load atomic pointers for comparison
NimBLECharacteristic* currentCredsChar = credsChar.load();
NimBLECharacteristic* currentTokenChar = tokenChar.load();
NimBLECharacteristic* currentRefreshChar = ssidRefreshChar.load();
// Check which characteristic was written to
if (pChar == currentCredsChar) {
// Credentials JSON characteristic
if (val.length() > 0) {
printf("Received JSON: %s\n", val.c_str());
// Parse JSON using cJSON
cJSON *root = cJSON_Parse(val.c_str());
if (root != NULL) {
cJSON *ssid = cJSON_GetObjectItem(root, "ssid");
cJSON *password = cJSON_GetObjectItem(root, "password");
cJSON *authType = cJSON_GetObjectItem(root, "auth");
cJSON *uname = cJSON_GetObjectItem(root, "uname");
// Parse JSON using cJSON
cJSON *root = cJSON_Parse(val.c_str());
if (root != NULL) {
cJSON *ssid = cJSON_GetObjectItem(root, "ssid");
cJSON *password = cJSON_GetObjectItem(root, "password");
cJSON *authType = cJSON_GetObjectItem(root, "auth");
cJSON *uname = cJSON_GetObjectItem(root, "uname");
bool enterprise = false;
bool open = false;
bool error = false;
if (cJSON_IsNumber(authType)) {
enterprise = authType->valueint == WIFI_AUTH_WPA2_ENTERPRISE ||
authType->valueint == WIFI_AUTH_WPA3_ENTERPRISE;
open = authType->valueint == WIFI_AUTH_OPEN;
error = authType->valueint < 0 || authType->valueint >= WIFI_AUTH_MAX;
}
else error = true;
if (error) {
printf("ERROR: Invalid Auth mode passed in with JSON.\n");
credsGiven = false;
cJSON_Delete(root);
return;
}
bool ssidPresent = cJSON_IsString(ssid) && ssid->valuestring != NULL;
bool passPresent = cJSON_IsString(password) && password->valuestring != NULL;
bool unamePresent = cJSON_IsString(uname) && uname->valuestring != NULL;
bool tempCredsGiven = ssidPresent && (passPresent || open) &&
(unamePresent || !enterprise);
if (tempCredsGiven) {
printf("Received credentials, will attempt connection\n");
bool enterprise = false;
bool open = false;
bool error = false;
if (cJSON_IsNumber(authType)) {
enterprise = authType->valueint == WIFI_AUTH_WPA2_ENTERPRISE ||
authType->valueint == WIFI_AUTH_WPA3_ENTERPRISE;
open = authType->valueint == WIFI_AUTH_OPEN;
error = authType->valueint < 0 || authType->valueint >= WIFI_AUTH_MAX;
}
else error = true;
if (error) {
printf("ERROR: Invalid Auth mode passed in with JSON.\n");
cJSON_Delete(root);
return;
}
bool ssidPresent = cJSON_IsString(ssid) && ssid->valuestring != NULL;
bool passPresent = cJSON_IsString(password) && password->valuestring != NULL;
bool unamePresent = cJSON_IsString(uname) && uname->valuestring != NULL;
bool tempCredsGiven = ssidPresent && (passPresent || open) &&
(unamePresent || !enterprise);
if (tempCredsGiven) {
printf("Received credentials, will attempt connection\n");
{
std::lock_guard<std::mutex> lock(dataMutex);
auth = (wifi_auth_mode_t)(authType->valueint);
SSID = ssid->valuestring;
PASS = passPresent ? password->valuestring : "";
UNAME = unamePresent ? uname->valuestring : "";
credsGiven = tempCredsGiven; // update the global flag.
}
else printf("ERROR: Did not receive necessary credentials.\n");
cJSON_Delete(root);
} else {
printf("Failed to parse JSON\n");
credsGiven = false;
BLE_event_type_t event_type = EVENT_CREDS_GIVEN;
if (xQueueSend(BLE_event_queue, &event_type, pdMS_TO_TICKS(10)) == pdPASS)
printf("Successfully added credsGiven to event queue\n");
else printf("CredsGiven event queue addition failed\n");
}
else printf("ERROR: Did not receive necessary credentials.\n");
cJSON_Delete(root);
} else {
printf("Failed to parse JSON\n");
}
}
else if (pChar == currentTokenChar) {
if (val.length() > 0) {
printf("Received Token: %s\n", val.c_str());
}
else if (pChar == currentTokenChar) {
if (val.length() > 0) {
printf("Received Token: %s\n", val.c_str());
{
std::lock_guard<std::mutex> lock(dataMutex);
TOKEN = val;
tokenGiven = true;
}
BLE_event_type_t event_type = EVENT_TOKEN_GIVEN;
if (xQueueSend(BLE_event_queue, &event_type, pdMS_TO_TICKS(10)) == pdPASS)
printf("Successfully added tokenGiven to event queue\n");
else printf("TokenGiven event queue addition failed\n");
}
else if (pChar == currentRefreshChar) {
if (val == "Start") {
// Refresh characteristic
}
else if (pChar == currentRefreshChar) {
if (val == "Start") {
// Refresh characteristic
BLE_event_type_t event_type = EVENT_SCAN_REQUESTED;
if (xQueueSend(BLE_event_queue, &event_type, pdMS_TO_TICKS(10)) == pdPASS) {
printf("Event queue addition success for scan start\n");
}
else printf("Scan start event queue addition failed\n");
}
else if (val == "Done") {
printf("Data read complete\n");
scanBlock = false;
}
}
else printf("Unknown UUID: %s\n", uuidStr.c_str());
}
void BLE_manager_task(void *pvParameters) {
BLE_event_type_t received_event_type;
while (true) {
if (xQueueReceive(BLE_event_queue, &received_event_type, portMAX_DELAY)) {
if (received_event_type == EVENT_SCAN_REQUESTED) {
printf("Refresh Requested\n");
flag_scan_requested = true;
if (!scanBlock) {
scanBlock = true;
printf("Scanning WiFi...\n");
bmWiFi.scanAndUpdateSSIDList();
}
else printf("Duplicate scan request\n");
}
else if (val == "Done") {
printf("Data read complete\n");
scanBlock = false;
else if (received_event_type == EVENT_TOKEN_GIVEN) {
if (tokenCheck()) {
vQueueDelete(BLE_event_queue);
if (setupTaskHandle != NULL) {
xTaskNotifyGive(setupTaskHandle);
printf("Setup complete.\n");
}
break;
}
}
else if (received_event_type == EVENT_CREDS_GIVEN)
attemptUseWiFiCreds();
else if (received_event_type == EVENT_SHUTDOWN) break;
}
else printf("Unknown UUID: %s\n", uuidStr.c_str());
}
}
xSemaphoreGive(BLE_Queue_Shutdown_Semaphore);
vTaskDelete(NULL);
}
bool tokenCheck() {
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;
}
bool attemptUseWiFiCreds() {
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 (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;
}
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;
}
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);
}
}

View File

@@ -23,6 +23,17 @@ class MyCharCallbacks : public NimBLECharacteristicCallbacks {
};
NimBLEAdvertising* initBLE();
bool BLEtick(NimBLEAdvertising* pAdvertising);
void BLE_manager_task(void *pvParameters);
// Event Types
typedef enum {
EVENT_SCAN_REQUESTED,
EVENT_TOKEN_GIVEN,
EVENT_CREDS_GIVEN,
EVENT_SHUTDOWN
} BLE_event_type_t;
bool tokenCheck();
#endif

44
include/bmEvents.cpp Normal file
View File

@@ -0,0 +1,44 @@
#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");
// }
// }

9
include/bmEvents.hpp Normal file
View File

@@ -0,0 +1,9 @@
#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);
#endif

View File

@@ -23,7 +23,7 @@ void servoInit() {
ledc_timer.timer_num = LEDC_TIMER_0;
ledc_timer.duty_resolution = LEDC_TIMER_16_BIT;
ledc_timer.freq_hz = 50;
ledc_timer.clk_cfg = LEDC_AUTO_CLK;
ledc_timer.clk_cfg = LEDC_USE_RC_FAST_CLK;
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
// LEDC channel configuration
@@ -35,7 +35,9 @@ void servoInit() {
ledc_channel.gpio_num = servoPin;
ledc_channel.duty = offSpeed; // Start off
ledc_channel.hpoint = 0;
ledc_channel.sleep_mode = LEDC_SLEEP_MODE_KEEP_ALIVE;
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
gpio_sleep_sel_dis(servoPin);
// Configure servo power switch pin as output
gpio_set_direction(servoSwitch, GPIO_MODE_OUTPUT);

View File

@@ -6,16 +6,15 @@
#include "bmHTTP.hpp"
#include "socketIO.hpp"
TaskHandle_t setupTaskHandle = NULL;
void initialSetup() {
printf("Entered Setup\n");
NimBLEAdvertising* pAdv = initBLE();
while (!BLEtick(pAdv)) {
vTaskDelay(pdMS_TO_TICKS(100));
}
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
}
void setupLoop() {
void setupLoop(void *pvParameters) {
bool initSuccess = false;
while(!initSuccess) {
nvs_handle_t WiFiHandle;

View File

@@ -1,7 +1,9 @@
#ifndef SETUP_H
#define SETUP_H
extern TaskHandle_t setupTaskHandle;
void initialSetup();
void setupLoop();
void setupLoop(void *pvParameters);
#endif