1use enumset::{EnumSet, EnumSetType};
7use esp_config::esp_config_int;
8use esp_sync::NonReentrantMutex;
9use num_derive::FromPrimitive;
10
11use super::Ssid;
12
13static WIFI_EVENT_ENABLE_MASK: NonReentrantMutex<EnumSet<WifiEvent>> =
14 NonReentrantMutex::new(enumset::enum_set!());
15
16pub(crate) static EVENT_CHANNEL: embassy_sync::pubsub::PubSubChannel<
17 esp_sync::RawMutex,
18 EventInfo,
19 { esp_config_int!(usize, "ESP_RADIO_CONFIG_EVENT_CHANNEL_CAPACITY") },
20 { esp_config_int!(usize, "ESP_RADIO_CONFIG_EVENT_CHANNEL_SUBSCRIBERS") },
21 1,
22> = embassy_sync::pubsub::PubSubChannel::new();
23
24#[derive(Debug, Hash, FromPrimitive, EnumSetType)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27#[non_exhaustive]
28#[repr(i32)]
29#[instability::unstable]
30pub enum WifiEvent {
31 WifiReady = 0,
33 ScanDone,
35 StationStart,
37 StationStop,
39 StationConnected,
41 StationDisconnected,
43 StationAuthenticationModeChange,
45
46 StationWifiProtectedStatusEnrolleeSuccess,
48 StationWifiProtectedStatusEnrolleeFailed,
50 StationWifiProtectedStatusEnrolleeTimeout,
52 StationWifiProtectedStatusEnrolleePin,
54 StationWifiProtectedStatusEnrolleePushButtonConfigurationOverlap,
56
57 AccessPointStart,
59 AccessPointStop,
61 AccessPointStationConnected,
63 AccessPointStationDisconnected,
65 AccessPointProbeRequestReceived,
67
68 FineTimingMeasurementReport,
70
71 StationBasicServiceSetReceivedSignalStrengthIndicatorLow,
73 ActionTransmissionStatus,
75 RemainOnChannelDone,
77
78 StationBeaconTimeout,
80
81 ConnectionlessModuleWakeIntervalStart,
83
84 AccessPointWifiProtectedStatusRegistrarSuccess,
86 AccessPointWifiProtectedStatusRegistrarFailed,
88 AccessPointWifiProtectedStatusRegistrarTimeout,
90 AccessPointWifiProtectedStatusRegistrarPin,
92 AccessPointWifiProtectedStatusRegistrarPushButtonConfigurationOverlap,
94
95 IndividualTargetWakeTimeSetup,
97 IndividualTargetWakeTimeTeardown,
99 IndividualTargetWakeTimeProbe,
101 IndividualTargetWakeTimeSuspend,
103 TargetWakeTimeWakeup,
105 BroadcastTargetWakeTimeSetup,
107 BroadcastTargetWakeTimeTeardown,
109
110 NeighborAwarenessNetworkingStarted,
112 NeighborAwarenessNetworkingStopped,
114 NeighborAwarenessNetworkingServiceMatch,
116 NeighborAwarenessNetworkingReplied,
118 NeighborAwarenessNetworkingReceive,
120 NeighborDiscoveryProtocolIndication,
123 NeighborDiscoveryProtocolConfirmation,
125 NeighborDiscoveryProtocolTerminated,
127 HomeChannelChange,
129
130 StationNeighborRep,
132}
133
134trait Event {
135 unsafe fn from_raw_event_data(ptr: *mut crate::sys::c_types::c_void) -> Self;
138}
139
140macro_rules! impl_wifi_event {
141 ($newtype:ident) => {
143 #[derive(Copy, Clone)]
145 #[instability::unstable]
146 pub struct $newtype;
147
148 impl Event for $newtype {
149 unsafe fn from_raw_event_data(_: *mut crate::sys::c_types::c_void) -> Self {
150 Self
151 }
152 }
153 };
154
155 ($newtype:ident, $data:ident) => {
156 use crate::sys::include::$data;
157 #[derive(Copy, Clone)]
159 #[instability::unstable]
160 pub struct $newtype<'a>(&'a $data);
161
162 impl Event for $newtype<'_> {
163 unsafe fn from_raw_event_data(ptr: *mut crate::sys::c_types::c_void) -> Self {
164 Self(unsafe { &*ptr.cast() })
165 }
166 }
167 };
168}
169
170impl_wifi_event!(WifiReady);
171impl_wifi_event!(ScanDone, wifi_event_sta_scan_done_t);
172impl_wifi_event!(StationStart);
173impl_wifi_event!(StationStop);
174impl_wifi_event!(StationConnected, wifi_event_sta_connected_t);
175impl_wifi_event!(StationDisconnected, wifi_event_sta_disconnected_t);
176impl_wifi_event!(
177 StationAuthenticationModeChange,
178 wifi_event_sta_authmode_change_t
179);
180impl_wifi_event!(
181 StationWifiProtectedStatusEnrolleeSuccess,
182 wifi_event_sta_wps_er_success_t
183);
184impl_wifi_event!(StationWifiProtectedStatusEnrolleeFailed);
185impl_wifi_event!(StationWifiProtectedStatusEnrolleeTimeout);
186impl_wifi_event!(
187 StationWifiProtectedStatusEnrolleePin,
188 wifi_event_sta_wps_er_pin_t
189);
190impl_wifi_event!(StationWifiProtectedStatusEnrolleePushButtonConfigurationOverlap);
191impl_wifi_event!(AccessPointStart);
192impl_wifi_event!(AccessPointStop);
193impl_wifi_event!(AccessPointStationConnected, wifi_event_ap_staconnected_t);
194impl_wifi_event!(
195 AccessPointStationDisconnected,
196 wifi_event_ap_stadisconnected_t
197);
198impl_wifi_event!(
199 AccessPointProbeRequestReceived,
200 wifi_event_ap_probe_req_rx_t
201);
202impl_wifi_event!(FineTimingMeasurementReport, wifi_event_ftm_report_t);
203impl_wifi_event!(
204 StationBasicServiceSetReceivedSignalStrengthIndicatorLow,
205 wifi_event_bss_rssi_low_t
206);
207impl_wifi_event!(ActionTransmissionStatus, wifi_event_action_tx_status_t);
208impl_wifi_event!(RemainOnChannelDone, wifi_event_roc_done_t);
209impl_wifi_event!(StationBeaconTimeout);
210impl_wifi_event!(ConnectionlessModuleWakeIntervalStart);
211impl_wifi_event!(
212 AccessPointWifiProtectedStatusRegistrarSuccess,
213 wifi_event_ap_wps_rg_success_t
214);
215impl_wifi_event!(
216 AccessPointWifiProtectedStatusRegistrarFailed,
217 wifi_event_ap_wps_rg_fail_reason_t
218);
219impl_wifi_event!(AccessPointWifiProtectedStatusRegistrarTimeout);
220impl_wifi_event!(
221 AccessPointWifiProtectedStatusRegistrarPin,
222 wifi_event_ap_wps_rg_pin_t
223);
224impl_wifi_event!(AccessPointWifiProtectedStatusRegistrarPushButtonConfigurationOverlap);
225impl_wifi_event!(IndividualTargetWakeTimeSetup);
226impl_wifi_event!(IndividualTargetWakeTimeTeardown);
227impl_wifi_event!(IndividualTargetWakeTimeProbe);
228impl_wifi_event!(IndividualTargetWakeTimeSuspend);
229impl_wifi_event!(TargetWakeTimeWakeup);
230impl_wifi_event!(BroadcastTargetWakeTimeSetup);
231impl_wifi_event!(BroadcastTargetWakeTimeTeardown);
232impl_wifi_event!(NeighborAwarenessNetworkingStarted);
233impl_wifi_event!(NeighborAwarenessNetworkingStopped);
234impl_wifi_event!(
235 NeighborAwarenessNetworkingServiceMatch,
236 wifi_event_nan_svc_match_t
237);
238impl_wifi_event!(NeighborAwarenessNetworkingReplied, wifi_event_nan_replied_t);
239impl_wifi_event!(NeighborAwarenessNetworkingReceive, wifi_event_nan_receive_t);
240impl_wifi_event!(
241 NeighborDiscoveryProtocolIndication,
242 wifi_event_ndp_indication_t
243);
244impl_wifi_event!(
245 NeighborDiscoveryProtocolConfirmation,
246 wifi_event_ndp_confirm_t
247);
248impl_wifi_event!(
249 NeighborDiscoveryProtocolTerminated,
250 wifi_event_ndp_terminated_t
251);
252impl_wifi_event!(HomeChannelChange, wifi_event_home_channel_change_t);
253impl_wifi_event!(StationNeighborRep, wifi_event_neighbor_report_t);
254impl_wifi_event!(
255 AccessPointCredential,
256 wifi_event_sta_wps_er_success_t__bindgen_ty_1
257);
258
259impl AccessPointStationConnected<'_> {
260 pub fn mac(&self) -> &[u8] {
262 &self.0.mac
263 }
264
265 pub fn aid(&self) -> u8 {
267 self.0.aid
268 }
269
270 pub fn is_mesh_child(&self) -> bool {
272 self.0.is_mesh_child
273 }
274}
275
276impl AccessPointStationDisconnected<'_> {
277 pub fn mac(&self) -> &[u8] {
279 &self.0.mac
280 }
281
282 pub fn reason(&self) -> u16 {
284 self.0.reason
285 }
286
287 pub fn aid(&self) -> u8 {
289 self.0.aid
290 }
291
292 pub fn is_mesh_child(&self) -> bool {
294 self.0.is_mesh_child
295 }
296}
297
298impl ScanDone<'_> {
299 pub fn status(&self) -> u32 {
301 self.0.status
302 }
303
304 pub fn number(&self) -> u8 {
306 self.0.number
307 }
308
309 pub fn id(&self) -> u8 {
311 self.0.scan_id
312 }
313}
314
315impl StationConnected<'_> {
316 pub fn ssid(&self) -> &[u8] {
318 &self.0.ssid
319 }
320
321 pub fn ssid_len(&self) -> u8 {
323 self.0.ssid_len
324 }
325
326 pub fn bssid(&self) -> &[u8] {
328 &self.0.bssid
329 }
330
331 pub fn channel(&self) -> u8 {
333 self.0.channel
334 }
335
336 pub fn authmode(&self) -> u32 {
338 self.0.authmode
339 }
340
341 pub fn aid(&self) -> u16 {
343 self.0.aid
344 }
345}
346
347impl StationDisconnected<'_> {
348 pub fn ssid(&self) -> &[u8] {
350 &self.0.ssid
351 }
352
353 pub fn ssid_len(&self) -> u8 {
355 self.0.ssid_len
356 }
357
358 pub fn bssid(&self) -> &[u8] {
360 &self.0.bssid
361 }
362
363 pub fn reason(&self) -> u8 {
365 self.0.reason
366 }
367
368 pub fn rssi(&self) -> i8 {
370 self.0.rssi
371 }
372}
373
374impl AccessPointCredential<'_> {
375 pub fn ssid(&self) -> &[u8] {
377 &self.0.ssid
378 }
379
380 pub fn passphrase(&self) -> &[u8] {
382 &self.0.passphrase
383 }
384}
385
386impl StationAuthenticationModeChange<'_> {
387 pub fn old_mode(&self) -> u32 {
389 self.0.old_mode
390 }
391
392 pub fn new_mode(&self) -> u32 {
394 self.0.new_mode
395 }
396}
397
398impl StationWifiProtectedStatusEnrolleeSuccess<'_> {
399 pub fn access_point_cred_cnt(&self) -> u8 {
401 self.0.ap_cred_cnt
402 }
403
404 pub fn access_point_cred(&self) -> &[AccessPointCredential<'_>] {
406 let array_ref: &[AccessPointCredential<'_>; 3] =
407 unsafe { &*(&self.0.ap_cred as *const _ as *const [AccessPointCredential<'_>; 3]) };
409
410 &array_ref[..]
411 }
412}
413
414impl StationWifiProtectedStatusEnrolleePin<'_> {
415 pub fn pin(&self) -> &[u8] {
417 &self.0.pin_code
418 }
419}
420
421impl FineTimingMeasurementReport<'_> {
422 pub fn peer_mac(&self) -> &[u8] {
424 &self.0.peer_mac
425 }
426
427 pub fn status(&self) -> u32 {
429 self.0.status
430 }
431
432 pub fn rtt_raw(&self) -> u32 {
434 self.0.rtt_raw
435 }
436
437 pub fn rtt_est(&self) -> u32 {
439 self.0.rtt_est
440 }
441
442 pub fn dist_est(&self) -> u32 {
444 self.0.dist_est
445 }
446
447 pub fn report_num_entries(&self) -> u8 {
449 self.0.ftm_report_num_entries
450 }
451
452 pub fn entries(&self) -> impl Iterator<Item = FineTimingMeasurementReportInfo> {
459 self.load_entries().into_iter()
460 }
461
462 fn load_entries(&self) -> alloc::vec::Vec<FineTimingMeasurementReportInfo> {
463 let len = self.0.ftm_report_num_entries as usize;
464 if len == 0 {
465 return alloc::vec::Vec::new();
466 }
467
468 let mut buf = alloc::vec![
469 crate::sys::include::wifi_ftm_report_entry_t {
470 dlog_token: 0,
471 rssi: 0,
472 rtt: 0,
473 t1: 0,
474 t2: 0,
475 t3: 0,
476 t4: 0,
477 ppm: 0,
478 };
479 len
480 ];
481
482 let rc =
484 unsafe { crate::sys::include::esp_wifi_ftm_get_report(buf.as_mut_ptr(), len as u8) };
485 if rc != 0 {
486 warn!("esp_wifi_ftm_get_report failed: {}", rc);
487 return alloc::vec::Vec::new();
488 }
489
490 buf.into_iter()
491 .map(|entry| FineTimingMeasurementReportInfo {
492 dlog_token: entry.dlog_token,
493 rssi: entry.rssi,
494 rtt: entry.rtt,
495 t1: entry.t1,
496 t2: entry.t2,
497 t3: entry.t3,
498 t4: entry.t4,
499 ppm: entry.ppm,
500 })
501 .collect()
502 }
503}
504
505impl AccessPointProbeRequestReceived<'_> {
506 pub fn rssi(&self) -> i32 {
508 self.0.rssi
509 }
510
511 pub fn mac(&self) -> &[u8] {
513 &self.0.mac
514 }
515}
516
517impl StationBasicServiceSetReceivedSignalStrengthIndicatorLow<'_> {
518 pub fn rssi(&self) -> i32 {
520 self.0.rssi
521 }
522}
523
524impl ActionTransmissionStatus<'_> {
525 pub fn ifx(&self) -> u32 {
527 self.0.ifx
528 }
529
530 pub fn context(&self) -> u32 {
532 self.0.context
533 }
534
535 pub fn op_id(&self) -> u8 {
537 self.0.op_id
538 }
539
540 pub fn channel(&self) -> u8 {
542 self.0.channel
543 }
544
545 pub fn status(&self) -> u32 {
547 self.0.status
548 }
549}
550
551impl RemainOnChannelDone<'_> {
552 pub fn context(&self) -> u32 {
554 self.0.context
555 }
556
557 pub fn status(&self) -> u32 {
559 self.0.status
560 }
561
562 pub fn op_id(&self) -> u8 {
564 self.0.op_id
565 }
566
567 pub fn channel(&self) -> u8 {
569 self.0.channel
570 }
571}
572
573impl AccessPointWifiProtectedStatusRegistrarSuccess<'_> {
574 pub fn peer_mac(&self) -> &[u8] {
576 &self.0.peer_macaddr
577 }
578}
579
580impl AccessPointWifiProtectedStatusRegistrarFailed<'_> {
581 pub fn reason(&self) -> u32 {
583 self.0.reason
584 }
585
586 pub fn peer_macaddr(&self) -> &[u8; 6] {
588 &self.0.peer_macaddr
589 }
590}
591
592impl AccessPointWifiProtectedStatusRegistrarPin<'_> {
593 pub fn pin_code(&self) -> &[u8] {
595 &self.0.pin_code
596 }
597}
598
599impl NeighborAwarenessNetworkingServiceMatch<'_> {
600 pub fn subscribe_id(&self) -> u8 {
602 self.0.subscribe_id
603 }
604
605 pub fn publish_id(&self) -> u8 {
607 self.0.publish_id
608 }
609
610 pub fn pub_if_mac(&self) -> &[u8] {
612 &self.0.pub_if_mac
613 }
614
615 pub fn update_pub_id(&self) -> bool {
617 self.0.update_pub_id
618 }
619}
620
621impl NeighborAwarenessNetworkingReplied<'_> {
622 pub fn subscribe_id(&self) -> u8 {
624 self.0.subscribe_id
625 }
626
627 pub fn publish_id(&self) -> u8 {
629 self.0.publish_id
630 }
631
632 pub fn sub_if_mac(&self) -> &[u8] {
634 &self.0.sub_if_mac
635 }
636}
637
638impl NeighborAwarenessNetworkingReceive<'_> {
639 pub fn inst_id(&self) -> u8 {
641 self.0.inst_id
642 }
643
644 pub fn peer_inst_id(&self) -> u8 {
646 self.0.peer_inst_id
647 }
648
649 pub fn peer_if_mac(&self) -> &[u8; 6] {
651 &self.0.peer_if_mac
652 }
653
654 pub fn peer_svc_info(&self) -> &[u8] {
656 unsafe { self.0.ssi.as_slice(self.0.ssi_len as usize) }
657 }
658}
659
660impl NeighborDiscoveryProtocolIndication<'_> {
661 pub fn publish_id(&self) -> u8 {
663 self.0.publish_id
664 }
665
666 pub fn ndp_id(&self) -> u8 {
668 self.0.ndp_id
669 }
670
671 pub fn peer_nmi(&self) -> &[u8; 6] {
673 &self.0.peer_nmi
674 }
675
676 pub fn peer_ndi(&self) -> &[u8; 6] {
678 &self.0.peer_ndi
679 }
680
681 pub fn svc_info(&self) -> &[u8] {
683 unsafe { self.0.ssi.as_slice(self.0.ssi_len as usize) }
684 }
685}
686
687impl NeighborDiscoveryProtocolConfirmation<'_> {
688 pub fn status(&self) -> u8 {
690 self.0.status
691 }
692
693 pub fn id(&self) -> u8 {
695 self.0.ndp_id
696 }
697
698 pub fn peer_nmi(&self) -> &[u8; 6] {
700 &self.0.peer_nmi
701 }
702
703 pub fn peer_ndi(&self) -> &[u8; 6] {
705 &self.0.peer_ndi
706 }
707
708 pub fn own_ndi(&self) -> &[u8; 6] {
710 &self.0.own_ndi
711 }
712
713 pub fn svc_info(&self) -> &[u8] {
715 unsafe { self.0.ssi.as_slice(self.0.ssi_len as usize) }
716 }
717}
718
719impl NeighborDiscoveryProtocolTerminated<'_> {
720 pub fn reason(&self) -> u8 {
722 self.0.reason
723 }
724
725 pub fn id(&self) -> u8 {
727 self.0.ndp_id
728 }
729
730 pub fn init_ndi(&self) -> &[u8; 6] {
732 &self.0.init_ndi
733 }
734}
735
736impl HomeChannelChange<'_> {
737 pub fn old_chan(&self) -> u8 {
739 self.0.old_chan
740 }
741
742 pub fn old_snd(&self) -> u32 {
744 self.0.old_snd
745 }
746
747 pub fn new_chan(&self) -> u8 {
749 self.0.new_chan
750 }
751
752 pub fn new_snd(&self) -> u32 {
754 self.0.new_snd
755 }
756}
757
758impl StationNeighborRep<'_> {
759 pub fn report(&self) -> &[u8] {
761 unsafe { self.0.n_report.as_slice(self.0.report_len as usize) }
762 }
763
764 pub fn report_len(&self) -> u16 {
766 self.0.report_len
767 }
768}
769
770#[derive(Debug, Clone)]
772#[cfg_attr(feature = "defmt", derive(defmt::Format))]
773#[instability::unstable]
774pub struct FineTimingMeasurementReportInfo {
775 pub dlog_token: u8,
777 pub rssi: i8,
779 pub rtt: u32,
781 pub t1: u64,
783 pub t2: u64,
785 pub t3: u64,
787 pub t4: u64,
789 pub ppm: i16,
791}
792
793#[derive(Debug, Clone)]
795#[cfg_attr(feature = "defmt", derive(defmt::Format))]
796#[instability::unstable]
797pub struct CredentialsInfo {
798 pub ssid: Ssid,
800 pub passphrase: [u8; 64usize],
802}
803
804#[derive(Debug, Clone)]
806pub struct Collection<T>(alloc::vec::Vec<T>);
807
808impl<T> Collection<T> {
809 pub fn as_slice(&self) -> &[T] {
811 self.0.as_slice()
812 }
813}
814
815#[cfg(feature = "defmt")]
816impl<T: defmt::Format> defmt::Format for Collection<T> {
817 fn format(&self, fmt: defmt::Formatter<'_>) {
818 self.0.iter().for_each(|v| {
819 defmt::write!(fmt, "{}", v);
820 });
821 }
822}
823
824#[derive(Debug, Clone)]
826#[cfg_attr(feature = "defmt", derive(defmt::Format))]
827#[instability::unstable]
828pub enum EventInfo {
829 WifiReady,
831
832 ScanDone {
834 status: u32,
836 number: u8,
838 scan_id: u8,
840 },
841
842 StationStart,
844
845 StationStop,
847
848 StationConnected {
850 ssid: Ssid,
852 bssid: [u8; 6usize],
854 channel: u8,
856 authmode: u32,
858 aid: u16,
860 },
861
862 StationDisconnected {
864 ssid: Ssid,
866 bssid: [u8; 6usize],
868 reason: u16,
870 rssi: i8,
872 },
873
874 StationAuthenticationModeChange {
876 old_mode: u32,
878 new_mode: u32,
880 },
881
882 StationWifiProtectedStatusEnrolleeSuccess {
884 credentials: Collection<CredentialsInfo>,
886 },
887
888 StationWifiProtectedStatusEnrolleeFailed,
890
891 StationWifiProtectedStatusEnrolleeTimeout,
893
894 StationWifiProtectedStatusEnrolleePin {
896 pin_code: [u8; 8usize],
898 },
899
900 StationWifiProtectedStatusEnrolleePushButtonConfigurationOverlap,
902
903 AccessPointStart,
905
906 AccessPointStop,
908
909 AccessPointStationConnected {
911 mac: [u8; 6usize],
913 aid: u16,
915 is_mesh_child: bool,
917 },
918
919 AccessPointStationDisconnected {
921 mac: [u8; 6usize],
923 aid: u8,
925 is_mesh_child: bool,
927 reason: u16,
929 },
930
931 AccessPointProbeRequestReceived {
933 rssi: i8,
935 mac: [u8; 6usize],
937 },
938
939 FineTimingMeasurementReport {
941 peer_mac: [u8; 6usize],
943 status: u32,
945 rtt_raw: u32,
947 rtt_est: u32,
949 dist_est: u32,
951 entries: Collection<FineTimingMeasurementReportInfo>,
953 },
954
955 StationBasicServiceSetReceivedSignalStrengthIndicatorLow {
957 rssi: i8,
959 },
960
961 ActionTransmissionStatus {
963 ifx: u32,
965 context: u32,
967 status: u32,
969 op_id: u8,
971 channel: u8,
973 },
974
975 RemainOnChannelDone {
977 context: u32,
979 status: u32,
981 op_id: u8,
983 channel: u8,
985 },
986
987 StationBeaconTimeout,
989
990 ConnectionlessModuleWakeIntervalStart,
992
993 AccessPointWifiProtectedStatusRegistrarSuccess {
995 peer_macaddr: [u8; 6usize],
997 },
998
999 AccessPointWifiProtectedStatusRegistrarFailed {
1001 reason: u32,
1003 peer_macaddr: [u8; 6usize],
1005 },
1006
1007 AccessPointWifiProtectedStatusRegistrarTimeout,
1009
1010 AccessPointWifiProtectedStatusRegistrarPin {
1012 pin_code: [u8; 8usize],
1014 },
1015
1016 AccessPointWifiProtectedStatusRegistrarPushButtonConfigurationOverlap,
1018
1019 IndividualTargetWakeTimeSetup,
1021
1022 IndividualTargetWakeTimeTeardown,
1024
1025 IndividualTargetWakeTimeProbe,
1027
1028 IndividualTargetWakeTimeSuspend,
1030
1031 TargetWakeTimeWakeup,
1033
1034 BroadcastTargetWakeTimeSetup,
1036
1037 BroadcastTargetWakeTimeTeardown,
1039
1040 HomeChannelChange,
1043}
1044
1045impl EventInfo {
1046 pub(crate) fn from_wifi_event_raw(
1047 event: WifiEvent,
1048 payload: *mut crate::sys::c_types::c_void,
1049 ) -> Option<Self> {
1050 let enabled = WIFI_EVENT_ENABLE_MASK.with(|mask| mask.contains(event));
1051
1052 if !enabled {
1053 return None;
1054 }
1055
1056 match event {
1057 WifiEvent::WifiReady => Some(EventInfo::WifiReady),
1058 WifiEvent::ScanDone => {
1059 let ev = unsafe { ScanDone::from_raw_event_data(payload) };
1060
1061 Some(EventInfo::ScanDone {
1062 status: ev.status(),
1063 number: ev.number(),
1064 scan_id: ev.id(),
1065 })
1066 }
1067 WifiEvent::StationStart => Some(EventInfo::StationStart),
1068 WifiEvent::StationStop => Some(EventInfo::StationStop),
1069 WifiEvent::StationConnected => {
1070 let ev = unsafe { StationConnected::from_raw_event_data(payload) };
1071
1072 let Ok(ssid) = Ssid::from_raw(ev.ssid(), ev.ssid_len()) else {
1073 warn!("Dropping StationConnected event: invalid SSID length");
1074 return None;
1075 };
1076
1077 Some(EventInfo::StationConnected {
1078 ssid,
1079 bssid: ev.bssid().try_into().unwrap(),
1080 channel: ev.channel(),
1081 authmode: ev.authmode(),
1082 aid: ev.aid(),
1083 })
1084 }
1085 WifiEvent::StationDisconnected => {
1086 let ev = unsafe { StationDisconnected::from_raw_event_data(payload) };
1087
1088 let Ok(ssid) = Ssid::from_raw(ev.ssid(), ev.ssid_len()) else {
1089 warn!("Dropping StationDisconnected event: invalid SSID length");
1090 return None;
1091 };
1092
1093 Some(EventInfo::StationDisconnected {
1094 ssid,
1095 bssid: ev.bssid().try_into().unwrap(),
1096 reason: ev.reason() as u16,
1097 rssi: ev.rssi(),
1098 })
1099 }
1100 WifiEvent::AccessPointStart => Some(EventInfo::AccessPointStart),
1101 WifiEvent::AccessPointStop => Some(EventInfo::AccessPointStop),
1102 WifiEvent::AccessPointStationConnected => {
1103 let ev = unsafe { AccessPointStationConnected::from_raw_event_data(payload) };
1104 Some(EventInfo::AccessPointStationConnected {
1105 mac: ev.mac().try_into().unwrap(),
1106 aid: ev.aid() as u16,
1107 is_mesh_child: ev.is_mesh_child(),
1108 })
1109 }
1110 WifiEvent::AccessPointStationDisconnected => {
1111 let ev = unsafe { AccessPointStationDisconnected::from_raw_event_data(payload) };
1112 Some(EventInfo::AccessPointStationDisconnected {
1113 mac: ev.mac().try_into().unwrap(),
1114 aid: ev.aid(),
1115 is_mesh_child: ev.is_mesh_child(),
1116 reason: ev.reason(),
1117 })
1118 }
1119 WifiEvent::StationAuthenticationModeChange => {
1120 let ev = unsafe { StationAuthenticationModeChange::from_raw_event_data(payload) };
1121 Some(EventInfo::StationAuthenticationModeChange {
1122 old_mode: ev.old_mode(),
1123 new_mode: ev.new_mode(),
1124 })
1125 }
1126 WifiEvent::StationWifiProtectedStatusEnrolleeSuccess => {
1127 let ev = unsafe {
1128 StationWifiProtectedStatusEnrolleeSuccess::from_raw_event_data(payload)
1129 };
1130 Some(EventInfo::StationWifiProtectedStatusEnrolleeSuccess {
1131 credentials: Collection(
1132 ev.access_point_cred()[..ev.access_point_cred_cnt() as usize]
1133 .iter()
1134 .filter_map(|cred| {
1135 let Ok(ssid) = Ssid::try_from(cred.ssid()) else {
1136 warn!("Dropping WPS credential: invalid SSID length");
1137 return None;
1138 };
1139 let Ok(passphrase) = <[u8; 64]>::try_from(cred.passphrase()) else {
1140 warn!("Dropping WPS credential: invalid passphrase length");
1141 return None;
1142 };
1143 Some(CredentialsInfo { ssid, passphrase })
1144 })
1145 .collect(),
1146 ),
1147 })
1148 }
1149 WifiEvent::StationWifiProtectedStatusEnrolleeFailed => {
1150 Some(EventInfo::StationWifiProtectedStatusEnrolleeFailed)
1151 }
1152 WifiEvent::StationWifiProtectedStatusEnrolleeTimeout => {
1153 Some(EventInfo::StationWifiProtectedStatusEnrolleeTimeout)
1154 }
1155 WifiEvent::StationWifiProtectedStatusEnrolleePin => {
1156 let ev =
1157 unsafe { StationWifiProtectedStatusEnrolleePin::from_raw_event_data(payload) };
1158 Some(EventInfo::StationWifiProtectedStatusEnrolleePin {
1159 pin_code: ev.pin().try_into().unwrap_or_default(),
1160 })
1161 }
1162 WifiEvent::StationWifiProtectedStatusEnrolleePushButtonConfigurationOverlap => {
1163 Some(EventInfo::StationWifiProtectedStatusEnrolleePushButtonConfigurationOverlap)
1164 }
1165 WifiEvent::AccessPointProbeRequestReceived => {
1166 let ev = unsafe { AccessPointProbeRequestReceived::from_raw_event_data(payload) };
1167 Some(EventInfo::AccessPointProbeRequestReceived {
1168 rssi: ev.rssi() as i8,
1169 mac: ev.mac().try_into().unwrap_or_default(),
1170 })
1171 }
1172 WifiEvent::FineTimingMeasurementReport => {
1173 let ev = unsafe { FineTimingMeasurementReport::from_raw_event_data(payload) };
1174 Some(EventInfo::FineTimingMeasurementReport {
1175 peer_mac: ev.peer_mac().try_into().unwrap_or_default(),
1176 status: ev.status(),
1177 rtt_raw: ev.rtt_raw(),
1178 rtt_est: ev.rtt_est(),
1179 dist_est: ev.dist_est(),
1180 entries: Collection(ev.entries().collect()),
1181 })
1182 }
1183 WifiEvent::StationBasicServiceSetReceivedSignalStrengthIndicatorLow => {
1184 let ev = unsafe {
1185 StationBasicServiceSetReceivedSignalStrengthIndicatorLow::from_raw_event_data(
1186 payload,
1187 )
1188 };
1189 Some(
1190 EventInfo::StationBasicServiceSetReceivedSignalStrengthIndicatorLow {
1191 rssi: ev.rssi() as i8,
1192 },
1193 )
1194 }
1195 WifiEvent::ActionTransmissionStatus => {
1196 let ev = unsafe { ActionTransmissionStatus::from_raw_event_data(payload) };
1197 Some(EventInfo::ActionTransmissionStatus {
1198 ifx: ev.ifx(),
1199 context: ev.context(),
1200 status: ev.status(),
1201 op_id: ev.op_id(),
1202 channel: ev.channel(),
1203 })
1204 }
1205 WifiEvent::RemainOnChannelDone => {
1206 let ev = unsafe { RemainOnChannelDone::from_raw_event_data(payload) };
1207 Some(EventInfo::RemainOnChannelDone {
1208 context: ev.context(),
1209 status: ev.status(),
1210 op_id: ev.op_id(),
1211 channel: ev.channel(),
1212 })
1213 }
1214 WifiEvent::StationBeaconTimeout => Some(EventInfo::StationBeaconTimeout),
1215 WifiEvent::ConnectionlessModuleWakeIntervalStart => {
1216 Some(EventInfo::ConnectionlessModuleWakeIntervalStart)
1217 }
1218 WifiEvent::AccessPointWifiProtectedStatusRegistrarSuccess => {
1219 let ev = unsafe {
1220 AccessPointWifiProtectedStatusRegistrarSuccess::from_raw_event_data(payload)
1221 };
1222 Some(EventInfo::AccessPointWifiProtectedStatusRegistrarSuccess {
1223 peer_macaddr: ev.peer_mac().try_into().unwrap_or_default(),
1224 })
1225 }
1226 WifiEvent::AccessPointWifiProtectedStatusRegistrarFailed => {
1227 let ev = unsafe {
1228 AccessPointWifiProtectedStatusRegistrarFailed::from_raw_event_data(payload)
1229 };
1230 Some(EventInfo::AccessPointWifiProtectedStatusRegistrarFailed {
1231 reason: ev.reason(),
1232 peer_macaddr: *ev.peer_macaddr(),
1233 })
1234 }
1235 WifiEvent::AccessPointWifiProtectedStatusRegistrarTimeout => {
1236 Some(EventInfo::AccessPointWifiProtectedStatusRegistrarTimeout)
1237 }
1238 WifiEvent::AccessPointWifiProtectedStatusRegistrarPin => {
1239 let ev = unsafe {
1240 AccessPointWifiProtectedStatusRegistrarPin::from_raw_event_data(payload)
1241 };
1242 Some(EventInfo::AccessPointWifiProtectedStatusRegistrarPin {
1243 pin_code: ev.pin_code().try_into().unwrap_or_default(),
1244 })
1245 }
1246 WifiEvent::AccessPointWifiProtectedStatusRegistrarPushButtonConfigurationOverlap => {
1247 Some(EventInfo::AccessPointWifiProtectedStatusRegistrarPushButtonConfigurationOverlap)
1248 }
1249 WifiEvent::IndividualTargetWakeTimeSetup => {
1250 Some(EventInfo::IndividualTargetWakeTimeSetup)
1251 }
1252 WifiEvent::IndividualTargetWakeTimeTeardown => {
1253 Some(EventInfo::IndividualTargetWakeTimeTeardown)
1254 }
1255 WifiEvent::IndividualTargetWakeTimeProbe => {
1256 Some(EventInfo::IndividualTargetWakeTimeProbe)
1257 }
1258 WifiEvent::IndividualTargetWakeTimeSuspend => {
1259 Some(EventInfo::IndividualTargetWakeTimeSuspend)
1260 }
1261 WifiEvent::TargetWakeTimeWakeup => {
1262 Some(EventInfo::TargetWakeTimeWakeup)
1263 }
1264 WifiEvent::BroadcastTargetWakeTimeSetup => {
1265 Some(EventInfo::BroadcastTargetWakeTimeSetup)
1266 }
1267 WifiEvent::BroadcastTargetWakeTimeTeardown => {
1268 Some(EventInfo::BroadcastTargetWakeTimeTeardown)
1269 }
1270 WifiEvent::HomeChannelChange => {
1271 Some(EventInfo::HomeChannelChange)
1272 }
1273 _ => None,
1274 }
1275 }
1276}
1277
1278#[instability::unstable]
1280pub fn enable_wifi_events(events: EnumSet<WifiEvent>) {
1281 WIFI_EVENT_ENABLE_MASK.with(|mask| *mask |= events);
1282}
1283
1284#[instability::unstable]
1303pub fn disable_wifi_events(events: EnumSet<WifiEvent>) {
1304 WIFI_EVENT_ENABLE_MASK.with(|mask| *mask &= !events);
1305}
1306
1307#[derive(Debug, Clone)]
1309#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1310#[instability::unstable]
1311pub enum MessageResult {
1312 Lagged(u64),
1315 Message(EventInfo),
1317}
1318
1319#[instability::unstable]
1321pub struct EventSubscriber<'a> {
1322 inner: embassy_sync::pubsub::Subscriber<
1323 'a,
1324 esp_sync::RawMutex,
1325 EventInfo,
1326 { esp_config_int!(usize, "ESP_RADIO_CONFIG_EVENT_CHANNEL_CAPACITY") },
1327 { esp_config_int!(usize, "ESP_RADIO_CONFIG_EVENT_CHANNEL_SUBSCRIBERS") },
1328 1,
1329 >,
1330}
1331
1332impl<'a> EventSubscriber<'a> {
1333 pub(crate) fn new(
1334 subscriber: embassy_sync::pubsub::Subscriber<
1335 'a,
1336 esp_sync::RawMutex,
1337 EventInfo,
1338 { esp_config_int!(usize, "ESP_RADIO_CONFIG_EVENT_CHANNEL_CAPACITY") },
1339 { esp_config_int!(usize, "ESP_RADIO_CONFIG_EVENT_CHANNEL_SUBSCRIBERS") },
1340 1,
1341 >,
1342 ) -> Self {
1343 Self { inner: subscriber }
1344 }
1345
1346 #[instability::unstable]
1348 pub async fn next_event(&mut self) -> MessageResult {
1349 match self.inner.next_message().await {
1350 embassy_sync::pubsub::WaitResult::Lagged(missed) => MessageResult::Lagged(missed),
1351 embassy_sync::pubsub::WaitResult::Message(msg) => MessageResult::Message(msg),
1352 }
1353 }
1354
1355 #[instability::unstable]
1357 pub async fn next_event_pure(&mut self) -> EventInfo {
1358 self.inner.next_message_pure().await
1359 }
1360}