Control Surface pin-t-adl
MIDI Control Surface library for Arduino
TeensyHostMIDI.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <USBHost_t36.h>
4#include <atomic>
5#include <chrono>
6#include <tuple>
7
8#include <Settings/NamespaceSettings.hpp>
9
11
13template <uint16_t MaxPacketSize = 512>
14class TeensyHostMIDI : public USBDriver {
15 public:
16 TeensyHostMIDI(USBHost &host) { init(); }
17
18 using microseconds = std::chrono::microseconds;
19
24 void write(uint32_t msg);
25
32 void write(const uint32_t *msgs, uint32_t num_msgs);
33
35 template <size_t N>
36 void write(const uint32_t (&msgs)[N]) {
37 write(msgs, N);
38 }
39
47 uint32_t write_nonblock(const uint32_t *msgs, uint32_t num_msgs);
48
52 uint32_t read();
53
57 void send_now();
58
62 void setTimeout(microseconds timeout) {
63 writing.timeout_duration = timeout;
64 }
68 }
69
71 uint32_t getWriteError() const { return writing.errors; }
74
75 protected:
76 bool claim(Device_t *device, int type, const uint8_t *descriptors,
77 uint32_t len) override;
78 void disconnect() override;
79
80 protected:
81 void timer_event(USBDriverTimer *whichtimer) override;
82
83 protected:
84 static void rx_callback(const Transfer_t *transfer);
85 static void tx_callback(const Transfer_t *transfer);
86
87 protected:
88 void write_start(uint8_t *buffer, uint32_t size);
89 void write_start_isr(uint8_t *buffer, uint32_t size);
90 uint32_t write_finish(const Transfer_t *transfer);
91
92 void read_start(uint8_t *buffer, uint32_t size);
93 void read_start_isr(uint8_t *buffer, uint32_t size);
94 uint32_t read_finish(const Transfer_t *transfer);
95
96 protected:
97 bool claim_if_midi(Device_t *device, int type, const uint8_t *descriptors,
98 uint32_t len);
99 void init();
100
101 private:
102 Pipe_t *rxpipe;
103 Pipe_t *txpipe;
104 uint16_t rx_size;
105 uint16_t tx_size;
106 uint8_t rx_ep;
107 uint8_t tx_ep;
108 uint8_t rx_ep_type;
109 uint8_t tx_ep_type;
110 Pipe_t mypipes[3] __attribute__((aligned(32)));
111 Transfer_t mytransfers[7] __attribute__((aligned(32)));
112 strbuf_t mystring_bufs[1];
113
114 public:
116 static constexpr uint32_t PacketSize = MaxPacketSize;
117
118 protected:
119 static constexpr uint32_t SizeReserved = PacketSize + 1;
120 static constexpr uint32_t NumRxPackets = 2;
121
123 struct Reading {
124 struct Buffer {
125 uint32_t size = 0;
126 uint32_t index = 0;
127 alignas(uint32_t) uint8_t buffer[PacketSize];
129 std::atomic<uint32_t> available{0};
130 std::atomic<uint32_t> read_idx{0};
131 std::atomic<uint32_t> write_idx{0};
132 std::atomic<bool> reading{false};
134 using rbuffer_t = typename Reading::Buffer;
135
137 struct Writing {
138 struct Buffer {
139 std::atomic<uint32_t> size{0};
140 std::atomic<bool> ready_to_send{false};
141 alignas(uint32_t) uint8_t buffer[PacketSize];
143 std::atomic<uint32_t> active_writebuffer{0};
144 std::atomic<Buffer *> sending{nullptr};
145 std::atomic<Buffer *> send_timeout{nullptr};
148 uint32_t errors{0};
150 using wbuffer_t = typename Writing::Buffer;
151 USBDriverTimer write_timeout{this};
152
153 protected:
154 uint32_t write_impl(const uint32_t *msgs, uint32_t num_msgs,
155 bool nonblocking);
156 using writebuf_size_tup = std::tuple<uint32_t, wbuffer_t *, uint32_t>;
158 bool send_now_impl_nonblock(uint32_t activebuf_idx);
160 void in_callback(const Transfer_t *transfer);
161 void out_callback(const Transfer_t *transfer);
162
163 private:
164 template <class T, size_t N>
165 static constexpr size_t len(T (&)[N]) {
166 return N;
167 }
168};
169
171
172#include "TeensyHostMIDI.ipp"
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
Teensy USB Host MIDI driver.
void disconnect() override
uint32_t read_finish(const Transfer_t *transfer)
void write(const uint32_t(&msgs)[N])
Send multiple MIDI USB messages. May block.
void read_start(uint8_t *buffer, uint32_t size)
static constexpr uint32_t PacketSize
USB packet size. Must be a power of two.
void setErrorTimeout(microseconds timeout)
std::atomic< uint32_t > size
uint32_t write_finish(const Transfer_t *transfer)
uint32_t write_nonblock(const uint32_t *msgs, uint32_t num_msgs)
Send multiple MIDI USB messages without blocking.
bool claim_if_midi(Device_t *device, int type, const uint8_t *descriptors, uint32_t len)
microseconds error_timeout_duration
void timeout_callback()
void timer_event(USBDriverTimer *whichtimer) override
static constexpr uint32_t SizeReserved
uint32_t read()
Try reading a 4-byte MIDI USB message.
bool claim(Device_t *device, int type, const uint8_t *descriptors, uint32_t len) override
struct TeensyHostMIDI::Reading::Buffer buffers[NumRxPackets]
void send_now()
Try sending the buffered data now.
USBDriverTimer write_timeout
std::atomic< uint32_t > write_idx
std::atomic< uint32_t > active_writebuffer
void in_callback(const Transfer_t *transfer)
std::atomic< uint32_t > available
writebuf_size_tup read_writebuf_size()
void read_start_isr(uint8_t *buffer, uint32_t size)
struct TeensyHostMIDI::Reading reading
typename Reading::Buffer rbuffer_t
uint32_t getWriteError() const
Count how many USB packets were dropped.
void setTimeout(microseconds timeout)
Set the timeout, the number of microseconds to buffer the outgoing MIDI messages.
static constexpr size_t len(T(&)[N])
std::atomic< Buffer * > sending
uint32_t write_impl(const uint32_t *msgs, uint32_t num_msgs, bool nonblocking)
std::tuple< uint32_t, wbuffer_t *, uint32_t > writebuf_size_tup
TeensyHostMIDI(USBHost &host)
void write_start(uint8_t *buffer, uint32_t size)
typename Writing::Buffer wbuffer_t
static void tx_callback(const Transfer_t *transfer)
void write(const uint32_t *msgs, uint32_t num_msgs)
Send multiple MIDI USB messages.
std::atomic< uint32_t > read_idx
std::atomic< bool > reading
bool send_now_impl_nonblock(uint32_t activebuf_idx)
void out_callback(const Transfer_t *transfer)
std::atomic< Buffer * > send_timeout
static constexpr uint32_t NumRxPackets
static void rx_callback(const Transfer_t *transfer)
struct TeensyHostMIDI::Writing::Buffer buffers[2]
void write(uint32_t msg)
Send a MIDI USB message.
std::chrono::microseconds microseconds
strbuf_t mystring_bufs[1]
void clearWriteError()
Clear the counter of how many USB packets were dropped.
void write_start_isr(uint8_t *buffer, uint32_t size)
struct TeensyHostMIDI::Writing writing
State for writing outgoing USB-MIDI data.
State for reading incoming USB-MIDI data.