Compare commits
2 Commits
taskDriven
...
56d8a0f2cf
| Author | SHA1 | Date | |
|---|---|---|---|
| 56d8a0f2cf | |||
| bec3d91d98 |
1
components/esp-nimble-cpp
Submodule
1
components/esp-nimble-cpp
Submodule
Submodule components/esp-nimble-cpp added at 25af28bcad
@@ -13,28 +13,8 @@ dependencies:
|
|||||||
registry_url: https://components.espressif.com/
|
registry_url: https://components.espressif.com/
|
||||||
type: service
|
type: service
|
||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
esp-nimble-cpp:
|
|
||||||
component_hash: 224980602c685130c426248ad9a0500686d4a5aff0ec3a10b6dfacf00c554a91
|
|
||||||
dependencies:
|
|
||||||
- name: espressif/esp_hosted
|
|
||||||
rules:
|
|
||||||
- if: target in [esp32p4]
|
|
||||||
version: '*'
|
|
||||||
- name: espressif/esp_wifi_remote
|
|
||||||
rules:
|
|
||||||
- if: target in [esp32p4]
|
|
||||||
version: '>=0.5.3'
|
|
||||||
- name: idf
|
|
||||||
rules:
|
|
||||||
- if: target in [esp32p4]
|
|
||||||
version: '>=5.3.0'
|
|
||||||
source:
|
|
||||||
git: https://github.com/h2zero/esp-nimble-cpp.git
|
|
||||||
path: .
|
|
||||||
type: git
|
|
||||||
version: 002abf91e9779ea5646d75278ae52c6b848d3fa0
|
|
||||||
espressif/esp_websocket_client:
|
espressif/esp_websocket_client:
|
||||||
component_hash: c5a067a9fddea370c478017e66fac302f4b79c3d4027e9bdd42a019786cceb92
|
component_hash: 723aba370113196c66321442426cd6452c351eef31c85c83bd1446831ef9f8f4
|
||||||
dependencies:
|
dependencies:
|
||||||
- name: idf
|
- name: idf
|
||||||
require: private
|
require: private
|
||||||
@@ -42,14 +22,13 @@ dependencies:
|
|||||||
source:
|
source:
|
||||||
registry_url: https://components.espressif.com
|
registry_url: https://components.espressif.com
|
||||||
type: service
|
type: service
|
||||||
version: 1.6.1
|
version: 1.6.0
|
||||||
idf:
|
idf:
|
||||||
source:
|
source:
|
||||||
type: idf
|
type: idf
|
||||||
version: 5.5.1
|
version: 5.5.1
|
||||||
direct_dependencies:
|
direct_dependencies:
|
||||||
- bubblesnake/esp_socketio_client
|
- bubblesnake/esp_socketio_client
|
||||||
- esp-nimble-cpp
|
manifest_hash: d73c96c5d6ddd24707089a2953e50f36a12ebbc66b5458ada3d4f55c0987ccf1
|
||||||
manifest_hash: 5f4bfc48b0eb389591b06fcf0a5c43c05e081427d594466829c6f7c545158221
|
|
||||||
target: esp32c6
|
target: esp32c6
|
||||||
version: 2.0.0
|
version: 2.0.0
|
||||||
|
|||||||
@@ -23,17 +23,6 @@ class MyCharCallbacks : public NimBLECharacteristicCallbacks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
NimBLEAdvertising* initBLE();
|
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
|
#endif
|
||||||
@@ -14,10 +14,9 @@ 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;
|
||||||
@@ -28,4 +27,6 @@ class WiFi {
|
|||||||
static std::string getIP();
|
static std::string getIP();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern WiFi bmWiFi;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -6,7 +6,6 @@
|
|||||||
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,27 +1,24 @@
|
|||||||
#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"
|
||||||
|
|
||||||
class Calibration {
|
class Calibration {
|
||||||
public:
|
public:
|
||||||
static void init();
|
void init();
|
||||||
static bool beginDownwardCalib(Encoder& topEnc);
|
bool beginDownwardCalib(Encoder& topEnc);
|
||||||
static bool completeCalib(Encoder& topEnc);
|
bool completeCalib(Encoder& topEnc);
|
||||||
static int32_t convertToTicks(uint8_t appPos);
|
int32_t convertToTicks(uint8_t appPos);
|
||||||
static uint8_t convertToAppPos(int32_t ticks);
|
uint8_t convertToAppPos(int32_t ticks);
|
||||||
static bool getCalibrated() {return calibrated;}
|
bool getCalibrated() {return calibrated;}
|
||||||
static bool clearCalibrated();
|
bool clearCalibrated();
|
||||||
static std::atomic<int32_t> DownTicks;
|
std::atomic<int32_t> DownTicks;
|
||||||
static std::atomic<int32_t> UpTicks;
|
std::atomic<int32_t> UpTicks;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static std::atomic<bool> calibrated;
|
std::atomic<bool> calibrated;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern TaskHandle_t calibTaskHandle;
|
extern Calibration calib;
|
||||||
bool calibrate();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -31,16 +31,16 @@
|
|||||||
// #define srvAddr "192.168.1.190:3000"
|
// #define srvAddr "192.168.1.190:3000"
|
||||||
#define srvAddr "wahwa.com"
|
#define srvAddr "wahwa.com"
|
||||||
|
|
||||||
#define ENCODER_PIN_A GPIO_NUM_21 // d3
|
#define ENCODER_PIN_A GPIO_NUM_23 // d5
|
||||||
#define ENCODER_PIN_B GPIO_NUM_16 // d6
|
#define ENCODER_PIN_B GPIO_NUM_16 // d6
|
||||||
|
|
||||||
#define InputEnc_PIN_A GPIO_NUM_0 // d0
|
#define InputEnc_PIN_A GPIO_NUM_1 // d1
|
||||||
#define InputEnc_PIN_B GPIO_NUM_1 // d1
|
#define InputEnc_PIN_B GPIO_NUM_2 // d2
|
||||||
|
|
||||||
#define servoPin GPIO_NUM_20
|
#define servoPin GPIO_NUM_20
|
||||||
#define servoLEDCChannel LEDC_CHANNEL_0
|
#define servoLEDCChannel LEDC_CHANNEL_0
|
||||||
#define servoSwitch GPIO_NUM_17
|
#define servoSwitch GPIO_NUM_17
|
||||||
|
|
||||||
#define debugLED GPIO_NUM_18 // d10
|
#define debugLED GPIO_NUM_22 // d4
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#ifndef I2C_HELPER_H
|
|
||||||
#define I2C_HELPER_H
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// I2C Configuration (Match your schematic)
|
|
||||||
#define I2C_MASTER_SCL_IO GPIO_NUM_23 // Example GPIO for C6
|
|
||||||
#define I2C_MASTER_SDA_IO GPIO_NUM_22 // Example GPIO for C6
|
|
||||||
#define I2C_MASTER_NUM 0
|
|
||||||
#define I2C_MASTER_FREQ_HZ 100000 // use standard freq
|
|
||||||
#define I2C_MASTER_TIMEOUT_MS 1000
|
|
||||||
|
|
||||||
esp_err_t i2c_init();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
#ifndef BM_EVENTS_H
|
|
||||||
#define BM_EVENTS_H
|
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Shared with max17048.c (C) — only C-compatible types here
|
|
||||||
typedef enum {
|
|
||||||
EVENT_CLEAR_CALIB,
|
|
||||||
EVENT_SAVE_POS,
|
|
||||||
EVENT_REQUEST_POS,
|
|
||||||
EVENT_BATTERY_CRITICAL, // stop servo, save pos, alert server, deep sleep
|
|
||||||
EVENT_BATTERY_WARNING, // alert server (no shutdown)
|
|
||||||
EVENT_REPORT_SOC, // periodic SOC sync to server
|
|
||||||
} main_event_type_t;
|
|
||||||
|
|
||||||
extern QueueHandle_t main_event_queue;
|
|
||||||
extern TaskHandle_t wakeTaskHandle;
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
void mainEventLoop();
|
|
||||||
void wakeTimer(void* pvParameters);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
#ifndef MAX_17_H
|
|
||||||
#define MAX_17_H
|
|
||||||
|
|
||||||
#define MAX17048_ADDR 0x36
|
|
||||||
#define MAX17048_REG_VCELL 0x02
|
|
||||||
#define MAX17048_REG_SOC 0x04
|
|
||||||
#define MAX17048_REG_MODE 0x06
|
|
||||||
#define MAX17048_REG_VERSION 0x08
|
|
||||||
#define MAX17048_REG_CONFIG 0x0C
|
|
||||||
#define MAX17048_REG_VALRT 0x14
|
|
||||||
#define MAX17048_REG_VRST_ID 0x18
|
|
||||||
#define MAX17048_REG_STATUS 0x1A
|
|
||||||
#define MAX17048_REG_CMD 0xFE
|
|
||||||
|
|
||||||
#define MAX17048_CMD_POR 0x5400
|
|
||||||
#define MAX17048_CMD_QSTRT 0x4000
|
|
||||||
|
|
||||||
// NOTE: maxALRT (GPIO_NUM_2) conflicts with InputEnc_PIN_B in defines.h.
|
|
||||||
// Assign maxALRT to a free GPIO before enabling the interrupt.
|
|
||||||
#define maxALRT GPIO_NUM_2
|
|
||||||
|
|
||||||
// STATUS register MSB (addr 0x1A) bit masks
|
|
||||||
// [7:X] [6:EnVR] [5:SC] [4:HD] [3:VR] [2:VL] [1:VH] [0:RI]
|
|
||||||
#define SCbit (1 << 5) // SOC changed by 1%
|
|
||||||
#define HDbit (1 << 4) // SOC crossed low threshold (CONFIG.ATHD)
|
|
||||||
#define VRbit (1 << 3) // voltage reset alert
|
|
||||||
#define VLbit (1 << 2) // VCELL below VALRT.MIN
|
|
||||||
#define VHbit (1 << 1) // VCELL above VALRT.MAX
|
|
||||||
#define RIbit (1 << 0) // reset indicator (device just powered on)
|
|
||||||
|
|
||||||
// SOC thresholds for user-facing push notifications / shutdown logic
|
|
||||||
#define SOC_WARN_20 20 // emit warning push at this level
|
|
||||||
#define SOC_WARN_10 10 // emit critical push at this level
|
|
||||||
#define SOC_CRITICAL_VL 5 // treat undervoltage as critical only below this SOC
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "driver/i2c.h"
|
|
||||||
|
|
||||||
// Alert type carried from bms_checker_task to mainEventLoop via bms_pending_alert
|
|
||||||
typedef enum {
|
|
||||||
BATT_ALERT_OVERVOLTAGE, // VH: charging fault / damaged battery
|
|
||||||
BATT_ALERT_CRITICAL_LOW, // HD, or VL + SOC < SOC_CRITICAL_VL
|
|
||||||
BATT_ALERT_LOW_VOLTAGE_WARNING, // VL with SOC >= SOC_CRITICAL_VL (transient dip)
|
|
||||||
BATT_ALERT_SOC_LOW_20, // SOC just crossed 20% downward
|
|
||||||
BATT_ALERT_SOC_LOW_10, // SOC just crossed 10% downward
|
|
||||||
} batt_alert_type_t;
|
|
||||||
|
|
||||||
extern uint8_t established_soc;
|
|
||||||
extern volatile batt_alert_type_t bms_pending_alert;
|
|
||||||
|
|
||||||
esp_err_t max17048_init();
|
|
||||||
uint8_t bms_get_soc();
|
|
||||||
esp_err_t bms_set_alert_bound_voltages(float min, float max);
|
|
||||||
esp_err_t bms_set_reset_voltage(float vreset);
|
|
||||||
void bms_checker_task(void *pvParameters);
|
|
||||||
|
|
||||||
#define bms_set_alsc() max17048_friendly_write_reg(MAX17048_REG_CONFIG, 0, 1<<6, 0, 1<<6)
|
|
||||||
#define bms_clear_status() max17048_write_reg(MAX17048_REG_STATUS, 0, 0)
|
|
||||||
#define bms_clear_alrt() max17048_friendly_write_reg(MAX17048_REG_CONFIG, 0, 0, 0, 1<<5)
|
|
||||||
|
|
||||||
esp_err_t max17048_read_reg(uint8_t reg_addr, uint8_t *MSB, uint8_t *LSB);
|
|
||||||
esp_err_t max17048_write_reg(uint8_t reg_addr, uint8_t MSB, uint8_t LSB);
|
|
||||||
esp_err_t max17048_friendly_write_reg(uint8_t reg_addr, uint8_t MSB, uint8_t LSB,
|
|
||||||
uint8_t MSBmask, uint8_t LSBmask);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -10,6 +10,8 @@
|
|||||||
#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,16 +1,7 @@
|
|||||||
#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 std::atomic<bool> awaitCalibration;
|
|
||||||
|
|
||||||
void initialSetup();
|
void initialSetup();
|
||||||
void setupLoop();
|
void setupLoop();
|
||||||
|
|
||||||
void setupAndCalibrate();
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -2,7 +2,8 @@
|
|||||||
#define SOCKETIO_HPP
|
#define SOCKETIO_HPP
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
extern std::atomic<bool> socketIOactive;
|
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();
|
||||||
|
|||||||
@@ -1152,6 +1152,7 @@ CONFIG_ESP_TLS_DYN_BUF_STRATEGY_SUPPORTED=y
|
|||||||
CONFIG_ESP_COEX_ENABLED=y
|
CONFIG_ESP_COEX_ENABLED=y
|
||||||
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
||||||
# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set
|
# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set
|
||||||
|
# CONFIG_ESP_COEX_GPIO_DEBUG is not set
|
||||||
# end of Wireless Coexistence
|
# end of Wireless Coexistence
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1292,7 +1293,6 @@ CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
|||||||
# ESP-Driver:USB Serial/JTAG Configuration
|
# ESP-Driver:USB Serial/JTAG Configuration
|
||||||
#
|
#
|
||||||
CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y
|
CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y
|
||||||
# CONFIG_USJ_NO_AUTO_LS_ON_CONNECTION is not set
|
|
||||||
# end of ESP-Driver:USB Serial/JTAG Configuration
|
# end of ESP-Driver:USB Serial/JTAG Configuration
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1423,7 +1423,6 @@ CONFIG_ESP_SLEEP_WAIT_FLASH_READY_EXTRA_DELAY=0
|
|||||||
# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set
|
# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set
|
||||||
# CONFIG_ESP_SLEEP_DEBUG is not set
|
# CONFIG_ESP_SLEEP_DEBUG is not set
|
||||||
CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y
|
CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y
|
||||||
# CONFIG_ESP_SLEEP_EVENT_CALLBACKS is not set
|
|
||||||
# end of Sleep Config
|
# end of Sleep Config
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1528,7 +1527,6 @@ CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
|||||||
# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
|
# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
|
||||||
CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
|
CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
|
||||||
CONFIG_ESP_PHY_MAX_TX_POWER=20
|
CONFIG_ESP_PHY_MAX_TX_POWER=20
|
||||||
CONFIG_ESP_PHY_MAC_BB_PD=y
|
|
||||||
# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set
|
# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set
|
||||||
# CONFIG_ESP_PHY_ENABLE_CERT_TEST is not set
|
# CONFIG_ESP_PHY_ENABLE_CERT_TEST is not set
|
||||||
CONFIG_ESP_PHY_RF_CAL_PARTIAL=y
|
CONFIG_ESP_PHY_RF_CAL_PARTIAL=y
|
||||||
@@ -1546,18 +1544,11 @@ CONFIG_ESP_PHY_IRAM_OPT=y
|
|||||||
# Power Management
|
# Power Management
|
||||||
#
|
#
|
||||||
CONFIG_PM_SLEEP_FUNC_IN_IRAM=y
|
CONFIG_PM_SLEEP_FUNC_IN_IRAM=y
|
||||||
CONFIG_PM_ENABLE=y
|
# CONFIG_PM_ENABLE is not set
|
||||||
CONFIG_PM_DFS_INIT_AUTO=y
|
|
||||||
# CONFIG_PM_PROFILING is not set
|
|
||||||
CONFIG_PM_TRACE=y
|
|
||||||
CONFIG_PM_SLP_IRAM_OPT=y
|
CONFIG_PM_SLP_IRAM_OPT=y
|
||||||
CONFIG_PM_RTOS_IDLE_OPT=y
|
|
||||||
CONFIG_PM_SLP_DISABLE_GPIO=y
|
|
||||||
CONFIG_PM_SLP_DEFAULT_PARAMS_OPT=y
|
CONFIG_PM_SLP_DEFAULT_PARAMS_OPT=y
|
||||||
CONFIG_PM_LIGHTSLEEP_RTC_OSC_CAL_INTERVAL=1
|
|
||||||
CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
|
CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
|
||||||
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
|
# CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP is not set
|
||||||
# CONFIG_PM_LIGHT_SLEEP_CALLBACKS is not set
|
|
||||||
# end of Power Management
|
# end of Power Management
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1620,7 +1611,7 @@ CONFIG_ESP_SYSTEM_PMP_IDRAM_SPLIT=y
|
|||||||
|
|
||||||
CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
|
CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
|
||||||
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
|
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
|
||||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
|
CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584
|
||||||
CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y
|
CONFIG_ESP_MAIN_TASK_AFFINITY_CPU0=y
|
||||||
# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
|
# CONFIG_ESP_MAIN_TASK_AFFINITY_NO_AFFINITY is not set
|
||||||
CONFIG_ESP_MAIN_TASK_AFFINITY=0x0
|
CONFIG_ESP_MAIN_TASK_AFFINITY=0x0
|
||||||
@@ -1716,7 +1707,6 @@ CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y
|
|||||||
# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set
|
# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set
|
||||||
CONFIG_ESP_WIFI_GMAC_SUPPORT=y
|
CONFIG_ESP_WIFI_GMAC_SUPPORT=y
|
||||||
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
|
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
|
||||||
# CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP is not set
|
|
||||||
# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set
|
# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set
|
||||||
CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7
|
CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7
|
||||||
CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y
|
CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y
|
||||||
@@ -1839,8 +1829,6 @@ CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1
|
|||||||
# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
|
# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
|
||||||
# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set
|
# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set
|
||||||
# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
|
# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
|
||||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
|
||||||
CONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP=3
|
|
||||||
# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set
|
# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set
|
||||||
# end of Kernel
|
# end of Kernel
|
||||||
|
|
||||||
@@ -1920,7 +1908,6 @@ CONFIG_IEEE802154_CCA_THRESHOLD=-60
|
|||||||
CONFIG_IEEE802154_PENDING_TABLE_SIZE=20
|
CONFIG_IEEE802154_PENDING_TABLE_SIZE=20
|
||||||
# CONFIG_IEEE802154_MULTI_PAN_ENABLE is not set
|
# CONFIG_IEEE802154_MULTI_PAN_ENABLE is not set
|
||||||
CONFIG_IEEE802154_TIMING_OPTIMIZATION=y
|
CONFIG_IEEE802154_TIMING_OPTIMIZATION=y
|
||||||
# CONFIG_IEEE802154_SLEEP_ENABLE is not set
|
|
||||||
# CONFIG_IEEE802154_DEBUG is not set
|
# CONFIG_IEEE802154_DEBUG is not set
|
||||||
# CONFIG_IEEE802154_DEBUG_ASSERT_MONITOR is not set
|
# CONFIG_IEEE802154_DEBUG_ASSERT_MONITOR is not set
|
||||||
# end of IEEE 802.15.4
|
# end of IEEE 802.15.4
|
||||||
@@ -2568,10 +2555,6 @@ CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y
|
|||||||
# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set
|
# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set
|
||||||
# end of Wi-Fi Provisioning Manager
|
# end of Wi-Fi Provisioning Manager
|
||||||
|
|
||||||
#
|
|
||||||
# ESP Socket.IO client
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ESP-NimBLE-CPP configuration
|
# ESP-NimBLE-CPP configuration
|
||||||
#
|
#
|
||||||
@@ -2594,6 +2577,10 @@ CONFIG_NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT=31
|
|||||||
CONFIG_NIMBLE_CPP_IDF=y
|
CONFIG_NIMBLE_CPP_IDF=y
|
||||||
# end of ESP-NimBLE-CPP configuration
|
# end of ESP-NimBLE-CPP configuration
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP Socket.IO client
|
||||||
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
# ESP WebSocket client
|
# ESP WebSocket client
|
||||||
#
|
#
|
||||||
@@ -2701,14 +2688,12 @@ CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
|||||||
# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
|
# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
|
||||||
CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
|
CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
|
||||||
CONFIG_ESP32_PHY_MAX_TX_POWER=20
|
CONFIG_ESP32_PHY_MAX_TX_POWER=20
|
||||||
CONFIG_MAC_BB_PD=y
|
|
||||||
CONFIG_ESP32_PHY_MAC_BB_PD=y
|
|
||||||
# CONFIG_REDUCE_PHY_TX_POWER is not set
|
# CONFIG_REDUCE_PHY_TX_POWER is not set
|
||||||
# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set
|
# CONFIG_ESP32_REDUCE_PHY_TX_POWER is not set
|
||||||
CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y
|
CONFIG_ESP_SYSTEM_PM_POWER_DOWN_CPU=y
|
||||||
CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
|
CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
|
||||||
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
|
CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
|
||||||
CONFIG_MAIN_TASK_STACK_SIZE=8192
|
CONFIG_MAIN_TASK_STACK_SIZE=3584
|
||||||
CONFIG_CONSOLE_UART_DEFAULT=y
|
CONFIG_CONSOLE_UART_DEFAULT=y
|
||||||
# CONFIG_CONSOLE_UART_CUSTOM is not set
|
# CONFIG_CONSOLE_UART_CUSTOM is not set
|
||||||
# CONFIG_CONSOLE_UART_NONE is not set
|
# CONFIG_CONSOLE_UART_NONE is not set
|
||||||
@@ -2807,4 +2792,5 @@ CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
|
|||||||
CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y
|
||||||
CONFIG_SUPPORT_TERMIOS=y
|
CONFIG_SUPPORT_TERMIOS=y
|
||||||
CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
|
CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
|
||||||
|
CONFIG_NIMBLE_ENABLED=y
|
||||||
# End of deprecated options
|
# End of deprecated options
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_VALID_GPIO_MASK=0
|
|||||||
CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT=8
|
CONFIG_SOC_GPIO_DEEP_SLEEP_WAKE_SUPPORTED_PIN_CNT=8
|
||||||
CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x000000007FFFFF00
|
CONFIG_SOC_GPIO_VALID_DIGITAL_IO_PAD_MASK=0x000000007FFFFF00
|
||||||
CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y
|
CONFIG_SOC_GPIO_SUPPORT_FORCE_HOLD=y
|
||||||
|
CONFIG_SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP=y
|
||||||
CONFIG_SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP=y
|
CONFIG_SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP=y
|
||||||
CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX=y
|
CONFIG_SOC_GPIO_CLOCKOUT_BY_GPIO_MATRIX=y
|
||||||
CONFIG_SOC_CLOCKOUT_HAS_SOURCE_GATE=y
|
CONFIG_SOC_CLOCKOUT_HAS_SOURCE_GATE=y
|
||||||
@@ -1152,6 +1153,7 @@ CONFIG_ESP_TLS_DYN_BUF_STRATEGY_SUPPORTED=y
|
|||||||
CONFIG_ESP_COEX_ENABLED=y
|
CONFIG_ESP_COEX_ENABLED=y
|
||||||
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
CONFIG_ESP_COEX_SW_COEXIST_ENABLE=y
|
||||||
# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set
|
# CONFIG_ESP_COEX_POWER_MANAGEMENT is not set
|
||||||
|
# CONFIG_ESP_COEX_GPIO_DEBUG is not set
|
||||||
# end of Wireless Coexistence
|
# end of Wireless Coexistence
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1292,7 +1294,6 @@ CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
|
|||||||
# ESP-Driver:USB Serial/JTAG Configuration
|
# ESP-Driver:USB Serial/JTAG Configuration
|
||||||
#
|
#
|
||||||
CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y
|
CONFIG_USJ_ENABLE_USB_SERIAL_JTAG=y
|
||||||
# CONFIG_USJ_NO_AUTO_LS_ON_CONNECTION is not set
|
|
||||||
# end of ESP-Driver:USB Serial/JTAG Configuration
|
# end of ESP-Driver:USB Serial/JTAG Configuration
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1423,7 +1424,6 @@ CONFIG_ESP_SLEEP_WAIT_FLASH_READY_EXTRA_DELAY=0
|
|||||||
# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set
|
# CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is not set
|
||||||
# CONFIG_ESP_SLEEP_DEBUG is not set
|
# CONFIG_ESP_SLEEP_DEBUG is not set
|
||||||
CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y
|
CONFIG_ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS=y
|
||||||
# CONFIG_ESP_SLEEP_EVENT_CALLBACKS is not set
|
|
||||||
# end of Sleep Config
|
# end of Sleep Config
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1528,7 +1528,6 @@ CONFIG_ESP_PHY_CALIBRATION_AND_DATA_STORAGE=y
|
|||||||
# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
|
# CONFIG_ESP_PHY_INIT_DATA_IN_PARTITION is not set
|
||||||
CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
|
CONFIG_ESP_PHY_MAX_WIFI_TX_POWER=20
|
||||||
CONFIG_ESP_PHY_MAX_TX_POWER=20
|
CONFIG_ESP_PHY_MAX_TX_POWER=20
|
||||||
CONFIG_ESP_PHY_MAC_BB_PD=y
|
|
||||||
# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set
|
# CONFIG_ESP_PHY_REDUCE_TX_POWER is not set
|
||||||
# CONFIG_ESP_PHY_ENABLE_CERT_TEST is not set
|
# CONFIG_ESP_PHY_ENABLE_CERT_TEST is not set
|
||||||
CONFIG_ESP_PHY_RF_CAL_PARTIAL=y
|
CONFIG_ESP_PHY_RF_CAL_PARTIAL=y
|
||||||
@@ -1546,18 +1545,11 @@ CONFIG_ESP_PHY_IRAM_OPT=y
|
|||||||
# Power Management
|
# Power Management
|
||||||
#
|
#
|
||||||
CONFIG_PM_SLEEP_FUNC_IN_IRAM=y
|
CONFIG_PM_SLEEP_FUNC_IN_IRAM=y
|
||||||
CONFIG_PM_ENABLE=y
|
# CONFIG_PM_ENABLE is not set
|
||||||
CONFIG_PM_DFS_INIT_AUTO=y
|
|
||||||
# CONFIG_PM_PROFILING is not set
|
|
||||||
CONFIG_PM_TRACE=y
|
|
||||||
CONFIG_PM_SLP_IRAM_OPT=y
|
CONFIG_PM_SLP_IRAM_OPT=y
|
||||||
CONFIG_PM_RTOS_IDLE_OPT=y
|
|
||||||
CONFIG_PM_SLP_DISABLE_GPIO=y
|
|
||||||
CONFIG_PM_SLP_DEFAULT_PARAMS_OPT=y
|
CONFIG_PM_SLP_DEFAULT_PARAMS_OPT=y
|
||||||
CONFIG_PM_LIGHTSLEEP_RTC_OSC_CAL_INTERVAL=1
|
|
||||||
CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
|
CONFIG_PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP=y
|
||||||
CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP=y
|
# CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP is not set
|
||||||
# CONFIG_PM_LIGHT_SLEEP_CALLBACKS is not set
|
|
||||||
# end of Power Management
|
# end of Power Management
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -1672,7 +1664,7 @@ CONFIG_ESP_TIMER_INTERRUPT_LEVEL=1
|
|||||||
CONFIG_ESP_TIMER_TASK_AFFINITY=0x0
|
CONFIG_ESP_TIMER_TASK_AFFINITY=0x0
|
||||||
CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y
|
CONFIG_ESP_TIMER_TASK_AFFINITY_CPU0=y
|
||||||
CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y
|
CONFIG_ESP_TIMER_ISR_AFFINITY_CPU0=y
|
||||||
CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD=y
|
# CONFIG_ESP_TIMER_SUPPORTS_ISR_DISPATCH_METHOD is not set
|
||||||
CONFIG_ESP_TIMER_IMPL_SYSTIMER=y
|
CONFIG_ESP_TIMER_IMPL_SYSTIMER=y
|
||||||
# end of ESP Timer (High Resolution Timer)
|
# end of ESP Timer (High Resolution Timer)
|
||||||
|
|
||||||
@@ -1716,7 +1708,6 @@ CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE=y
|
|||||||
# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set
|
# CONFIG_ESP_WIFI_GCMP_SUPPORT is not set
|
||||||
CONFIG_ESP_WIFI_GMAC_SUPPORT=y
|
CONFIG_ESP_WIFI_GMAC_SUPPORT=y
|
||||||
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
|
CONFIG_ESP_WIFI_SOFTAP_SUPPORT=y
|
||||||
# CONFIG_ESP_WIFI_ENHANCED_LIGHT_SLEEP is not set
|
|
||||||
# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set
|
# CONFIG_ESP_WIFI_SLP_BEACON_LOST_OPT is not set
|
||||||
CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7
|
CONFIG_ESP_WIFI_ESPNOW_MAX_ENCRYPT_NUM=7
|
||||||
CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y
|
CONFIG_ESP_WIFI_MBEDTLS_CRYPTO=y
|
||||||
@@ -1839,8 +1830,6 @@ CONFIG_FREERTOS_TASK_NOTIFICATION_ARRAY_ENTRIES=1
|
|||||||
# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
|
# CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
|
||||||
# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set
|
# CONFIG_FREERTOS_USE_LIST_DATA_INTEGRITY_CHECK_BYTES is not set
|
||||||
# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
|
# CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
|
||||||
CONFIG_FREERTOS_USE_TICKLESS_IDLE=y
|
|
||||||
CONFIG_FREERTOS_IDLE_TIME_BEFORE_SLEEP=3
|
|
||||||
# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set
|
# CONFIG_FREERTOS_USE_APPLICATION_TASK_TAG is not set
|
||||||
# end of Kernel
|
# end of Kernel
|
||||||
|
|
||||||
@@ -1920,7 +1909,6 @@ CONFIG_IEEE802154_CCA_THRESHOLD=-60
|
|||||||
CONFIG_IEEE802154_PENDING_TABLE_SIZE=20
|
CONFIG_IEEE802154_PENDING_TABLE_SIZE=20
|
||||||
# CONFIG_IEEE802154_MULTI_PAN_ENABLE is not set
|
# CONFIG_IEEE802154_MULTI_PAN_ENABLE is not set
|
||||||
CONFIG_IEEE802154_TIMING_OPTIMIZATION=y
|
CONFIG_IEEE802154_TIMING_OPTIMIZATION=y
|
||||||
# CONFIG_IEEE802154_SLEEP_ENABLE is not set
|
|
||||||
# CONFIG_IEEE802154_DEBUG is not set
|
# CONFIG_IEEE802154_DEBUG is not set
|
||||||
# CONFIG_IEEE802154_DEBUG_ASSERT_MONITOR is not set
|
# CONFIG_IEEE802154_DEBUG_ASSERT_MONITOR is not set
|
||||||
# end of IEEE 802.15.4
|
# end of IEEE 802.15.4
|
||||||
@@ -2356,6 +2344,13 @@ CONFIG_LIBC_TIME_SYSCALL_USE_RTC_HRT=y
|
|||||||
#
|
#
|
||||||
# CONFIG_OPENTHREAD_ENABLED is not set
|
# CONFIG_OPENTHREAD_ENABLED is not set
|
||||||
|
|
||||||
|
#
|
||||||
|
# Thread Console
|
||||||
|
#
|
||||||
|
CONFIG_OPENTHREAD_CLI=y
|
||||||
|
CONFIG_OPENTHREAD_CONSOLE_COMMAND_PREFIX="ot"
|
||||||
|
# end of Thread Console
|
||||||
|
|
||||||
#
|
#
|
||||||
# OpenThread Spinel
|
# OpenThread Spinel
|
||||||
#
|
#
|
||||||
@@ -2568,10 +2563,6 @@ CONFIG_WIFI_PROV_STA_ALL_CHANNEL_SCAN=y
|
|||||||
# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set
|
# CONFIG_WIFI_PROV_STA_FAST_SCAN is not set
|
||||||
# end of Wi-Fi Provisioning Manager
|
# end of Wi-Fi Provisioning Manager
|
||||||
|
|
||||||
#
|
|
||||||
# ESP Socket.IO client
|
|
||||||
#
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# ESP-NimBLE-CPP configuration
|
# ESP-NimBLE-CPP configuration
|
||||||
#
|
#
|
||||||
@@ -2594,6 +2585,10 @@ CONFIG_NIMBLE_CPP_FREERTOS_TASK_BLOCK_BIT=31
|
|||||||
CONFIG_NIMBLE_CPP_IDF=y
|
CONFIG_NIMBLE_CPP_IDF=y
|
||||||
# end of ESP-NimBLE-CPP configuration
|
# end of ESP-NimBLE-CPP configuration
|
||||||
|
|
||||||
|
#
|
||||||
|
# ESP Socket.IO client
|
||||||
|
#
|
||||||
|
|
||||||
#
|
#
|
||||||
# ESP WebSocket client
|
# ESP WebSocket client
|
||||||
#
|
#
|
||||||
|
|||||||
449
src/BLE.cpp
449
src/BLE.cpp
@@ -1,19 +1,16 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "BLE.hpp"
|
#include "BLE.hpp"
|
||||||
|
#include "NimBLEDevice.h"
|
||||||
#include "WiFi.hpp"
|
#include "WiFi.hpp"
|
||||||
#include "nvs_flash.h"
|
#include "nvs_flash.h"
|
||||||
#include "socketIO.hpp"
|
#include "socketIO.hpp"
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include "bmHTTP.hpp"
|
#include "bmHTTP.hpp"
|
||||||
#include "setup.hpp"
|
|
||||||
#include "esp_mac.h"
|
#include "esp_mac.h"
|
||||||
#include "esp_netif.h"
|
|
||||||
|
|
||||||
|
|
||||||
std::atomic<bool> flag_scan_requested{false};
|
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};
|
||||||
@@ -28,24 +25,13 @@ 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;
|
||||||
std::atomic<NimBLECharacteristic*> ssidRefreshChar = nullptr;
|
std::atomic<NimBLECharacteristic*> ssidRefreshChar = nullptr;
|
||||||
std::atomic<NimBLECharacteristic*> deviceInfoChar = nullptr;
|
std::atomic<NimBLECharacteristic*> deviceInfoChar = 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() {
|
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;
|
finalAuth = false;
|
||||||
|
|
||||||
NimBLEDevice::init("BlindMaster-C6");
|
NimBLEDevice::init("BlindMaster-C6");
|
||||||
@@ -157,18 +143,126 @@ void notifyAuthStatus(bool success) {
|
|||||||
tmpConfChar->notify();
|
tmpConfChar->notify();
|
||||||
tmpConfChar->setValue(""); // Clear value after 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() {
|
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();
|
esp_wifi_scan_stop();
|
||||||
if (!finalAuth) esp_wifi_disconnect();
|
if (!finalAuth) esp_wifi_disconnect();
|
||||||
scanBlock = false;
|
scanBlock = false;
|
||||||
vSemaphoreDelete(BLE_Queue_Shutdown_Semaphore);
|
flag_scan_requested = false;
|
||||||
BLE_event_queue = xQueueCreate(10, sizeof(BLE_event_type_t));
|
credsGiven = false;
|
||||||
xTaskCreate(BLE_manager_task, "BLE", 8192, NULL, 5, &BLE_manager_task_handle);
|
tokenGiven = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
|
void MyServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo) {
|
||||||
@@ -180,7 +274,7 @@ void MyServerCallbacks::onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInf
|
|||||||
void MyServerCallbacks::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
|
void MyServerCallbacks::onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason) {
|
||||||
isBLEClientConnected = false;
|
isBLEClientConnected = false;
|
||||||
printf("Client disconnected - reason: %d\n", reason);
|
printf("Client disconnected - reason: %d\n", reason);
|
||||||
if (!finalAuth) reset();
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyCharCallbacks::onRead(NimBLECharacteristic* pChar, NimBLEConnInfo& connInfo) {
|
void MyCharCallbacks::onRead(NimBLECharacteristic* pChar, NimBLEConnInfo& connInfo) {
|
||||||
@@ -188,258 +282,89 @@ void MyCharCallbacks::onRead(NimBLECharacteristic* pChar, NimBLEConnInfo& connIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connInfo) {
|
void MyCharCallbacks::onWrite(NimBLECharacteristic* pChar, NimBLEConnInfo& connInfo) {
|
||||||
std::string val = pChar->getValue();
|
std::string val = pChar->getValue();
|
||||||
std::string uuidStr = pChar->getUUID().toString();
|
std::string uuidStr = pChar->getUUID().toString();
|
||||||
|
|
||||||
printf("onWrite called! UUID: %s, Value length: %d\n", uuidStr.c_str(), val.length());
|
printf("onWrite called! UUID: %s, Value length: %d\n", uuidStr.c_str(), val.length());
|
||||||
|
|
||||||
// Load atomic pointers for comparison
|
// Load atomic pointers for comparison
|
||||||
NimBLECharacteristic* currentCredsChar = credsChar.load();
|
NimBLECharacteristic* currentCredsChar = credsChar.load();
|
||||||
NimBLECharacteristic* currentTokenChar = tokenChar.load();
|
NimBLECharacteristic* currentTokenChar = tokenChar.load();
|
||||||
NimBLECharacteristic* currentRefreshChar = ssidRefreshChar.load();
|
NimBLECharacteristic* currentRefreshChar = ssidRefreshChar.load();
|
||||||
|
|
||||||
// Check which characteristic was written to
|
// Check which characteristic was written to
|
||||||
if (pChar == currentCredsChar) {
|
if (pChar == currentCredsChar) {
|
||||||
// Credentials JSON characteristic
|
// Credentials JSON characteristic
|
||||||
if (val.length() > 0) {
|
if (val.length() > 0) {
|
||||||
printf("Received JSON: %s\n", val.c_str());
|
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");
|
|
||||||
|
|
||||||
bool enterprise = false;
|
// Parse JSON using cJSON
|
||||||
bool open = false;
|
cJSON *root = cJSON_Parse(val.c_str());
|
||||||
bool error = false;
|
if (root != NULL) {
|
||||||
if (cJSON_IsNumber(authType)) {
|
cJSON *ssid = cJSON_GetObjectItem(root, "ssid");
|
||||||
enterprise = authType->valueint == WIFI_AUTH_WPA2_ENTERPRISE ||
|
cJSON *password = cJSON_GetObjectItem(root, "password");
|
||||||
authType->valueint == WIFI_AUTH_WPA3_ENTERPRISE;
|
cJSON *authType = cJSON_GetObjectItem(root, "auth");
|
||||||
open = authType->valueint == WIFI_AUTH_OPEN;
|
cJSON *uname = cJSON_GetObjectItem(root, "uname");
|
||||||
error = authType->valueint < 0 || authType->valueint >= WIFI_AUTH_MAX;
|
|
||||||
}
|
bool enterprise = false;
|
||||||
else error = true;
|
bool open = false;
|
||||||
if (error) {
|
bool error = false;
|
||||||
printf("ERROR: Invalid Auth mode passed in with JSON.\n");
|
if (cJSON_IsNumber(authType)) {
|
||||||
cJSON_Delete(root);
|
enterprise = authType->valueint == WIFI_AUTH_WPA2_ENTERPRISE ||
|
||||||
return;
|
authType->valueint == WIFI_AUTH_WPA3_ENTERPRISE;
|
||||||
}
|
open = authType->valueint == WIFI_AUTH_OPEN;
|
||||||
|
error = authType->valueint < 0 || authType->valueint >= WIFI_AUTH_MAX;
|
||||||
bool ssidPresent = cJSON_IsString(ssid) && ssid->valuestring != NULL;
|
}
|
||||||
bool passPresent = cJSON_IsString(password) && password->valuestring != NULL;
|
else error = true;
|
||||||
bool unamePresent = cJSON_IsString(uname) && uname->valuestring != NULL;
|
if (error) {
|
||||||
bool tempCredsGiven = ssidPresent && (passPresent || open) &&
|
printf("ERROR: Invalid Auth mode passed in with JSON.\n");
|
||||||
(unamePresent || !enterprise);
|
credsGiven = false;
|
||||||
|
cJSON_Delete(root);
|
||||||
if (tempCredsGiven) {
|
return;
|
||||||
printf("Received credentials, will attempt connection\n");
|
}
|
||||||
{
|
|
||||||
|
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);
|
std::lock_guard<std::mutex> lock(dataMutex);
|
||||||
|
|
||||||
auth = (wifi_auth_mode_t)(authType->valueint);
|
auth = (wifi_auth_mode_t)(authType->valueint);
|
||||||
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.
|
||||||
}
|
}
|
||||||
BLE_event_type_t event_type = EVENT_CREDS_GIVEN;
|
else printf("ERROR: Did not receive necessary credentials.\n");
|
||||||
if (xQueueSend(BLE_event_queue, &event_type, pdMS_TO_TICKS(10)) == pdPASS)
|
cJSON_Delete(root);
|
||||||
printf("Successfully added credsGiven to event queue\n");
|
} else {
|
||||||
else printf("CredsGiven event queue addition failed\n");
|
printf("Failed to parse JSON\n");
|
||||||
|
credsGiven = false;
|
||||||
}
|
}
|
||||||
else printf("ERROR: Did not receive necessary credentials.\n");
|
|
||||||
cJSON_Delete(root);
|
|
||||||
} else {
|
|
||||||
printf("Failed to parse JSON\n");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
else if (pChar == currentTokenChar) {
|
||||||
else if (pChar == currentTokenChar) {
|
if (val.length() > 0) {
|
||||||
if (val.length() > 0) {
|
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;
|
||||||
}
|
}
|
||||||
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) {
|
||||||
else if (pChar == currentRefreshChar) {
|
if (val == "Start") {
|
||||||
if (val == "Start") {
|
// Refresh characteristic
|
||||||
// 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");
|
printf("Refresh Requested\n");
|
||||||
if (!scanBlock) {
|
flag_scan_requested = true;
|
||||||
scanBlock = true;
|
|
||||||
printf("Scanning WiFi...\n");
|
|
||||||
WiFi::scanAndUpdateSSIDList();
|
|
||||||
}
|
|
||||||
else printf("Duplicate scan request\n");
|
|
||||||
}
|
}
|
||||||
else if (received_event_type == EVENT_TOKEN_GIVEN) {
|
else if (val == "Done") {
|
||||||
if (tokenCheck()) {
|
printf("Data read complete\n");
|
||||||
vQueueDelete(BLE_event_queue);
|
scanBlock = false;
|
||||||
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); // this is null-safe
|
}
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tokenCheck() {
|
|
||||||
if (!WiFi::isConnected()) {
|
|
||||||
printf("ERROR: token given without WiFi connection\n");
|
|
||||||
notifyAuthStatus(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
|
||||||
|
|
||||||
// --- DIAGNOSTIC: snapshot network state before HTTP ---
|
|
||||||
{
|
|
||||||
extern esp_netif_t* _diag_netif __attribute__((weak));
|
|
||||||
// Use esp_netif_get_handle_from_ifkey to get the STA netif without changing headers
|
|
||||||
esp_netif_t* sta_netif = esp_netif_get_handle_from_ifkey("WIFI_STA_DEF");
|
|
||||||
if (sta_netif) {
|
|
||||||
esp_netif_ip_info_t ip_info;
|
|
||||||
esp_netif_get_ip_info(sta_netif, &ip_info);
|
|
||||||
printf("[DIAG tokenCheck] IP: " IPSTR "\n", IP2STR(&ip_info.ip));
|
|
||||||
|
|
||||||
esp_netif_dns_info_t dns;
|
|
||||||
if (esp_netif_get_dns_info(sta_netif, ESP_NETIF_DNS_MAIN, &dns) == ESP_OK)
|
|
||||||
printf("[DIAG tokenCheck] DNS: " IPSTR "\n", IP2STR(&dns.ip.u_addr.ip4));
|
|
||||||
else
|
|
||||||
printf("[DIAG tokenCheck] DNS: NOT SET\n");
|
|
||||||
} else {
|
|
||||||
printf("[DIAG tokenCheck] Could not get STA netif handle\n");
|
|
||||||
}
|
|
||||||
printf("[DIAG tokenCheck] WiFi::isConnected() = %d\n", (int)WiFi::isConnected());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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) {
|
|
||||||
notifyAuthStatus(false);
|
|
||||||
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 = WiFi::attemptConnect(tmpSSID.c_str(), tmpUNAME.c_str(), tmpPASS.c_str(), tmpAUTH);
|
|
||||||
else wifiConnect = WiFi::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);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// notify errored
|
|
||||||
notifyConnectionStatus(false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
# This file was automatically generated for projects
|
# This file was automatically generated for projects
|
||||||
# without default 'CMakeLists.txt' file.
|
# without default 'CMakeLists.txt' file.
|
||||||
|
|
||||||
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.* ${CMAKE_SOURCE_DIR}/test/*.*)
|
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
|
||||||
|
|
||||||
idf_component_register(SRCS ${app_sources}
|
idf_component_register(SRCS ${app_sources}
|
||||||
INCLUDE_DIRS "." "${CMAKE_SOURCE_DIR}/test"
|
INCLUDE_DIRS "."
|
||||||
REQUIRES nvs_flash esp-nimble-cpp esp_socketio_client)
|
REQUIRES nvs_flash esp-nimble-cpp esp_socketio_client)
|
||||||
|
|||||||
117
src/WiFi.cpp
117
src/WiFi.cpp
@@ -2,11 +2,8 @@
|
|||||||
#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"
|
|
||||||
#include "esp_netif.h"
|
|
||||||
#include "lwip/dns.h"
|
|
||||||
|
|
||||||
TaskHandle_t WiFi::awaitConnectHandle = NULL;
|
std::atomic<bool> WiFi::authFailed{false};
|
||||||
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;
|
||||||
@@ -15,6 +12,8 @@ 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) {
|
||||||
@@ -39,33 +38,26 @@ 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");
|
||||||
if (awaitConnectHandle != NULL) {
|
authFailed = true;
|
||||||
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");
|
||||||
if (awaitConnectHandle != NULL) {
|
authFailed = true;
|
||||||
xTaskNotify(awaitConnectHandle, false, eSetValueWithOverwrite);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case WIFI_REASON_ASSOC_LEAVE: // Reason 8 - Manual disconnect
|
case WIFI_REASON_ASSOC_LEAVE: // Reason 8 - Manual disconnect
|
||||||
printf("Manual disconnect, not retrying\n");
|
printf("Manual disconnect, not retrying\n");
|
||||||
esp_netif_dhcpc_start(netif);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
@@ -83,9 +75,6 @@ void WiFi::event_handler(void* arg, esp_event_base_t event_base,
|
|||||||
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));
|
||||||
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
|
||||||
if (awaitConnectHandle != NULL) {
|
|
||||||
xTaskNotify(awaitConnectHandle, true, eSetValueWithOverwrite);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +110,6 @@ 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 ---
|
||||||
@@ -184,59 +172,19 @@ bool WiFi::attemptConnect(const std::string ssid, const std::string uname,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool WiFi::awaitConnected() {
|
bool WiFi::awaitConnected() {
|
||||||
awaitConnectHandle = xTaskGetCurrentTaskHandle();
|
authFailed = false;
|
||||||
if (esp_wifi_connect() != ESP_OK) {
|
if (esp_wifi_connect() != ESP_OK) return false;
|
||||||
awaitConnectHandle = NULL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t status;
|
uint8_t attempts = 0;
|
||||||
uint8_t MAX_TIMEOUT = 10; //seconds
|
while (!isConnected() && attempts < 20) {
|
||||||
if (xTaskNotifyWait(0, ULONG_MAX, &status, pdMS_TO_TICKS(MAX_TIMEOUT * 1000)) == pdTRUE) {
|
if (authFailed) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
} else {
|
vTaskDelay(500);
|
||||||
// Timeout - check if connected anyway
|
attempts++;
|
||||||
awaitConnectHandle = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isConnected()) {
|
|
||||||
// --- DIAGNOSTIC: snapshot network state before DHCP stop ---
|
|
||||||
// Save IP and DNS before stopping DHCP — dhcpc_stop clears both
|
|
||||||
esp_netif_ip_info_t ip_info;
|
|
||||||
esp_netif_get_ip_info(netif, &ip_info);
|
|
||||||
esp_netif_dns_info_t dns_main, dns_backup;
|
|
||||||
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_main);
|
|
||||||
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_backup);
|
|
||||||
|
|
||||||
esp_netif_dhcpc_stop(netif);
|
|
||||||
|
|
||||||
// Re-apply IP and DNS as static configuration
|
|
||||||
esp_netif_set_ip_info(netif, &ip_info);
|
|
||||||
esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_main);
|
|
||||||
esp_netif_set_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_backup);
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -244,6 +192,8 @@ 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();
|
||||||
|
|
||||||
@@ -274,13 +224,7 @@ 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();
|
||||||
@@ -312,33 +256,4 @@ void WiFi::processScanResults() {
|
|||||||
free(ap_list);
|
free(ap_list);
|
||||||
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\n");
|
|
||||||
esp_netif_ip_info_t ip_info;
|
|
||||||
esp_netif_get_ip_info(netif, &ip_info);
|
|
||||||
esp_netif_dns_info_t dns_main, dns_backup;
|
|
||||||
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_main);
|
|
||||||
esp_netif_get_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_backup);
|
|
||||||
|
|
||||||
esp_netif_dhcpc_stop(netif);
|
|
||||||
|
|
||||||
esp_netif_set_ip_info(netif, &ip_info);
|
|
||||||
esp_netif_set_dns_info(netif, ESP_NETIF_DNS_MAIN, &dns_main);
|
|
||||||
esp_netif_set_dns_info(netif, ESP_NETIF_DNS_BACKUP, &dns_backup);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
printf("DHCP Renewal failed. Reconnecting Wi-Fi...\n");
|
|
||||||
esp_wifi_disconnect();
|
|
||||||
return awaitConnected();
|
|
||||||
}
|
}
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
|
|
||||||
// // 3. Post Event to System Loop
|
|
||||||
// battery_data_t data = { .soc = soc, .voltage = voltage };
|
|
||||||
|
|
||||||
// esp_event_post(BATTERY_EVENTS, BATTERY_EVENT_UPDATE, &data, sizeof(data), 0);
|
|
||||||
|
|
||||||
// // Optional: Post warnings
|
|
||||||
// if (soc < 20.0) {
|
|
||||||
// esp_event_post(BATTERY_EVENTS, BATTERY_EVENT_LOW, NULL, 0, 0);
|
|
||||||
// }
|
|
||||||
@@ -63,59 +63,6 @@ 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) {
|
||||||
|
|||||||
@@ -1,16 +1,6 @@
|
|||||||
#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;
|
||||||
@@ -112,58 +102,11 @@ bool Calibration::completeCalib(Encoder& topEnc) {
|
|||||||
|
|
||||||
int32_t Calibration::convertToTicks(uint8_t appPos) {
|
int32_t Calibration::convertToTicks(uint8_t appPos) {
|
||||||
// appPos between 0 and 10, convert to target encoder ticks.
|
// appPos between 0 and 10, convert to target encoder ticks.
|
||||||
return (((int32_t)appPos * (UpTicks - DownTicks)) / 10) + DownTicks + ((UpTicks - DownTicks) / 20);
|
return (((int32_t)appPos * (UpTicks - DownTicks)) / 10) + DownTicks;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Calibration::convertToAppPos(int32_t ticks) {
|
uint8_t Calibration::convertToAppPos(int32_t ticks) {
|
||||||
// appPos between 0 and 10, convert to target encoder ticks.
|
// appPos between 0 and 10, convert to target encoder 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");
|
|
||||||
// Socket is now authenticated. Tell the server this device is not
|
|
||||||
// calibrated so it resets DB state and notifies the app to show the
|
|
||||||
// pre-calibration screen. The device stays connected, so when the user
|
|
||||||
// taps Calibrate the subsequent calib_start event will arrive here.
|
|
||||||
emitCalibStatus(false, 1);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -51,8 +51,8 @@ void IRAM_ATTR Encoder::isr_handler(void* arg)
|
|||||||
if (calibListen) servoCalibListen();
|
if (calibListen) servoCalibListen();
|
||||||
if (encoder->feedWDog) {
|
if (encoder->feedWDog) {
|
||||||
esp_timer_stop(encoder->watchdog_handle);
|
esp_timer_stop(encoder->watchdog_handle);
|
||||||
esp_timer_start_once(encoder->watchdog_handle, 2000000);
|
esp_timer_start_once(encoder->watchdog_handle, 500000);
|
||||||
// debugLEDTgl();
|
debugLEDTgl();
|
||||||
}
|
}
|
||||||
if (encoder->wandListen) servoWandListen();
|
if (encoder->wandListen) servoWandListen();
|
||||||
if (encoder->serverListen) servoServerListen();
|
if (encoder->serverListen) servoServerListen();
|
||||||
@@ -63,8 +63,8 @@ void IRAM_ATTR Encoder::isr_handler(void* arg)
|
|||||||
if (calibListen) servoCalibListen();
|
if (calibListen) servoCalibListen();
|
||||||
if (encoder->feedWDog) {
|
if (encoder->feedWDog) {
|
||||||
esp_timer_stop(encoder->watchdog_handle);
|
esp_timer_stop(encoder->watchdog_handle);
|
||||||
esp_timer_start_once(encoder->watchdog_handle, 2000000);
|
esp_timer_start_once(encoder->watchdog_handle, 500000);
|
||||||
// debugLEDTgl();
|
debugLEDTgl();
|
||||||
}
|
}
|
||||||
if (encoder->wandListen) servoWandListen();
|
if (encoder->wandListen) servoWandListen();
|
||||||
if (encoder->serverListen) servoServerListen();
|
if (encoder->serverListen) servoServerListen();
|
||||||
@@ -112,7 +112,7 @@ void Encoder::setupWatchdog() {
|
|||||||
ESP_ERROR_CHECK(esp_timer_create(&enc_watchdog_args, &watchdog_handle));
|
ESP_ERROR_CHECK(esp_timer_create(&enc_watchdog_args, &watchdog_handle));
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_ERROR_CHECK(esp_timer_start_once(watchdog_handle, 2000000));
|
ESP_ERROR_CHECK(esp_timer_start_once(watchdog_handle, 500000));
|
||||||
feedWDog = true;
|
feedWDog = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
20
src/i2c.c
20
src/i2c.c
@@ -1,20 +0,0 @@
|
|||||||
#include "i2c.h"
|
|
||||||
#include "driver/i2c.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "max17048.h"
|
|
||||||
|
|
||||||
// Helper: Initializes I2C controller at 100kHz, returns 0=success
|
|
||||||
esp_err_t i2c_init() {
|
|
||||||
// 1. Initialize I2C
|
|
||||||
i2c_config_t conf = {
|
|
||||||
.mode = I2C_MODE_MASTER,
|
|
||||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
|
||||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
|
||||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
|
||||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
|
||||||
.master.clk_speed = I2C_MASTER_FREQ_HZ,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (i2c_param_config(I2C_MASTER_NUM, &conf) ||
|
|
||||||
i2c_driver_install(I2C_MASTER_NUM, conf.mode, 0, 0, 0));
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,2 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
bubblesnake/esp_socketio_client: "^1.0.0"
|
bubblesnake/esp_socketio_client: "^1.0.0"
|
||||||
esp-nimble-cpp:
|
|
||||||
git: https://github.com/h2zero/esp-nimble-cpp.git
|
|
||||||
96
src/main.cpp
96
src/main.cpp
@@ -8,17 +8,27 @@
|
|||||||
#include "socketIO.hpp"
|
#include "socketIO.hpp"
|
||||||
#include "encoder.hpp"
|
#include "encoder.hpp"
|
||||||
#include "calibration.hpp"
|
#include "calibration.hpp"
|
||||||
#include "esp_pm.h"
|
|
||||||
#include "mainEventLoop.hpp"
|
|
||||||
#include "max17048.h"
|
|
||||||
#include "bms_test.hpp"
|
|
||||||
#include "servo_test.hpp"
|
|
||||||
#include "encoder_test.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)
|
||||||
|
|
||||||
|
// Global calibration instance
|
||||||
|
Calibration calib;
|
||||||
|
|
||||||
|
void switchOnOffServo() {
|
||||||
|
while (1) {
|
||||||
|
printf("Servo On\n");
|
||||||
|
servoOn(CCW, manual);
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||||
|
printf("Servo Off\n");
|
||||||
|
servoOff();
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(2000));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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
|
||||||
@@ -28,36 +38,72 @@ void mainApp() {
|
|||||||
}
|
}
|
||||||
ESP_ERROR_CHECK(ret);
|
ESP_ERROR_CHECK(ret);
|
||||||
|
|
||||||
main_event_queue = xQueueCreate(10, sizeof(main_event_type_t));
|
bmWiFi.init();
|
||||||
|
calib.init();
|
||||||
WiFi::init();
|
|
||||||
Calibration::init();
|
|
||||||
|
|
||||||
// Initialize encoders
|
// Initialize encoders
|
||||||
topEnc->init();
|
topEnc->init();
|
||||||
bottomEnc->init();
|
bottomEnc->init();
|
||||||
servoInit();
|
servoInit();
|
||||||
max17048_init();
|
|
||||||
printf("beforeSetup\n");
|
|
||||||
setupAndCalibrate();
|
|
||||||
printf("afterSetup\n");
|
|
||||||
|
|
||||||
xTaskCreate(wakeTimer, "wakeTimer", 2048, NULL, 5, &wakeTaskHandle);
|
// switchOnOffServo();
|
||||||
|
|
||||||
mainEventLoop();
|
setupLoop();
|
||||||
|
|
||||||
|
statusResolved = false;
|
||||||
|
|
||||||
|
int32_t prevCount = topEnc->getCount();
|
||||||
|
|
||||||
|
// Main loop
|
||||||
|
while (1) {
|
||||||
|
// websocket disconnect/reconnect handling
|
||||||
|
if (statusResolved) {
|
||||||
|
if (!connected) {
|
||||||
|
printf("Disconnected! Beginning setup loop.\n");
|
||||||
|
stopSocketIO();
|
||||||
|
setupLoop();
|
||||||
|
}
|
||||||
|
else printf("Reconnected!\n");
|
||||||
|
statusResolved = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clearCalibFlag) {
|
||||||
|
calib.clearCalibrated();
|
||||||
|
emitCalibStatus(false);
|
||||||
|
clearCalibFlag = false;
|
||||||
|
}
|
||||||
|
if (savePosFlag) {
|
||||||
|
servoSavePos();
|
||||||
|
savePosFlag = false;
|
||||||
|
|
||||||
|
// Send position update to server
|
||||||
|
uint8_t currentAppPos = calib.convertToAppPos(topEnc->getCount());
|
||||||
|
emitPosHit(currentAppPos);
|
||||||
|
|
||||||
|
printf("Sent pos_hit: position %d\n", currentAppPos);
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pm_init() {
|
void encoderTest() {
|
||||||
esp_pm_config_t pm_config = {
|
// Create encoder instance
|
||||||
.max_freq_mhz = 160, // Max CPU frequency
|
Encoder encoder(ENCODER_PIN_A, ENCODER_PIN_B);
|
||||||
.min_freq_mhz = 80, // Min CPU frequency (DFS)
|
encoder.init();
|
||||||
.light_sleep_enable = true // ALLOW CPU to power down during idle
|
|
||||||
};
|
int32_t prevCount = encoder.getCount();
|
||||||
ESP_ERROR_CHECK(esp_pm_configure(&pm_config));
|
|
||||||
|
while (1) {
|
||||||
|
int32_t currentCount = encoder.getCount();
|
||||||
|
if (currentCount != prevCount) {
|
||||||
|
prevCount = currentCount;
|
||||||
|
printf("Encoder Pos: %d\n", prevCount);
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void app_main() {
|
extern "C" void app_main() {
|
||||||
pm_init();
|
|
||||||
mainApp();
|
mainApp();
|
||||||
// servo_test();
|
// encoderTest();
|
||||||
}
|
}
|
||||||
@@ -1,220 +0,0 @@
|
|||||||
#include "mainEventLoop.hpp"
|
|
||||||
#include "calibration.hpp"
|
|
||||||
#include "setup.hpp"
|
|
||||||
#include "servo.hpp"
|
|
||||||
#include "bmHTTP.hpp"
|
|
||||||
#include "cJSON.h"
|
|
||||||
#include "encoder.hpp"
|
|
||||||
#include "WiFi.hpp"
|
|
||||||
#include "socketIO.hpp"
|
|
||||||
#include "max17048.h"
|
|
||||||
#include "esp_sleep.h"
|
|
||||||
#include "defines.h"
|
|
||||||
|
|
||||||
// Give C linkage so max17048.c (a C translation unit) can link against these
|
|
||||||
extern "C" {
|
|
||||||
TaskHandle_t wakeTaskHandle = NULL;
|
|
||||||
QueueHandle_t main_event_queue = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Battery helpers ───────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
static const char* battAlertTypeStr(batt_alert_type_t type) {
|
|
||||||
switch (type) {
|
|
||||||
case BATT_ALERT_OVERVOLTAGE: return "overvoltage";
|
|
||||||
case BATT_ALERT_CRITICAL_LOW: return "critical_low";
|
|
||||||
case BATT_ALERT_LOW_VOLTAGE_WARNING: return "low_voltage_warning";
|
|
||||||
case BATT_ALERT_SOC_LOW_20: return "low_20";
|
|
||||||
case BATT_ALERT_SOC_LOW_10: return "low_10";
|
|
||||||
default: return "unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool postBatteryAlert(batt_alert_type_t type, uint8_t soc) {
|
|
||||||
cJSON* payload = cJSON_CreateObject();
|
|
||||||
cJSON_AddStringToObject(payload, "type", battAlertTypeStr(type));
|
|
||||||
cJSON_AddNumberToObject(payload, "soc", soc);
|
|
||||||
cJSON* response = nullptr;
|
|
||||||
bool ok = httpPOST("battery_alert", webToken, payload, response);
|
|
||||||
cJSON_Delete(payload);
|
|
||||||
if (response) cJSON_Delete(response);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool postBatterySoc(uint8_t soc) {
|
|
||||||
cJSON* payload = cJSON_CreateObject();
|
|
||||||
cJSON_AddNumberToObject(payload, "soc", soc);
|
|
||||||
cJSON* response = nullptr;
|
|
||||||
bool ok = httpPOST("battery_update", webToken, payload, response);
|
|
||||||
cJSON_Delete(payload);
|
|
||||||
if (response) cJSON_Delete(response);
|
|
||||||
return ok;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Position helpers ──────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
bool postServoPos(uint8_t currentAppPos) {
|
|
||||||
cJSON* posData = cJSON_CreateObject();
|
|
||||||
cJSON_AddNumberToObject(posData, "port", 1);
|
|
||||||
cJSON_AddNumberToObject(posData, "pos", currentAppPos);
|
|
||||||
|
|
||||||
cJSON* response = nullptr;
|
|
||||||
bool success = httpPOST("position", webToken, posData, response);
|
|
||||||
cJSON_Delete(posData);
|
|
||||||
|
|
||||||
if (success && response != nullptr) {
|
|
||||||
cJSON* awaitCalibItem = cJSON_GetObjectItem(response, "await_calib");
|
|
||||||
bool awaitCalib = cJSON_IsBool(awaitCalibItem) && awaitCalibItem->valueint != 0;
|
|
||||||
printf("Position update sent: %d, await_calib=%d\n", currentAppPos, awaitCalib);
|
|
||||||
cJSON_Delete(response);
|
|
||||||
|
|
||||||
if (awaitCalib) {
|
|
||||||
gpio_set_level(debugLED, 1); // Start with LED off
|
|
||||||
gpio_hold_en(debugLED);
|
|
||||||
Calibration::clearCalibrated();
|
|
||||||
if (!calibrate()) {
|
|
||||||
if (!WiFi::attemptDHCPrenewal())
|
|
||||||
setupAndCalibrate();
|
|
||||||
else if (!calibrate()) {
|
|
||||||
printf("ERROR: EVEN AFTER DHCP RENEWAL, SOCKET OPENING FAIL\n");
|
|
||||||
setupAndCalibrate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gpio_hold_dis(debugLED);
|
|
||||||
gpio_set_level(debugLED, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getServoPos() {
|
|
||||||
cJSON* response = nullptr;
|
|
||||||
bool success = httpGET("position", webToken, response);
|
|
||||||
|
|
||||||
if (success && response != NULL) {
|
|
||||||
if (cJSON_IsArray(response)) {
|
|
||||||
int arraySize = cJSON_GetArraySize(response);
|
|
||||||
|
|
||||||
if (arraySize > 1) {
|
|
||||||
printf("Multiple peripherals detected, entering setup.\n");
|
|
||||||
cJSON_Delete(response);
|
|
||||||
return false;
|
|
||||||
} 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: EVEN AFTER DHCP RENEWAL, SOCKET OPENING FAIL\n");
|
|
||||||
setupAndCalibrate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cJSON* pos = cJSON_GetObjectItem(firstObject, "last_pos");
|
|
||||||
runToAppPos(pos->valueint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cJSON_Delete(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Wake timer (fires every 60 s) ────────────────────────────────────────────
|
|
||||||
|
|
||||||
void wakeTimer(void* pvParameters) {
|
|
||||||
while (1) {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(60000));
|
|
||||||
if (setupTaskHandle != NULL || socketIOactive
|
|
||||||
|| uxQueueMessagesWaiting(main_event_queue) > 2) continue;
|
|
||||||
|
|
||||||
main_event_type_t evt = EVENT_REQUEST_POS;
|
|
||||||
xQueueSend(main_event_queue, &evt, portMAX_DELAY);
|
|
||||||
|
|
||||||
evt = EVENT_REPORT_SOC;
|
|
||||||
xQueueSend(main_event_queue, &evt, portMAX_DELAY);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ── Main event loop ───────────────────────────────────────────────────────────
|
|
||||||
|
|
||||||
void mainEventLoop() {
|
|
||||||
main_event_type_t received_event_type;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (!xQueueReceive(main_event_queue, &received_event_type, portMAX_DELAY)) continue;
|
|
||||||
|
|
||||||
if (received_event_type == EVENT_CLEAR_CALIB) {
|
|
||||||
Calibration::clearCalibrated();
|
|
||||||
if (!calibrate()) {
|
|
||||||
if (!WiFi::attemptDHCPrenewal())
|
|
||||||
setupAndCalibrate();
|
|
||||||
else if (!calibrate()) {
|
|
||||||
printf("ERROR: EVEN AFTER DHCP RENEWAL, 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 but still failed to post position\n");
|
|
||||||
setupAndCalibrate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (received_event_type == EVENT_REQUEST_POS) {
|
|
||||||
if (!getServoPos()) {
|
|
||||||
printf("Failed to get position\n");
|
|
||||||
if (!WiFi::attemptDHCPrenewal()) {
|
|
||||||
setupAndCalibrate();
|
|
||||||
getServoPos();
|
|
||||||
} else if (!getServoPos()) {
|
|
||||||
printf("Renewed DHCP but still failed to get position\n");
|
|
||||||
setupAndCalibrate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (received_event_type == EVENT_BATTERY_CRITICAL) {
|
|
||||||
// Stop the motor immediately, persist position, notify server, then hibernate.
|
|
||||||
// esp_deep_sleep_start() with no wakeup source = indefinite sleep until reset.
|
|
||||||
// The MAX17048 VRESET comparator handles detection of battery recovery.
|
|
||||||
servoOff();
|
|
||||||
servoSavePos();
|
|
||||||
batt_alert_type_t alertType = bms_pending_alert; // snapshot volatile
|
|
||||||
postBatteryAlert(alertType, established_soc);
|
|
||||||
printf("CRITICAL BATTERY EVENT (%s, SOC=%d%%). Entering deep sleep.\n",
|
|
||||||
battAlertTypeStr(alertType), established_soc);
|
|
||||||
esp_deep_sleep_start();
|
|
||||||
|
|
||||||
} else if (received_event_type == EVENT_BATTERY_WARNING) {
|
|
||||||
postBatteryAlert((batt_alert_type_t)bms_pending_alert, established_soc);
|
|
||||||
|
|
||||||
} else if (received_event_type == EVENT_REPORT_SOC) {
|
|
||||||
postBatterySoc(established_soc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vTaskDelete(NULL);
|
|
||||||
}
|
|
||||||
175
src/max17048.c
175
src/max17048.c
@@ -1,175 +0,0 @@
|
|||||||
#include "max17048.h"
|
|
||||||
#include "mainEventLoop.hpp"
|
|
||||||
#include "i2c.h"
|
|
||||||
#include "esp_err.h"
|
|
||||||
#include "esp_log.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
|
|
||||||
static const char *TAG = "BATTERY";
|
|
||||||
|
|
||||||
uint8_t established_soc = 100;
|
|
||||||
volatile batt_alert_type_t bms_pending_alert = BATT_ALERT_CRITICAL_LOW;
|
|
||||||
|
|
||||||
static TaskHandle_t bms_event_handler = NULL;
|
|
||||||
|
|
||||||
void IRAM_ATTR alrt_ISR(void* arg) {
|
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
||||||
vTaskNotifyGiveFromISR(bms_event_handler, &xHigherPriorityTaskWoken);
|
|
||||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t max17048_init() {
|
|
||||||
esp_err_t err = ESP_OK;
|
|
||||||
err |= i2c_init();
|
|
||||||
err |= bms_set_alert_bound_voltages(3.3f, 4.2f);
|
|
||||||
err |= bms_set_reset_voltage(3.25f);
|
|
||||||
err |= bms_set_alsc();
|
|
||||||
|
|
||||||
xTaskCreate(bms_checker_task, "BMS", 4096, NULL, 20, &bms_event_handler);
|
|
||||||
|
|
||||||
gpio_config_t io_conf = {
|
|
||||||
.pin_bit_mask = (1ULL << maxALRT),
|
|
||||||
.mode = GPIO_MODE_INPUT,
|
|
||||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
|
||||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
||||||
.intr_type = GPIO_INTR_NEGEDGE,
|
|
||||||
};
|
|
||||||
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1);
|
|
||||||
gpio_isr_handler_add(maxALRT, alrt_ISR, NULL);
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "MAX17048 initialized, ALRT interrupt on GPIO %d", maxALRT);
|
|
||||||
|
|
||||||
err |= bms_clear_status();
|
|
||||||
err |= bms_clear_alrt();
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t bms_get_soc() {
|
|
||||||
uint16_t raw_soc;
|
|
||||||
if (max17048_read_reg(MAX17048_REG_SOC, ((uint8_t*)&raw_soc) + 1, (uint8_t*)&raw_soc) == ESP_OK) {
|
|
||||||
// upper byte = whole percent; lower byte msb = 0.5%; round to nearest
|
|
||||||
return (uint8_t)(raw_soc >> 8) + ((raw_soc & 0x80) ? 1 : 0);
|
|
||||||
}
|
|
||||||
ESP_LOGE(TAG, "Failed to read SOC register");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t bms_set_alert_bound_voltages(float min, float max) {
|
|
||||||
uint8_t minVal = (uint8_t)((uint16_t)(min * 1000.0f) / 20);
|
|
||||||
uint8_t maxVal = (uint8_t)((uint16_t)(max * 1000.0f) / 20);
|
|
||||||
return max17048_write_reg(MAX17048_REG_VALRT, minVal, maxVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t bms_set_reset_voltage(float vreset) {
|
|
||||||
uint8_t val = (uint8_t)((uint16_t)(vreset * 1000.0f) / 40);
|
|
||||||
return max17048_write_reg(MAX17048_REG_VRST_ID, val, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bms_checker_task(void *pvParameters) {
|
|
||||||
uint8_t prev_soc = 100;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
|
||||||
|
|
||||||
uint8_t status, _;
|
|
||||||
if (max17048_read_reg(MAX17048_REG_STATUS, &status, &_) != ESP_OK) {
|
|
||||||
ESP_LOGE(TAG, "STATUS read failed");
|
|
||||||
bms_clear_alrt();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t soc = bms_get_soc();
|
|
||||||
established_soc = soc;
|
|
||||||
|
|
||||||
// Clear before posting to queue so ALRT pin is deasserted promptly
|
|
||||||
bms_clear_status();
|
|
||||||
bms_clear_alrt();
|
|
||||||
|
|
||||||
main_event_type_t evt;
|
|
||||||
|
|
||||||
if ((status & HDbit) || ((status & VLbit) && soc < SOC_CRITICAL_VL)) {
|
|
||||||
// Critical: overvoltage (hardware fault) or battery truly empty
|
|
||||||
bms_pending_alert = (status & VHbit) ? BATT_ALERT_OVERVOLTAGE : BATT_ALERT_CRITICAL_LOW;
|
|
||||||
evt = EVENT_BATTERY_CRITICAL;
|
|
||||||
xQueueSend(main_event_queue, &evt, portMAX_DELAY);
|
|
||||||
|
|
||||||
} else if (status & VLbit) {
|
|
||||||
// Undervoltage but SOC still healthy — likely a transient load spike
|
|
||||||
bms_pending_alert = BATT_ALERT_LOW_VOLTAGE_WARNING;
|
|
||||||
evt = EVENT_BATTERY_WARNING;
|
|
||||||
xQueueSend(main_event_queue, &evt, portMAX_DELAY);
|
|
||||||
|
|
||||||
} else if (status & SCbit) {
|
|
||||||
// 1% SOC change: check downward threshold crossings for user notifications
|
|
||||||
if (soc <= SOC_WARN_10 && prev_soc > SOC_WARN_10) {
|
|
||||||
bms_pending_alert = BATT_ALERT_SOC_LOW_10;
|
|
||||||
evt = EVENT_BATTERY_WARNING;
|
|
||||||
xQueueSend(main_event_queue, &evt, portMAX_DELAY);
|
|
||||||
} else if (soc <= SOC_WARN_20 && prev_soc > SOC_WARN_20) {
|
|
||||||
bms_pending_alert = BATT_ALERT_SOC_LOW_20;
|
|
||||||
evt = EVENT_BATTERY_WARNING;
|
|
||||||
xQueueSend(main_event_queue, &evt, portMAX_DELAY);
|
|
||||||
}
|
|
||||||
prev_soc = soc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper: Read 16-bit register to 2-byte array (MSB first big endian)
|
|
||||||
esp_err_t max17048_read_reg(uint8_t reg_addr, uint8_t *MSB, uint8_t *LSB) {
|
|
||||||
// this is better than converting to little endian for my application
|
|
||||||
// since I usually need to handle bytes individually.
|
|
||||||
uint8_t data[2];
|
|
||||||
// Write register address
|
|
||||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
|
||||||
i2c_master_start(cmd);
|
|
||||||
i2c_master_write_byte(cmd, (MAX17048_ADDR << 1) | I2C_MASTER_WRITE, true);
|
|
||||||
i2c_master_write_byte(cmd, reg_addr, true);
|
|
||||||
|
|
||||||
// Restart and Read 2 bytes
|
|
||||||
i2c_master_start(cmd);
|
|
||||||
i2c_master_write_byte(cmd, (MAX17048_ADDR << 1) | I2C_MASTER_READ, true);
|
|
||||||
i2c_master_read(cmd, data, 2, I2C_MASTER_LAST_NACK);
|
|
||||||
i2c_master_stop(cmd);
|
|
||||||
|
|
||||||
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
|
|
||||||
i2c_cmd_link_delete(cmd);
|
|
||||||
|
|
||||||
if (ret == ESP_OK) {
|
|
||||||
*MSB = data[0];
|
|
||||||
*LSB = data[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write big endian 2-byte array to a 16-bit register
|
|
||||||
esp_err_t max17048_write_reg(uint8_t reg_addr, uint8_t MSB, uint8_t LSB) {
|
|
||||||
// Write register address
|
|
||||||
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
|
||||||
i2c_master_start(cmd);
|
|
||||||
i2c_master_write_byte(cmd, (MAX17048_ADDR << 1) | I2C_MASTER_WRITE, true);
|
|
||||||
i2c_master_write_byte(cmd, reg_addr, true);
|
|
||||||
i2c_master_write_byte(cmd, MSB, true);
|
|
||||||
i2c_master_write_byte(cmd, LSB, true);
|
|
||||||
i2c_master_stop(cmd);
|
|
||||||
|
|
||||||
esp_err_t ret = i2c_master_cmd_begin(I2C_MASTER_NUM, cmd, pdMS_TO_TICKS(I2C_MASTER_TIMEOUT_MS));
|
|
||||||
i2c_cmd_link_delete(cmd);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t max17048_friendly_write_reg(uint8_t reg_addr, uint8_t MSB, uint8_t LSB,
|
|
||||||
uint8_t MSBmask, uint8_t LSBmask) {
|
|
||||||
uint8_t origMSB, origLSB;
|
|
||||||
esp_err_t err = max17048_read_reg(reg_addr, &origMSB, &origLSB);
|
|
||||||
MSB &= MSBmask;
|
|
||||||
LSB &= LSBmask;
|
|
||||||
MSB |= origMSB & ~MSBmask;
|
|
||||||
LSB |= origLSB & ~LSBmask;
|
|
||||||
return err | max17048_write_reg(reg_addr, MSB, LSB);
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,10 @@
|
|||||||
#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};
|
||||||
@@ -14,6 +12,8 @@ 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() {
|
||||||
@@ -23,7 +23,7 @@ void servoInit() {
|
|||||||
ledc_timer.timer_num = LEDC_TIMER_0;
|
ledc_timer.timer_num = LEDC_TIMER_0;
|
||||||
ledc_timer.duty_resolution = LEDC_TIMER_16_BIT;
|
ledc_timer.duty_resolution = LEDC_TIMER_16_BIT;
|
||||||
ledc_timer.freq_hz = 50;
|
ledc_timer.freq_hz = 50;
|
||||||
ledc_timer.clk_cfg = LEDC_USE_RC_FAST_CLK;
|
ledc_timer.clk_cfg = LEDC_AUTO_CLK;
|
||||||
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
||||||
|
|
||||||
// LEDC channel configuration
|
// LEDC channel configuration
|
||||||
@@ -35,9 +35,7 @@ void servoInit() {
|
|||||||
ledc_channel.gpio_num = servoPin;
|
ledc_channel.gpio_num = servoPin;
|
||||||
ledc_channel.duty = offSpeed; // Start off
|
ledc_channel.duty = offSpeed; // Start off
|
||||||
ledc_channel.hpoint = 0;
|
ledc_channel.hpoint = 0;
|
||||||
ledc_channel.sleep_mode = LEDC_SLEEP_MODE_KEEP_ALIVE;
|
|
||||||
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
||||||
gpio_sleep_sel_dis(servoPin);
|
|
||||||
|
|
||||||
// Configure servo power switch pin as output
|
// Configure servo power switch pin as output
|
||||||
gpio_reset_pin(servoSwitch);
|
gpio_reset_pin(servoSwitch);
|
||||||
@@ -45,14 +43,13 @@ void servoInit() {
|
|||||||
gpio_set_level(servoSwitch, 0); // Start with servo power off
|
gpio_set_level(servoSwitch, 0); // Start with servo power off
|
||||||
|
|
||||||
// Configure debug LED pin as output
|
// Configure debug LED pin as output
|
||||||
gpio_reset_pin(debugLED);
|
gpio_reset_pin(GPIO_NUM_22);
|
||||||
gpio_set_direction(debugLED, GPIO_MODE_OUTPUT);
|
gpio_set_direction(debugLED, GPIO_MODE_OUTPUT);
|
||||||
gpio_set_level(debugLED, 0); // Start with LED off
|
gpio_set_level(debugLED, 0); // Start with LED off
|
||||||
|
|
||||||
topEnc->count = servoReadPos();
|
topEnc->count = servoReadPos();
|
||||||
bottomEnc->count = servoReadPos();
|
if (calib.getCalibrated()) initMainLoop();
|
||||||
if (Calibration::getCalibrated()) initMainLoop();
|
debugLEDSwitch(1);
|
||||||
// debugLEDSwitch(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void servoOn(uint8_t dir, uint8_t manOrServer) {
|
void servoOn(uint8_t dir, uint8_t manOrServer) {
|
||||||
@@ -91,7 +88,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 (!Calibration::clearCalibrated()) return false;
|
if (!calib.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;
|
||||||
@@ -121,7 +118,7 @@ bool servoBeginDownwardCalib() {
|
|||||||
calibListen = false;
|
calibListen = false;
|
||||||
servoOff();
|
servoOff();
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
if (!Calibration::beginDownwardCalib(*topEnc)) return false;
|
if (!calib.beginDownwardCalib(*topEnc)) return false;
|
||||||
baseDiff = bottomEnc->getCount() - topEnc->getCount();
|
baseDiff = bottomEnc->getCount() - topEnc->getCount();
|
||||||
calibListen = true;
|
calibListen = true;
|
||||||
return true;
|
return true;
|
||||||
@@ -131,7 +128,7 @@ bool servoCompleteCalib() {
|
|||||||
calibListen = false;
|
calibListen = false;
|
||||||
servoOff();
|
servoOff();
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
vTaskDelay(pdMS_TO_TICKS(1000));
|
||||||
if (!Calibration::completeCalib(*topEnc)) return false;
|
if (!calib.completeCalib(*topEnc)) return false;
|
||||||
initMainLoop();
|
initMainLoop();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -144,6 +141,8 @@ 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
|
||||||
|
clearCalibFlag = true;
|
||||||
topEnc->pauseWatchdog();
|
topEnc->pauseWatchdog();
|
||||||
|
|
||||||
// get ready for recalibration by clearing all these listeners
|
// get ready for recalibration by clearing all these listeners
|
||||||
@@ -151,18 +150,11 @@ void IRAM_ATTR watchdogCallback(void* arg) {
|
|||||||
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);
|
||||||
servoOff();
|
servoOff();
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
||||||
main_event_type_t evt = EVENT_CLEAR_CALIB;
|
|
||||||
BaseType_t result = xQueueSendFromISR(main_event_queue, &evt, &xHigherPriorityTaskWoken);
|
|
||||||
if (result == pdPASS) portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
|
||||||
}
|
}
|
||||||
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
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
savePosFlag = true;
|
||||||
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;
|
||||||
@@ -212,8 +204,8 @@ void servoWandListen() {
|
|||||||
stopServerRun();
|
stopServerRun();
|
||||||
|
|
||||||
// freeze atomic values
|
// freeze atomic values
|
||||||
int32_t upBound = Calibration::UpTicks;
|
int32_t upBound = calib.UpTicks;
|
||||||
int32_t downBound = Calibration::DownTicks;
|
int32_t downBound = calib.DownTicks;
|
||||||
int32_t bottomCount = bottomEnc->getCount();
|
int32_t bottomCount = bottomEnc->getCount();
|
||||||
int32_t topCount = topEnc->getCount();
|
int32_t topCount = topEnc->getCount();
|
||||||
|
|
||||||
@@ -233,20 +225,20 @@ void servoWandListen() {
|
|||||||
// otherwise, run servo in whichever direction necessary and
|
// otherwise, run servo in whichever direction necessary and
|
||||||
// ensure servo-listener is active.
|
// ensure servo-listener is active.
|
||||||
if (topCount >= (MAX(upBound, downBound) - 1)
|
if (topCount >= (MAX(upBound, downBound) - 1)
|
||||||
&& effDiff > 2) { // TODO: see whether these margins need to be removed.
|
&& effDiff > 1) { // TODO: see whether these margins need to be removed.
|
||||||
servoOff();
|
servoOff();
|
||||||
topEnc->wandListen.store(false, std::memory_order_release);
|
topEnc->wandListen.store(false, std::memory_order_release);
|
||||||
}
|
}
|
||||||
else if (topCount <= (MIN(upBound, downBound) + 1)
|
else if (topCount <= (MIN(upBound, downBound) + 1)
|
||||||
&& effDiff < -2) {
|
&& effDiff < -1) {
|
||||||
servoOff();
|
servoOff();
|
||||||
topEnc->wandListen.store(false, std::memory_order_release);
|
topEnc->wandListen.store(false, std::memory_order_release);
|
||||||
}
|
}
|
||||||
else if (effDiff > 2) {
|
else if (effDiff > 1) {
|
||||||
topEnc->wandListen.store(true, std::memory_order_release);
|
topEnc->wandListen.store(true, std::memory_order_release);
|
||||||
servoOn(CCW, manual);
|
servoOn(CCW, manual);
|
||||||
}
|
}
|
||||||
else if (effDiff < -2) {
|
else if (effDiff < -1) {
|
||||||
topEnc->wandListen.store(true, std::memory_order_release);
|
topEnc->wandListen.store(true, std::memory_order_release);
|
||||||
servoOn(CW, manual);
|
servoOn(CW, manual);
|
||||||
}
|
}
|
||||||
@@ -266,15 +258,11 @@ 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 || !Calibration::getCalibrated()) return;
|
if (runningManual || !calib.getCalibrated()) return;
|
||||||
servoOff();
|
servoOff();
|
||||||
|
|
||||||
if (Calibration::convertToAppPos(topEnc->getCount()) == appPos) {
|
target = calib.convertToTicks(appPos); // calculate target encoder position
|
||||||
printf("Already at pos: %d, not running\n", appPos);
|
printf("runToAppPos Called, running to %d from %d", target.load(), topEnc->getCount());
|
||||||
return;
|
|
||||||
}
|
|
||||||
target = Calibration::convertToTicks(appPos); // calculate target encoder position
|
|
||||||
printf("runToAppPos Called, running to %d from %d\n", target.load(), topEnc->getCount());
|
|
||||||
|
|
||||||
// allow servo position to settle
|
// allow servo position to settle
|
||||||
vTaskDelay(pdMS_TO_TICKS(500));
|
vTaskDelay(pdMS_TO_TICKS(500));
|
||||||
|
|||||||
135
src/setup.cpp
135
src/setup.cpp
@@ -1,4 +1,3 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "setup.hpp"
|
#include "setup.hpp"
|
||||||
#include "BLE.hpp"
|
#include "BLE.hpp"
|
||||||
#include "WiFi.hpp"
|
#include "WiFi.hpp"
|
||||||
@@ -6,37 +5,17 @@
|
|||||||
#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;
|
|
||||||
|
|
||||||
std::atomic<bool> awaitCalibration{false};
|
|
||||||
|
|
||||||
void initialSetup() {
|
void initialSetup() {
|
||||||
printf("Entered Setup\n");
|
printf("Entered Setup\n");
|
||||||
initBLE();
|
NimBLEAdvertising* pAdv = initBLE();
|
||||||
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
|
|
||||||
setupTaskHandle = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setupAndCalibrate() {
|
while (!BLEtick(pAdv)) {
|
||||||
gpio_reset_pin(debugLED);
|
vTaskDelay(pdMS_TO_TICKS(100));
|
||||||
gpio_set_direction(debugLED, GPIO_MODE_OUTPUT);
|
|
||||||
gpio_set_level(debugLED, 1); // Start with LED off
|
|
||||||
gpio_hold_en(debugLED);
|
|
||||||
while (1) {
|
|
||||||
setupLoop();
|
|
||||||
if (awaitCalibration) {
|
|
||||||
if (calibrate()) break;
|
|
||||||
}
|
|
||||||
else break;
|
|
||||||
}
|
}
|
||||||
gpio_hold_dis(debugLED);
|
|
||||||
gpio_set_level(debugLED, 0); // Start with LED off
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void setupLoop() {
|
void setupLoop() {
|
||||||
setupTaskHandle = xTaskGetCurrentTaskHandle();
|
|
||||||
bool initSuccess = false;
|
bool initSuccess = false;
|
||||||
while(!initSuccess) {
|
while(!initSuccess) {
|
||||||
nvs_handle_t WiFiHandle;
|
nvs_handle_t WiFiHandle;
|
||||||
@@ -52,19 +31,16 @@ void setupLoop() {
|
|||||||
// Make the RGB LED a certain color (Blue?)
|
// Make the RGB LED a certain color (Blue?)
|
||||||
nvs_close(WiFiHandle);
|
nvs_close(WiFiHandle);
|
||||||
initialSetup();
|
initialSetup();
|
||||||
continue;
|
} else if (WiFiPrefsError == ESP_OK) {
|
||||||
}
|
|
||||||
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];
|
||||||
nvs_get_str(WiFiHandle, passTag, pw, &pwSize);
|
nvs_get_str(WiFiHandle, passTag, pw, &pwSize);
|
||||||
nvs_close(WiFiHandle);
|
nvs_close(WiFiHandle);
|
||||||
if (!WiFi::attemptConnect(ssid, pw, (wifi_auth_mode_t)authMode)) {
|
if (!bmWiFi.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();
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
printf("Connected to WiFi from NVS credentials\n");
|
printf("Connected to WiFi from NVS credentials\n");
|
||||||
@@ -79,90 +55,34 @@ void setupLoop() {
|
|||||||
// 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);
|
||||||
cJSON* response = nullptr;
|
printf("Connecting to Socket.IO server with saved token...\n");
|
||||||
initSuccess = httpGET("position", webToken, response);
|
statusResolved = false;
|
||||||
if (!initSuccess) {
|
initSocketIO();
|
||||||
initialSetup();
|
|
||||||
continue;
|
// 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++;
|
||||||
}
|
}
|
||||||
initSuccess = false;
|
|
||||||
|
if (timeout_count >= MAX_TIMEOUT) {
|
||||||
if (response != NULL) {
|
printf("Timeout waiting for device_init - connection failed\n");
|
||||||
// Check if response is an array
|
stopSocketIO();
|
||||||
if (cJSON_IsArray(response)) {
|
initSuccess = false;
|
||||||
int arraySize = cJSON_GetArraySize(response);
|
initialSetup();
|
||||||
|
} else {
|
||||||
// Condition 1: More than one object in array
|
initSuccess = connected;
|
||||||
if (arraySize > 1) {
|
if (!initSuccess) {
|
||||||
printf("Multiple peripherals detected, entering setup.\n");
|
printf("Device authentication failed - 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();
|
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");
|
||||||
nvs_close(authHandle);
|
|
||||||
initialSetup();
|
initialSetup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,5 +103,4 @@ void setupLoop() {
|
|||||||
initialSetup();
|
initialSetup();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setupTaskHandle = NULL; // Clear handle on function exit (safety)
|
|
||||||
}
|
}
|
||||||
101
src/socketIO.cpp
101
src/socketIO.cpp
@@ -11,8 +11,9 @@
|
|||||||
|
|
||||||
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> socketIOactive{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,
|
||||||
@@ -64,8 +65,8 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mark connection as failed
|
// Mark connection as failed
|
||||||
if (calibTaskHandle != NULL)
|
connected = false;
|
||||||
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
statusResolved = true;
|
||||||
}
|
}
|
||||||
// Handle device_init event
|
// Handle device_init event
|
||||||
else if (strcmp(eventName->valuestring, "device_init") == 0) {
|
else if (strcmp(eventName->valuestring, "device_init") == 0) {
|
||||||
@@ -90,18 +91,25 @@ 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 = calib.getCalibrated();
|
||||||
|
emitCalibStatus(deviceCalibrated);
|
||||||
|
printf(" Reported calibrated=%d for port %d\n", deviceCalibrated, port);
|
||||||
|
runToAppPos(lastPos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now mark as connected
|
// Now mark as connected
|
||||||
if (calibTaskHandle != NULL)
|
connected = true;
|
||||||
xTaskNotify(calibTaskHandle, true, eSetValueWithOverwrite);
|
statusResolved = true;
|
||||||
} else {
|
} else {
|
||||||
printf("Device authentication failed\n");
|
printf("Device authentication failed\n");
|
||||||
Calibration::clearCalibrated();
|
calib.clearCalibrated();
|
||||||
deleteWiFiAndTokenDetails();
|
deleteWiFiAndTokenDetails();
|
||||||
if (calibTaskHandle != NULL)
|
connected = false;
|
||||||
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
statusResolved = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -115,10 +123,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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Calibration::clearCalibrated();
|
calib.clearCalibrated();
|
||||||
deleteWiFiAndTokenDetails();
|
deleteWiFiAndTokenDetails();
|
||||||
if (calibTaskHandle != NULL)
|
connected = false;
|
||||||
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
statusResolved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle calib_start event
|
// Handle calib_start event
|
||||||
@@ -180,21 +188,13 @@ 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 {
|
else emitCalibDone();
|
||||||
emitCalibDone();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// Handle user_stage1_complete 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,6 +211,37 @@ 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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,8 +293,8 @@ static void socketio_event_handler(void *handler_args, esp_event_base_t base,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (calibTaskHandle != NULL)
|
connected = false;
|
||||||
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
statusResolved = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -271,29 +302,26 @@ 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");
|
||||||
if (calibTaskHandle != NULL)
|
connected = false;
|
||||||
xTaskNotify(calibTaskHandle, false, eSetValueWithOverwrite);
|
statusResolved = true;
|
||||||
}
|
|
||||||
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();
|
||||||
|
|
||||||
if (secureSrv) {
|
if (secureSrv) {
|
||||||
config.websocket_config.transport = WEBSOCKET_TRANSPORT_OVER_SSL;
|
config.websocket_config.transport = WEBSOCKET_TRANSPORT_OVER_SSL;
|
||||||
config.websocket_config.crt_bundle_attach = esp_crt_bundle_attach;
|
config.websocket_config.crt_bundle_attach = esp_crt_bundle_attach;
|
||||||
}
|
}
|
||||||
|
|
||||||
io_client = esp_socketio_client_init(&config);
|
io_client = esp_socketio_client_init(&config);
|
||||||
@@ -301,8 +329,6 @@ void initSocketIO() {
|
|||||||
|
|
||||||
esp_socketio_register_events(io_client, SOCKETIO_EVENT_ANY, socketio_event_handler, NULL);
|
esp_socketio_register_events(io_client, SOCKETIO_EVENT_ANY, socketio_event_handler, NULL);
|
||||||
esp_socketio_client_start(io_client);
|
esp_socketio_client_start(io_client);
|
||||||
|
|
||||||
socketIOactive = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopSocketIO() {
|
void stopSocketIO() {
|
||||||
@@ -312,8 +338,9 @@ 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;
|
||||||
}
|
}
|
||||||
socketIOactive = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to emit Socket.IO event with data
|
// Helper function to emit Socket.IO event with data
|
||||||
|
|||||||
@@ -1,112 +0,0 @@
|
|||||||
#include "bms_test.hpp"
|
|
||||||
#include "i2c.h"
|
|
||||||
#include "max17048.h"
|
|
||||||
#include "defines.h"
|
|
||||||
|
|
||||||
void bms_test_LED() {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
|
||||||
i2c_init();
|
|
||||||
|
|
||||||
gpio_config_t led_conf = {
|
|
||||||
.pin_bit_mask = (1ULL << debugLED),
|
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
|
||||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
|
||||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
||||||
.intr_type = GPIO_INTR_DISABLE,
|
|
||||||
};
|
|
||||||
gpio_config(&led_conf);
|
|
||||||
|
|
||||||
bms_set_alert_bound_voltages(3.8f, 3.9f);
|
|
||||||
bms_clear_status();
|
|
||||||
bms_clear_alrt();
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
uint8_t msb, lsb;
|
|
||||||
if (max17048_read_reg(MAX17048_REG_STATUS, &msb, &lsb) == ESP_OK) {
|
|
||||||
bool vh = !!(msb & VHbit);
|
|
||||||
bool vl = !!(msb & VLbit);
|
|
||||||
|
|
||||||
bms_clear_status();
|
|
||||||
bms_clear_alrt();
|
|
||||||
if (vl) {
|
|
||||||
// Under-voltage: LED off
|
|
||||||
gpio_set_level(debugLED, 0);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
} else if (vh) {
|
|
||||||
// Over-voltage: rapid blink
|
|
||||||
gpio_set_level(debugLED, 1);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
gpio_set_level(debugLED, 0);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(100));
|
|
||||||
} else {
|
|
||||||
// Normal: LED on
|
|
||||||
gpio_set_level(debugLED, 1);
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bms_test() {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
|
||||||
esp_err_t err = i2c_init();
|
|
||||||
|
|
||||||
printf("Error after init: %d\n", err);
|
|
||||||
|
|
||||||
gpio_config_t io_conf = {
|
|
||||||
.pin_bit_mask = (1ULL << maxALRT),
|
|
||||||
.mode = GPIO_MODE_INPUT,
|
|
||||||
.pull_up_en = GPIO_PULLUP_ENABLE,
|
|
||||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
|
||||||
.intr_type = GPIO_INTR_DISABLE,
|
|
||||||
};
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
|
|
||||||
printf("BMS test running. Polling ALRT pin every 1s...\n");
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t msb, lsb;
|
|
||||||
if (max17048_read_reg(MAX17048_REG_STATUS, &msb, &lsb) == ESP_OK) {
|
|
||||||
printf(" STATUS before clear: RI=%d\n", !!(msb & RIbit));
|
|
||||||
printf(" STATUS reg before clear: RI=%x, %x\n", msb, lsb);
|
|
||||||
} else {
|
|
||||||
printf(" STATUS read FAILED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bms_set_alert_bound_voltages(3.3f, 4.2f);
|
|
||||||
printf("Error after boundV: %d\n", err);
|
|
||||||
err |= bms_clear_status();
|
|
||||||
printf("Error after clearStatus: %d\n", err);
|
|
||||||
err |= bms_clear_alrt();
|
|
||||||
printf("Error after clearALRT: %d\n", err);
|
|
||||||
|
|
||||||
if (max17048_read_reg(MAX17048_REG_STATUS, &msb, &lsb) == ESP_OK) {
|
|
||||||
printf(" STATUS after clear: RI=%d\n", !!(msb & RIbit));
|
|
||||||
printf(" STATUS reg after clear: RI=%x, %x\n", msb, lsb);
|
|
||||||
} else {
|
|
||||||
printf(" STATUS read FAILED\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
int level = gpio_get_level(maxALRT);
|
|
||||||
printf("ALRT pin: %s\n", level ? "HIGH (no alert)" : "LOW (alert asserted)");
|
|
||||||
|
|
||||||
if (level == 0) {
|
|
||||||
if (max17048_read_reg(MAX17048_REG_STATUS, &msb, &lsb) == ESP_OK) {
|
|
||||||
printf(" STATUS: VH=%d VL=%d HD=%d SC=%d\n",
|
|
||||||
!!(msb & VHbit),
|
|
||||||
!!(msb & VLbit),
|
|
||||||
!!(msb & HDbit),
|
|
||||||
!!(msb & SCbit));
|
|
||||||
bms_clear_status();
|
|
||||||
bms_clear_alrt();
|
|
||||||
} else {
|
|
||||||
printf(" STATUS read FAILED\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(1000));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
#ifndef BMS_TEST_H
|
|
||||||
#define BMS_TEST_H
|
|
||||||
|
|
||||||
void bms_test();
|
|
||||||
void bms_test_LED();
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
#include "encoder_test.hpp"
|
|
||||||
#include "defines.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
#include "freertos/queue.h"
|
|
||||||
#include "soc/gpio_struct.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t encoder_id; // 0 = top, 1 = bottom
|
|
||||||
int8_t direction; // +1 or -1
|
|
||||||
} enc_event_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
gpio_num_t pin_a;
|
|
||||||
gpio_num_t pin_b;
|
|
||||||
uint8_t id;
|
|
||||||
uint8_t last_a;
|
|
||||||
uint8_t last_b;
|
|
||||||
int8_t base;
|
|
||||||
} enc_state_t;
|
|
||||||
|
|
||||||
static QueueHandle_t enc_queue;
|
|
||||||
static enc_state_t enc_states[2];
|
|
||||||
static bool led_state = false;
|
|
||||||
|
|
||||||
static void IRAM_ATTR enc_isr(void* arg) {
|
|
||||||
enc_state_t* s = (enc_state_t*)arg;
|
|
||||||
|
|
||||||
uint32_t levels = GPIO.in.val;
|
|
||||||
uint8_t a = (levels >> s->pin_a) & 1;
|
|
||||||
uint8_t b = (levels >> s->pin_b) & 1;
|
|
||||||
|
|
||||||
if (a != s->last_a) {
|
|
||||||
if (!a) s->base += b ? 1 : -1;
|
|
||||||
else s->base += b ? -1 : 1;
|
|
||||||
} else if (b != s->last_b) {
|
|
||||||
if (!b) s->base += a ? -1 : 1;
|
|
||||||
else s->base += a ? 1 : -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->last_a = a;
|
|
||||||
s->last_b = b;
|
|
||||||
|
|
||||||
enc_event_t evt;
|
|
||||||
evt.encoder_id = s->id;
|
|
||||||
BaseType_t woken = pdFALSE;
|
|
||||||
|
|
||||||
if (s->base >= 4) {
|
|
||||||
s->base -= 4;
|
|
||||||
evt.direction = 1;
|
|
||||||
led_state = !led_state;
|
|
||||||
gpio_set_level(debugLED, led_state);
|
|
||||||
xQueueSendFromISR(enc_queue, &evt, &woken);
|
|
||||||
portYIELD_FROM_ISR(woken);
|
|
||||||
} else if (s->base <= -4) {
|
|
||||||
s->base += 4;
|
|
||||||
evt.direction = -1;
|
|
||||||
led_state = !led_state;
|
|
||||||
gpio_set_level(debugLED, led_state);
|
|
||||||
xQueueSendFromISR(enc_queue, &evt, &woken);
|
|
||||||
portYIELD_FROM_ISR(woken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void encoder_test() {
|
|
||||||
// LED
|
|
||||||
gpio_reset_pin(debugLED);
|
|
||||||
gpio_set_direction(debugLED, GPIO_MODE_OUTPUT);
|
|
||||||
gpio_set_level(debugLED, 0);
|
|
||||||
|
|
||||||
enc_queue = xQueueCreate(32, sizeof(enc_event_t));
|
|
||||||
|
|
||||||
// Init encoder states
|
|
||||||
enc_states[0] = { ENCODER_PIN_A, ENCODER_PIN_B, 0, 0, 0, 0 };
|
|
||||||
enc_states[1] = { InputEnc_PIN_A, InputEnc_PIN_B, 1, 0, 0, 0 };
|
|
||||||
|
|
||||||
// Configure encoder pins
|
|
||||||
gpio_config_t io_conf = {};
|
|
||||||
io_conf.intr_type = GPIO_INTR_ANYEDGE;
|
|
||||||
io_conf.mode = GPIO_MODE_INPUT;
|
|
||||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
|
||||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
|
||||||
io_conf.pin_bit_mask = (1ULL << ENCODER_PIN_A) | (1ULL << ENCODER_PIN_B)
|
|
||||||
| (1ULL << InputEnc_PIN_A) | (1ULL << InputEnc_PIN_B);
|
|
||||||
gpio_config(&io_conf);
|
|
||||||
|
|
||||||
gpio_install_isr_service(ESP_INTR_FLAG_LEVEL1);
|
|
||||||
gpio_isr_handler_add(ENCODER_PIN_A, enc_isr, &enc_states[0]);
|
|
||||||
gpio_isr_handler_add(ENCODER_PIN_B, enc_isr, &enc_states[0]);
|
|
||||||
gpio_isr_handler_add(InputEnc_PIN_A, enc_isr, &enc_states[1]);
|
|
||||||
gpio_isr_handler_add(InputEnc_PIN_B, enc_isr, &enc_states[1]);
|
|
||||||
|
|
||||||
printf("Encoder test running...\n");
|
|
||||||
|
|
||||||
enc_event_t evt;
|
|
||||||
while (true) {
|
|
||||||
if (xQueueReceive(enc_queue, &evt, portMAX_DELAY) == pdTRUE) {
|
|
||||||
printf("[%s] %s\n",
|
|
||||||
evt.encoder_id == 0 ? "TOP " : "BOTTOM",
|
|
||||||
evt.direction == 1 ? "CW (+1)" : "CCW (-1)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#ifndef ENCODER_TEST_H
|
|
||||||
#define ENCODER_TEST_H
|
|
||||||
|
|
||||||
void encoder_test();
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
#include "servo_test.hpp"
|
|
||||||
#include "defines.h"
|
|
||||||
#include "driver/gpio.h"
|
|
||||||
#include "driver/ledc.h"
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include "freertos/task.h"
|
|
||||||
|
|
||||||
void servo_test() {
|
|
||||||
// LEDC timer
|
|
||||||
ledc_timer_config_t ledc_timer = {};
|
|
||||||
ledc_timer.speed_mode = LEDC_LOW_SPEED_MODE;
|
|
||||||
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_USE_RC_FAST_CLK;
|
|
||||||
ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer));
|
|
||||||
|
|
||||||
// LEDC channel
|
|
||||||
ledc_channel_config_t ledc_channel = {};
|
|
||||||
ledc_channel.speed_mode = LEDC_LOW_SPEED_MODE;
|
|
||||||
ledc_channel.channel = servoLEDCChannel;
|
|
||||||
ledc_channel.timer_sel = LEDC_TIMER_0;
|
|
||||||
ledc_channel.intr_type = LEDC_INTR_DISABLE;
|
|
||||||
ledc_channel.gpio_num = servoPin;
|
|
||||||
ledc_channel.duty = offSpeed;
|
|
||||||
ledc_channel.hpoint = 0;
|
|
||||||
ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel));
|
|
||||||
|
|
||||||
// Servo switch
|
|
||||||
gpio_reset_pin(servoSwitch);
|
|
||||||
gpio_set_direction(servoSwitch, GPIO_MODE_OUTPUT);
|
|
||||||
gpio_set_level(servoSwitch, 0);
|
|
||||||
|
|
||||||
// Debug LED
|
|
||||||
gpio_reset_pin(debugLED);
|
|
||||||
gpio_set_direction(debugLED, GPIO_MODE_OUTPUT);
|
|
||||||
gpio_set_level(debugLED, 0);
|
|
||||||
|
|
||||||
// Cycle: CW on -> off -> CCW on -> off -> ...
|
|
||||||
static const uint32_t duties[4] = { cwSpeed, offSpeed, ccwSpeed, offSpeed };
|
|
||||||
static const bool switches[4] = { true, false, true, false };
|
|
||||||
|
|
||||||
int step = 0;
|
|
||||||
while (true) {
|
|
||||||
vTaskDelay(pdMS_TO_TICKS(5000));
|
|
||||||
|
|
||||||
ledc_set_duty(LEDC_LOW_SPEED_MODE, servoLEDCChannel, duties[step]);
|
|
||||||
ledc_update_duty(LEDC_LOW_SPEED_MODE, servoLEDCChannel);
|
|
||||||
gpio_set_level(servoSwitch, switches[step] ? 1 : 0);
|
|
||||||
gpio_set_level(debugLED, switches[step] ? 1 : 0);
|
|
||||||
|
|
||||||
step = (step + 1) % 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#ifndef SERVO_TEST_H
|
|
||||||
#define SERVO_TEST_H
|
|
||||||
|
|
||||||
void servo_test();
|
|
||||||
|
|
||||||
#endif
|
|
||||||
Reference in New Issue
Block a user