Compilable version with wifi support - need to test

This commit is contained in:
2025-11-29 16:24:56 -06:00
parent 8bb08d2819
commit d6dfa5d681
9 changed files with 320 additions and 28 deletions

2
.gitignore vendored
View File

@@ -3,3 +3,5 @@
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
.DS_Store

68
.vscode/settings.json vendored
View File

@@ -1,5 +1,71 @@
{
"files.associations": {
"nimbledevice.h": "c"
"nimbledevice.h": "c",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"format": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"semaphore": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"text_encoding": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"variant": "cpp"
}
}

View File

@@ -4,8 +4,8 @@
bool flag_scan_requested = false;
std::string SSID = "";
std::string password = "";
std::string tempSSID = "";
std::string tempPassword = "";
bool SSIDGiven = false;
bool passGiven = false;

View File

@@ -5,8 +5,8 @@
extern bool flag_scan_requested;
extern std::string SSID;
extern std::string password;
extern std::string tempSSID;
extern std::string tempPassword;
extern bool SSIDGiven;
extern bool passGiven;
@@ -40,7 +40,7 @@ class MyCharCallbacks : public NimBLECharacteristicCallbacks {
// SSID characteristic
if (val.length() > 0) {
printf("Received SSID: %s\n", val.c_str());
SSID = val;
tempSSID = val;
SSIDGiven = true;
}
}
@@ -49,7 +49,7 @@ class MyCharCallbacks : public NimBLECharacteristicCallbacks {
if (val.length() > 0) {
printf("Received Password: %s\n", val.c_str());
passGiven = true;
password = val;
tempPassword = val;
}
}
else if (uuidStr.find("0003") != std::string::npos) {

View File

@@ -1,10 +1,61 @@
#include "WiFi.hpp"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_eap_client.h"
#include "cJSON.h" // Native replacement for ArduinoJson
#include "BLE.hpp"
void init_wifi() {
bool WiFi::authFailed = false;
EventGroupHandle_t WiFi::s_wifi_event_group = NULL;
esp_netif_t* WiFi::netif = NULL;
esp_event_handler_instance_t WiFi::instance_any_id = NULL;
esp_event_handler_instance_t WiFi::instance_got_ip = NULL;
#define WIFI_CONNECTED_BIT BIT0
// The Event Handler (The engine room)
void WiFi::event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) {
// We got disconnected -> Retry automatically
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
// 1. Cast the data to the correct struct
wifi_event_sta_disconnected_t* event = (wifi_event_sta_disconnected_t*) event_data;
printf("WiFi Disconnected. Reason Code: %d\n", event->reason);
// 2. Check specific Reason Codes
switch (event->reason) {
case WIFI_REASON_AUTH_EXPIRE: // Reason 2
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: // Reason 15 (Most Common for Wrong Pass)
case WIFI_REASON_BEACON_TIMEOUT: // Reason 200
case WIFI_REASON_AUTH_FAIL: // Reason 203
case WIFI_REASON_ASSOC_FAIL: // Reason 204
case WIFI_REASON_HANDSHAKE_TIMEOUT: // Reason 205
printf("ERROR: Likely Wrong Password!\n");
// OPTIONAL: Don't retry immediately if password is wrong
authFailed = true;
break;
case WIFI_REASON_NO_AP_FOUND: // Reason 201
printf("ERROR: SSID Not Found\n");
authFailed = true;
break;
default:
printf("Retrying...\n");
esp_wifi_connect(); // Retry for other reasons (interference, etc)
break;
}
xEventGroupClearBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
// 3. We got an IP Address -> Success!
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;
printf("Got IP: " IPSTR "\n", IP2STR(&event->ip_info.ip));
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void WiFi::init() {
// 1. Init Network Interface
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
@@ -16,9 +67,110 @@ void init_wifi() {
// 3. Set Mode to Station (Client)
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_event_handler_instance_register(
WIFI_EVENT, // The "Topic" (Base)
ESP_EVENT_ANY_ID, // The specific "Subject" (Any ID)
&event_handler, // The Function to call
NULL, // Argument to pass to the function (optional)
&instance_any_id // Where to store the registration handle
));
ESP_ERROR_CHECK(esp_event_handler_instance_register(
IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip
));
ESP_ERROR_CHECK(esp_wifi_start());
}
// --- CHECK STATUS ---
bool WiFi::isConnected() {
if (s_wifi_event_group == NULL) return false;
EventBits_t bits = xEventGroupGetBits(s_wifi_event_group);
return (bits & WIFI_CONNECTED_BIT);
}
// --- GET IP AS STRING ---
std::string WiFi::getIP() {
esp_netif_ip_info_t ip_info;
esp_netif_get_ip_info(netif, &ip_info);
char buf[20];
sprintf(buf, IPSTR, IP2STR(&ip_info.ip));
return std::string(buf);
}
bool WiFi::attemptConnect(char *SSID, char *PW, wifi_auth_mode_t authMode) {
wifi_config_t wifi_config = {};
strncpy((char*)wifi_config.sta.ssid, SSID, sizeof(wifi_config.sta.ssid));
strncpy((char*)wifi_config.sta.password, PW, sizeof(wifi_config.sta.password));
wifi_config.sta.threshold.authmode = authMode;
wifi_config.sta.pmf_cfg.capable = true;
wifi_config.sta.pmf_cfg.required = false;
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
return awaitConnected();
}
bool WiFi::attemptConnectEnterprise(char *SSID, char *username, char *PW, wifi_auth_mode_t authMode) {
std::string ssid = SSID;
std::string uname = username;
std::string password = PW;
// 1. Auto-generate the Identity
std::string identity = "anonymous";
// Check if the username is an email (contains '@')
size_t atPos = uname.find('@');
if (atPos != std::string::npos) {
// Append the domain from the real username
// Example: "user@gmail.com" -> "anonymous@gmail.com"
identity += uname.substr(atPos);
}
printf("Real User: %s\n", uname.c_str());
printf("Outer ID : %s (Privacy Safe)\n", identity.c_str());
// 2. Clear & Config
esp_wifi_disconnect();
wifi_config_t wifi_config = {};
strncpy((char*)wifi_config.sta.ssid, ssid.c_str(), sizeof(wifi_config.sta.ssid));
wifi_config.sta.threshold.authmode = authMode;
esp_wifi_set_config(WIFI_IF_STA, &wifi_config);
// 3. Set the calculated identity (using new ESP-IDF v5.x API)
esp_eap_client_set_identity((uint8_t *)identity.c_str(), identity.length());
esp_eap_client_set_username((uint8_t *)uname.c_str(), uname.length());
esp_eap_client_set_password((uint8_t *)password.c_str(), password.length());
esp_wifi_sta_enterprise_enable();
return awaitConnected();
}
bool WiFi::awaitConnected() {
authFailed = false;
if (esp_wifi_connect() != ESP_OK) return false;
uint8_t attempts = 0;
while (!isConnected() && attempts < 20) {
if (authFailed) {
printf("SSID/Password was wrong! Aborting connection attempt.\n");
return false;
}
vTaskDelay(500);
attempts++;
}
if (isConnected()) return true;
return false;
}
// ------------- non-class --------------
void scanAndUpdateSSIDList() {
printf("Starting WiFi Scan...\n");

View File

@@ -1,7 +1,28 @@
#ifndef WIFI_H
#define WIFI_H
void init_wifi();
#include "esp_wifi.h"
#include <string>
class WiFi {
public:
static void init();
static bool attemptConnect(char *SSID, char *PW, wifi_auth_mode_t authMode);
static bool attemptConnectEnterprise(char *SSID, char *username,
char *PW, wifi_auth_mode_t authMode);
private:
static bool authFailed;
static bool awaitConnected();
static esp_event_handler_instance_t instance_any_id;
static esp_event_handler_instance_t instance_got_ip;
static EventGroupHandle_t s_wifi_event_group;
static esp_netif_t* netif;
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data);
static bool isConnected();
static std::string getIP();
};
void scanAndUpdateSSIDList();
#endif

12
include/setup.cpp Normal file
View File

@@ -0,0 +1,12 @@
#include "setup.hpp"
#include "BLE.hpp"
#include "WiFi.hpp"
void initialSetup() {
NimBLEAdvertising* pAdv = initBLE();
while (1) { // try to connect to wifi too.
BLEtick(pAdv);
vTaskDelay(pdMS_TO_TICKS(10));
}
}

6
include/setup.hpp Normal file
View File

@@ -0,0 +1,6 @@
#ifndef SETUP_H
#define SETUP_H
void initialSetup();
#endif

View File

@@ -5,9 +5,10 @@
#include "NimBLEDevice.h"
#include "BLE.hpp"
#include "WiFi.hpp"
#include "setup.hpp"
extern "C" void app_main() {
esp_err_t ret = nvs_flash_init();
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());
@@ -15,11 +16,43 @@ extern "C" void app_main() {
}
ESP_ERROR_CHECK(ret);
init_wifi();
NimBLEAdvertising* pAdv = initBLE();
WiFi bmWiFi;
bmWiFi.init();
nvs_handle_t WiFiHandle;
nvs_open("WiFiCreds", NVS_READWRITE, &WiFiHandle);
size_t ssidSize;
esp_err_t WiFiPrefsError = nvs_get_str(WiFiHandle, "SSID", NULL, &ssidSize);
size_t pwSize;
WiFiPrefsError |= nvs_get_str(WiFiHandle, "PW", NULL, &pwSize);
uint8_t authMode;
WiFiPrefsError |= nvs_get_u8(WiFiHandle, "AuthMode", &authMode);
if (WiFiPrefsError == ESP_ERR_NVS_NOT_FOUND) {
// Make the RGB LED a certain color (Blue?)
nvs_close(WiFiHandle);
initialSetup();
} else if (WiFiPrefsError == ESP_OK) {
char ssid[ssidSize];
nvs_get_str(WiFiHandle, "SSID", ssid, &ssidSize);
char pw[pwSize];
nvs_get_str(WiFiHandle, "PW", pw, &pwSize);
nvs_close(WiFiHandle);
// TODO: add enterprise support
if (!bmWiFi.attemptConnect(ssid, pw, (wifi_auth_mode_t)authMode)) {
// Make RGB LED certain color (Blue?)
initialSetup();
}
} else {
// Make RGB LED certain color (Blue?)
nvs_close(WiFiHandle);
printf("Program error in Wifi Connection\n");
initialSetup();
}
// Main loop
while (1) {
BLEtick(pAdv);
vTaskDelay(pdMS_TO_TICKS(10));
// Your main application logic here
vTaskDelay(pdMS_TO_TICKS(100));
}
}