aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-hal-common/src/atomic_ring_buffer.rs147
1 files changed, 147 insertions, 0 deletions
diff --git a/embassy-hal-common/src/atomic_ring_buffer.rs b/embassy-hal-common/src/atomic_ring_buffer.rs
index ccbc37362..afd3ce1de 100644
--- a/embassy-hal-common/src/atomic_ring_buffer.rs
+++ b/embassy-hal-common/src/atomic_ring_buffer.rs
@@ -153,6 +153,14 @@ impl<'a> Writer<'a> {
153 unsafe { slice::from_raw_parts_mut(data, len) } 153 unsafe { slice::from_raw_parts_mut(data, len) }
154 } 154 }
155 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
156 /// Get a buffer where data can be pushed to. 164 /// Get a buffer where data can be pushed to.
157 /// 165 ///
158 /// Write data to the start of the buffer, then call `push_done` with 166 /// Write data to the start of the buffer, then call `push_done` with
@@ -191,6 +199,45 @@ impl<'a> Writer<'a> {
191 (unsafe { buf.add(end) }, n) 199 (unsafe { buf.add(end) }, n)
192 } 200 }
193 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
194 pub fn push_done(&mut self, n: usize) { 241 pub fn push_done(&mut self, n: usize) {
195 trace!(" ringbuf: push {:?}", n); 242 trace!(" ringbuf: push {:?}", n);
196 let end = self.0.end.load(Ordering::Relaxed); 243 let end = self.0.end.load(Ordering::Relaxed);
@@ -408,4 +455,104 @@ mod tests {
408 }); 455 });
409 } 456 }
410 } 457 }
458
459 #[test]
460 fn push_slices() {
461 init();
462
463 let mut b = [0; 4];
464 let rb = RingBuffer::new();
465 unsafe {
466 rb.init(b.as_mut_ptr(), 4);
467
468 /* push 3 -> [1 2 3 x] */
469 let mut w = rb.writer();
470 let ps = w.push_slices();
471 assert_eq!(4, ps[0].len());
472 assert_eq!(0, ps[1].len());
473 ps[0][0] = 1;
474 ps[0][1] = 2;
475 ps[0][2] = 3;
476 w.push_done(3);
477 drop(w);
478
479 /* pop 2 -> [x x 3 x] */
480 rb.reader().pop(|buf| {
481 assert_eq!(3, buf.len());
482 assert_eq!(1, buf[0]);
483 assert_eq!(2, buf[1]);
484 assert_eq!(3, buf[2]);
485 2
486 });
487
488 /* push 3 -> [5 6 3 4] */
489 let mut w = rb.writer();
490 let ps = w.push_slices();
491 assert_eq!(1, ps[0].len());
492 assert_eq!(2, ps[1].len());
493 ps[0][0] = 4;
494 ps[1][0] = 5;
495 ps[1][1] = 6;
496 w.push_done(3);
497 drop(w);
498
499 /* buf is now full */
500 let mut w = rb.writer();
501 let ps = w.push_slices();
502 assert_eq!(0, ps[0].len());
503 assert_eq!(0, ps[1].len());
504
505 /* pop 2 -> [5 6 x x] */
506 rb.reader().pop(|buf| {
507 assert_eq!(2, buf.len());
508 assert_eq!(3, buf[0]);
509 assert_eq!(4, buf[1]);
510 2
511 });
512
513 /* should now have one push slice again */
514 let mut w = rb.writer();
515 let ps = w.push_slices();
516 assert_eq!(2, ps[0].len());
517 assert_eq!(0, ps[1].len());
518 drop(w);
519
520 /* pop 2 -> [x x x x] */
521 rb.reader().pop(|buf| {
522 assert_eq!(2, buf.len());
523 assert_eq!(5, buf[0]);
524 assert_eq!(6, buf[1]);
525 2
526 });
527
528 /* should now have two push slices */
529 let mut w = rb.writer();
530 let ps = w.push_slices();
531 assert_eq!(2, ps[0].len());
532 assert_eq!(2, ps[1].len());
533 drop(w);
534
535 /* make sure we exercise all wrap around cases properly */
536 for _ in 0..10 {
537 /* should be empty, push 1 */
538 let mut w = rb.writer();
539 let ps = w.push_slices();
540 assert_eq!(4, ps[0].len() + ps[1].len());
541 w.push_done(1);
542 drop(w);
543
544 /* should have 1 element */
545 let mut w = rb.writer();
546 let ps = w.push_slices();
547 assert_eq!(3, ps[0].len() + ps[1].len());
548 drop(w);
549
550 /* pop 1 */
551 rb.reader().pop(|buf| {
552 assert_eq!(1, buf.len());
553 1
554 });
555 }
556 }
557 }
411} 558}