seeed_lora_e5_at_commands/
signal.rs

1//! A synchronization primitive for passing the latest value to a task.
2//! Copied over from embassy-sync
3use core::cell::Cell;
4use core::future::{poll_fn, Future};
5use core::task::{Context, Poll, Waker};
6
7use embassy_sync::blocking_mutex::raw::RawMutex;
8use embassy_sync::blocking_mutex::Mutex;
9
10/// Single-slot signaling primitive.
11///
12/// This is similar to a [`Channel`](crate::channel::Channel) with a buffer size of 1, except
13/// "sending" to it (calling [`Signal::signal`]) when full will overwrite the previous value instead
14/// of waiting for the receiver to pop the previous value.
15///
16/// It is useful for sending data between tasks when the receiver only cares about
17/// the latest data, and therefore it's fine to "lose" messages. This is often the case for "state"
18/// updates.
19///
20/// For more advanced use cases, you might want to use [`Channel`](crate::channel::Channel) instead.
21///
22/// Signals are generally declared as `static`s and then borrowed as required.
23///
24/// ```
25/// use embassy_sync::signal::Signal;
26/// use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
27///
28/// enum SomeCommand {
29///   On,
30///   Off,
31/// }
32///
33/// static SOME_SIGNAL: Signal<CriticalSectionRawMutex, SomeCommand> = Signal::new();
34/// ```
35pub struct Signal<M, T>
36where
37    M: RawMutex,
38{
39    state: Mutex<M, Cell<State<T>>>,
40}
41
42enum State<T> {
43    None,
44    Waiting(Waker),
45    Signaled(T),
46}
47
48impl<M, T> Signal<M, T>
49where
50    M: RawMutex,
51{
52    /// Create a new `Signal`.
53    pub const fn new() -> Self {
54        Self {
55            state: Mutex::new(Cell::new(State::None)),
56        }
57    }
58}
59
60impl<M, T: Send> Signal<M, T>
61where
62    M: RawMutex,
63{
64    /// Mark this Signal as signaled.
65    pub fn signal(&self, val: T) {
66        self.state.lock(|cell| {
67            let state = cell.replace(State::Signaled(val));
68            if let State::Waiting(waker) = state {
69                waker.wake();
70            }
71        })
72    }
73
74    /// Remove the queued value in this `Signal`, if any.
75    pub fn reset(&self) {
76        self.state.lock(|cell| cell.set(State::None));
77    }
78
79    fn poll_wait(&self, cx: &mut Context<'_>) -> Poll<T> {
80        self.state.lock(|cell| {
81            let state = cell.replace(State::None);
82            match state {
83                State::None => {
84                    cell.set(State::Waiting(cx.waker().clone()));
85                    Poll::Pending
86                }
87                State::Waiting(w) if w.will_wake(cx.waker()) => {
88                    cell.set(State::Waiting(w));
89                    Poll::Pending
90                }
91                State::Waiting(w) => {
92                    cell.set(State::Waiting(cx.waker().clone()));
93                    w.wake();
94                    Poll::Pending
95                }
96                State::Signaled(res) => Poll::Ready(res),
97            }
98        })
99    }
100
101    /// Future that completes when this Signal has been signaled.
102    pub fn wait(&self) -> impl Future<Output = T> + '_ {
103        poll_fn(move |cx| self.poll_wait(cx))
104    }
105
106    /// non-blocking method to check whether this signal has been signaled.
107    pub fn signaled(&self) -> bool {
108        self.state.lock(|cell| {
109            let state = cell.replace(State::None);
110            let res = matches!(state, State::Signaled(_));
111            cell.set(state);
112            res
113        })
114    }
115}
116
117impl<M, T: Copy> Signal<M, T>
118where
119    M: RawMutex,
120{
121    pub fn try_signaled_value(&self) -> Option<T> {
122        let mut ret = None;
123        self.state.lock(|cell| {
124            let state = cell.replace(State::None);
125
126            if let State::Signaled(v) = state {
127                ret = Some(v);
128            }
129            cell.set(state);
130        });
131        ret
132    }
133}