Skip to main content

esp_radio/wifi/
event.rs

1//! Wi-Fi Events
2//!
3//! This is considered unstable functionality.
4//! Use with caution.
5
6use 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/// Events generated by the Wi-Fi driver.
25#[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    /// Wi-Fi is ready for operation.
32    WifiReady = 0,
33    /// Scan operation has completed.
34    ScanDone,
35    /// Station mode started.
36    StationStart,
37    /// Station mode stopped.
38    StationStop,
39    /// Station connected to a network.
40    StationConnected,
41    /// Station disconnected from a network.
42    StationDisconnected,
43    /// Station authentication mode changed.
44    StationAuthenticationModeChange,
45
46    /// Station Wi-Fi-Protected-Status succeeds in enrollee mode.
47    StationWifiProtectedStatusEnrolleeSuccess,
48    /// Station Wi-Fi-Protected-Status fails in enrollee mode.
49    StationWifiProtectedStatusEnrolleeFailed,
50    /// Station Wi-Fi-Protected-Status timeout in enrollee mode.
51    StationWifiProtectedStatusEnrolleeTimeout,
52    /// Station Wi-Fi-Protected-Status pin code in enrollee mode.
53    StationWifiProtectedStatusEnrolleePin,
54    /// Station Wi-Fi-Protected-Status overlap in enrollee mode.
55    StationWifiProtectedStatusEnrolleePushButtonConfigurationOverlap,
56
57    /// Soft-AccessPoint start.
58    AccessPointStart,
59    /// Soft-AccessPoint stop.
60    AccessPointStop,
61    /// A station connected to Soft-AccessPoint.
62    AccessPointStationConnected,
63    /// A station disconnected from Soft-AccessPoint.
64    AccessPointStationDisconnected,
65    /// Received probe request packet in Soft-AccessPoint interface.
66    AccessPointProbeRequestReceived,
67
68    /// Received report of Fine-Timing-Measurement procedure.
69    FineTimingMeasurementReport,
70
71    /// Station Receive-Signal-Strenght-Indicator goes below the configured threshold.
72    StationBasicServiceSetReceivedSignalStrengthIndicatorLow,
73    /// Status indication of Action Transmission operation.
74    ActionTransmissionStatus,
75    /// Remain-on-Channel operation complete.
76    RemainOnChannelDone,
77
78    /// Station beacon timeout.
79    StationBeaconTimeout,
80
81    /// Connectionless module wake interval has started.
82    ConnectionlessModuleWakeIntervalStart,
83
84    /// Soft-AccessPoint Wi-Fi-Protected-Status succeeded in registrar mode.
85    AccessPointWifiProtectedStatusRegistrarSuccess,
86    /// Soft-AccessPoint Wi-Fi-Protected-Status failed in registrar mode.
87    AccessPointWifiProtectedStatusRegistrarFailed,
88    /// Soft-AccessPoint Wi-Fi-Protected-Status timed out in registrar mode.
89    AccessPointWifiProtectedStatusRegistrarTimeout,
90    /// Soft-AccessPoint Wi-Fi-Protected-Status pin code in registrar mode.
91    AccessPointWifiProtectedStatusRegistrarPin,
92    /// Soft-AccessPoint Wi-Fi-Protected-Status overlap in registrar mode.
93    AccessPointWifiProtectedStatusRegistrarPushButtonConfigurationOverlap,
94
95    /// Individual Target-Wake-Time setup.
96    IndividualTargetWakeTimeSetup,
97    /// Individual Target-Wake-Time teardown.
98    IndividualTargetWakeTimeTeardown,
99    /// Individual Target-Wake-Time probe.
100    IndividualTargetWakeTimeProbe,
101    /// Individual Target-Wake-Time suspended.
102    IndividualTargetWakeTimeSuspend,
103    /// Target-Wake-Wakeup event.
104    TargetWakeTimeWakeup,
105    /// Broadcast-Target-Wake-Time setup.
106    BroadcastTargetWakeTimeSetup,
107    /// Broadcast-Target-Wake-Time teardown.
108    BroadcastTargetWakeTimeTeardown,
109
110    /// Neighbor-Awareness-Networking discovery has started.
111    NeighborAwarenessNetworkingStarted,
112    /// Neighbor-Awareness-Networking discovery has stopped.
113    NeighborAwarenessNetworkingStopped,
114    /// Neighbor-Awareness-Networking service discovery match found.
115    NeighborAwarenessNetworkingServiceMatch,
116    /// Replied to a Neighbor-Awareness-Networking peer with service discovery match.
117    NeighborAwarenessNetworkingReplied,
118    /// Received a follow-up message in Neighbor-Awareness-Networking.
119    NeighborAwarenessNetworkingReceive,
120    /// Received NDP (Neighbor Discovery Protocol) request from a Neighbor-Awareness-Networking
121    /// peer.
122    NeighborDiscoveryProtocolIndication,
123    /// NDP confirm indication.
124    NeighborDiscoveryProtocolConfirmation,
125    /// Neighbor-Awareness-Networking datapath terminated indication.
126    NeighborDiscoveryProtocolTerminated,
127    /// Wi-Fi home channel change, doesn't occur when scanning.
128    HomeChannelChange,
129
130    /// Received Neighbor Report response.
131    StationNeighborRep,
132}
133
134trait Event {
135    /// # Safety
136    /// `ptr` must be a valid for casting to this event's inner event data.
137    unsafe fn from_raw_event_data(ptr: *mut crate::sys::c_types::c_void) -> Self;
138}
139
140macro_rules! impl_wifi_event {
141    // no data
142    ($newtype:ident) => {
143        /// See [`WifiEvent`].
144        #[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        /// See [`WifiEvent`].
158        #[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    /// Get the MAC address of the connected station.
261    pub fn mac(&self) -> &[u8] {
262        &self.0.mac
263    }
264
265    /// Get the AID (Association Identifier) of the connected station.
266    pub fn aid(&self) -> u8 {
267        self.0.aid
268    }
269
270    /// Flag indicating whether the connected station is a mesh child.
271    pub fn is_mesh_child(&self) -> bool {
272        self.0.is_mesh_child
273    }
274}
275
276impl AccessPointStationDisconnected<'_> {
277    /// Get the MAC address of the disconnected station.
278    pub fn mac(&self) -> &[u8] {
279        &self.0.mac
280    }
281
282    /// Get the reason for the disconnection.
283    pub fn reason(&self) -> u16 {
284        self.0.reason
285    }
286
287    /// AID that the Soft-AccessPoint assigned to the disconnected station.
288    pub fn aid(&self) -> u8 {
289        self.0.aid
290    }
291
292    /// Flag indicating whether the connected station is a mesh child.
293    pub fn is_mesh_child(&self) -> bool {
294        self.0.is_mesh_child
295    }
296}
297
298impl ScanDone<'_> {
299    /// Get the status of the scan operation.
300    pub fn status(&self) -> u32 {
301        self.0.status
302    }
303
304    /// Get the number of found APs.
305    pub fn number(&self) -> u8 {
306        self.0.number
307    }
308
309    /// Get the scan ID associated with this scan operation.
310    pub fn id(&self) -> u8 {
311        self.0.scan_id
312    }
313}
314
315impl StationConnected<'_> {
316    /// Get the SSID of the connected station.
317    pub fn ssid(&self) -> &[u8] {
318        &self.0.ssid
319    }
320
321    /// Get the length of the SSID.
322    pub fn ssid_len(&self) -> u8 {
323        self.0.ssid_len
324    }
325
326    /// Get the BSSID (MAC address) of the connected station.
327    pub fn bssid(&self) -> &[u8] {
328        &self.0.bssid
329    }
330
331    /// Get the channel on which the station is connected.
332    pub fn channel(&self) -> u8 {
333        self.0.channel
334    }
335
336    /// Get the authentication mode used for the connection.
337    pub fn authmode(&self) -> u32 {
338        self.0.authmode
339    }
340
341    /// Get the AID (Association Identifier) of the connected station.
342    pub fn aid(&self) -> u16 {
343        self.0.aid
344    }
345}
346
347impl StationDisconnected<'_> {
348    /// Get the SSID of the disconnected station.
349    pub fn ssid(&self) -> &[u8] {
350        &self.0.ssid
351    }
352
353    /// Get the length of the SSID.
354    pub fn ssid_len(&self) -> u8 {
355        self.0.ssid_len
356    }
357
358    /// Get the BSSID (MAC address) of the disconnected station.
359    pub fn bssid(&self) -> &[u8] {
360        &self.0.bssid
361    }
362
363    /// Get the reason for the disconnection.
364    pub fn reason(&self) -> u8 {
365        self.0.reason
366    }
367
368    /// Get the authentication mode used for the disconnection.
369    pub fn rssi(&self) -> i8 {
370        self.0.rssi
371    }
372}
373
374impl AccessPointCredential<'_> {
375    /// Get the SSID of an access point.
376    pub fn ssid(&self) -> &[u8] {
377        &self.0.ssid
378    }
379
380    /// Get passphrase for the access point.
381    pub fn passphrase(&self) -> &[u8] {
382        &self.0.passphrase
383    }
384}
385
386impl StationAuthenticationModeChange<'_> {
387    /// Get the old authentication mode.
388    pub fn old_mode(&self) -> u32 {
389        self.0.old_mode
390    }
391
392    /// Get the new authentication mode.
393    pub fn new_mode(&self) -> u32 {
394        self.0.new_mode
395    }
396}
397
398impl StationWifiProtectedStatusEnrolleeSuccess<'_> {
399    /// Get number of access point credentials received.
400    pub fn access_point_cred_cnt(&self) -> u8 {
401        self.0.ap_cred_cnt
402    }
403
404    /// Get all access point credentials received.
405    pub fn access_point_cred(&self) -> &[AccessPointCredential<'_>] {
406        let array_ref: &[AccessPointCredential<'_>; 3] =
407            // cast reference of fixed-size array to wrapper type
408            unsafe { &*(&self.0.ap_cred as *const _ as *const [AccessPointCredential<'_>; 3]) };
409
410        &array_ref[..]
411    }
412}
413
414impl StationWifiProtectedStatusEnrolleePin<'_> {
415    /// Get the PIN code received from the WPS.
416    pub fn pin(&self) -> &[u8] {
417        &self.0.pin_code
418    }
419}
420
421impl FineTimingMeasurementReport<'_> {
422    /// Get the MAC address of the FTM peer.
423    pub fn peer_mac(&self) -> &[u8] {
424        &self.0.peer_mac
425    }
426
427    /// Get the status of the FTM operation.
428    pub fn status(&self) -> u32 {
429        self.0.status
430    }
431
432    /// Get the raw round-trip time (RTT) in nanoseconds.
433    pub fn rtt_raw(&self) -> u32 {
434        self.0.rtt_raw
435    }
436
437    /// Get the estimated round-trip time (RTT) in nanoseconds.
438    pub fn rtt_est(&self) -> u32 {
439        self.0.rtt_est
440    }
441
442    /// Get the distance estimate in centimeters.
443    pub fn dist_est(&self) -> u32 {
444        self.0.dist_est
445    }
446
447    /// Get the number of entries in the FTM report data.
448    pub fn report_num_entries(&self) -> u8 {
449        self.0.ftm_report_num_entries
450    }
451
452    /// Returns an iterator over the detailed FTM report entries.
453    ///
454    /// Entries are copied via `esp_wifi_ftm_get_report`, which frees the
455    /// driver's report. The first fetch (including [`EventInfo`] construction)
456    /// consumes it; later calls return an empty iterator. The iterator is also
457    /// empty if there are no entries or if the driver fails to copy them.
458    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        // Frees the driver's report; a later call cannot retrieve the same entries.
483        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    /// Get received probe request SSID.
507    pub fn rssi(&self) -> i32 {
508        self.0.rssi
509    }
510
511    /// Get the MAC address of the station which send probe request.
512    pub fn mac(&self) -> &[u8] {
513        &self.0.mac
514    }
515}
516
517impl StationBasicServiceSetReceivedSignalStrengthIndicatorLow<'_> {
518    /// Get received probe request SSID of bss.
519    pub fn rssi(&self) -> i32 {
520        self.0.rssi
521    }
522}
523
524impl ActionTransmissionStatus<'_> {
525    /// Get Wi-Fi interface to send request to.
526    pub fn ifx(&self) -> u32 {
527        self.0.ifx
528    }
529
530    /// Get context to identify the request.
531    pub fn context(&self) -> u32 {
532        self.0.context
533    }
534
535    /// ID of the corresponding operation that was provided during action tx request.
536    pub fn op_id(&self) -> u8 {
537        self.0.op_id
538    }
539
540    /// Channel provided in tx request.
541    pub fn channel(&self) -> u8 {
542        self.0.channel
543    }
544
545    /// Get the status of the operation.
546    pub fn status(&self) -> u32 {
547        self.0.status
548    }
549}
550
551impl RemainOnChannelDone<'_> {
552    /// Get context to identify the request.
553    pub fn context(&self) -> u32 {
554        self.0.context
555    }
556
557    /// Get the status of the operation.
558    pub fn status(&self) -> u32 {
559        self.0.status
560    }
561
562    /// ID of the corresponding operation.
563    pub fn op_id(&self) -> u8 {
564        self.0.op_id
565    }
566
567    /// Channel provided.
568    pub fn channel(&self) -> u8 {
569        self.0.channel
570    }
571}
572
573impl AccessPointWifiProtectedStatusRegistrarSuccess<'_> {
574    /// Get enrollee mac address.
575    pub fn peer_mac(&self) -> &[u8] {
576        &self.0.peer_macaddr
577    }
578}
579
580impl AccessPointWifiProtectedStatusRegistrarFailed<'_> {
581    /// Get WPS failure reason.
582    pub fn reason(&self) -> u32 {
583        self.0.reason
584    }
585
586    /// Get enrollee mac address.
587    pub fn peer_macaddr(&self) -> &[u8; 6] {
588        &self.0.peer_macaddr
589    }
590}
591
592impl AccessPointWifiProtectedStatusRegistrarPin<'_> {
593    /// Get the PIN code of station in enrollee mode.
594    pub fn pin_code(&self) -> &[u8] {
595        &self.0.pin_code
596    }
597}
598
599impl NeighborAwarenessNetworkingServiceMatch<'_> {
600    /// Get the Subscribe Service ID.
601    pub fn subscribe_id(&self) -> u8 {
602        self.0.subscribe_id
603    }
604
605    /// Get the Publish Service ID.
606    pub fn publish_id(&self) -> u8 {
607        self.0.publish_id
608    }
609
610    /// Get the NAN Interface MAC of the Publisher.
611    pub fn pub_if_mac(&self) -> &[u8] {
612        &self.0.pub_if_mac
613    }
614
615    /// Indicates whether publisher’s service ID needs to be updated.
616    pub fn update_pub_id(&self) -> bool {
617        self.0.update_pub_id
618    }
619}
620
621impl NeighborAwarenessNetworkingReplied<'_> {
622    /// Get the Subscribe Service ID.
623    pub fn subscribe_id(&self) -> u8 {
624        self.0.subscribe_id
625    }
626
627    /// Get the Publish Service ID.
628    pub fn publish_id(&self) -> u8 {
629        self.0.publish_id
630    }
631
632    /// Get the NAN Interface MAC of the Subscriber.
633    pub fn sub_if_mac(&self) -> &[u8] {
634        &self.0.sub_if_mac
635    }
636}
637
638impl NeighborAwarenessNetworkingReceive<'_> {
639    /// Get Our Service Identifier.
640    pub fn inst_id(&self) -> u8 {
641        self.0.inst_id
642    }
643
644    /// Get Peer's Service Identifier.
645    pub fn peer_inst_id(&self) -> u8 {
646        self.0.peer_inst_id
647    }
648
649    /// Get Peer’s NAN Interface MAC
650    pub fn peer_if_mac(&self) -> &[u8; 6] {
651        &self.0.peer_if_mac
652    }
653
654    /// Get Peer Service Info.
655    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    /// Get Publish ID for NAN Service.
662    pub fn publish_id(&self) -> u8 {
663        self.0.publish_id
664    }
665
666    /// Get NDF instance ID.
667    pub fn ndp_id(&self) -> u8 {
668        self.0.ndp_id
669    }
670
671    /// Get Peer’s NAN Interface MAC.
672    pub fn peer_nmi(&self) -> &[u8; 6] {
673        &self.0.peer_nmi
674    }
675
676    /// Get Peer’s NAN Data Interface MAC.
677    pub fn peer_ndi(&self) -> &[u8; 6] {
678        &self.0.peer_ndi
679    }
680
681    /// Get Service Specific Info.
682    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    /// Get NDP status code.
689    pub fn status(&self) -> u8 {
690        self.0.status
691    }
692
693    /// Get NDP instance ID.
694    pub fn id(&self) -> u8 {
695        self.0.ndp_id
696    }
697
698    /// Get Peer’s NAN Management Interface MAC.
699    pub fn peer_nmi(&self) -> &[u8; 6] {
700        &self.0.peer_nmi
701    }
702
703    /// Get Peer’s NAN Data Interface MAC.
704    pub fn peer_ndi(&self) -> &[u8; 6] {
705        &self.0.peer_ndi
706    }
707
708    /// Get Own NAN Data Interface MAC.
709    pub fn own_ndi(&self) -> &[u8; 6] {
710        &self.0.own_ndi
711    }
712
713    /// Get Service Specific Info.
714    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    /// Get termination reason code.
721    pub fn reason(&self) -> u8 {
722        self.0.reason
723    }
724
725    /// Get NDP instance ID.
726    pub fn id(&self) -> u8 {
727        self.0.ndp_id
728    }
729
730    /// Get Initiator’s NAN Data Interface MAC
731    pub fn init_ndi(&self) -> &[u8; 6] {
732        &self.0.init_ndi
733    }
734}
735
736impl HomeChannelChange<'_> {
737    /// Get the old home channel of the device.
738    pub fn old_chan(&self) -> u8 {
739        self.0.old_chan
740    }
741
742    /// Get the old second channel of the device.
743    pub fn old_snd(&self) -> u32 {
744        self.0.old_snd
745    }
746
747    /// Get the new home channel of the device.
748    pub fn new_chan(&self) -> u8 {
749        self.0.new_chan
750    }
751
752    /// Get the new second channel of the device.
753    pub fn new_snd(&self) -> u32 {
754        self.0.new_snd
755    }
756}
757
758impl StationNeighborRep<'_> {
759    /// Get the Neighbor Report received from the access point.
760    pub fn report(&self) -> &[u8] {
761        unsafe { self.0.n_report.as_slice(self.0.report_len as usize) }
762    }
763
764    /// Get the length of report.
765    pub fn report_len(&self) -> u16 {
766        self.0.report_len
767    }
768}
769
770/// Detailed FTM report entry.
771#[derive(Debug, Clone)]
772#[cfg_attr(feature = "defmt", derive(defmt::Format))]
773#[instability::unstable]
774pub struct FineTimingMeasurementReportInfo {
775    /// Dialog Token of the FTM frame
776    pub dlog_token: u8,
777    /// RSSI of the FTM frame received
778    pub rssi: i8,
779    /// Round Trip Time in pSec with a peer
780    pub rtt: u32,
781    /// Time of departure of FTM frame from FTM Responder in pSec
782    pub t1: u64,
783    /// Time of arrival of FTM frame at FTM Initiator in pSec
784    pub t2: u64,
785    /// Time of departure of ACK from FTM Initiator in pSec
786    pub t3: u64,
787    /// Time of arrival of ACK at FTM Responder in pSec
788    pub t4: u64,
789    /// Clock frequency offset in parts per million between local and peer device
790    pub ppm: i16,
791}
792
793/// Credential info record.
794#[derive(Debug, Clone)]
795#[cfg_attr(feature = "defmt", derive(defmt::Format))]
796#[instability::unstable]
797pub struct CredentialsInfo {
798    /// SSID of AP
799    pub ssid: Ssid,
800    /// Passphrase for the AP
801    pub passphrase: [u8; 64usize],
802}
803
804/// A collection of elements.
805#[derive(Debug, Clone)]
806pub struct Collection<T>(alloc::vec::Vec<T>);
807
808impl<T> Collection<T> {
809    /// The elements of this collection.
810    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/// Event including the payload.
825#[derive(Debug, Clone)]
826#[cfg_attr(feature = "defmt", derive(defmt::Format))]
827#[instability::unstable]
828pub enum EventInfo {
829    /// Wi-Fi is ready for operation.
830    WifiReady,
831
832    /// Scan operation has completed.
833    ScanDone {
834        /// Status of scanning APs: 0 — success, 1 - failure
835        status: u32,
836        /// Number of scan results
837        number: u8,
838        /// Scan sequence number, used for block scan
839        scan_id: u8,
840    },
841
842    /// Station mode started.
843    StationStart,
844
845    /// Station mode stopped.
846    StationStop,
847
848    /// Station connected to a network.
849    StationConnected {
850        /// SSID of connected AP
851        ssid: Ssid,
852        /// BSSID of connected AP
853        bssid: [u8; 6usize],
854        /// Channel of connected AP
855        channel: u8,
856        /// Authentication mode used by the connection
857        authmode: u32,
858        /// Authentication id assigned by the connected AP
859        aid: u16,
860    },
861
862    /// Station disconnected from a network.
863    StationDisconnected {
864        /// SSID of disconnected AP
865        ssid: Ssid,
866        /// BSSID of disconnected AP
867        bssid: [u8; 6usize],
868        /// Disconnection reason
869        reason: u16,
870        /// Disconnection RSSI
871        rssi: i8,
872    },
873
874    /// Station authentication mode changed.
875    StationAuthenticationModeChange {
876        /// Old auth mode of AP
877        old_mode: u32,
878        /// New auth mode of AP
879        new_mode: u32,
880    },
881
882    /// Station Wi-Fi-Protected-Status succeeds in enrollee mode.
883    StationWifiProtectedStatusEnrolleeSuccess {
884        /// Credentials
885        credentials: Collection<CredentialsInfo>,
886    },
887
888    /// Station Wi-Fi-Protected-Status fails in enrollee mode.
889    StationWifiProtectedStatusEnrolleeFailed,
890
891    /// Station Wi-Fi-Protected-Status timeout in enrollee mode.
892    StationWifiProtectedStatusEnrolleeTimeout,
893
894    /// Station Wi-Fi-Protected-Status pin code in enrollee mode.
895    StationWifiProtectedStatusEnrolleePin {
896        /// PIN code of station in enrollee mode
897        pin_code: [u8; 8usize],
898    },
899
900    /// Station Wi-Fi-Protected-Status overlap in enrollee mode.
901    StationWifiProtectedStatusEnrolleePushButtonConfigurationOverlap,
902
903    /// Soft-AccessPoint start.
904    AccessPointStart,
905
906    /// Soft-AccessPoint stop.
907    AccessPointStop,
908
909    /// A station connected to Soft-AccessPoint.
910    AccessPointStationConnected {
911        /// MAC address of the station connected to Soft-AP
912        mac: [u8; 6usize],
913        /// AID assigned by the Soft-AP to the connected station
914        aid: u16,
915        /// Flag indicating whether the connected station is a mesh child
916        is_mesh_child: bool,
917    },
918
919    /// A station disconnected from Soft-AccessPoint.
920    AccessPointStationDisconnected {
921        /// MAC address of the station disconnects from the soft-AP
922        mac: [u8; 6usize],
923        /// AID that the Soft-AP assigned to the disconnected station
924        aid: u8,
925        /// Flag indicating whether the disconnected station is a mesh child
926        is_mesh_child: bool,
927        /// Disconnection reason
928        reason: u16,
929    },
930
931    /// Received probe request packet in Soft-AccessPoint interface.
932    AccessPointProbeRequestReceived {
933        /// Received probe request signal strength
934        rssi: i8,
935        /// MAC address of the station which send probe request
936        mac: [u8; 6usize],
937    },
938
939    /// Received report of Fine-Timing-Measurement procedure.
940    FineTimingMeasurementReport {
941        /// MAC address of the FTM Peer
942        peer_mac: [u8; 6usize],
943        /// Status of the FTM operation
944        status: u32,
945        /// Raw average Round-Trip-Time with peer in Nano-Seconds
946        rtt_raw: u32,
947        /// Estimated Round-Trip-Time with peer in Nano-Seconds
948        rtt_est: u32,
949        /// Estimated one-way distance in Centi-Meters
950        dist_est: u32,
951        /// Detailed FTM report entries.
952        entries: Collection<FineTimingMeasurementReportInfo>,
953    },
954
955    /// Station Receive-Signal-Strenght-Indicator goes below the configured threshold.
956    StationBasicServiceSetReceivedSignalStrengthIndicatorLow {
957        /// RSSI value of bss
958        rssi: i8,
959    },
960
961    /// Status indication of Action Transmission operation.
962    ActionTransmissionStatus {
963        /// WiFi interface to send request to
964        ifx: u32,
965        /// Context to identify the request
966        context: u32,
967        /// Status of the operation
968        status: u32,
969        /// ID of the corresponding operation that was provided during action tx request
970        op_id: u8,
971        /// Channel provided in tx request
972        channel: u8,
973    },
974
975    /// Remain-on-Channel operation complete.
976    RemainOnChannelDone {
977        /// Context to identify the initiator of the request
978        context: u32,
979        /// ROC status
980        status: u32,
981        /// ID of the corresponding ROC operation
982        op_id: u8,
983        /// Channel provided in tx request
984        channel: u8,
985    },
986
987    /// Station beacon timeout.
988    StationBeaconTimeout,
989
990    /// Connectionless module wake interval has started.
991    ConnectionlessModuleWakeIntervalStart,
992
993    /// Soft-AccessPoint Wi-Fi-Protected-Status succeeded in registrar mode.
994    AccessPointWifiProtectedStatusRegistrarSuccess {
995        /// Enrollee mac address
996        peer_macaddr: [u8; 6usize],
997    },
998
999    /// Soft-AccessPoint Wi-Fi-Protected-Status failed in registrar mode.
1000    AccessPointWifiProtectedStatusRegistrarFailed {
1001        /// WPS failure reason wps_fail_reason_t
1002        reason: u32,
1003        /// Enrollee mac address
1004        peer_macaddr: [u8; 6usize],
1005    },
1006
1007    /// Soft-AccessPoint Wi-Fi-Protected-Status timed out in registrar mode.
1008    AccessPointWifiProtectedStatusRegistrarTimeout,
1009
1010    /// Soft-AccessPoint Wi-Fi-Protected-Status pin code in registrar mode.
1011    AccessPointWifiProtectedStatusRegistrarPin {
1012        /// PIN code of station in enrollee mode
1013        pin_code: [u8; 8usize],
1014    },
1015
1016    /// Soft-AccessPoint Wi-Fi-Protected-Status overlap in registrar mode.
1017    AccessPointWifiProtectedStatusRegistrarPushButtonConfigurationOverlap,
1018
1019    /// Individual Target-Wake-Time setup.
1020    IndividualTargetWakeTimeSetup,
1021
1022    /// Individual Target-Wake-Time teardown.
1023    IndividualTargetWakeTimeTeardown,
1024
1025    /// Individual Target-Wake-Time probe.
1026    IndividualTargetWakeTimeProbe,
1027
1028    /// Individual Target-Wake-Time suspended.
1029    IndividualTargetWakeTimeSuspend,
1030
1031    /// Target-Wake-Wakeup event.
1032    TargetWakeTimeWakeup,
1033
1034    /// Broadcast-Target-Wake-Time setup.
1035    BroadcastTargetWakeTimeSetup,
1036
1037    /// Broadcast-Target-Wake-Time teardown.
1038    BroadcastTargetWakeTimeTeardown,
1039
1040    // we don't currently support NAN - and there is no intention right now to change that
1041    /// Wi-Fi home channel change, doesn't occur when scanning.
1042    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/// Enable the given events.
1279#[instability::unstable]
1280pub fn enable_wifi_events(events: EnumSet<WifiEvent>) {
1281    WIFI_EVENT_ENABLE_MASK.with(|mask| *mask |= events);
1282}
1283
1284/// Disable the given events.
1285///
1286/// # Attention
1287/// Disabling events which are used internally will cause problems.
1288///
1289/// Therefore you usually don't want to disable these:
1290/// - [WifiEvent::StationStart]
1291/// - [WifiEvent::StationStop]
1292/// - [WifiEvent::StationConnected]
1293/// - [WifiEvent::StationDisconnected]
1294/// - [WifiEvent::AccessPointStart]
1295/// - [WifiEvent::AccessPointStop]
1296/// - [WifiEvent::AccessPointStationConnected]
1297/// - [WifiEvent::AccessPointStationDisconnected]
1298/// - [WifiEvent::ScanDone]
1299///
1300/// [crate::wifi::WifiController::new] always enables these events, even if they were disabled
1301/// beforehand.
1302#[instability::unstable]
1303pub fn disable_wifi_events(events: EnumSet<WifiEvent>) {
1304    WIFI_EVENT_ENABLE_MASK.with(|mask| *mask &= !events);
1305}
1306
1307/// Result for [EventSubscriber::next_message].
1308#[derive(Debug, Clone)]
1309#[cfg_attr(feature = "defmt", derive(defmt::Format))]
1310#[instability::unstable]
1311pub enum MessageResult {
1312    /// The subscriber did not receive all messages and lagged by the given amount of messages.
1313    /// (This is the amount of messages that were missed)
1314    Lagged(u64),
1315    /// The received event.
1316    Message(EventInfo),
1317}
1318
1319/// Event subscriber.
1320#[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    /// Wait for a published event
1347    #[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    /// Wait for a published event (ignoring lag results)
1356    #[instability::unstable]
1357    pub async fn next_event_pure(&mut self) -> EventInfo {
1358        self.inner.next_message_pure().await
1359    }
1360}