LCOV - code coverage report
Current view: top level - src/MIDI_Interfaces/BLEMIDI - BLEMIDIPacketBuilder.cpp (source / functions) Hit Total Coverage
Test: b8a30b4b7040ae1abf162fd0a258beaa2de43626 Lines: 94 94 100.0 %
Date: 2024-12-21 21:28:55 Functions: 10 10 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "BLEMIDIPacketBuilder.hpp"
       2             : 
       3             : BEGIN_CS_NAMESPACE
       4             : 
       5             : template <bool ThreeBytes>
       6          56 : bool BLEMIDIPacketBuilder::addImpl(uint8_t header, uint8_t data1, uint8_t data2,
       7             :                                    uint16_t timestamp) {
       8          56 :     initBuffer(timestamp);
       9             : 
      10          56 :     uint8_t timestampLSB = getTimestampLSB(timestamp);
      11             : 
      12             :     // If the header is the same as the previous message, use running status
      13          56 :     if (header == runningHeader) {
      14             :         // If the timestamp is the same, no need to send it again
      15          17 :         if (timestampLSB == runningTimestamp) {
      16           9 :             if (!hasSpaceFor(1 + ThreeBytes))
      17           1 :                 return false; // Buffer full
      18           8 :             buffer.push_back(data1);
      19             :             if (ThreeBytes)
      20           8 :                 buffer.push_back(data2);
      21             :         }
      22             :         // Timestamp is different, send again
      23             :         else {
      24           8 :             if (!hasSpaceFor(2 + ThreeBytes))
      25           1 :                 return false; // Buffer full
      26           7 :             runningTimestamp = timestampLSB;
      27           7 :             buffer.push_back(timestampLSB);
      28           7 :             buffer.push_back(data1);
      29             :             if (ThreeBytes)
      30           7 :                 buffer.push_back(data2);
      31             :         }
      32             :     }
      33             :     // If the header is different, running status is not possible, send all
      34             :     else {
      35          39 :         if (!hasSpaceFor(3 + ThreeBytes))
      36           3 :             return false; // Buffer full
      37          36 :         runningHeader = header;
      38          36 :         runningTimestamp = timestampLSB;
      39          36 :         buffer.push_back(timestampLSB);
      40          36 :         buffer.push_back(header);
      41          36 :         buffer.push_back(data1);
      42             :         if (ThreeBytes)
      43          32 :             buffer.push_back(data2);
      44             :     }
      45          51 :     return true;
      46             : }
      47             : 
      48          34 : void BLEMIDIPacketBuilder::reset() {
      49          34 :     buffer.resize(0);
      50          34 :     runningHeader = 0;
      51          34 : }
      52             : 
      53          56 : void BLEMIDIPacketBuilder::setCapacity(uint16_t capacity) {
      54          56 :     if (capacity < 5)
      55             :         ERROR(F("capacity less than 5 bytes"), 0x2005); // LCOV_EXCL_LINE
      56          56 :     buffer.shrink_to_fit();
      57          56 :     buffer.reserve(capacity);
      58          56 : }
      59             : 
      60          51 : bool BLEMIDIPacketBuilder::add3B(uint8_t header, uint8_t data1, uint8_t data2,
      61             :                                  uint16_t timestamp) {
      62          51 :     constexpr bool ThreeBytes = true;
      63          51 :     return addImpl<ThreeBytes>(header, data1, data2, timestamp);
      64             : }
      65             : 
      66           5 : bool BLEMIDIPacketBuilder::add2B(uint8_t header, uint8_t data1,
      67             :                                  uint16_t timestamp) {
      68           5 :     constexpr bool ThreeBytes = false;
      69           5 :     return addImpl<ThreeBytes>(header, data1, 0, timestamp);
      70             : }
      71             : 
      72          10 : bool BLEMIDIPacketBuilder::addRealTime(uint8_t rt, uint16_t timestamp) {
      73          10 :     initBuffer(timestamp);
      74             : 
      75          10 :     if (!hasSpaceFor(2))
      76           3 :         return false; // Buffer full
      77             : 
      78           7 :     buffer.push_back(getTimestampLSB(timestamp));
      79           7 :     buffer.push_back(rt);
      80           7 :     runningTimestamp = 0; // Re-send the timestamp next time
      81             : 
      82           7 :     return true;
      83             : }
      84             : 
      85          10 : bool BLEMIDIPacketBuilder::addSysCommon(uint8_t num_data, uint8_t header,
      86             :                                         uint8_t data1, uint8_t data2,
      87             :                                         uint16_t timestamp) {
      88          10 :     initBuffer(timestamp);
      89             : 
      90          10 :     uint8_t timestampLSB = getTimestampLSB(timestamp);
      91             : 
      92          10 :     if (!hasSpaceFor(2 + num_data))
      93           3 :         return false; // Buffer full
      94           7 :     buffer.push_back(timestampLSB);
      95           7 :     buffer.push_back(header);
      96           7 :     if (num_data >= 1)
      97           5 :         buffer.push_back(data1);
      98           7 :     if (num_data >= 2)
      99           3 :         buffer.push_back(data2);
     100           7 :     runningTimestamp = 0; // Re-send the timestamp next time
     101             : 
     102           7 :     return true;
     103             : }
     104             : 
     105          20 : bool BLEMIDIPacketBuilder::addSysEx(const uint8_t *&data, size_t &length,
     106             :                                     uint16_t timestamp) {
     107          20 :     initBuffer(timestamp);
     108             : 
     109             :     // We can't do anything with an empty message
     110          20 :     if (length == 0)
     111           1 :         return true;
     112             : 
     113             :     // If the first byte is a SysExStart byte we first have to write a
     114             :     // timestamp + SysExStart.
     115          19 :     if (*data == SysExStart) {
     116             :         // We need space for at least the timestamp and a SysExStart
     117          14 :         if (!hasSpaceFor(2))
     118           3 :             return false; // Buffer full
     119             : 
     120             :         // Normal running status is interrupted by SysEx
     121          11 :         runningHeader = 0;
     122             : 
     123          11 :         const uint8_t timestampLSB = getTimestampLSB(timestamp);
     124             : 
     125             :         // Start of SysEx
     126          11 :         buffer.push_back(timestampLSB);
     127          11 :         buffer.push_back(SysExStart);
     128          11 :         ++data; // First byte was added
     129          11 :         --length;
     130             :     }
     131             : 
     132             :     // Copy the rest of the data, and terminate the message if necessary
     133          16 :     continueSysEx(data, length, timestamp);
     134          16 :     return true;
     135             : }
     136             : 
     137          32 : void BLEMIDIPacketBuilder::continueSysEx(const uint8_t *&data, size_t &length,
     138             :                                          uint16_t timestamp) {
     139          32 :     initBuffer(timestamp);
     140             : 
     141          32 :     if (length == 0) {
     142             :         // Message was finished, no continuation
     143           1 :         data = nullptr;
     144           1 :         return;
     145             :     }
     146             : 
     147             :     // Copy as much data as possible, but stop before the last byte, which
     148             :     // could be a SysExEnd (and should be handled differently than data bytes)
     149         102 :     while (length-- > 1 && buffer.size() < buffer.capacity())
     150          71 :         buffer.push_back(*data++);
     151             : 
     152             :     // If everything fit into the buffer
     153          31 :     if (length == 0) {
     154             :         // End of SysEx
     155          21 :         if (*data == SysExEnd) {
     156          17 :             if (hasSpaceFor(2)) {
     157          12 :                 buffer.push_back(getTimestampLSB(timestamp));
     158          12 :                 buffer.push_back(SysExEnd);
     159             :                 // Message was finished, no continuation
     160          12 :                 data = nullptr;
     161             :             } else {
     162             :                 // Send the SysExEnd byte next time
     163           5 :                 ++length;
     164             :             }
     165             :         }
     166             :         // End of chunk but not end of SysEx
     167             :         else {
     168           4 :             if (hasSpaceFor(1)) {
     169           3 :                 buffer.push_back(*data);
     170             :                 // Message was finished, no continuation
     171           3 :                 data = nullptr;
     172             :             } else {
     173             :                 // Send the last byte next time
     174           1 :                 ++length;
     175             :             }
     176             :         }
     177             :     }
     178             :     // If the while loop stopped because the buffer was full
     179             :     else {
     180             :         // data is not set to nullptr to let the caller know where to start
     181             :         // sending the next continuation packet,
     182          10 :         ++length;
     183             :     }
     184             : }
     185             : 
     186             : constexpr const uint8_t BLEMIDIPacketBuilder::SysExStart;
     187             : constexpr const uint8_t BLEMIDIPacketBuilder::SysExEnd;
     188             : 
     189             : END_CS_NAMESPACE

Generated by: LCOV version 1.15