diff options
| -rw-r--r-- | embassy-nrf/src/buffered_uarte.rs | 159 |
1 files changed, 68 insertions, 91 deletions
diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index dbdb6f514..2e29da25a 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs | |||
| @@ -33,12 +33,25 @@ enum RxState { | |||
| 33 | ReceivingReady, | 33 | ReceivingReady, |
| 34 | Stopping, | 34 | Stopping, |
| 35 | } | 35 | } |
| 36 | |||
| 36 | #[derive(Copy, Clone, Debug, PartialEq)] | 37 | #[derive(Copy, Clone, Debug, PartialEq)] |
| 37 | enum TxState { | 38 | enum TxState { |
| 38 | Idle, | 39 | Idle, |
| 39 | Transmitting(usize), | 40 | Transmitting(usize), |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 43 | struct State<'a, T: Instance> { | ||
| 44 | inner: T, | ||
| 45 | |||
| 46 | rx: RingBuffer<'a>, | ||
| 47 | rx_state: RxState, | ||
| 48 | rx_waker: WakerRegistration, | ||
| 49 | |||
| 50 | tx: RingBuffer<'a>, | ||
| 51 | tx_state: TxState, | ||
| 52 | tx_waker: WakerRegistration, | ||
| 53 | } | ||
| 54 | |||
| 42 | /// Interface to a UARTE instance | 55 | /// Interface to a UARTE instance |
| 43 | /// | 56 | /// |
| 44 | /// This is a very basic interface that comes with the following limitations: | 57 | /// This is a very basic interface that comes with the following limitations: |
| @@ -145,6 +158,10 @@ impl<'a, T: Instance> BufferedUarte<'a, T> { | |||
| 145 | ), | 158 | ), |
| 146 | } | 159 | } |
| 147 | } | 160 | } |
| 161 | |||
| 162 | fn inner(self: Pin<&mut Self>) -> Pin<&mut PeripheralMutex<T::Interrupt, State<'a, T>>> { | ||
| 163 | unsafe { Pin::new_unchecked(&mut self.get_unchecked_mut().inner) } | ||
| 164 | } | ||
| 148 | } | 165 | } |
| 149 | 166 | ||
| 150 | impl<'a, T: Instance> Drop for BufferedUarte<'a, T> { | 167 | impl<'a, T: Instance> Drop for BufferedUarte<'a, T> { |
| @@ -156,111 +173,71 @@ impl<'a, T: Instance> Drop for BufferedUarte<'a, T> { | |||
| 156 | 173 | ||
| 157 | impl<'a, T: Instance> AsyncBufRead for BufferedUarte<'a, T> { | 174 | impl<'a, T: Instance> AsyncBufRead for BufferedUarte<'a, T> { |
| 158 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { | 175 | fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { |
| 159 | let this = unsafe { self.get_unchecked_mut() }; | 176 | self.inner().with(|_irq, state| { |
| 160 | let reg = unsafe { Pin::new_unchecked(&mut this.inner) }; | 177 | // Conservative compiler fence to prevent optimizations that do not |
| 161 | reg.with(|_irq, state| { | 178 | // take in to account actions by DMA. The fence has been placed here, |
| 162 | let z: Poll<Result<&[u8]>> = state.poll_fill_buf(cx); | 179 | // before any DMA action has started |
| 163 | let z: Poll<Result<&[u8]>> = unsafe { mem::transmute(z) }; | 180 | compiler_fence(Ordering::SeqCst); |
| 164 | z | 181 | trace!("poll_read"); |
| 182 | |||
| 183 | // We have data ready in buffer? Return it. | ||
| 184 | let buf = state.rx.pop_buf(); | ||
| 185 | if buf.len() != 0 { | ||
| 186 | trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); | ||
| 187 | let buf: &[u8] = buf; | ||
| 188 | let buf: &[u8] = unsafe { mem::transmute(buf) }; | ||
| 189 | return Poll::Ready(Ok(buf)); | ||
| 190 | } | ||
| 191 | |||
| 192 | trace!(" empty"); | ||
| 193 | |||
| 194 | if state.rx_state == RxState::ReceivingReady { | ||
| 195 | trace!(" stopping"); | ||
| 196 | state.rx_state = RxState::Stopping; | ||
| 197 | state.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 198 | } | ||
| 199 | |||
| 200 | state.rx_waker.register(cx.waker()); | ||
| 201 | Poll::<Result<&[u8]>>::Pending | ||
| 165 | }) | 202 | }) |
| 166 | } | 203 | } |
| 167 | 204 | ||
| 168 | fn consume(self: Pin<&mut Self>, amt: usize) { | 205 | fn consume(self: Pin<&mut Self>, amt: usize) { |
| 169 | let this = unsafe { self.get_unchecked_mut() }; | 206 | self.inner().with(|irq, state| { |
| 170 | let reg = unsafe { Pin::new_unchecked(&mut this.inner) }; | 207 | trace!("consume {:?}", amt); |
| 171 | reg.with(|irq, state| state.consume(irq, amt)) | 208 | state.rx.pop(amt); |
| 209 | irq.pend(); | ||
| 210 | }) | ||
| 172 | } | 211 | } |
| 173 | } | 212 | } |
| 174 | 213 | ||
| 175 | impl<'a, T: Instance> AsyncWrite for BufferedUarte<'a, T> { | 214 | impl<'a, T: Instance> AsyncWrite for BufferedUarte<'a, T> { |
| 176 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { | 215 | fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> { |
| 177 | let this = unsafe { self.get_unchecked_mut() }; | 216 | self.inner().with(|irq, state| { |
| 178 | let reg = unsafe { Pin::new_unchecked(&mut this.inner) }; | 217 | trace!("poll_write: {:?}", buf.len()); |
| 179 | reg.with(|irq, state| state.poll_write(irq, cx, buf)) | 218 | |
| 180 | } | 219 | let tx_buf = state.tx.push_buf(); |
| 181 | } | 220 | if tx_buf.len() == 0 { |
| 182 | 221 | trace!("poll_write: pending"); | |
| 183 | // ==================================== | 222 | state.tx_waker.register(cx.waker()); |
| 184 | // ==================================== | 223 | return Poll::Pending; |
| 185 | // ==================================== | 224 | } |
| 186 | |||
| 187 | // public because it needs to be used in Instance trait, but | ||
| 188 | // should not be used outside the module | ||
| 189 | #[doc(hidden)] | ||
| 190 | pub struct State<'a, T: Instance> { | ||
| 191 | inner: T, | ||
| 192 | |||
| 193 | rx: RingBuffer<'a>, | ||
| 194 | rx_state: RxState, | ||
| 195 | rx_waker: WakerRegistration, | ||
| 196 | |||
| 197 | tx: RingBuffer<'a>, | ||
| 198 | tx_state: TxState, | ||
| 199 | tx_waker: WakerRegistration, | ||
| 200 | } | ||
| 201 | |||
| 202 | impl<'a, T: Instance> State<'a, T> { | ||
| 203 | fn poll_fill_buf(&mut self, cx: &mut Context<'_>) -> Poll<Result<&[u8]>> { | ||
| 204 | // Conservative compiler fence to prevent optimizations that do not | ||
| 205 | // take in to account actions by DMA. The fence has been placed here, | ||
| 206 | // before any DMA action has started | ||
| 207 | compiler_fence(Ordering::SeqCst); | ||
| 208 | trace!("poll_read"); | ||
| 209 | |||
| 210 | // We have data ready in buffer? Return it. | ||
| 211 | let buf = self.rx.pop_buf(); | ||
| 212 | if buf.len() != 0 { | ||
| 213 | trace!(" got {:?} {:?}", buf.as_ptr() as u32, buf.len()); | ||
| 214 | return Poll::Ready(Ok(buf)); | ||
| 215 | } | ||
| 216 | |||
| 217 | trace!(" empty"); | ||
| 218 | |||
| 219 | if self.rx_state == RxState::ReceivingReady { | ||
| 220 | trace!(" stopping"); | ||
| 221 | self.rx_state = RxState::Stopping; | ||
| 222 | self.inner.tasks_stoprx.write(|w| unsafe { w.bits(1) }); | ||
| 223 | } | ||
| 224 | |||
| 225 | self.rx_waker.register(cx.waker()); | ||
| 226 | Poll::Pending | ||
| 227 | } | ||
| 228 | |||
| 229 | fn consume(&mut self, irq: &mut T::Interrupt, amt: usize) { | ||
| 230 | trace!("consume {:?}", amt); | ||
| 231 | self.rx.pop(amt); | ||
| 232 | irq.pend(); | ||
| 233 | } | ||
| 234 | |||
| 235 | fn poll_write( | ||
| 236 | &mut self, | ||
| 237 | irq: &mut T::Interrupt, | ||
| 238 | cx: &mut Context<'_>, | ||
| 239 | buf: &[u8], | ||
| 240 | ) -> Poll<Result<usize>> { | ||
| 241 | trace!("poll_write: {:?}", buf.len()); | ||
| 242 | |||
| 243 | let tx_buf = self.tx.push_buf(); | ||
| 244 | if tx_buf.len() == 0 { | ||
| 245 | trace!("poll_write: pending"); | ||
| 246 | self.tx_waker.register(cx.waker()); | ||
| 247 | return Poll::Pending; | ||
| 248 | } | ||
| 249 | 225 | ||
| 250 | let n = min(tx_buf.len(), buf.len()); | 226 | let n = min(tx_buf.len(), buf.len()); |
| 251 | tx_buf[..n].copy_from_slice(&buf[..n]); | 227 | tx_buf[..n].copy_from_slice(&buf[..n]); |
| 252 | self.tx.push(n); | 228 | state.tx.push(n); |
| 253 | 229 | ||
| 254 | trace!("poll_write: queued {:?}", n); | 230 | trace!("poll_write: queued {:?}", n); |
| 255 | 231 | ||
| 256 | // Conservative compiler fence to prevent optimizations that do not | 232 | // Conservative compiler fence to prevent optimizations that do not |
| 257 | // take in to account actions by DMA. The fence has been placed here, | 233 | // take in to account actions by DMA. The fence has been placed here, |
| 258 | // before any DMA action has started | 234 | // before any DMA action has started |
| 259 | compiler_fence(Ordering::SeqCst); | 235 | compiler_fence(Ordering::SeqCst); |
| 260 | 236 | ||
| 261 | irq.pend(); | 237 | irq.pend(); |
| 262 | 238 | ||
| 263 | Poll::Ready(Ok(n)) | 239 | Poll::Ready(Ok(n)) |
| 240 | }) | ||
| 264 | } | 241 | } |
| 265 | } | 242 | } |
| 266 | 243 | ||
