diff options
| author | jacqueline <me@jacqueline.id.au> | 2024-07-11 15:11:28 +1000 |
|---|---|---|
| committer | jacqueline <me@jacqueline.id.au> | 2024-07-11 15:11:28 +1000 |
| commit | a3eb2dd9dc2399ce9c22cd3b07f482f080976440 (patch) | |
| tree | 4a7883755d07b7d9a391d5b6e7858c0ab26e3bdd /src/tangara | |
| parent | a9d2335e1d86b3012789a440e7f0e71033393056 (diff) | |
| download | tangara-fw-a3eb2dd9dc2399ce9c22cd3b07f482f080976440.tar.gz | |
WIP improve bluetooth api and settings screen
Diffstat (limited to 'src/tangara')
| -rw-r--r-- | src/tangara/app_console/app_console.cpp | 17 | ||||
| -rw-r--r-- | src/tangara/audio/audio_fsm.cpp | 11 | ||||
| -rw-r--r-- | src/tangara/audio/bt_audio_output.cpp | 13 | ||||
| -rw-r--r-- | src/tangara/lua/property.cpp | 30 | ||||
| -rw-r--r-- | src/tangara/lua/property.hpp | 4 | ||||
| -rw-r--r-- | src/tangara/system_fsm/booting.cpp | 3 | ||||
| -rw-r--r-- | src/tangara/ui/ui_fsm.cpp | 114 | ||||
| -rw-r--r-- | src/tangara/ui/ui_fsm.hpp | 5 |
8 files changed, 118 insertions, 79 deletions
diff --git a/src/tangara/app_console/app_console.cpp b/src/tangara/app_console/app_console.cpp index f3593e1b..af9061fe 100644 --- a/src/tangara/app_console/app_console.cpp +++ b/src/tangara/app_console/app_console.cpp @@ -418,28 +418,21 @@ int CmdBtList(int argc, char** argv) { return 1; } - auto devices = AppConsole::sServices->bluetooth().KnownDevices(); + auto devices = AppConsole::sServices->bluetooth().knownDevices(); if (argc == 2) { int index = std::atoi(argv[1]); if (index < 0 || index >= devices.size()) { std::cout << "index out of range" << std::endl; return -1; } - drivers::bluetooth::MacAndName dev{ - .mac = devices[index].address, - .name = {devices[index].name.data(), devices[index].name.size()}, - }; - AppConsole::sServices->bluetooth().SetPreferredDevice(dev); + AppConsole::sServices->bluetooth().pairedDevice(devices[index]); } else { - std::cout << "mac\t\trssi\tname" << std::endl; + std::cout << "mac\t\tname" << std::endl; for (const auto& device : devices) { - for (size_t i = 0; i < device.address.size(); i++) { + for (size_t i = 0; i < device.mac.size(); i++) { std::cout << std::hex << std::setfill('0') << std::setw(2) - << static_cast<int>(device.address[i]); + << static_cast<int>(device.mac[i]); } - float perc = - (static_cast<double>(device.signal_strength) + 127.0) / 256.0 * 100; - std::cout << "\t" << std::fixed << std::setprecision(0) << perc << "%"; std::cout << "\t" << device.name << std::endl; } } diff --git a/src/tangara/audio/audio_fsm.cpp b/src/tangara/audio/audio_fsm.cpp index 24f287ac..fbc38f97 100644 --- a/src/tangara/audio/audio_fsm.cpp +++ b/src/tangara/audio/audio_fsm.cpp @@ -222,7 +222,12 @@ void AudioState::react(const system_fsm::BluetoothEvent& ev) { auto simpleEvent = std::get<SimpleEvent>(ev.event); switch (simpleEvent) { case SimpleEvent::kConnectionStateChanged: { - auto dev = sServices->bluetooth().ConnectedDevice(); + auto bt = sServices->bluetooth(); + if (bt.connectionState() != + drivers::Bluetooth::ConnectionState::kConnected) { + return; + } + auto dev = sServices->bluetooth().pairedDevice(); if (!dev) { return; } @@ -341,7 +346,7 @@ auto AudioState::commitVolume() -> void { if (mode == drivers::NvsStorage::Output::kHeadphones) { sServices->nvs().AmpCurrentVolume(vol); } else if (mode == drivers::NvsStorage::Output::kBluetooth) { - auto dev = sServices->bluetooth().ConnectedDevice(); + auto dev = sServices->bluetooth().pairedDevice(); if (!dev) { return; } @@ -372,7 +377,7 @@ void Uninitialised::react(const system_fsm::BootComplete& ev) { sOutput = sI2SOutput; } else { // Ensure Bluetooth gets enabled if it's the default sink. - sServices->bluetooth().Enable(); + sServices->bluetooth().enable(true); sOutput = sBtOutput; } sOutput->mode(IAudioOutput::Modes::kOnPaused); diff --git a/src/tangara/audio/bt_audio_output.cpp b/src/tangara/audio/bt_audio_output.cpp index 616a385f..336fc758 100644 --- a/src/tangara/audio/bt_audio_output.cpp +++ b/src/tangara/audio/bt_audio_output.cpp @@ -13,6 +13,7 @@ #include <memory> #include <variant> +#include "drivers/bluetooth.hpp" #include "esp_err.h" #include "esp_heap_caps.h" #include "freertos/portmacro.h" @@ -32,6 +33,8 @@ namespace audio { static constexpr uint16_t kVolumeRange = 60; +using ConnectionState = drivers::Bluetooth::ConnectionState; + BluetoothAudioOutput::BluetoothAudioOutput(drivers::Bluetooth& bt, drivers::PcmBuffer& buffer, tasks::WorkerPool& p) @@ -45,9 +48,9 @@ BluetoothAudioOutput::~BluetoothAudioOutput() {} auto BluetoothAudioOutput::changeMode(Modes mode) -> void { if (mode == Modes::kOnPlaying) { - bluetooth_.SetSource(&buffer_); + bluetooth_.source(&buffer_); } else { - bluetooth_.SetSource(nullptr); + bluetooth_.source(nullptr); } } @@ -60,7 +63,7 @@ auto BluetoothAudioOutput::SetVolume(uint16_t v) -> void { bg_worker_.Dispatch<void>([&]() { float factor = pow(10, static_cast<double>(kVolumeRange) * (volume_ - 100) / 100 / 20); - bluetooth_.SetVolumeFactor(factor); + bluetooth_.softVolume(factor); }); } @@ -95,7 +98,7 @@ auto BluetoothAudioOutput::SetVolumeDb(int_fast16_t val) -> bool { } auto BluetoothAudioOutput::AdjustVolumeUp() -> bool { - if (volume_ == 100 || !bluetooth_.IsConnected()) { + if (volume_ == 100) { return false; } volume_++; @@ -104,7 +107,7 @@ auto BluetoothAudioOutput::AdjustVolumeUp() -> bool { } auto BluetoothAudioOutput::AdjustVolumeDown() -> bool { - if (volume_ == 0 || !bluetooth_.IsConnected()) { + if (volume_ == 0) { return false; } volume_--; diff --git a/src/tangara/lua/property.cpp b/src/tangara/lua/property.cpp index 2b93809d..7b4f0b97 100644 --- a/src/tangara/lua/property.cpp +++ b/src/tangara/lua/property.cpp @@ -289,13 +289,14 @@ static void pushTrack(lua_State* L, const audio::TrackInfo& track) { lua_settable(L, -3); } -static void pushDevice(lua_State* L, const drivers::bluetooth::Device& dev) { +static void pushDevice(lua_State* L, + const drivers::bluetooth::MacAndName& dev) { lua_createtable(L, 0, 4); lua_pushliteral(L, "address"); auto* mac = reinterpret_cast<drivers::bluetooth::mac_addr_t*>( lua_newuserdata(L, sizeof(drivers::bluetooth::mac_addr_t))); - *mac = dev.address; + *mac = dev.mac; lua_rawset(L, -3); // What I just did there was perfectly safe. Look, I can prove it: @@ -308,14 +309,8 @@ static void pushDevice(lua_State* L, const drivers::bluetooth::Device& dev) { lua_pushlstring(L, dev.name.data(), dev.name.size()); lua_rawset(L, -3); - // FIXME: This field deserves a little more structure. - lua_pushliteral(L, "class"); - lua_pushinteger(L, dev.class_of_device); - lua_rawset(L, -3); - - lua_pushliteral(L, "signal_strength"); - lua_pushinteger(L, dev.signal_strength); - lua_rawset(L, -3); + // FIXME: Plumbing through device classes to here could be useful if we ever + // want to show cute little icons. } auto Property::pushValue(lua_State& s) -> int { @@ -332,10 +327,12 @@ auto Property::pushValue(lua_State& s) -> int { lua_pushstring(&s, arg.c_str()); } else if constexpr (std::is_same_v<T, audio::TrackInfo>) { pushTrack(&s, arg); - } else if constexpr (std::is_same_v<T, drivers::bluetooth::Device>) { + } else if constexpr (std::is_same_v<T, + drivers::bluetooth::MacAndName>) { pushDevice(&s, arg); } else if constexpr (std::is_same_v< - T, std::vector<drivers::bluetooth::Device>>) { + T, + std::vector<drivers::bluetooth::MacAndName>>) { lua_createtable(&s, arg.size(), 0); size_t i = 1; for (const auto& dev : arg) { @@ -364,15 +361,10 @@ auto popRichType(lua_State* L) -> LuaValue { lua_pushliteral(L, "name"); lua_gettable(L, -2); - std::pmr::string name = lua_tostring(L, -1); + std::string name = lua_tostring(L, -1); lua_pop(L, 1); - return drivers::bluetooth::Device{ - .address = mac, - .name = name, - .class_of_device = 0, - .signal_strength = 0, - }; + return drivers::bluetooth::MacAndName{.mac = mac, .name = name}; } return std::monostate{}; diff --git a/src/tangara/lua/property.hpp b/src/tangara/lua/property.hpp index 9f925766..d45821bd 100644 --- a/src/tangara/lua/property.hpp +++ b/src/tangara/lua/property.hpp @@ -24,8 +24,8 @@ using LuaValue = std::variant<std::monostate, bool, std::string, audio::TrackInfo, - drivers::bluetooth::Device, - std::vector<drivers::bluetooth::Device>>; + drivers::bluetooth::MacAndName, + std::vector<drivers::bluetooth::MacAndName>>; using LuaFunction = std::function<int(lua_State*)>; diff --git a/src/tangara/system_fsm/booting.cpp b/src/tangara/system_fsm/booting.cpp index 9d505f81..86993767 100644 --- a/src/tangara/system_fsm/booting.cpp +++ b/src/tangara/system_fsm/booting.cpp @@ -104,8 +104,7 @@ auto Booting::entry() -> void { ESP_LOGI(kTag, "init bluetooth"); sServices->bluetooth(std::make_unique<drivers::Bluetooth>( - sServices->nvs(), sServices->bg_worker())); - sServices->bluetooth().SetEventHandler(bt_event_cb); + sServices->nvs(), sServices->bg_worker(), bt_event_cb)); BootComplete ev{.services = sServices}; events::Audio().Dispatch(ev); 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 <stdint.h> +#include <algorithm> #include <memory> #include <memory_resource> #include <variant> #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<bool>(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<bool>(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<bool>(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<bool>(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<drivers::bluetooth::Device>(val)) { - auto dev = std::get<drivers::bluetooth::Device>(val); - sServices->bluetooth().SetPreferredDevice( - drivers::bluetooth::MacAndName{ - .mac = dev.address, - .name = {dev.name.data(), dev.name.size()}, - }); + if (std::holds_alternative<drivers::bluetooth::MacAndName>(val)) { + auto dev = std::get<drivers::bluetooth::MacAndName>(val); + sServices->bluetooth().pairedDevice(dev); + } else if (std::holds_alternative<std::monostate>(val)) { + sServices->bluetooth().pairedDevice({}); + } else { + // Don't accept any other types. + return false; } - return false; + return true; }}; -lua::Property UiState::sBluetoothDevices{ - std::vector<drivers::bluetooth::Device>{}}; + +lua::Property UiState::sBluetoothKnownDevices{ + std::vector<drivers::bluetooth::MacAndName>{}}; +lua::Property UiState::sBluetoothDiscoveredDevices{ + std::vector<drivers::bluetooth::MacAndName>{}}; 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<drivers::bluetooth::MacAndName> dev; + std::vector<drivers::bluetooth::MacAndName> devs; + if (std::holds_alternative<SimpleEvent>(ev.event)) { switch (std::get<SimpleEvent>(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<drivers::bluetooth::RemoteVolumeChanged>( 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<drivers::bluetooth::RemoteVolumeChanged>(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<UiState> { 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; |
