fix(batt-led): force LED off + disarm on disconnect
The low-battery blink would stay frozen mid-cycle (or briefly resume during reconnect retries) after a controller died and lost connection, because the stale-report check stopped toggling but never turned the LED off, and the cached interrupt_in_data[52] still read low. New `battery_led_on_disconnect()` clears blink state, forces the LED off, and zeros last_report_us so the stale-check early-return blocks any new blink until a fresh 0x31 report arrives on the next connection. Called from bt.cpp's HCI_EVENT_DISCONNECTION_COMPLETE handler. Stale-check in the tick also now forces LED off when it fires while a blink was in progress (defense in depth for unclean disconnects). Same bug exists in upstream awalol/DS5Dongle (their battery_led.cpp is byte-identical to ours pre-fix) — Sura Academy reported it in their Discord. Plan to send this back as a PR after we validate it locally. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
9e6269d413
commit
fb68ea5608
+20
-2
@@ -37,11 +37,29 @@ void battery_led_note_report(void) {
|
|||||||
last_report_us = time_us_64();
|
last_report_us = time_us_64();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void battery_led_on_disconnect(void) {
|
||||||
|
// Stop any in-progress blink and force the LED off immediately. Zero
|
||||||
|
// last_report_us so the tick's stale-check early-returns until a fresh
|
||||||
|
// 0x31 report arrives on the next connection — prevents the cached
|
||||||
|
// low-battery byte from re-arming a blink during reconnect retries.
|
||||||
|
blinking = false;
|
||||||
|
led_state = false;
|
||||||
|
last_report_us = 0;
|
||||||
|
last_toggle_us = 0;
|
||||||
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, false);
|
||||||
|
}
|
||||||
|
|
||||||
void battery_led_tick(void) {
|
void battery_led_tick(void) {
|
||||||
const uint64_t now = time_us_64();
|
const uint64_t now = time_us_64();
|
||||||
if (last_report_us == 0 || (now - last_report_us) >= REPORT_STALE_US) {
|
if (last_report_us == 0 || (now - last_report_us) >= REPORT_STALE_US) {
|
||||||
// No fresh data — bt.cpp owns the LED while disconnected.
|
// No fresh data — bt.cpp owns the LED while disconnected. If we
|
||||||
blinking = false;
|
// were mid-blink when the report went stale, force the LED off
|
||||||
|
// so it doesn't freeze in whichever half-cycle it was in.
|
||||||
|
if (blinking) {
|
||||||
|
blinking = false;
|
||||||
|
led_state = false;
|
||||||
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, false);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,3 +16,11 @@ void battery_led_tick(void);
|
|||||||
// has been copied into interrupt_in_data. Used to detect disconnection
|
// has been copied into interrupt_in_data. Used to detect disconnection
|
||||||
// via stale-report timeout.
|
// via stale-report timeout.
|
||||||
void battery_led_note_report(void);
|
void battery_led_note_report(void);
|
||||||
|
|
||||||
|
// Call from the BT disconnect handler. Cancels any in-progress blink,
|
||||||
|
// forces the LED off, and arms the module so it ignores the cached
|
||||||
|
// (now-stale) battery byte until a fresh report arrives on the next
|
||||||
|
// connection. Without this, the LED can stay frozen in whichever state
|
||||||
|
// it was at the moment of disconnect, or briefly resume blinking during
|
||||||
|
// reconnect retries while interrupt_in_data[52] still reads low.
|
||||||
|
void battery_led_on_disconnect(void);
|
||||||
|
|||||||
@@ -19,6 +19,9 @@
|
|||||||
#include "state_mgr.h"
|
#include "state_mgr.h"
|
||||||
#include "pico/util/queue.h"
|
#include "pico/util/queue.h"
|
||||||
#include "slots.h"
|
#include "slots.h"
|
||||||
|
#if ENABLE_BATT_LED
|
||||||
|
#include "battery_led.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define MTU_CONTROL 672
|
#define MTU_CONTROL 672
|
||||||
#define MTU_INTERRUPT 672
|
#define MTU_INTERRUPT 672
|
||||||
@@ -454,6 +457,9 @@ static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *p
|
|||||||
hid_interrupt_cid = 0;
|
hid_interrupt_cid = 0;
|
||||||
feature_data.clear();
|
feature_data.clear();
|
||||||
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, false);
|
cyw43_arch_gpio_put(CYW43_WL_GPIO_LED_PIN, false);
|
||||||
|
#if ENABLE_BATT_LED
|
||||||
|
battery_led_on_disconnect();
|
||||||
|
#endif
|
||||||
printf("[HCI] Disconnected reason=0x%02X, start inquiry\n", reason);
|
printf("[HCI] Disconnected reason=0x%02X, start inquiry\n", reason);
|
||||||
gap_inquiry_start(30);
|
gap_inquiry_start(30);
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user