Open MabezDev opened 6 years ago
I was thinking of something like this recently and I think we could have peek
expose both the half that's not being modified (or has been completed) and the completed fraction of the other half. Something like this:
// [X, X, X, ?, ?, ?, ?, ?, X, X, X, X, X, X, X, X]
// ~~~~~~~ in progress ~~~~~~~~~~~~~~~~~~~~~~ completed
// "?" = to be written by the DMA
circ_buffer.peek(
|in_progress_half: &[u8], completed_half: &[u8; 16], half: Half| {
// ~~~~~~~~~~~~~~~~ NEW!
let n = half_being_modified.len();
let cndtr = if half == Half::Second {
32 - n
} else {
16 - n
};
},
);
There may be some more descriptive names for the halves ...
Thoughts? Perhaps there should be two methods?
This looks promising. To keep things simpler, what about just returning each half of the buffer based on the half given as a param? E.g if you pass Half::Second you would get the current state of thye second part of the buffer, which could be either the full amount or a fraction of the buffer.
circ_buffer.peek(
|requested_half_buf: &[u8], half: Half| {
// ~~~~~~~~~~~~~~~~ NEW!
let n = half_requested.len();
let cndtr = if half == Half::Second {
32 - n
} else {
16 - n
};
},
);
Here is my solution. I call this when my USART line goes idle:
pub fn partial_peek<R, F, T>(&mut self, f: F) -> Result<R, Error>
where
F: FnOnce(&[T], Half) -> Result<(usize, R), ()>,
B: Unsize<[T]>,
{
// this inverts expectation and returns the half being _written_
let buf = match self.readable_half {
Half::First => &self.buffer[1],
Half::Second => &self.buffer[0],
};
// ,- half-buffer
// [ x x x x y y y y y z | z z z z z z z z z z ]
// ^- pending=11
let pending = self.channel.get_cndtr() as usize; // available bytes in _whole_ buffer
let slice: &[T] = buf;
let capacity = slice.len(); // capacity of _half_ a buffer
// <--- capacity=10 --->
// [ x x x x y y y y y z | z z z z z z z z z z ]
let pending = if pending > capacity {
pending - capacity
} else {
pending
};
// ,- half-buffer
// [ x x x x y y y y y z | z z z z z z z z z z ]
// ^- pending=1
let end = capacity - pending;
// [ x x x x y y y y y z | z z z z z z z z z z ]
// ^- end=9
// ^- consumed_offset=4
// [y y y y y] <-- slice
let slice = &slice[self.consumed_offset..end];
match f(slice, self.readable_half) {
Ok((l, r)) => { self.consumed_offset += l; Ok(r) },
Err(_) => Err(Error::BufferError),
}
}
Not included in the listing is the addition of the consumed_offset: usize
member of CircBuffer
I am using the DMA with a circular buffer to recieve serial data on a UART, its working fine if it fills up both halves of the circ buffer. The problem I am having is how to grab the data still in the buffer when the serial data stops coming in.
In a C project at work I had used the
CNDTR
register in the DMA channel to figure out where in the buffer and how much data had been read after a timeout. Looking though dma.rs I see there is a function to access theCNDTR
reg but its private to the crate. I am wondering if this is something that should be exposed.I am fairly new to rust so I may be missing something obvious. I'd also like to mention that the work you are doing for embedded rust is amazing!