1use alloc::{boxed::Box, collections::vec_deque::VecDeque};
13use core::{cell::RefCell, fmt::Debug, marker::PhantomData};
14
15use critical_section::Mutex;
16use portable_atomic::{AtomicBool, AtomicU8, Ordering};
17
18#[cfg(feature = "csi")]
19use crate::wifi::CsiConfig;
20use crate::{
21 binary::include::*,
22 wifi::{RxControlInfo, WifiError},
23};
24
25const RECEIVE_QUEUE_SIZE: usize = 10;
26
27pub const ESP_NOW_MAX_DATA_LEN: usize = 250;
29
30pub const BROADCAST_ADDRESS: [u8; 6] = [0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8, 0xffu8];
32
33static RECEIVE_QUEUE: Mutex<RefCell<VecDeque<ReceivedData>>> =
35 Mutex::new(RefCell::new(VecDeque::new()));
36
37static ESP_NOW_SEND_CB_INVOKED: AtomicBool = AtomicBool::new(false);
43static ESP_NOW_SEND_STATUS: AtomicBool = AtomicBool::new(true);
45
46macro_rules! check_error {
47 ($block:block) => {
48 match unsafe { $block } {
49 0 => Ok(()),
50 res => Err(EspNowError::Error(Error::from_code(res as u32))),
51 }
52 };
53}
54
55#[repr(u32)]
57#[derive(Debug)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59#[allow(clippy::enum_variant_names)] pub enum Error {
61 NotInitialized = 12389,
63
64 InvalidArgument = 12390,
66
67 OutOfMemory = 12391,
69
70 PeerListFull = 12392,
72
73 NotFound = 12393,
75
76 InternalError = 12394,
78
79 PeerExists = 12395,
81
82 InterfaceError = 12396,
84
85 Other(u32),
88}
89
90impl Error {
91 pub fn from_code(code: u32) -> Error {
92 match code {
93 12389 => Error::NotInitialized,
94 12390 => Error::InvalidArgument,
95 12391 => Error::OutOfMemory,
96 12392 => Error::PeerListFull,
97 12393 => Error::NotFound,
98 12394 => Error::InternalError,
99 12395 => Error::PeerExists,
100 12396 => Error::InterfaceError,
101 _ => Error::Other(code),
102 }
103 }
104}
105
106#[derive(Debug)]
108#[cfg_attr(feature = "defmt", derive(defmt::Format))]
109pub enum EspNowError {
110 Error(Error),
112 SendFailed,
114 DuplicateInstance,
116 Initialization(WifiError),
118}
119
120impl From<WifiError> for EspNowError {
121 fn from(f: WifiError) -> Self {
122 Self::Initialization(f)
123 }
124}
125
126#[derive(Debug)]
128#[cfg_attr(feature = "defmt", derive(defmt::Format))]
129pub struct PeerCount {
130 pub total_count: i32,
132
133 pub encrypted_count: i32,
135}
136
137#[repr(u32)]
139#[cfg_attr(feature = "defmt", derive(defmt::Format))]
140pub enum WifiPhyRate {
141 Rate1mL = 0,
143 Rate2m,
145 Rate5mL,
147 Rate11mL,
149 Rate2mS,
151 Rate5mS,
153 Rate11mS,
155 Rate48m,
157 Rate24m,
159 Rate12m,
161 Rate6m,
163 Rate54m,
165 Rate36m,
167 Rate18m,
169 Rate9m,
171 RateMcs0Lgi,
173 RateMcs1Lgi,
175 RateMcs2Lgi,
177 RateMcs3Lgi,
179 RateMcs4Lgi,
181 RateMcs5Lgi,
183 RateMcs6Lgi,
185 RateMcs7Lgi,
187 RateMcs0Sgi,
189 RateMcs1Sgi,
191 RateMcs2Sgi,
193 RateMcs3Sgi,
195 RateMcs4Sgi,
197 RateMcs5Sgi,
199 RateMcs6Sgi,
201 RateMcs7Sgi,
203 RateLora250k,
205 RateLora500k,
207 RateMax,
209}
210
211#[derive(Debug, Clone, Copy)]
213#[cfg_attr(feature = "defmt", derive(defmt::Format))]
214pub struct PeerInfo {
215 pub interface: EspNowWifiInterface,
217
218 pub peer_address: [u8; 6],
221
222 pub lmk: Option<[u8; 16]>,
224
225 pub channel: Option<u8>,
227
228 pub encrypt: bool,
230 }
232
233#[derive(Debug, Clone, Copy)]
235#[cfg_attr(feature = "defmt", derive(defmt::Format))]
236pub struct ReceiveInfo {
237 pub src_address: [u8; 6],
239
240 pub dst_address: [u8; 6],
242
243 pub rx_control: RxControlInfo,
245}
246
247#[derive(Clone)]
250pub struct ReceivedData {
251 data: Box<[u8]>,
252 pub info: ReceiveInfo,
253}
254
255impl ReceivedData {
256 pub fn data(&self) -> &[u8] {
258 &self.data
259 }
260}
261
262#[cfg(feature = "defmt")]
263impl defmt::Format for ReceivedData {
264 fn format(&self, fmt: defmt::Formatter<'_>) {
265 defmt::write!(fmt, "ReceivedData {}, Info {}", &self.data[..], &self.info,)
266 }
267}
268
269impl Debug for ReceivedData {
270 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
271 f.debug_struct("ReceivedData")
272 .field("data", &self.data())
273 .field("info", &self.info)
274 .finish()
275 }
276}
277
278#[derive(Debug, Clone, Copy, PartialEq)]
280#[cfg_attr(feature = "defmt", derive(defmt::Format))]
281pub enum EspNowWifiInterface {
282 Ap,
284 Sta,
286}
287
288impl EspNowWifiInterface {
289 fn as_wifi_interface(&self) -> wifi_interface_t {
290 match self {
291 EspNowWifiInterface::Ap => wifi_interface_t_WIFI_IF_AP,
292 EspNowWifiInterface::Sta => wifi_interface_t_WIFI_IF_STA,
293 }
294 }
295
296 fn from_wifi_interface(interface: wifi_interface_t) -> Self {
297 #[allow(non_upper_case_globals)]
298 match interface {
299 wifi_interface_t_WIFI_IF_AP => EspNowWifiInterface::Ap,
300 wifi_interface_t_WIFI_IF_STA => EspNowWifiInterface::Sta,
301 wifi_interface_t_WIFI_IF_NAN => panic!("NAN is unsupported"),
302 _ => unreachable!("Unknown interface"),
303 }
304 }
305}
306
307pub struct EspNowManager<'d> {
309 _rc: EspNowRc<'d>,
310}
311
312impl EspNowManager<'_> {
313 pub fn set_channel(&self, channel: u8) -> Result<(), EspNowError> {
316 check_error!({ esp_wifi_set_channel(channel, 0) })
317 }
318
319 pub fn version(&self) -> Result<u32, EspNowError> {
321 let mut version = 0u32;
322 check_error!({ esp_now_get_version(&mut version as *mut u32) })?;
323 Ok(version)
324 }
325
326 pub fn add_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> {
328 let raw_peer = esp_now_peer_info_t {
329 peer_addr: peer.peer_address,
330 lmk: peer.lmk.unwrap_or([0u8; 16]),
331 channel: peer.channel.unwrap_or(0),
332 ifidx: peer.interface.as_wifi_interface(),
333 encrypt: peer.encrypt,
334 priv_: core::ptr::null_mut(),
335 };
336 check_error!({ esp_now_add_peer(&raw_peer as *const _) })
337 }
338
339 #[cfg(feature = "csi")]
341 pub fn set_csi(
342 &mut self,
343 mut csi: CsiConfig,
344 cb: impl FnMut(crate::wifi::wifi_csi_info_t) + Send,
345 ) -> Result<(), WifiError> {
346 csi.apply_config()?;
347 csi.set_receive_cb(cb)?;
348 csi.set_csi(true)?;
349
350 Ok(())
351 }
352
353 pub fn remove_peer(&self, peer_address: &[u8; 6]) -> Result<(), EspNowError> {
355 check_error!({ esp_now_del_peer(peer_address.as_ptr()) })
356 }
357
358 pub fn modify_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> {
360 let raw_peer = esp_now_peer_info_t {
361 peer_addr: peer.peer_address,
362 lmk: peer.lmk.unwrap_or([0u8; 16]),
363 channel: peer.channel.unwrap_or(0),
364 ifidx: peer.interface.as_wifi_interface(),
365 encrypt: peer.encrypt,
366 priv_: core::ptr::null_mut(),
367 };
368 check_error!({ esp_now_mod_peer(&raw_peer as *const _) })
369 }
370
371 pub fn peer(&self, peer_address: &[u8; 6]) -> Result<PeerInfo, EspNowError> {
373 let mut raw_peer = esp_now_peer_info_t {
374 peer_addr: [0u8; 6],
375 lmk: [0u8; 16],
376 channel: 0,
377 ifidx: 0,
378 encrypt: false,
379 priv_: core::ptr::null_mut(),
380 };
381 check_error!({ esp_now_get_peer(peer_address.as_ptr(), &mut raw_peer as *mut _) })?;
382
383 Ok(PeerInfo {
384 interface: EspNowWifiInterface::from_wifi_interface(raw_peer.ifidx),
385 peer_address: raw_peer.peer_addr,
386 lmk: if raw_peer.lmk.is_empty() {
387 None
388 } else {
389 Some(raw_peer.lmk)
390 },
391 channel: if raw_peer.channel != 0 {
392 Some(raw_peer.channel)
393 } else {
394 None
395 },
396 encrypt: raw_peer.encrypt,
397 })
398 }
399
400 pub fn fetch_peer(&self, from_head: bool) -> Result<PeerInfo, EspNowError> {
406 let mut raw_peer = esp_now_peer_info_t {
407 peer_addr: [0u8; 6],
408 lmk: [0u8; 16],
409 channel: 0,
410 ifidx: 0,
411 encrypt: false,
412 priv_: core::ptr::null_mut(),
413 };
414 check_error!({ esp_now_fetch_peer(from_head, &mut raw_peer as *mut _) })?;
415
416 Ok(PeerInfo {
417 interface: EspNowWifiInterface::from_wifi_interface(raw_peer.ifidx),
418 peer_address: raw_peer.peer_addr,
419 lmk: if raw_peer.lmk.is_empty() {
420 None
421 } else {
422 Some(raw_peer.lmk)
423 },
424 channel: if raw_peer.channel != 0 {
425 Some(raw_peer.channel)
426 } else {
427 None
428 },
429 encrypt: raw_peer.encrypt,
430 })
431 }
432
433 pub fn peer_exists(&self, peer_address: &[u8; 6]) -> bool {
435 unsafe { esp_now_is_peer_exist(peer_address.as_ptr()) }
436 }
437
438 pub fn peer_count(&self) -> Result<PeerCount, EspNowError> {
440 let mut peer_num = esp_now_peer_num_t {
441 total_num: 0,
442 encrypt_num: 0,
443 };
444 check_error!({ esp_now_get_peer_num(&mut peer_num as *mut _) })?;
445
446 Ok(PeerCount {
447 total_count: peer_num.total_num,
448 encrypted_count: peer_num.encrypt_num,
449 })
450 }
451
452 pub fn set_pmk(&self, pmk: &[u8; 16]) -> Result<(), EspNowError> {
454 check_error!({ esp_now_set_pmk(pmk.as_ptr()) })
455 }
456
457 pub fn set_wake_window(&self, wake_window: u16) -> Result<(), EspNowError> {
462 check_error!({ esp_now_set_wake_window(wake_window) })
463 }
464
465 pub fn set_rate(&self, rate: WifiPhyRate) -> Result<(), EspNowError> {
467 check_error!({ esp_wifi_config_espnow_rate(wifi_interface_t_WIFI_IF_STA, rate as u32,) })
468 }
469}
470
471pub struct EspNowSender<'d> {
479 _rc: EspNowRc<'d>,
480}
481
482impl EspNowSender<'_> {
483 pub fn send<'s>(
487 &'s mut self,
488 dst_addr: &[u8; 6],
489 data: &[u8],
490 ) -> Result<SendWaiter<'s>, EspNowError> {
491 ESP_NOW_SEND_CB_INVOKED.store(false, Ordering::Release);
492 check_error!({ esp_now_send(dst_addr.as_ptr(), data.as_ptr(), data.len()) })?;
493 Ok(SendWaiter(PhantomData))
494 }
495}
496
497#[allow(unknown_lints)]
498#[allow(clippy::too_long_first_doc_paragraph)]
499#[must_use]
510pub struct SendWaiter<'s>(PhantomData<&'s mut EspNowSender<'s>>);
511
512impl SendWaiter<'_> {
513 pub fn wait(self) -> Result<(), EspNowError> {
516 core::mem::forget(self);
519 while !ESP_NOW_SEND_CB_INVOKED.load(Ordering::Acquire) {}
520
521 if ESP_NOW_SEND_STATUS.load(Ordering::Relaxed) {
522 Ok(())
523 } else {
524 Err(EspNowError::SendFailed)
525 }
526 }
527}
528
529impl Drop for SendWaiter<'_> {
530 fn drop(&mut self) {
533 while !ESP_NOW_SEND_CB_INVOKED.load(Ordering::Acquire) {}
534 }
535}
536
537pub struct EspNowReceiver<'d> {
540 _rc: EspNowRc<'d>,
541}
542
543impl EspNowReceiver<'_> {
544 pub fn receive(&self) -> Option<ReceivedData> {
546 critical_section::with(|cs| {
547 let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs);
548 queue.pop_front()
549 })
550 }
551}
552
553struct EspNowRc<'d> {
556 rc: &'static AtomicU8,
557 inner: PhantomData<EspNow<'d>>,
558}
559
560impl EspNowRc<'_> {
561 fn new() -> Self {
562 static ESP_NOW_RC: AtomicU8 = AtomicU8::new(0);
563 assert!(ESP_NOW_RC.fetch_add(1, Ordering::AcqRel) == 0);
564
565 Self {
566 rc: &ESP_NOW_RC,
567 inner: PhantomData,
568 }
569 }
570}
571
572impl Clone for EspNowRc<'_> {
573 fn clone(&self) -> Self {
574 self.rc.fetch_add(1, Ordering::Release);
575 Self {
576 rc: self.rc,
577 inner: PhantomData,
578 }
579 }
580}
581
582impl Drop for EspNowRc<'_> {
583 fn drop(&mut self) {
584 if self.rc.fetch_sub(1, Ordering::AcqRel) == 1 {
585 unsafe {
586 esp_now_unregister_recv_cb();
587 esp_now_deinit();
588 }
589 }
590 }
591}
592
593#[allow(unknown_lints)]
594#[allow(clippy::too_long_first_doc_paragraph)]
595pub struct EspNow<'d> {
605 manager: EspNowManager<'d>,
606 sender: EspNowSender<'d>,
607 receiver: EspNowReceiver<'d>,
608 _phantom: PhantomData<&'d ()>,
609}
610
611impl<'d> EspNow<'d> {
612 pub(crate) fn new_internal() -> EspNow<'d> {
613 let espnow_rc = EspNowRc::new();
614 let esp_now = EspNow {
615 manager: EspNowManager {
616 _rc: espnow_rc.clone(),
617 },
618 sender: EspNowSender {
619 _rc: espnow_rc.clone(),
620 },
621 receiver: EspNowReceiver { _rc: espnow_rc },
622 _phantom: PhantomData,
623 };
624
625 check_error!({ esp_now_init() }).expect("esp-now-init failed");
626 check_error!({ esp_now_register_recv_cb(Some(rcv_cb)) }).ok();
627 check_error!({ esp_now_register_send_cb(Some(send_cb)) }).ok();
628
629 esp_now
630 .add_peer(PeerInfo {
631 interface: EspNowWifiInterface::Sta,
632 peer_address: BROADCAST_ADDRESS,
633 lmk: None,
634 channel: None,
635 encrypt: false,
636 })
637 .ok();
638
639 esp_now
640 }
641
642 pub fn split(self) -> (EspNowManager<'d>, EspNowSender<'d>, EspNowReceiver<'d>) {
645 (self.manager, self.sender, self.receiver)
646 }
647
648 pub fn set_channel(&self, channel: u8) -> Result<(), EspNowError> {
651 self.manager.set_channel(channel)
652 }
653
654 pub fn version(&self) -> Result<u32, EspNowError> {
656 self.manager.version()
657 }
658
659 pub fn add_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> {
661 self.manager.add_peer(peer)
662 }
663
664 pub fn remove_peer(&self, peer_address: &[u8; 6]) -> Result<(), EspNowError> {
666 self.manager.remove_peer(peer_address)
667 }
668
669 pub fn modify_peer(&self, peer: PeerInfo) -> Result<(), EspNowError> {
671 self.manager.modify_peer(peer)
672 }
673
674 pub fn peer(&self, peer_address: &[u8; 6]) -> Result<PeerInfo, EspNowError> {
676 self.manager.peer(peer_address)
677 }
678
679 pub fn fetch_peer(&self, from_head: bool) -> Result<PeerInfo, EspNowError> {
685 self.manager.fetch_peer(from_head)
686 }
687
688 pub fn peer_exists(&self, peer_address: &[u8; 6]) -> bool {
690 self.manager.peer_exists(peer_address)
691 }
692
693 pub fn peer_count(&self) -> Result<PeerCount, EspNowError> {
695 self.manager.peer_count()
696 }
697
698 pub fn set_pmk(&self, pmk: &[u8; 16]) -> Result<(), EspNowError> {
700 self.manager.set_pmk(pmk)
701 }
702
703 pub fn set_wake_window(&self, wake_window: u16) -> Result<(), EspNowError> {
708 self.manager.set_wake_window(wake_window)
709 }
710
711 pub fn set_rate(&self, rate: WifiPhyRate) -> Result<(), EspNowError> {
713 self.manager.set_rate(rate)
714 }
715
716 pub fn send<'s>(
720 &'s mut self,
721 dst_addr: &[u8; 6],
722 data: &[u8],
723 ) -> Result<SendWaiter<'s>, EspNowError> {
724 self.sender.send(dst_addr, data)
725 }
726
727 pub fn receive(&self) -> Option<ReceivedData> {
729 self.receiver.receive()
730 }
731}
732
733unsafe extern "C" fn send_cb(_mac_addr: *const u8, status: esp_now_send_status_t) {
734 critical_section::with(|_| {
735 let is_success = status == esp_now_send_status_t_ESP_NOW_SEND_SUCCESS;
736 ESP_NOW_SEND_STATUS.store(is_success, Ordering::Relaxed);
737
738 ESP_NOW_SEND_CB_INVOKED.store(true, Ordering::Release);
739
740 asynch::ESP_NOW_TX_WAKER.wake();
741 })
742}
743
744unsafe extern "C" fn rcv_cb(
745 esp_now_info: *const esp_now_recv_info_t,
746 data: *const u8,
747 data_len: i32,
748) {
749 let src = unsafe {
750 [
751 (*esp_now_info).src_addr.offset(0).read(),
752 (*esp_now_info).src_addr.offset(1).read(),
753 (*esp_now_info).src_addr.offset(2).read(),
754 (*esp_now_info).src_addr.offset(3).read(),
755 (*esp_now_info).src_addr.offset(4).read(),
756 (*esp_now_info).src_addr.offset(5).read(),
757 ]
758 };
759
760 let dst = unsafe {
761 [
762 (*esp_now_info).des_addr.offset(0).read(),
763 (*esp_now_info).des_addr.offset(1).read(),
764 (*esp_now_info).des_addr.offset(2).read(),
765 (*esp_now_info).des_addr.offset(3).read(),
766 (*esp_now_info).des_addr.offset(4).read(),
767 (*esp_now_info).des_addr.offset(5).read(),
768 ]
769 };
770
771 let rx_cntl = unsafe { (*esp_now_info).rx_ctrl };
772 let rx_control = unsafe { RxControlInfo::from_raw(rx_cntl) };
773
774 let info = ReceiveInfo {
775 src_address: src,
776 dst_address: dst,
777 rx_control,
778 };
779 let slice = unsafe { core::slice::from_raw_parts(data, data_len as usize) };
780 critical_section::with(|cs| {
781 let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs);
782 let data = Box::from(slice);
783
784 if queue.len() >= RECEIVE_QUEUE_SIZE {
785 queue.pop_front();
786 }
787
788 queue.push_back(ReceivedData { data, info });
789
790 asynch::ESP_NOW_RX_WAKER.wake();
791 });
792}
793
794pub use asynch::SendFuture;
795
796mod asynch {
797 use core::task::{Context, Poll};
798
799 use esp_hal::asynch::AtomicWaker;
800
801 use super::*;
802
803 pub(super) static ESP_NOW_TX_WAKER: AtomicWaker = AtomicWaker::new();
804 pub(super) static ESP_NOW_RX_WAKER: AtomicWaker = AtomicWaker::new();
805
806 impl EspNowReceiver<'_> {
807 pub fn receive_async(&mut self) -> ReceiveFuture<'_> {
811 ReceiveFuture(PhantomData)
812 }
813 }
814
815 impl EspNowSender<'_> {
816 pub fn send_async<'s, 'r>(
818 &'s mut self,
819 addr: &'r [u8; 6],
820 data: &'r [u8],
821 ) -> SendFuture<'s, 'r> {
822 SendFuture {
823 _sender: PhantomData,
824 addr,
825 data,
826 sent: false,
827 }
828 }
829 }
830
831 impl EspNow<'_> {
832 pub fn receive_async(&mut self) -> ReceiveFuture<'_> {
836 self.receiver.receive_async()
837 }
838
839 pub fn send_async<'s, 'r>(
842 &'s mut self,
843 dst_addr: &'r [u8; 6],
844 data: &'r [u8],
845 ) -> SendFuture<'s, 'r> {
846 self.sender.send_async(dst_addr, data)
847 }
848 }
849
850 #[must_use = "futures do nothing unless you `.await` or poll them"]
853 pub struct SendFuture<'s, 'r> {
854 _sender: PhantomData<&'s mut EspNowSender<'s>>,
855 addr: &'r [u8; 6],
856 data: &'r [u8],
857 sent: bool,
858 }
859
860 impl core::future::Future for SendFuture<'_, '_> {
861 type Output = Result<(), EspNowError>;
862
863 fn poll(mut self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
864 if !self.sent {
865 ESP_NOW_TX_WAKER.register(cx.waker());
866 ESP_NOW_SEND_CB_INVOKED.store(false, Ordering::Release);
867 if let Err(e) = check_error!({
868 esp_now_send(self.addr.as_ptr(), self.data.as_ptr(), self.data.len())
869 }) {
870 return Poll::Ready(Err(e));
871 }
872 self.sent = true;
873 }
874
875 if !ESP_NOW_SEND_CB_INVOKED.load(Ordering::Acquire) {
876 Poll::Pending
877 } else {
878 Poll::Ready(if ESP_NOW_SEND_STATUS.load(Ordering::Relaxed) {
879 Ok(())
880 } else {
881 Err(EspNowError::SendFailed)
882 })
883 }
884 }
885 }
886
887 #[must_use = "futures do nothing unless you `.await` or poll them"]
891 pub struct ReceiveFuture<'r>(PhantomData<&'r mut EspNowReceiver<'r>>);
892
893 impl core::future::Future for ReceiveFuture<'_> {
894 type Output = ReceivedData;
895
896 fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
897 ESP_NOW_RX_WAKER.register(cx.waker());
898
899 if let Some(data) = critical_section::with(|cs| {
900 let mut queue = RECEIVE_QUEUE.borrow_ref_mut(cs);
901 queue.pop_front()
902 }) {
903 Poll::Ready(data)
904 } else {
905 Poll::Pending
906 }
907 }
908 }
909}