1use alloc::boxed::Box;
4
5use esp_sync::NonReentrantMutex;
6
7use super::WifiEvent;
8use crate::wifi::include::{
9 wifi_event_sta_wps_er_success_t__bindgen_ty_1,
10 wifi_ftm_report_entry_t,
11};
12
13pub(crate) mod sealed {
14 use super::*;
15
16 pub trait Event {
17 fn handler() -> &'static NonReentrantMutex<Option<Box<Handler<Self>>>>;
19 unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self;
22 }
23}
24
25#[instability::unstable]
27pub type Handler<T> = dyn FnMut(&T) + Sync + Send;
28
29fn default_handler<Event: 'static>() -> Box<Handler<Event>> {
30 fn drop_ref<T>(_: &T) {}
31 Box::new(drop_ref)
34}
35
36#[instability::unstable]
52pub trait EventExt: sealed::Event + Sized + 'static {
53 fn take_handler() -> Box<Handler<Self>> {
55 Self::handler().with(|handler| handler.take().unwrap_or_else(default_handler::<Self>))
56 }
57
58 fn replace_handler<F: FnMut(&Self) + Sync + Send + 'static>(f: F) -> Box<Handler<Self>> {
60 Self::handler().with(|handler| {
61 handler
62 .replace(Box::new(f))
63 .unwrap_or_else(default_handler::<Self>)
64 })
65 }
66
67 fn update_handler<F: FnMut(&Self) + Sync + Send + 'static>(mut f: F) {
71 Self::handler().with(|handler| {
72 let mut prev: Box<Handler<Self>> =
73 handler.take().unwrap_or_else(default_handler::<Self>);
74 handler.replace(Box::new(move |event| {
75 prev(event);
76 f(event)
77 }));
78 })
79 }
80}
81
82impl<T: sealed::Event + 'static> EventExt for T {}
83
84macro_rules! impl_wifi_event {
85 ($newtype:ident) => {
87 #[derive(Copy, Clone)]
89 pub struct $newtype;
90
91 impl sealed::Event for $newtype {
92 unsafe fn from_raw_event_data(_: *mut crate::binary::c_types::c_void) -> Self {
93 Self
94 }
95 fn handler() -> &'static NonReentrantMutex<Option<Box<Handler<Self>>>> {
96 static HANDLE: NonReentrantMutex<Option<Box<Handler<$newtype>>>> =
97 NonReentrantMutex::new(None);
98 &HANDLE
99 }
100 }
101 };
102
103 ($newtype:ident, $data:ident) => {
104 use esp_wifi_sys::include::$data;
105 #[derive(Copy, Clone)]
107 pub struct $newtype<'a>(&'a $data);
108
109 impl sealed::Event for $newtype<'_> {
110 unsafe fn from_raw_event_data(ptr: *mut crate::binary::c_types::c_void) -> Self {
111 Self(unsafe { &*ptr.cast() })
112 }
113
114 fn handler() -> &'static NonReentrantMutex<Option<Box<Handler<Self>>>> {
115 static HANDLE: NonReentrantMutex<Option<Box<Handler<$newtype<'_>>>>> =
116 NonReentrantMutex::new(None);
117 &HANDLE
118 }
119 }
120 };
121}
122
123impl_wifi_event!(WifiReady);
124impl_wifi_event!(ScanDone, wifi_event_sta_scan_done_t);
125impl_wifi_event!(StaStart);
126impl_wifi_event!(StaStop);
127impl_wifi_event!(StaConnected, wifi_event_sta_connected_t);
128impl_wifi_event!(StaDisconnected, wifi_event_sta_disconnected_t);
129impl_wifi_event!(StaAuthmodeChange, wifi_event_sta_authmode_change_t);
130impl_wifi_event!(StaWpsErSuccess, wifi_event_sta_wps_er_success_t);
131impl_wifi_event!(StaWpsErFailed);
132impl_wifi_event!(StaWpsErTimeout);
133impl_wifi_event!(StaWpsErPin, wifi_event_sta_wps_er_pin_t);
134impl_wifi_event!(StaWpsErPbcOverlap);
135impl_wifi_event!(ApStart);
136impl_wifi_event!(ApStop);
137impl_wifi_event!(ApStaConnected, wifi_event_ap_staconnected_t);
138impl_wifi_event!(ApStaDisconnected, wifi_event_ap_stadisconnected_t);
139impl_wifi_event!(ApProbeReqReceived, wifi_event_ap_probe_req_rx_t);
140impl_wifi_event!(FtmReport, wifi_event_ftm_report_t);
141impl_wifi_event!(StaBssRssiLow, wifi_event_bss_rssi_low_t);
142impl_wifi_event!(ActionTxStatus, wifi_event_action_tx_status_t);
143impl_wifi_event!(RocDone, wifi_event_roc_done_t);
144impl_wifi_event!(StaBeaconTimeout);
145impl_wifi_event!(ConnectionlessModuleWakeIntervalStart);
146impl_wifi_event!(ApWpsRgSuccess, wifi_event_ap_wps_rg_success_t);
147impl_wifi_event!(ApWpsRgFailed, wifi_event_ap_wps_rg_fail_reason_t);
148impl_wifi_event!(ApWpsRgTimeout);
149impl_wifi_event!(ApWpsRgPin, wifi_event_ap_wps_rg_pin_t);
150impl_wifi_event!(ApWpsRgPbcOverlap);
151impl_wifi_event!(ItwtSetup);
152impl_wifi_event!(ItwtTeardown);
153impl_wifi_event!(ItwtProbe);
154impl_wifi_event!(ItwtSuspend);
155impl_wifi_event!(TwtWakeup);
156impl_wifi_event!(BtwtSetup);
157impl_wifi_event!(BtwtTeardown);
158impl_wifi_event!(NanStarted);
159impl_wifi_event!(NanStopped);
160impl_wifi_event!(NanSvcMatch, wifi_event_nan_svc_match_t);
161impl_wifi_event!(NanReplied, wifi_event_nan_replied_t);
162impl_wifi_event!(NanReceive, wifi_event_nan_receive_t);
163impl_wifi_event!(NdpIndication, wifi_event_ndp_indication_t);
164impl_wifi_event!(NdpConfirm, wifi_event_ndp_confirm_t);
165impl_wifi_event!(NdpTerminated, wifi_event_ndp_terminated_t);
166impl_wifi_event!(HomeChannelChange, wifi_event_home_channel_change_t);
167impl_wifi_event!(StaNeighborRep, wifi_event_neighbor_report_t);
168
169impl ApStaConnected<'_> {
170 pub fn mac(&self) -> &[u8] {
172 &self.0.mac
173 }
174
175 pub fn aid(&self) -> u8 {
177 self.0.aid
178 }
179
180 pub fn is_mesh_child(&self) -> bool {
182 self.0.is_mesh_child
183 }
184}
185
186impl ApStaDisconnected<'_> {
187 pub fn mac(&self) -> &[u8] {
189 &self.0.mac
190 }
191
192 pub fn reason(&self) -> u16 {
194 self.0.reason
195 }
196
197 pub fn aid(&self) -> u8 {
199 self.0.aid
200 }
201
202 pub fn is_mesh_child(&self) -> bool {
204 self.0.is_mesh_child
205 }
206}
207
208impl ScanDone<'_> {
209 pub fn status(&self) -> u32 {
211 self.0.status
212 }
213
214 pub fn number(&self) -> u8 {
216 self.0.number
217 }
218
219 pub fn id(&self) -> u8 {
221 self.0.scan_id
222 }
223}
224
225impl StaConnected<'_> {
226 pub fn ssid(&self) -> &[u8] {
228 &self.0.ssid
229 }
230
231 pub fn ssid_len(&self) -> u8 {
233 self.0.ssid_len
234 }
235
236 pub fn bssid(&self) -> &[u8] {
238 &self.0.bssid
239 }
240
241 pub fn channel(&self) -> u8 {
243 self.0.channel
244 }
245
246 pub fn authmode(&self) -> u32 {
248 self.0.authmode
249 }
250
251 pub fn aid(&self) -> u16 {
253 self.0.aid
254 }
255}
256
257impl StaDisconnected<'_> {
258 pub fn ssid(&self) -> &[u8] {
260 &self.0.ssid
261 }
262
263 pub fn ssid_len(&self) -> u8 {
265 self.0.ssid_len
266 }
267
268 pub fn bssid(&self) -> &[u8] {
270 &self.0.bssid
271 }
272
273 pub fn reason(&self) -> u8 {
275 self.0.reason
276 }
277
278 pub fn rssi(&self) -> i8 {
280 self.0.rssi
281 }
282}
283
284#[repr(transparent)]
286pub struct ApCredential(wifi_event_sta_wps_er_success_t__bindgen_ty_1);
287
288impl ApCredential {
289 pub fn ssid(&self) -> &[u8] {
291 &self.0.ssid
292 }
293
294 pub fn passphrase(&self) -> &[u8] {
296 &self.0.passphrase
297 }
298}
299
300impl StaAuthmodeChange<'_> {
301 pub fn old_mode(&self) -> u32 {
303 self.0.old_mode
304 }
305
306 pub fn new_mode(&self) -> u32 {
308 self.0.new_mode
309 }
310}
311
312impl StaWpsErSuccess<'_> {
313 pub fn ap_cred_cnt(&self) -> u8 {
315 self.0.ap_cred_cnt
316 }
317
318 pub fn ap_cred(&self) -> &[ApCredential] {
320 let array_ref: &[ApCredential; 3] =
321 unsafe { &*(&self.0.ap_cred as *const _ as *const [ApCredential; 3]) };
323
324 &array_ref[..]
325 }
326}
327
328impl StaWpsErPin<'_> {
329 pub fn pin(&self) -> &[u8] {
331 &self.0.pin_code
332 }
333}
334
335#[repr(transparent)]
337pub struct FtmReportEntry<'a>(&'a wifi_ftm_report_entry_t);
338
339impl FtmReportEntry<'_> {
340 pub fn dialog_token(&self) -> u8 {
342 self.0.dlog_token
343 }
344
345 pub fn rssi(&self) -> i8 {
347 self.0.rssi
348 }
349
350 pub fn rtt(&self) -> u32 {
352 self.0.rtt
353 }
354
355 pub fn t1(&self) -> u64 {
357 self.0.t1
358 }
359
360 pub fn t2(&self) -> u64 {
362 self.0.t2
363 }
364
365 pub fn t3(&self) -> u64 {
367 self.0.t3
368 }
369
370 pub fn t4(&self) -> u64 {
372 self.0.t4
373 }
374}
375
376impl FtmReport<'_> {
377 pub fn peer_mac(&self) -> &[u8] {
379 &self.0.peer_mac
380 }
381
382 pub fn status(&self) -> u32 {
384 self.0.status
385 }
386
387 pub fn rtt_raw(&self) -> u32 {
389 self.0.rtt_raw
390 }
391
392 pub fn rtt_est(&self) -> u32 {
394 self.0.rtt_est
395 }
396
397 pub fn dist_est(&self) -> u32 {
399 self.0.dist_est
400 }
401
402 pub fn report_num_entries(&self) -> u8 {
404 self.0.ftm_report_num_entries
405 }
406
407 pub fn entries(&self) -> impl Iterator<Item = FtmReportEntry<'_>> + '_ {
409 let ptr = self.0.ftm_report_data;
410 let len = self.0.ftm_report_num_entries as usize;
411
412 let entries_slice = if ptr.is_null() || len == 0 {
414 &[]
415 } else {
416 unsafe { core::slice::from_raw_parts(ptr, len) }
419 };
420
421 entries_slice.iter().map(FtmReportEntry)
422 }
423}
424
425impl ApProbeReqReceived<'_> {
426 pub fn rssi(&self) -> i32 {
428 self.0.rssi
429 }
430
431 pub fn mac(&self) -> &[u8] {
433 &self.0.mac
434 }
435}
436
437impl StaBssRssiLow<'_> {
438 pub fn rssi(&self) -> i32 {
440 self.0.rssi
441 }
442}
443
444impl ActionTxStatus<'_> {
445 pub fn ifx(&self) -> u32 {
447 self.0.ifx
448 }
449
450 pub fn context(&self) -> u32 {
452 self.0.context
453 }
454
455 pub fn op_id(&self) -> u8 {
457 self.0.op_id
458 }
459
460 pub fn channel(&self) -> u8 {
462 self.0.channel
463 }
464
465 pub fn status(&self) -> u32 {
467 self.0.status
468 }
469}
470
471impl RocDone<'_> {
472 pub fn context(&self) -> u32 {
474 self.0.context
475 }
476}
477
478impl ApWpsRgSuccess<'_> {
479 pub fn peer_mac(&self) -> &[u8] {
481 &self.0.peer_macaddr
482 }
483}
484
485impl ApWpsRgFailed<'_> {
486 pub fn reason(&self) -> u32 {
488 self.0.reason
489 }
490
491 pub fn peer_macaddr(&self) -> &[u8; 6] {
493 &self.0.peer_macaddr
494 }
495}
496
497impl ApWpsRgPin<'_> {
498 pub fn pin_code(&self) -> &[u8] {
500 &self.0.pin_code
501 }
502}
503
504impl NanSvcMatch<'_> {
505 pub fn subscribe_id(&self) -> u8 {
507 self.0.subscribe_id
508 }
509
510 pub fn publish_id(&self) -> u8 {
512 self.0.publish_id
513 }
514
515 pub fn pub_if_mac(&self) -> &[u8] {
517 &self.0.pub_if_mac
518 }
519
520 pub fn update_pub_id(&self) -> bool {
522 self.0.update_pub_id
523 }
524}
525
526impl NanReplied<'_> {
527 pub fn subscribe_id(&self) -> u8 {
529 self.0.subscribe_id
530 }
531
532 pub fn publish_id(&self) -> u8 {
534 self.0.publish_id
535 }
536
537 pub fn sub_if_mac(&self) -> &[u8] {
539 &self.0.sub_if_mac
540 }
541}
542
543impl NanReceive<'_> {
544 pub fn inst_id(&self) -> u8 {
546 self.0.inst_id
547 }
548
549 pub fn peer_inst_id(&self) -> u8 {
551 self.0.peer_inst_id
552 }
553
554 pub fn peer_if_mac(&self) -> &[u8; 6] {
556 &self.0.peer_if_mac
557 }
558
559 pub fn peer_svc_info(&self) -> &[u8; 64] {
561 &self.0.peer_svc_info
562 }
563}
564
565impl NdpIndication<'_> {
566 pub fn publish_id(&self) -> u8 {
568 self.0.publish_id
569 }
570
571 pub fn ndp_id(&self) -> u8 {
573 self.0.ndp_id
574 }
575
576 pub fn peer_nmi(&self) -> &[u8; 6] {
578 &self.0.peer_nmi
579 }
580
581 pub fn peer_ndi(&self) -> &[u8; 6] {
583 &self.0.peer_ndi
584 }
585
586 pub fn svc_info(&self) -> &[u8; 64] {
588 &self.0.svc_info
589 }
590}
591
592impl NdpConfirm<'_> {
593 pub fn status(&self) -> u8 {
595 self.0.status
596 }
597
598 pub fn id(&self) -> u8 {
600 self.0.ndp_id
601 }
602
603 pub fn peer_nmi(&self) -> &[u8; 6] {
605 &self.0.peer_nmi
606 }
607
608 pub fn peer_ndi(&self) -> &[u8; 6] {
610 &self.0.peer_ndi
611 }
612
613 pub fn own_ndi(&self) -> &[u8; 6] {
615 &self.0.own_ndi
616 }
617
618 pub fn svc_info(&self) -> &[u8; 64] {
620 &self.0.svc_info
621 }
622}
623
624impl NdpTerminated<'_> {
625 pub fn reason(&self) -> u8 {
627 self.0.reason
628 }
629
630 pub fn id(&self) -> u8 {
632 self.0.ndp_id
633 }
634
635 pub fn init_ndi(&self) -> &[u8; 6] {
637 &self.0.init_ndi
638 }
639}
640
641impl HomeChannelChange<'_> {
642 pub fn old_chan(&self) -> u8 {
644 self.0.old_chan
645 }
646
647 pub fn old_snd(&self) -> u32 {
649 self.0.old_snd
650 }
651
652 pub fn new_chan(&self) -> u8 {
654 self.0.new_chan
655 }
656
657 pub fn new_snd(&self) -> u32 {
659 self.0.new_snd
660 }
661}
662
663impl StaNeighborRep<'_> {
664 pub fn report(&self) -> &[u8] {
666 &self.0.report[..self.0.report_len as usize]
667 }
668
669 pub fn report_len(&self) -> u16 {
671 self.0.report_len
672 }
673}
674
675#[instability::unstable]
677pub fn handle<Event: EventExt>(event_data: &Event) -> bool {
678 Event::handler().with(|handler| {
679 if let Some(handler) = handler {
680 handler(event_data);
681 true
682 } else {
683 false
684 }
685 })
686}
687
688pub(crate) unsafe fn handle_raw<Event: EventExt>(
693 event_data: *mut crate::binary::c_types::c_void,
694 _event_data_size: usize,
695) -> bool {
696 let event = unsafe { Event::from_raw_event_data(event_data) };
697 handle::<Event>(&event)
698}
699
700#[rustfmt::skip]
705pub(crate) unsafe fn dispatch_event_handler(
706 event: WifiEvent,
707 event_data: *mut crate::binary::c_types::c_void,
708 event_data_size: usize,
709) -> bool { unsafe {
710 match event {
711 WifiEvent::WifiReady => {
712 handle_raw::<WifiReady>(event_data, event_data_size)
713 }
714 WifiEvent::ScanDone => {
715 handle_raw::<ScanDone<'_>>(event_data, event_data_size)
716 }
717 WifiEvent::StaStart => {
718 handle_raw::<StaStart>(event_data, event_data_size)
719 }
720 WifiEvent::StaStop => {
721 handle_raw::<StaStop>(event_data, event_data_size)
722 }
723 WifiEvent::StaConnected => {
724 handle_raw::<StaConnected<'_>>(event_data, event_data_size)
725 }
726 WifiEvent::StaDisconnected => {
727 handle_raw::<StaDisconnected<'_>>(event_data, event_data_size)
728 }
729 WifiEvent::StaAuthmodeChange => {
730 handle_raw::<StaAuthmodeChange<'_>>(event_data, event_data_size)
731 }
732 WifiEvent::StaWpsErSuccess => {
733 handle_raw::<StaWpsErSuccess<'_>>(event_data, event_data_size)
734 }
735 WifiEvent::StaWpsErFailed => {
736 handle_raw::<StaWpsErFailed>(event_data, event_data_size)
737 }
738 WifiEvent::StaWpsErTimeout => {
739 handle_raw::<StaWpsErTimeout>(event_data, event_data_size)
740 }
741 WifiEvent::StaWpsErPin => {
742 handle_raw::<StaWpsErPin<'_>>(event_data, event_data_size)
743 }
744 WifiEvent::StaWpsErPbcOverlap => {
745 handle_raw::<StaWpsErPbcOverlap>(event_data, event_data_size)
746 }
747 WifiEvent::ApStart => {
748 handle_raw::<ApStart>(event_data, event_data_size)
749 }
750 WifiEvent::ApStop => {
751 handle_raw::<ApStop>(event_data, event_data_size)
752 }
753 WifiEvent::ApStaConnected => {
754 handle_raw::<ApStaConnected<'_>>(event_data, event_data_size)
755 }
756 WifiEvent::ApStaDisconnected => {
757 handle_raw::<ApStaDisconnected<'_>>(event_data, event_data_size)
758 }
759 WifiEvent::ApProbeReqReceived => {
760 handle_raw::<ApProbeReqReceived<'_>>(event_data, event_data_size)
761 }
762 WifiEvent::FtmReport => {
763 handle_raw::<FtmReport<'_>>(event_data, event_data_size)
764 }
765 WifiEvent::StaBssRssiLow => {
766 handle_raw::<StaBssRssiLow<'_>>(event_data, event_data_size)
767 }
768 WifiEvent::ActionTxStatus => {
769 handle_raw::<ActionTxStatus<'_>>(event_data, event_data_size)
770 }
771 WifiEvent::RocDone => {
772 handle_raw::<RocDone<'_>>(event_data, event_data_size)
773 }
774 WifiEvent::StaBeaconTimeout => {
775 handle_raw::<StaBeaconTimeout>(event_data, event_data_size)
776 }
777 WifiEvent::ConnectionlessModuleWakeIntervalStart => {
778 handle_raw::<ConnectionlessModuleWakeIntervalStart>(event_data, event_data_size)
779 }
780 WifiEvent::ApWpsRgSuccess => {
781 handle_raw::<ApWpsRgSuccess<'_>>(event_data, event_data_size)
782 }
783 WifiEvent::ApWpsRgFailed => {
784 handle_raw::<ApWpsRgFailed<'_>>(event_data, event_data_size)
785 }
786 WifiEvent::ApWpsRgTimeout => {
787 handle_raw::<ApWpsRgTimeout>(event_data, event_data_size)
788 }
789 WifiEvent::ApWpsRgPin => {
790 handle_raw::<ApWpsRgPin<'_>>(event_data, event_data_size)
791 }
792 WifiEvent::ApWpsRgPbcOverlap => {
793 handle_raw::<ApWpsRgPbcOverlap>(event_data, event_data_size)
794 }
795 WifiEvent::ItwtSetup => {
796 handle_raw::<ItwtSetup>(event_data, event_data_size)
797 }
798 WifiEvent::ItwtTeardown => {
799 handle_raw::<ItwtTeardown>(event_data, event_data_size)
800 }
801 WifiEvent::ItwtProbe => {
802 handle_raw::<ItwtProbe>(event_data, event_data_size)
803 }
804 WifiEvent::ItwtSuspend => {
805 handle_raw::<ItwtSuspend>(event_data, event_data_size)
806 }
807 WifiEvent::TwtWakeup => {
808 handle_raw::<TwtWakeup>(event_data, event_data_size)
809 }
810 WifiEvent::BtwtSetup => {
811 handle_raw::<BtwtSetup>(event_data, event_data_size)
812 }
813 WifiEvent::BtwtTeardown => {
814 handle_raw::<BtwtTeardown>(event_data, event_data_size)
815 }
816 WifiEvent::NanStarted => {
817 handle_raw::<NanStarted>(event_data, event_data_size)
818 }
819 WifiEvent::NanStopped => {
820 handle_raw::<NanStopped>(event_data, event_data_size)
821 }
822 WifiEvent::NanSvcMatch => {
823 handle_raw::<NanSvcMatch<'_>>(event_data, event_data_size)
824 }
825 WifiEvent::NanReplied => {
826 handle_raw::<NanReplied<'_>>(event_data, event_data_size)
827 }
828 WifiEvent::NanReceive => {
829 handle_raw::<NanReceive<'_>>(event_data, event_data_size)
830 }
831 WifiEvent::NdpIndication => {
832 handle_raw::<NdpIndication<'_>>(event_data, event_data_size)
833 }
834 WifiEvent::NdpConfirm => {
835 handle_raw::<NdpConfirm<'_>>(event_data, event_data_size)
836 }
837 WifiEvent::NdpTerminated => {
838 handle_raw::<NdpTerminated<'_>>(event_data, event_data_size)
839 }
840 WifiEvent::HomeChannelChange => {
841 handle_raw::<HomeChannelChange<'_>>(event_data, event_data_size)
842 }
843 WifiEvent::StaNeighborRep => {
844 handle_raw::<StaNeighborRep<'_>>(event_data, event_data_size)
845 }
846 }
847}}