Make BLE daemon resilient to device swaps and add device-initiated refresh
- Cache invalidation: drop ~/.config/claude-usage-monitor/ble-address and remove the dead MAC from bluez on connect failure, so swapping ESP boards no longer pins the daemon to a stale factory MAC - Scan robustness: pick first matching candidate (head -1), sanity-check cached content for valid MAC format, handle multiple Claude Controllers in bluez - 5s tick + 60s poll: inner loop wakes every 5s for fast disconnect detection while keeping Anthropic API cadence at one minute - Refresh-request channel: new GATT characteristic ...0004 NOTIFY, firmware fires once in onSubscribe when has_received_data is false; daemon subscribes via setsid'd dbus-monitor pipeline (process group cleanup avoids the bash-wait-on-job hang we hit on disconnect) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
97a5443601
commit
38d8894016
+33
-1
@@ -8,7 +8,8 @@
|
||||
// Custom GATT UUIDs for data channel
|
||||
#define SERVICE_UUID "4c41555a-4465-7669-6365-000000000001"
|
||||
#define RX_CHAR_UUID "4c41555a-4465-7669-6365-000000000002" // host writes here
|
||||
#define TX_CHAR_UUID "4c41555a-4465-7669-6365-000000000003" // device notifies here
|
||||
#define TX_CHAR_UUID "4c41555a-4465-7669-6365-000000000003" // device ack/nack notifies
|
||||
#define REQ_CHAR_UUID "4c41555a-4465-7669-6365-000000000004" // device-initiated refresh request
|
||||
|
||||
#define BLE_BUF_SIZE 512
|
||||
|
||||
@@ -45,11 +46,13 @@ static NimBLEHIDDevice* hid_dev = nullptr;
|
||||
static NimBLECharacteristic* input_kbd = nullptr;
|
||||
static NimBLECharacteristic* tx_char = nullptr;
|
||||
static NimBLECharacteristic* rx_char = nullptr;
|
||||
static NimBLECharacteristic* req_char = nullptr;
|
||||
|
||||
static ble_state_t state = BLE_STATE_INIT;
|
||||
static bool need_advertise = false;
|
||||
static char rx_buf[BLE_BUF_SIZE];
|
||||
static volatile bool data_ready = false;
|
||||
static volatile bool has_received_data = false;
|
||||
static char mac_str[18];
|
||||
|
||||
static void start_advertising() {
|
||||
@@ -86,6 +89,19 @@ class RxCallbacks : public NimBLECharacteristicCallbacks {
|
||||
memcpy(rx_buf, val.c_str(), len);
|
||||
rx_buf[len] = '\0';
|
||||
data_ready = true;
|
||||
has_received_data = true;
|
||||
}
|
||||
};
|
||||
|
||||
// When the daemon enables notifications on the refresh char, ask for data
|
||||
// if we have none yet. Firing on subscribe (not on connect) ensures the
|
||||
// notification isn't dropped before the daemon's CCCD write completes.
|
||||
class ReqCallbacks : public NimBLECharacteristicCallbacks {
|
||||
void onSubscribe(NimBLECharacteristic* chr, NimBLEConnInfo& info, uint16_t subValue) override {
|
||||
Serial.printf("BLE: req_char onSubscribe subValue=%u has_data=%d\n", subValue, has_received_data ? 1 : 0);
|
||||
if (subValue != 0 && !has_received_data) {
|
||||
ble_request_refresh();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -128,6 +144,13 @@ void ble_init(void) {
|
||||
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY
|
||||
);
|
||||
|
||||
req_char = svc->createCharacteristic(
|
||||
REQ_CHAR_UUID,
|
||||
NIMBLE_PROPERTY::NOTIFY
|
||||
);
|
||||
static ReqCallbacks reqCb;
|
||||
req_char->setCallbacks(&reqCb);
|
||||
|
||||
svc->start();
|
||||
server->start();
|
||||
start_advertising();
|
||||
@@ -186,6 +209,15 @@ void ble_send_nack(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void ble_request_refresh(void) {
|
||||
if (state == BLE_STATE_CONNECTED && req_char) {
|
||||
uint8_t v = 0x01;
|
||||
req_char->setValue(&v, 1);
|
||||
req_char->notify();
|
||||
Serial.println("BLE: refresh requested");
|
||||
}
|
||||
}
|
||||
|
||||
void ble_keyboard_press(uint8_t key, uint8_t modifier) {
|
||||
if (state != BLE_STATE_CONNECTED || !input_kbd) return;
|
||||
// HID report: [modifier, reserved, key1, key2, key3, key4, key5, key6]
|
||||
|
||||
Reference in New Issue
Block a user