Skip to content

Commit

Permalink
Merge #412
Browse files Browse the repository at this point in the history
412: Add is_done and try_wait methods to i2s::Transfer r=jonas-schievink a=nospam2678

Wouldn't it be useful if being able to determine whether an I²S transfer has completed without busy looping?

The changes is this PR appears to be working for both `wait()` and `try_wait()`, but I must admit that the compiler fencing part flies a bit above my head even after refreshing myself on the topic. I'm actually preplexed of why it is needed in the first place. Is it to prevent buffer from being fetched for return prior to the loop being finished?

An implementation detail which might be questioned is whether `is_done()` is at all desired. My reasoning is that it reduces the code duplication slightly, and that adding it to the public api might be useful for someone. One could argue an extra function call adds overhead, but I am imagining the compiler would inline and optimize away such a tiny function.

Co-authored-by: Martin <[email protected]>
  • Loading branch information
bors[bot] and Martin authored Nov 15, 2022
2 parents 214c08d + eb3b96b commit afda587
Showing 1 changed file with 28 additions and 3 deletions.
31 changes: 28 additions & 3 deletions nrf-hal-common/src/i2s.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,15 +680,40 @@ struct Inner<B> {
}

impl<B> Transfer<B> {
/// Returns `true` if the transfer is done.
pub fn is_done(&self) -> bool {
if let Some(inner) = self
.inner
.as_ref()
{
inner.i2s.is_event_triggered(I2SEvent::RxPtrUpdated)
|| inner.i2s.is_event_triggered(I2SEvent::TxPtrUpdated)
} else {
unsafe { core::hint::unreachable_unchecked() };
}
}

/// Attempts to return the buffer if the transfer is done.
pub fn try_wait(mut self) -> Option<(B, I2S)> {
if self.is_done() {
let inner = self
.inner
.take()
.unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() });
compiler_fence(Ordering::Acquire);
Some((inner.buffer, inner.i2s))
} else {
None
}
}

/// Blocks until the transfer is done and returns the buffer.
pub fn wait(mut self) -> (B, I2S) {
while !self.is_done() {}
let inner = self
.inner
.take()
.unwrap_or_else(|| unsafe { core::hint::unreachable_unchecked() });
while !(inner.i2s.is_event_triggered(I2SEvent::RxPtrUpdated)
|| inner.i2s.is_event_triggered(I2SEvent::TxPtrUpdated))
{}
compiler_fence(Ordering::Acquire);
(inner.buffer, inner.i2s)
}
Expand Down

0 comments on commit afda587

Please sign in to comment.