aboutsummaryrefslogtreecommitdiff
path: root/embassy-hal-internal/src
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-07-28 13:23:22 +0200
committerGitHub <[email protected]>2023-07-28 13:23:22 +0200
commit036e6ae30c9e772ef8ef20439f121e108b9106f0 (patch)
tree7c654de04304274a11d44733b51c5012aeec9e3c /embassy-hal-internal/src
parent0ced8400d00da30abe76438ef26224c7ed649708 (diff)
Rename embassy-hal-common to embassy-hal-internal, document it's for internal use only. (#1700)
Diffstat (limited to 'embassy-hal-internal/src')
-rw-r--r--embassy-hal-internal/src/atomic_ring_buffer.rs556
-rw-r--r--embassy-hal-internal/src/drop.rs51
-rw-r--r--embassy-hal-internal/src/fmt.rs225
-rw-r--r--embassy-hal-internal/src/interrupt.rs846
-rw-r--r--embassy-hal-internal/src/lib.rs17
-rw-r--r--embassy-hal-internal/src/macros.rs123
-rw-r--r--embassy-hal-internal/src/peripheral.rs174
-rw-r--r--embassy-hal-internal/src/ratio.rs129
-rw-r--r--embassy-hal-internal/src/ring_buffer.rs136
9 files changed, 2257 insertions, 0 deletions
diff --git a/embassy-hal-internal/src/atomic_ring_buffer.rs b/embassy-hal-internal/src/atomic_ring_buffer.rs
new file mode 100644
index 000000000..ea84925c4
--- /dev/null
+++ b/embassy-hal-internal/src/atomic_ring_buffer.rs
@@ -0,0 +1,556 @@
1use core::slice;
2use core::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
3
4/// Atomic reusable ringbuffer
5///
6/// This ringbuffer implementation is designed to be stored in a `static`,
7/// therefore all methods take `&self` and not `&mut self`.
8///
9/// It is "reusable": when created it has no backing buffer, you can give it
10/// one with `init` and take it back with `deinit`, and init it again in the
11/// future if needed. This is very non-idiomatic, but helps a lot when storing
12/// it in a `static`.
13///
14/// One concurrent writer and one concurrent reader are supported, even at
15/// different execution priorities (like main and irq).
16pub struct RingBuffer {
17 pub buf: AtomicPtr<u8>,
18 pub len: AtomicUsize,
19
20 // start and end wrap at len*2, not at len.
21 // This allows distinguishing "full" and "empty".
22 // full is when start+len == end (modulo len*2)
23 // empty is when start == end
24 //
25 // This avoids having to consider the ringbuffer "full" at len-1 instead of len.
26 // The usual solution is adding a "full" flag, but that can't be made atomic
27 pub start: AtomicUsize,
28 pub end: AtomicUsize,
29}
30
31pub struct Reader<'a>(&'a RingBuffer);
32pub struct Writer<'a>(&'a RingBuffer);
33
34impl RingBuffer {
35 /// Create a new empty ringbuffer.
36 pub const fn new() -> Self {
37 Self {
38 buf: AtomicPtr::new(core::ptr::null_mut()),
39 len: AtomicUsize::new(0),
40 start: AtomicUsize::new(0),
41 end: AtomicUsize::new(0),
42 }
43 }
44
45 /// Initialize the ring buffer with a buffer.
46 ///
47 /// # Safety
48 /// - The buffer (`buf .. buf+len`) must be valid memory until `deinit` is called.
49 /// - Must not be called concurrently with any other methods.
50 pub unsafe fn init(&self, buf: *mut u8, len: usize) {
51 // Ordering: it's OK to use `Relaxed` because this is not called
52 // concurrently with other methods.
53 self.buf.store(buf, Ordering::Relaxed);
54 self.len.store(len, Ordering::Relaxed);
55 self.start.store(0, Ordering::Relaxed);
56 self.end.store(0, Ordering::Relaxed);
57 }
58
59 /// Deinitialize the ringbuffer.
60 ///
61 /// After calling this, the ringbuffer becomes empty, as if it was
62 /// just created with `new()`.
63 ///
64 /// # Safety
65 /// - Must not be called concurrently with any other methods.
66 pub unsafe fn deinit(&self) {
67 // Ordering: it's OK to use `Relaxed` because this is not called
68 // concurrently with other methods.
69 self.len.store(0, Ordering::Relaxed);
70 self.start.store(0, Ordering::Relaxed);
71 self.end.store(0, Ordering::Relaxed);
72 }
73
74 /// Create a reader.
75 ///
76 /// # Safety
77 ///
78 /// Only one reader can exist at a time.
79 pub unsafe fn reader(&self) -> Reader<'_> {
80 Reader(self)
81 }
82
83 /// Create a writer.
84 ///
85 /// # Safety
86 ///
87 /// Only one writer can exist at a time.
88 pub unsafe fn writer(&self) -> Writer<'_> {
89 Writer(self)
90 }
91
92 pub fn len(&self) -> usize {
93 self.len.load(Ordering::Relaxed)
94 }
95
96 pub fn is_full(&self) -> bool {
97 let len = self.len.load(Ordering::Relaxed);
98 let start = self.start.load(Ordering::Relaxed);
99 let end = self.end.load(Ordering::Relaxed);
100
101 self.wrap(start + len) == end
102 }
103
104 pub fn is_empty(&self) -> bool {
105 let start = self.start.load(Ordering::Relaxed);
106 let end = self.end.load(Ordering::Relaxed);
107
108 start == end
109 }
110
111 fn wrap(&self, mut n: usize) -> usize {
112 let len = self.len.load(Ordering::Relaxed);
113
114 if n >= len * 2 {
115 n -= len * 2
116 }
117 n
118 }
119}
120
121impl<'a> Writer<'a> {
122 /// Push data into the buffer in-place.
123 ///
124 /// The closure `f` is called with a free part of the buffer, it must write
125 /// some data to it and return the amount of bytes written.
126 pub fn push(&mut self, f: impl FnOnce(&mut [u8]) -> usize) -> usize {
127 let (p, n) = self.push_buf();
128 let buf = unsafe { slice::from_raw_parts_mut(p, n) };
129 let n = f(buf);
130 self.push_done(n);
131 n
132 }
133
134 /// Push one data byte.
135 ///
136 /// Returns true if pushed successfully.
137 pub fn push_one(&mut self, val: u8) -> bool {
138 let n = self.push(|f| match f {
139 [] => 0,
140 [x, ..] => {
141 *x = val;
142 1
143 }
144 });
145 n != 0
146 }
147
148 /// Get a buffer where data can be pushed to.
149 ///
150 /// Equivalent to [`Self::push_buf`] but returns a slice.
151 pub fn push_slice(&mut self) -> &mut [u8] {
152 let (data, len) = self.push_buf();
153 unsafe { slice::from_raw_parts_mut(data, len) }
154 }
155
156 /// Get up to two buffers where data can be pushed to.
157 ///
158 /// Equivalent to [`Self::push_bufs`] but returns slices.
159 pub fn push_slices(&mut self) -> [&mut [u8]; 2] {
160 let [(d0, l0), (d1, l1)] = self.push_bufs();
161 unsafe { [slice::from_raw_parts_mut(d0, l0), slice::from_raw_parts_mut(d1, l1)] }
162 }
163
164 /// Get a buffer where data can be pushed to.
165 ///
166 /// Write data to the start of the buffer, then call `push_done` with
167 /// however many bytes you've pushed.
168 ///
169 /// The buffer is suitable to DMA to.
170 ///
171 /// If the ringbuf is full, size=0 will be returned.
172 ///
173 /// The buffer stays valid as long as no other `Writer` method is called
174 /// and `init`/`deinit` aren't called on the ringbuf.
175 pub fn push_buf(&mut self) -> (*mut u8, usize) {
176 // Ordering: popping writes `start` last, so we read `start` first.
177 // Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
178 let mut start = self.0.start.load(Ordering::Acquire);
179 let buf = self.0.buf.load(Ordering::Relaxed);
180 let len = self.0.len.load(Ordering::Relaxed);
181 let mut end = self.0.end.load(Ordering::Relaxed);
182
183 let empty = start == end;
184
185 if start >= len {
186 start -= len
187 }
188 if end >= len {
189 end -= len
190 }
191
192 if start == end && !empty {
193 // full
194 return (buf, 0);
195 }
196 let n = if start > end { start - end } else { len - end };
197
198 trace!(" ringbuf: push_buf {:?}..{:?}", end, end + n);
199 (unsafe { buf.add(end) }, n)
200 }
201
202 /// Get up to two buffers where data can be pushed to.
203 ///
204 /// Write data starting at the beginning of the first buffer, then call
205 /// `push_done` with however many bytes you've pushed.
206 ///
207 /// The buffers are suitable to DMA to.
208 ///
209 /// If the ringbuf is full, both buffers will be zero length.
210 /// If there is only area available, the second buffer will be zero length.
211 ///
212 /// The buffer stays valid as long as no other `Writer` method is called
213 /// and `init`/`deinit` aren't called on the ringbuf.
214 pub fn push_bufs(&mut self) -> [(*mut u8, usize); 2] {
215 // Ordering: as per push_buf()
216 let mut start = self.0.start.load(Ordering::Acquire);
217 let buf = self.0.buf.load(Ordering::Relaxed);
218 let len = self.0.len.load(Ordering::Relaxed);
219 let mut end = self.0.end.load(Ordering::Relaxed);
220
221 let empty = start == end;
222
223 if start >= len {
224 start -= len
225 }
226 if end >= len {
227 end -= len
228 }
229
230 if start == end && !empty {
231 // full
232 return [(buf, 0), (buf, 0)];
233 }
234 let n0 = if start > end { start - end } else { len - end };
235 let n1 = if start <= end { start } else { 0 };
236
237 trace!(" ringbuf: push_bufs [{:?}..{:?}, {:?}..{:?}]", end, end + n0, 0, n1);
238 [(unsafe { buf.add(end) }, n0), (buf, n1)]
239 }
240
241 pub fn push_done(&mut self, n: usize) {
242 trace!(" ringbuf: push {:?}", n);
243 let end = self.0.end.load(Ordering::Relaxed);
244
245 // Ordering: write `end` last, with Release ordering.
246 // The ordering ensures no preceding memory accesses (such as writing
247 // the actual data in the buffer) can be reordered down past it, which
248 // will guarantee the reader sees them after reading from `end`.
249 self.0.end.store(self.0.wrap(end + n), Ordering::Release);
250 }
251}
252
253impl<'a> Reader<'a> {
254 /// Pop data from the buffer in-place.
255 ///
256 /// The closure `f` is called with the next data, it must process
257 /// some data from it and return the amount of bytes processed.
258 pub fn pop(&mut self, f: impl FnOnce(&[u8]) -> usize) -> usize {
259 let (p, n) = self.pop_buf();
260 let buf = unsafe { slice::from_raw_parts(p, n) };
261 let n = f(buf);
262 self.pop_done(n);
263 n
264 }
265
266 /// Pop one data byte.
267 ///
268 /// Returns true if popped successfully.
269 pub fn pop_one(&mut self) -> Option<u8> {
270 let mut res = None;
271 self.pop(|f| match f {
272 &[] => 0,
273 &[x, ..] => {
274 res = Some(x);
275 1
276 }
277 });
278 res
279 }
280
281 /// Get a buffer where data can be popped from.
282 ///
283 /// Equivalent to [`Self::pop_buf`] but returns a slice.
284 pub fn pop_slice(&mut self) -> &mut [u8] {
285 let (data, len) = self.pop_buf();
286 unsafe { slice::from_raw_parts_mut(data, len) }
287 }
288
289 /// Get a buffer where data can be popped from.
290 ///
291 /// Read data from the start of the buffer, then call `pop_done` with
292 /// however many bytes you've processed.
293 ///
294 /// The buffer is suitable to DMA from.
295 ///
296 /// If the ringbuf is empty, size=0 will be returned.
297 ///
298 /// The buffer stays valid as long as no other `Reader` method is called
299 /// and `init`/`deinit` aren't called on the ringbuf.
300 pub fn pop_buf(&mut self) -> (*mut u8, usize) {
301 // Ordering: pushing writes `end` last, so we read `end` first.
302 // Read it with Acquire ordering, so that the next accesses can't be reordered up past it.
303 // This is needed to guarantee we "see" the data written by the writer.
304 let mut end = self.0.end.load(Ordering::Acquire);
305 let buf = self.0.buf.load(Ordering::Relaxed);
306 let len = self.0.len.load(Ordering::Relaxed);
307 let mut start = self.0.start.load(Ordering::Relaxed);
308
309 if start == end {
310 return (buf, 0);
311 }
312
313 if start >= len {
314 start -= len
315 }
316 if end >= len {
317 end -= len
318 }
319
320 let n = if end > start { end - start } else { len - start };
321
322 trace!(" ringbuf: pop_buf {:?}..{:?}", start, start + n);
323 (unsafe { buf.add(start) }, n)
324 }
325
326 pub fn pop_done(&mut self, n: usize) {
327 trace!(" ringbuf: pop {:?}", n);
328
329 let start = self.0.start.load(Ordering::Relaxed);
330
331 // Ordering: write `start` last, with Release ordering.
332 // The ordering ensures no preceding memory accesses (such as reading
333 // the actual data) can be reordered down past it. This is necessary
334 // because writing to `start` is effectively freeing the read part of the
335 // buffer, which "gives permission" to the writer to write to it again.
336 // Therefore, all buffer accesses must be completed before this.
337 self.0.start.store(self.0.wrap(start + n), Ordering::Release);
338 }
339}
340
341#[cfg(test)]
342mod tests {
343 use super::*;
344
345 #[test]
346 fn push_pop() {
347 let mut b = [0; 4];
348 let rb = RingBuffer::new();
349 unsafe {
350 rb.init(b.as_mut_ptr(), 4);
351
352 assert_eq!(rb.is_empty(), true);
353 assert_eq!(rb.is_full(), false);
354
355 rb.writer().push(|buf| {
356 assert_eq!(4, buf.len());
357 buf[0] = 1;
358 buf[1] = 2;
359 buf[2] = 3;
360 buf[3] = 4;
361 4
362 });
363
364 assert_eq!(rb.is_empty(), false);
365 assert_eq!(rb.is_full(), true);
366
367 rb.writer().push(|buf| {
368 // If it's full, we can push 0 bytes.
369 assert_eq!(0, buf.len());
370 0
371 });
372
373 assert_eq!(rb.is_empty(), false);
374 assert_eq!(rb.is_full(), true);
375
376 rb.reader().pop(|buf| {
377 assert_eq!(4, buf.len());
378 assert_eq!(1, buf[0]);
379 1
380 });
381
382 assert_eq!(rb.is_empty(), false);
383 assert_eq!(rb.is_full(), false);
384
385 rb.reader().pop(|buf| {
386 assert_eq!(3, buf.len());
387 0
388 });
389
390 assert_eq!(rb.is_empty(), false);
391 assert_eq!(rb.is_full(), false);
392
393 rb.reader().pop(|buf| {
394 assert_eq!(3, buf.len());
395 assert_eq!(2, buf[0]);
396 assert_eq!(3, buf[1]);
397 2
398 });
399 rb.reader().pop(|buf| {
400 assert_eq!(1, buf.len());
401 assert_eq!(4, buf[0]);
402 1
403 });
404
405 assert_eq!(rb.is_empty(), true);
406 assert_eq!(rb.is_full(), false);
407
408 rb.reader().pop(|buf| {
409 assert_eq!(0, buf.len());
410 0
411 });
412
413 rb.writer().push(|buf| {
414 assert_eq!(4, buf.len());
415 buf[0] = 10;
416 1
417 });
418
419 rb.writer().push(|buf| {
420 assert_eq!(3, buf.len());
421 buf[0] = 11;
422 buf[1] = 12;
423 2
424 });
425
426 assert_eq!(rb.is_empty(), false);
427 assert_eq!(rb.is_full(), false);
428
429 rb.writer().push(|buf| {
430 assert_eq!(1, buf.len());
431 buf[0] = 13;
432 1
433 });
434
435 assert_eq!(rb.is_empty(), false);
436 assert_eq!(rb.is_full(), true);
437 }
438 }
439
440 #[test]
441 fn zero_len() {
442 let rb = RingBuffer::new();
443 unsafe {
444 assert_eq!(rb.is_empty(), true);
445 assert_eq!(rb.is_full(), true);
446
447 rb.writer().push(|buf| {
448 assert_eq!(0, buf.len());
449 0
450 });
451
452 rb.reader().pop(|buf| {
453 assert_eq!(0, buf.len());
454 0
455 });
456 }
457 }
458
459 #[test]
460 fn push_slices() {
461 let mut b = [0; 4];
462 let rb = RingBuffer::new();
463 unsafe {
464 rb.init(b.as_mut_ptr(), 4);
465
466 /* push 3 -> [1 2 3 x] */
467 let mut w = rb.writer();
468 let ps = w.push_slices();
469 assert_eq!(4, ps[0].len());
470 assert_eq!(0, ps[1].len());
471 ps[0][0] = 1;
472 ps[0][1] = 2;
473 ps[0][2] = 3;
474 w.push_done(3);
475 drop(w);
476
477 /* pop 2 -> [x x 3 x] */
478 rb.reader().pop(|buf| {
479 assert_eq!(3, buf.len());
480 assert_eq!(1, buf[0]);
481 assert_eq!(2, buf[1]);
482 assert_eq!(3, buf[2]);
483 2
484 });
485
486 /* push 3 -> [5 6 3 4] */
487 let mut w = rb.writer();
488 let ps = w.push_slices();
489 assert_eq!(1, ps[0].len());
490 assert_eq!(2, ps[1].len());
491 ps[0][0] = 4;
492 ps[1][0] = 5;
493 ps[1][1] = 6;
494 w.push_done(3);
495 drop(w);
496
497 /* buf is now full */
498 let mut w = rb.writer();
499 let ps = w.push_slices();
500 assert_eq!(0, ps[0].len());
501 assert_eq!(0, ps[1].len());
502
503 /* pop 2 -> [5 6 x x] */
504 rb.reader().pop(|buf| {
505 assert_eq!(2, buf.len());
506 assert_eq!(3, buf[0]);
507 assert_eq!(4, buf[1]);
508 2
509 });
510
511 /* should now have one push slice again */
512 let mut w = rb.writer();
513 let ps = w.push_slices();
514 assert_eq!(2, ps[0].len());
515 assert_eq!(0, ps[1].len());
516 drop(w);
517
518 /* pop 2 -> [x x x x] */
519 rb.reader().pop(|buf| {
520 assert_eq!(2, buf.len());
521 assert_eq!(5, buf[0]);
522 assert_eq!(6, buf[1]);
523 2
524 });
525
526 /* should now have two push slices */
527 let mut w = rb.writer();
528 let ps = w.push_slices();
529 assert_eq!(2, ps[0].len());
530 assert_eq!(2, ps[1].len());
531 drop(w);
532
533 /* make sure we exercise all wrap around cases properly */
534 for _ in 0..10 {
535 /* should be empty, push 1 */
536 let mut w = rb.writer();
537 let ps = w.push_slices();
538 assert_eq!(4, ps[0].len() + ps[1].len());
539 w.push_done(1);
540 drop(w);
541
542 /* should have 1 element */
543 let mut w = rb.writer();
544 let ps = w.push_slices();
545 assert_eq!(3, ps[0].len() + ps[1].len());
546 drop(w);
547
548 /* pop 1 */
549 rb.reader().pop(|buf| {
550 assert_eq!(1, buf.len());
551 1
552 });
553 }
554 }
555 }
556}
diff --git a/embassy-hal-internal/src/drop.rs b/embassy-hal-internal/src/drop.rs
new file mode 100644
index 000000000..7cd16aaec
--- /dev/null
+++ b/embassy-hal-internal/src/drop.rs
@@ -0,0 +1,51 @@
1use core::mem;
2use core::mem::MaybeUninit;
3
4#[must_use = "to delay the drop handler invokation to the end of the scope"]
5pub struct OnDrop<F: FnOnce()> {
6 f: MaybeUninit<F>,
7}
8
9impl<F: FnOnce()> OnDrop<F> {
10 pub fn new(f: F) -> Self {
11 Self { f: MaybeUninit::new(f) }
12 }
13
14 pub fn defuse(self) {
15 mem::forget(self)
16 }
17}
18
19impl<F: FnOnce()> Drop for OnDrop<F> {
20 fn drop(&mut self) {
21 unsafe { self.f.as_ptr().read()() }
22 }
23}
24
25/// An explosive ordinance that panics if it is improperly disposed of.
26///
27/// This is to forbid dropping futures, when there is absolutely no other choice.
28///
29/// To correctly dispose of this device, call the [defuse](struct.DropBomb.html#method.defuse)
30/// method before this object is dropped.
31#[must_use = "to delay the drop bomb invokation to the end of the scope"]
32pub struct DropBomb {
33 _private: (),
34}
35
36impl DropBomb {
37 pub fn new() -> Self {
38 Self { _private: () }
39 }
40
41 /// Defuses the bomb, rendering it safe to drop.
42 pub fn defuse(self) {
43 mem::forget(self)
44 }
45}
46
47impl Drop for DropBomb {
48 fn drop(&mut self) {
49 panic!("boom")
50 }
51}
diff --git a/embassy-hal-internal/src/fmt.rs b/embassy-hal-internal/src/fmt.rs
new file mode 100644
index 000000000..066970813
--- /dev/null
+++ b/embassy-hal-internal/src/fmt.rs
@@ -0,0 +1,225 @@
1#![macro_use]
2#![allow(unused_macros)]
3
4#[cfg(all(feature = "defmt", feature = "log"))]
5compile_error!("You may not enable both `defmt` and `log` features.");
6
7macro_rules! assert {
8 ($($x:tt)*) => {
9 {
10 #[cfg(not(feature = "defmt"))]
11 ::core::assert!($($x)*);
12 #[cfg(feature = "defmt")]
13 ::defmt::assert!($($x)*);
14 }
15 };
16}
17
18macro_rules! assert_eq {
19 ($($x:tt)*) => {
20 {
21 #[cfg(not(feature = "defmt"))]
22 ::core::assert_eq!($($x)*);
23 #[cfg(feature = "defmt")]
24 ::defmt::assert_eq!($($x)*);
25 }
26 };
27}
28
29macro_rules! assert_ne {
30 ($($x:tt)*) => {
31 {
32 #[cfg(not(feature = "defmt"))]
33 ::core::assert_ne!($($x)*);
34 #[cfg(feature = "defmt")]
35 ::defmt::assert_ne!($($x)*);
36 }
37 };
38}
39
40macro_rules! debug_assert {
41 ($($x:tt)*) => {
42 {
43 #[cfg(not(feature = "defmt"))]
44 ::core::debug_assert!($($x)*);
45 #[cfg(feature = "defmt")]
46 ::defmt::debug_assert!($($x)*);
47 }
48 };
49}
50
51macro_rules! debug_assert_eq {
52 ($($x:tt)*) => {
53 {
54 #[cfg(not(feature = "defmt"))]
55 ::core::debug_assert_eq!($($x)*);
56 #[cfg(feature = "defmt")]
57 ::defmt::debug_assert_eq!($($x)*);
58 }
59 };
60}
61
62macro_rules! debug_assert_ne {
63 ($($x:tt)*) => {
64 {
65 #[cfg(not(feature = "defmt"))]
66 ::core::debug_assert_ne!($($x)*);
67 #[cfg(feature = "defmt")]
68 ::defmt::debug_assert_ne!($($x)*);
69 }
70 };
71}
72
73macro_rules! todo {
74 ($($x:tt)*) => {
75 {
76 #[cfg(not(feature = "defmt"))]
77 ::core::todo!($($x)*);
78 #[cfg(feature = "defmt")]
79 ::defmt::todo!($($x)*);
80 }
81 };
82}
83
84macro_rules! unreachable {
85 ($($x:tt)*) => {
86 {
87 #[cfg(not(feature = "defmt"))]
88 ::core::unreachable!($($x)*);
89 #[cfg(feature = "defmt")]
90 ::defmt::unreachable!($($x)*);
91 }
92 };
93}
94
95macro_rules! panic {
96 ($($x:tt)*) => {
97 {
98 #[cfg(not(feature = "defmt"))]
99 ::core::panic!($($x)*);
100 #[cfg(feature = "defmt")]
101 ::defmt::panic!($($x)*);
102 }
103 };
104}
105
106macro_rules! trace {
107 ($s:literal $(, $x:expr)* $(,)?) => {
108 {
109 #[cfg(feature = "log")]
110 ::log::trace!($s $(, $x)*);
111 #[cfg(feature = "defmt")]
112 ::defmt::trace!($s $(, $x)*);
113 #[cfg(not(any(feature = "log", feature="defmt")))]
114 let _ = ($( & $x ),*);
115 }
116 };
117}
118
119macro_rules! debug {
120 ($s:literal $(, $x:expr)* $(,)?) => {
121 {
122 #[cfg(feature = "log")]
123 ::log::debug!($s $(, $x)*);
124 #[cfg(feature = "defmt")]
125 ::defmt::debug!($s $(, $x)*);
126 #[cfg(not(any(feature = "log", feature="defmt")))]
127 let _ = ($( & $x ),*);
128 }
129 };
130}
131
132macro_rules! info {
133 ($s:literal $(, $x:expr)* $(,)?) => {
134 {
135 #[cfg(feature = "log")]
136 ::log::info!($s $(, $x)*);
137 #[cfg(feature = "defmt")]
138 ::defmt::info!($s $(, $x)*);
139 #[cfg(not(any(feature = "log", feature="defmt")))]
140 let _ = ($( & $x ),*);
141 }
142 };
143}
144
145macro_rules! warn {
146 ($s:literal $(, $x:expr)* $(,)?) => {
147 {
148 #[cfg(feature = "log")]
149 ::log::warn!($s $(, $x)*);
150 #[cfg(feature = "defmt")]
151 ::defmt::warn!($s $(, $x)*);
152 #[cfg(not(any(feature = "log", feature="defmt")))]
153 let _ = ($( & $x ),*);
154 }
155 };
156}
157
158macro_rules! error {
159 ($s:literal $(, $x:expr)* $(,)?) => {
160 {
161 #[cfg(feature = "log")]
162 ::log::error!($s $(, $x)*);
163 #[cfg(feature = "defmt")]
164 ::defmt::error!($s $(, $x)*);
165 #[cfg(not(any(feature = "log", feature="defmt")))]
166 let _ = ($( & $x ),*);
167 }
168 };
169}
170
171#[cfg(feature = "defmt")]
172macro_rules! unwrap {
173 ($($x:tt)*) => {
174 ::defmt::unwrap!($($x)*)
175 };
176}
177
178#[cfg(not(feature = "defmt"))]
179macro_rules! unwrap {
180 ($arg:expr) => {
181 match $crate::fmt::Try::into_result($arg) {
182 ::core::result::Result::Ok(t) => t,
183 ::core::result::Result::Err(e) => {
184 ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
185 }
186 }
187 };
188 ($arg:expr, $($msg:expr),+ $(,)? ) => {
189 match $crate::fmt::Try::into_result($arg) {
190 ::core::result::Result::Ok(t) => t,
191 ::core::result::Result::Err(e) => {
192 ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
193 }
194 }
195 }
196}
197
198#[derive(Debug, Copy, Clone, Eq, PartialEq)]
199pub struct NoneError;
200
201pub trait Try {
202 type Ok;
203 type Error;
204 fn into_result(self) -> Result<Self::Ok, Self::Error>;
205}
206
207impl<T> Try for Option<T> {
208 type Ok = T;
209 type Error = NoneError;
210
211 #[inline]
212 fn into_result(self) -> Result<T, NoneError> {
213 self.ok_or(NoneError)
214 }
215}
216
217impl<T, E> Try for Result<T, E> {
218 type Ok = T;
219 type Error = E;
220
221 #[inline]
222 fn into_result(self) -> Self {
223 self
224 }
225}
diff --git a/embassy-hal-internal/src/interrupt.rs b/embassy-hal-internal/src/interrupt.rs
new file mode 100644
index 000000000..b970aa2cd
--- /dev/null
+++ b/embassy-hal-internal/src/interrupt.rs
@@ -0,0 +1,846 @@
1//! Interrupt handling for cortex-m devices.
2use core::mem;
3use core::sync::atomic::{compiler_fence, Ordering};
4
5use cortex_m::interrupt::InterruptNumber;
6use cortex_m::peripheral::NVIC;
7
8/// Generate a standard `mod interrupt` for a HAL.
9#[macro_export]
10macro_rules! interrupt_mod {
11 ($($irqs:ident),* $(,)?) => {
12 #[cfg(feature = "rt")]
13 pub use cortex_m_rt::interrupt;
14
15 /// Interrupt definitions.
16 pub mod interrupt {
17 pub use $crate::interrupt::{InterruptExt, Priority};
18 pub use crate::pac::Interrupt::*;
19 pub use crate::pac::Interrupt;
20
21 /// Type-level interrupt infrastructure.
22 ///
23 /// This module contains one *type* per interrupt. This is used for checking at compile time that
24 /// the interrupts are correctly bound to HAL drivers.
25 ///
26 /// As an end user, you shouldn't need to use this module directly. Use the [`crate::bind_interrupts!`] macro
27 /// to bind interrupts, and the [`crate::interrupt`] module to manually register interrupt handlers and manipulate
28 /// interrupts directly (pending/unpending, enabling/disabling, setting the priority, etc...)
29 pub mod typelevel {
30 use super::InterruptExt;
31
32 mod sealed {
33 pub trait Interrupt {}
34 }
35
36 /// Type-level interrupt.
37 ///
38 /// This trait is implemented for all typelevel interrupt types in this module.
39 pub trait Interrupt: sealed::Interrupt {
40
41 /// Interrupt enum variant.
42 ///
43 /// This allows going from typelevel interrupts (one type per interrupt) to
44 /// non-typelevel interrupts (a single `Interrupt` enum type, with one variant per interrupt).
45 const IRQ: super::Interrupt;
46
47 /// Enable the interrupt.
48 #[inline]
49 unsafe fn enable() {
50 Self::IRQ.enable()
51 }
52
53 /// Disable the interrupt.
54 #[inline]
55 fn disable() {
56 Self::IRQ.disable()
57 }
58
59 /// Check if interrupt is enabled.
60 #[inline]
61 fn is_enabled() -> bool {
62 Self::IRQ.is_enabled()
63 }
64
65 /// Check if interrupt is pending.
66 #[inline]
67 fn is_pending() -> bool {
68 Self::IRQ.is_pending()
69 }
70
71 /// Set interrupt pending.
72 #[inline]
73 fn pend() {
74 Self::IRQ.pend()
75 }
76
77 /// Unset interrupt pending.
78 #[inline]
79 fn unpend() {
80 Self::IRQ.unpend()
81 }
82
83 /// Get the priority of the interrupt.
84 #[inline]
85 fn get_priority() -> crate::interrupt::Priority {
86 Self::IRQ.get_priority()
87 }
88
89 /// Set the interrupt priority.
90 #[inline]
91 fn set_priority(prio: crate::interrupt::Priority) {
92 Self::IRQ.set_priority(prio)
93 }
94 }
95
96 $(
97 #[allow(non_camel_case_types)]
98 #[doc=stringify!($irqs)]
99 #[doc=" typelevel interrupt."]
100 pub enum $irqs {}
101 impl sealed::Interrupt for $irqs{}
102 impl Interrupt for $irqs {
103 const IRQ: super::Interrupt = super::Interrupt::$irqs;
104 }
105 )*
106
107 /// Interrupt handler trait.
108 ///
109 /// Drivers that need to handle interrupts implement this trait.
110 /// The user must ensure `on_interrupt()` is called every time the interrupt fires.
111 /// Drivers must use use [`Binding`] to assert at compile time that the user has done so.
112 pub trait Handler<I: Interrupt> {
113 /// Interrupt handler function.
114 ///
115 /// Must be called every time the `I` interrupt fires, synchronously from
116 /// the interrupt handler context.
117 ///
118 /// # Safety
119 ///
120 /// This function must ONLY be called from the interrupt handler for `I`.
121 unsafe fn on_interrupt();
122 }
123
124 /// Compile-time assertion that an interrupt has been bound to a handler.
125 ///
126 /// For the vast majority of cases, you should use the `bind_interrupts!`
127 /// macro instead of writing `unsafe impl`s of this trait.
128 ///
129 /// # Safety
130 ///
131 /// By implementing this trait, you are asserting that you have arranged for `H::on_interrupt()`
132 /// to be called every time the `I` interrupt fires.
133 ///
134 /// This allows drivers to check bindings at compile-time.
135 pub unsafe trait Binding<I: Interrupt, H: Handler<I>> {}
136 }
137 }
138 };
139}
140
141/// Represents an interrupt type that can be configured by embassy to handle
142/// interrupts.
143pub unsafe trait InterruptExt: InterruptNumber + Copy {
144 /// Enable the interrupt.
145 #[inline]
146 unsafe fn enable(self) {
147 compiler_fence(Ordering::SeqCst);
148 NVIC::unmask(self)
149 }
150
151 /// Disable the interrupt.
152 #[inline]
153 fn disable(self) {
154 NVIC::mask(self);
155 compiler_fence(Ordering::SeqCst);
156 }
157
158 /// Check if interrupt is being handled.
159 #[inline]
160 #[cfg(not(armv6m))]
161 fn is_active(self) -> bool {
162 NVIC::is_active(self)
163 }
164
165 /// Check if interrupt is enabled.
166 #[inline]
167 fn is_enabled(self) -> bool {
168 NVIC::is_enabled(self)
169 }
170
171 /// Check if interrupt is pending.
172 #[inline]
173 fn is_pending(self) -> bool {
174 NVIC::is_pending(self)
175 }
176
177 /// Set interrupt pending.
178 #[inline]
179 fn pend(self) {
180 NVIC::pend(self)
181 }
182
183 /// Unset interrupt pending.
184 #[inline]
185 fn unpend(self) {
186 NVIC::unpend(self)
187 }
188
189 /// Get the priority of the interrupt.
190 #[inline]
191 fn get_priority(self) -> Priority {
192 Priority::from(NVIC::get_priority(self))
193 }
194
195 /// Set the interrupt priority.
196 #[inline]
197 fn set_priority(self, prio: Priority) {
198 critical_section::with(|_| unsafe {
199 let mut nvic: cortex_m::peripheral::NVIC = mem::transmute(());
200 nvic.set_priority(self, prio.into())
201 })
202 }
203}
204
205unsafe impl<T: InterruptNumber + Copy> InterruptExt for T {}
206
207impl From<u8> for Priority {
208 fn from(priority: u8) -> Self {
209 unsafe { mem::transmute(priority & PRIO_MASK) }
210 }
211}
212
213impl From<Priority> for u8 {
214 fn from(p: Priority) -> Self {
215 p as u8
216 }
217}
218
219#[cfg(feature = "prio-bits-0")]
220const PRIO_MASK: u8 = 0x00;
221#[cfg(feature = "prio-bits-1")]
222const PRIO_MASK: u8 = 0x80;
223#[cfg(feature = "prio-bits-2")]
224const PRIO_MASK: u8 = 0xc0;
225#[cfg(feature = "prio-bits-3")]
226const PRIO_MASK: u8 = 0xe0;
227#[cfg(feature = "prio-bits-4")]
228const PRIO_MASK: u8 = 0xf0;
229#[cfg(feature = "prio-bits-5")]
230const PRIO_MASK: u8 = 0xf8;
231#[cfg(feature = "prio-bits-6")]
232const PRIO_MASK: u8 = 0xfc;
233#[cfg(feature = "prio-bits-7")]
234const PRIO_MASK: u8 = 0xfe;
235#[cfg(feature = "prio-bits-8")]
236const PRIO_MASK: u8 = 0xff;
237
238/// The interrupt priority level.
239///
240/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
241#[cfg(feature = "prio-bits-0")]
242#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
243#[cfg_attr(feature = "defmt", derive(defmt::Format))]
244#[repr(u8)]
245#[allow(missing_docs)]
246pub enum Priority {
247 P0 = 0x0,
248}
249
250/// The interrupt priority level.
251///
252/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
253#[cfg(feature = "prio-bits-1")]
254#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
255#[cfg_attr(feature = "defmt", derive(defmt::Format))]
256#[repr(u8)]
257#[allow(missing_docs)]
258pub enum Priority {
259 P0 = 0x0,
260 P1 = 0x80,
261}
262
263/// The interrupt priority level.
264///
265/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
266#[cfg(feature = "prio-bits-2")]
267#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
268#[cfg_attr(feature = "defmt", derive(defmt::Format))]
269#[repr(u8)]
270#[allow(missing_docs)]
271pub enum Priority {
272 P0 = 0x0,
273 P1 = 0x40,
274 P2 = 0x80,
275 P3 = 0xc0,
276}
277
278/// The interrupt priority level.
279///
280/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
281#[cfg(feature = "prio-bits-3")]
282#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
283#[cfg_attr(feature = "defmt", derive(defmt::Format))]
284#[repr(u8)]
285#[allow(missing_docs)]
286pub enum Priority {
287 P0 = 0x0,
288 P1 = 0x20,
289 P2 = 0x40,
290 P3 = 0x60,
291 P4 = 0x80,
292 P5 = 0xa0,
293 P6 = 0xc0,
294 P7 = 0xe0,
295}
296
297/// The interrupt priority level.
298///
299/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
300#[cfg(feature = "prio-bits-4")]
301#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
302#[cfg_attr(feature = "defmt", derive(defmt::Format))]
303#[repr(u8)]
304#[allow(missing_docs)]
305pub enum Priority {
306 P0 = 0x0,
307 P1 = 0x10,
308 P2 = 0x20,
309 P3 = 0x30,
310 P4 = 0x40,
311 P5 = 0x50,
312 P6 = 0x60,
313 P7 = 0x70,
314 P8 = 0x80,
315 P9 = 0x90,
316 P10 = 0xa0,
317 P11 = 0xb0,
318 P12 = 0xc0,
319 P13 = 0xd0,
320 P14 = 0xe0,
321 P15 = 0xf0,
322}
323
324/// The interrupt priority level.
325///
326/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
327#[cfg(feature = "prio-bits-5")]
328#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
329#[cfg_attr(feature = "defmt", derive(defmt::Format))]
330#[repr(u8)]
331#[allow(missing_docs)]
332pub enum Priority {
333 P0 = 0x0,
334 P1 = 0x8,
335 P2 = 0x10,
336 P3 = 0x18,
337 P4 = 0x20,
338 P5 = 0x28,
339 P6 = 0x30,
340 P7 = 0x38,
341 P8 = 0x40,
342 P9 = 0x48,
343 P10 = 0x50,
344 P11 = 0x58,
345 P12 = 0x60,
346 P13 = 0x68,
347 P14 = 0x70,
348 P15 = 0x78,
349 P16 = 0x80,
350 P17 = 0x88,
351 P18 = 0x90,
352 P19 = 0x98,
353 P20 = 0xa0,
354 P21 = 0xa8,
355 P22 = 0xb0,
356 P23 = 0xb8,
357 P24 = 0xc0,
358 P25 = 0xc8,
359 P26 = 0xd0,
360 P27 = 0xd8,
361 P28 = 0xe0,
362 P29 = 0xe8,
363 P30 = 0xf0,
364 P31 = 0xf8,
365}
366
367/// The interrupt priority level.
368///
369/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
370#[cfg(feature = "prio-bits-6")]
371#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
372#[cfg_attr(feature = "defmt", derive(defmt::Format))]
373#[repr(u8)]
374#[allow(missing_docs)]
375pub enum Priority {
376 P0 = 0x0,
377 P1 = 0x4,
378 P2 = 0x8,
379 P3 = 0xc,
380 P4 = 0x10,
381 P5 = 0x14,
382 P6 = 0x18,
383 P7 = 0x1c,
384 P8 = 0x20,
385 P9 = 0x24,
386 P10 = 0x28,
387 P11 = 0x2c,
388 P12 = 0x30,
389 P13 = 0x34,
390 P14 = 0x38,
391 P15 = 0x3c,
392 P16 = 0x40,
393 P17 = 0x44,
394 P18 = 0x48,
395 P19 = 0x4c,
396 P20 = 0x50,
397 P21 = 0x54,
398 P22 = 0x58,
399 P23 = 0x5c,
400 P24 = 0x60,
401 P25 = 0x64,
402 P26 = 0x68,
403 P27 = 0x6c,
404 P28 = 0x70,
405 P29 = 0x74,
406 P30 = 0x78,
407 P31 = 0x7c,
408 P32 = 0x80,
409 P33 = 0x84,
410 P34 = 0x88,
411 P35 = 0x8c,
412 P36 = 0x90,
413 P37 = 0x94,
414 P38 = 0x98,
415 P39 = 0x9c,
416 P40 = 0xa0,
417 P41 = 0xa4,
418 P42 = 0xa8,
419 P43 = 0xac,
420 P44 = 0xb0,
421 P45 = 0xb4,
422 P46 = 0xb8,
423 P47 = 0xbc,
424 P48 = 0xc0,
425 P49 = 0xc4,
426 P50 = 0xc8,
427 P51 = 0xcc,
428 P52 = 0xd0,
429 P53 = 0xd4,
430 P54 = 0xd8,
431 P55 = 0xdc,
432 P56 = 0xe0,
433 P57 = 0xe4,
434 P58 = 0xe8,
435 P59 = 0xec,
436 P60 = 0xf0,
437 P61 = 0xf4,
438 P62 = 0xf8,
439 P63 = 0xfc,
440}
441
442/// The interrupt priority level.
443///
444/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
445#[cfg(feature = "prio-bits-7")]
446#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
447#[cfg_attr(feature = "defmt", derive(defmt::Format))]
448#[repr(u8)]
449#[allow(missing_docs)]
450pub enum Priority {
451 P0 = 0x0,
452 P1 = 0x2,
453 P2 = 0x4,
454 P3 = 0x6,
455 P4 = 0x8,
456 P5 = 0xa,
457 P6 = 0xc,
458 P7 = 0xe,
459 P8 = 0x10,
460 P9 = 0x12,
461 P10 = 0x14,
462 P11 = 0x16,
463 P12 = 0x18,
464 P13 = 0x1a,
465 P14 = 0x1c,
466 P15 = 0x1e,
467 P16 = 0x20,
468 P17 = 0x22,
469 P18 = 0x24,
470 P19 = 0x26,
471 P20 = 0x28,
472 P21 = 0x2a,
473 P22 = 0x2c,
474 P23 = 0x2e,
475 P24 = 0x30,
476 P25 = 0x32,
477 P26 = 0x34,
478 P27 = 0x36,
479 P28 = 0x38,
480 P29 = 0x3a,
481 P30 = 0x3c,
482 P31 = 0x3e,
483 P32 = 0x40,
484 P33 = 0x42,
485 P34 = 0x44,
486 P35 = 0x46,
487 P36 = 0x48,
488 P37 = 0x4a,
489 P38 = 0x4c,
490 P39 = 0x4e,
491 P40 = 0x50,
492 P41 = 0x52,
493 P42 = 0x54,
494 P43 = 0x56,
495 P44 = 0x58,
496 P45 = 0x5a,
497 P46 = 0x5c,
498 P47 = 0x5e,
499 P48 = 0x60,
500 P49 = 0x62,
501 P50 = 0x64,
502 P51 = 0x66,
503 P52 = 0x68,
504 P53 = 0x6a,
505 P54 = 0x6c,
506 P55 = 0x6e,
507 P56 = 0x70,
508 P57 = 0x72,
509 P58 = 0x74,
510 P59 = 0x76,
511 P60 = 0x78,
512 P61 = 0x7a,
513 P62 = 0x7c,
514 P63 = 0x7e,
515 P64 = 0x80,
516 P65 = 0x82,
517 P66 = 0x84,
518 P67 = 0x86,
519 P68 = 0x88,
520 P69 = 0x8a,
521 P70 = 0x8c,
522 P71 = 0x8e,
523 P72 = 0x90,
524 P73 = 0x92,
525 P74 = 0x94,
526 P75 = 0x96,
527 P76 = 0x98,
528 P77 = 0x9a,
529 P78 = 0x9c,
530 P79 = 0x9e,
531 P80 = 0xa0,
532 P81 = 0xa2,
533 P82 = 0xa4,
534 P83 = 0xa6,
535 P84 = 0xa8,
536 P85 = 0xaa,
537 P86 = 0xac,
538 P87 = 0xae,
539 P88 = 0xb0,
540 P89 = 0xb2,
541 P90 = 0xb4,
542 P91 = 0xb6,
543 P92 = 0xb8,
544 P93 = 0xba,
545 P94 = 0xbc,
546 P95 = 0xbe,
547 P96 = 0xc0,
548 P97 = 0xc2,
549 P98 = 0xc4,
550 P99 = 0xc6,
551 P100 = 0xc8,
552 P101 = 0xca,
553 P102 = 0xcc,
554 P103 = 0xce,
555 P104 = 0xd0,
556 P105 = 0xd2,
557 P106 = 0xd4,
558 P107 = 0xd6,
559 P108 = 0xd8,
560 P109 = 0xda,
561 P110 = 0xdc,
562 P111 = 0xde,
563 P112 = 0xe0,
564 P113 = 0xe2,
565 P114 = 0xe4,
566 P115 = 0xe6,
567 P116 = 0xe8,
568 P117 = 0xea,
569 P118 = 0xec,
570 P119 = 0xee,
571 P120 = 0xf0,
572 P121 = 0xf2,
573 P122 = 0xf4,
574 P123 = 0xf6,
575 P124 = 0xf8,
576 P125 = 0xfa,
577 P126 = 0xfc,
578 P127 = 0xfe,
579}
580
581/// The interrupt priority level.
582///
583/// NOTE: The contents of this enum differ according to the set `prio-bits-*` Cargo feature.
584#[cfg(feature = "prio-bits-8")]
585#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
586#[cfg_attr(feature = "defmt", derive(defmt::Format))]
587#[repr(u8)]
588#[allow(missing_docs)]
589pub enum Priority {
590 P0 = 0x0,
591 P1 = 0x1,
592 P2 = 0x2,
593 P3 = 0x3,
594 P4 = 0x4,
595 P5 = 0x5,
596 P6 = 0x6,
597 P7 = 0x7,
598 P8 = 0x8,
599 P9 = 0x9,
600 P10 = 0xa,
601 P11 = 0xb,
602 P12 = 0xc,
603 P13 = 0xd,
604 P14 = 0xe,
605 P15 = 0xf,
606 P16 = 0x10,
607 P17 = 0x11,
608 P18 = 0x12,
609 P19 = 0x13,
610 P20 = 0x14,
611 P21 = 0x15,
612 P22 = 0x16,
613 P23 = 0x17,
614 P24 = 0x18,
615 P25 = 0x19,
616 P26 = 0x1a,
617 P27 = 0x1b,
618 P28 = 0x1c,
619 P29 = 0x1d,
620 P30 = 0x1e,
621 P31 = 0x1f,
622 P32 = 0x20,
623 P33 = 0x21,
624 P34 = 0x22,
625 P35 = 0x23,
626 P36 = 0x24,
627 P37 = 0x25,
628 P38 = 0x26,
629 P39 = 0x27,
630 P40 = 0x28,
631 P41 = 0x29,
632 P42 = 0x2a,
633 P43 = 0x2b,
634 P44 = 0x2c,
635 P45 = 0x2d,
636 P46 = 0x2e,
637 P47 = 0x2f,
638 P48 = 0x30,
639 P49 = 0x31,
640 P50 = 0x32,
641 P51 = 0x33,
642 P52 = 0x34,
643 P53 = 0x35,
644 P54 = 0x36,
645 P55 = 0x37,
646 P56 = 0x38,
647 P57 = 0x39,
648 P58 = 0x3a,
649 P59 = 0x3b,
650 P60 = 0x3c,
651 P61 = 0x3d,
652 P62 = 0x3e,
653 P63 = 0x3f,
654 P64 = 0x40,
655 P65 = 0x41,
656 P66 = 0x42,
657 P67 = 0x43,
658 P68 = 0x44,
659 P69 = 0x45,
660 P70 = 0x46,
661 P71 = 0x47,
662 P72 = 0x48,
663 P73 = 0x49,
664 P74 = 0x4a,
665 P75 = 0x4b,
666 P76 = 0x4c,
667 P77 = 0x4d,
668 P78 = 0x4e,
669 P79 = 0x4f,
670 P80 = 0x50,
671 P81 = 0x51,
672 P82 = 0x52,
673 P83 = 0x53,
674 P84 = 0x54,
675 P85 = 0x55,
676 P86 = 0x56,
677 P87 = 0x57,
678 P88 = 0x58,
679 P89 = 0x59,
680 P90 = 0x5a,
681 P91 = 0x5b,
682 P92 = 0x5c,
683 P93 = 0x5d,
684 P94 = 0x5e,
685 P95 = 0x5f,
686 P96 = 0x60,
687 P97 = 0x61,
688 P98 = 0x62,
689 P99 = 0x63,
690 P100 = 0x64,
691 P101 = 0x65,
692 P102 = 0x66,
693 P103 = 0x67,
694 P104 = 0x68,
695 P105 = 0x69,
696 P106 = 0x6a,
697 P107 = 0x6b,
698 P108 = 0x6c,
699 P109 = 0x6d,
700 P110 = 0x6e,
701 P111 = 0x6f,
702 P112 = 0x70,
703 P113 = 0x71,
704 P114 = 0x72,
705 P115 = 0x73,
706 P116 = 0x74,
707 P117 = 0x75,
708 P118 = 0x76,
709 P119 = 0x77,
710 P120 = 0x78,
711 P121 = 0x79,
712 P122 = 0x7a,
713 P123 = 0x7b,
714 P124 = 0x7c,
715 P125 = 0x7d,
716 P126 = 0x7e,
717 P127 = 0x7f,
718 P128 = 0x80,
719 P129 = 0x81,
720 P130 = 0x82,
721 P131 = 0x83,
722 P132 = 0x84,
723 P133 = 0x85,
724 P134 = 0x86,
725 P135 = 0x87,
726 P136 = 0x88,
727 P137 = 0x89,
728 P138 = 0x8a,
729 P139 = 0x8b,
730 P140 = 0x8c,
731 P141 = 0x8d,
732 P142 = 0x8e,
733 P143 = 0x8f,
734 P144 = 0x90,
735 P145 = 0x91,
736 P146 = 0x92,
737 P147 = 0x93,
738 P148 = 0x94,
739 P149 = 0x95,
740 P150 = 0x96,
741 P151 = 0x97,
742 P152 = 0x98,
743 P153 = 0x99,
744 P154 = 0x9a,
745 P155 = 0x9b,
746 P156 = 0x9c,
747 P157 = 0x9d,
748 P158 = 0x9e,
749 P159 = 0x9f,
750 P160 = 0xa0,
751 P161 = 0xa1,
752 P162 = 0xa2,
753 P163 = 0xa3,
754 P164 = 0xa4,
755 P165 = 0xa5,
756 P166 = 0xa6,
757 P167 = 0xa7,
758 P168 = 0xa8,
759 P169 = 0xa9,
760 P170 = 0xaa,
761 P171 = 0xab,
762 P172 = 0xac,
763 P173 = 0xad,
764 P174 = 0xae,
765 P175 = 0xaf,
766 P176 = 0xb0,
767 P177 = 0xb1,
768 P178 = 0xb2,
769 P179 = 0xb3,
770 P180 = 0xb4,
771 P181 = 0xb5,
772 P182 = 0xb6,
773 P183 = 0xb7,
774 P184 = 0xb8,
775 P185 = 0xb9,
776 P186 = 0xba,
777 P187 = 0xbb,
778 P188 = 0xbc,
779 P189 = 0xbd,
780 P190 = 0xbe,
781 P191 = 0xbf,
782 P192 = 0xc0,
783 P193 = 0xc1,
784 P194 = 0xc2,
785 P195 = 0xc3,
786 P196 = 0xc4,
787 P197 = 0xc5,
788 P198 = 0xc6,
789 P199 = 0xc7,
790 P200 = 0xc8,
791 P201 = 0xc9,
792 P202 = 0xca,
793 P203 = 0xcb,
794 P204 = 0xcc,
795 P205 = 0xcd,
796 P206 = 0xce,
797 P207 = 0xcf,
798 P208 = 0xd0,
799 P209 = 0xd1,
800 P210 = 0xd2,
801 P211 = 0xd3,
802 P212 = 0xd4,
803 P213 = 0xd5,
804 P214 = 0xd6,
805 P215 = 0xd7,
806 P216 = 0xd8,
807 P217 = 0xd9,
808 P218 = 0xda,
809 P219 = 0xdb,
810 P220 = 0xdc,
811 P221 = 0xdd,
812 P222 = 0xde,
813 P223 = 0xdf,
814 P224 = 0xe0,
815 P225 = 0xe1,
816 P226 = 0xe2,
817 P227 = 0xe3,
818 P228 = 0xe4,
819 P229 = 0xe5,
820 P230 = 0xe6,
821 P231 = 0xe7,
822 P232 = 0xe8,
823 P233 = 0xe9,
824 P234 = 0xea,
825 P235 = 0xeb,
826 P236 = 0xec,
827 P237 = 0xed,
828 P238 = 0xee,
829 P239 = 0xef,
830 P240 = 0xf0,
831 P241 = 0xf1,
832 P242 = 0xf2,
833 P243 = 0xf3,
834 P244 = 0xf4,
835 P245 = 0xf5,
836 P246 = 0xf6,
837 P247 = 0xf7,
838 P248 = 0xf8,
839 P249 = 0xf9,
840 P250 = 0xfa,
841 P251 = 0xfb,
842 P252 = 0xfc,
843 P253 = 0xfd,
844 P254 = 0xfe,
845 P255 = 0xff,
846}
diff --git a/embassy-hal-internal/src/lib.rs b/embassy-hal-internal/src/lib.rs
new file mode 100644
index 000000000..3640ea184
--- /dev/null
+++ b/embassy-hal-internal/src/lib.rs
@@ -0,0 +1,17 @@
1#![no_std]
2#![allow(clippy::new_without_default)]
3#![doc = include_str!("../README.md")]
4
5// This mod MUST go first, so that the others see its macros.
6pub(crate) mod fmt;
7
8pub mod atomic_ring_buffer;
9pub mod drop;
10mod macros;
11mod peripheral;
12pub mod ratio;
13pub mod ring_buffer;
14pub use peripheral::{Peripheral, PeripheralRef};
15
16#[cfg(feature = "cortex-m")]
17pub mod interrupt;
diff --git a/embassy-hal-internal/src/macros.rs b/embassy-hal-internal/src/macros.rs
new file mode 100644
index 000000000..f06b46002
--- /dev/null
+++ b/embassy-hal-internal/src/macros.rs
@@ -0,0 +1,123 @@
1#[macro_export]
2macro_rules! peripherals_definition {
3 ($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
4 /// Types for the peripheral singletons.
5 pub mod peripherals {
6 $(
7 $(#[$cfg])?
8 #[allow(non_camel_case_types)]
9 #[doc = concat!(stringify!($name), " peripheral")]
10 pub struct $name { _private: () }
11
12 $(#[$cfg])?
13 impl $name {
14 /// Unsafely create an instance of this peripheral out of thin air.
15 ///
16 /// # Safety
17 ///
18 /// You must ensure that you're only using one instance of this type at a time.
19 #[inline]
20 pub unsafe fn steal() -> Self {
21 Self{ _private: ()}
22 }
23 }
24
25 $(#[$cfg])?
26 $crate::impl_peripheral!($name);
27 )*
28 }
29 };
30}
31
32#[macro_export]
33macro_rules! peripherals_struct {
34 ($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
35 /// Struct containing all the peripheral singletons.
36 ///
37 /// To obtain the peripherals, you must initialize the HAL, by calling [`crate::init`].
38 #[allow(non_snake_case)]
39 pub struct Peripherals {
40 $(
41 #[doc = concat!(stringify!($name), " peripheral")]
42 $(#[$cfg])?
43 pub $name: peripherals::$name,
44 )*
45 }
46
47 impl Peripherals {
48 ///Returns all the peripherals *once*
49 #[inline]
50 pub(crate) fn take() -> Self {
51
52 #[no_mangle]
53 static mut _EMBASSY_DEVICE_PERIPHERALS: bool = false;
54
55 critical_section::with(|_| unsafe {
56 if _EMBASSY_DEVICE_PERIPHERALS {
57 panic!("init called more than once!")
58 }
59 _EMBASSY_DEVICE_PERIPHERALS = true;
60 Self::steal()
61 })
62 }
63 }
64
65 impl Peripherals {
66 /// Unsafely create an instance of this peripheral out of thin air.
67 ///
68 /// # Safety
69 ///
70 /// You must ensure that you're only using one instance of this type at a time.
71 #[inline]
72 pub unsafe fn steal() -> Self {
73 Self {
74 $(
75 $(#[$cfg])?
76 $name: peripherals::$name::steal(),
77 )*
78 }
79 }
80 }
81 };
82}
83
84#[macro_export]
85macro_rules! peripherals {
86 ($($(#[$cfg:meta])? $name:ident),*$(,)?) => {
87 $crate::peripherals_definition!(
88 $(
89 $(#[$cfg])?
90 $name,
91 )*
92 );
93 $crate::peripherals_struct!(
94 $(
95 $(#[$cfg])?
96 $name,
97 )*
98 );
99 };
100}
101
102#[macro_export]
103macro_rules! into_ref {
104 ($($name:ident),*) => {
105 $(
106 let mut $name = $name.into_ref();
107 )*
108 }
109}
110
111#[macro_export]
112macro_rules! impl_peripheral {
113 ($type:ident) => {
114 impl $crate::Peripheral for $type {
115 type P = $type;
116
117 #[inline]
118 unsafe fn clone_unchecked(&self) -> Self::P {
119 $type { ..*self }
120 }
121 }
122 };
123}
diff --git a/embassy-hal-internal/src/peripheral.rs b/embassy-hal-internal/src/peripheral.rs
new file mode 100644
index 000000000..38b4c452e
--- /dev/null
+++ b/embassy-hal-internal/src/peripheral.rs
@@ -0,0 +1,174 @@
1use core::marker::PhantomData;
2use core::ops::{Deref, DerefMut};
3
4/// An exclusive reference to a peripheral.
5///
6/// This is functionally the same as a `&'a mut T`. There's a few advantages in having
7/// a dedicated struct instead:
8///
9/// - Memory efficiency: Peripheral singletons are typically either zero-sized (for concrete
10/// peripherals like `PA9` or `SPI4`) or very small (for example `AnyPin`, which is 1 byte).
11/// However `&mut T` is always 4 bytes for 32-bit targets, even if T is zero-sized.
12/// PeripheralRef stores a copy of `T` instead, so it's the same size.
13/// - Code size efficiency. If the user uses the same driver with both `SPI4` and `&mut SPI4`,
14/// the driver code would be monomorphized two times. With PeripheralRef, the driver is generic
15/// over a lifetime only. `SPI4` becomes `PeripheralRef<'static, SPI4>`, and `&mut SPI4` becomes
16/// `PeripheralRef<'a, SPI4>`. Lifetimes don't cause monomorphization.
17pub struct PeripheralRef<'a, T> {
18 inner: T,
19 _lifetime: PhantomData<&'a mut T>,
20}
21
22impl<'a, T> PeripheralRef<'a, T> {
23 #[inline]
24 pub fn new(inner: T) -> Self {
25 Self {
26 inner,
27 _lifetime: PhantomData,
28 }
29 }
30
31 /// Unsafely clone (duplicate) a peripheral singleton.
32 ///
33 /// # Safety
34 ///
35 /// This returns an owned clone of the peripheral. You must manually ensure
36 /// only one copy of the peripheral is in use at a time. For example, don't
37 /// create two SPI drivers on `SPI1`, because they will "fight" each other.
38 ///
39 /// You should strongly prefer using `reborrow()` instead. It returns a
40 /// `PeripheralRef` that borrows `self`, which allows the borrow checker
41 /// to enforce this at compile time.
42 pub unsafe fn clone_unchecked(&self) -> PeripheralRef<'a, T>
43 where
44 T: Peripheral<P = T>,
45 {
46 PeripheralRef::new(self.inner.clone_unchecked())
47 }
48
49 /// Reborrow into a "child" PeripheralRef.
50 ///
51 /// `self` will stay borrowed until the child PeripheralRef is dropped.
52 pub fn reborrow(&mut self) -> PeripheralRef<'_, T>
53 where
54 T: Peripheral<P = T>,
55 {
56 // safety: we're returning the clone inside a new PeripheralRef that borrows
57 // self, so user code can't use both at the same time.
58 PeripheralRef::new(unsafe { self.inner.clone_unchecked() })
59 }
60
61 /// Map the inner peripheral using `Into`.
62 ///
63 /// This converts from `PeripheralRef<'a, T>` to `PeripheralRef<'a, U>`, using an
64 /// `Into` impl to convert from `T` to `U`.
65 ///
66 /// For example, this can be useful to degrade GPIO pins: converting from PeripheralRef<'a, PB11>` to `PeripheralRef<'a, AnyPin>`.
67 #[inline]
68 pub fn map_into<U>(self) -> PeripheralRef<'a, U>
69 where
70 T: Into<U>,
71 {
72 PeripheralRef {
73 inner: self.inner.into(),
74 _lifetime: PhantomData,
75 }
76 }
77}
78
79impl<'a, T> Deref for PeripheralRef<'a, T> {
80 type Target = T;
81
82 #[inline]
83 fn deref(&self) -> &Self::Target {
84 &self.inner
85 }
86}
87
88impl<'a, T> DerefMut for PeripheralRef<'a, T> {
89 #[inline]
90 fn deref_mut(&mut self) -> &mut Self::Target {
91 &mut self.inner
92 }
93}
94
95/// Trait for any type that can be used as a peripheral of type `P`.
96///
97/// This is used in driver constructors, to allow passing either owned peripherals (e.g. `TWISPI0`),
98/// or borrowed peripherals (e.g. `&mut TWISPI0`).
99///
100/// For example, if you have a driver with a constructor like this:
101///
102/// ```ignore
103/// impl<'d, T: Instance> Twim<'d, T> {
104/// pub fn new(
105/// twim: impl Peripheral<P = T> + 'd,
106/// irq: impl Peripheral<P = T::Interrupt> + 'd,
107/// sda: impl Peripheral<P = impl GpioPin> + 'd,
108/// scl: impl Peripheral<P = impl GpioPin> + 'd,
109/// config: Config,
110/// ) -> Self { .. }
111/// }
112/// ```
113///
114/// You may call it with owned peripherals, which yields an instance that can live forever (`'static`):
115///
116/// ```ignore
117/// let mut twi: Twim<'static, ...> = Twim::new(p.TWISPI0, irq, p.P0_03, p.P0_04, config);
118/// ```
119///
120/// Or you may call it with borrowed peripherals, which yields an instance that can only live for as long
121/// as the borrows last:
122///
123/// ```ignore
124/// let mut twi: Twim<'_, ...> = Twim::new(&mut p.TWISPI0, &mut irq, &mut p.P0_03, &mut p.P0_04, config);
125/// ```
126///
127/// # Implementation details, for HAL authors
128///
129/// When writing a HAL, the intended way to use this trait is to take `impl Peripheral<P = ..>` in
130/// the HAL's public API (such as driver constructors), calling `.into_ref()` to obtain a `PeripheralRef`,
131/// and storing that in the driver struct.
132///
133/// `.into_ref()` on an owned `T` yields a `PeripheralRef<'static, T>`.
134/// `.into_ref()` on an `&'a mut T` yields a `PeripheralRef<'a, T>`.
135pub trait Peripheral: Sized {
136 /// Peripheral singleton type
137 type P;
138
139 /// Unsafely clone (duplicate) a peripheral singleton.
140 ///
141 /// # Safety
142 ///
143 /// This returns an owned clone of the peripheral. You must manually ensure
144 /// only one copy of the peripheral is in use at a time. For example, don't
145 /// create two SPI drivers on `SPI1`, because they will "fight" each other.
146 ///
147 /// You should strongly prefer using `into_ref()` instead. It returns a
148 /// `PeripheralRef`, which allows the borrow checker to enforce this at compile time.
149 unsafe fn clone_unchecked(&self) -> Self::P;
150
151 /// Convert a value into a `PeripheralRef`.
152 ///
153 /// When called on an owned `T`, yields a `PeripheralRef<'static, T>`.
154 /// When called on an `&'a mut T`, yields a `PeripheralRef<'a, T>`.
155 #[inline]
156 fn into_ref<'a>(self) -> PeripheralRef<'a, Self::P>
157 where
158 Self: 'a,
159 {
160 PeripheralRef::new(unsafe { self.clone_unchecked() })
161 }
162}
163
164impl<'b, T: DerefMut> Peripheral for T
165where
166 T::Target: Peripheral,
167{
168 type P = <T::Target as Peripheral>::P;
169
170 #[inline]
171 unsafe fn clone_unchecked(&self) -> Self::P {
172 self.deref().clone_unchecked()
173 }
174}
diff --git a/embassy-hal-internal/src/ratio.rs b/embassy-hal-internal/src/ratio.rs
new file mode 100644
index 000000000..9a8808a33
--- /dev/null
+++ b/embassy-hal-internal/src/ratio.rs
@@ -0,0 +1,129 @@
1use core::ops::{Add, Div, Mul};
2
3use num_traits::{CheckedAdd, CheckedDiv, CheckedMul};
4
5/// Represents the ratio between two numbers.
6#[derive(Copy, Clone, Debug)]
7#[cfg_attr(feature = "defmt", derive(defmt::Format))]
8pub struct Ratio<T> {
9 /// Numerator.
10 numer: T,
11 /// Denominator.
12 denom: T,
13}
14
15impl<T> Ratio<T> {
16 /// Creates a new `Ratio`.
17 #[inline(always)]
18 pub const fn new_raw(numer: T, denom: T) -> Ratio<T> {
19 Ratio { numer, denom }
20 }
21
22 /// Gets an immutable reference to the numerator.
23 #[inline(always)]
24 pub const fn numer(&self) -> &T {
25 &self.numer
26 }
27
28 /// Gets an immutable reference to the denominator.
29 #[inline(always)]
30 pub const fn denom(&self) -> &T {
31 &self.denom
32 }
33}
34
35impl<T: CheckedDiv> Ratio<T> {
36 /// Converts to an integer, rounding towards zero.
37 #[inline(always)]
38 pub fn to_integer(&self) -> T {
39 unwrap!(self.numer().checked_div(self.denom()))
40 }
41}
42
43impl<T: CheckedMul> Div<T> for Ratio<T> {
44 type Output = Self;
45
46 #[inline(always)]
47 fn div(mut self, rhs: T) -> Self::Output {
48 self.denom = unwrap!(self.denom().checked_mul(&rhs));
49 self
50 }
51}
52
53impl<T: CheckedMul> Mul<T> for Ratio<T> {
54 type Output = Self;
55
56 #[inline(always)]
57 fn mul(mut self, rhs: T) -> Self::Output {
58 self.numer = unwrap!(self.numer().checked_mul(&rhs));
59 self
60 }
61}
62
63impl<T: CheckedMul + CheckedAdd> Add<T> for Ratio<T> {
64 type Output = Self;
65
66 #[inline(always)]
67 fn add(mut self, rhs: T) -> Self::Output {
68 self.numer = unwrap!(unwrap!(self.denom().checked_mul(&rhs)).checked_add(self.numer()));
69 self
70 }
71}
72
73macro_rules! impl_from_for_float {
74 ($from:ident) => {
75 impl From<Ratio<$from>> for f32 {
76 #[inline(always)]
77 fn from(r: Ratio<$from>) -> Self {
78 (r.numer as f32) / (r.denom as f32)
79 }
80 }
81
82 impl From<Ratio<$from>> for f64 {
83 #[inline(always)]
84 fn from(r: Ratio<$from>) -> Self {
85 (r.numer as f64) / (r.denom as f64)
86 }
87 }
88 };
89}
90
91impl_from_for_float!(u8);
92impl_from_for_float!(u16);
93impl_from_for_float!(u32);
94impl_from_for_float!(u64);
95impl_from_for_float!(u128);
96impl_from_for_float!(i8);
97impl_from_for_float!(i16);
98impl_from_for_float!(i32);
99impl_from_for_float!(i64);
100impl_from_for_float!(i128);
101
102impl<T: core::fmt::Display> core::fmt::Display for Ratio<T> {
103 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
104 core::write!(f, "{} / {}", self.numer(), self.denom())
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::Ratio;
111
112 #[test]
113 fn basics() {
114 let mut r = Ratio::new_raw(1, 2) + 2;
115 assert_eq!(*r.numer(), 5);
116 assert_eq!(*r.denom(), 2);
117 assert_eq!(r.to_integer(), 2);
118
119 r = r * 2;
120 assert_eq!(*r.numer(), 10);
121 assert_eq!(*r.denom(), 2);
122 assert_eq!(r.to_integer(), 5);
123
124 r = r / 2;
125 assert_eq!(*r.numer(), 10);
126 assert_eq!(*r.denom(), 4);
127 assert_eq!(r.to_integer(), 2);
128 }
129}
diff --git a/embassy-hal-internal/src/ring_buffer.rs b/embassy-hal-internal/src/ring_buffer.rs
new file mode 100644
index 000000000..fcad68bb1
--- /dev/null
+++ b/embassy-hal-internal/src/ring_buffer.rs
@@ -0,0 +1,136 @@
1pub struct RingBuffer<'a> {
2 buf: &'a mut [u8],
3 start: usize,
4 end: usize,
5 empty: bool,
6}
7
8impl<'a> RingBuffer<'a> {
9 pub fn new(buf: &'a mut [u8]) -> Self {
10 Self {
11 buf,
12 start: 0,
13 end: 0,
14 empty: true,
15 }
16 }
17
18 pub fn push_buf(&mut self) -> &mut [u8] {
19 if self.start == self.end && !self.empty {
20 trace!(" ringbuf: push_buf empty");
21 return &mut self.buf[..0];
22 }
23
24 let n = if self.start <= self.end {
25 self.buf.len() - self.end
26 } else {
27 self.start - self.end
28 };
29
30 trace!(" ringbuf: push_buf {:?}..{:?}", self.end, self.end + n);
31 &mut self.buf[self.end..self.end + n]
32 }
33
34 pub fn push(&mut self, n: usize) {
35 trace!(" ringbuf: push {:?}", n);
36 if n == 0 {
37 return;
38 }
39
40 self.end = self.wrap(self.end + n);
41 self.empty = false;
42 }
43
44 pub fn pop_buf(&mut self) -> &mut [u8] {
45 if self.empty {
46 trace!(" ringbuf: pop_buf empty");
47 return &mut self.buf[..0];
48 }
49
50 let n = if self.end <= self.start {
51 self.buf.len() - self.start
52 } else {
53 self.end - self.start
54 };
55
56 trace!(" ringbuf: pop_buf {:?}..{:?}", self.start, self.start + n);
57 &mut self.buf[self.start..self.start + n]
58 }
59
60 pub fn pop(&mut self, n: usize) {
61 trace!(" ringbuf: pop {:?}", n);
62 if n == 0 {
63 return;
64 }
65
66 self.start = self.wrap(self.start + n);
67 self.empty = self.start == self.end;
68 }
69
70 pub fn is_full(&self) -> bool {
71 self.start == self.end && !self.empty
72 }
73
74 pub fn is_empty(&self) -> bool {
75 self.empty
76 }
77
78 pub fn clear(&mut self) {
79 self.start = 0;
80 self.end = 0;
81 self.empty = true;
82 }
83
84 fn wrap(&self, n: usize) -> usize {
85 assert!(n <= self.buf.len());
86 if n == self.buf.len() {
87 0
88 } else {
89 n
90 }
91 }
92}
93
94#[cfg(test)]
95mod tests {
96 use super::*;
97
98 #[test]
99 fn push_pop() {
100 let mut b = [0; 4];
101 let mut rb = RingBuffer::new(&mut b);
102 let buf = rb.push_buf();
103 assert_eq!(4, buf.len());
104 buf[0] = 1;
105 buf[1] = 2;
106 buf[2] = 3;
107 buf[3] = 4;
108 rb.push(4);
109
110 let buf = rb.pop_buf();
111 assert_eq!(4, buf.len());
112 assert_eq!(1, buf[0]);
113 rb.pop(1);
114
115 let buf = rb.pop_buf();
116 assert_eq!(3, buf.len());
117 assert_eq!(2, buf[0]);
118 rb.pop(1);
119
120 let buf = rb.pop_buf();
121 assert_eq!(2, buf.len());
122 assert_eq!(3, buf[0]);
123 rb.pop(1);
124
125 let buf = rb.pop_buf();
126 assert_eq!(1, buf.len());
127 assert_eq!(4, buf[0]);
128 rb.pop(1);
129
130 let buf = rb.pop_buf();
131 assert_eq!(0, buf.len());
132
133 let buf = rb.push_buf();
134 assert_eq!(4, buf.len());
135 }
136}