1use alloc::{boxed::Box, collections::vec_deque::VecDeque};
13use core::{
14 fmt::Debug,
15 marker::PhantomData,
16 task::{Context, Poll},
17};
18
19use docsplay::Display;
20use esp_hal::time::Duration;
21use esp_sync::NonReentrantMutex;
22use portable_atomic::{AtomicBool, AtomicU8, Ordering};
23
24use super::*;
25#[cfg(feature = "csi")]
26use crate::wifi::csi::CsiConfig;
27use crate::{
28 asynch::AtomicWaker,
29 sys::include::*,
30 wifi::{RxControlInfo, WifiError},
31};
32
33const RECEIVE_QUEUE_SIZE: usize = 10;
34
35pub const ESP_NOW_MAX_DATA_LEN: usize = 250;
37
38pub const BROADCAST_ADDRESS: [u8; 6] = [0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8];
40
41struct EspNowState {
42 rx_queue: VecDeque<ReceivedData>,
44}
45
46static STATE: NonReentrantMutex<EspNowState> = NonReentrantMutex::new(EspNowState {
47 rx_queue: VecDeque::new(),
48});
49
50static ESP_NOW_SEND_CB_INVOKED: AtomicBool = AtomicBool::new(false);
56static ESP_NOW_SEND_STATUS: AtomicBool = AtomicBool::new(true);
58
59static ESP_NOW_TX_WAKER: AtomicWaker = AtomicWaker::new();
60static ESP_NOW_RX_WAKER: AtomicWaker = AtomicWaker::new();
61
62macro_rules! check_error {
63 ($block:block) => {
64 match unsafe { $block } {
65 0 => Ok(()),
66 res => Err(EspNowError::Error(Error::from_code(res as u32))),
67 }
68 };
69}
70
71macro_rules! check_error_expect {
72 ($block:block, $msg:literal) => {
73 match unsafe { $block } {
74 0 => (),
75 res => panic!(
76 "{}: {:?}",
77 $msg,
78 EspNowError::Error(Error::from_code(res as u32))
79 ),
80 }
81 };
82}
83
84#[repr(u32)]
86#[derive(Display, Debug, Copy, Clone, Eq, PartialEq, Hash)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88#[instability::unstable]
89pub enum Error {
90 NotInitialized = 12389,
92
93 InvalidArgument = 12390,
95
96 OutOfMemory = 12391,
98
99 PeerListFull = 12392,
101
102 NotFound = 12393,
104
105 Internal = 12394,
107
108 PeerExists = 12395,
110
111 InterfaceMismatch = 12396,
113
114 Other(u32),
117}
118
119impl Error {
120 fn from_code(code: u32) -> Error {
122 match code {
123 12389 => Error::NotInitialized,
124 12390 => Error::InvalidArgument,
125 12391 => Error::OutOfMemory,
126 12392 => Error::PeerListFull,
127 12393 => Error::NotFound,
128 12394 => Error::Internal,
129 12395 => Error::PeerExists,
130 12396 => Error::InterfaceMismatch,
131 _ => Error::Other(code),
132 }
133 }
134}
135
136impl core::error::Error for Error {}
137
138#[derive(Display, Debug, Copy, Clone, Eq, PartialEq, Hash)]
140#[cfg_attr(feature = "defmt", derive(defmt::Format))]
141#[instability::unstable]
142pub enum EspNowError {
143 Error(Error),
145 SendFailed,
147 DuplicateInstance,
149 Initialization(WifiError),
151}
152
153impl core::error::Error for EspNowError {}
154
155impl From<WifiError> for EspNowError {
156 fn from(f: WifiError) -> Self {
157 Self::Initialization(f)
158 }
159}
160
161#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
163#[cfg_attr(feature = "defmt", derive(defmt::Format))]
164#[instability::unstable]
165pub struct PeerCount {
166 pub total_count: i32,
168
169 pub encrypted_count: i32,
171}
172
173#[repr(u32)]
175#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
176#[cfg_attr(feature = "defmt", derive(defmt::Format))]
177#[instability::unstable]
178pub enum WifiPhyRate {
179 Rate1mL = 0,
181 Rate2m,
183 Rate5mL,
185 Rate11mL,
187 Rate2mS,
189 Rate5mS,
191 Rate11mS,
193 Rate48m,
195 Rate24m,
197 Rate12m,
199 Rate6m,
201 Rate54m,
203 Rate36m,
205 Rate18m,
207 Rate9m,
209 RateMcs0Lgi,
211 RateMcs1Lgi,
213 RateMcs2Lgi,
215 RateMcs3Lgi,
217 RateMcs4Lgi,
219 RateMcs5Lgi,
221 RateMcs6Lgi,
223 RateMcs7Lgi,
225 RateMcs0Sgi,
227 RateMcs1Sgi,
229 RateMcs2Sgi,
231 RateMcs3Sgi,
233 RateMcs4Sgi,
235 RateMcs5Sgi,
237 RateMcs6Sgi,
239 RateMcs7Sgi,
241 RateLora250k,
243 RateLora500k,
245 RateMax,
247}
248
249#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
251#[cfg_attr(feature = "defmt", derive(defmt::Format))]
252#[instability::unstable]
253pub struct PeerInfo {
254 pub interface: EspNowWifiInterface,
256
257 pub peer_address: [u8; 6],
260
261 pub lmk: Option<[u8; 16]>,
263
264 pub channel: Option<u8>,
266
267 pub encrypt: bool,
269 }
271
272#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
274#[cfg_attr(feature = "defmt", derive(defmt::Format))]
275#[instability::unstable]
276pub struct ReceiveInfo {
277 pub src_address: [u8; 6],
279
280 pub dst_address: [u8; 6],
282
283 pub rx_control: RxControlInfo,
285}
286
287#[derive(Clone)]
290#[instability::unstable]
291pub struct ReceivedData {
292 data: Box<[u8]>,
293 pub info: ReceiveInfo,
295}
296
297impl ReceivedData {
298 #[instability::unstable]
300 pub fn data(&self) -> &[u8] {
301 &self.data
302 }
303}
304
305#[cfg(feature = "defmt")]
306impl defmt::Format for ReceivedData {
307 fn format(&self, fmt: defmt::Formatter<'_>) {
308 defmt::write!(fmt, "ReceivedData {}, Info {}", &self.data[..], &self.info,)
309 }
310}
311
312impl Debug for ReceivedData {
313 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
314 f.debug_struct("ReceivedData")
315 .field("data", &self.data())
316 .field("info", &self.info)
317 .finish()
318 }
319}
320
321#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
323#[cfg_attr(feature = "defmt", derive(defmt::Format))]
324#[instability::unstable]
325pub enum EspNowWifiInterface {
326 AccessPoint,
328 Station,
330}
331
332impl EspNowWifiInterface {
333 fn as_wifi_interface(&self) -> wifi_interface_t {
334 match self {
335 EspNowWifiInterface::AccessPoint => wifi_interface_t_WIFI_IF_AP,
336 EspNowWifiInterface::Station => wifi_interface_t_WIFI_IF_STA,
337 }
338 }
339
340 fn from_wifi_interface(interface: wifi_interface_t) -> Self {
341 #[allow(non_upper_case_globals)]
342 match interface {
343 wifi_interface_t_WIFI_IF_AP => EspNowWifiInterface::AccessPoint,
344 wifi_interface_t_WIFI_IF_STA => EspNowWifiInterface::Station,
345 wifi_interface_t_WIFI_IF_NAN => panic!("NAN is unsupported"),
346 _ => unreachable!("Unknown interface"),
347 }
348 }
349}
350
351#[derive(Debug)]
353#[cfg_attr(feature = "defmt", derive(defmt::Format))]
354#[instability::unstable]
355pub struct EspNowManager<'d> {
356 _rc: EspNowRc<'d>,
357}
358
359impl EspNowManager<'_> {
360 #[instability::unstable]
363 pub fn set_channel(&self, channel: u8) -> Result<(), EspNowError> {
364 check_error!({ esp_wifi_set_channel(channel, 0) })
365 }
366
367 #[instability::unstable]
369 pub fn version(&self) -> Result<u32, EspNowError> {
370 let mut version = 0u32;
371 check_error!({ esp_now_get_version(&mut version as *mut u32) })?;
372 Ok(version)
373 }
374
375 #[instability::unstable]
377 pub fn add_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> {
378 let raw_peer = esp_now_peer_info_t {
379 peer_addr: peer.peer_address,
380 lmk: peer.lmk.unwrap_or([0u8; 16]),
381 channel: peer.channel.unwrap_or(0),
382 ifidx: peer.interface.as_wifi_interface(),
383 encrypt: peer.encrypt,
384 priv_: core::ptr::null_mut(),
385 };
386 check_error!({ esp_now_add_peer(&raw_peer as *const _) })
387 }
388
389 #[cfg(feature = "csi")]
391 #[instability::unstable]
392 pub fn set_csi(
393 &mut self,
394 mut csi: CsiConfig,
395 cb: impl FnMut(crate::wifi::csi::WifiCsiInfo<'_>) + Send,
396 ) -> Result<(), WifiError> {
397 csi.apply_config()?;
398 csi.set_receive_cb(cb)?;
399 csi.set_csi(true)?;
400
401 Ok(())
402 }
403
404 #[instability::unstable]
406 pub fn remove_peer(&self, peer_address: &[u8; 6]) -> Result<(), EspNowError> {
407 check_error!({ esp_now_del_peer(peer_address.as_ptr()) })
408 }
409
410 #[instability::unstable]
412 pub fn modify_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> {
413 let raw_peer = esp_now_peer_info_t {
414 peer_addr: peer.peer_address,
415 lmk: peer.lmk.unwrap_or([0u8; 16]),
416 channel: peer.channel.unwrap_or(0),
417 ifidx: peer.interface.as_wifi_interface(),
418 encrypt: peer.encrypt,
419 priv_: core::ptr::null_mut(),
420 };
421 check_error!({ esp_now_mod_peer(&raw_peer as *const _) })
422 }
423
424 #[instability::unstable]
426 pub fn peer(&self, peer_address: &[u8; 6]) -> Result<PeerInfo, EspNowError> {
427 let mut raw_peer = esp_now_peer_info_t {
428 peer_addr: [0u8; 6],
429 lmk: [0u8; 16],
430 channel: 0,
431 ifidx: 0,
432 encrypt: false,
433 priv_: core::ptr::null_mut(),
434 };
435 check_error!({ esp_now_get_peer(peer_address.as_ptr(), &mut raw_peer as *mut _) })?;
436
437 Ok(PeerInfo {
438 interface: EspNowWifiInterface::from_wifi_interface(raw_peer.ifidx),
439 peer_address: raw_peer.peer_addr,
440 lmk: if raw_peer.lmk.is_empty() {
441 None
442 } else {
443 Some(raw_peer.lmk)
444 },
445 channel: if raw_peer.channel != 0 {
446 Some(raw_peer.channel)
447 } else {
448 None
449 },
450 encrypt: raw_peer.encrypt,
451 })
452 }
453
454 #[instability::unstable]
460 pub fn fetch_peer(&self, from_head: bool) -> Result<PeerInfo, EspNowError> {
461 let mut raw_peer = esp_now_peer_info_t {
462 peer_addr: [0u8; 6],
463 lmk: [0u8; 16],
464 channel: 0,
465 ifidx: 0,
466 encrypt: false,
467 priv_: core::ptr::null_mut(),
468 };
469 check_error!({ esp_now_fetch_peer(from_head, &mut raw_peer as *mut _) })?;
470
471 Ok(PeerInfo {
472 interface: EspNowWifiInterface::from_wifi_interface(raw_peer.ifidx),
473 peer_address: raw_peer.peer_addr,
474 lmk: if raw_peer.lmk.is_empty() {
475 None
476 } else {
477 Some(raw_peer.lmk)
478 },
479 channel: if raw_peer.channel != 0 {
480 Some(raw_peer.channel)
481 } else {
482 None
483 },
484 encrypt: raw_peer.encrypt,
485 })
486 }
487
488 #[instability::unstable]
490 pub fn peer_exists(&self, peer_address: &[u8; 6]) -> bool {
491 unsafe { esp_now_is_peer_exist(peer_address.as_ptr()) }
492 }
493
494 #[instability::unstable]
496 pub fn peer_count(&self) -> Result<PeerCount, EspNowError> {
497 let mut peer_num = esp_now_peer_num_t {
498 total_num: 0,
499 encrypt_num: 0,
500 };
501 check_error!({ esp_now_get_peer_num(&mut peer_num as *mut _) })?;
502
503 Ok(PeerCount {
504 total_count: peer_num.total_num,
505 encrypted_count: peer_num.encrypt_num,
506 })
507 }
508
509 #[instability::unstable]
511 pub fn set_pmk(&self, pmk: &[u8; 16]) -> Result<(), EspNowError> {
512 check_error!({ esp_now_set_pmk(pmk.as_ptr()) })
513 }
514
515 #[instability::unstable]
520 pub fn set_wake_window(&self, wake_window: Duration) -> Result<(), EspNowError> {
521 let ms = wake_window.as_millis();
522
523 if ms > u16::MAX as u64 {
524 return Err(EspNowError::Error(Error::InvalidArgument));
525 }
526 check_error!({ esp_now_set_wake_window(ms as u16) })
527 }
528
529 #[instability::unstable]
531 pub fn set_rate(&self, rate: WifiPhyRate) -> Result<(), EspNowError> {
532 check_error!({ esp_wifi_config_espnow_rate(wifi_interface_t_WIFI_IF_STA, rate as u32,) })
533 }
534}
535
536#[derive(Debug)]
544#[cfg_attr(feature = "defmt", derive(defmt::Format))]
545#[instability::unstable]
546pub struct EspNowSender<'d> {
547 _rc: EspNowRc<'d>,
548}
549
550impl EspNowSender<'_> {
551 #[instability::unstable]
555 pub fn send<'s>(
556 &'s mut self,
557 dst_addr: &[u8; 6],
558 data: &[u8],
559 ) -> Result<SendWaiter<'s>, EspNowError> {
560 ESP_NOW_SEND_CB_INVOKED.store(false, Ordering::Release);
561 check_error!({ esp_now_send(dst_addr.as_ptr(), data.as_ptr(), data.len()) })?;
562 Ok(SendWaiter(PhantomData))
563 }
564}
565
566#[allow(unknown_lints)]
567#[allow(clippy::too_long_first_doc_paragraph)]
568#[must_use]
579#[instability::unstable]
580pub struct SendWaiter<'s>(PhantomData<&'s mut EspNowSender<'s>>);
581
582impl SendWaiter<'_> {
583 #[instability::unstable]
586 pub fn wait(self) -> Result<(), EspNowError> {
587 core::mem::forget(self);
590 while !ESP_NOW_SEND_CB_INVOKED.load(Ordering::Acquire) {}
591
592 if ESP_NOW_SEND_STATUS.load(Ordering::Relaxed) {
593 Ok(())
594 } else {
595 Err(EspNowError::SendFailed)
596 }
597 }
598}
599
600impl Drop for SendWaiter<'_> {
601 fn drop(&mut self) {
604 while !ESP_NOW_SEND_CB_INVOKED.load(Ordering::Acquire) {}
605 }
606}
607
608#[derive(Debug)]
611#[cfg_attr(feature = "defmt", derive(defmt::Format))]
612#[instability::unstable]
613pub struct EspNowReceiver<'d> {
614 _rc: EspNowRc<'d>,
615}
616
617impl EspNowReceiver<'_> {
618 #[instability::unstable]
620 pub fn receive(&self) -> Option<ReceivedData> {
621 STATE.with(|state| state.rx_queue.pop_front())
622 }
623}
624
625#[derive(Debug)]
628struct EspNowRc<'d> {
629 rc: &'static AtomicU8,
630 inner: PhantomData<EspNow<'d>>,
631}
632
633#[cfg(feature = "defmt")]
634impl defmt::Format for EspNowRc<'_> {
635 fn format(&self, f: defmt::Formatter<'_>) {
636 defmt::write!(
637 f,
638 "EspNowRc {{ rc: {}, inner: ... }}",
639 self.rc.load(Ordering::Relaxed)
640 );
641 }
642}
643
644impl EspNowRc<'_> {
645 fn new() -> Self {
646 static ESP_NOW_RC: AtomicU8 = AtomicU8::new(0);
647 assert!(ESP_NOW_RC.fetch_add(1, Ordering::AcqRel) == 0);
648
649 Self {
650 rc: &ESP_NOW_RC,
651 inner: PhantomData,
652 }
653 }
654}
655
656impl Clone for EspNowRc<'_> {
657 fn clone(&self) -> Self {
658 self.rc.fetch_add(1, Ordering::Release);
659 Self {
660 rc: self.rc,
661 inner: PhantomData,
662 }
663 }
664}
665
666impl Drop for EspNowRc<'_> {
667 fn drop(&mut self) {
668 if self.rc.fetch_sub(1, Ordering::AcqRel) == 1 {
669 unsafe {
670 esp_now_unregister_recv_cb();
671 esp_now_deinit();
672 }
673 }
674 }
675}
676
677#[allow(unknown_lints)]
678#[allow(clippy::too_long_first_doc_paragraph)]
679#[derive(Debug)]
689#[cfg_attr(feature = "defmt", derive(defmt::Format))]
690#[instability::unstable]
691pub struct EspNow<'d> {
692 manager: EspNowManager<'d>,
693 sender: EspNowSender<'d>,
694 receiver: EspNowReceiver<'d>,
695 _phantom: PhantomData<&'d ()>,
696}
697
698impl<'d> EspNow<'d> {
699 pub(crate) fn new_internal() -> EspNow<'d> {
700 let espnow_rc = EspNowRc::new();
701 let esp_now = EspNow {
702 manager: EspNowManager {
703 _rc: espnow_rc.clone(),
704 },
705 sender: EspNowSender {
706 _rc: espnow_rc.clone(),
707 },
708 receiver: EspNowReceiver { _rc: espnow_rc },
709 _phantom: PhantomData,
710 };
711
712 check_error_expect!({ esp_now_init() }, "esp-now-init failed");
713 check_error_expect!(
714 { esp_now_register_recv_cb(Some(rcv_cb)) },
715 "receiving callback failed"
716 );
717 check_error_expect!(
718 { esp_now_register_send_cb(Some(send_cb)) },
719 "sending callback failed"
720 );
721
722 esp_now
723 .add_peer(PeerInfo {
724 interface: EspNowWifiInterface::Station,
725 peer_address: BROADCAST_ADDRESS,
726 lmk: None,
727 channel: None,
728 encrypt: false,
729 })
730 .expect("adding peer failed");
731
732 esp_now
733 }
734
735 #[instability::unstable]
738 pub fn split(self) -> (EspNowManager<'d>, EspNowSender<'d>, EspNowReceiver<'d>) {
739 (self.manager, self.sender, self.receiver)
740 }
741
742 #[instability::unstable]
745 pub fn set_channel(&self, channel: u8) -> Result<(), EspNowError> {
746 self.manager.set_channel(channel)
747 }
748
749 #[instability::unstable]
751 pub fn version(&self) -> Result<u32, EspNowError> {
752 self.manager.version()
753 }
754
755 #[instability::unstable]
757 pub fn add_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> {
758 self.manager.add_peer(peer)
759 }
760
761 #[instability::unstable]
763 pub fn remove_peer(&self, peer_address: &[u8; 6]) -> Result<(), EspNowError> {
764 self.manager.remove_peer(peer_address)
765 }
766
767 #[instability::unstable]
769 pub fn modify_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> {
770 self.manager.modify_peer(peer)
771 }
772
773 #[instability::unstable]
775 pub fn peer(&self, peer_address: &[u8; 6]) -> Result<PeerInfo, EspNowError> {
776 self.manager.peer(peer_address)
777 }
778
779 #[instability::unstable]
785 pub fn fetch_peer(&self, from_head: bool) -> Result<PeerInfo, EspNowError> {
786 self.manager.fetch_peer(from_head)
787 }
788
789 #[instability::unstable]
791 pub fn peer_exists(&self, peer_address: &[u8; 6]) -> bool {
792 self.manager.peer_exists(peer_address)
793 }
794
795 #[instability::unstable]
797 pub fn peer_count(&self) -> Result<PeerCount, EspNowError> {
798 self.manager.peer_count()
799 }
800
801 #[instability::unstable]
803 pub fn set_pmk(&self, pmk: &[u8; 16]) -> Result<(), EspNowError> {
804 self.manager.set_pmk(pmk)
805 }
806
807 #[instability::unstable]
812 pub fn set_wake_window(&self, wake_window: Duration) -> Result<(), EspNowError> {
813 self.manager.set_wake_window(wake_window)
814 }
815
816 #[instability::unstable]
818 pub fn set_rate(&self, rate: WifiPhyRate) -> Result<(), EspNowError> {
819 self.manager.set_rate(rate)
820 }
821
822 #[instability::unstable]
826 pub fn send<'s>(
827 &'s mut self,
828 dst_addr: &[u8; 6],
829 data: &[u8],
830 ) -> Result<SendWaiter<'s>, EspNowError> {
831 self.sender.send(dst_addr, data)
832 }
833
834 #[instability::unstable]
836 pub fn receive(&self) -> Option<ReceivedData> {
837 self.receiver.receive()
838 }
839}
840
841unsafe extern "C" fn send_cb(_tx_info: *const esp_now_send_info_t, status: esp_now_send_status_t) {
842 let is_success = status == esp_now_send_status_t_ESP_NOW_SEND_SUCCESS;
843 ESP_NOW_SEND_STATUS.store(is_success, Ordering::Relaxed);
844
845 ESP_NOW_SEND_CB_INVOKED.store(true, Ordering::Release);
846
847 ESP_NOW_TX_WAKER.wake();
848}
849
850unsafe extern "C" fn rcv_cb(
851 esp_now_info: *const esp_now_recv_info_t,
852 data: *const u8,
853 data_len: i32,
854) {
855 let src = unsafe {
856 [
857 (*esp_now_info).src_addr.offset(0).read(),
858 (*esp_now_info).src_addr.offset(1).read(),
859 (*esp_now_info).src_addr.offset(2).read(),
860 (*esp_now_info).src_addr.offset(3).read(),
861 (*esp_now_info).src_addr.offset(4).read(),
862 (*esp_now_info).src_addr.offset(5).read(),
863 ]
864 };
865
866 let dst = unsafe {
867 [
868 (*esp_now_info).des_addr.offset(0).read(),
869 (*esp_now_info).des_addr.offset(1).read(),
870 (*esp_now_info).des_addr.offset(2).read(),
871 (*esp_now_info).des_addr.offset(3).read(),
872 (*esp_now_info).des_addr.offset(4).read(),
873 (*esp_now_info).des_addr.offset(5).read(),
874 ]
875 };
876
877 let rx_cntl = unsafe { (*esp_now_info).rx_ctrl };
878 let rx_control = unsafe { RxControlInfo::from_raw(rx_cntl) };
879
880 let info = ReceiveInfo {
881 src_address: src,
882 dst_address: dst,
883 rx_control,
884 };
885 let slice = unsafe { core::slice::from_raw_parts(data, data_len as usize) };
886
887 STATE.with(|state| {
888 let data = Box::from(slice);
889
890 if state.rx_queue.len() >= RECEIVE_QUEUE_SIZE {
891 state.rx_queue.pop_front();
892 }
893
894 state.rx_queue.push_back(ReceivedData { data, info });
895 ESP_NOW_RX_WAKER.wake();
896 });
897}
898
899impl EspNowReceiver<'_> {
900 #[instability::unstable]
904 pub fn receive_async(&mut self) -> ReceiveFuture<'_> {
905 ReceiveFuture(PhantomData)
906 }
907}
908
909impl EspNowSender<'_> {
910 #[instability::unstable]
912 pub fn send_async<'s, 'r>(
913 &'s mut self,
914 addr: &'r [u8; 6],
915 data: &'r [u8],
916 ) -> SendFuture<'s, 'r> {
917 SendFuture {
918 _sender: PhantomData,
919 addr,
920 data,
921 sent: false,
922 }
923 }
924}
925
926impl EspNow<'_> {
927 #[instability::unstable]
931 pub fn receive_async(&mut self) -> ReceiveFuture<'_> {
932 self.receiver.receive_async()
933 }
934
935 #[instability::unstable]
938 pub fn send_async<'s, 'r>(
939 &'s mut self,
940 dst_addr: &'r [u8; 6],
941 data: &'r [u8],
942 ) -> SendFuture<'s, 'r> {
943 self.sender.send_async(dst_addr, data)
944 }
945}
946
947#[must_use = "futures do nothing unless you `.await` or poll them"]
950#[instability::unstable]
951pub struct SendFuture<'s, 'r> {
952 _sender: PhantomData<&'s mut EspNowSender<'s>>,
953 addr: &'r [u8; 6],
954 data: &'r [u8],
955 sent: bool,
956}
957
958impl core::future::Future for SendFuture<'_, '_> {
959 type Output = Result<(), EspNowError>;
960
961 fn poll(mut self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
962 if !self.sent {
963 ESP_NOW_TX_WAKER.register(cx.waker());
964 ESP_NOW_SEND_CB_INVOKED.store(false, Ordering::Release);
965 if let Err(e) = check_error!({
966 esp_now_send(self.addr.as_ptr(), self.data.as_ptr(), self.data.len())
967 }) {
968 return Poll::Ready(Err(e));
969 }
970 self.sent = true;
971 }
972
973 if !ESP_NOW_SEND_CB_INVOKED.load(Ordering::Acquire) {
974 Poll::Pending
975 } else {
976 Poll::Ready(if ESP_NOW_SEND_STATUS.load(Ordering::Relaxed) {
977 Ok(())
978 } else {
979 Err(EspNowError::SendFailed)
980 })
981 }
982 }
983}
984
985#[must_use = "futures do nothing unless you `.await` or poll them"]
989#[instability::unstable]
990pub struct ReceiveFuture<'r>(PhantomData<&'r mut EspNowReceiver<'r>>);
991
992impl core::future::Future for ReceiveFuture<'_> {
993 type Output = ReceivedData;
994
995 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
996 ESP_NOW_RX_WAKER.register(cx.waker());
997
998 if let Some(data) = STATE.with(|state| state.rx_queue.pop_front()) {
999 Poll::Ready(data)
1000 } else {
1001 Poll::Pending
1002 }
1003 }
1004}