Line data Source code
1 : #pragma once
2 :
3 : #include <AH/Error/Error.hpp>
4 :
5 : #include "BLEAPI.hpp"
6 : #include "BufferedBLEMIDIParser.hpp"
7 : #include "ThreadedBLEMIDISender.hpp"
8 : #include "Util/ESP32Threads.hpp"
9 :
10 : #include <atomic>
11 :
12 : #ifndef ARDUINO
13 : #define ESP_LOGD(...) ((void)0)
14 : #define ESP_LOGE(...) ((void)0)
15 : #define ESP_LOGI(...) ((void)0)
16 : #endif
17 :
18 : BEGIN_CS_NAMESPACE
19 :
20 : /// ESP32 backend intended to be plugged into @ref GenericBLEMIDI_Interface.
21 : /// @p Impl can be used to select different low-level BLE stacks.
22 : template <class Impl>
23 : class ESP32BLEBackend : private ThreadedBLEMIDISender<ESP32BLEBackend<Impl>>,
24 : private MIDIBLEInstance {
25 : protected:
26 : [[no_unique_address]] Impl impl;
27 : using Sender = ThreadedBLEMIDISender<ESP32BLEBackend>;
28 : friend Sender;
29 22 : void sendData(BLEDataView data) {
30 22 : auto chr = characteristic.load();
31 22 : auto con = connection.load();
32 : ESP_LOGD("CS-BLEMIDI", "conn=%d, char=%d", con.conn,
33 : chr.characteristic);
34 22 : if (chr.characteristic == 0xFFFF)
35 0 : return;
36 22 : impl.notify(con, chr, data);
37 : }
38 : std::atomic<BLEConnectionHandle> connection;
39 : std::atomic<BLECharacteristicHandle> characteristic;
40 :
41 : protected:
42 28 : void handleConnect(BLEConnectionHandle conn_handle) override {
43 : ESP_LOGD("CS-BLEMIDI", "conn=%d", conn_handle.conn);
44 28 : this->connection.store(conn_handle);
45 28 : }
46 0 : void handleDisconnect(
47 : [[maybe_unused]] BLEConnectionHandle conn_handle) override {
48 : ESP_LOGD("CS-BLEMIDI", "conn=%d", conn_handle.conn);
49 0 : this->connection.store({});
50 0 : this->characteristic.store({});
51 0 : }
52 0 : void handleMTU([[maybe_unused]] BLEConnectionHandle conn_handle,
53 : uint16_t mtu) override {
54 : ESP_LOGD("CS-BLEMIDI", "conn=%d, mtu=%d", conn_handle.conn, mtu);
55 0 : Sender::updateMTU(mtu);
56 0 : }
57 28 : void handleSubscribe(BLEConnectionHandle conn_handle,
58 : BLECharacteristicHandle char_handle,
59 : bool notify) override {
60 : ESP_LOGD("CS-BLEMIDI", "conn=%d, char=%d, notify=%d", conn_handle.conn,
61 : char_handle.characteristic, +notify);
62 28 : if (notify) {
63 28 : this->connection.store(conn_handle);
64 28 : this->characteristic.store(char_handle);
65 : } else {
66 0 : this->characteristic.store({});
67 : }
68 28 : }
69 15 : void handleData([[maybe_unused]] BLEConnectionHandle conn_handle,
70 : BLEDataGenerator &&data, BLEDataLifetime) override {
71 : ESP_LOGD("CS-BLEMIDI", "conn=%d", conn_handle.conn);
72 15 : BLEDataView packet = data();
73 15 : if (!packet)
74 0 : return;
75 15 : if (!parser.pushPacket(packet)) {
76 : ESP_LOGE("CS-BLEMIDI", "BLE packet dropped, size=%d",
77 : packet.length);
78 0 : return;
79 : }
80 15 : while (BLEDataView cont = data()) {
81 0 : if (!parser.pushPacket(cont, BLEDataType::Continuation)) {
82 : ESP_LOGE("CS-BLEMIDI", "BLE chunk dropped, size=%d",
83 : cont.length);
84 0 : return;
85 : } else {
86 : ESP_LOGI("CS-BLEMIDI", "added chunk, size=%d", cont.length);
87 : }
88 : }
89 : }
90 :
91 : private:
92 : struct AtomicSize {
93 : #ifdef ESP32
94 : constexpr static size_t alignment = 32; // default cache size
95 : #else
96 : constexpr static size_t alignment = 64;
97 : #endif
98 29 : AtomicSize(uint_fast16_t value) : value {value} {}
99 : std::atomic_uint_fast16_t value;
100 42 : uint_fast16_t load_acquire() const {
101 84 : return value.load(std::memory_order_acquire);
102 : }
103 15 : void add_release(uint_fast16_t t) {
104 15 : value.fetch_add(t, std::memory_order_release);
105 15 : }
106 27 : void sub_release(uint_fast16_t t) {
107 27 : value.fetch_sub(t, std::memory_order_release);
108 27 : }
109 : };
110 : /// Contains incoming BLE MIDI data to be parsed.
111 : BufferedBLEMIDIParser<4096, AtomicSize> parser;
112 :
113 : public:
114 : using IncomingMIDIMessage = AnyMIDIMessage;
115 52 : bool popMessage(IncomingMIDIMessage &incomingMessage) {
116 52 : return parser.popMessage(incomingMessage);
117 : }
118 :
119 : public:
120 28 : void begin(BLESettings ble_settings) {
121 28 : impl.init(*this, ble_settings);
122 : // Need larger stack than default, pin to non-Arduino core
123 28 : ScopedThreadConfig sc {4096, 3, true, "CS-BLEMIDI", 0};
124 28 : Sender::begin();
125 28 : }
126 : void end() {
127 : FATAL_ERROR(F("ESP32BLEBackend::end not implemented"), 0x3278);
128 : }
129 : bool isConnected() const {
130 : return connection.load(std::memory_order_relaxed).conn != 0xFFFF;
131 : }
132 : using Sender::acquirePacket;
133 : using Sender::forceMinMTU;
134 : using Sender::getMinMTU;
135 : using Sender::releasePacketAndNotify;
136 : using Sender::sendNow;
137 : using Sender::setTimeout;
138 : };
139 :
140 : END_CS_NAMESPACE
|