LCOV - code coverage report
Current view: top level - src/MIDI_Interfaces/BLEMIDI - BLEMIDIPacketBuilder.hpp (source / functions) Coverage Total Hit
Test: 73449d9b107c772cf65493691543348214e5d5eb Lines: 100.0 % 15 15
Test Date: 2026-06-06 17:44:35 Functions: 100.0 % 9 9
Legend: Lines:     hit not hit

            Line data    Source code
       1              : #pragma once
       2              : 
       3              : #include <MIDI_Parsers/MIDI_MessageTypes.hpp>
       4              : 
       5              : #include <AH/STL/vector>
       6              : 
       7              : BEGIN_CS_NAMESPACE
       8              : 
       9              : /// Class for building MIDI over Bluetooth Low Energy packets.
      10              : class BLEMIDIPacketBuilder {
      11              :   private:
      12              :     uint8_t runningHeader = 0;
      13              :     uint8_t runningTimestamp = 0;
      14              :     std::vector<uint8_t> buffer = std::vector<uint8_t>(0);
      15              : 
      16              :     constexpr static const uint8_t SysExStart =
      17              :         static_cast<uint8_t>(MIDIMessageType::SysExStart);
      18              :     constexpr static const uint8_t SysExEnd =
      19              :         static_cast<uint8_t>(MIDIMessageType::SysExEnd);
      20              : 
      21              :     /// Check if the buffer has space left.
      22          111 :     bool hasSpaceFor(size_t bytes) const {
      23          111 :         return bytes <= size_t(buffer.capacity() - buffer.size());
      24              :     }
      25              : 
      26              :     /// Timestamp[0]: 0b10hh hhhh
      27           71 :     constexpr static uint8_t getTimestampMSB(uint16_t timestamp) {
      28           71 :         return ((timestamp >> 7) & 0x3F) | 0x80;
      29              :     }
      30              :     /// Timestamp[1]: 0b1lll llll
      31           96 :     constexpr static uint8_t getTimestampLSB(uint16_t timestamp) {
      32           96 :         return timestamp | 0x80;
      33              :     }
      34              : 
      35              :     /// If this is the first byte/message in the packet, add the header
      36              :     /// containing the 6 most significant bits of the timestamp
      37          128 :     void initBuffer(uint16_t timestamp) {
      38          128 :         if (buffer.empty())
      39           71 :             buffer.push_back(getTimestampMSB(timestamp));
      40          128 :     }
      41              : 
      42              :     /** 
      43              :      * @brief   Try adding a 2-byte or 3-byte MIDI channel voice message to the
      44              :      *          packet.
      45              :      * 
      46              :      * @tparam  ThreeBytes 
      47              :      *          Set to `true` for a 3-byte message, `false` for a 2-byte message.
      48              :      * 
      49              :      * @param   header 
      50              :      *          MIDI status byte.
      51              :      * @param   data1 
      52              :      *          MIDI data byte 1.
      53              :      * @param   data2 
      54              :      *          MIDI data byte 2 (if `ThreeBytes == true`).
      55              :      * @param   timestamp 
      56              :      *          13-bit BLE-MIDI timestamp.
      57              :      * 
      58              :      * @retval  true
      59              :      *          Successfully added message to the packet.
      60              :      * @retval  false 
      61              :      *          Buffer is too full, send the current packet, reset the packet
      62              :      *          builder, and try again.
      63              :      */
      64              :     template <bool ThreeBytes>
      65              :     bool addImpl(uint8_t header, uint8_t data1, uint8_t data2,
      66              :                  uint16_t timestamp);
      67              : 
      68              :   public:
      69          198 :     BLEMIDIPacketBuilder(size_t capacity = 20) { buffer.reserve(capacity); }
      70              : 
      71              :     /// Reset the builder to start a new packet.
      72              :     void reset();
      73              : 
      74              :     /// Set the maximum capacity of the buffer. Set this to the MTU of the BLE
      75              :     /// link minus three bytes (for notify overhead).
      76              :     void setCapacity(uint16_t capacity);
      77              : 
      78              :     /// Get the size of the current packet.
      79           29 :     uint16_t getSize() const { return buffer.size(); }
      80              :     /// Get a pointer to the packet data buffer.
      81           22 :     const uint8_t *getBuffer() const { return buffer.data(); }
      82              :     /// Check if the packet buffer is empty.
      83          120 :     bool empty() const { return buffer.empty(); }
      84              : 
      85              :     /// Return the packet as a vector of bytes.
      86           50 :     const std::vector<uint8_t> &getPacket() const { return buffer; }
      87              : 
      88              :     /** 
      89              :      * @brief   Try adding a 3-byte MIDI channel voice message to the packet.
      90              :      * 
      91              :      * @param   header 
      92              :      *          MIDI status byte.
      93              :      * @param   data1 
      94              :      *          MIDI data byte 1.
      95              :      * @param   data2 
      96              :      *          MIDI data byte 2.
      97              :      * @param   timestamp 
      98              :      *          13-bit BLE-MIDI timestamp.
      99              :      * 
     100              :      * @retval  true
     101              :      *          Successfully added message to the packet.
     102              :      * @retval  false 
     103              :      *          Buffer is too full, send the current packet, reset the packet
     104              :      *          builder, and try again.
     105              :      */
     106              :     bool add3B(uint8_t header, uint8_t data1, uint8_t data2,
     107              :                uint16_t timestamp);
     108              : 
     109              :     /** 
     110              :      * @brief   Try adding a 2-byte MIDI channel voice message to the packet.
     111              :      * 
     112              :      * @param   header 
     113              :      *          MIDI status byte.
     114              :      * @param   data1 
     115              :      *          MIDI data byte 1.
     116              :      * @param   timestamp 
     117              :      *          13-bit BLE-MIDI timestamp.
     118              :      * 
     119              :      * @retval  true
     120              :      *          Successfully added message to the packet.
     121              :      * @retval  false 
     122              :      *          Buffer is too full, send the current packet, reset the packet
     123              :      *          builder, and try again.
     124              :      */
     125              :     bool add2B(uint8_t header, uint8_t data1, uint16_t timestamp);
     126              : 
     127              :     /** 
     128              :      * @brief   Try adding a MIDI real-time message to the packet.
     129              :      * 
     130              :      * @param   rt 
     131              :      *          MIDI real-time byte.
     132              :      * @param   timestamp 
     133              :      *          13-bit BLE-MIDI timestamp.
     134              :      * 
     135              :      * @retval  true
     136              :      *          Successfully added message to the packet.
     137              :      * @retval  false 
     138              :      *          Buffer is too full, send the current packet, reset the packet
     139              :      *          builder, and try again.
     140              :      */
     141              :     bool addRealTime(uint8_t rt, uint16_t timestamp);
     142              : 
     143              :     /** 
     144              :      * @brief   Try adding a MIDI system common message to the packet.
     145              :      * 
     146              :      * @param   num_data 
     147              :      *          The number of data bytes (0, 1 or 2).
     148              :      * @param   header
     149              :      *          System common status byte.
     150              :      * @param   data1 
     151              :      *          MIDI data byte 1.
     152              :      * @param   data2 
     153              :      *          MIDI data byte 2.
     154              :      * @param   timestamp 
     155              :      *          13-bit BLE-MIDI timestamp.
     156              :      * 
     157              :      * @retval  true
     158              :      *          Successfully added message to the packet.
     159              :      * @retval  false 
     160              :      *          Buffer is too full, send the current packet, reset the packet
     161              :      *          builder, and try again.
     162              :      */
     163              :     bool addSysCommon(uint8_t num_data, uint8_t header, uint8_t data1,
     164              :                       uint8_t data2, uint16_t timestamp);
     165              : 
     166              :     /**
     167              :      * @brief   Try adding (part of) a SysEx message to the packet.
     168              :      * 
     169              :      * @param[in,out]   data 
     170              :      *                  Pointer to the first byte of the SysEx message. 
     171              :      *                  At the end, this will point to the first byte to 
     172              :      *                  send in the next packet, or `nullptr` if the message was
     173              :      *                  finished.
     174              :      * @param[in,out]   length 
     175              :      *                  The number of bytes in the SysEx message. 
     176              :      *                  At the end, this will be set to remaining number of
     177              :      *                  bytes to send in the next packet.
     178              :      * @param[in]       timestamp 
     179              :      *                  13-bit BLE-MIDI timestamp.
     180              :      * 
     181              :      * @retval  true
     182              :      *          Successfully added (part of) the message to the packet.
     183              :      * @retval  false 
     184              :      *          Buffer is too full, send the current packet, reset the packet
     185              :      *          builder, and try again.
     186              :      * 
     187              :      * If the message fits in a single packet, `length` is set to `0` (no
     188              :      * remaining data bytes) and `data` is set to `nullptr`.
     189              :      * 
     190              :      * For example:
     191              :      * ~~~cpp
     192              :      * BLEMIDIPacketBuilder packetbuilder;
     193              :      * 
     194              :      * const uint8_t *data = (...);
     195              :      * size_t length = (...);
     196              :      * uint16_t timestamp = (...);
     197              :      * 
     198              :      * if (!packetbuilder.addSysEx(data, length, timestamp)) {
     199              :      *     sendnow(packetbuilder.getBuffer(), packetbuilder.getSize());
     200              :      *     packetbuilder.reset();
     201              :      *     packetbuilder.addSysEx(data, length, timestamp)
     202              :      * }
     203              :      * while (data) {
     204              :      *     sendnow(packetbuilder.getBuffer(), packetbuilder.getSize());
     205              :      *     packetbuilder.reset();
     206              :      *     packetbuilder.continueSysEx(data, length, timestamp);
     207              :      * }
     208              :      * ~~~
     209              :      */
     210              :     bool addSysEx(const uint8_t *&data, size_t &length, uint16_t timestamp);
     211              : 
     212              :     /**
     213              :      * @brief   Add a SysEx continuation to the packet.
     214              :      * 
     215              :      * @param[in,out]   data 
     216              :      *                  Pointer to the first byte of the SysEx message to send
     217              :      *                  in this continuation packet.
     218              :      *                  At the end, this will point to the first byte to send in
     219              :      *                  the next packet, or `nullptr` if the message was
     220              :      *                  finished.
     221              :      * @param[in,out]   length 
     222              :      *                  The number of remaining bytes in the SysEx message. 
     223              :      *                  At the end, this will be set to remaining number of
     224              :      *                  bytes to send in the next packet.
     225              :      * @param[in]       timestamp 
     226              :      *                  13-bit BLE-MIDI timestamp.
     227              :      * 
     228              :      * If the message can be completed in a single packet, `length` is set to 
     229              :      * `0` (no remaining data bytes) and `data` is set to `nullptr`.
     230              :      * 
     231              :      * @see @ref addSysEx()
     232              :      */
     233              :     void continueSysEx(const uint8_t *&data, size_t &length,
     234              :                        uint16_t timestamp);
     235              : };
     236              : 
     237              : END_CS_NAMESPACE
        

Generated by: LCOV version 2.4-beta