Send large BLE host frames across multiple notifies.

Prefer ATT MTU 517 and chunk oversized responses so CLIENT_INFO/BATTERY work with many pods; reset the goTool parser after timeouts so partial frames do not poison the next exchange.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-11-01 23:53:40 +01:00
co-authored by Cursor
parent 9046677460
commit 141176a824
7 changed files with 114 additions and 42 deletions
+13
View File
@@ -22,6 +22,7 @@ type bleLink struct {
device bluetooth.Device
char bluetooth.DeviceCharacteristic
mu sync.Mutex
parserMu sync.Mutex
parser *uartframe.Parser
respCh chan []byte
streamCh chan []byte
@@ -162,6 +163,8 @@ func connectBLEDevice(addr bluetooth.Address, settle time.Duration) (*bleLink, e
}
func (b *bleLink) onNotify(buf []byte) {
b.parserMu.Lock()
defer b.parserMu.Unlock()
for _, by := range buf {
payload, ok, err := b.parser.Feed(by)
if err != nil || !ok {
@@ -195,6 +198,12 @@ func (b *bleLink) onNotify(buf []byte) {
}
}
func (b *bleLink) resetParser() {
b.parserMu.Lock()
b.parser = uartframe.NewParser()
b.parserMu.Unlock()
}
func (b *bleLink) Close() error {
return b.device.Disconnect()
}
@@ -243,6 +252,9 @@ sent:
for {
remain := time.Until(deadline)
if remain <= 0 {
// Drop a half-parsed frame (e.g. aborted multi-notify) so the next
// exchange does not treat a new 0xAA as payload data.
b.resetParser()
return nil, fmt.Errorf("BLE read timeout for %s (check DIP8=BLE / -ble)", cmdName)
}
timer := time.NewTimer(remain)
@@ -264,6 +276,7 @@ sent:
}
return resp, nil
case <-timer.C:
b.resetParser()
return nil, fmt.Errorf("BLE read timeout for %s (check DIP8=BLE / -ble)", cmdName)
}
}