1#if defined(ARDUINO_ARCH_MBED) && !defined(ARDUINO_ARCH_MBED_RP2040)
3#include "PluggableUSBMIDI.hpp"
11#define CS_MIDI_USB_ASSERT(a) MBED_ASSERT((a))
13#define CS_MIDI_USB_ASSERT(a) (void)(a)
16constexpr static auto mo_rel = std::memory_order_release;
17constexpr static auto mo_acq = std::memory_order_acquire;
18constexpr static auto mo_rlx = std::memory_order_relaxed;
19constexpr static auto mo_acq_rel = std::memory_order_acq_rel;
26 PluggableUSBD().plug(
this);
36 CS_MIDI_USB_ASSERT(resolver.valid());
45 usb_connected.store(new_state == USBDevice::Configured, mo_rlx);
49 USBDevice::RequestResult *result,
52 *result = USBDevice::PassThrough;
66 PluggableUSBD().endpoint_add(
69 PluggableUSBD().endpoint_add(
103 const uint32_t *end = msgs + num_msgs;
110 uint32_t total_sent = 0, sent = 1;
111 while (total_sent < num_msgs && sent != 0) {
112 sent =
write_impl(msgs + total_sent, num_msgs - total_sent,
true);
119 uint32_t active_idx, size;
177std::tuple<uint32_t, PluggableUSBMIDI::wbuffer_t *, uint32_t>
185 size = writebuffer->
size.load(mo_acq);
190 uint32_t old_idx = active_idx;
192 if (old_idx != active_idx) {
194 size = writebuffer->
size.load(mo_acq);
198 return std::make_tuple(active_idx, writebuffer, size);
218 auto old_idx = active_idx;
223 CS_MIDI_USB_ASSERT(old_idx != active_idx);
224 CS_MIDI_USB_ASSERT(size == 0);
231 CS_MIDI_USB_ASSERT(free_size % 4 == 0);
232 memcpy(&writebuf->buffer[size], msgs, free_size);
233 uint32_t newsize = size + free_size;
236 while (!writebuf->size.compare_exchange_weak(size, newsize, mo_rel)) {
247 memcpy(&writebuf->buffer[size], msgs, free_size);
248 newsize = size + free_size;
257 else if (size == 0) {
259 CS_MIDI_USB_ASSERT(old ==
nullptr);
260 std::atomic_signal_fence(mo_rel);
267 return free_size / 4u;
273 if (old_timeout !=
nullptr)
279 bool old_ready = writebuffer->
ready_to_send.exchange(
true, mo_rlx);
288 if (!
writing.
sending.compare_exchange_strong(send, writebuffer, mo_acq))
299 uint32_t size = writebuffer->size.exchange(
SizeReserved, mo_acq_rel);
301 CS_MIDI_USB_ASSERT(size != 0);
316 CS_MIDI_USB_ASSERT(size != 0);
323 std::atomic_signal_fence(mo_acq);
332 bool old_ready = sendbuffer->
ready_to_send.exchange(
true, mo_rlx);
339 if (!
writing.
sending.compare_exchange_strong(expected, sendbuffer, mo_acq))
357 std::atomic_signal_fence(mo_rel);
363 std::atomic_signal_fence(mo_acq);
373 uint32_t next_idx = !sent_idx;
386 CS_MIDI_USB_ASSERT(old_sending ==
nullptr);
390 sent->ready_to_send.store(
false, mo_rlx);
391 uint32_t oldsize = sent->size.exchange(0, mo_rel);
402 sent->ready_to_send.store(
false, mo_rlx);
403 uint32_t oldsize = sent->size.exchange(0, mo_rel);
422 memcpy(&data, &readbuffer.buffer[readbuffer.index], 4);
424 readbuffer.index += 4;
426 if (readbuffer.index == readbuffer.size) {
447 uint32_t num_bytes_read = read_finish(
bulk_out_ep);
448 CS_MIDI_USB_ASSERT(num_bytes_read % 4 == 0);
452 if (num_bytes_read == 0) {
459 writebuffer.
index = 0;
460 writebuffer.size = num_bytes_read;
#define BEGIN_CS_NAMESPACE
static constexpr uint32_t NumRxPackets
static constexpr uint32_t PacketSize
USB packet size.
Reading::Buffer rbuffer_t
uint32_t active_writebuffer
The index of the buffer that is currently being written to.
bool ready_to_send
Indicates that this buffer can be sent as soon as the previous one has been sent.
void send_in_callback(uint32_t activebuf_idx)
static constexpr uint32_t SizeReserved
struct PluggableUSBMIDI::Reading reading
struct PluggableUSBMIDI::Writing writing
uint32_t write_nonblock(const uint32_t *msgs, uint32_t num_msgs)
Send multiple MIDI USB messages without blocking.
Writing::Buffer wbuffer_t
uint32_t read()
Try reading a 4-byte MIDI USB message.
void callback_state_change(DeviceState new_state) override
void send_now()
Try sending the buffered data now.
void write_start_sync(uint8_t *buffer, uint32_t size)
uint8_t buffer[PacketSize]
Buffer * send_timeout
Buffer to be sent in the timeout callback.
microseconds timeout_duration
void callback_set_interface(uint16_t interface, uint8_t alternate) override
uint32_t write_impl(const uint32_t *msgs, uint32_t num_msgs, bool nonblocking)
Buffer * sending
Buffer that is being sent.
bool callback_set_configuration(uint8_t configuration) override
bool connected() const
Check if this class is connected and ready.
void init(EndpointResolver &resolver) override
struct PluggableUSBMIDI::Reading::Buffer buffers[NumRxPackets]
std::tuple< uint32_t, wbuffer_t *, uint32_t > read_writebuf_size()
std::atomic< bool > usb_connected
uint32_t size
How many bytes are in the buffer.
bool send_now_impl_nonblock(uint32_t activebuf_idx)
uint32_t callback_request(const setup_packet_t *setup, USBDevice::RequestResult *result, uint8_t **data) override
bool callback_request_xfer_done(const setup_packet_t *setup, bool aborted) override
struct PluggableUSBMIDI::Writing::Buffer buffers[2]
void write(uint32_t msg)
Send a MIDI USB message.
constexpr auto min(const T &a, const U &b) -> decltype(b< a ? b :a)
Return the smaller of two numbers/objects.