Fixes & memory optimizations (#540)

- Disable BlueTooth driver by default, to ensure it doesn't allocate memory
- Update BlueTooth settings app behaviour to make sure it starts/stops the devices
- Disable SPI RAM usage for ST7789 as it broke App Hub
- Reduce T-Display and T-Deck display buffers from 1/3rd to 1/10th of resolution
- Enabled dynamic buffers for MbedTLS to optimize memory
- TLS 1.3 did not work with dynamic buffers: downgrade to 1.2 for now
- WiFi is now enabled from the Boot app callback to the WiFi service, instead of the WiFi service start() function. This avoids a lockup when WiFi is started by the service while the Boot app is updating the WiFi settings.
This commit is contained in:
Ken Van Hoeylandt
2026-07-01 21:11:46 +02:00
committed by GitHub
parent 599fa46766
commit d3439f6f45
251 changed files with 112319 additions and 67 deletions
+83 -24
View File
@@ -40,18 +40,16 @@ static std::vector<CachedAddr> scan_addr_cache; // parallel to scan_results_cach
// ---- Device accessor ----
struct Device* findFirstDevice() {
struct Device* found = nullptr;
device_for_each_of_type(&BLUETOOTH_TYPE, &found, [](struct Device* dev, void* ctx) -> bool {
if (device_is_ready(dev)) {
*static_cast<struct Device**>(ctx) = dev;
return false;
}
Device* findFirstRegisteredDevice() {
Device* found = nullptr;
device_for_each_of_type(&BLUETOOTH_TYPE, &found, [](Device* dev, void* ctx) -> bool {
*static_cast<Device**>(ctx) = dev;
return true;
});
return found;
}
// ---- Scan cache helpers ----
void cacheScanAddr(const uint8_t addr[6], uint8_t addr_type) {
@@ -110,7 +108,7 @@ static void cachePeerRecord(const BtPeerRecord& krecord) {
// and settings management. Consumers should register their own callbacks via
// bluetooth_add_event_callback() to receive events directly.
static void bt_event_bridge(struct Device* /*device*/, void* /*context*/, struct BtEvent event) {
static void bt_event_bridge(Device*, void* /*context*/, BtEvent event) {
switch (event.type) {
case BT_EVENT_RADIO_STATE_CHANGED:
switch (event.radio_state) {
@@ -126,24 +124,24 @@ static void bt_event_bridge(struct Device* /*device*/, void* /*context*/, struct
}
if (has_hid_host_auto) {
LOGGER.info("HID host auto-connect peer found — starting scan");
if (struct Device* dev = findFirstDevice()) {
if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) {
bluetooth_scan_start(dev);
}
} else if (has_hid_device_auto) {
LOGGER.info("HID device auto-start (bonded peer found)");
if (struct Device* dev = bluetooth_hid_device_get_device()) {
if (Device* dev = bluetooth_hid_device_get_device()) {
bluetooth_hid_device_start(dev, BT_HID_DEVICE_MODE_KEYBOARD);
}
} else {
if (settings::shouldSppAutoStart()) {
LOGGER.info("Auto-starting SPP server");
if (struct Device* dev = bluetooth_serial_get_device()) {
if (Device* dev = bluetooth_serial_get_device()) {
bluetooth_serial_start(dev);
}
}
if (settings::shouldMidiAutoStart()) {
LOGGER.info("Auto-starting MIDI server");
if (struct Device* dev = bluetooth_midi_get_device()) {
if (Device* dev = bluetooth_midi_get_device()) {
bluetooth_midi_start(dev);
}
}
@@ -233,7 +231,7 @@ static void bt_event_bridge(struct Device* /*device*/, void* /*context*/, struct
}
}
if (has_auto) {
if (struct Device* dev = findFirstDevice()) {
if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) {
if (!bluetooth_is_scanning(dev)) {
bluetooth_scan_start(dev);
}
@@ -251,19 +249,80 @@ static void bt_event_bridge(struct Device* /*device*/, void* /*context*/, struct
// ---- systemStart ----
void systemStart() {
struct Device* dev = findFirstDevice();
Device* dev = findFirstRegisteredDevice();
if (dev == nullptr) {
LOGGER.warn("systemStart: no BLE device found");
return;
}
bluetooth_add_event_callback(dev, nullptr, bt_event_bridge);
if (settings::shouldEnableOnBoot()) {
LOGGER.info("Auto-enabling Bluetooth on boot");
bluetooth_set_radio_enabled(dev, true);
start(dev);
}
}
bool isRadioOnOrPending(Device* dev) {
if (!device_is_ready(dev)) return false;
BtRadioState state;
if (bluetooth_get_radio_state(dev, &state) != ERROR_NONE) return false;
return state == BT_RADIO_STATE_ON || state == BT_RADIO_STATE_ON_PENDING;
}
bool start(Device* dev) {
LOGGER.info("Auto-enabling BLE on boot");
if (!device_is_ready(dev)) {
LOGGER.info("Starting BLE device");
if (device_start(dev) != ERROR_NONE) {
LOGGER.error("Failed to start BLE device");
return false;
}
}
// TODO: Fix bug where repeatedly calling start would add this callback multiple times
if (bluetooth_add_event_callback(dev, nullptr, bt_event_bridge) != ERROR_NONE) {
LOGGER.error("Failed to set BLE callback");
}
LOGGER.info("Enabling BT radio");
if (bluetooth_set_radio_enabled(dev, true) != ERROR_NONE) {
LOGGER.error("Failed to enable BLE radio");
// Add bridge again
bluetooth_remove_event_callback(dev, bt_event_bridge);
return false;
}
LOGGER.info("BT enabled");
return true;
}
bool stop(Device* dev) {
BtRadioState state;
if (bluetooth_get_radio_state(dev, &state) != ERROR_NONE) {
return false;
}
if (state == BT_RADIO_STATE_OFF || state == BT_RADIO_STATE_OFF_PENDING) {
return true;
}
if (bluetooth_remove_event_callback(dev, bt_event_bridge) != ERROR_NONE) {
LOGGER.error("Failed to remove BLE callback");
}
if (bluetooth_set_radio_enabled(dev, false) != ERROR_NONE) {
LOGGER.error("Failed to disable BT radio");
// Re-register bridge
bluetooth_add_event_callback(dev, nullptr, bt_event_bridge);
return false;
}
if (device_stop(dev) != ERROR_NONE) {
LOGGER.error("Failed to stop BT device");
return false;
}
return true;
}
// ---- Public API ----
const char* radioStateToString(RadioState state) {
@@ -278,7 +337,7 @@ const char* radioStateToString(RadioState state) {
}
RadioState getRadioState() {
struct Device* dev = findFirstDevice();
Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE);
if (dev == nullptr) return RadioState::Off;
BtRadioState state = BT_RADIO_STATE_OFF;
bluetooth_get_radio_state(dev, &state);
@@ -346,7 +405,7 @@ void pair(const std::array<uint8_t, 6>& /*addr*/) {
}
void unpair(const std::array<uint8_t, 6>& addr) {
struct Device* dev = findFirstDevice();
Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE);
if (dev != nullptr) {
bluetooth_unpair(dev, addr.data());
}
@@ -358,16 +417,16 @@ void connect(const std::array<uint8_t, 6>& addr, int profileId) {
if (profileId == BT_PROFILE_HID_HOST) {
hidHostConnect(addr);
} else if (profileId == BT_PROFILE_HID_DEVICE) {
if (struct Device* dev = bluetooth_hid_device_get_device()) {
if (Device* dev = bluetooth_hid_device_get_device()) {
bluetooth_hid_device_start(dev, BT_HID_DEVICE_MODE_KEYBOARD);
}
} else if (profileId == BT_PROFILE_SPP) {
if (struct Device* dev = bluetooth_serial_get_device()) {
if (Device* dev = bluetooth_serial_get_device()) {
bluetooth_serial_start(dev);
settings::setSppAutoStart(true);
}
} else if (profileId == BT_PROFILE_MIDI) {
if (struct Device* dev = bluetooth_midi_get_device()) {
if (Device* dev = bluetooth_midi_get_device()) {
bluetooth_midi_start(dev);
settings::setMidiAutoStart(true);
}
@@ -379,11 +438,11 @@ void disconnect(const std::array<uint8_t, 6>& addr, int profileId) {
if (profileId == BT_PROFILE_HID_HOST) {
hidHostDisconnect();
} else if (profileId == BT_PROFILE_HID_DEVICE) {
if (struct Device* dev = bluetooth_hid_device_get_device()) {
if (Device* dev = bluetooth_hid_device_get_device()) {
bluetooth_hid_device_stop(dev);
}
} else {
struct Device* dev = findFirstDevice();
Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE);
if (dev == nullptr) return;
bluetooth_disconnect(dev, addr.data(), (BtProfileId)profileId);
}
@@ -502,8 +502,8 @@ static void hidHostSubscribeNext(HidHostCtx& ctx) {
}
device.name = name;
settings::save(device);
if (struct Device* dev = findFirstDevice()) {
struct BtEvent e = {};
if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) {
BtEvent e = {};
e.type = BT_EVENT_PROFILE_STATE_CHANGED;
e.profile_state.state = BT_PROFILE_STATE_CONNECTED;
e.profile_state.profile = BT_PROFILE_HID_HOST;
@@ -662,7 +662,7 @@ static int hidHostGapCb(struct ble_gap_event* event, void* /*arg*/) {
} else {
LOGGER.warn("Connect failed status={}", event->connect.status);
hid_host_ctx.reset();
if (struct Device* dev = findFirstDevice()) {
if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) {
bluetooth_set_hid_host_active(dev, false);
struct BtEvent e = {};
e.type = BT_EVENT_PROFILE_STATE_CHANGED;
@@ -687,7 +687,7 @@ static int hidHostGapCb(struct ble_gap_event* event, void* /*arg*/) {
hid_host_mouse_btn.store(false);
hid_host_mouse_active.store(false);
if (struct Device* dev = findFirstDevice()) {
if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) {
bluetooth_set_hid_host_active(dev, false);
struct BtEvent e = {};
e.type = BT_EVENT_PROFILE_STATE_CHANGED;
@@ -795,7 +795,7 @@ void hidHostConnect(const std::array<uint8_t, 6>& addr) {
}
// Notify driver that a HID host central connection is starting.
if (struct Device* dev = findFirstDevice()) bluetooth_set_hid_host_active(dev, true);
if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) bluetooth_set_hid_host_active(dev, true);
// Look up the addr_type from the cached scan results.
ble_addr_t ble_addr = {};
@@ -815,10 +815,10 @@ void hidHostConnect(const std::array<uint8_t, 6>& addr) {
if (rc != 0) {
LOGGER.warn("ble_gap_connect failed rc={}", rc);
hid_host_ctx.reset();
if (struct Device* dev = findFirstDevice()) {
if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) {
bluetooth_set_hid_host_active(dev, false);
// Fire IDLE so bt_event_bridge can start a new scan and retry.
struct BtEvent e = {};
BtEvent e = {};
e.type = BT_EVENT_PROFILE_STATE_CHANGED;
e.profile_state.state = BT_PROFILE_STATE_IDLE;
e.profile_state.profile = BT_PROFILE_HID_HOST;
@@ -869,7 +869,7 @@ void autoConnectHidHost() {
auto peers = settings::loadAll();
for (const auto& peer : peers) {
if (peer.autoConnect && peer.profileId == BT_PROFILE_HID_HOST) {
if (struct Device* dev = findFirstDevice()) {
if (Device* dev = device_find_first_active_by_type(&BLUETOOTH_TYPE)) {
if (!bluetooth_is_scanning(dev)) {
LOGGER.info("Auto-connect HID host: device not in scan, retrying scan");
bluetooth_scan_start(dev);