LCOV - code coverage report
Current view: top level - src/MIDI_Interfaces/BLEMIDI - ThreadedBLEMIDISender.ipp (source / functions) Coverage Total Hit
Test: 73449d9b107c772cf65493691543348214e5d5eb Lines: 96.9 % 64 62
Test Date: 2026-06-06 17:44:35 Functions: 100.0 % 13 13
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           28 :     send_thread = std::thread([this] {
      24              :         // As long as you didn't get the stop signal, wait for data to send
      25           50 :         while (handleSendEvents())
      26              :             ; // loop
      27              :     });
      28           28 : }
      29              : 
      30              : template <class Derived>
      31           40 : auto ThreadedBLEMIDISender<Derived>::acquirePacket() -> ProtectedBuilder {
      32          120 :     return {&shared.packet, lock_t {shared.mtx}};
      33           80 : }
      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          149 :     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 2.4-beta