1#![cfg_attr(
2 all(docsrs, not(not_really_docsrs)),
3 doc = "<div style='padding:30px;background:#810;color:#fff;text-align:center;'><p>You might want to <a href='https://docs.espressif.com/projects/rust/'>browse the <code>esp-radio</code> documentation on the esp-rs website</a> instead.</p><p>The documentation here on <a href='https://docs.rs'>docs.rs</a> is built for a single chip only (ESP32-C3, in particular), while on the esp-rs website you can select your exact chip from the list of supported devices. Available peripherals and their APIs might change depending on the chip.</p></div>\n\n<br/>\n\n"
4)]
5#![doc = concat!("**", chip_pretty!(), "**")]
9#![cfg_attr(
26 feature = "ieee802154",
27 doc = "<div class=\"warning\"><b>Hint:</b> The scheduler is not required for the 802.15.4.</div>"
28)]
29#![doc = ""]
30#![doc = esp_hal::before_snippet!()]
32#![cfg_attr(
46 wifi_driver_supported,
47 doc = r#"
48
49if let Ok((controller, interfaces)) = esp_radio::wifi::new(
50 peripherals.WIFI,
51 Default::default(),
52) {}
53"#
54)]
55#![cfg_attr(
56 all(bt_driver_supported, not(wifi_driver_supported)),
57 doc = r#"
58
59# use esp_radio::ble::controller::BleConnector;
60if let Ok(controller) = BleConnector::new(peripherals.BT, Default::default()) {}
61"#
62)]
63#![doc = esp_hal::after_snippet!()]
64#![doc = concat!(r#"features = [""#, chip!(), r#"", "wifi", "esp-now", "esp-alloc"]"#)]
69#![doc = concat!(r#"features = [""#, chip!(), r#"", "esp-radio", "esp-alloc"]"#)]
71#![doc = concat!(r#"features = [""#, chip!(), r#""]"#)]
73#![cfg_attr(
92 multi_core,
93 doc = concat!(
94 "### Running on the Second Core",
95 "\n\n",
96 "BLE and Wi-Fi can also be run on the second core.",
97 "\n\n",
98 "`esp_radio::init` is recommended to be called on the first core. The tasks ",
99 "created by `esp-radio` are pinned to the first core.",
100 "\n\n",
101 "It's also important to allocate adequate stack for the second core; in many ",
102 "cases 8kB is not enough, and 16kB or more may be required depending on your ",
103 "use case. Failing to allocate adequate stack may result in strange behaviour, ",
104 "such as your application silently failing at some point during execution."
105 )
106)]
107#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
117#![doc = ""]
124#![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_radio_config_table.md"))]
125#![doc(html_logo_url = "https://avatars.githubusercontent.com/u/46717278")]
126#![no_std]
127#![cfg_attr(xtensa, feature(asm_experimental_arch))]
128#![deny(missing_docs, rust_2018_idioms, rustdoc::all)]
129#![cfg_attr(
130 not(any(feature = "wifi", feature = "ble")),
131 allow(
132 unused,
133 reason = "There are a number of places where code is needed for either wifi or ble,
134 and cfg-ing them out would make the code less readable just to avoid warnings in the
135 less common case. Truly unused code will be flagged by the check that enables either
136 ble or wifi."
137 )
138)]
139#![cfg_attr(docsrs, feature(doc_cfg, custom_inner_attributes, proc_macro_hygiene))]
140
141#[macro_use]
142extern crate esp_metadata_generated;
143
144extern crate alloc;
145
146mod coex_utils;
148mod fmt;
149pub(crate) mod reg_access;
150
151use core::marker::PhantomData;
152
153use esp_hal as hal;
154#[instability::unstable]
155pub use esp_phy::CalibrationResult;
156use esp_radio_rtos_driver as preempt;
157#[cfg(all(esp32, feature = "unstable"))]
158use hal::analog::adc::{release_adc2, try_claim_adc2};
159#[cfg(feature = "wifi")]
160use hal::{after_snippet, before_snippet};
161use sys::include::esp_phy_calibration_data_t;
162pub(crate) mod sys {
163 #[cfg(esp32)]
164 pub use esp_wifi_sys_esp32::*;
165 #[cfg(esp32c2)]
166 pub use esp_wifi_sys_esp32c2::*;
167 #[cfg(esp32c3)]
168 pub use esp_wifi_sys_esp32c3::*;
169 #[cfg(esp32c5)]
170 pub use esp_wifi_sys_esp32c5::*;
171 #[cfg(esp32c6)]
172 pub use esp_wifi_sys_esp32c6::*;
173 #[cfg(esp32c61)]
174 pub use esp_wifi_sys_esp32c61::*;
175 #[cfg(esp32h2)]
176 pub use esp_wifi_sys_esp32h2::*;
177 #[cfg(esp32s2)]
178 pub use esp_wifi_sys_esp32s2::*;
179 #[cfg(esp32s3)]
180 pub use esp_wifi_sys_esp32s3::*;
181}
182
183use crate::refcount::Refcount;
184#[cfg(feature = "wifi")]
185use crate::wifi::WifiError;
186
187#[doc(hidden)]
189macro_rules! unstable_module {
190 ($(
191 $(#[$meta:meta])*
192 pub mod $module:ident;
193 )*) => {
194 $(
195 $(#[$meta])*
196 #[cfg(feature = "unstable")]
197 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
198 pub mod $module;
199
200 $(#[$meta])*
201 #[cfg(not(feature = "unstable"))]
202 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
203 #[allow(unused)]
204 pub(crate) mod $module;
205 )*
206 };
207}
208
209mod asynch;
210mod compat;
211mod interrupt_dispatch;
212mod radio_clocks;
213mod refcount;
214mod time;
215
216#[cfg(feature = "wifi")]
217pub mod wifi;
218
219unstable_module! {
220 #[cfg(feature = "esp-now")]
221 #[cfg_attr(docsrs, doc(cfg(feature = "esp-now")))]
222 pub mod esp_now;
223 #[cfg(feature = "ble")]
224 #[cfg_attr(docsrs, doc(cfg(feature = "ble")))]
225 pub mod ble;
226 #[cfg(feature = "ieee802154")]
227 #[cfg_attr(docsrs, doc(cfg(feature = "ieee802154")))]
228 pub mod ieee802154;
229}
230
231pub(crate) mod common_adapter;
232
233#[cfg(all(feature = "ble", bt_controller = "npl"))]
234pub(crate) static ESP_RADIO_LOCK: esp_sync::RawMutex = esp_sync::RawMutex::new();
235
236#[allow(clippy::assertions_on_constants)] const _: () = {
239 cfg_if::cfg_if! {
240 if #[cfg(wifi_driver_supported)] {
241 core::assert!(sys::include::CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM == 10);
242 core::assert!(sys::include::CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM == 32);
243 core::assert!(sys::include::WIFI_STATIC_TX_BUFFER_NUM == 0);
244 core::assert!(sys::include::CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM == 32);
245 core::assert!(sys::include::CONFIG_ESP_WIFI_AMPDU_RX_ENABLED == 1);
246 core::assert!(sys::include::CONFIG_ESP_WIFI_AMPDU_TX_ENABLED == 1);
247 core::assert!(sys::include::WIFI_AMSDU_TX_ENABLED == 0);
248 core::assert!(sys::include::CONFIG_ESP32_WIFI_RX_BA_WIN == 6);
249 }
250 };
251};
252
253#[procmacros::doc_replace]
254#[cfg_attr(
270 esp32,
271 doc = " - The function may return an error if ADC2 is already in use."
272)]
273pub(crate) fn init() {
276 #[cfg(all(esp32, feature = "unstable"))]
277 if try_claim_adc2(unsafe { hal::Internal::conjure() }).is_err() {
278 panic!(
279 "ADC2 is currently in use by esp-hal, but esp-radio requires it for Wi-Fi operation."
280 );
281 }
282
283 if !preempt::initialized() {
284 panic!("The scheduler must be initialized before initializing the radio.");
285 }
286
287 const MIN_CLOCK: u32 = 80;
289 let cpu_clock = esp_hal::clock::cpu_clock().as_mhz();
290 if cpu_clock < MIN_CLOCK {
291 panic!(
292 "CPU clock {} MHz is too slow for Wi-Fi operation, minimum required is {} MHz",
293 cpu_clock, MIN_CLOCK
294 );
295 }
296
297 crate::common_adapter::enable_wifi_power_domain();
298
299 wifi_set_log_verbose();
300 radio_clocks::init_radio_clocks();
301
302 #[cfg(feature = "coex")]
303 match crate::wifi::coex_initialize() {
304 0 => {}
305 error => panic!("Failed to initialize coexistence, error code: {}", error),
306 }
307
308 debug!("Radio initialized");
309}
310
311pub(crate) fn deinit() {
312 #[cfg(feature = "coex")]
314 {
315 unsafe { crate::wifi::os_adapter::coex_disable() };
316 unsafe { crate::wifi::os_adapter::coex_deinit() };
317 }
318
319 #[cfg(feature = "wifi")]
320 wifi::shutdown_wifi_isr();
321 #[cfg(feature = "ble")]
322 ble::shutdown_ble_isr();
323
324 #[cfg(all(esp32, feature = "unstable"))]
325 release_adc2(unsafe { esp_hal::Internal::conjure() });
327
328 debug!("Radio deinitialized");
329}
330
331#[derive(Debug)]
334#[cfg_attr(feature = "defmt", derive(defmt::Format))]
335pub(crate) struct RadioRefGuard {
336 _private: PhantomData<()>,
337}
338
339static RADIO_REFCOUNT: Refcount = Refcount::new();
340
341impl RadioRefGuard {
342 fn new() -> Self {
345 debug!("Creating RadioRefGuard");
346
347 RADIO_REFCOUNT.increment(init);
348 RadioRefGuard {
349 _private: PhantomData,
350 }
351 }
352}
353
354impl Drop for RadioRefGuard {
355 fn drop(&mut self) {
357 debug!("Dropping RadioRefGuard");
358
359 RADIO_REFCOUNT.decrement(deinit);
360 }
361}
362
363#[instability::unstable]
366pub fn wifi_set_log_verbose() {
367 #[cfg(all(feature = "print-logs-from-driver", not(esp32h2)))]
368 unsafe {
369 use crate::sys::include::{
370 esp_wifi_internal_set_log_level,
371 wifi_log_level_t_WIFI_LOG_VERBOSE,
372 };
373
374 esp_wifi_internal_set_log_level(wifi_log_level_t_WIFI_LOG_VERBOSE);
375 }
376}
377
378#[instability::unstable]
385pub fn phy_calibration_data(data: &mut [u8; esp_phy::PHY_CALIBRATION_DATA_LENGTH]) {
386 let _ = esp_phy::backup_phy_calibration_data(data);
387}
388
389#[instability::unstable]
393pub fn set_phy_calibration_data(data: &[u8; core::mem::size_of::<esp_phy_calibration_data_t>()]) {
394 let _ = esp_phy::set_phy_calibration_data(data);
397}
398
399#[instability::unstable]
404pub fn last_calibration_result() -> Option<CalibrationResult> {
405 esp_phy::last_calibration_result()
406}