stm32_usbd/
endpoint_memory.rs

1use crate::endpoint::NUM_ENDPOINTS;
2use crate::UsbPeripheral;
3use core::slice;
4use core::{marker::PhantomData, mem};
5use usb_device::{Result, UsbError};
6use vcell::VolatileCell;
7
8/// Different endpoint memory access schemes
9#[derive(Debug, PartialEq, Eq, Clone, Copy)]
10#[non_exhaustive]
11pub enum MemoryAccess {
12    /// 16x1 bits per word. Each 32-bit word is accessed as one 16-bit half-word. The second half-word of the word is ignored.
13    ///
14    /// This matches the behavior of `EP_MEMORY_ACCESS_2X16 = false` from previous versions of this library.
15    Word16x1,
16    /// 16x2 bits per word. Each 32-bit word is accessed as two 16-bit half-words.
17    ///
18    /// This matches the behavior of `EP_MEMORY_ACCESS_2X16 = true` from previous versions of this library.
19    Word16x2,
20    /// 32x1 bits per word. Each 32-bit word is accessed as one 32-bit word.
21    Word32x1,
22}
23
24impl MemoryAccess {
25    /// Value to multiply offsets within the EP memory by when calculating address to read or write to.
26    #[inline(always)]
27    const fn offset_multiplier(self) -> usize {
28        match self {
29            MemoryAccess::Word16x1 => 2,
30            MemoryAccess::Word16x2 | MemoryAccess::Word32x1 => 1,
31        }
32    }
33
34    /// Size of unit used when reading and writing EP memory, in bytes.
35    #[inline(always)]
36    const fn unit_size(self) -> usize {
37        match self {
38            MemoryAccess::Word16x1 | MemoryAccess::Word16x2 => 2,
39            MemoryAccess::Word32x1 => 4,
40        }
41    }
42}
43
44pub struct EndpointBuffer<USB> {
45    mem_ptr: *mut (),
46    mem_len: usize,
47    marker: PhantomData<USB>,
48}
49
50unsafe impl<USB> Send for EndpointBuffer<USB> {}
51
52impl<USB: UsbPeripheral> EndpointBuffer<USB> {
53    pub fn new(offset_bytes: usize, size_bytes: usize) -> Self {
54        let mem_offset_bytes = offset_bytes * USB::EP_MEMORY_ACCESS.offset_multiplier();
55        let mem_len = size_bytes * USB::EP_MEMORY_ACCESS.offset_multiplier() / USB::EP_MEMORY_ACCESS.unit_size();
56
57        let mem_ptr = unsafe { USB::EP_MEMORY.byte_add(mem_offset_bytes).cast_mut() };
58        Self {
59            mem_ptr,
60            mem_len,
61            marker: PhantomData,
62        }
63    }
64
65    /// # Safety
66    ///
67    /// Caller must ensure that while the returned reference exists, no mutable references to the section of EP memory covered by this slice exist.
68    #[inline(always)]
69    unsafe fn get_mem_slice<T>(&self) -> &[VolatileCell<T>] {
70        unsafe { slice::from_raw_parts(self.mem_ptr.cast(), self.mem_len) }
71    }
72
73    pub fn read(&self, mut buf: &mut [u8]) {
74        if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
75            let mem = unsafe { self.get_mem_slice::<u32>() };
76
77            let mut index = 0;
78
79            while buf.len() >= 4 {
80                let value = mem[index].get().to_ne_bytes();
81                index += USB::EP_MEMORY_ACCESS.offset_multiplier();
82
83                buf[0..4].copy_from_slice(&value);
84                buf = &mut buf[4..];
85            }
86
87            if buf.len() > 0 {
88                let value = mem[index].get().to_ne_bytes();
89                buf.copy_from_slice(&value[0..buf.len()]);
90            }
91        } else {
92            let mem = unsafe { self.get_mem_slice::<u16>() };
93
94            let mut index = 0;
95
96            while buf.len() >= 2 {
97                let value = mem[index].get().to_ne_bytes();
98                index += USB::EP_MEMORY_ACCESS.offset_multiplier();
99
100                buf[0..2].copy_from_slice(&value);
101                buf = &mut buf[2..];
102            }
103
104            if buf.len() > 0 {
105                let value = mem[index].get().to_ne_bytes();
106                buf.copy_from_slice(&value[0..buf.len()]);
107            }
108        }
109    }
110
111    pub fn write(&self, mut buf: &[u8]) {
112        if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
113            let mem = unsafe { self.get_mem_slice::<u32>() };
114
115            let mut index = 0;
116
117            while buf.len() >= 4 {
118                let mut value = [0; 4];
119                value.copy_from_slice(&buf[0..4]);
120                buf = &buf[4..];
121
122                mem[index].set(u32::from_ne_bytes(value));
123                index += USB::EP_MEMORY_ACCESS.offset_multiplier();
124            }
125
126            if buf.len() > 0 {
127                let mut value = [0; 4];
128                value[0..buf.len()].copy_from_slice(buf);
129                mem[index].set(u32::from_ne_bytes(value));
130            }
131        } else {
132            let mem = unsafe { self.get_mem_slice::<u16>() };
133
134            let mut index = 0;
135
136            while buf.len() >= 2 {
137                let mut value = [0; 2];
138                value.copy_from_slice(&buf[0..2]);
139                buf = &buf[2..];
140
141                mem[index].set(u16::from_ne_bytes(value));
142                index += USB::EP_MEMORY_ACCESS.offset_multiplier();
143            }
144
145            if buf.len() > 0 {
146                let mut value = [0; 2];
147                value[0..buf.len()].copy_from_slice(buf);
148                mem[index].set(u16::from_ne_bytes(value));
149            }
150        }
151    }
152
153    pub fn offset(&self) -> u16 {
154        let offset_bytes = self.mem_ptr as usize - USB::EP_MEMORY as usize;
155        (offset_bytes / USB::EP_MEMORY_ACCESS.offset_multiplier()) as u16
156    }
157
158    pub fn capacity(&self) -> usize {
159        self.mem_len * USB::EP_MEMORY_ACCESS.unit_size() / USB::EP_MEMORY_ACCESS.offset_multiplier()
160    }
161}
162
163pub struct Field<USB> {
164    ptr: *const (),
165    marker: PhantomData<USB>,
166}
167
168impl<USB: UsbPeripheral> Field<USB> {
169    #[inline(always)]
170    pub fn get(&self) -> u16 {
171        if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
172            let unaligned_offset = self.ptr as usize & 0b11;
173            let cell: &VolatileCell<u32> = unsafe { &*self.ptr.byte_sub(unaligned_offset).cast() };
174            let value: [u16; 2] = unsafe { mem::transmute(cell.get()) };
175            value[unaligned_offset >> 1]
176        } else {
177            let cell: &VolatileCell<u16> = unsafe { &*self.ptr.cast() };
178            cell.get()
179        }
180    }
181
182    #[inline(always)]
183    pub fn set(&self, value: u16) {
184        if USB::EP_MEMORY_ACCESS == MemoryAccess::Word32x1 {
185            let unaligned_offset = self.ptr as usize & 0b11;
186            let cell: &VolatileCell<u32> = unsafe { &*self.ptr.byte_sub(unaligned_offset).cast() };
187            let mut previous_value: [u16; 2] = unsafe { mem::transmute(cell.get()) };
188            previous_value[unaligned_offset >> 1] = value;
189            cell.set(unsafe { mem::transmute(previous_value) });
190        } else {
191            let cell: &VolatileCell<u16> = unsafe { &*self.ptr.cast() };
192            cell.set(value);
193        }
194    }
195}
196
197#[repr(C)]
198pub struct BufferDescriptor<USB> {
199    ptr: *const (),
200    marker: PhantomData<USB>,
201}
202
203impl<USB: UsbPeripheral> BufferDescriptor<USB> {
204    #[inline(always)]
205    fn field(&self, index: usize) -> Field<USB> {
206        let mul = USB::EP_MEMORY_ACCESS.offset_multiplier();
207        let ptr = unsafe { self.ptr.byte_add(index * 2 * mul) };
208        Field {
209            ptr,
210            marker: PhantomData,
211        }
212    }
213
214    #[inline(always)]
215    pub fn addr_tx(&self) -> Field<USB> {
216        self.field(0)
217    }
218
219    #[inline(always)]
220    pub fn count_tx(&self) -> Field<USB> {
221        self.field(1)
222    }
223
224    #[inline(always)]
225    pub fn addr_rx(&self) -> Field<USB> {
226        self.field(2)
227    }
228
229    #[inline(always)]
230    pub fn count_rx(&self) -> Field<USB> {
231        self.field(3)
232    }
233}
234
235pub struct EndpointMemoryAllocator<USB> {
236    next_free_offset: usize,
237    _marker: PhantomData<USB>,
238}
239
240impl<USB: UsbPeripheral> EndpointMemoryAllocator<USB> {
241    pub fn new() -> Self {
242        Self {
243            next_free_offset: NUM_ENDPOINTS * 8,
244            _marker: PhantomData,
245        }
246    }
247
248    pub fn allocate_buffer(&mut self, size: usize) -> Result<EndpointBuffer<USB>> {
249        assert_eq!(size & 1, 0);
250        assert!(size < USB::EP_MEMORY_SIZE);
251
252        let offset = self.next_free_offset;
253        if offset as usize + size > USB::EP_MEMORY_SIZE {
254            return Err(UsbError::EndpointMemoryOverflow);
255        }
256
257        self.next_free_offset += size;
258
259        Ok(EndpointBuffer::new(offset, size))
260    }
261
262    pub fn buffer_descriptor(index: u8) -> BufferDescriptor<USB> {
263        let mul = USB::EP_MEMORY_ACCESS.offset_multiplier();
264        let ptr = unsafe { USB::EP_MEMORY.byte_add((index as usize) * 8 * mul).cast() };
265        BufferDescriptor {
266            ptr,
267            marker: Default::default(),
268        }
269    }
270}