LCOV - code coverage report
Current view: top level - src/MIDI_Interfaces/BLEMIDI - ESP32Backend.hpp (source / functions) Hit Total Coverage
Test: b8a30b4b7040ae1abf162fd0a258beaa2de43626 Lines: 34 47 72.3 %
Date: 2024-12-21 21:28:55 Functions: 10 12 83.3 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.15