diff --git a/src/audio/audio_fsm.cpp b/src/audio/audio_fsm.cpp index 8791b9c4..9558d778 100644 --- a/src/audio/audio_fsm.cpp +++ b/src/audio/audio_fsm.cpp @@ -59,7 +59,7 @@ auto AudioState::Init(drivers::IGpios* gpio_expander, sFileSource.reset(new FatfsAudioInput(tag_parser)); sI2SOutput.reset(new I2SAudioOutput(sIGpios, sDac)); - // sBtOutput.reset(new BluetoothAudioOutput(bluetooth)); + sBtOutput.reset(new BluetoothAudioOutput(bluetooth)); AudioTask::Start(sFileSource.get(), sI2SOutput.get()); // AudioTask::Start(sFileSource.get(), sBtOutput.get()); diff --git a/src/drivers/bluetooth.cpp b/src/drivers/bluetooth.cpp index 79999b2c..f6992f05 100644 --- a/src/drivers/bluetooth.cpp +++ b/src/drivers/bluetooth.cpp @@ -20,6 +20,7 @@ #include "esp_wifi.h" #include "esp_wifi_types.h" #include "freertos/portmacro.h" +#include "nvs.hpp" #include "tinyfsm/include/tinyfsm.hpp" namespace drivers { @@ -55,8 +56,8 @@ auto a2dp_data_cb(uint8_t* buf, int32_t buf_size) -> int32_t { return xStreamBufferReceive(stream, buf, buf_size, 0); } -Bluetooth::Bluetooth() { - tinyfsm::FsmList::start(); +Bluetooth::Bluetooth(NvsStorage* storage) { + bluetooth::BluetoothState::Init(storage); } auto Bluetooth::Enable() -> bool { @@ -101,12 +102,15 @@ auto DeviceName() -> std::string { uint8_t mac[8]{0}; esp_efuse_mac_get_default(mac); std::ostringstream name; - name << "TANGARA " << std::hex << mac[0] << mac[1]; + name << "TANGARA " << std::hex << static_cast(mac[0]) + << static_cast(mac[1]); return name.str(); } namespace bluetooth { +NvsStorage* BluetoothState::sStorage_; + std::mutex BluetoothState::sDevicesMutex_; std::map BluetoothState::sDevices_; std::optional BluetoothState::sPreferredDevice_; @@ -114,6 +118,12 @@ mac_addr_t BluetoothState::sCurrentDevice_; std::atomic BluetoothState::sSource_; +auto BluetoothState::Init(NvsStorage* storage) -> void { + sStorage_ = storage; + sPreferredDevice_ = storage->PreferredBluetoothDevice(); + tinyfsm::FsmList::start(); +} + auto BluetoothState::devices() -> std::vector { std::lock_guard lock{sDevicesMutex_}; std::vector out; @@ -417,6 +427,11 @@ void Connecting::react(const events::internal::A2dp& ev) { void Connected::entry() { ESP_LOGI(kTag, "entering connected state"); + + auto stored_pref = sStorage_->PreferredBluetoothDevice(); + if (stored_pref != sPreferredDevice_) { + sStorage_->PreferredBluetoothDevice(sPreferredDevice_); + } // TODO: if we already have a source, immediately start playing } diff --git a/src/drivers/include/bluetooth.hpp b/src/drivers/include/bluetooth.hpp index bdc45910..fc72d393 100644 --- a/src/drivers/include/bluetooth.hpp +++ b/src/drivers/include/bluetooth.hpp @@ -11,32 +11,22 @@ #include #include +#include "bluetooth_types.hpp" #include "esp_a2dp_api.h" #include "esp_avrc_api.h" #include "esp_gap_bt_api.h" +#include "nvs.hpp" #include "tinyfsm.hpp" #include "tinyfsm/include/tinyfsm.hpp" namespace drivers { -namespace bluetooth { - -typedef std::array mac_addr_t; - -struct Device { - mac_addr_t address; - std::string name; - uint32_t class_of_device; - int8_t signal_strength; -}; -} // namespace bluetooth - /* * A handle used to interact with the bluetooth state machine. */ class Bluetooth { public: - Bluetooth(); + Bluetooth(NvsStorage* storage); auto Enable() -> bool; auto Disable() -> void; @@ -74,6 +64,8 @@ struct Avrc : public tinyfsm::Event { class BluetoothState : public tinyfsm::Fsm { public: + static auto Init(NvsStorage* storage) -> void; + static auto devices() -> std::vector; static auto preferred_device() -> std::optional; static auto preferred_device(const mac_addr_t&) -> void; @@ -96,6 +88,8 @@ class BluetoothState : public tinyfsm::Fsm { virtual void react(const events::internal::Avrc& ev){}; protected: + static NvsStorage* sStorage_; + static std::mutex sDevicesMutex_; static std::map sDevices_; static std::optional sPreferredDevice_; diff --git a/src/drivers/include/bluetooth_types.hpp b/src/drivers/include/bluetooth_types.hpp new file mode 100644 index 00000000..03100651 --- /dev/null +++ b/src/drivers/include/bluetooth_types.hpp @@ -0,0 +1,20 @@ + +#pragma once + +#include +#include + +namespace drivers { +namespace bluetooth { + +typedef std::array mac_addr_t; + +struct Device { + mac_addr_t address; + std::string name; + uint32_t class_of_device; + int8_t signal_strength; +}; + +} // namespace bluetooth +} // namespace drivers diff --git a/src/drivers/include/nvs.hpp b/src/drivers/include/nvs.hpp index be783583..32c2ae73 100644 --- a/src/drivers/include/nvs.hpp +++ b/src/drivers/include/nvs.hpp @@ -6,9 +6,13 @@ #pragma once +#include + #include "esp_err.h" #include "nvs.h" +#include "bluetooth_types.hpp" + namespace drivers { class NvsStorage { @@ -17,6 +21,9 @@ class NvsStorage { auto SchemaVersion() -> uint8_t; + auto PreferredBluetoothDevice() -> std::optional; + auto PreferredBluetoothDevice(std::optional) -> void; + explicit NvsStorage(nvs_handle_t); ~NvsStorage(); diff --git a/src/drivers/nvs.cpp b/src/drivers/nvs.cpp index a2de9518..8c7e54a8 100644 --- a/src/drivers/nvs.cpp +++ b/src/drivers/nvs.cpp @@ -10,6 +10,7 @@ #include #include +#include "bluetooth.hpp" #include "esp_log.h" #include "nvs.h" #include "nvs_flash.h" @@ -20,6 +21,7 @@ static constexpr char kTag[] = "nvm"; static constexpr uint8_t kSchemaVersion = 1; static constexpr char kKeyVersion[] = "ver"; +static constexpr char kKeyBluetooth[] = "bt"; auto NvsStorage::Open() -> NvsStorage* { esp_err_t err = nvs_flash_init(); @@ -70,4 +72,24 @@ auto NvsStorage::SchemaVersion() -> uint8_t { return ret; } +auto NvsStorage::PreferredBluetoothDevice() + -> std::optional { + bluetooth::mac_addr_t out{0}; + size_t size = out.size(); + if (nvs_get_blob(handle_, kKeyBluetooth, out.data(), &size) != ESP_OK) { + return {}; + } + return out; +} +auto NvsStorage::PreferredBluetoothDevice( + std::optional addr) -> void { + if (!addr) { + nvs_erase_key(handle_, kKeyBluetooth); + } else { + nvs_set_blob(handle_, kKeyBluetooth, addr.value().data(), + addr.value().size()); + } + nvs_commit(handle_); +} + } // namespace drivers diff --git a/src/system_fsm/booting.cpp b/src/system_fsm/booting.cpp index 7bd5f890..1fc01976 100644 --- a/src/system_fsm/booting.cpp +++ b/src/system_fsm/booting.cpp @@ -62,7 +62,8 @@ auto Booting::entry() -> void { } ESP_LOGI(kTag, "starting bluetooth"); - sBluetooth.reset(new drivers::Bluetooth()); + sBluetooth.reset(new drivers::Bluetooth(sNvs.get())); + // sBluetooth->Enable(); // At this point we've done all of the essential boot tasks. Start remaining // state machines and inform them that the system is ready.