2 Commits

Auteur SHA1 Bericht Datum
  Mathias Gottschlag c0b41b7242 WIP. 4 jaren geleden
  Mathias Gottschlag c551a0eee7 WIP. 4 jaren geleden
4 gewijzigde bestanden met toevoegingen van 301 en 11 verwijderingen
  1. 3
    0
      Cargo.lock
  2. 3
    3
      Cargo.toml
  3. 14
    5
      src/usb.rs
  4. 281
    3
      src/usb_audio.rs

+ 3
- 0
Cargo.lock Bestand weergeven

@@ -586,6 +586,7 @@ checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468"
586 586
 [[package]]
587 587
 name = "pio"
588 588
 version = "0.1.0"
589
+source = "git+https://github.com/rp-rs/pio-rs.git?branch=main#8c12d426685ac23cac975341e728fc0a50ebfd6c"
589 590
 dependencies = [
590 591
  "arrayvec",
591 592
  "num_enum",
@@ -595,6 +596,7 @@ dependencies = [
595 596
 [[package]]
596 597
 name = "pio-parser"
597 598
 version = "0.1.0"
599
+source = "git+https://github.com/rp-rs/pio-rs.git?branch=main#8c12d426685ac23cac975341e728fc0a50ebfd6c"
598 600
 dependencies = [
599 601
  "lalrpop",
600 602
  "lalrpop-util",
@@ -604,6 +606,7 @@ dependencies = [
604 606
 [[package]]
605 607
 name = "pio-proc"
606 608
 version = "0.1.0"
609
+source = "git+https://github.com/rp-rs/pio-rs.git?branch=main#8c12d426685ac23cac975341e728fc0a50ebfd6c"
607 610
 dependencies = [
608 611
  "codespan-reporting",
609 612
  "lalrpop-util",

+ 3
- 3
Cargo.toml Bestand weergeven

@@ -14,14 +14,14 @@ embedded-hal ="0.2.5"
14 14
 embedded-time = "0.12.0"
15 15
 nb = "1.0"
16 16
 panic-halt = "0.2.0"
17
-pio = { path = "../pio-rs" }
18
-pio-proc = { path = "../pio-rs/pio-proc" }
17
+pio = { git = "https://github.com/rp-rs/pio-rs.git", branch = "main" }
18
+pio-proc = { git = "https://github.com/rp-rs/pio-rs.git", branch = "main" }
19 19
 #rp2040-hal = { git = "https://github.com/rp-rs/rp-hal.git", features = ["rt"] }
20 20
 rp2040-hal = { path = "../rp-hal/rp2040-hal", features = ["rt"] }
21 21
 rp2040-boot2 = "0.1.2"
22 22
 stable_deref_trait = { version = "1.2.0", default-features = false }
23 23
 systick-monotonic = "0.1.0-alpha.0"
24
-usb-device= "0.2.8"
24
+usb-device = { version = "0.2.8", features = ["control-buffer-256"] }
25 25
 void = { version = "*", default_features = false }
26 26
 
27 27
 [patch.crates-io]

+ 14
- 5
src/usb.rs Bestand weergeven

@@ -1,4 +1,4 @@
1
-use crate::audio_buffer::WriteBuffer;
1
+use crate::audio_buffer::{WriteBuffer, WritePacket};
2 2
 use crate::usb_audio::UsbAudioClass;
3 3
 use rp2040_hal::pac::USBCTRL_REGS;
4 4
 use rp2040_hal::timer::Timer;
@@ -6,9 +6,11 @@ use rp2040_hal::usb::UsbBus;
6 6
 use usb_device::{class_prelude::*, prelude::*};
7 7
 
8 8
 pub struct Usb {
9
-    usb_audio: UsbAudioClass<'static, UsbBus>,
9
+    usb_audio: UsbAudioClass<'static, UsbBus, WritePacket<4>>,
10 10
     usb_dev: UsbDevice<'static, UsbBus>,
11 11
     in_buffer: WriteBuffer<4>,
12
+
13
+    timer: Timer,
12 14
 }
13 15
 
14 16
 impl Usb {
@@ -17,7 +19,7 @@ impl Usb {
17 19
         in_buffer: WriteBuffer<4>,
18 20
         timer: Timer,
19 21
     ) -> Usb {
20
-        let usb_audio = UsbAudioClass::new(bus, 64);
22
+        let usb_audio = UsbAudioClass::new(bus);
21 23
 
22 24
         // This PID/VID combination is selected from the pid.codes PID space and only intended for
23 25
         // software development. It is not universally unique and should not be used outside of
@@ -33,6 +35,7 @@ impl Usb {
33 35
             usb_audio,
34 36
             usb_dev,
35 37
             in_buffer,
38
+            timer,
36 39
         }
37 40
     }
38 41
 
@@ -41,13 +44,19 @@ impl Usb {
41 44
         // using the USB peripheral at this time.
42 45
         let sof = unsafe { (&*USBCTRL_REGS::ptr()).intr.read().dev_sof().bit_is_set() };
43 46
         if sof {
44
-            let mut buffer = [0u8; 64];
47
+            // Calculate the frequency difference (frames versus 1kHz derived from the system
48
+            // clock) and update the synchronization data for the USB audio class accordingly.
49
+            // Also, add a correction factor if the buffers are running low or high.
50
+            // TODO
51
+
52
+            /*let mut buffer = [0u8; 64];
45 53
             for i in 0..64 {
46 54
                 buffer[i] = i as u8 * 4;
47 55
             }
48
-            let _err = self.usb_audio.write_packet(&buffer);
56
+            let _err = self.usb_audio.write_packet(&buffer);*/
49 57
         }
50 58
         if self.usb_dev.poll(&mut [&mut self.usb_audio]) {
59
+            // If we received audio data, move it into the buffer.
51 60
             // TODO
52 61
         }
53 62
     }

+ 281
- 3
src/usb_audio.rs Bestand weergeven

@@ -3,12 +3,290 @@
3 3
 //! See "Universal Serial Bus Device Class Definition for Audio Devices", release 1.0 (March 18,
4 4
 //! 1998) for a specification of the USB audio class.
5 5
 use usb_device::class_prelude::*;
6
+use usb_device::endpoint::{IsochronousSynchronizationType, IsochronousUsageType};
7
+use usb_device::Result;
8
+
9
+const DEVICE_CLASS_AUDIO: u8 = 0x01;
10
+const AUDIO_SUBCLASS_CONTROL: u8 = 0x01;
11
+const AUDIO_SUBCLASS_STREAMING: u8 = 0x02;
12
+const AUDIO_PROTOCOL_NONE: u8 = 0x00;
13
+
14
+const AUDIO_INTERFACE_DESC_TYPE: u8 = 0x24;
15
+const AUDIO_ENDPOINT_DESC_TYPE: u8 = 0x25;
16
+
17
+const AUDIO_CONTROL_HEADER: u8 = 0x01;
18
+const AUDIO_CONTROL_INPUT_TERMINAL: u8 = 0x02;
19
+const AUDIO_CONTROL_OUTPUT_TERMINAL: u8 = 0x03;
20
+const AUDIO_CONTROL_FEATURE_UNIT: u8 = 0x06;
21
+
22
+const AUDIO_STREAMING_GENERAL: u8 = 0x01;
23
+const AUDIO_STREAMING_FORMAT_TYPE: u8 = 0x02;
24
+
25
+const AUDIO_ENDPOINT_GENERAL: u8 = 0x01;
26
+
27
+// TODO: Update bDelay.
6 28
 
7
-pub struct UsbAudioClass<'a, BUS: UsbBus> {
29
+pub struct UsbAudioClass<'a, B: UsbBus, OUTBUF: AsRef<[u32]>> {
8 30
     audio_control: InterfaceNumber,
31
+    audio_streaming_inactive: InterfaceNumber,
9 32
     audio_streaming: InterfaceNumber,
10
-    audio_streaming: InterfaceNumber,
11
-    // TODO
33
+    audio_out: EndpointOut<'a, B>,
34
+    audio_out_sync: EndpointIn<'a, B>,
35
+    //audio_in: EndpointIn<'a, B>,
36
+    samples_per_frame: [u8; 3],
37
+
38
+    audio_out_buf: Option<OUTBUF>,
39
+}
40
+
41
+impl<'a, B: UsbBus, OUTBUF: AsRef<[u32]>> UsbAudioClass<'a, B, OUTBUF> {
42
+    pub fn new(bus_alloc: &'a UsbBusAllocator<B>) -> Self {
43
+        UsbAudioClass {
44
+            audio_control: bus_alloc.interface(),
45
+            audio_streaming_inactive: bus_alloc.interface(),
46
+            audio_streaming: bus_alloc.interface(),
47
+            // 48kHz * 2 * 16bit = 192B per packet. We allocate a bit more in case the device clock
48
+            // is faster than the host clock.
49
+            /*audio_out: bus_alloc.isochronous(
50
+                IsochronousSynchronizationType::Asynchronous,
51
+                IsochronousUsageType::Data,
52
+                256,
53
+                1,
54
+            ),*/
55
+            audio_out: bus_alloc.isochronous(
56
+                IsochronousSynchronizationType::Synchronous,
57
+                IsochronousUsageType::Data,
58
+                256,
59
+                1,
60
+            ),
61
+            audio_out_sync: bus_alloc.isochronous(
62
+                IsochronousSynchronizationType::Asynchronous,
63
+                IsochronousUsageType::Feedback,
64
+                3,
65
+                1,
66
+            ),
67
+            /*audio_in: bus_alloc.isochronous(
68
+                IsochronousSynchronizationType::Asynchronous,
69
+                IsochronousUsageType::Data,
70
+                256,
71
+                1,
72
+            ),*/
73
+            samples_per_frame: [48 >> 2, 48 << 6, 0], // 48 kHz
74
+            audio_out_buf: None,
75
+        }
76
+    }
77
+
78
+    // TODO: Functions to read and write data?
79
+}
80
+
81
+impl<B: UsbBus, OUTBUF: AsRef<[u32]>> UsbClass<B> for UsbAudioClass<'_, B, OUTBUF> {
82
+    fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
83
+        writer.iad(
84
+            self.audio_control,
85
+            2,   // Two interfaces (control + streaming).
86
+            0x0, // Each interface specifies its own class.
87
+            0x0, // Each interface specifies its own subclass.
88
+            0x0, // No class-specific protocols for this device.
89
+        )?;
90
+
91
+        // Audio control interface.
92
+        writer.interface(
93
+            self.audio_control,
94
+            DEVICE_CLASS_AUDIO,
95
+            AUDIO_SUBCLASS_CONTROL,
96
+            AUDIO_PROTOCOL_NONE,
97
+        )?;
98
+
99
+        writer.write(
100
+            AUDIO_INTERFACE_DESC_TYPE,
101
+            &[
102
+                AUDIO_CONTROL_HEADER,        // bDescriptorSubtype
103
+                0x00,                        // bcdADC
104
+                0x01,                        //
105
+                37,                          // wTotalLength
106
+                0,                           //
107
+                0x01,                        // bInCollection
108
+                self.audio_streaming.into(), // baInterfaceNr
109
+            ],
110
+        )?;
111
+
112
+        // Input terminal (USB streaming).
113
+        writer.write(
114
+            AUDIO_INTERFACE_DESC_TYPE,
115
+            &[
116
+                AUDIO_CONTROL_INPUT_TERMINAL, // bDescriptorSubtype
117
+                0x01,                         // bTerminalID
118
+                0x01,                         // wTerminalType
119
+                0x01,                         //
120
+                0x00,                         // bAssocTerminal
121
+                0x02,                         // bNrChannels
122
+                0x03,                         // wChannelConfig
123
+                0x00,                         //
124
+                0x00,                         // iChannelNames
125
+                0x00,                         // iTerminal
126
+            ],
127
+        )?;
128
+
129
+        // Feature unit (volume and mute).
130
+        writer.write(
131
+            AUDIO_INTERFACE_DESC_TYPE,
132
+            &[
133
+                AUDIO_CONTROL_FEATURE_UNIT, // bDescriptorSubtype
134
+                0x02,                       // bUnitID
135
+                0x01,                       // bSourceID
136
+                0x01,                       // bControlSize
137
+                0x03,                       // bmaControls(0)
138
+                0x00,                       // iFeature
139
+            ],
140
+        )?;
141
+
142
+        // Output terminal (speaker).
143
+        writer.write(
144
+            AUDIO_INTERFACE_DESC_TYPE,
145
+            &[
146
+                AUDIO_CONTROL_OUTPUT_TERMINAL, // bDescriptorSubtype
147
+                0x03,                          // bTerminalID
148
+                0x01,                          // wTerminalType
149
+                0x03,                          //
150
+                0x00,                          // bAssocTerminal
151
+                0x02,                          // bSourceID
152
+                0x00,                          // iTerminal
153
+            ],
154
+        )?;
155
+
156
+        // Audio streaming interface (zero-bandwidth).
157
+        writer.interface(
158
+            self.audio_streaming_inactive,
159
+            DEVICE_CLASS_AUDIO,
160
+            AUDIO_SUBCLASS_STREAMING,
161
+            AUDIO_PROTOCOL_NONE,
162
+        )?;
163
+
164
+        // Audio streaming interface (operational).
165
+        writer.interface_alt(
166
+            self.audio_streaming,
167
+            1,
168
+            DEVICE_CLASS_AUDIO,
169
+            AUDIO_SUBCLASS_STREAMING,
170
+            AUDIO_PROTOCOL_NONE,
171
+            None,
172
+        )?;
173
+
174
+        writer.write(
175
+            AUDIO_INTERFACE_DESC_TYPE,
176
+            &[
177
+                AUDIO_STREAMING_GENERAL, // bDescriptorSubtype
178
+                0x01,                    // bTerminalLink
179
+                0x03,                    // bDelay
180
+                0x01,                    // wFormatTag
181
+                0x00,                    //
182
+            ],
183
+        )?;
184
+
185
+        writer.write(
186
+            AUDIO_INTERFACE_DESC_TYPE,
187
+            &[
188
+                AUDIO_STREAMING_FORMAT_TYPE, // bDescriptorSubtype
189
+                0x01,                        // bFormatType
190
+                0x02,                        // bNrChannels
191
+                0x02,                        // bSubframeSize
192
+                0x10,                        // bBitResolution
193
+                0x01,                        // bSamFreqType
194
+            ],
195
+        )?;
196
+
197
+        /*writer.endpoint_ex(&self.audio_out, |data| {
198
+            // TODO: Faster refresh
199
+            data[0] = 0x09; // bRefresh
200
+            data[1] = self.audio_out_sync.address().into(); // bSynchAddress
201
+            Ok(2)
202
+        })?;*/
203
+        writer.endpoint(&self.audio_out)?;
204
+
205
+        writer.write(
206
+            AUDIO_ENDPOINT_DESC_TYPE,
207
+            &[
208
+                AUDIO_ENDPOINT_GENERAL, // bDescriptorSubtype
209
+                0x00,                   // bmAttributes
210
+                0x01,                   // bLockDelayUnits
211
+                0x00,                   // wLockDelay
212
+                0x00,
213
+            ],
214
+        )?;
215
+
216
+        /*writer.endpoint_ex(&self.audio_out_sync, |data| {
217
+            data[0] = 0x00; // bRefresh
218
+            data[1] = 0x00; // bSynchAddress
219
+            Ok(2)
220
+        })?;*/
221
+
222
+        Ok(())
223
+    }
224
+
225
+    fn get_string(&self, _index: StringIndex, _lang_id: u16) -> Option<&str> {
226
+        // TODO
227
+        None
228
+    }
229
+
230
+    fn reset(&mut self) {
231
+        // Start sending synchronization data.
232
+        self.endpoint_in_complete(self.audio_out_sync.address());
233
+    }
234
+
235
+    fn control_out(&mut self, xfer: ControlOut<B>) {
236
+        let req = xfer.request();
237
+
238
+        if !(req.request_type == control::RequestType::Class
239
+            && req.recipient == control::Recipient::Interface
240
+            && req.index == u8::from(self.audio_control) as u16)
241
+        {
242
+            return;
243
+        }
244
+
245
+        match req.request {
246
+            // TODO
247
+            _ => {
248
+                xfer.reject().ok();
249
+            }
250
+        };
251
+    }
252
+
253
+    fn control_in(&mut self, xfer: ControlIn<B>) {
254
+        let req = xfer.request();
255
+
256
+        if !(req.request_type == control::RequestType::Class
257
+            && req.recipient == control::Recipient::Interface
258
+            && req.index == u8::from(self.audio_control) as u16)
259
+        {
260
+            return;
261
+        }
262
+
263
+        match req.request {
264
+            // TODO
265
+            _ => {
266
+                xfer.reject().ok();
267
+            }
268
+        };
269
+    }
270
+
271
+    fn endpoint_out(&mut self, addr: EndpointAddress) {
272
+        if addr == self.audio_out.address() {
273
+            if self.audio_out_buf.is_some() {
274
+                // TODO: Write data into buffer, move buffer somewhere else.
275
+            } else {
276
+                // TODO
277
+            }
278
+            // TODO: Process incoming audio data.
279
+            let mut buffer = [0u8; 256];
280
+            self.audio_out.read(&mut buffer);
281
+        }
282
+    }
283
+
284
+    fn endpoint_in_complete(&mut self, addr: EndpointAddress) {
285
+        if addr == self.audio_out_sync.address() {
286
+            // Immediately write the next sync value.
287
+            //self.audio_out_sync.write(&self.samples_per_frame).unwrap();
288
+        }
289
+    }
12 290
 }
13 291
 
14 292
 /*use usb_device::class_prelude::*;

Laden…
Annuleren
Opslaan