esp_wifi/wifi/
event.rs

1use alloc::boxed::Box;
2
3use esp_hal::sync::Locked;
4
5use super::WifiEvent;
6
7pub(crate) mod sealed {
8    use super::*;
9
10    pub trait Event {
11        /// Get the static reference to the handler for this event.
12        fn handler() -> &'static Locked<Option<Box<Handler<Self>>>>;
13        /// # Safety
14        /// `ptr` must be a valid for casting to this event's inner event data.
15        unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self;
16    }
17}
18/// The type of handlers of events.
19pub type Handler<T> = dyn FnMut(&T) + Sync + Send;
20
21fn default_handler<Event: 'static>() -> Box<Handler<Event>> {
22    fn drop_ref<T>(_: &T) {}
23    // perf: `drop_ref` is a ZST [function item](https://doc.rust-lang.org/reference/types/function-item.html)
24    // so this doesn't actually allocate.
25    Box::new(drop_ref)
26}
27
28/// Extension trait for setting handlers for an event.
29///
30/// Register a new event handler like:
31///
32/// ```rust, no_run
33/// # use esp_wifi::wifi::event::{self, *};
34/// # fn new_handler(_: &ApStaconnected) {}
35/// event::ApStaconnected::update_handler(|_cs, event| {
36///     new_handler(event);
37/// })
38/// ```
39// Implemented like this instead of free functions because the syntax would be
40// ```
41// event::update_handler::<event::ApStaconnected, _>(...)
42// ```
43pub trait EventExt: sealed::Event + Sized + 'static {
44    /// Get the handler for this event, replacing it with the default handler.
45    fn take_handler() -> Box<Handler<Self>> {
46        Self::handler().with(|handler| handler.take().unwrap_or_else(default_handler::<Self>))
47    }
48    /// Set the handler for this event, returning the old handler.
49    fn replace_handler<F: FnMut(&Self) + Sync + Send + 'static>(f: F) -> Box<Handler<Self>> {
50        Self::handler().with(|handler| {
51            handler
52                .replace(Box::new(f))
53                .unwrap_or_else(default_handler::<Self>)
54        })
55    }
56    /// Atomic combination of [`Self::take_handler`] and
57    /// [`Self::replace_handler`]. Use this to add a new handler which runs
58    /// after the previously registered handlers.
59    fn update_handler<F: FnMut(&Self) + Sync + Send + 'static>(mut f: F) {
60        Self::handler().with(|handler| {
61            let mut prev: Box<Handler<Self>> =
62                handler.take().unwrap_or_else(default_handler::<Self>);
63            handler.replace(Box::new(move |event| {
64                prev(event);
65                f(event)
66            }));
67        })
68    }
69}
70impl<T: sealed::Event + 'static> EventExt for T {}
71
72macro_rules! impl_wifi_event {
73    // no data
74    ($newtype:ident) => {
75        /// See [`WifiEvent`].
76        #[derive(Copy, Clone)]
77        pub struct $newtype;
78        impl sealed::Event for $newtype {
79            unsafe fn from_raw_event_data(_: *mut crate::binary::c_types::c_void) -> Self {
80                Self
81            }
82            fn handler() -> &'static Locked<Option<Box<Handler<Self>>>> {
83                static HANDLE: Locked<Option<Box<Handler<$newtype>>>> = Locked::new(None);
84                &HANDLE
85            }
86        }
87    };
88    // data
89    ($newtype:ident, $data:ident) => {
90        pub use esp_wifi_sys::include::$data;
91        /// See [`WifiEvent`].
92        #[derive(Copy, Clone)]
93        pub struct $newtype(pub $data);
94        impl sealed::Event for $newtype {
95            unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self {
96                Self(unsafe { *ptr.cast() })
97            }
98            fn handler() -> &'static Locked<Option<Box<Handler<Self>>>> {
99                static HANDLE: Locked<Option<Box<Handler<$newtype>>>> = Locked::new(None);
100                &HANDLE
101            }
102        }
103    };
104}
105
106impl_wifi_event!(WifiReady);
107impl_wifi_event!(ScanDone, wifi_event_sta_scan_done_t);
108impl_wifi_event!(StaStart);
109impl_wifi_event!(StaStop);
110impl_wifi_event!(StaConnected, wifi_event_sta_connected_t);
111impl_wifi_event!(StaDisconnected, wifi_event_sta_disconnected_t);
112impl_wifi_event!(StaAuthmodeChange, wifi_event_sta_authmode_change_t);
113impl_wifi_event!(StaWpsErSuccess, wifi_event_sta_wps_er_success_t);
114impl_wifi_event!(StaWpsErFailed);
115impl_wifi_event!(StaWpsErTimeout);
116impl_wifi_event!(StaWpsErPin, wifi_event_sta_wps_er_pin_t);
117impl_wifi_event!(StaWpsErPbcOverlap);
118impl_wifi_event!(ApStart);
119impl_wifi_event!(ApStop);
120impl_wifi_event!(ApStaconnected, wifi_event_ap_staconnected_t);
121impl_wifi_event!(ApStadisconnected, wifi_event_ap_stadisconnected_t);
122impl_wifi_event!(ApProbereqrecved, wifi_event_ap_probe_req_rx_t);
123impl_wifi_event!(FtmReport, wifi_event_ftm_report_t);
124impl_wifi_event!(StaBssRssiLow, wifi_event_bss_rssi_low_t);
125impl_wifi_event!(ActionTxStatus, wifi_event_action_tx_status_t);
126impl_wifi_event!(RocDone, wifi_event_roc_done_t);
127impl_wifi_event!(StaBeaconTimeout);
128impl_wifi_event!(ConnectionlessModuleWakeIntervalStart);
129impl_wifi_event!(ApWpsRgSuccess, wifi_event_ap_wps_rg_success_t);
130impl_wifi_event!(ApWpsRgFailed, wifi_event_ap_wps_rg_fail_reason_t);
131impl_wifi_event!(ApWpsRgTimeout);
132impl_wifi_event!(ApWpsRgPin, wifi_event_ap_wps_rg_pin_t);
133impl_wifi_event!(ApWpsRgPbcOverlap);
134cfg_if::cfg_if! {
135    if #[cfg(wifi6)] {
136        impl_wifi_event!(ItwtSetup, wifi_event_sta_itwt_setup_t);
137        impl_wifi_event!(ItwtTeardown, wifi_event_sta_itwt_teardown_t);
138        impl_wifi_event!(ItwtProbe, wifi_event_sta_itwt_probe_t);
139        impl_wifi_event!(ItwtSuspend, wifi_event_sta_itwt_suspend_t);
140        impl_wifi_event!(TwtWakeup);
141        impl_wifi_event!(BtwtSetup, wifi_event_sta_btwt_setup_t);
142        impl_wifi_event!(BtwtTeardown, wifi_event_sta_btwt_teardown_t);
143    } else {
144        impl_wifi_event!(ItwtSetup);
145        impl_wifi_event!(ItwtTeardown);
146        impl_wifi_event!(ItwtProbe);
147        impl_wifi_event!(ItwtSuspend);
148        impl_wifi_event!(TwtWakeup);
149        impl_wifi_event!(BtwtSetup);
150        impl_wifi_event!(BtwtTeardown);
151    }
152}
153impl_wifi_event!(NanStarted);
154impl_wifi_event!(NanStopped);
155impl_wifi_event!(NanSvcMatch, wifi_event_nan_svc_match_t);
156impl_wifi_event!(NanReplied, wifi_event_nan_replied_t);
157impl_wifi_event!(NanReceive, wifi_event_nan_receive_t);
158impl_wifi_event!(NdpIndication, wifi_event_ndp_indication_t);
159impl_wifi_event!(NdpConfirm, wifi_event_ndp_confirm_t);
160impl_wifi_event!(NdpTerminated, wifi_event_ndp_terminated_t);
161impl_wifi_event!(HomeChannelChange, wifi_event_home_channel_change_t);
162impl_wifi_event!(StaNeighborRep, wifi_event_neighbor_report_t);
163
164/// Handle the given event using the registered event handlers.
165pub fn handle<Event: EventExt>(event_data: &Event) -> bool {
166    Event::handler().with(|handler| {
167        if let Some(handler) = handler {
168            handler(event_data);
169            true
170        } else {
171            false
172        }
173    })
174}
175
176/// Handle an event given the raw pointers.
177/// # Safety
178/// The pointer should be valid to cast to `Event`'s inner type (if it has one)
179pub(crate) unsafe fn handle_raw<Event: EventExt>(
180    event_data: *mut crate::binary::c_types::c_void,
181    event_data_size: usize,
182) -> bool {
183    debug_assert_eq!(
184        event_data_size,
185        core::mem::size_of::<Event>(),
186        "wrong size event data"
187    );
188
189    handle::<Event>(unsafe { &Event::from_raw_event_data(event_data) })
190}
191
192/// Handle event regardless of its type.
193/// # Safety
194/// Arguments should be self-consistent.
195#[rustfmt::skip]
196pub(crate) unsafe fn dispatch_event_handler(
197    event: WifiEvent,
198    event_data: *mut crate::binary::c_types::c_void,
199    event_data_size: usize,
200) -> bool {
201    match event {
202        WifiEvent::WifiReady => {
203            handle_raw::<WifiReady>(event_data, event_data_size)
204        }
205        WifiEvent::ScanDone => {
206            handle_raw::<ScanDone>(event_data, event_data_size)
207        }
208        WifiEvent::StaStart => {
209            handle_raw::<StaStart>(event_data, event_data_size)
210        }
211        WifiEvent::StaStop => {
212            handle_raw::<StaStop>(event_data, event_data_size)
213        }
214        WifiEvent::StaConnected => {
215            handle_raw::<StaConnected>(event_data, event_data_size)
216        }
217        WifiEvent::StaDisconnected => {
218            handle_raw::<StaDisconnected>(event_data, event_data_size)
219        }
220        WifiEvent::StaAuthmodeChange => {
221            handle_raw::<StaAuthmodeChange>(event_data, event_data_size)
222        }
223        WifiEvent::StaWpsErSuccess => {
224            handle_raw::<StaWpsErSuccess>(event_data, event_data_size)
225        }
226        WifiEvent::StaWpsErFailed => {
227            handle_raw::<StaWpsErFailed>(event_data, event_data_size)
228        }
229        WifiEvent::StaWpsErTimeout => {
230            handle_raw::<StaWpsErTimeout>(event_data, event_data_size)
231        }
232        WifiEvent::StaWpsErPin => {
233            handle_raw::<StaWpsErPin>(event_data, event_data_size)
234        }
235        WifiEvent::StaWpsErPbcOverlap => {
236            handle_raw::<StaWpsErPbcOverlap>(event_data, event_data_size)
237        }
238        WifiEvent::ApStart => {
239            handle_raw::<ApStart>(event_data, event_data_size)
240        }
241        WifiEvent::ApStop => {
242            handle_raw::<ApStop>(event_data, event_data_size)
243        }
244        WifiEvent::ApStaconnected => {
245            handle_raw::<ApStaconnected>(event_data, event_data_size)
246        }
247        WifiEvent::ApStadisconnected => {
248            handle_raw::<ApStadisconnected>(event_data, event_data_size)
249        }
250        WifiEvent::ApProbereqrecved => {
251            handle_raw::<ApProbereqrecved>(event_data, event_data_size)
252        }
253        WifiEvent::FtmReport => {
254            handle_raw::<FtmReport>(event_data, event_data_size)
255        }
256        WifiEvent::StaBssRssiLow => {
257            handle_raw::<StaBssRssiLow>(event_data, event_data_size)
258        }
259        WifiEvent::ActionTxStatus => {
260            handle_raw::<ActionTxStatus>(event_data, event_data_size)
261        }
262        WifiEvent::RocDone => {
263            handle_raw::<RocDone>(event_data, event_data_size)
264        }
265        WifiEvent::StaBeaconTimeout => {
266            handle_raw::<StaBeaconTimeout>(event_data, event_data_size)
267        }
268        WifiEvent::ConnectionlessModuleWakeIntervalStart => {
269            handle_raw::<ConnectionlessModuleWakeIntervalStart>(event_data, event_data_size)
270        }
271        WifiEvent::ApWpsRgSuccess => {
272            handle_raw::<ApWpsRgSuccess>(event_data, event_data_size)
273        }
274        WifiEvent::ApWpsRgFailed => {
275            handle_raw::<ApWpsRgFailed>(event_data, event_data_size)
276        }
277        WifiEvent::ApWpsRgTimeout => {
278            handle_raw::<ApWpsRgTimeout>(event_data, event_data_size)
279        }
280        WifiEvent::ApWpsRgPin => {
281            handle_raw::<ApWpsRgPin>(event_data, event_data_size)
282        }
283        WifiEvent::ApWpsRgPbcOverlap => {
284            handle_raw::<ApWpsRgPbcOverlap>(event_data, event_data_size)
285        }
286        WifiEvent::ItwtSetup => {
287            handle_raw::<ItwtSetup>(event_data, event_data_size)
288        }
289        WifiEvent::ItwtTeardown => {
290            handle_raw::<ItwtTeardown>(event_data, event_data_size)
291        }
292        WifiEvent::ItwtProbe => {
293            handle_raw::<ItwtProbe>(event_data, event_data_size)
294        }
295        WifiEvent::ItwtSuspend => {
296            handle_raw::<ItwtSuspend>(event_data, event_data_size)
297        }
298        WifiEvent::TwtWakeup => {
299            handle_raw::<TwtWakeup>(event_data, event_data_size)
300        }
301        WifiEvent::BtwtSetup => {
302            handle_raw::<BtwtSetup>(event_data, event_data_size)
303        }
304        WifiEvent::BtwtTeardown => {
305            handle_raw::<BtwtTeardown>(event_data, event_data_size)
306        }
307        WifiEvent::NanStarted => {
308            handle_raw::<NanStarted>(event_data, event_data_size)
309        }
310        WifiEvent::NanStopped => {
311            handle_raw::<NanStopped>(event_data, event_data_size)
312        }
313        WifiEvent::NanSvcMatch => {
314            handle_raw::<NanSvcMatch>(event_data, event_data_size)
315        }
316        WifiEvent::NanReplied => {
317            handle_raw::<NanReplied>(event_data, event_data_size)
318        }
319        WifiEvent::NanReceive => {
320            handle_raw::<NanReceive>(event_data, event_data_size)
321        }
322        WifiEvent::NdpIndication => {
323            handle_raw::<NdpIndication>(event_data, event_data_size)
324        }
325        WifiEvent::NdpConfirm => {
326            handle_raw::<NdpConfirm>(event_data, event_data_size)
327        }
328        WifiEvent::NdpTerminated => {
329            handle_raw::<NdpTerminated>(event_data, event_data_size)
330        }
331        WifiEvent::HomeChannelChange => {
332            handle_raw::<HomeChannelChange>(event_data, event_data_size)
333        }
334        WifiEvent::StaNeighborRep => {
335            handle_raw::<StaNeighborRep>(event_data, event_data_size)
336        }
337    }
338}