embedded_draw_target/
completion.rs1use core::cell::Cell;
4use core::future::Future;
5use core::pin::Pin;
6use core::sync::atomic::{AtomicBool, Ordering};
7use core::task::{Context, Poll, Waker};
8
9use critical_section::Mutex;
10use embedded_graphics_core::pixelcolor::Rgb565;
11use embedded_graphics_framebuf::{FrameBuf, backends::DMACapableFrameBufferBackend};
12
13pub trait DmaTransfer {
15 type Buffer;
17
18 fn is_done(&self) -> bool;
20
21 fn wait(self) -> Self::Buffer;
23}
24
25pub trait AsyncDmaTransfer: DmaTransfer {
27 type WaitFuture: Future<Output = Self::Buffer>;
29
30 fn wait_async(self) -> Self::WaitFuture;
32}
33
34pub struct CompletionSlot {
36 signaled: AtomicBool,
37 waker: Mutex<Cell<Option<Waker>>>,
38}
39
40impl CompletionSlot {
41 pub const fn new() -> Self {
43 Self {
44 signaled: AtomicBool::new(false),
45 waker: Mutex::new(Cell::new(None)),
46 }
47 }
48
49 pub fn reset(&self) {
51 self.signaled.store(false, Ordering::Release);
52 critical_section::with(|cs| {
53 self.waker.borrow(cs).set(None);
54 });
55 }
56
57 pub fn signal(&self) {
59 self.signaled.store(true, Ordering::Release);
60 critical_section::with(|cs| {
61 if let Some(waker) = self.waker.borrow(cs).take() {
62 waker.wake();
63 }
64 });
65 }
66
67 pub fn is_signaled(&self) -> bool {
69 self.signaled.load(Ordering::Acquire)
70 }
71
72 pub fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<()> {
74 if self.is_signaled() {
75 return Poll::Ready(());
76 }
77 critical_section::with(|cs| {
78 self.waker.borrow(cs).set(Some(cx.waker().clone()));
79 });
80 if self.is_signaled() {
81 Poll::Ready(())
82 } else {
83 Poll::Pending
84 }
85 }
86}
87
88impl Default for CompletionSlot {
89 fn default() -> Self {
90 Self::new()
91 }
92}
93
94pub struct WaitTransfer<FB>
96where
97 FB: DMACapableFrameBufferBackend<Color = Rgb565>,
98{
99 framebuffer: Option<FrameBuf<Rgb565, FB>>,
100 completion: &'static CompletionSlot,
101}
102
103impl<FB> WaitTransfer<FB>
104where
105 FB: DMACapableFrameBufferBackend<Color = Rgb565>,
106{
107 pub fn new(framebuffer: FrameBuf<Rgb565, FB>, completion: &'static CompletionSlot) -> Self {
109 completion.reset();
110 Self {
111 framebuffer: Some(framebuffer),
112 completion,
113 }
114 }
115
116 pub const fn completion(&self) -> &'static CompletionSlot {
118 self.completion
119 }
120}
121
122impl<FB> DmaTransfer for WaitTransfer<FB>
123where
124 FB: DMACapableFrameBufferBackend<Color = Rgb565>,
125{
126 type Buffer = FrameBuf<Rgb565, FB>;
127
128 fn is_done(&self) -> bool {
129 self.completion.is_signaled()
130 }
131
132 fn wait(self) -> Self::Buffer {
133 while !self.completion.is_signaled() {
134 core::hint::spin_loop();
135 }
136 self.framebuffer
137 .expect("WaitTransfer polled after completion")
138 }
139}
140
141pub struct WaitTransferFuture<FB>
143where
144 FB: DMACapableFrameBufferBackend<Color = Rgb565>,
145{
146 inner: Option<WaitTransfer<FB>>,
147}
148
149impl<FB> AsyncDmaTransfer for WaitTransfer<FB>
150where
151 FB: DMACapableFrameBufferBackend<Color = Rgb565>,
152{
153 type WaitFuture = WaitTransferFuture<FB>;
154
155 fn wait_async(self) -> Self::WaitFuture {
156 WaitTransferFuture { inner: Some(self) }
157 }
158}
159
160impl<FB> Future for WaitTransferFuture<FB>
161where
162 FB: DMACapableFrameBufferBackend<Color = Rgb565>,
163{
164 type Output = FrameBuf<Rgb565, FB>;
165
166 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
167 let this = unsafe { self.get_unchecked_mut() };
168 let inner = this
169 .inner
170 .as_mut()
171 .expect("WaitTransferFuture polled after completion");
172 match inner.completion.poll_wait(cx) {
173 Poll::Ready(()) => Poll::Ready(
174 this.inner
175 .take()
176 .expect("WaitTransferFuture polled after completion")
177 .framebuffer
178 .expect("WaitTransferFuture polled after completion"),
179 ),
180 Poll::Pending => Poll::Pending,
181 }
182 }
183}