fix(bluetooth): auto-reconnect to paired devices after reboot

- Auto-set enableOnBoot=true when BT is enabled or device is paired,
  so board restarts with BT on and can reconnect
- Make RADIO_STATE_ON handler non-exclusive: scan for HID Host,
  start HID Device, SPP and MIDI all independently (was else-if)
- Improve HID Host auto-connect for RPA: direct addr match, name-match
  fallback, and direct connect to stored identity using resolving list
- Persist addrType in PairedDevice file for more reliable reconnection
- Add verbose logging for loadAll/save to debug missing files

Fixes issue where board restart did not reconnect to previously
connected BT devices. Also preserves f94cc160 fullscreen flag feature.
This commit is contained in:
Adolfo Reyna
2026-07-19 19:31:57 -04:00
parent f94cc160cf
commit 80bd1c9f20
4 changed files with 149 additions and 34 deletions
@@ -19,10 +19,11 @@ constexpr auto* TAG = "BluetoothPairedDevice";
// Use the same directory as the old service for backward compatibility.
constexpr auto* DEVICE_SETTINGS_FORMAT = "{}/{}.device.properties";
constexpr auto* KEY_NAME = "name";
constexpr auto* KEY_ADDR = "addr";
constexpr auto* KEY_NAME = "name";
constexpr auto* KEY_ADDR = "addr";
constexpr auto* KEY_AUTO_CONNECT = "autoConnect";
constexpr auto* KEY_PROFILE_ID = "profileId";
constexpr auto* KEY_PROFILE_ID = "profileId";
constexpr auto* KEY_ADDR_TYPE = "addrType";
static std::string getSettingsFilePath() {
return getUserDataPath() + "/service/bluetooth";
@@ -78,8 +79,23 @@ bool load(const std::string& addr_hex, PairedDevice& device) {
device.autoConnect = !map.contains(KEY_AUTO_CONNECT) || (map[KEY_AUTO_CONNECT] == "true");
if (map.contains(KEY_PROFILE_ID)) {
// TODO: Handle incorrect parsing input
device.profileId = std::stoi(map[KEY_PROFILE_ID]);
char* endPtr = nullptr;
long val = std::strtol(map[KEY_PROFILE_ID].c_str(), &endPtr, 10);
if (endPtr != map[KEY_PROFILE_ID].c_str()) {
device.profileId = static_cast<int>(val);
}
}
if (map.contains(KEY_ADDR_TYPE)) {
char* endPtr = nullptr;
long val = std::strtol(map[KEY_ADDR_TYPE].c_str(), &endPtr, 10);
if (endPtr != map[KEY_ADDR_TYPE].c_str() && val >= 0 && val <= 255) {
device.addrType = static_cast<uint8_t>(val);
} else {
device.addrType = 0;
}
} else {
device.addrType = 0; // backward compat: assume PUBLIC
}
return true;
}
@@ -91,12 +107,17 @@ bool save(const PairedDevice& device) {
map[KEY_ADDR] = addr_hex;
map[KEY_AUTO_CONNECT] = device.autoConnect ? "true" : "false";
map[KEY_PROFILE_ID] = std::to_string(device.profileId);
map[KEY_ADDR_TYPE] = std::to_string(device.addrType);
auto file_path = getFilePath(addr_hex);
LOG_I(TAG, "Saving device file %s profile=%d auto=%d type=%d",
file_path.c_str(), device.profileId, (int)device.autoConnect, (int)device.addrType);
if (!file::findOrCreateParentDirectory(file_path, 0755)) {
LOG_E(TAG, "Failed to create parent dir for %s", file_path.c_str());
return false;
}
return file::savePropertiesFile(file_path, map);
bool result = file::savePropertiesFile(file_path, map);
LOG_I(TAG, "SavePropertiesFile result for %s: %d", file_path.c_str(), (int)result);
return result;
}
bool remove(const std::string& addr_hex) {
@@ -108,6 +129,7 @@ bool remove(const std::string& addr_hex) {
std::vector<PairedDevice> loadAll() {
std::vector<dirent> entries;
if (!file::isDirectory(getSettingsFilePath())) {
LOG_I(TAG, "loadAll: directory %s does not exist", getSettingsFilePath().c_str());
return {};
}
file::scandir(getSettingsFilePath(), entries, [](const dirent* entry) -> int {
@@ -116,6 +138,7 @@ std::vector<PairedDevice> loadAll() {
return name.ends_with(".device.properties") ? 0 : -1;
}, nullptr);
LOG_I(TAG, "loadAll: found %d entries in %s", (int)entries.size(), getSettingsFilePath().c_str());
std::vector<PairedDevice> result;
result.reserve(entries.size());
for (const auto& entry : entries) {
@@ -126,6 +149,8 @@ std::vector<PairedDevice> loadAll() {
PairedDevice device;
if (load(addr_hex, device)) {
result.push_back(std::move(device));
} else {
LOG_W(TAG, "loadAll: failed to load %s", filename.c_str());
}
}
return result;