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 + 9
154 + (4 + self.n_out_jacks as usize)
155 + 9
156 + (4 + self.n_in_jacks as usize);
157
158 writer.write(
160 CS_INTERFACE,
162 &[
163 MS_HEADER_SUBTYPE,
164 0x00,
165 0x01, (midi_streaming_total_length & 0xFF) as u8,
167 ((midi_streaming_total_length >> 8) & 0xFF) as u8,
168 ],
169 )?;
170
171 for i in 0..self.n_in_jacks {
173 writer.write(
174 CS_INTERFACE,
176 &[
177 MIDI_IN_JACK_SUBTYPE,
178 EXTERNAL,
179 self.in_jack_id_ext(i), 0x00,
181 ],
182 )?;
183 }
184
185 for i in 0..self.n_out_jacks {
186 writer.write(
187 CS_INTERFACE,
189 &[
190 MIDI_IN_JACK_SUBTYPE,
191 EMBEDDED,
192 self.in_jack_id_emb(i), 0x00,
194 ],
195 )?;
196 }
197
198 for i in 0..self.n_out_jacks {
199 writer.write(
200 CS_INTERFACE,
202 &[
203 MIDI_OUT_JACK_SUBTYPE,
204 EXTERNAL,
205 self.out_jack_id_ext(i), 0x01, self.in_jack_id_emb(i), 0x01, 0x00,
210 ],
211 )?;
212 }
213
214 for i in 0..self.n_in_jacks {
215 writer.write(
216 CS_INTERFACE,
218 &[
219 MIDI_OUT_JACK_SUBTYPE,
220 EMBEDDED,
221 self.out_jack_id_emb(i), 0x01, self.in_jack_id_ext(i), 0x01, 0x00,
226 ],
227 )?;
228 }
229
230 let mut endpoint_data = [
231 MS_GENERAL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
233 0, ];
235
236 writer.endpoint_ex(&self.standard_bulkout, |data| {
237 data[0] = 0; data[1] = 0; Ok(2)
240 })?; endpoint_data[1] = self.n_out_jacks;
243 for i in 0..self.n_out_jacks {
244 endpoint_data[2 + i as usize] = self.in_jack_id_emb(i);
245 }
246 writer.write(
247 CS_ENDPOINT,
249 &endpoint_data[0..2 + self.n_out_jacks as usize],
250 )?;
251
252 writer.endpoint_ex(&self.standard_bulkin, |data| {
253 data[0] = 0; data[1] = 0; Ok(2)
256 })?; endpoint_data[1] = self.n_in_jacks;
259 for i in 0..self.n_in_jacks {
260 endpoint_data[2 + i as usize] = self.out_jack_id_emb(i);
261 }
262 writer.write(
263 CS_ENDPOINT,
265 &endpoint_data[0..2 + self.n_in_jacks as usize],
266 )?;
267
268 let midi_streaming_end_byte = writer.position();
269 assert!(midi_streaming_end_byte - midi_streaming_start_byte == midi_streaming_total_length);
270
271 Ok(())
272 }
273}