1use usb_device::class_prelude::*;
4use usb_device::Result;
5
6use crate::packet::{UsbMidiEventPacket, UsbMidiEventPacketError};
7
8const USB_AUDIO_CLASS: u8 = 0x01;
10const USB_AUDIOCONTROL_SUBCLASS: u8 = 0x01;
11const USB_MIDISTREAMING_SUBCLASS: u8 = 0x03;
12const MIDI_IN_JACK_SUBTYPE: u8 = 0x02;
13const MIDI_OUT_JACK_SUBTYPE: u8 = 0x03;
14const EMBEDDED: u8 = 0x01;
15const EXTERNAL: u8 = 0x02;
16const CS_INTERFACE: u8 = 0x24;
17const CS_ENDPOINT: u8 = 0x25;
18const HEADER_SUBTYPE: u8 = 0x01;
19const MS_HEADER_SUBTYPE: u8 = 0x01;
20const MS_GENERAL: u8 = 0x01;
21
22const MIDI_IN_SIZE: u8 = 0x06;
23const MIDI_OUT_SIZE: u8 = 0x09;
24
25pub const MIDI_PACKET_SIZE: usize = 4;
27
28pub const MAX_PACKET_SIZE: usize = 64;
30
31pub struct UsbMidiClass<'a, B: UsbBus> {
33 standard_ac: InterfaceNumber,
34 standard_mc: InterfaceNumber,
35 standard_bulkout: EndpointOut<'a, B>,
36 standard_bulkin: EndpointIn<'a, B>,
37 n_in_jacks: u8,
38 n_out_jacks: u8,
39}
40
41#[derive(Debug, Clone, Eq, PartialEq)]
43pub enum UsbMidiReadError {
44 ParsingFailed(UsbMidiEventPacketError),
46 UsbError(UsbError),
48}
49
50#[derive(Debug)]
52pub struct InvalidArguments;
53
54impl<B: UsbBus> UsbMidiClass<'_, B> {
55 pub fn new(
59 alloc: &UsbBusAllocator<B>,
60 n_in_jacks: u8,
61 n_out_jacks: u8,
62 ) -> core::result::Result<UsbMidiClass<'_, B>, InvalidArguments> {
63 if n_in_jacks > 16 || n_out_jacks > 16 {
64 return Err(InvalidArguments);
65 }
66 Ok(UsbMidiClass {
67 standard_ac: alloc.interface(),
68 standard_mc: alloc.interface(),
69 standard_bulkout: alloc.bulk(MAX_PACKET_SIZE as u16),
70 standard_bulkin: alloc.bulk(MAX_PACKET_SIZE as u16),
71 n_in_jacks,
72 n_out_jacks,
73 })
74 }
75
76 pub fn send_bytes(&mut self, buffer: [u8; 4]) -> Result<usize> {
78 self.standard_bulkin.write(&buffer)
79 }
80
81 pub fn send_packet(&mut self, usb_midi: UsbMidiEventPacket) -> Result<usize> {
83 let bytes: [u8; MIDI_PACKET_SIZE] = usb_midi.into();
84 self.standard_bulkin.write(&bytes)
85 }
86
87 pub fn read(&mut self, buffer: &mut [u8]) -> Result<usize> {
89 self.standard_bulkout.read(buffer)
90 }
91
92 fn in_jack_id_ext(&self, index: u8) -> u8 {
94 debug_assert!(index < self.n_in_jacks);
95 2 * index + 1
96 }
97
98 fn out_jack_id_emb(&self, index: u8) -> u8 {
100 debug_assert!(index < self.n_in_jacks);
101 2 * index + 2
102 }
103
104 fn out_jack_id_ext(&self, index: u8) -> u8 {
106 debug_assert!(index < self.n_out_jacks);
107 2 * self.n_in_jacks + 2 * index + 1
108 }
109
110 fn in_jack_id_emb(&self, index: u8) -> u8 {
112 debug_assert!(index < self.n_out_jacks);
113 2 * self.n_in_jacks + 2 * index + 2
114 }
115}
116
117impl<B: UsbBus> UsbClass<B> for UsbMidiClass<'_, B> {
118 fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
119 writer.interface(
121 self.standard_ac,
122 USB_AUDIO_CLASS,
123 USB_AUDIOCONTROL_SUBCLASS,
124 0, )?;
126
127 writer.write(
129 CS_INTERFACE,
130 &[
131 HEADER_SUBTYPE,
132 0x00,
133 0x01, 0x09,
135 0x00, 0x01, 0x01, ],
139 )?;
140
141 writer.interface(
143 self.standard_mc,
144 USB_AUDIO_CLASS,
145 USB_MIDISTREAMING_SUBCLASS,
146 0, )?; let midi_streaming_start_byte = writer.position();
150 let midi_streaming_total_length = 7
151 + (self.n_in_jacks + self.n_out_jacks) as usize
152 * (MIDI_IN_SIZE + MIDI_OUT_SIZE) as usize
153 + if self.n_out_jacks > 0 {
154 9 + (4 + self.n_out_jacks as usize)
155 } else {
156 0
157 }
158 + if self.n_in_jacks > 0 {
159 9 + 4 + self.n_in_jacks as usize
160 } else {
161 0
162 };
163
164 writer.write(
166 CS_INTERFACE,
168 &[
169 MS_HEADER_SUBTYPE,
170 0x00,
171 0x01, (midi_streaming_total_length & 0xFF) as u8,
173 ((midi_streaming_total_length >> 8) & 0xFF) as u8,
174 ],
175 )?;
176
177 for i in 0..self.n_in_jacks {
179 writer.write(
180 CS_INTERFACE,
182 &[
183 MIDI_IN_JACK_SUBTYPE,
184 EXTERNAL,
185 self.in_jack_id_ext(i), 0x00,
187 ],
188 )?;
189 }
190
191 for i in 0..self.n_out_jacks {
192 writer.write(
193 CS_INTERFACE,
195 &[
196 MIDI_IN_JACK_SUBTYPE,
197 EMBEDDED,
198 self.in_jack_id_emb(i), 0x00,
200 ],
201 )?;
202 }
203
204 for i in 0..self.n_out_jacks {
205 writer.write(
206 CS_INTERFACE,
208 &[
209 MIDI_OUT_JACK_SUBTYPE,
210 EXTERNAL,
211 self.out_jack_id_ext(i), 0x01, self.in_jack_id_emb(i), 0x01, 0x00,
216 ],
217 )?;
218 }
219
220 for i in 0..self.n_in_jacks {
221 writer.write(
222 CS_INTERFACE,
224 &[
225 MIDI_OUT_JACK_SUBTYPE,
226 EMBEDDED,
227 self.out_jack_id_emb(i), 0x01, self.in_jack_id_ext(i), 0x01, 0x00,
232 ],
233 )?;
234 }
235
236 let mut endpoint_data = [
237 MS_GENERAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
239 0, ];
241
242 if self.n_out_jacks > 0 {
243 writer.endpoint_ex(&self.standard_bulkout, |data| {
244 data[0] = 0; data[1] = 0; Ok(2)
247 })?; endpoint_data[1] = self.n_out_jacks;
250 for i in 0..self.n_out_jacks {
251 endpoint_data[2 + i as usize] = self.in_jack_id_emb(i);
252 }
253 writer.write(
254 CS_ENDPOINT,
256 &endpoint_data[0..2 + self.n_out_jacks as usize],
257 )?;
258 }
259
260 if self.n_in_jacks > 0 {
261 writer.endpoint_ex(&self.standard_bulkin, |data| {
262 data[0] = 0; data[1] = 0; Ok(2)
265 })?; endpoint_data[1] = self.n_in_jacks;
268 for i in 0..self.n_in_jacks {
269 endpoint_data[2 + i as usize] = self.out_jack_id_emb(i);
270 }
271 writer.write(
272 CS_ENDPOINT,
274 &endpoint_data[0..2 + self.n_in_jacks as usize],
275 )?;
276 }
277
278 let midi_streaming_end_byte = writer.position();
279 assert!(midi_streaming_end_byte - midi_streaming_start_byte == midi_streaming_total_length);
280
281 Ok(())
282 }
283}