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(wifi_has_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    let event = unsafe { Event::from_raw_event_data(event_data) };
190    handle::<Event>(&event)
191}
192
193/// Handle event regardless of its type.
194/// # Safety
195/// Arguments should be self-consistent.
196#[rustfmt::skip]
197pub(crate) unsafe fn dispatch_event_handler(
198    event: WifiEvent,
199    event_data: *mut crate::binary::c_types::c_void,
200    event_data_size: usize,
201) -> bool { unsafe {
202    match event {
203        WifiEvent::WifiReady => {
204            handle_raw::<WifiReady>(event_data, event_data_size)
205        }
206        WifiEvent::ScanDone => {
207            handle_raw::<ScanDone>(event_data, event_data_size)
208        }
209        WifiEvent::StaStart => {
210            handle_raw::<StaStart>(event_data, event_data_size)
211        }
212        WifiEvent::StaStop => {
213            handle_raw::<StaStop>(event_data, event_data_size)
214        }
215        WifiEvent::StaConnected => {
216            handle_raw::<StaConnected>(event_data, event_data_size)
217        }
218        WifiEvent::StaDisconnected => {
219            handle_raw::<StaDisconnected>(event_data, event_data_size)
220        }
221        WifiEvent::StaAuthmodeChange => {
222            handle_raw::<StaAuthmodeChange>(event_data, event_data_size)
223        }
224        WifiEvent::StaWpsErSuccess => {
225            handle_raw::<StaWpsErSuccess>(event_data, event_data_size)
226        }
227        WifiEvent::StaWpsErFailed => {
228            handle_raw::<StaWpsErFailed>(event_data, event_data_size)
229        }
230        WifiEvent::StaWpsErTimeout => {
231            handle_raw::<StaWpsErTimeout>(event_data, event_data_size)
232        }
233        WifiEvent::StaWpsErPin => {
234            handle_raw::<StaWpsErPin>(event_data, event_data_size)
235        }
236        WifiEvent::StaWpsErPbcOverlap => {
237            handle_raw::<StaWpsErPbcOverlap>(event_data, event_data_size)
238        }
239        WifiEvent::ApStart => {
240            handle_raw::<ApStart>(event_data, event_data_size)
241        }
242        WifiEvent::ApStop => {
243            handle_raw::<ApStop>(event_data, event_data_size)
244        }
245        WifiEvent::ApStaconnected => {
246            handle_raw::<ApStaconnected>(event_data, event_data_size)
247        }
248        WifiEvent::ApStadisconnected => {
249            handle_raw::<ApStadisconnected>(event_data, event_data_size)
250        }
251        WifiEvent::ApProbereqrecved => {
252            handle_raw::<ApProbereqrecved>(event_data, event_data_size)
253        }
254        WifiEvent::FtmReport => {
255            handle_raw::<FtmReport>(event_data, event_data_size)
256        }
257        WifiEvent::StaBssRssiLow => {
258            handle_raw::<StaBssRssiLow>(event_data, event_data_size)
259        }
260        WifiEvent::ActionTxStatus => {
261            handle_raw::<ActionTxStatus>(event_data, event_data_size)
262        }
263        WifiEvent::RocDone => {
264            handle_raw::<RocDone>(event_data, event_data_size)
265        }
266        WifiEvent::StaBeaconTimeout => {
267            handle_raw::<StaBeaconTimeout>(event_data, event_data_size)
268        }
269        WifiEvent::ConnectionlessModuleWakeIntervalStart => {
270            handle_raw::<ConnectionlessModuleWakeIntervalStart>(event_data, event_data_size)
271        }
272        WifiEvent::ApWpsRgSuccess => {
273            handle_raw::<ApWpsRgSuccess>(event_data, event_data_size)
274        }
275        WifiEvent::ApWpsRgFailed => {
276            handle_raw::<ApWpsRgFailed>(event_data, event_data_size)
277        }
278        WifiEvent::ApWpsRgTimeout => {
279            handle_raw::<ApWpsRgTimeout>(event_data, event_data_size)
280        }
281        WifiEvent::ApWpsRgPin => {
282            handle_raw::<ApWpsRgPin>(event_data, event_data_size)
283        }
284        WifiEvent::ApWpsRgPbcOverlap => {
285            handle_raw::<ApWpsRgPbcOverlap>(event_data, event_data_size)
286        }
287        WifiEvent::ItwtSetup => {
288            handle_raw::<ItwtSetup>(event_data, event_data_size)
289        }
290        WifiEvent::ItwtTeardown => {
291            handle_raw::<ItwtTeardown>(event_data, event_data_size)
292        }
293        WifiEvent::ItwtProbe => {
294            handle_raw::<ItwtProbe>(event_data, event_data_size)
295        }
296        WifiEvent::ItwtSuspend => {
297            handle_raw::<ItwtSuspend>(event_data, event_data_size)
298        }
299        WifiEvent::TwtWakeup => {
300            handle_raw::<TwtWakeup>(event_data, event_data_size)
301        }
302        WifiEvent::BtwtSetup => {
303            handle_raw::<BtwtSetup>(event_data, event_data_size)
304        }
305        WifiEvent::BtwtTeardown => {
306            handle_raw::<BtwtTeardown>(event_data, event_data_size)
307        }
308        WifiEvent::NanStarted => {
309            handle_raw::<NanStarted>(event_data, event_data_size)
310        }
311        WifiEvent::NanStopped => {
312            handle_raw::<NanStopped>(event_data, event_data_size)
313        }
314        WifiEvent::NanSvcMatch => {
315            handle_raw::<NanSvcMatch>(event_data, event_data_size)
316        }
317        WifiEvent::NanReplied => {
318            handle_raw::<NanReplied>(event_data, event_data_size)
319        }
320        WifiEvent::NanReceive => {
321            handle_raw::<NanReceive>(event_data, event_data_size)
322        }
323        WifiEvent::NdpIndication => {
324            handle_raw::<NdpIndication>(event_data, event_data_size)
325        }
326        WifiEvent::NdpConfirm => {
327            handle_raw::<NdpConfirm>(event_data, event_data_size)
328        }
329        WifiEvent::NdpTerminated => {
330            handle_raw::<NdpTerminated>(event_data, event_data_size)
331        }
332        WifiEvent::HomeChannelChange => {
333            handle_raw::<HomeChannelChange>(event_data, event_data_size)
334        }
335        WifiEvent::StaNeighborRep => {
336            handle_raw::<StaNeighborRep>(event_data, event_data_size)
337        }
338    }
339}}