LCOV - code coverage report
Current view: top level - src/MIDI_Interfaces/BLEMIDI - ThreadedBLEMIDISender.ipp (source / functions) Hit Total Coverage
Test: 169c36a3797bc662d84b5726f34a3f37d3c58247 Lines: 61 63 96.8 %
Date: 2024-11-09 15:32:27 Functions: 13 13 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #include "ThreadedBLEMIDISender.hpp"
       2             : 
       3             : #include <AH/Containers/CRTP.hpp>
       4             : 
       5             : BEGIN_CS_NAMESPACE
       6             : 
       7             : template <class Derived>
       8          29 : ThreadedBLEMIDISender<Derived>::~ThreadedBLEMIDISender() {
       9          29 :     lock_t lck(shared.mtx);
      10             :     // Tell the sender that this is the last packet
      11          29 :     shared.stop = true;
      12             :     // Tell the sender to not to wait for the timeout
      13          29 :     shared.flush = true;
      14          29 :     lck.unlock();
      15          29 :     cv.notify_one();
      16             :     // Wait for it to be sent, and join the thread when done
      17          29 :     if (send_thread.joinable())
      18          28 :         send_thread.join();
      19          58 : }
      20             : 
      21             : template <class Derived>
      22          28 : void ThreadedBLEMIDISender<Derived>::begin() {
      23          78 :     send_thread = std::thread([this] {
      24             :         // As long as you didn't get the stop signal, wait for data to send
      25          78 :         while (handleSendEvents())
      26             :             ; // loop
      27             :     });
      28          28 : }
      29             : 
      30             : template <class Derived>
      31          40 : auto ThreadedBLEMIDISender<Derived>::acquirePacket() -> ProtectedBuilder {
      32          40 :     return {&shared.packet, lock_t {shared.mtx}};
      33             : }
      34             : 
      35             : template <class Derived>
      36          21 : void ThreadedBLEMIDISender<Derived>::releasePacketAndNotify(
      37             :     ProtectedBuilder &lck) {
      38          21 :     lck.lck.unlock();
      39          21 :     cv.notify_one();
      40          21 : }
      41             : 
      42             : template <class Derived>
      43          21 : void ThreadedBLEMIDISender<Derived>::sendNow(ProtectedBuilder &lck) {
      44          21 :     assert(lck.lck.owns_lock());
      45             :     // No need to send empty packets
      46          21 :     if (shared.packet.empty())
      47           0 :         return;
      48             : 
      49             :     // Tell the background sender thread to send the packet now
      50          21 :     shared.flush = true;
      51          21 :     lck.lck.unlock();
      52          21 :     cv.notify_one();
      53             : 
      54             :     // Wait for flush to complete (when the sender clears the flush flag)
      55          21 :     lck.lck.lock();
      56          63 :     cv.wait(lck.lck, [this] { return !shared.flush; });
      57             : }
      58             : 
      59             : template <class Derived>
      60           7 : void ThreadedBLEMIDISender<Derived>::updateMTU(uint16_t mtu) {
      61           7 :     uint16_t force_min_mtu_c = force_min_mtu;
      62           7 :     if (force_min_mtu_c == 0)
      63           0 :         min_mtu = mtu;
      64             :     else
      65           7 :         min_mtu = std::min(force_min_mtu_c, mtu);
      66             :     DEBUGFN(NAMEDVALUE(min_mtu));
      67           7 :     auto lck = acquirePacket();
      68           7 :     if (lck.packet->getSize() == 0)
      69           7 :         lck.packet->setCapacity(min_mtu - 3);
      70          14 : }
      71             : 
      72             : template <class Derived>
      73           7 : void ThreadedBLEMIDISender<Derived>::forceMinMTU(uint16_t mtu) {
      74           7 :     force_min_mtu = mtu;
      75           7 :     updateMTU(min_mtu);
      76           7 : }
      77             : 
      78             : template <class Derived>
      79           3 : void ThreadedBLEMIDISender<Derived>::setTimeout(
      80             :     std::chrono::milliseconds timeout) {
      81           3 :     lock_t lck(shared.mtx);
      82           3 :     shared.timeout = timeout;
      83           6 : }
      84             : 
      85             : template <class Derived>
      86          50 : bool ThreadedBLEMIDISender<Derived>::handleSendEvents() {
      87          50 :     lock_t lck(shared.mtx);
      88             : 
      89             :     // Wait for a packet to be started (or for a stop signal)
      90         150 :     cv.wait(lck, [this] { return !shared.packet.empty() || shared.stop; });
      91             :     // Wait for flush signal or timeout.
      92          50 :     auto timeout = shared.timeout;
      93         110 :     cv.wait_for(lck, timeout, [this] { return shared.flush; });
      94             : 
      95             :     // Stop this thread
      96          50 :     if (shared.stop)
      97          28 :         return false;
      98             :     // Note: do not send anything in this case, because we might be in the base
      99             :     // class destructor, and the subclass implementing the sendData function
     100             :     // might already be destroyed.
     101             : 
     102             :     // Send the packet over BLE, empty the buffer, and update the buffer
     103             :     // size based on the MTU of the connected clients.
     104          22 :     BLEDataView data {shared.packet.getBuffer(), shared.packet.getSize()};
     105          22 :     if (data.length > 0)
     106          22 :         CRTP(Derived).sendData(data);
     107          22 :     shared.packet.reset();
     108          22 :     shared.packet.setCapacity(min_mtu - 3);
     109             :     // Note: the MTU may have been reduced asynchronously, in which case the
     110             :     // sending of the data may fail, or it may be truncated. However, since
     111             :     // updating the MTU while a transmission is already going on is rare, we
     112             :     // don't handle this case, as it would require parsing and re-encoding the
     113             :     // buffer into two or more packets.
     114             : 
     115             :     // Notify the main thread that the flush was done.
     116          22 :     if (shared.flush) {
     117          21 :         shared.flush = false;
     118          21 :         lck.unlock();
     119          21 :         cv.notify_one();
     120             :     }
     121          22 :     return true;
     122          50 : }
     123             : 
     124             : END_CS_NAMESPACE

Generated by: LCOV version 1.15