Files

128 lines
5.5 KiB
C++

#pragma once
/**
* @file BleManager.h
* @brief BLE Central (client) manager using NimBLE-Arduino.
*
* Responsibilities:
* - Scan for the Marine Gateway peripheral ("MarineGateway")
* - Establish a secure, bonded connection (passkey entry via Serial/Web)
* - Subscribe to all five NOTIFY characteristics and parse incoming JSON
* - Provide thread-safe access to the aggregated BoatState
* - Send autopilot and admin commands
* - Manage automatic reconnection
*/
#include "Config.h"
#include <NimBLEDevice.h>
class BleManager : public NimBLEClientCallbacks,
public NimBLEScanCallbacks {
public:
/**
* @brief Initialise the NimBLE stack and start scanning.
* Must be called once from setup().
*/
void begin();
/**
* @brief Call from loop() — handles reconnect scheduling and
* dispatches any pending state changes.
*/
void update();
// ── Data access (thread-safe) ─────────────────────────────────────────────
/**
* @brief Copy the current BoatState snapshot into @p dst.
* Protected by an internal mutex.
*/
void getBoatState(BoatState& dst) const;
/** @brief Returns true when actively connected to the gateway. */
bool isConnected() const;
/** @brief Current BLE status for status LED / UI. */
AppState::BleStatus status() const { return _status; }
// ── Command senders ───────────────────────────────────────────────────────
/** @brief Send an autopilot command (e.g. "adjust+1"). */
bool sendAutopilotCmd(const char* command);
/** @brief Send a raw admin JSON command string. */
bool sendAdminCmd(const char* jsonCmd);
// Convenience admin helpers
bool sendRestart();
bool sendWifiSta(const char* ssid, const char* password);
bool sendWifiAp(const char* ssid, const char* password);
// ── Passkey (pairing) ─────────────────────────────────────────────────────
/**
* @brief Provide the passkey entered by the user.
* Called by the WiFi web UI when the user submits the PIN.
*/
void providePasskey(uint32_t pin);
private:
// BLE callback trampolines declared in BleManager.cpp
friend void navNotifyCB(NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
friend void windNotifyCB(NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
friend void autopilotNotifyCB(NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
friend void perfNotifyCB(NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
friend void adminNotifyCB(NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
// ── NimBLEClientCallbacks ─────────────────────────────────────────────────
void onConnect(NimBLEClient* pClient) override;
void onDisconnect(NimBLEClient* pClient, int reason) override;
void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pin) override;
void onAuthenticationComplete(NimBLEConnInfo& connInfo) override;
// ── NimBLEScanCallbacks ───────────────────────────────────────────────────
void onResult(const NimBLEAdvertisedDevice* device) override;
void onScanEnd(const NimBLEScanResults& results, int reason) override;
// ── Internal helpers ──────────────────────────────────────────────────────
bool _connectToServer(const NimBLEAddress& addr);
bool _subscribeAll();
void _startScan();
void _scheduleReconnect();
// Notification callbacks (one per characteristic)
void _onNavNotify (NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
void _onWindNotify (NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
void _onAutopilotNotify(NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
void _onPerfNotify (NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
void _onAdminNotify (NimBLERemoteCharacteristic*, uint8_t*, size_t, bool);
// JSON parsers
void _parseNav (const char* json);
void _parseWind (const char* json);
void _parseAutopilot(const char* json);
void _parsePerf (const char* json);
void _parseAdmin (const char* json);
// ── State ─────────────────────────────────────────────────────────────────
NimBLEClient* _pClient = nullptr;
NimBLEAddress _targetAddr;
bool _targetFound = false;
bool _doConnect = false;
bool _subscribePending = false;
bool _subscribed = false;
uint32_t _reconnectAt = 0; ///< millis() when next reconnect is due
AppState::BleStatus _status = AppState::BleStatus::IDLE;
mutable portMUX_TYPE _mux = portMUX_INITIALIZER_UNLOCKED;
BoatState _state;
// Pending passkey from the web UI
volatile bool _passkeyPending = false;
volatile uint32_t _passkey = 0;
};
// Singleton accessor
extern BleManager bleManager;