Skip to main content

esp_idf_svc/
eventloop.rs

1//! Event loop library
2
3use core::fmt::Debug;
4use core::marker::PhantomData;
5use core::time::Duration;
6use core::{ffi, mem, ptr, slice};
7
8extern crate alloc;
9use alloc::boxed::Box;
10use alloc::sync::{Arc, Weak};
11
12use embedded_svc::channel;
13
14use ::log::*;
15
16use crate::hal::cpu::Core;
17use crate::hal::delay;
18use crate::hal::interrupt;
19
20use crate::sys::*;
21
22use crate::handle::RawHandle;
23use crate::private::cstr::RawCstrs;
24use crate::private::mutex;
25use crate::private::waitable::Waitable;
26use crate::private::zerocopy::{Channel, QuitOnDrop, Receiver};
27
28#[cfg(all(feature = "alloc", esp_idf_comp_esp_timer_enabled))]
29pub use async_wait::*;
30
31pub type EspSystemSubscription<'a> = EspSubscription<'a, System>;
32pub type EspBackgroundSubscription<'a> = EspSubscription<'a, User<Background>>;
33pub type EspExplicitSubscription<'a> = EspSubscription<'a, User<Explicit>>;
34
35pub type EspSystemAsyncSubscription<P> = EspAsyncSubscription<P, System>;
36pub type EspBackgroundAsyncSubscription<P> = EspAsyncSubscription<P, User<Background>>;
37pub type EspExplicitAsyncSubscription<P> = EspAsyncSubscription<P, User<Explicit>>;
38
39pub type EspSystemEventLoop = EspEventLoop<System>;
40pub type EspBackgroundEventLoop = EspEventLoop<User<Background>>;
41pub type EspExplicitEventLoop = EspEventLoop<User<Explicit>>;
42
43#[derive(Debug)]
44pub struct BackgroundLoopConfiguration<'a> {
45    pub queue_size: usize,
46    pub task_name: &'a str,
47    pub task_priority: u8,
48    pub task_stack_size: usize,
49    pub task_pin_to_core: Core,
50}
51
52impl Default for BackgroundLoopConfiguration<'_> {
53    fn default() -> Self {
54        Self {
55            queue_size: 64,
56            task_name: "EventLoop",
57            task_priority: 0,
58            task_stack_size: 3072,
59            task_pin_to_core: Core::Core0,
60        }
61    }
62}
63
64impl<'a> TryFrom<&BackgroundLoopConfiguration<'a>> for (esp_event_loop_args_t, RawCstrs) {
65    type Error = EspError;
66
67    fn try_from(conf: &BackgroundLoopConfiguration<'a>) -> Result<Self, Self::Error> {
68        let mut rcs = RawCstrs::new();
69
70        let ela = esp_event_loop_args_t {
71            queue_size: conf.queue_size as _,
72            task_name: rcs.as_ptr(conf.task_name)?,
73            task_priority: conf.task_priority as _,
74            task_stack_size: conf.task_stack_size as _,
75            task_core_id: conf.task_pin_to_core as _,
76        };
77
78        Ok((ela, rcs))
79    }
80}
81
82#[derive(Debug)]
83pub struct ExplicitLoopConfiguration {
84    pub queue_size: usize,
85}
86
87impl Default for ExplicitLoopConfiguration {
88    fn default() -> Self {
89        Self { queue_size: 8192 }
90    }
91}
92
93impl From<&ExplicitLoopConfiguration> for esp_event_loop_args_t {
94    fn from(conf: &ExplicitLoopConfiguration) -> Self {
95        esp_event_loop_args_t {
96            queue_size: conf.queue_size as _,
97            ..Default::default()
98        }
99    }
100}
101
102static TAKEN: mutex::Mutex<bool> = mutex::Mutex::new(false);
103
104#[derive(Clone, Debug)]
105pub struct System;
106#[derive(Clone, Debug)]
107pub struct User<T>(esp_event_loop_handle_t, PhantomData<fn() -> T>);
108#[derive(Clone, Debug)]
109pub struct Background;
110#[derive(Clone, Debug)]
111pub struct Explicit;
112
113unsafe impl Send for User<Background> {}
114unsafe impl Sync for User<Background> {}
115
116unsafe impl Send for User<Explicit> {}
117unsafe impl Sync for User<Explicit> {}
118
119pub trait EspEventLoopType {
120    fn is_system() -> bool;
121}
122
123impl EspEventLoopType for System {
124    fn is_system() -> bool {
125        true
126    }
127}
128
129impl<T> EspEventLoopType for User<T> {
130    fn is_system() -> bool {
131        false
132    }
133}
134
135/// # Safety
136///
137/// By implementing this trait, the user guarantees that the binary format serialized/deserialized by
138/// `EspTypedEventSerializer` and `EspTypedEventDeserializer` is indeed THE binary format that stands behind
139/// the source ID returned by the `source` method in this trait
140/// (and that other producers/consumers of the ESP IDF event loop also recognize as the binary format corresponbding
141/// to this source ID).
142///
143/// Providing the wrong source ID for a binary format, or the wrong binary format for a given source ID
144/// would lead to a runtime crash, hence this trait can only be implemented unsafely, as the guarantee lies with the user
145/// and not with the compiler, that cannot enforce this contract.
146pub unsafe trait EspEventSource {
147    fn source() -> Option<&'static ffi::CStr>;
148
149    fn event_id() -> Option<i32> {
150        None
151    }
152}
153
154pub trait EspEventSerializer: EspEventSource {
155    type Data<'a>;
156
157    fn serialize<F, R>(data: &Self::Data<'_>, f: F) -> R
158    where
159        F: FnOnce(&EspEventPostData) -> R;
160}
161
162pub trait EspEventDeserializer: EspEventSource {
163    type Data<'a>;
164
165    fn deserialize<'a>(data: &EspEvent<'a>) -> Self::Data<'a>;
166}
167
168#[derive(Debug, Clone)]
169pub struct EspEventPostData<'a> {
170    source: &'static ffi::CStr,
171    event_id: i32,
172    payload: &'a ffi::c_void,
173    payload_len: usize,
174}
175
176impl<'a> EspEventPostData<'a> {
177    /// # Safety
178    ///
179    /// Care should be taken to only call this function with payload reference that lives at least as long as
180    /// the call that will post this data to the event loop
181    pub unsafe fn new<P: Copy + Send + 'static>(
182        source: &'static ffi::CStr,
183        event_id: Option<i32>,
184        payload: &'a P,
185    ) -> Self {
186        Self {
187            source,
188            event_id: event_id.unwrap_or(0),
189            payload: unsafe {
190                (payload as *const _ as *const ffi::c_void)
191                    .as_ref()
192                    .unwrap()
193            },
194            payload_len: mem::size_of::<P>(),
195        }
196    }
197
198    /// # Safety
199    ///
200    /// Care should be taken to only call this function with payload reference that lives at least as long as
201    /// the call that will post this data to the event loop
202    pub unsafe fn new_raw(
203        source: &'static ffi::CStr,
204        event_id: Option<i32>,
205        payload: &'a [u8],
206    ) -> Self {
207        Self {
208            source,
209            event_id: event_id.unwrap_or(0),
210            payload: unsafe {
211                (payload.as_ptr() as *const _ as *const ffi::c_void)
212                    .as_ref()
213                    .unwrap()
214            },
215            payload_len: payload.len(),
216        }
217    }
218}
219
220unsafe impl EspEventSource for EspEventPostData<'_> {
221    fn source() -> Option<&'static ffi::CStr> {
222        None
223    }
224}
225
226impl EspEventSerializer for EspEventPostData<'_> {
227    type Data<'d> = EspEventPostData<'d>;
228
229    fn serialize<F, R>(data: &Self::Data<'_>, f: F) -> R
230    where
231        F: FnOnce(&EspEventPostData) -> R,
232    {
233        f(data)
234    }
235}
236
237#[derive(Debug, Clone)]
238pub struct EspEvent<'a> {
239    pub source: &'static ffi::CStr,
240    pub event_id: i32,
241    pub payload: Option<&'a ffi::c_void>,
242}
243
244impl<'a> EspEvent<'a> {
245    /// # Safety
246    ///
247    /// Care should be taken to only call this function on fetch data that one is certain to be
248    /// of type `P`
249    pub unsafe fn as_payload<P: Copy + Send + 'static>(&self) -> &'a P {
250        let payload: &P = if mem::size_of::<P>() > 0 {
251            self.payload.unwrap() as *const _ as *const P
252        } else {
253            ptr::NonNull::dangling().as_ptr() as *const P
254        }
255        .as_ref()
256        .unwrap();
257
258        payload
259    }
260
261    /// # Safety
262    ///
263    /// Care should be taken to only call this function on fetch data that one is certain to be
264    /// of length `len`
265    pub unsafe fn as_raw_payload(&self, len: usize) -> Option<&[u8]> {
266        self.payload
267            .map(|payload| slice::from_raw_parts(payload as *const _ as *const _, len))
268    }
269}
270
271unsafe impl EspEventSource for EspEvent<'_> {
272    fn source() -> Option<&'static ffi::CStr> {
273        None
274    }
275}
276
277impl EspEventDeserializer for EspEvent<'_> {
278    type Data<'d> = EspEvent<'d>;
279
280    fn deserialize<'d>(data: &EspEvent<'d>) -> Self::Data<'d> {
281        data.clone()
282    }
283}
284
285struct UnsafeCallback<'a>(*mut Box<dyn FnMut(EspEvent) + Send + 'a>);
286
287impl<'a> UnsafeCallback<'a> {
288    #[allow(clippy::type_complexity)]
289    fn from(boxed: &mut Box<Box<dyn FnMut(EspEvent) + Send + 'a>>) -> Self {
290        Self(boxed.as_mut())
291    }
292
293    unsafe fn from_ptr(ptr: *mut ffi::c_void) -> Self {
294        Self(ptr as *mut _)
295    }
296
297    fn as_ptr(&self) -> *mut ffi::c_void {
298        self.0 as *mut _
299    }
300
301    unsafe fn call(&self, data: EspEvent) {
302        let reference = self.0.as_mut().unwrap();
303
304        (reference)(data);
305    }
306}
307
308enum EventLoopHandleRef<T>
309where
310    T: EspEventLoopType,
311{
312    Strong(Arc<EventLoopHandle<T>>),
313    Weak(Weak<EventLoopHandle<T>>),
314}
315
316impl<T> EventLoopHandleRef<T>
317where
318    T: EspEventLoopType,
319{
320    fn make_weak(&mut self) {
321        if matches!(self, Self::Strong(_)) {
322            *self = Self::Weak(Arc::downgrade(&self.upgrade().unwrap()))
323        }
324    }
325
326    fn upgrade(&self) -> Option<Arc<EventLoopHandle<T>>> {
327        match self {
328            Self::Strong(handle) => Some(handle.clone()),
329            Self::Weak(handle) => handle.upgrade(),
330        }
331    }
332}
333
334pub struct EspSubscription<'a, T>
335where
336    T: EspEventLoopType,
337{
338    event_loop_handle: EventLoopHandleRef<T>,
339    handler_instance: esp_event_handler_instance_t,
340    source: Option<&'static ffi::CStr>,
341    event_id: i32,
342    #[allow(clippy::type_complexity)]
343    _callback: Box<Box<dyn FnMut(EspEvent) + Send + 'a>>,
344}
345
346impl<T> EspSubscription<'_, T>
347where
348    T: EspEventLoopType,
349{
350    pub fn make_weak(&mut self) {
351        self.event_loop_handle.make_weak();
352    }
353
354    extern "C" fn handle(
355        event_handler_arg: *mut ffi::c_void,
356        event_base: esp_event_base_t,
357        event_id: i32,
358        event_data: *mut ffi::c_void,
359    ) {
360        let data = EspEvent {
361            source: unsafe { ffi::CStr::from_ptr(event_base) },
362            event_id,
363            payload: unsafe { (event_data as *const ffi::c_void).as_ref() },
364        };
365
366        unsafe {
367            UnsafeCallback::from_ptr(event_handler_arg).call(data);
368        }
369    }
370}
371
372unsafe impl<T> Send for EspSubscription<'_, T> where T: EspEventLoopType {}
373
374impl<T> Drop for EspSubscription<'_, T>
375where
376    T: EspEventLoopType,
377{
378    fn drop(&mut self) {
379        #[allow(clippy::unwrap_or_default)]
380        if let Some(handle) = self.event_loop_handle.upgrade() {
381            if T::is_system() {
382                unsafe {
383                    esp!(esp_event_handler_instance_unregister(
384                        self.source
385                            .map(ffi::CStr::as_ptr)
386                            .unwrap_or(core::ptr::null()),
387                        self.event_id,
388                        self.handler_instance
389                    ))
390                    .unwrap();
391                }
392            } else {
393                unsafe {
394                    let handle: &T = &handle.0;
395                    let user: &User<Background> = mem::transmute(handle);
396
397                    esp!(esp_event_handler_instance_unregister_with(
398                        user.0,
399                        self.source
400                            .map(ffi::CStr::as_ptr)
401                            .unwrap_or(core::ptr::null()),
402                        self.event_id,
403                        self.handler_instance
404                    ))
405                    .unwrap();
406                }
407            }
408        }
409    }
410}
411
412impl<T> RawHandle for EspSubscription<'_, User<T>>
413where
414    T: EspEventLoopType,
415{
416    type Handle = esp_event_handler_instance_t;
417
418    fn handle(&self) -> Self::Handle {
419        self.handler_instance
420    }
421}
422
423pub struct EspAsyncSubscription<D, T>
424where
425    D: EspEventDeserializer,
426    T: EspEventLoopType,
427{
428    receiver: Receiver<EspEvent<'static>>,
429    subscription: EspSubscription<'static, T>,
430    given: bool,
431    _deserializer: PhantomData<fn() -> D>,
432}
433
434impl<D, T> EspAsyncSubscription<D, T>
435where
436    D: EspEventDeserializer,
437    T: EspEventLoopType,
438{
439    pub fn make_weak(&mut self) {
440        self.subscription.make_weak();
441    }
442
443    pub async fn recv(&mut self) -> Result<D::Data<'_>, EspError> {
444        if self.given {
445            self.receiver.done();
446            self.given = false;
447        }
448
449        while let Some(data) = self.receiver.get_shared_async().await {
450            if Some(data.source) != D::source() {
451                self.receiver.done();
452                continue;
453            }
454            self.given = true;
455            return Ok(D::deserialize(data));
456        }
457
458        Err(EspError::from_infallible::<ESP_ERR_INVALID_STATE>())
459    }
460}
461
462impl<D, T> RawHandle for EspAsyncSubscription<D, User<T>>
463where
464    D: EspEventDeserializer,
465    T: EspEventLoopType,
466{
467    type Handle = esp_event_handler_instance_t;
468
469    fn handle(&self) -> Self::Handle {
470        self.subscription.handle()
471    }
472}
473
474impl<D, T> channel::ErrorType for EspAsyncSubscription<D, T>
475where
476    D: EspEventDeserializer,
477    T: EspEventLoopType,
478{
479    type Error = EspError;
480}
481
482impl<D, T> channel::asynch::Receiver for EspAsyncSubscription<D, T>
483where
484    D: EspEventDeserializer + 'static,
485    T: EspEventLoopType + 'static,
486{
487    type Data<'a> = D::Data<'a>;
488
489    async fn recv(&mut self) -> Result<Self::Data<'_>, Self::Error> {
490        EspAsyncSubscription::recv(self).await
491    }
492}
493
494#[derive(Debug)]
495struct EventLoopHandle<T>(T)
496where
497    T: EspEventLoopType;
498
499impl EventLoopHandle<System> {
500    fn new() -> Result<Self, EspError> {
501        let mut taken = TAKEN.lock();
502
503        if *taken {
504            return Err(EspError::from_infallible::<ESP_ERR_INVALID_STATE>());
505        }
506
507        esp!(unsafe { esp_event_loop_create_default() })?;
508
509        *taken = true;
510
511        Ok(Self(System))
512    }
513}
514
515impl<T> EventLoopHandle<User<T>> {
516    fn new_internal(conf: &esp_event_loop_args_t) -> Result<Self, EspError> {
517        let mut handle: esp_event_loop_handle_t = ptr::null_mut();
518
519        esp!(unsafe { esp_event_loop_create(conf as *const _, &mut handle as _) })?;
520
521        Ok(Self(User(handle, PhantomData)))
522    }
523}
524
525impl EventLoopHandle<User<Background>> {
526    fn new(conf: &BackgroundLoopConfiguration) -> Result<Self, EspError> {
527        let (nconf, _rcs) = conf.try_into()?;
528
529        Self::new_internal(&nconf)
530    }
531}
532
533impl EventLoopHandle<User<Explicit>> {
534    fn new(conf: &ExplicitLoopConfiguration) -> Result<Self, EspError> {
535        Self::new_internal(&conf.into())
536    }
537}
538
539impl<T> Drop for EventLoopHandle<T>
540where
541    T: EspEventLoopType,
542{
543    fn drop(&mut self) {
544        if T::is_system() {
545            let mut taken = TAKEN.lock();
546
547            unsafe {
548                esp!(esp_event_loop_delete_default()).unwrap();
549            }
550
551            *taken = false;
552
553            info!("System event loop dropped");
554        } else {
555            unsafe {
556                let handle: &T = &self.0;
557                let user: &User<Background> = mem::transmute(handle);
558
559                esp!(esp_event_loop_delete(user.0)).unwrap();
560            }
561
562            info!("Event loop dropped");
563        }
564    }
565}
566
567#[derive(Debug)]
568pub struct EspEventLoop<T>(Arc<EventLoopHandle<T>>)
569where
570    T: EspEventLoopType;
571
572impl<T> EspEventLoop<T>
573where
574    T: EspEventLoopType,
575{
576    pub fn subscribe_async<D>(&self) -> Result<EspAsyncSubscription<D, T>, EspError>
577    where
578        D: EspEventDeserializer,
579    {
580        let (channel, receiver) = Channel::new();
581
582        let sender = QuitOnDrop::new(channel);
583
584        let subscription = self.subscribe::<EspEvent, _>(move |event| {
585            let mut event = unsafe { mem::transmute::<EspEvent<'_>, EspEvent<'_>>(event) };
586
587            sender.channel().share(&mut event);
588        })?;
589
590        Ok(EspAsyncSubscription {
591            receiver,
592            subscription,
593            given: false,
594            _deserializer: PhantomData,
595        })
596    }
597
598    pub fn subscribe<D, F>(&self, mut callback: F) -> Result<EspSubscription<'static, T>, EspError>
599    where
600        D: EspEventDeserializer,
601        F: for<'a> FnMut(D::Data<'a>) + Send + 'static,
602    {
603        self.subscribe_raw::<D, _>(move |event| callback(D::deserialize(&event)))
604    }
605
606    /// # Safety
607    ///
608    /// This method - in contrast to method `subscribe` - allows the user to pass
609    /// a non-static callback/closure. This enables users to borrow
610    /// - in the closure - variables that live on the stack - or more generally - in the same
611    ///   scope where the service is created.
612    ///
613    /// HOWEVER: care should be taken NOT to call `core::mem::forget()` on the service,
614    /// as that would immediately lead to an UB (crash).
615    /// Also note that forgetting the service might happen with `Rc` and `Arc`
616    /// when circular references are introduced: <https://github.com/rust-lang/rust/issues/24456>
617    ///
618    /// The reason is that the closure is actually sent to a hidden ESP IDF thread.
619    /// This means that if the service is forgotten, Rust is free to e.g. unwind the stack
620    /// and the closure now owned by this other thread will end up with references to variables that no longer exist.
621    ///
622    /// The destructor of the service takes care - prior to the service being dropped and e.g.
623    /// the stack being unwind - to remove the closure from the hidden thread and destroy it.
624    /// Unfortunately, when the service is forgotten, the un-subscription does not happen
625    /// and invalid references are left dangling.
626    ///
627    /// This "local borrowing" will only be possible to express in a safe way once/if `!Leak` types
628    /// are introduced to Rust (i.e. the impossibility to "forget" a type and thus not call its destructor).
629    pub unsafe fn subscribe_nonstatic<'a, D, F>(
630        &self,
631        mut callback: F,
632    ) -> Result<EspSubscription<'a, T>, EspError>
633    where
634        D: EspEventDeserializer,
635        F: for<'d> FnMut(D::Data<'d>) + Send + 'a,
636    {
637        self.subscribe_raw::<D, _>(move |event| callback(D::deserialize(&event)))
638    }
639
640    pub async fn post_async<S>(&self, payload: &S::Data<'_>) -> Result<(), EspError>
641    where
642        S: EspEventSerializer,
643    {
644        loop {
645            if self.post::<S>(payload, delay::NON_BLOCK)? {
646                break Ok(());
647            }
648
649            crate::hal::task::yield_now().await;
650        }
651    }
652
653    pub fn post<S>(&self, payload: &S::Data<'_>, timeout: TickType_t) -> Result<bool, EspError>
654    where
655        S: EspEventSerializer,
656    {
657        if interrupt::active() {
658            #[cfg(not(esp_idf_esp_event_post_from_isr))]
659            panic!("Trying to post from an ISR handler. Enable `CONFIG_ESP_EVENT_POST_FROM_ISR` in `sdkconfig.defaults`");
660
661            #[cfg(esp_idf_esp_event_post_from_isr)]
662            S::serialize(payload, |event| self.isr_post_raw(event))
663        } else {
664            S::serialize(payload, |event| self.post_raw(event, timeout))
665        }
666    }
667
668    fn subscribe_raw<'a, S, F>(&self, callback: F) -> Result<EspSubscription<'a, T>, EspError>
669    where
670        S: EspEventSource,
671        F: FnMut(EspEvent) + Send + 'a,
672    {
673        let mut handler_instance: esp_event_handler_instance_t = ptr::null_mut();
674
675        let callback: Box<dyn FnMut(EspEvent) + Send + 'a> = Box::new(callback);
676        let mut callback = Box::new(callback);
677
678        let unsafe_callback = UnsafeCallback::from(&mut callback);
679
680        if T::is_system() {
681            esp!(unsafe {
682                esp_event_handler_instance_register(
683                    S::source().map(ffi::CStr::as_ptr).unwrap_or(ptr::null()),
684                    S::event_id().unwrap_or(ESP_EVENT_ANY_ID),
685                    Some(EspSubscription::<System>::handle),
686                    unsafe_callback.as_ptr(),
687                    &mut handler_instance as *mut _,
688                )
689            })?;
690        } else {
691            esp!(unsafe {
692                let handle: &T = &self.0 .0;
693                let user: &User<Background> = mem::transmute(handle);
694
695                esp_event_handler_instance_register_with(
696                    user.0,
697                    S::source().map(ffi::CStr::as_ptr).unwrap_or(ptr::null()),
698                    S::event_id().unwrap_or(ESP_EVENT_ANY_ID),
699                    Some(EspSubscription::<User<T>>::handle),
700                    unsafe_callback.as_ptr(),
701                    &mut handler_instance as *mut _,
702                )
703            })?;
704        }
705
706        Ok(EspSubscription {
707            event_loop_handle: EventLoopHandleRef::Strong(self.0.clone()),
708            handler_instance,
709            source: S::source(),
710            event_id: S::event_id().unwrap_or(ESP_EVENT_ANY_ID),
711            _callback: callback,
712        })
713    }
714
715    fn post_raw(&self, data: &EspEventPostData, timeout: TickType_t) -> Result<bool, EspError> {
716        let result = if T::is_system() {
717            unsafe {
718                esp_event_post(
719                    data.source.as_ptr(),
720                    data.event_id,
721                    data.payload as *const _ as *mut _,
722                    data.payload_len as _,
723                    timeout,
724                )
725            }
726        } else {
727            unsafe {
728                let handle: &T = &self.0 .0;
729                let user: &User<Background> = mem::transmute(handle);
730
731                esp_event_post_to(
732                    user.0,
733                    data.source.as_ptr(),
734                    data.event_id,
735                    data.payload as *const _ as *mut _,
736                    data.payload_len as _,
737                    timeout,
738                )
739            }
740        };
741
742        if result == ESP_ERR_TIMEOUT {
743            Ok(false)
744        } else {
745            esp_result!(result, true)
746        }
747    }
748
749    #[cfg(esp_idf_esp_event_post_from_isr)]
750    fn isr_post_raw(&self, data: &EspEventPostData) -> Result<bool, EspError> {
751        let mut higher_prio_task_woken: BaseType_t = Default::default();
752
753        let result = if T::is_system() {
754            unsafe {
755                esp_event_isr_post(
756                    data.source.as_ptr(),
757                    data.event_id,
758                    data.payload as *const _ as *mut _,
759                    data.payload_len as _,
760                    &mut higher_prio_task_woken as *mut _,
761                )
762            }
763        } else {
764            unsafe {
765                let handle: &T = &self.0 .0;
766                let user: &User<Background> = mem::transmute(handle);
767
768                esp_event_isr_post_to(
769                    user.0,
770                    data.source.as_ptr(),
771                    data.event_id,
772                    data.payload as *const _ as *mut _,
773                    data.payload_len as _,
774                    &mut higher_prio_task_woken as *mut _,
775                )
776            }
777        };
778
779        if higher_prio_task_woken != 0 {
780            crate::hal::task::do_yield();
781        }
782
783        if result == ESP_FAIL {
784            Ok(false)
785        } else {
786            esp!(result)?;
787
788            Ok(true)
789        }
790    }
791}
792
793impl<T> EspEventLoop<User<T>> {
794    pub fn spin(&mut self, timeout: TickType_t) -> Result<(), EspError> {
795        esp!(unsafe { esp_event_loop_run(self.0 .0 .0, timeout) })
796    }
797}
798
799impl<T> RawHandle for EspEventLoop<User<T>> {
800    type Handle = esp_event_loop_handle_t;
801
802    fn handle(&self) -> Self::Handle {
803        self.0 .0 .0
804    }
805}
806
807impl EspEventLoop<System> {
808    pub fn take() -> Result<Self, EspError> {
809        Ok(Self(Arc::new(EventLoopHandle::<System>::new()?)))
810    }
811}
812
813impl EspEventLoop<User<Background>> {
814    pub fn new(conf: &BackgroundLoopConfiguration) -> Result<Self, EspError> {
815        Ok(Self(Arc::new(EventLoopHandle::<User<Background>>::new(
816            conf,
817        )?)))
818    }
819}
820
821impl EspEventLoop<User<Explicit>> {
822    pub fn new(conf: &ExplicitLoopConfiguration) -> Result<Self, EspError> {
823        Ok(Self(Arc::new(EventLoopHandle::<User<Explicit>>::new(
824            conf,
825        )?)))
826    }
827}
828
829impl<T> Clone for EspEventLoop<T>
830where
831    T: EspEventLoopType,
832{
833    fn clone(&self) -> Self {
834        Self(self.0.clone())
835    }
836}
837
838unsafe impl<T> Send for EspEventLoop<T> where T: EspEventLoopType + Send {}
839unsafe impl<T> Sync for EspEventLoop<T> where T: EspEventLoopType + Sync {}
840
841pub struct Wait<T>
842where
843    T: EspEventLoopType,
844{
845    waitable: Arc<Waitable<()>>,
846    _subscription: EspSubscription<'static, T>,
847}
848
849impl<T> Wait<T>
850where
851    T: EspEventLoopType,
852{
853    pub fn new<S>(event_loop: &EspEventLoop<T>) -> Result<Self, EspError>
854    where
855        S: EspEventSource,
856    {
857        let waitable: Arc<Waitable<()>> = Arc::new(Waitable::new(()));
858
859        let s_waitable = waitable.clone();
860        let subscription = event_loop.subscribe_raw::<S, _>(move |_| {
861            s_waitable.cvar.notify_all();
862        })?;
863
864        Ok(Self {
865            waitable,
866            _subscription: subscription,
867        })
868    }
869
870    pub fn wait_while<F: FnMut() -> Result<bool, EspError>>(
871        &self,
872        mut matcher: F,
873        duration: Option<Duration>,
874    ) -> Result<(), EspError> {
875        if let Some(duration) = duration {
876            debug!("About to wait for duration {duration:?}");
877
878            let (timeout, _) =
879                self.waitable
880                    .wait_timeout_while_and_get(duration, |_| matcher(), |_| ())?;
881
882            if !timeout {
883                debug!("Waiting done - success");
884                Ok(())
885            } else {
886                debug!("Timeout while waiting");
887                esp!(ESP_ERR_TIMEOUT)
888            }
889        } else {
890            debug!("About to wait");
891
892            self.waitable.wait_while(|_| matcher())?;
893
894            debug!("Waiting done - success");
895
896            Ok(())
897        }
898    }
899}
900
901#[cfg(all(feature = "alloc", esp_idf_comp_esp_timer_enabled))]
902mod async_wait {
903    use core::marker::PhantomData;
904    use core::pin::pin;
905    use core::time::Duration;
906
907    extern crate alloc;
908    use alloc::sync::Arc;
909
910    use esp_idf_hal::task::asynch::Notification;
911
912    use ::log::debug;
913
914    use super::{EspEventDeserializer, EspEventLoop, EspEventLoopType, EspSubscription};
915    use crate::sys::{esp, EspError, ESP_ERR_TIMEOUT};
916    use crate::timer::{EspAsyncTimer, EspTimerService, Task};
917
918    pub struct AsyncWait<D, T>
919    where
920        D: EspEventDeserializer,
921        T: EspEventLoopType,
922    {
923        notification: Arc<Notification>,
924        timer: EspAsyncTimer,
925        _subscription: EspSubscription<'static, T>,
926        _deserializer: PhantomData<fn() -> D>,
927    }
928
929    impl<D, T> AsyncWait<D, T>
930    where
931        D: EspEventDeserializer,
932        T: EspEventLoopType + Send,
933    {
934        pub fn new(
935            event_loop: &EspEventLoop<T>,
936            timer_service: &EspTimerService<Task>,
937        ) -> Result<Self, EspError> {
938            let notification = Arc::new(Notification::new());
939
940            Ok(Self {
941                _subscription: {
942                    let notification = notification.clone();
943                    event_loop.subscribe::<D, _>(move |_| {
944                        notification.notify_lsb();
945                    })?
946                },
947                notification,
948                timer: timer_service.timer_async()?,
949                _deserializer: PhantomData,
950            })
951        }
952
953        pub async fn wait_while<F: FnMut() -> Result<bool, EspError>>(
954            &mut self,
955            mut matcher: F,
956            duration: Option<Duration>,
957        ) -> Result<(), EspError> {
958            let notification = &self.notification;
959
960            let subscription_wait = pin!(async move {
961                while matcher()? {
962                    notification.wait().await;
963                }
964
965                Result::<(), EspError>::Ok(())
966            });
967
968            if let Some(duration) = duration {
969                debug!("About to wait for duration {duration:?}");
970
971                let timer_wait = self.timer.after(duration);
972
973                match embassy_futures::select::select(subscription_wait, timer_wait).await {
974                    embassy_futures::select::Either::First(_) => {
975                        debug!("Waiting done - success");
976                        Ok(())
977                    }
978                    embassy_futures::select::Either::Second(_) => {
979                        debug!("Timeout while waiting");
980                        esp!(ESP_ERR_TIMEOUT)
981                    }
982                }
983            } else {
984                debug!("About to wait");
985
986                subscription_wait.await?;
987
988                debug!("Waiting done - success");
989
990                Ok(())
991            }
992        }
993    }
994}