From a3eb2dd9dc2399ce9c22cd3b07f482f080976440 Mon Sep 17 00:00:00 2001 From: jacqueline Date: Thu, 11 Jul 2024 15:11:28 +1000 Subject: WIP improve bluetooth api and settings screen --- src/tangara/ui/ui_fsm.cpp | 114 ++++++++++++++++++++++++++++++++-------------- src/tangara/ui/ui_fsm.hpp | 5 +- 2 files changed, 83 insertions(+), 36 deletions(-) (limited to 'src/tangara/ui') diff --git a/src/tangara/ui/ui_fsm.cpp b/src/tangara/ui/ui_fsm.cpp index 7c4147a3..c5ede83c 100644 --- a/src/tangara/ui/ui_fsm.cpp +++ b/src/tangara/ui/ui_fsm.cpp @@ -7,11 +7,13 @@ #include "ui/ui_fsm.hpp" #include +#include #include #include #include #include "FreeRTOSConfig.h" +#include "drivers/bluetooth.hpp" #include "lvgl.h" #include "core/lv_group.h" @@ -100,32 +102,57 @@ lua::Property UiState::sBluetoothEnabled{ if (!std::holds_alternative(val)) { return false; } + // Note we always write the OutputMode NVS change before actually + // modifying the peripheral. We do this because ESP-IDF's Bluetooth stack + // breaks in surprising ways when repeatedly initialised/uninitialised. if (std::get(val)) { sServices->nvs().OutputMode(drivers::NvsStorage::Output::kBluetooth); - sServices->bluetooth().Enable(); + sServices->bluetooth().enable(true); } else { sServices->nvs().OutputMode(drivers::NvsStorage::Output::kHeadphones); - sServices->bluetooth().Disable(); + sServices->bluetooth().enable(false); } events::Audio().Dispatch(audio::OutputModeChanged{}); return true; }}; +lua::Property UiState::sBluetoothConnecting{false}; lua::Property UiState::sBluetoothConnected{false}; + +lua::Property UiState::sBluetoothDiscovering{ + false, [](const lua::LuaValue& val) { + if (!std::holds_alternative(val)) { + return false; + } + // Note we always write the OutputMode NVS change before actually + // modifying the peripheral. We do this because ESP-IDF's Bluetooth stack + // breaks in surprising ways when repeatedly initialised/uninitialised. + if (std::get(val)) { + sServices->bluetooth().discoveryEnabled(true); + } else { + sServices->bluetooth().discoveryEnabled(false); + } + return true; + }}; + lua::Property UiState::sBluetoothPairedDevice{ std::monostate{}, [](const lua::LuaValue& val) { - if (std::holds_alternative(val)) { - auto dev = std::get(val); - sServices->bluetooth().SetPreferredDevice( - drivers::bluetooth::MacAndName{ - .mac = dev.address, - .name = {dev.name.data(), dev.name.size()}, - }); + if (std::holds_alternative(val)) { + auto dev = std::get(val); + sServices->bluetooth().pairedDevice(dev); + } else if (std::holds_alternative(val)) { + sServices->bluetooth().pairedDevice({}); + } else { + // Don't accept any other types. + return false; } - return false; + return true; }}; -lua::Property UiState::sBluetoothDevices{ - std::vector{}}; + +lua::Property UiState::sBluetoothKnownDevices{ + std::vector{}}; +lua::Property UiState::sBluetoothDiscoveredDevices{ + std::vector{}}; lua::Property UiState::sPlaybackPlaying{ false, [](const lua::LuaValue& val) { @@ -412,8 +439,13 @@ void UiState::react(const audio::VolumeLimitChanged& ev) { void UiState::react(const system_fsm::BluetoothEvent& ev) { using drivers::bluetooth::SimpleEvent; + using ConnectionState = drivers::Bluetooth::ConnectionState; + ConnectionState state; auto bt = sServices->bluetooth(); - auto dev = bt.ConnectedDevice(); + + std::optional dev; + std::vector devs; + if (std::holds_alternative(ev.event)) { switch (std::get(ev.event)) { case SimpleEvent::kPlayPause: @@ -438,30 +470,36 @@ void UiState::react(const system_fsm::BluetoothEvent& ev) { break; case SimpleEvent::kFastForward: break; - case SimpleEvent::kKnownDevicesChanged: - sBluetoothDevices.setDirect(bt.KnownDevices()); - break; case SimpleEvent::kConnectionStateChanged: - sBluetoothConnected.setDirect(bt.IsConnected()); + state = bt.connectionState(); + sBluetoothConnected.setDirect(state == ConnectionState::kConnected); + sBluetoothConnecting.setDirect(state == ConnectionState::kConnecting); + break; + case SimpleEvent::kPairedDeviceChanged: + dev = bt.pairedDevice(); if (dev) { - sBluetoothPairedDevice.setDirect(drivers::bluetooth::Device{ - .address = dev->mac, - .name = {dev->name.data(), dev->name.size()}, - .class_of_device = 0, - .signal_strength = 0, - }); + sBluetoothPairedDevice.setDirect(*dev); } else { sBluetoothPairedDevice.setDirect(std::monostate{}); } break; - case SimpleEvent::kPreferredDeviceChanged: + case SimpleEvent::kKnownDevicesChanged: + sBluetoothKnownDevices.setDirect(bt.knownDevices()); + break; + case SimpleEvent::kDiscoveryChanged: + sBluetoothDiscovering.setDirect(bt.discoveryEnabled()); + // Dump the old list of discovered devices when discovery is toggled. + sBluetoothDiscoveredDevices.setDirect(bt.discoveredDevices()); + break; + case SimpleEvent::kDeviceDiscovered: + sBluetoothDiscoveredDevices.setDirect(bt.discoveredDevices()); break; default: break; } } else if (std::holds_alternative( ev.event)) { - // Todo: Do something with this (ie, bt volume alert) + // TODO: Do something with this (ie, bt volume alert) ESP_LOGI( kTag, "Recieved volume changed event with new volume: %d", std::get(ev.event).new_vol); @@ -517,13 +555,16 @@ void Lua::entry() { {"battery_millivolts", &sBatteryMv}, {"plugged_in", &sBatteryCharging}, }); - registry.AddPropertyModule("bluetooth", - { - {"enabled", &sBluetoothEnabled}, - {"connected", &sBluetoothConnected}, - {"paired_device", &sBluetoothPairedDevice}, - {"devices", &sBluetoothDevices}, - }); + registry.AddPropertyModule( + "bluetooth", { + {"enabled", &sBluetoothEnabled}, + {"connected", &sBluetoothConnected}, + {"connecting", &sBluetoothConnecting}, + {"discovering", &sBluetoothDiscovering}, + {"paired_device", &sBluetoothPairedDevice}, + {"discovered_devices", &sBluetoothDiscoveredDevices}, + {"known_devices", &sBluetoothKnownDevices}, + }); registry.AddPropertyModule("playback", { {"playing", &sPlaybackPlaying}, {"track", &sPlaybackTrack}, @@ -601,9 +642,12 @@ void Lua::entry() { sDatabaseAutoUpdate.setDirect(sServices->nvs().DbAutoIndex()); auto bt = sServices->bluetooth(); - sBluetoothEnabled.setDirect(bt.IsEnabled()); - sBluetoothConnected.setDirect(bt.IsConnected()); - sBluetoothDevices.setDirect(bt.KnownDevices()); + sBluetoothEnabled.setDirect(bt.enabled()); + auto paired = bt.pairedDevice(); + if (paired) { + sBluetoothPairedDevice.setDirect(*paired); + } + sBluetoothKnownDevices.setDirect(bt.knownDevices()); if (sServices->sd() == drivers::SdState::kMounted) { sLua->RunScript("/sdcard/config.lua"); diff --git a/src/tangara/ui/ui_fsm.hpp b/src/tangara/ui/ui_fsm.hpp index 7e34db34..72688fa0 100644 --- a/src/tangara/ui/ui_fsm.hpp +++ b/src/tangara/ui/ui_fsm.hpp @@ -102,9 +102,12 @@ class UiState : public tinyfsm::Fsm { static lua::Property sBatteryCharging; static lua::Property sBluetoothEnabled; + static lua::Property sBluetoothConnecting; static lua::Property sBluetoothConnected; + static lua::Property sBluetoothDiscovering; static lua::Property sBluetoothPairedDevice; - static lua::Property sBluetoothDevices; + static lua::Property sBluetoothKnownDevices; + static lua::Property sBluetoothDiscoveredDevices; static lua::Property sPlaybackPlaying; -- cgit v1.2.3