feat: user path to resume BT from low-memory pause via reader menu toggle
Field session: after a recovery teardown the heap settles at ~72 KB -- below the 100 KB start floor -- and never recovers on its own (the defrag silent-restart only fires when a build FAILS, and builds succeed now). BT stayed paused forever, the menu toggle claimed ON, and toggling off/on changed nothing. - Menu label tells the truth: ON / PAUSED (enabled but stack down) / OFF (new STR_STATE_PAUSED string) - Toggling BT on below the heap floor silent-restarts into the current book: the fresh boot's ~118 KB passes the gate and BT auto-starts on resume. Explicit user intent is the right trigger for the defrag. - Hoist the floor to bleinput::kStartMinFreeHeap, shared by the lifecycle gate and the toggle
This commit is contained in:
@@ -299,6 +299,8 @@ STR_BT_NO_PAIRED: "No paired devices"
|
|||||||
STR_BT_MAP_BUTTONS: "Map Remote Buttons"
|
STR_BT_MAP_BUTTONS: "Map Remote Buttons"
|
||||||
STR_BT_PRESS_REMOTE: "Press a button on your remote"
|
STR_BT_PRESS_REMOTE: "Press a button on your remote"
|
||||||
STR_BT_CONNECTING_POPUP: "BT Connecting..."
|
STR_BT_CONNECTING_POPUP: "BT Connecting..."
|
||||||
|
STR_BT_PAUSED_LOW_MEM_POPUP: "BT paused (low memory)"
|
||||||
|
STR_STATE_PAUSED: "PAUSED"
|
||||||
STR_BT_PAGE_FORWARD: "Page Forward"
|
STR_BT_PAGE_FORWARD: "Page Forward"
|
||||||
STR_BT_PAGE_BACK: "Page Back"
|
STR_BT_PAGE_BACK: "Page Back"
|
||||||
STR_BT_FORGET_PROMPT: "Hold Confirm to forget"
|
STR_BT_FORGET_PROMPT: "Hold Confirm to forget"
|
||||||
|
|||||||
@@ -25,6 +25,12 @@ namespace bleinput {
|
|||||||
// Advertised central name shown to peripherals during pairing.
|
// Advertised central name shown to peripherals during pairing.
|
||||||
inline constexpr const char* kHostName = "CrossPoint";
|
inline constexpr const char* kHostName = "CrossPoint";
|
||||||
|
|
||||||
|
// Heap floor for starting the NimBLE stack (~57 KB) while leaving the reader's
|
||||||
|
// section-build pre-flight (40 KB) satisfiable afterwards. Shared by the main-loop
|
||||||
|
// lifecycle gate and the reader menu's toggle (which offers a defrag restart when a
|
||||||
|
// user turns BT on below the floor).
|
||||||
|
inline constexpr size_t kStartMinFreeHeap = 100 * 1024;
|
||||||
|
|
||||||
// Start the BLE HID host (idempotent). Returns false if BLE is compiled out or
|
// Start the BLE HID host (idempotent). Returns false if BLE is compiled out or
|
||||||
// NimBLE init failed. Safe to call repeatedly.
|
// NimBLE init failed. Safe to call repeatedly.
|
||||||
bool ensureStarted();
|
bool ensureStarted();
|
||||||
|
|||||||
@@ -2,9 +2,12 @@
|
|||||||
|
|
||||||
#include <GfxRenderer.h>
|
#include <GfxRenderer.h>
|
||||||
#include <I18n.h>
|
#include <I18n.h>
|
||||||
|
#include <Logging.h>
|
||||||
|
|
||||||
|
#include "BleInput.h"
|
||||||
#include "CrossPointSettings.h"
|
#include "CrossPointSettings.h"
|
||||||
#include "MappedInputManager.h"
|
#include "MappedInputManager.h"
|
||||||
|
#include "SilentRestart.h"
|
||||||
#include "components/UITheme.h"
|
#include "components/UITheme.h"
|
||||||
#include "fontIds.h"
|
#include "fontIds.h"
|
||||||
|
|
||||||
@@ -84,6 +87,15 @@ void EpubReaderMenuActivity::loop() {
|
|||||||
// so start/stop has a single owner.
|
// so start/stop has a single owner.
|
||||||
SETTINGS.bluetoothEnabled = SETTINGS.bluetoothEnabled ? 0 : 1;
|
SETTINGS.bluetoothEnabled = SETTINGS.bluetoothEnabled ? 0 : 1;
|
||||||
SETTINGS.saveToFile();
|
SETTINGS.saveToFile();
|
||||||
|
// Turning BT on below the lifecycle's heap floor would otherwise sit in PAUSED
|
||||||
|
// until the heap happens to recover -- which a long session's fragmentation never
|
||||||
|
// gives back. The user asked for BT *now*: silent-restart into this book to
|
||||||
|
// defrag (fresh boot is ~118 KB free, comfortably above the floor), and BT
|
||||||
|
// auto-starts on the way back in.
|
||||||
|
if (SETTINGS.bluetoothEnabled && !BleHid.isRunning() && ESP.getFreeHeap() < bleinput::kStartMinFreeHeap) {
|
||||||
|
LOG_INF("ERM", "BT enabled below heap floor (%u); silent restart to defrag", ESP.getFreeHeap());
|
||||||
|
silentRestartToReader();
|
||||||
|
}
|
||||||
requestUpdate();
|
requestUpdate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -138,8 +150,12 @@ void EpubReaderMenuActivity::render(RenderLock&&) {
|
|||||||
// Render current page turn value on the right edge of the content area.
|
// Render current page turn value on the right edge of the content area.
|
||||||
return pageTurnLabels[selectedPageTurnOption];
|
return pageTurnLabels[selectedPageTurnOption];
|
||||||
} else if (value == MenuAction::TOGGLE_BLUETOOTH) {
|
} else if (value == MenuAction::TOGGLE_BLUETOOTH) {
|
||||||
// Render current Bluetooth on/off state on the right edge.
|
// Render current Bluetooth state on the right edge. "Enabled but the stack
|
||||||
return SETTINGS.bluetoothEnabled ? tr(STR_STATE_ON) : tr(STR_STATE_OFF);
|
// isn't running" is the low-memory deferral -- show PAUSED, not a lie.
|
||||||
|
if (SETTINGS.bluetoothEnabled) {
|
||||||
|
return BleHid.isRunning() ? tr(STR_STATE_ON) : tr(STR_STATE_PAUSED);
|
||||||
|
}
|
||||||
|
return tr(STR_STATE_OFF);
|
||||||
} else {
|
} else {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-5
@@ -514,18 +514,18 @@ void updateBluetoothLifecycle() {
|
|||||||
static constexpr uint32_t BLE_RESTART_COOLDOWN_MS = 30 * 1000;
|
static constexpr uint32_t BLE_RESTART_COOLDOWN_MS = 30 * 1000;
|
||||||
const bool inCooldown = recoveryTeardownMs != 0 && millis() - recoveryTeardownMs < BLE_RESTART_COOLDOWN_MS;
|
const bool inCooldown = recoveryTeardownMs != 0 && millis() - recoveryTeardownMs < BLE_RESTART_COOLDOWN_MS;
|
||||||
// Heap gate: NimBLE needs ~57 KB, and the section-build pre-flight needs 40 KB free
|
// Heap gate: NimBLE needs ~57 KB, and the section-build pre-flight needs 40 KB free
|
||||||
// AFTER the stack is up -- so anything below ~100 KB just re-enters build recovery
|
// AFTER the stack is up -- so anything below the floor just re-enters build recovery
|
||||||
// and tears BLE straight back down. (A first cut used 70 KB for restarts; 70-57=13 KB
|
// and tears BLE straight back down. (A first cut used 70 KB for restarts; 70-57=13 KB
|
||||||
// left for builds, guaranteeing the oscillation above.) Defer and retry next loop;
|
// left for builds, guaranteeing the oscillation above.) Defer and retry next loop;
|
||||||
// the build path's silent-restart defrag yields ~118 KB and passes this gate.
|
// the reader menu's toggle offers a defrag restart, and the build path's silent
|
||||||
static constexpr size_t BLE_START_MIN_FREE_HEAP = 100 * 1024;
|
// restart also yields ~118 KB and passes this gate.
|
||||||
static bool deferralAnnounced = false;
|
static bool deferralAnnounced = false;
|
||||||
if (wanted && !BleHid.isRunning() && (inCooldown || ESP.getFreeHeap() < BLE_START_MIN_FREE_HEAP)) {
|
if (wanted && !BleHid.isRunning() && (inCooldown || ESP.getFreeHeap() < bleinput::kStartMinFreeHeap)) {
|
||||||
static uint32_t lastGateLogMs = 0;
|
static uint32_t lastGateLogMs = 0;
|
||||||
if (millis() - lastGateLogMs > 10000) {
|
if (millis() - lastGateLogMs > 10000) {
|
||||||
lastGateLogMs = millis();
|
lastGateLogMs = millis();
|
||||||
LOG_INF("BLELC", "start deferred: heap %u floor %u cooldown=%d", ESP.getFreeHeap(),
|
LOG_INF("BLELC", "start deferred: heap %u floor %u cooldown=%d", ESP.getFreeHeap(),
|
||||||
(unsigned)BLE_START_MIN_FREE_HEAP, inCooldown ? 1 : 0);
|
(unsigned)bleinput::kStartMinFreeHeap, inCooldown ? 1 : 0);
|
||||||
}
|
}
|
||||||
// Tell the reader once per deferral episode that the remote is paused -- otherwise
|
// Tell the reader once per deferral episode that the remote is paused -- otherwise
|
||||||
// the only symptom is a remote that silently stopped working. Draws into the
|
// the only symptom is a remote that silently stopped working. Draws into the
|
||||||
|
|||||||
Reference in New Issue
Block a user