improve the locking strategy of the bluetooth fsm

custom
jacqueline 1 year ago
parent d23435fab7
commit 1b7821a474
  1. 35
      src/drivers/bluetooth.cpp
  2. 4
      src/drivers/include/bluetooth.hpp

@ -40,17 +40,20 @@ DRAM_ATTR static StreamBufferHandle_t sStream = nullptr;
static tasks::WorkerPool* sBgWorker; static tasks::WorkerPool* sBgWorker;
auto gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t* param) -> void { auto gap_cb(esp_bt_gap_cb_event_t event, esp_bt_gap_cb_param_t* param) -> void {
auto lock = bluetooth::BluetoothState::lock();
tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch( tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch(
bluetooth::events::internal::Gap{.type = event, .param = param}); bluetooth::events::internal::Gap{.type = event, .param = param});
} }
auto avrcp_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t* param) auto avrcp_cb(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t* param)
-> void { -> void {
auto lock = bluetooth::BluetoothState::lock();
tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch( tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch(
bluetooth::events::internal::Avrc{.type = event, .param = param}); bluetooth::events::internal::Avrc{.type = event, .param = param});
} }
auto a2dp_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t* param) -> void { auto a2dp_cb(esp_a2d_cb_event_t event, esp_a2d_cb_param_t* param) -> void {
auto lock = bluetooth::BluetoothState::lock();
tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch( tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch(
bluetooth::events::internal::A2dp{.type = event, .param = param}); bluetooth::events::internal::A2dp{.type = event, .param = param});
} }
@ -72,6 +75,7 @@ Bluetooth::Bluetooth(NvsStorage& storage, tasks::WorkerPool& bg_worker) {
} }
auto Bluetooth::Enable() -> bool { auto Bluetooth::Enable() -> bool {
auto lock = bluetooth::BluetoothState::lock();
tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch( tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch(
bluetooth::events::Enable{}); bluetooth::events::Enable{});
@ -79,20 +83,24 @@ auto Bluetooth::Enable() -> bool {
} }
auto Bluetooth::Disable() -> void { auto Bluetooth::Disable() -> void {
auto lock = bluetooth::BluetoothState::lock();
tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch( tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch(
bluetooth::events::Disable{}); bluetooth::events::Disable{});
} }
auto Bluetooth::IsEnabled() -> bool { auto Bluetooth::IsEnabled() -> bool {
auto lock = bluetooth::BluetoothState::lock();
return !bluetooth::BluetoothState::is_in_state<bluetooth::Disabled>(); return !bluetooth::BluetoothState::is_in_state<bluetooth::Disabled>();
} }
auto Bluetooth::IsConnected() -> bool { auto Bluetooth::IsConnected() -> bool {
auto lock = bluetooth::BluetoothState::lock();
return bluetooth::BluetoothState::is_in_state<bluetooth::Connected>(); return bluetooth::BluetoothState::is_in_state<bluetooth::Connected>();
} }
auto Bluetooth::ConnectedDevice() -> std::optional<bluetooth::Device> { auto Bluetooth::ConnectedDevice() -> std::optional<bluetooth::Device> {
if (!IsConnected()) { auto lock = bluetooth::BluetoothState::lock();
if (!bluetooth::BluetoothState::is_in_state<bluetooth::Connected>()) {
return {}; return {};
} }
auto looking_for = bluetooth::BluetoothState::preferred_device(); auto looking_for = bluetooth::BluetoothState::preferred_device();
@ -108,6 +116,7 @@ auto Bluetooth::ConnectedDevice() -> std::optional<bluetooth::Device> {
} }
auto Bluetooth::KnownDevices() -> std::vector<bluetooth::Device> { auto Bluetooth::KnownDevices() -> std::vector<bluetooth::Device> {
auto lock = bluetooth::BluetoothState::lock();
std::vector<bluetooth::Device> out = bluetooth::BluetoothState::devices(); std::vector<bluetooth::Device> out = bluetooth::BluetoothState::devices();
std::sort(out.begin(), out.end(), [](const auto& a, const auto& b) -> bool { std::sort(out.begin(), out.end(), [](const auto& a, const auto& b) -> bool {
return a.signal_strength < b.signal_strength; return a.signal_strength < b.signal_strength;
@ -117,6 +126,7 @@ auto Bluetooth::KnownDevices() -> std::vector<bluetooth::Device> {
auto Bluetooth::SetPreferredDevice(std::optional<bluetooth::MacAndName> dev) auto Bluetooth::SetPreferredDevice(std::optional<bluetooth::MacAndName> dev)
-> void { -> void {
auto lock = bluetooth::BluetoothState::lock();
auto cur = bluetooth::BluetoothState::preferred_device(); auto cur = bluetooth::BluetoothState::preferred_device();
if (dev && cur && dev->mac == cur->mac) { if (dev && cur && dev->mac == cur->mac) {
return; return;
@ -130,10 +140,12 @@ auto Bluetooth::SetPreferredDevice(std::optional<bluetooth::MacAndName> dev)
} }
auto Bluetooth::PreferredDevice() -> std::optional<bluetooth::MacAndName> { auto Bluetooth::PreferredDevice() -> std::optional<bluetooth::MacAndName> {
auto lock = bluetooth::BluetoothState::lock();
return bluetooth::BluetoothState::preferred_device(); return bluetooth::BluetoothState::preferred_device();
} }
auto Bluetooth::SetSource(StreamBufferHandle_t src) -> void { auto Bluetooth::SetSource(StreamBufferHandle_t src) -> void {
auto lock = bluetooth::BluetoothState::lock();
if (src == bluetooth::BluetoothState::source()) { if (src == bluetooth::BluetoothState::source()) {
return; return;
} }
@ -143,12 +155,14 @@ auto Bluetooth::SetSource(StreamBufferHandle_t src) -> void {
} }
auto Bluetooth::SetVolume(uint8_t vol) -> void { auto Bluetooth::SetVolume(uint8_t vol) -> void {
auto lock = bluetooth::BluetoothState::lock();
tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch( tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch(
bluetooth::events::ChangeVolume{.volume = vol}); bluetooth::events::ChangeVolume{.volume = vol});
} }
auto Bluetooth::SetEventHandler(std::function<void(bluetooth::Event)> cb) auto Bluetooth::SetEventHandler(std::function<void(bluetooth::Event)> cb)
-> void { -> void {
auto lock = bluetooth::BluetoothState::lock();
bluetooth::BluetoothState::event_handler(cb); bluetooth::BluetoothState::event_handler(cb);
} }
@ -296,7 +310,7 @@ auto Scanner::HandleDeviceDiscovery(const esp_bt_gap_cb_param_t& param)
NvsStorage* BluetoothState::sStorage_; NvsStorage* BluetoothState::sStorage_;
Scanner* BluetoothState::sScanner_; Scanner* BluetoothState::sScanner_;
std::mutex BluetoothState::sDevicesMutex_{}; std::mutex BluetoothState::sFsmMutex{};
std::map<mac_addr_t, Device> BluetoothState::sDevices_{}; std::map<mac_addr_t, Device> BluetoothState::sDevices_{};
std::optional<MacAndName> BluetoothState::sPreferredDevice_{}; std::optional<MacAndName> BluetoothState::sPreferredDevice_{};
std::optional<MacAndName> BluetoothState::sConnectingDevice_{}; std::optional<MacAndName> BluetoothState::sConnectingDevice_{};
@ -311,8 +325,11 @@ auto BluetoothState::Init(NvsStorage& storage) -> void {
tinyfsm::FsmList<bluetooth::BluetoothState>::start(); tinyfsm::FsmList<bluetooth::BluetoothState>::start();
} }
auto BluetoothState::lock() -> std::lock_guard<std::mutex> {
return std::lock_guard<std::mutex>{sFsmMutex};
}
auto BluetoothState::devices() -> std::vector<Device> { auto BluetoothState::devices() -> std::vector<Device> {
std::lock_guard lock{sDevicesMutex_};
std::vector<Device> out; std::vector<Device> out;
for (const auto& device : sDevices_) { for (const auto& device : sDevices_) {
out.push_back(device.second); out.push_back(device.second);
@ -321,34 +338,27 @@ auto BluetoothState::devices() -> std::vector<Device> {
} }
auto BluetoothState::preferred_device() -> std::optional<MacAndName> { auto BluetoothState::preferred_device() -> std::optional<MacAndName> {
std::lock_guard lock{sDevicesMutex_};
return sPreferredDevice_; return sPreferredDevice_;
} }
auto BluetoothState::preferred_device(std::optional<MacAndName> addr) -> void { auto BluetoothState::preferred_device(std::optional<MacAndName> addr) -> void {
std::lock_guard lock{sDevicesMutex_};
sPreferredDevice_ = addr; sPreferredDevice_ = addr;
} }
auto BluetoothState::source() -> StreamBufferHandle_t { auto BluetoothState::source() -> StreamBufferHandle_t {
std::lock_guard lock{sDevicesMutex_};
return sSource_.load(); return sSource_.load();
} }
auto BluetoothState::source(StreamBufferHandle_t src) -> void { auto BluetoothState::source(StreamBufferHandle_t src) -> void {
std::lock_guard lock{sDevicesMutex_};
sSource_.store(src); sSource_.store(src);
} }
auto BluetoothState::event_handler(std::function<void(Event)> cb) -> void { auto BluetoothState::event_handler(std::function<void(Event)> cb) -> void {
std::lock_guard lock{sDevicesMutex_};
sEventHandler_ = cb; sEventHandler_ = cb;
} }
auto BluetoothState::react(const events::DeviceDiscovered& ev) -> void { auto BluetoothState::react(const events::DeviceDiscovered& ev) -> void {
bool is_preferred = false; bool is_preferred = false;
{
std::lock_guard<std::mutex> lock{sDevicesMutex_};
bool already_known = sDevices_.contains(ev.device.address); bool already_known = sDevices_.contains(ev.device.address);
sDevices_[ev.device.address] = ev.device; sDevices_[ev.device.address] = ev.device;
@ -359,7 +369,6 @@ auto BluetoothState::react(const events::DeviceDiscovered& ev) -> void {
if (sEventHandler_ && !already_known) { if (sEventHandler_ && !already_known) {
std::invoke(sEventHandler_, Event::kKnownDevicesChanged); std::invoke(sEventHandler_, Event::kKnownDevicesChanged);
} }
}
if (is_preferred && sPreferredDevice_) { if (is_preferred && sPreferredDevice_) {
connect(*sPreferredDevice_); connect(*sPreferredDevice_);
@ -487,12 +496,9 @@ void Idle::react(const events::Disable& ev) {
void Idle::react(const events::PreferredDeviceChanged& ev) { void Idle::react(const events::PreferredDeviceChanged& ev) {
bool is_discovered = false; bool is_discovered = false;
{
std::lock_guard<std::mutex> lock{sDevicesMutex_};
if (sPreferredDevice_ && sDevices_.contains(sPreferredDevice_->mac)) { if (sPreferredDevice_ && sDevices_.contains(sPreferredDevice_->mac)) {
is_discovered = true; is_discovered = true;
} }
}
if (is_discovered) { if (is_discovered) {
connect(*sPreferredDevice_); connect(*sPreferredDevice_);
} }
@ -506,6 +512,7 @@ TimerHandle_t sTimeoutTimer;
static void timeoutCallback(TimerHandle_t) { static void timeoutCallback(TimerHandle_t) {
sBgWorker->Dispatch<void>([]() { sBgWorker->Dispatch<void>([]() {
auto lock = bluetooth::BluetoothState::lock();
tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch( tinyfsm::FsmList<bluetooth::BluetoothState>::dispatch(
events::ConnectTimedOut{}); events::ConnectTimedOut{});
}); });

@ -105,6 +105,8 @@ class BluetoothState : public tinyfsm::Fsm<BluetoothState> {
public: public:
static auto Init(NvsStorage& storage) -> void; static auto Init(NvsStorage& storage) -> void;
static auto lock() -> std::lock_guard<std::mutex>;
static auto devices() -> std::vector<Device>; static auto devices() -> std::vector<Device>;
static auto preferred_device() -> std::optional<bluetooth::MacAndName>; static auto preferred_device() -> std::optional<bluetooth::MacAndName>;
@ -141,7 +143,7 @@ class BluetoothState : public tinyfsm::Fsm<BluetoothState> {
static NvsStorage* sStorage_; static NvsStorage* sStorage_;
static Scanner* sScanner_; static Scanner* sScanner_;
static std::mutex sDevicesMutex_; static std::mutex sFsmMutex;
static std::map<mac_addr_t, Device> sDevices_; static std::map<mac_addr_t, Device> sDevices_;
static std::optional<bluetooth::MacAndName> sPreferredDevice_; static std::optional<bluetooth::MacAndName> sPreferredDevice_;

Loading…
Cancel
Save