218 lines
9.4 KiB
C
218 lines
9.4 KiB
C
#pragma once
|
||
#include <Arduino.h>
|
||
|
||
// ─── Feature Flags ────────────────────────────────────────────────────────────
|
||
#define FEATURE_CONFIG_SERVICE
|
||
#define FEATURE_TELEMETRY
|
||
#define FEATURE_IMU_STREAM
|
||
#define FEATURE_TAP_DETECTION
|
||
#define FEATURE_TEMP_COMPENSATION
|
||
#define FEATURE_AUTO_RECAL
|
||
#define FEATURE_BATTERY_MONITOR
|
||
#define FEATURE_BOOT_LOOP_DETECT
|
||
|
||
// ─── Debug ────────────────────────────────────────────────────────────────────
|
||
// #define DEBUG
|
||
|
||
// ─── ATT table size ───────────────────────────────────────────────────────────
|
||
#define _ATT_BASE 900
|
||
#ifdef FEATURE_CONFIG_SERVICE
|
||
#define _ATT_CFG 100 // +20 for cfgGitHash characteristic
|
||
#else
|
||
#define _ATT_CFG 0
|
||
#endif
|
||
#ifdef FEATURE_TELEMETRY
|
||
#define _ATT_TELEM 40
|
||
#else
|
||
#define _ATT_TELEM 0
|
||
#endif
|
||
#ifdef FEATURE_IMU_STREAM
|
||
#define _ATT_STREAM 30
|
||
#else
|
||
#define _ATT_STREAM 0
|
||
#endif
|
||
#define ATT_TABLE_SIZE_CALC (_ATT_BASE + _ATT_CFG + _ATT_TELEM + _ATT_STREAM)
|
||
#define ATT_TABLE_SIZE (ATT_TABLE_SIZE_CALC < 1536 ? 1536 : ATT_TABLE_SIZE_CALC)
|
||
|
||
// ─── IMU register addresses ───────────────────────────────────────────────────
|
||
#define REG_CTRL1_XL 0x10
|
||
#define REG_TAP_CFG 0x58
|
||
#define REG_TAP_THS_6D 0x59
|
||
#define REG_INT_DUR2 0x5A
|
||
#define REG_WAKE_UP_THS 0x5B
|
||
#define REG_MD1_CFG 0x5E
|
||
#define REG_TAP_SRC 0x1C
|
||
#define REG_OUT_TEMP_L 0x20
|
||
#define REG_OUT_TEMP_H 0x21
|
||
|
||
// ─── Pins ─────────────────────────────────────────────────────────────────────
|
||
#define PIN_VBAT_ENABLE (14)
|
||
#define PIN_VBAT_READ (32)
|
||
#define PIN_CHG (23)
|
||
#define PIN_HICHG (22)
|
||
|
||
// ─── Persistence ──────────────────────────────────────────────────────────────
|
||
#define CONFIG_FILENAME "/imu_mouse_cfg.bin"
|
||
#define CONFIG_MAGIC 0xDEAD123CUL
|
||
|
||
// ─── Runtime feature-override flags (cfg.featureFlags bitmask) ───────────────
|
||
// These mirror the compile-time FEATURE_* defines but can be toggled at runtime
|
||
// via the web UI and persisted in flash. Bits not listed here are reserved = 0.
|
||
#define FLAG_TAP_ENABLED 0x01 // Tap detection active (requires restart)
|
||
#define FLAG_TEMP_COMP_ENABLED 0x02 // Temperature gyro-drift compensation
|
||
#define FLAG_AUTO_RECAL_ENABLED 0x04 // Auto-recalibrate after long idle
|
||
#define FLAG_ALL_DEFAULT (FLAG_TAP_ENABLED | FLAG_TEMP_COMP_ENABLED | FLAG_AUTO_RECAL_ENABLED)
|
||
|
||
// ─── Enums ────────────────────────────────────────────────────────────────────
|
||
enum CurveType : uint8_t { CURVE_LINEAR=0, CURVE_SQUARE=1, CURVE_SQRT=2 };
|
||
enum ChargeMode : uint8_t { CHARGE_OFF=0, CHARGE_SLOW=1, CHARGE_FAST=2 };
|
||
enum ChargeStatus: uint8_t { CHGSTAT_DISCHARGING=0, CHGSTAT_CHARGING=1, CHGSTAT_FULL=2 };
|
||
|
||
// ─── Tap action types ─────────────────────────────────────────────────────────
|
||
// TAP_ACTION_KEY: fires a raw HID keycode (tapKey) with optional modifier (tapMod).
|
||
// Modifier byte: bit0=Ctrl, bit1=Shift, bit2=Alt, bit3=GUI (same as HID modifier byte).
|
||
enum TapAction : uint8_t {
|
||
TAP_ACTION_LEFT = 0,
|
||
TAP_ACTION_RIGHT = 1,
|
||
TAP_ACTION_MIDDLE = 2,
|
||
TAP_ACTION_KEY = 3,
|
||
};
|
||
|
||
// ─── Config (stored in flash) ─────────────────────────────────────────────────
|
||
struct Config {
|
||
uint32_t magic;
|
||
float sensitivity;
|
||
float deadZone;
|
||
float accelStrength;
|
||
CurveType curve;
|
||
uint8_t axisFlip;
|
||
ChargeMode chargeMode;
|
||
uint8_t tapThreshold; // 1–31 → REG_TAP_THS_6D bits[4:0]; 1 LSB = 62.5 mg at ±2g
|
||
TapAction tapAction; // what a double-tap does
|
||
uint8_t tapKey; // HID keycode (used when tapAction == TAP_ACTION_KEY)
|
||
uint8_t tapMod; // HID modifier byte (used when tapAction == TAP_ACTION_KEY)
|
||
float jerkThreshold; // jerk² threshold for tap-freeze detection
|
||
uint8_t tapFreezeEnabled; // 1 = enable jerk-based cursor freeze during taps
|
||
uint8_t featureFlags; // bitmask of FLAG_* — runtime feature overrides
|
||
};
|
||
extern Config cfg;
|
||
extern const Config CFG_DEFAULTS;
|
||
|
||
// ─── ConfigBlob (over BLE, 25 bytes) ─────────────────────────────────────────
|
||
struct __attribute__((packed)) ConfigBlob {
|
||
float sensitivity; // [0]
|
||
float deadZone; // [4]
|
||
float accelStrength; // [8]
|
||
uint8_t curve; // [12]
|
||
uint8_t axisFlip; // [13]
|
||
uint8_t chargeMode; // [14]
|
||
uint8_t tapThreshold; // [15] 1–31
|
||
uint8_t tapAction; // [16] TapAction enum
|
||
uint8_t tapKey; // [17] HID keycode
|
||
uint8_t tapMod; // [18] HID modifier
|
||
uint8_t tapFreezeEnabled; // [19] 1 = enable jerk-based cursor freeze during taps
|
||
float jerkThreshold; // [20] jerk² tap-freeze threshold
|
||
uint8_t featureFlags; // [24] FLAG_* bitmask — runtime feature overrides
|
||
};
|
||
static_assert(sizeof(ConfigBlob) == 25, "ConfigBlob must be 25 bytes");
|
||
|
||
// ─── TelemetryPacket (24 bytes) ───────────────────────────────────────────────
|
||
#ifdef FEATURE_TELEMETRY
|
||
struct __attribute__((packed)) TelemetryPacket {
|
||
uint32_t uptimeSeconds; // [0]
|
||
uint32_t leftClicks; // [4]
|
||
uint32_t rightClicks; // [8]
|
||
float tempCelsius; // [12]
|
||
float biasRmsRadS; // [16]
|
||
uint16_t recalCount; // [20]
|
||
uint8_t chargeStatus; // [22]
|
||
uint8_t _pad; // [23]
|
||
float battVoltage; // [24] raw battery voltage (V)
|
||
};
|
||
static_assert(sizeof(TelemetryPacket) == 28, "TelemetryPacket must be 28 bytes");
|
||
extern TelemetryPacket telem;
|
||
#endif
|
||
|
||
// ─── ImuPacket (14 bytes) ─────────────────────────────────────────────────────
|
||
#ifdef FEATURE_IMU_STREAM
|
||
struct __attribute__((packed)) ImuPacket {
|
||
int16_t gyroX_mDPS; // [0] pitch axis (nod up/down → cursor Y)
|
||
int16_t gyroZ_mDPS; // [2] yaw axis (pan left/right → cursor X)
|
||
int16_t accelX_mg; // [4]
|
||
int16_t accelY_mg; // [6]
|
||
int16_t accelZ_mg; // [8]
|
||
int8_t moveX; // [10]
|
||
int8_t moveY; // [11]
|
||
uint8_t flags; // [12] bit0=idle bit1=singleTap bit2=doubleTap
|
||
uint8_t _pad; // [13]
|
||
};
|
||
static_assert(sizeof(ImuPacket) == 14, "ImuPacket must be 14 bytes");
|
||
#endif
|
||
|
||
// ─── Tuning constants ─────────────────────────────────────────────────────────
|
||
extern const float ALPHA;
|
||
extern const int LOOP_RATE_MS;
|
||
extern const int BIAS_SAMPLES;
|
||
extern const int IDLE_FRAMES;
|
||
extern const unsigned long BATT_REPORT_MS;
|
||
extern const unsigned long TELEMETRY_MS;
|
||
extern const unsigned long HEARTBEAT_MS;
|
||
extern const int HEARTBEAT_DUR;
|
||
extern const unsigned long BOOT_SAFE_MS;
|
||
#ifdef FEATURE_IMU_STREAM
|
||
extern const unsigned long IMU_STREAM_RATE_MS;
|
||
#endif
|
||
extern const float BATT_FULL;
|
||
extern const float BATT_EMPTY;
|
||
extern const float BATT_CRITICAL;
|
||
#ifdef FEATURE_TAP_DETECTION
|
||
extern const unsigned long CLICK_HOLD_MS;
|
||
#endif
|
||
#ifdef FEATURE_TEMP_COMPENSATION
|
||
extern const float TEMP_COMP_COEFF_DPS_C;
|
||
#endif
|
||
#ifdef FEATURE_AUTO_RECAL
|
||
extern const unsigned long AUTO_RECAL_MS;
|
||
#endif
|
||
|
||
// ─── Global state ─────────────────────────────────────────────────────────────
|
||
extern float angleX, angleY;
|
||
extern float accumX, accumY;
|
||
extern float gravX, gravY, gravZ;
|
||
extern float biasGX, biasGY, biasGZ;
|
||
extern float calTempC;
|
||
extern float cachedTempC;
|
||
|
||
#ifdef FEATURE_TAP_DETECTION
|
||
extern bool clickButtonDown;
|
||
extern uint8_t clickButton;
|
||
extern unsigned long clickDownMs;
|
||
extern uint32_t statLeftClicks;
|
||
extern uint32_t statRightClicks;
|
||
#endif
|
||
|
||
#ifdef FEATURE_IMU_STREAM
|
||
extern bool imuStreamEnabled;
|
||
#endif
|
||
|
||
extern bool pendingCal;
|
||
extern bool pendingReset;
|
||
extern ChargeStatus lastChargeStatus;
|
||
extern int idleFrames;
|
||
extern unsigned long idleStartMs;
|
||
extern unsigned long lastTime;
|
||
extern unsigned long lastBattTime;
|
||
extern unsigned long lastHeartbeat;
|
||
extern unsigned long lastTelemetry;
|
||
extern unsigned long bootStartMs;
|
||
#ifdef FEATURE_IMU_STREAM
|
||
extern unsigned long lastImuStream;
|
||
#endif
|
||
#ifdef FEATURE_TELEMETRY
|
||
extern uint16_t statRecalCount;
|
||
extern float statBiasRms;
|
||
#endif
|
||
|
||
extern bool safeMode;
|
||
extern bool bootCountCleared;
|