LCOV - code coverage report
Current view: top level - src/MIDI_Interfaces - BluetoothMIDI_Interface.hpp (source / functions) Hit Total Coverage
Test: 90a1b9beff85a60dc6ebcea034a947a845e56960 Lines: 28 108 25.9 %
Date: 2019-11-30 15:53:32 Functions: 6 22 27.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "BLEMIDI.hpp"
       4             : #include "SerialMIDI_Interface.hpp"
       5             : 
       6             : #include <AH/Error/Error.hpp>
       7             : 
       8             : BEGIN_CS_NAMESPACE
       9             : 
      10             : /**
      11             :  * @brief   Bluetooth Low Energy MIDI Interface for the ESP32.
      12             :  * 
      13             :  * @ingroup MIDIInterfaces
      14             :  */
      15          10 : class BluetoothMIDI_Interface : public Parsing_MIDI_Interface,
      16             :                                 public BLEServerCallbacks,
      17             :                                 public BLECharacteristicCallbacks {
      18             : 
      19             :     // BLE Callbacks
      20             : 
      21           0 :     void onConnect(BLEServer *pServer) override {
      22             :         (void)pServer;
      23           0 :         DEBUGFN("Connected");
      24           0 :         connected++;
      25           0 :     };
      26           0 :     void onDisconnect(BLEServer *pServer) override {
      27             :         (void)pServer;
      28           0 :         DEBUGFN("Disonnected");
      29           0 :         if (!connected) {
      30           0 :             ERROR(F("Error: disconnect event, but was not connected"), 0x7788);
      31           0 :             return;
      32             :         }
      33           0 :         connected--;
      34           0 :     }
      35             : 
      36           0 :     void onRead(BLECharacteristic *pCharacteristic) override {
      37           0 :         DEBUGFN("Read");
      38           0 :         pCharacteristic->setValue(nullptr, 0);
      39           0 :     }
      40           0 :     void onWrite(BLECharacteristic *pCharacteristic) override {
      41           0 :         DEBUGFN("Write: ");
      42           0 :         std::string value = pCharacteristic->getValue();
      43           0 :         const uint8_t *const data =
      44           0 :             reinterpret_cast<const uint8_t *>(value.data());
      45           0 :         size_t len = value.size();
      46           0 :         for (size_t i = 0; i < len; i++) {
      47           0 :             Serial.print(data[i], HEX);
      48           0 :             Serial.print(' ');
      49           0 :         }
      50           0 :         Serial.println();
      51           0 :         parse(data, len);
      52           0 :     }
      53             : 
      54             :     constexpr static unsigned long MAX_MESSAGE_TIME = 10000; // microseconds
      55             : 
      56          10 :     unsigned long startTime = 0;
      57             : 
      58             :     constexpr static size_t BUFFER_LENGTH = 1024;
      59             : 
      60       10240 :     uint8_t buffer[BUFFER_LENGTH] = {};
      61          10 :     size_t index = 0;
      62             : 
      63             :     SerialMIDI_Parser parser;
      64             : 
      65             :     BLEMIDI bleMidi;
      66             : 
      67          10 :     uint8_t connected = 0;
      68             : 
      69           0 :     bool hasSpaceFor(size_t bytes) { return index + bytes < BUFFER_LENGTH; }
      70             : 
      71             :   public:
      72          20 :     BluetoothMIDI_Interface() : Parsing_MIDI_Interface(parser) {}
      73             : 
      74          10 :     void begin() override { bleMidi.begin(this, this); }
      75             : 
      76           0 :     void publish() {
      77           0 :         if (index == 0)
      78           0 :             return;
      79           0 :         if (!connected) {
      80           0 :             DEBUGFN("No connected BLE clients");
      81           0 :             return;
      82             :         }
      83           0 :         bleMidi.notifyValue(buffer, index);
      84           0 :         index = 0;
      85           0 :     }
      86             : 
      87           0 :     MIDI_read_t read() override {
      88           0 :         update();          // TODO
      89           0 :         return NO_MESSAGE; // TODO
      90             :     }
      91             : 
      92             :     template <size_t N>
      93           0 :     void addToBuffer(const uint8_t (&data)[N]) {
      94           0 :         addToBuffer(&data[0], N);
      95           0 :     }
      96             : 
      97           0 :     void addToBuffer(const uint8_t *data, size_t len) {
      98           0 :         bool first = index == 0;
      99           0 :         if (!hasSpaceFor(len + 1 + first)) { // TODO
     100           0 :             DEBUGFN("Buffer full");
     101           0 :             publish();
     102           0 :             if (!hasSpaceFor(len + 1 + first)) { // TODO
     103           0 :                 DEBUGFN("Message is larger than buffer");
     104           0 :                 return;
     105             :             }
     106           0 :         }
     107             : 
     108           0 :         if (first)
     109           0 :             startTime = micros();
     110             : 
     111           0 :         if (first)
     112           0 :             buffer[index++] = 0x80; // header / timestamp msb
     113           0 :         buffer[index++] = 0x80;     // timestamp lsb
     114           0 :         memcpy(&buffer[index], data, len);
     115           0 :         index += len;
     116             : 
     117           0 :         update();
     118           0 :     }
     119             : 
     120           0 :     void update() override {
     121           0 :         if (micros() - startTime >= MAX_MESSAGE_TIME)
     122           0 :             publish();
     123           0 :     }
     124             : 
     125           0 :     void sendImpl(uint8_t m, uint8_t c, uint8_t d1, uint8_t d2,
     126             :                   uint8_t cn) override {
     127             :         (void)cn;
     128           0 :         uint8_t msg[3] = {uint8_t(m | c), d1, d2};
     129           0 :         addToBuffer(msg);
     130           0 :     }
     131           0 :     void sendImpl(uint8_t m, uint8_t c, uint8_t d1, uint8_t cn) override {
     132             :         (void)cn;
     133           0 :         uint8_t msg[2] = {uint8_t(m | c), d1};
     134           0 :         addToBuffer(msg);
     135           0 :     }
     136             : 
     137           0 :     void sendImpl(const uint8_t *data, size_t length, uint8_t cn) override {
     138             :         (void)data;
     139             :         (void)length;
     140             :         (void)cn; // TODO
     141           0 :     }
     142             : 
     143           0 :     void sendImpl(uint8_t rt, uint8_t cn) override {
     144             :         (void)rt;
     145             :         (void)cn; // TODO
     146           0 :     }
     147             : 
     148          10 :     void parse(const uint8_t *const data, const size_t len) {
     149          10 :         if (len <= 1)
     150           0 :             return;
     151          10 :         if (MIDI_Parser::isData(data[0]))
     152           0 :             return;
     153          10 :         if (MIDI_Parser::isData(data[1]))
     154           1 :             parse(data[1]);
     155          10 :         bool prevWasTimestamp = true;
     156          84 :         for (const uint8_t *d = data + 2; d < data + len; d++) {
     157          74 :             if (MIDI_Parser::isData(*d)) {
     158          39 :                 parse(*d);
     159          39 :                 prevWasTimestamp = false;
     160          39 :             } else {
     161          35 :                 if (prevWasTimestamp)
     162          21 :                     parse(*d);
     163          35 :                 prevWasTimestamp = !prevWasTimestamp;
     164             :             }
     165          74 :         }
     166          10 :     }
     167             : 
     168          61 :     void parse(uint8_t data) {
     169          61 :         MIDI_read_t event = parser.parse(data);
     170          61 :         dispatchMIDIEvent(event);
     171          61 :     }
     172             : 
     173          10 :     BLEMIDI &getBLEMIDI() { return bleMidi; }
     174             : };
     175             : 
     176             : END_CS_NAMESPACE

Generated by: LCOV version 1.14-5-g4ff2ed6