|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+#![warn(missing_docs)]
|
|
|
2
|
+
|
|
|
3
|
+use core::cell::{Cell, UnsafeCell};
|
|
|
4
|
+
|
|
|
5
|
+use cortex_m::interrupt::{CriticalSection, Mutex};
|
|
|
6
|
+
|
|
|
7
|
+/// Each packet contains 1 millisecond of audio data (48 samples at 48000kHz).
|
|
|
8
|
+///
|
|
|
9
|
+/// This translates two twice the number of values, as each sample contains two channels.
|
|
|
10
|
+pub const SAMPLES_PER_PACKET: usize = 48;
|
|
|
11
|
+pub const CHANNELS: usize = 2;
|
|
|
12
|
+pub const PACKETS: usize = 3;
|
|
|
13
|
+
|
|
|
14
|
+pub type Packet = [u32; SAMPLES_PER_PACKET * CHANNELS];
|
|
|
15
|
+
|
|
|
16
|
+/// Type for audio packet buffering.
|
|
|
17
|
+///
|
|
|
18
|
+/// The audio packets always contain two channels with 32-bit samples. The type contains three
|
|
|
19
|
+/// buffers each containing the same fixed number of samples. This structure allows two buffers to
|
|
|
20
|
+/// be in use by the DMA engine while the third is used by the ARM core.
|
|
|
21
|
+pub struct AudioBuffer {
|
|
|
22
|
+ mutex: Mutex<AudioBufferInner>,
|
|
|
23
|
+}
|
|
|
24
|
+
|
|
|
25
|
+struct AudioBufferInner {
|
|
|
26
|
+ /// Packet contents.
|
|
|
27
|
+ packets: [UnsafeCell<Packet>; PACKETS],
|
|
|
28
|
+ /// Bitmask of packets which contain valid data and are not currently being read.
|
|
|
29
|
+ valid: Cell<u32>,
|
|
|
30
|
+ /// Bitmask of packets which do not contain valid data and which are not currently being
|
|
|
31
|
+ /// written.
|
|
|
32
|
+ invalid: Cell<u32>,
|
|
|
33
|
+ /// Bitmask of all packets which are currently borrowed via `borrow_read()`.
|
|
|
34
|
+ reading: Cell<u32>,
|
|
|
35
|
+ /// Bitmask of all packets which are currently borrowed via `borrow_write()`.
|
|
|
36
|
+ writing: Cell<u32>,
|
|
|
37
|
+}
|
|
|
38
|
+
|
|
|
39
|
+impl AudioBuffer {
|
|
|
40
|
+ /// Creates a new audio buffer.
|
|
|
41
|
+ pub const fn new() -> AudioBuffer {
|
|
|
42
|
+ // Initially, all packet contents are invalid and no packets are currently being read or
|
|
|
43
|
+ // written.
|
|
|
44
|
+ AudioBuffer {
|
|
|
45
|
+ mutex: Mutex::new(AudioBufferInner {
|
|
|
46
|
+ packets: [
|
|
|
47
|
+ UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
|
|
|
48
|
+ UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
|
|
|
49
|
+ UnsafeCell::new([0; SAMPLES_PER_PACKET * CHANNELS]),
|
|
|
50
|
+ ],
|
|
|
51
|
+ valid: Cell::new(0),
|
|
|
52
|
+ invalid: Cell::new(((1 << PACKETS) - 1) as u32),
|
|
|
53
|
+ reading: Cell::new(0),
|
|
|
54
|
+ writing: Cell::new(0),
|
|
|
55
|
+ }),
|
|
|
56
|
+ }
|
|
|
57
|
+ }
|
|
|
58
|
+
|
|
|
59
|
+ /// Returns whether there are any buffers with valid data ready for reading.
|
|
|
60
|
+ pub fn read_data_available(&self, cs: &CriticalSection) -> bool {
|
|
|
61
|
+ let inner = self.mutex.borrow(cs);
|
|
|
62
|
+ inner.valid.get() != 0
|
|
|
63
|
+ }
|
|
|
64
|
+
|
|
|
65
|
+ pub fn borrow_read(&'static self, cs: &CriticalSection) -> Option<ReadPacket> {
|
|
|
66
|
+ let inner = self.mutex.borrow(cs);
|
|
|
67
|
+ let valid = inner.valid.get();
|
|
|
68
|
+ if valid != 0 {
|
|
|
69
|
+ return None;
|
|
|
70
|
+ }
|
|
|
71
|
+ let index = valid.trailing_zeros();
|
|
|
72
|
+ inner.valid.set(valid & !(1 << index));
|
|
|
73
|
+ inner.reading.set(inner.reading.get() | (1 << index));
|
|
|
74
|
+
|
|
|
75
|
+ let index = index as usize;
|
|
|
76
|
+ Some(ReadPacket {
|
|
|
77
|
+ buffer: self,
|
|
|
78
|
+ data: unsafe { &*inner.packets[index].get() },
|
|
|
79
|
+ index,
|
|
|
80
|
+ })
|
|
|
81
|
+ }
|
|
|
82
|
+
|
|
|
83
|
+ pub fn read_finished(&'static self, _packet: ReadPacket, _cs: &CriticalSection) {
|
|
|
84
|
+ // TODO
|
|
|
85
|
+ panic!("Not yet implemented.");
|
|
|
86
|
+ }
|
|
|
87
|
+
|
|
|
88
|
+ /// Returns whether there are any empty buffers ready for writing.
|
|
|
89
|
+ pub fn write_data_available(&self, cs: &CriticalSection) -> bool {
|
|
|
90
|
+ let inner = self.mutex.borrow(cs);
|
|
|
91
|
+ inner.invalid.get() != 0
|
|
|
92
|
+ }
|
|
|
93
|
+
|
|
|
94
|
+ pub fn borrow_write(&'static self, cs: &CriticalSection) -> Option<WritePacket> {
|
|
|
95
|
+ let inner = self.mutex.borrow(cs);
|
|
|
96
|
+ let invalid = inner.invalid.get();
|
|
|
97
|
+ if invalid != 0 {
|
|
|
98
|
+ return None;
|
|
|
99
|
+ }
|
|
|
100
|
+ let index = invalid.trailing_zeros();
|
|
|
101
|
+ inner.invalid.set(invalid & !(1 << index));
|
|
|
102
|
+ inner.writing.set(inner.writing.get() | (1 << index));
|
|
|
103
|
+
|
|
|
104
|
+ let index = index as usize;
|
|
|
105
|
+ Some(WritePacket {
|
|
|
106
|
+ buffer: self,
|
|
|
107
|
+ data: unsafe { &mut *inner.packets[index].get() },
|
|
|
108
|
+ index,
|
|
|
109
|
+ })
|
|
|
110
|
+ }
|
|
|
111
|
+
|
|
|
112
|
+ pub fn write_finished(&'static self, _packet: WritePacket, _cs: &CriticalSection) {
|
|
|
113
|
+ // TODO
|
|
|
114
|
+ panic!("Not yet implemented.");
|
|
|
115
|
+ }
|
|
|
116
|
+}
|
|
|
117
|
+
|
|
|
118
|
+pub struct ReadPacket {
|
|
|
119
|
+ buffer: &'static AudioBuffer,
|
|
|
120
|
+ data: &'static Packet,
|
|
|
121
|
+ index: usize,
|
|
|
122
|
+}
|
|
|
123
|
+
|
|
|
124
|
+pub struct WritePacket {
|
|
|
125
|
+ buffer: &'static AudioBuffer,
|
|
|
126
|
+ data: &'static mut Packet,
|
|
|
127
|
+ index: usize,
|
|
|
128
|
+}
|