use std::{cell, vec};
use super::*;
#[allow(unused)]
#[derive(PartialEq, Debug)]
enum TestCircularTransferRequest {
ResetCompleteCount(usize),
PositionRequest(usize),
}
#[allow(unused)]
struct TestCircularTransfer {
len: usize,
requests: cell::RefCell<vec::Vec<TestCircularTransferRequest>>,
}
impl DmaCtrl for TestCircularTransfer {
fn get_remaining_transfers(&self) -> usize {
match self.requests.borrow_mut().pop().unwrap() {
TestCircularTransferRequest::PositionRequest(pos) => {
let len = self.len;
assert!(len >= pos);
len - pos
}
_ => unreachable!(),
}
}
fn reset_complete_count(&mut self) -> usize {
match self.requests.get_mut().pop().unwrap() {
TestCircularTransferRequest::ResetCompleteCount(complete_count) => complete_count,
_ => unreachable!(),
}
}
fn set_waker(&mut self, _waker: &Waker) {}
}
impl TestCircularTransfer {
#[allow(unused)]
pub fn new(len: usize) -> Self {
Self {
requests: cell::RefCell::new(vec![]),
len,
}
}
#[allow(unused)]
pub fn setup(&self, mut requests: vec::Vec<TestCircularTransferRequest>) {
requests.reverse();
self.requests.replace(requests);
}
}
const CAP: usize = 16;
#[test]
fn dma_index_as_index_returns_index_mod_cap_by_default() {
let index = DmaIndex::default();
assert_eq!(index.as_index(CAP, 0), 0);
assert_eq!(index.as_index(CAP, 1), 1);
assert_eq!(index.as_index(CAP, 2), 2);
assert_eq!(index.as_index(CAP, 3), 3);
assert_eq!(index.as_index(CAP, 4), 4);
assert_eq!(index.as_index(CAP, CAP), 0);
assert_eq!(index.as_index(CAP, CAP + 1), 1);
}
#[test]
fn dma_index_advancing_increases_as_index() {
let mut index = DmaIndex::default();
assert_eq!(index.as_index(CAP, 0), 0);
index.advance(CAP, 1);
assert_eq!(index.as_index(CAP, 0), 1);
index.advance(CAP, 1);
assert_eq!(index.as_index(CAP, 0), 2);
index.advance(CAP, 1);
assert_eq!(index.as_index(CAP, 0), 3);
index.advance(CAP, 1);
assert_eq!(index.as_index(CAP, 0), 4);
index.advance(CAP, CAP - 4);
assert_eq!(index.as_index(CAP, 0), 0);
index.advance(CAP, 1);
assert_eq!(index.as_index(CAP, 0), 1);
}
#[test]
fn alignment_skip_after_overrun() {
let mut dma_buf = [0u8; CAP];
for i in 0..CAP {
dma_buf[i] = i as u8;
}
let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
ringbuf.set_alignment(4);
let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(5), ]);
ringbuf.reset(&mut dma);
let mut read_buf = [0u8; 8];
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(14),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(14),
]);
let (read, _remaining) = ringbuf.read(&mut dma, &mut read_buf).unwrap();
assert_eq!(read, 4);
assert_eq!(&read_buf[..read], &[8, 9, 10, 11]);
}
#[test]
fn alignment_no_skip_when_aligned() {
let mut dma_buf = [0u8; CAP];
for i in 0..CAP {
dma_buf[i] = i as u8;
}
let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
ringbuf.set_alignment(4);
let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(8),
]);
ringbuf.reset(&mut dma);
let mut read_buf = [0u8; 8];
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(1),
TestCircularTransferRequest::PositionRequest(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(0),
]);
let (read, _remaining) = ringbuf.read(&mut dma, &mut read_buf).unwrap();
assert_eq!(read, 8);
assert_eq!(&read_buf[..read], &[8, 9, 10, 11, 12, 13, 14, 15]);
}
#[test]
fn alignment_rounds_down_read_length() {
let mut dma_buf = [0u8; CAP];
for i in 0..CAP {
dma_buf[i] = i as u8;
}
let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
ringbuf.set_alignment(4);
let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(0),
]);
ringbuf.reset(&mut dma);
let mut read_buf = [0u8; 5];
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(12),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(12),
]);
let (read, _remaining) = ringbuf.read(&mut dma, &mut read_buf).unwrap();
assert_eq!(read, 4);
assert_eq!(&read_buf[..read], &[0, 1, 2, 3]);
}
#[test]
#[should_panic(expected = "DMA buffer length must be a multiple of the alignment value")]
fn alignment_rejects_non_multiple() {
let mut dma_buf = [0u8; CAP]; let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
ringbuf.set_alignment(3); }
#[test]
fn read_latest_returns_most_recent_data() {
let mut dma_buf = [0u8; CAP];
for i in 0..CAP {
dma_buf[i] = i as u8;
}
let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(0),
]);
ringbuf.reset(&mut dma);
let mut read_buf = [0u8; 4];
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(12),
]);
let n = ringbuf.read_latest(&mut dma, &mut read_buf);
assert_eq!(n, 4);
assert_eq!(&read_buf[..n], &[8, 9, 10, 11]);
}
#[test]
fn read_latest_recovers_from_overrun() {
let mut dma_buf = [0u8; CAP];
for i in 0..CAP {
dma_buf[i] = i as u8;
}
let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(0),
]);
ringbuf.reset(&mut dma);
let mut read_buf = [0u8; 8];
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(2),
TestCircularTransferRequest::PositionRequest(5),
]);
let n = ringbuf.read_latest(&mut dma, &mut read_buf);
assert_eq!(n, 0);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(13),
]);
let n = ringbuf.read_latest(&mut dma, &mut read_buf);
assert_eq!(n, 8);
assert_eq!(&read_buf[..n], &[5, 6, 7, 8, 9, 10, 11, 12]);
}
#[test]
fn read_latest_returns_zero_when_empty() {
let mut dma_buf = [0u8; CAP];
let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(4),
]);
ringbuf.reset(&mut dma);
let mut read_buf = [0u8; 8];
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(4),
]);
let n = ringbuf.read_latest(&mut dma, &mut read_buf);
assert_eq!(n, 0);
}
#[test]
fn read_latest_with_alignment() {
let mut dma_buf = [0u8; CAP];
for i in 0..CAP {
dma_buf[i] = i as u8;
}
let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
ringbuf.set_alignment(4);
let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(0),
]);
ringbuf.reset(&mut dma);
let mut read_buf = [0u8; 6];
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(14),
]);
let n = ringbuf.read_latest(&mut dma, &mut read_buf);
assert_eq!(n, 4);
assert_eq!(&read_buf[..n], &[8, 9, 10, 11]);
}
#[test]
fn read_latest_reads_all_when_buffer_is_large() {
let mut dma_buf = [0u8; CAP];
for i in 0..CAP {
dma_buf[i] = i as u8;
}
let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(0),
]);
ringbuf.reset(&mut dma);
let mut read_buf = [0u8; CAP];
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(6),
]);
let n = ringbuf.read_latest(&mut dma, &mut read_buf);
assert_eq!(n, 6);
assert_eq!(&read_buf[..n], &[0, 1, 2, 3, 4, 5]);
}
#[test]
fn read_latest_wraps_around() {
let mut dma_buf = [0u8; CAP];
for i in 0..CAP {
dma_buf[i] = i as u8;
}
let mut ringbuf = ReadableDmaRingBuffer::new(&mut dma_buf);
let mut dma = TestCircularTransfer::new(CAP);
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::ResetCompleteCount(0),
TestCircularTransferRequest::PositionRequest(12),
]);
ringbuf.reset(&mut dma);
let mut read_buf = [0u8; 4];
dma.setup(vec![
TestCircularTransferRequest::ResetCompleteCount(1),
TestCircularTransferRequest::PositionRequest(4),
]);
let n = ringbuf.read_latest(&mut dma, &mut read_buf);
assert_eq!(n, 4);
assert_eq!(&read_buf[..n], &[0, 1, 2, 3]);
}
mod prop_test;