You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
5.8 KiB
223 lines
5.8 KiB
|
|
#pragma once
|
|
|
|
#include <array>
|
|
#include <atomic>
|
|
#include <map>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include <freertos/FreeRTOS.h>
|
|
#include <freertos/stream_buffer.h>
|
|
#include <stdint.h>
|
|
#include "bluetooth_types.hpp"
|
|
#include "esp_a2dp_api.h"
|
|
#include "esp_avrc_api.h"
|
|
#include "esp_gap_bt_api.h"
|
|
#include "nvs.hpp"
|
|
#include "tasks.hpp"
|
|
#include "tinyfsm.hpp"
|
|
#include "tinyfsm/include/tinyfsm.hpp"
|
|
|
|
namespace drivers {
|
|
|
|
/*
|
|
* A handle used to interact with the bluetooth state machine.
|
|
*/
|
|
class Bluetooth {
|
|
public:
|
|
Bluetooth(NvsStorage& storage, tasks::WorkerPool&);
|
|
|
|
auto Enable() -> bool;
|
|
auto Disable() -> void;
|
|
auto IsEnabled() -> bool;
|
|
|
|
auto IsConnected() -> bool;
|
|
auto ConnectedDevice() -> std::optional<bluetooth::MacAndName>;
|
|
|
|
auto KnownDevices() -> std::vector<bluetooth::Device>;
|
|
|
|
auto SetPreferredDevice(std::optional<bluetooth::MacAndName> dev) -> void;
|
|
auto PreferredDevice() -> std::optional<bluetooth::MacAndName>;
|
|
|
|
auto SetSource(StreamBufferHandle_t) -> void;
|
|
auto SetVolume(uint8_t) -> void;
|
|
|
|
auto SetEventHandler(std::function<void(bluetooth::Event)> cb) -> void;
|
|
};
|
|
|
|
namespace bluetooth {
|
|
|
|
namespace events {
|
|
struct Enable : public tinyfsm::Event {};
|
|
struct Disable : public tinyfsm::Event {};
|
|
|
|
struct ConnectTimedOut : public tinyfsm::Event {};
|
|
struct PreferredDeviceChanged : public tinyfsm::Event {};
|
|
struct SourceChanged : public tinyfsm::Event {};
|
|
struct DeviceDiscovered : public tinyfsm::Event {
|
|
const Device& device;
|
|
};
|
|
struct ChangeVolume : public tinyfsm::Event {
|
|
const uint8_t volume;
|
|
};
|
|
|
|
namespace internal {
|
|
struct Gap : public tinyfsm::Event {
|
|
esp_bt_gap_cb_event_t type;
|
|
esp_bt_gap_cb_param_t* param;
|
|
};
|
|
struct A2dp : public tinyfsm::Event {
|
|
esp_a2d_cb_event_t type;
|
|
esp_a2d_cb_param_t* param;
|
|
};
|
|
struct Avrc : public tinyfsm::Event {
|
|
esp_avrc_ct_cb_event_t type;
|
|
esp_avrc_ct_cb_param_t param;
|
|
};
|
|
} // namespace internal
|
|
} // namespace events
|
|
|
|
/*
|
|
* Utility for managing scanning, independent of the current connection state.
|
|
*/
|
|
class Scanner {
|
|
public:
|
|
Scanner();
|
|
|
|
auto ScanContinuously() -> void;
|
|
auto ScanOnce() -> void;
|
|
auto StopScanning() -> void;
|
|
auto StopScanningNow() -> void;
|
|
|
|
auto HandleGapEvent(const events::internal::Gap&) -> void;
|
|
|
|
private:
|
|
bool enabled_;
|
|
bool is_discovering_;
|
|
|
|
auto HandleDeviceDiscovery(const esp_bt_gap_cb_param_t& param) -> void;
|
|
};
|
|
|
|
class BluetoothState : public tinyfsm::Fsm<BluetoothState> {
|
|
public:
|
|
static auto Init(NvsStorage& storage) -> void;
|
|
|
|
static auto lock() -> std::lock_guard<std::mutex>;
|
|
|
|
static auto devices() -> std::vector<Device>;
|
|
|
|
static auto preferred_device() -> std::optional<bluetooth::MacAndName>;
|
|
static auto preferred_device(std::optional<bluetooth::MacAndName>) -> void;
|
|
|
|
static auto scanning() -> bool;
|
|
static auto discovery() -> bool;
|
|
static auto discovery(bool) -> void;
|
|
|
|
static auto source() -> StreamBufferHandle_t;
|
|
static auto source(StreamBufferHandle_t) -> void;
|
|
|
|
static auto event_handler(std::function<void(Event)>) -> void;
|
|
|
|
virtual ~BluetoothState(){};
|
|
|
|
virtual void entry() {}
|
|
virtual void exit() {}
|
|
|
|
virtual void react(const events::Enable& ev){};
|
|
virtual void react(const events::Disable& ev) = 0;
|
|
virtual void react(const events::ConnectTimedOut& ev){};
|
|
virtual void react(const events::PreferredDeviceChanged& ev){};
|
|
virtual void react(const events::SourceChanged& ev){};
|
|
virtual void react(const events::ChangeVolume&) {}
|
|
|
|
virtual void react(const events::DeviceDiscovered&);
|
|
|
|
virtual void react(const events::internal::Gap& ev) = 0;
|
|
virtual void react(const events::internal::A2dp& ev){};
|
|
virtual void react(const events::internal::Avrc& ev){};
|
|
|
|
protected:
|
|
static NvsStorage* sStorage_;
|
|
static Scanner* sScanner_;
|
|
|
|
static std::mutex sFsmMutex;
|
|
static std::map<mac_addr_t, Device> sDevices_;
|
|
static std::optional<bluetooth::MacAndName> sPreferredDevice_;
|
|
|
|
static std::optional<bluetooth::MacAndName> sConnectingDevice_;
|
|
static int sConnectAttemptsRemaining_;
|
|
|
|
static std::atomic<StreamBufferHandle_t> sSource_;
|
|
static std::function<void(Event)> sEventHandler_;
|
|
|
|
auto connect(const bluetooth::MacAndName&) -> bool;
|
|
};
|
|
|
|
class Disabled : public BluetoothState {
|
|
public:
|
|
void entry() override;
|
|
|
|
void react(const events::Enable& ev) override;
|
|
void react(const events::Disable& ev) override{};
|
|
|
|
void react(const events::internal::Gap& ev) override {}
|
|
void react(const events::internal::A2dp& ev) override {}
|
|
|
|
using BluetoothState::react;
|
|
};
|
|
|
|
class Idle : public BluetoothState {
|
|
public:
|
|
void entry() override;
|
|
void exit() override;
|
|
|
|
void react(const events::Disable& ev) override;
|
|
void react(const events::PreferredDeviceChanged& ev) override;
|
|
|
|
void react(const events::internal::Gap& ev) override;
|
|
|
|
using BluetoothState::react;
|
|
};
|
|
|
|
class Connecting : public BluetoothState {
|
|
public:
|
|
void entry() override;
|
|
void exit() override;
|
|
|
|
void react(const events::PreferredDeviceChanged& ev) override;
|
|
|
|
void react(const events::ConnectTimedOut& ev) override;
|
|
void react(const events::Disable& ev) override;
|
|
void react(const events::internal::Gap& ev) override;
|
|
void react(const events::internal::A2dp& ev) override;
|
|
|
|
using BluetoothState::react;
|
|
};
|
|
|
|
class Connected : public BluetoothState {
|
|
public:
|
|
void entry() override;
|
|
void exit() override;
|
|
|
|
void react(const events::PreferredDeviceChanged& ev) override;
|
|
void react(const events::SourceChanged& ev) override;
|
|
void react(const events::ChangeVolume&) override;
|
|
|
|
void react(const events::Disable& ev) override;
|
|
void react(const events::internal::Gap& ev) override;
|
|
void react(const events::internal::A2dp& ev) override;
|
|
void react(const events::internal::Avrc& ev) override;
|
|
|
|
using BluetoothState::react;
|
|
|
|
private:
|
|
uint8_t transaction_num_;
|
|
mac_addr_t connected_to_;
|
|
};
|
|
|
|
} // namespace bluetooth
|
|
|
|
} // namespace drivers
|
|
|