Line data Source code
1 : #pragma once 2 : 3 : #include <cstddef> 4 : 5 : #include <MIDI_Interfaces/USBMIDI/util/Atomic.hpp> 6 : #include <Settings/NamespaceSettings.hpp> 7 : 8 : BEGIN_CS_NAMESPACE 9 : 10 : /// Sends Bulk packets (IN for device mode, OUT for host mode) 11 : template <class Derived, class MessageTypeT, uint16_t MaxPacketSizeV> 12 : struct BulkTX { 13 : public: 14 : using MessageType = MessageTypeT; 15 : 16 : /// Send a MIDI USB message. May block. 17 : /// 18 : /// @param msg 19 : /// The 4-byte MIDI USB message to send. 20 : void write(MessageType msg); 21 : 22 : /// Send multiple MIDI USB messages. May block. 23 : /// 24 : /// @param msgs 25 : /// An array of 4-byte MIDI USB messages to send. 26 : /// @param num_msgs 27 : /// The number of messages in the array. 28 : void write(const MessageType *msgs, uint32_t num_msgs); 29 : 30 : /// Send multiple MIDI USB messages. May block. 31 : template <size_t N> 32 : void write(const MessageType (&msgs)[N]) { 33 : write(msgs, N); 34 : } 35 : 36 : /// Send multiple MIDI USB messages without blocking. 37 : /// 38 : /// @param msgs 39 : /// An array of 4-byte MIDI USB messages to send. 40 : /// @param num_msgs 41 : /// The number of messages in the array. 42 : /// @return The number of messages that were actually sent. 43 : uint32_t write_nonblock(const MessageType *msgs, uint32_t num_msgs); 44 : 45 : /// Try sending the buffered data now. 46 : /// Start transmitting the latest packet if possible, even if it isn't full 47 : /// yet. If the latest packet is empty, this function has no effect. 48 : void send_now(); 49 : 50 : /// Check if all transfers have completed. 51 : bool is_done() const; 52 : 53 : /// Get the number messages that failed to send. 54 : uint32_t getWriteError() const { return writing.error.load(mo_rlx); } 55 : /// Get and clear the number messages that failed to send. 56 : uint32_t clearWriteError() { return writing.error.exchange(0, mo_rlx); } 57 : 58 : protected: 59 : void reset(uint16_t packet_size = MaxPacketSize); 60 : bool wait_connect(); 61 : 62 : private: 63 : static constexpr uint16_t MaxPacketSize = MaxPacketSizeV; 64 : static constexpr uint16_t SizeReserved = MaxPacketSize + 1; 65 : 66 : protected: 67 : // Derived should implement the following methods: 68 : 69 : /// Start a timeout (e.g. using a timer interrupt) that later calls 70 : /// @ref timeout_callback(). 71 : void start_timeout() = delete; 72 : /// Cancel the timeout started by @ref timeout_callback(). 73 : void cancel_timeout() = delete; 74 : /// Start a USB transfer (from the main program). 75 : void tx_start(const void *data, uint32_t size) = delete; 76 : /// Start a USB transfer (from the timeout callback). 77 : void tx_start_timeout(const void *data, uint32_t size) = delete; 78 : /// Start a USB transfer (from the USB interrupt handler). 79 : void tx_start_isr(const void *data, uint32_t size) = delete; 80 : 81 : private: 82 : constexpr static std::memory_order mo_seq = std::memory_order_seq_cst; 83 : constexpr static std::memory_order mo_rel = std::memory_order_release; 84 : constexpr static std::memory_order mo_acq = std::memory_order_acquire; 85 : constexpr static std::memory_order mo_rlx = std::memory_order_relaxed; 86 : constexpr static std::memory_order mo_acq_rel = std::memory_order_acq_rel; 87 : 88 : /// State for writing outgoing USB-MIDI data. 89 : struct Writing { 90 : struct Buffer { 91 : uint16_t size {0}; 92 : alignas(MessageType) uint8_t buffer[MaxPacketSize]; 93 : } buffers[2]; 94 : interrupt_atomic<Buffer *> active_writebuffer {&buffers[0]}; 95 : interrupt_atomic<Buffer *> sending {nullptr}; 96 : interrupt_atomic<Buffer *> send_later {nullptr}; 97 : interrupt_atomic<Buffer *> send_now {nullptr}; 98 : interrupt_atomic<uint32_t> error {0}; 99 : uint16_t packet_size = MaxPacketSize; 100 : } writing; 101 : using wbuffer_t = typename Writing::Buffer; 102 : bool disconnected = false; 103 : 104 94934 : uint32_t index_of(wbuffer_t *p) const { return p - writing.buffers; } 105 94934 : wbuffer_t *other_buf(wbuffer_t *p) { 106 94934 : return &writing.buffers[!index_of(p)]; 107 : } 108 : uint32_t write_impl(const MessageType *msgs, uint32_t num_msgs); 109 : 110 : protected: 111 : void timeout_callback(); 112 : void tx_callback(); 113 : }; 114 : 115 : END_CS_NAMESPACE 116 : 117 : #include "BulkTX.ipp"