Control Surface pin-t-adl
MIDI Control Surface library for Arduino
mbed/PluggableUSBMIDI.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <atomic>
6#include <cstdint>
7#include <tuple>
8
9#include <USB/PluggableUSBDevice.h>
10#include <drivers/Timeout.h>
11#include <platform/Callback.h>
12
14#include <Settings/NamespaceSettings.hpp>
15
17
18class PluggableUSBMIDI : protected arduino::internal::PluggableUSBModule {
19 public:
22
23 public:
24 using setup_packet_t = USBDevice::setup_packet_t;
25 using DeviceState = USBDevice::DeviceState;
26 using microseconds = std::chrono::microseconds;
27
28 public:
30 bool connected() const;
31
36 void write(uint32_t msg);
37
44 void write(const uint32_t *msgs, uint32_t num_msgs);
45
47 template <size_t N>
48 void write(const uint32_t (&msgs)[N]) {
49 write(msgs, N);
50 }
51
59 uint32_t write_nonblock(const uint32_t *msgs, uint32_t num_msgs);
60
64 uint32_t read();
65
69 void send_now();
70
74 void setTimeout(microseconds timeout) {
75 writing.timeout_duration = timeout;
76 }
80 }
81
83 uint32_t getWriteError() const { return writing.errors; }
86
87 protected:
88 void init(EndpointResolver &resolver) override;
89 void callback_state_change(DeviceState new_state) override;
90 uint32_t callback_request(const setup_packet_t *setup,
91 USBDevice::RequestResult *result,
92 uint8_t **data) override;
94 bool aborted) override;
95 bool callback_set_configuration(uint8_t configuration) override;
96 void callback_set_interface(uint16_t interface, uint8_t alternate) override;
97
98 const uint8_t *string_iinterface_desc() override;
99 const uint8_t *configuration_desc(uint8_t index) override;
100 uint8_t getProductVersion() override { return 16; }
101
102 protected:
103 std::atomic<bool> usb_connected{false};
104
105 public:
108 static constexpr uint32_t PacketSize = 64;
109
110 protected:
111 static constexpr uint32_t SizeReserved = PacketSize + 1;
112 static constexpr uint32_t NumRxPackets = 2;
113
115 struct Reading {
116 struct Buffer {
117 uint32_t size = 0;
118 uint32_t index = 0;
119 alignas(uint32_t) uint8_t buffer[PacketSize];
121 std::atomic<uint32_t> available{0};
122 std::atomic<uint32_t> read_idx{0};
123 std::atomic<uint32_t> write_idx{0};
124 std::atomic<bool> reading{false};
125 } reading;
126 using rbuffer_t = std::remove_reference_t<decltype(reading.buffers[0])>;
127
129 struct Writing {
130 struct Buffer {
131 std::atomic<uint32_t> size{0};
132 std::atomic<bool> ready_to_send{false};
133 alignas(uint32_t) uint8_t buffer[PacketSize];
134 } buffers[2];
135 std::atomic<uint32_t> active_writebuffer{0};
136 std::atomic<Buffer *> sending{nullptr};
137 std::atomic<Buffer *> send_timeout{nullptr};
140 mbed::Timeout timeout;
141 uint32_t errors{0};
142 } writing;
143 using wbuffer_t = std::remove_reference_t<decltype(writing.buffers[0])>;
144
145 usb_ep_t bulk_in_ep;
146 usb_ep_t bulk_out_ep;
147 uint8_t config_descriptor[0x65];
148
149 uint32_t write_impl(const uint32_t *msgs, uint32_t num_msgs,
150 bool nonblocking);
151 std::tuple<uint32_t, wbuffer_t *, uint32_t> read_writebuf_size();
152 void write_start_sync(uint8_t *buffer, uint32_t size);
153 void send_in_callback(uint32_t activebuf_idx);
154 bool send_now_impl_nonblock(uint32_t activebuf_idx);
158};
159
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
static constexpr uint32_t NumRxPackets
void write(const uint32_t(&msgs)[N])
Send multiple MIDI USB messages. May block.
static constexpr uint32_t PacketSize
USB packet size.
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 setErrorTimeout(microseconds timeout)
void send_in_callback(uint32_t activebuf_idx)
static constexpr uint32_t SizeReserved
struct PluggableUSBMIDI::Reading reading
USBDevice::setup_packet_t setup_packet_t
struct PluggableUSBMIDI::Writing writing
uint32_t write_nonblock(const uint32_t *msgs, uint32_t num_msgs)
Send multiple MIDI USB messages without blocking.
uint8_t getProductVersion() override
void timeout_callback()
USBDevice::DeviceState DeviceState
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)
Buffer * send_timeout
Buffer to be sent in the timeout callback.
uint32_t getWriteError() const
Count how many USB packets were dropped.
const uint8_t * configuration_desc(uint8_t index) override
void callback_set_interface(uint16_t interface, uint8_t alternate) override
void setTimeout(microseconds timeout)
Set the timeout, the number of microseconds to buffer the outgoing MIDI messages.
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]
void write(const uint32_t *msgs, uint32_t num_msgs)
Send multiple MIDI USB messages.
std::tuple< uint32_t, wbuffer_t *, uint32_t > read_writebuf_size()
std::atomic< bool > usb_connected
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
const uint8_t * string_iinterface_desc() override
struct PluggableUSBMIDI::Writing::Buffer buffers[2]
void write(uint32_t msg)
Send a MIDI USB message.
std::chrono::microseconds microseconds
void clearWriteError()
Clear the counter of how many USB packets were dropped.
State for writing outgoing USB-MIDI data.