initial
This commit is contained in:
102
include/BLE.cpp
Normal file
102
include/BLE.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include "BLE.hpp"
|
||||
#include "NimBLEDevice.h"
|
||||
#include "WiFi.hpp"
|
||||
|
||||
bool flag_scan_requested = false;
|
||||
|
||||
std::string SSID = "";
|
||||
std::string password = "";
|
||||
bool SSIDGiven = false;
|
||||
bool passGiven = false;
|
||||
|
||||
std::string token = "";
|
||||
bool tokenGiven = false;
|
||||
|
||||
// Global pointers to characteristics for notification support
|
||||
NimBLECharacteristic* ssidListChar = nullptr;
|
||||
NimBLECharacteristic* connectConfirmChar = nullptr;
|
||||
|
||||
NimBLEAdvertising* initBLE() {
|
||||
NimBLEDevice::init("BlindMaster-C6");
|
||||
|
||||
// Optional: Boost power for better range (ESP32-C6 supports up to +20dBm)
|
||||
NimBLEDevice::setPower(ESP_PWR_LVL_P9);
|
||||
|
||||
// Set security
|
||||
NimBLEDevice::setSecurityAuth(false, false, true); // bonding=false, mitm=false, sc=true (Secure Connections)
|
||||
NimBLEDevice::setSecurityIOCap(BLE_HS_IO_NO_INPUT_OUTPUT); // No input/output capability
|
||||
|
||||
NimBLEServer *pServer = NimBLEDevice::createServer();
|
||||
pServer->setCallbacks(new MyServerCallbacks());
|
||||
pServer->advertiseOnDisconnect(true); // Automatically restart advertising on disconnect
|
||||
|
||||
NimBLEService *pService = pServer->createService("181C");
|
||||
|
||||
// Create all characteristics with callbacks
|
||||
MyCharCallbacks* charCallbacks = new MyCharCallbacks();
|
||||
|
||||
// 0x0000 - SSID List (READ + NOTIFY)
|
||||
ssidListChar = pService->createCharacteristic(
|
||||
"0000",
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY
|
||||
);
|
||||
ssidListChar->createDescriptor("2902"); // Add BLE2902 descriptor for notifications
|
||||
|
||||
// 0x0001 - SSID (WRITE)
|
||||
NimBLECharacteristic *ssidChar = pService->createCharacteristic(
|
||||
"0001",
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
);
|
||||
ssidChar->setCallbacks(charCallbacks);
|
||||
|
||||
// 0x0002 - Password (WRITE)
|
||||
NimBLECharacteristic *passChar = pService->createCharacteristic(
|
||||
"0002",
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
);
|
||||
passChar->setCallbacks(charCallbacks);
|
||||
|
||||
// 0x0003 - Token (WRITE)
|
||||
NimBLECharacteristic *tokenChar = pService->createCharacteristic(
|
||||
"0003",
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
);
|
||||
tokenChar->setCallbacks(charCallbacks);
|
||||
|
||||
// 0x0004 - SSID Refresh (WRITE)
|
||||
NimBLECharacteristic *ssidRefreshChar = pService->createCharacteristic(
|
||||
"0004",
|
||||
NIMBLE_PROPERTY::WRITE
|
||||
);
|
||||
ssidRefreshChar->setCallbacks(charCallbacks);
|
||||
|
||||
// 0x0005 - Connect Confirmation (READ + NOTIFY)
|
||||
connectConfirmChar = pService->createCharacteristic(
|
||||
"0005",
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY
|
||||
);
|
||||
connectConfirmChar->createDescriptor("2902"); // Add BLE2902 descriptor for notifications
|
||||
|
||||
// Start
|
||||
pService->start();
|
||||
|
||||
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
|
||||
pAdvertising->addServiceUUID("181C");
|
||||
pAdvertising->setName("BlindMaster-C6");
|
||||
pAdvertising->enableScanResponse(true);
|
||||
pAdvertising->setPreferredParams(0x06, 0x12); // Connection interval preferences
|
||||
pAdvertising->start();
|
||||
|
||||
printf("BLE Started. Waiting...\n");
|
||||
flag_scan_requested = true;
|
||||
|
||||
return pAdvertising;
|
||||
}
|
||||
|
||||
void BLEtick(NimBLEAdvertising* pAdvertising) {
|
||||
if(flag_scan_requested) {
|
||||
flag_scan_requested = false;
|
||||
printf("Scanning WiFi...\n");
|
||||
scanAndUpdateSSIDList();
|
||||
}
|
||||
}
|
||||
77
include/BLE.hpp
Normal file
77
include/BLE.hpp
Normal file
@@ -0,0 +1,77 @@
|
||||
#ifndef BLE_H
|
||||
#define BLE_H
|
||||
|
||||
#include "NimBLEDevice.h"
|
||||
|
||||
extern bool flag_scan_requested;
|
||||
|
||||
extern std::string SSID;
|
||||
extern std::string password;
|
||||
extern bool SSIDGiven;
|
||||
extern bool passGiven;
|
||||
|
||||
extern std::string token;
|
||||
extern bool tokenGiven;
|
||||
|
||||
// Global pointers to characteristics for notification support
|
||||
extern NimBLECharacteristic* ssidListChar;
|
||||
extern NimBLECharacteristic* connectConfirmChar;
|
||||
|
||||
class MyServerCallbacks : public NimBLEServerCallbacks {
|
||||
void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
|
||||
printf("Client connected\n");
|
||||
};
|
||||
|
||||
void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
|
||||
printf("Client disconnected - reason: %d\n", reason);
|
||||
// Advertising will restart automatically
|
||||
}
|
||||
};
|
||||
|
||||
class MyCharCallbacks : public NimBLECharacteristicCallbacks {
|
||||
void 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());
|
||||
|
||||
// Check which characteristic was written to
|
||||
if (uuidStr.find("0001") != std::string::npos) {
|
||||
// SSID characteristic
|
||||
if (val.length() > 0) {
|
||||
printf("Received SSID: %s\n", val.c_str());
|
||||
SSID = val;
|
||||
SSIDGiven = true;
|
||||
}
|
||||
}
|
||||
else if (uuidStr.find("0002") != std::string::npos) {
|
||||
// Password characteristic
|
||||
if (val.length() > 0) {
|
||||
printf("Received Password: %s\n", val.c_str());
|
||||
passGiven = true;
|
||||
password = val;
|
||||
}
|
||||
}
|
||||
else if (uuidStr.find("0003") != std::string::npos) {
|
||||
// Token characteristic
|
||||
if (val.length() > 0) {
|
||||
printf("Received Token: %s\n", val.c_str());
|
||||
tokenGiven = true;
|
||||
token = val;
|
||||
}
|
||||
}
|
||||
else if (uuidStr.find("0004") != std::string::npos) {
|
||||
// Refresh characteristic
|
||||
printf("Refresh Requested\n");
|
||||
flag_scan_requested = true;
|
||||
}
|
||||
else {
|
||||
printf("Unknown UUID: %s\n", uuidStr.c_str());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NimBLEAdvertising* initBLE();
|
||||
void BLEtick(NimBLEAdvertising* pAdvertising);
|
||||
|
||||
#endif
|
||||
37
include/README
Normal file
37
include/README
Normal file
@@ -0,0 +1,37 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the convention is to give header files names that end with `.h'.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
78
include/WiFi.cpp
Normal file
78
include/WiFi.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
#include "WiFi.hpp"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_event.h"
|
||||
#include "cJSON.h" // Native replacement for ArduinoJson
|
||||
#include "BLE.hpp"
|
||||
|
||||
void init_wifi() {
|
||||
// 1. Init Network Interface
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
esp_netif_create_default_wifi_sta();
|
||||
|
||||
// 2. Init WiFi Driver
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
// 3. Set Mode to Station (Client)
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
}
|
||||
|
||||
void scanAndUpdateSSIDList() {
|
||||
printf("Starting WiFi Scan...\n");
|
||||
|
||||
// 1. Start Scan (Blocking Mode = true)
|
||||
// In blocking mode, this function waits here until scan is done (~2 seconds)
|
||||
wifi_scan_config_t scan_config = {
|
||||
.ssid = NULL,
|
||||
.bssid = NULL,
|
||||
.channel = 0,
|
||||
.show_hidden = false
|
||||
};
|
||||
esp_err_t err = esp_wifi_scan_start(&scan_config, true);
|
||||
|
||||
if (err != ESP_OK) {
|
||||
printf("Scan failed!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Get the results
|
||||
uint16_t ap_count = 0;
|
||||
esp_wifi_scan_get_ap_num(&ap_count);
|
||||
|
||||
// Limit to 10 networks to save RAM/BLE MTU space
|
||||
if (ap_count > 10) ap_count = 10;
|
||||
|
||||
wifi_ap_record_t *ap_list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * ap_count);
|
||||
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&ap_count, ap_list));
|
||||
|
||||
// 3. Build JSON using cJSON
|
||||
cJSON *root = cJSON_CreateArray();
|
||||
|
||||
for (int i = 0; i < ap_count; i++) {
|
||||
cJSON *item = cJSON_CreateObject();
|
||||
// ESP-IDF stores SSID as uint8_t, cast to char*
|
||||
cJSON_AddStringToObject(item, "ssid", (char *)ap_list[i].ssid);
|
||||
cJSON_AddNumberToObject(item, "rssi", ap_list[i].rssi);
|
||||
// Add encryption type if you want (optional)
|
||||
cJSON_AddNumberToObject(item, "auth", ap_list[i].authmode);
|
||||
|
||||
cJSON_AddItemToArray(root, item);
|
||||
}
|
||||
|
||||
// 4. Convert to String
|
||||
char *json_string = cJSON_PrintUnformatted(root); // Compact JSON
|
||||
printf("JSON: %s\n", json_string);
|
||||
|
||||
// 5. Update BLE
|
||||
if (ssidListChar != nullptr) {
|
||||
ssidListChar->setValue(std::string(json_string));
|
||||
ssidListChar->notify();
|
||||
}
|
||||
|
||||
// 6. Cleanup Memory (CRITICAL in C++)
|
||||
free(ap_list);
|
||||
cJSON_Delete(root); // This deletes all children (items) too
|
||||
free(json_string); // cJSON_Print allocates memory, you must free it
|
||||
}
|
||||
7
include/WiFi.hpp
Normal file
7
include/WiFi.hpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef WIFI_H
|
||||
#define WIFI_H
|
||||
|
||||
void init_wifi();
|
||||
void scanAndUpdateSSIDList();
|
||||
|
||||
#endif
|
||||
38
include/defines.h
Normal file
38
include/defines.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifndef DEFINES_H
|
||||
#define DEFINES_H
|
||||
|
||||
#define ccwSpeed 6500
|
||||
#define cwSpeed 3300
|
||||
#define offSpeed 4900
|
||||
|
||||
#define ccwMax 10
|
||||
#define cwMax 0
|
||||
|
||||
#define getMovingCW(port) ((movingCW & (1 << port)) >> port)
|
||||
#define setMovingCW(port) (movingCW |= (1 << port))
|
||||
#define clearMovingCW(port) (movingCW &= ~(1 << port))
|
||||
#define getMovingCCW(port) ((movingCCW & (1 << port)) >> port)
|
||||
#define setMovingCCW(port) (movingCCW |= (1 << port))
|
||||
#define clearMovingCCW(port) (movingCCW &= ~(1 << port))
|
||||
#define getCalibCW(port) ((calibCW & (1 << port)) >> port)
|
||||
#define setCalibCW(port) (calibCW |= (1 << port))
|
||||
#define clearCalibCW(port) (calibCW &= ~(1 << port))
|
||||
#define getCalibCCW(port) ((calibCCW & (1 << port)) >> port)
|
||||
#define setCalibCCW(port) (calibCCW |= (1 << port))
|
||||
#define clearCalibCCW(port) (calibCCW &= ~(1 << port))
|
||||
#define getCalibDone(port) ((calibDone & (1 << port)) >> port)
|
||||
#define setCalibDone(port) (calibDone |= (1 << port))
|
||||
#define clearCalibDone(port) (calibDone &= ~(1 << port))
|
||||
#define getBlocked(port) ((blocked & (1 << port)) >> port)
|
||||
#define setBlocked(port) (blocked |= (1 << port))
|
||||
#define clearBlocked(port) (blocked &= ~(1 << port))
|
||||
#define getPos10(port) ((movingCCW & (1 << (port + 4))) >> (port + 4))
|
||||
#define setPos10(port) (movingCCW |= (1 << (port + 4)))
|
||||
#define clearPos10(port) (movingCCW &= ~(1 << (port + 4)))
|
||||
#define getPos0(port) ((movingCW & (1 << (port + 4))) >> (port + 4))
|
||||
#define setPos0(port) (movingCW |= (1 << (port + 4)))
|
||||
#define clearPos0(port) (movingCW &= ~(1 << (port + 4)))
|
||||
|
||||
#define prefNameCalibs "periph_info_"
|
||||
|
||||
#endif
|
||||
30
include/pwm.c
Normal file
30
include/pwm.c
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "driver/ledc.h"
|
||||
#include "defines.h"
|
||||
|
||||
void init_servo_PWM(void) {
|
||||
ledc_timer_config_t ledc_timer = {
|
||||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||
.timer_num = LEDC_TIMER_0,
|
||||
.duty_resolution = LEDC_TIMER_16_BIT,
|
||||
.freq_hz = 50,
|
||||
.clk_cfg = LEDC_AUTO_CLK
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
||||
|
||||
ledc_channel_config_t ledc_channel = {
|
||||
.speed_mode = LEDC_LOW_SPEED_MODE,
|
||||
.channel = LEDC_CHANNEL_0,
|
||||
.timer_sel = LEDC_TIMER_0,
|
||||
.intr_type = LEDC_INTR_DISABLE,
|
||||
.gpio_num = 0, // Using pin D0 for servo.
|
||||
.duty = offSpeed, // Start off
|
||||
.hpoint = 0
|
||||
};
|
||||
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
||||
}
|
||||
|
||||
void set_servo_speed(int channel, uint32_t duty) {
|
||||
// duty input should be between 0 and 65535
|
||||
ledc_set_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)channel, duty);
|
||||
ledc_update_duty(LEDC_LOW_SPEED_MODE, (ledc_channel_t)channel);
|
||||
}
|
||||
7
include/pwm.h
Normal file
7
include/pwm.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#ifndef PWM_H
|
||||
#define PWM_H
|
||||
|
||||
void init_servo_PWM(void);
|
||||
void set_servo_speed(int channel, int speed);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user