170 lines
6.7 KiB
C++
170 lines
6.7 KiB
C++
#include "ble_config.h"
|
|
#include <Adafruit_LittleFS.h>
|
|
#include <InternalFileSystem.h>
|
|
|
|
using namespace Adafruit_LittleFS_Namespace;
|
|
extern File cfgFile;
|
|
|
|
// ─── BLE Config Service objects ───────────────────────────────────────────────
|
|
#ifdef FEATURE_CONFIG_SERVICE
|
|
BLEService cfgService (0x1234);
|
|
BLECharacteristic cfgBlob (0x1235); // ConfigBlob R/W 16 bytes
|
|
BLECharacteristic cfgCommand (0x1236); // Command W 1 byte
|
|
#ifdef FEATURE_TELEMETRY
|
|
BLECharacteristic cfgTelemetry(0x1237); // Telemetry R/N 24 bytes
|
|
#endif
|
|
#ifdef FEATURE_IMU_STREAM
|
|
BLECharacteristic cfgImuStream(0x1238); // ImuStream N 14 bytes
|
|
#endif
|
|
#endif
|
|
|
|
// ─── Charge mode ──────────────────────────────────────────────────────────────
|
|
void applyChargeMode(ChargeMode mode) {
|
|
switch (mode) {
|
|
case CHARGE_OFF: pinMode(PIN_HICHG, INPUT_PULLUP); break;
|
|
case CHARGE_SLOW: pinMode(PIN_HICHG, OUTPUT); digitalWrite(PIN_HICHG, HIGH); break;
|
|
case CHARGE_FAST: pinMode(PIN_HICHG, OUTPUT); digitalWrite(PIN_HICHG, LOW); break;
|
|
}
|
|
const char* n[] = {"OFF (~0mA)", "SLOW (50mA)", "FAST (100mA)"};
|
|
Serial.print("[CHG] "); Serial.println(n[mode]);
|
|
}
|
|
|
|
// ─── Config persistence ───────────────────────────────────────────────────────
|
|
void loadConfig() {
|
|
InternalFS.begin();
|
|
cfgFile.open(CONFIG_FILENAME, FILE_O_READ);
|
|
if (cfgFile) {
|
|
cfgFile.read(&cfg, sizeof(cfg)); cfgFile.close();
|
|
if (cfg.magic != CONFIG_MAGIC) {
|
|
cfg = CFG_DEFAULTS; Serial.println("[CFG] Defaults (bad magic)");
|
|
} else {
|
|
Serial.println("[CFG] Loaded from flash");
|
|
}
|
|
} else { cfg = CFG_DEFAULTS; Serial.println("[CFG] Defaults (no file)"); }
|
|
}
|
|
|
|
void saveConfig() {
|
|
InternalFS.remove(CONFIG_FILENAME);
|
|
cfgFile.open(CONFIG_FILENAME, FILE_O_WRITE);
|
|
if (cfgFile) { cfgFile.write((uint8_t*)&cfg, sizeof(cfg)); cfgFile.close(); Serial.println("[CFG] Saved"); }
|
|
else { Serial.println("[CFG] ERROR: write failed"); }
|
|
}
|
|
|
|
// ─── ConfigBlob push ─────────────────────────────────────────────────────────
|
|
#ifdef FEATURE_CONFIG_SERVICE
|
|
void pushConfigBlob() {
|
|
ConfigBlob b;
|
|
b.sensitivity = cfg.sensitivity; b.deadZone = cfg.deadZone;
|
|
b.accelStrength = cfg.accelStrength; b.curve = (uint8_t)cfg.curve;
|
|
b.axisFlip = cfg.axisFlip; b.chargeMode = (uint8_t)cfg.chargeMode; b._pad = 0;
|
|
cfgBlob.write((uint8_t*)&b, sizeof(b));
|
|
}
|
|
#endif
|
|
|
|
void factoryReset() {
|
|
cfg = CFG_DEFAULTS; saveConfig();
|
|
applyChargeMode(cfg.chargeMode);
|
|
#ifdef FEATURE_CONFIG_SERVICE
|
|
if (!safeMode) pushConfigBlob();
|
|
#endif
|
|
#ifdef FEATURE_TELEMETRY
|
|
telem = {};
|
|
#endif
|
|
#ifdef FEATURE_TAP_DETECTION
|
|
statLeftClicks = statRightClicks = 0;
|
|
#endif
|
|
Serial.println("[CFG] Factory reset complete");
|
|
}
|
|
|
|
// ─── BLE callbacks ────────────────────────────────────────────────────────────
|
|
#ifdef FEATURE_CONFIG_SERVICE
|
|
void onConfigBlobWrite(uint16_t h, BLECharacteristic* c, uint8_t* d, uint16_t l) {
|
|
if (l != sizeof(ConfigBlob)) { Serial.println("[CFG] Bad blob length"); return; }
|
|
ConfigBlob* b = (ConfigBlob*)d;
|
|
cfg.sensitivity = b->sensitivity;
|
|
cfg.deadZone = b->deadZone;
|
|
cfg.accelStrength = b->accelStrength;
|
|
if (b->curve <= 2) cfg.curve = (CurveType)b->curve;
|
|
cfg.axisFlip = b->axisFlip;
|
|
if (b->chargeMode <= 2) { cfg.chargeMode = (ChargeMode)b->chargeMode; applyChargeMode(cfg.chargeMode); }
|
|
saveConfig();
|
|
Serial.print("[CFG] Written — sens="); Serial.print(cfg.sensitivity,0);
|
|
Serial.print(" dz="); Serial.print(cfg.deadZone,3);
|
|
Serial.print(" curve="); Serial.print(cfg.curve);
|
|
Serial.print(" chg="); Serial.println(cfg.chargeMode);
|
|
}
|
|
|
|
void onCommandWrite(uint16_t h, BLECharacteristic* c, uint8_t* d, uint16_t l) {
|
|
if (l < 1) return;
|
|
if (d[0] == 0x01) pendingCal = true;
|
|
if (d[0] == 0xFF) pendingReset = true;
|
|
}
|
|
|
|
#ifdef FEATURE_IMU_STREAM
|
|
void onImuStreamCccd(uint16_t conn_hdl, BLECharacteristic* chr, uint16_t value) {
|
|
imuStreamEnabled = (value == BLE_GATT_HVX_NOTIFICATION);
|
|
Serial.print("[STREAM] "); Serial.println(imuStreamEnabled ? "ON" : "OFF");
|
|
}
|
|
#endif
|
|
|
|
// ─── BLE config service setup ─────────────────────────────────────────────────
|
|
void setupConfigService() {
|
|
cfgService.begin();
|
|
|
|
cfgBlob.setProperties(CHR_PROPS_READ | CHR_PROPS_WRITE);
|
|
cfgBlob.setPermission(SECMODE_OPEN, SECMODE_OPEN);
|
|
cfgBlob.setFixedLen(sizeof(ConfigBlob));
|
|
cfgBlob.setWriteCallback(onConfigBlobWrite);
|
|
cfgBlob.begin();
|
|
pushConfigBlob();
|
|
|
|
cfgCommand.setProperties(CHR_PROPS_WRITE);
|
|
cfgCommand.setPermission(SECMODE_OPEN, SECMODE_OPEN);
|
|
cfgCommand.setFixedLen(1);
|
|
cfgCommand.setWriteCallback(onCommandWrite);
|
|
cfgCommand.begin();
|
|
|
|
#ifdef FEATURE_TELEMETRY
|
|
cfgTelemetry.setProperties(CHR_PROPS_READ | CHR_PROPS_NOTIFY);
|
|
cfgTelemetry.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
|
|
cfgTelemetry.setFixedLen(sizeof(TelemetryPacket));
|
|
cfgTelemetry.begin();
|
|
cfgTelemetry.write((uint8_t*)&telem, sizeof(telem));
|
|
#endif
|
|
|
|
#ifdef FEATURE_IMU_STREAM
|
|
cfgImuStream.setProperties(CHR_PROPS_NOTIFY);
|
|
cfgImuStream.setPermission(SECMODE_OPEN, SECMODE_NO_ACCESS);
|
|
cfgImuStream.setFixedLen(sizeof(ImuPacket));
|
|
cfgImuStream.setCccdWriteCallback(onImuStreamCccd);
|
|
cfgImuStream.begin();
|
|
#endif
|
|
|
|
Serial.print("[BLE] ATT_TABLE_SIZE="); Serial.print(ATT_TABLE_SIZE);
|
|
Serial.print(" | chars=2");
|
|
#ifdef FEATURE_TELEMETRY
|
|
Serial.print("+TELEM");
|
|
#endif
|
|
#ifdef FEATURE_IMU_STREAM
|
|
Serial.print("+STREAM");
|
|
#endif
|
|
Serial.println();
|
|
}
|
|
#endif // FEATURE_CONFIG_SERVICE
|
|
|
|
// ─── Telemetry push ───────────────────────────────────────────────────────────
|
|
#ifdef FEATURE_TELEMETRY
|
|
void pushTelemetry(unsigned long now) {
|
|
telem.uptimeSeconds = now / 1000;
|
|
telem.tempCelsius = cachedTempC;
|
|
telem.biasRmsRadS = statBiasRms;
|
|
telem.recalCount = statRecalCount;
|
|
#ifdef FEATURE_TAP_DETECTION
|
|
telem.leftClicks = statLeftClicks;
|
|
telem.rightClicks = statRightClicks;
|
|
#endif
|
|
cfgTelemetry.write ((uint8_t*)&telem, sizeof(telem));
|
|
cfgTelemetry.notify((uint8_t*)&telem, sizeof(telem));
|
|
}
|
|
#endif
|