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(
24 feature = "ieee802154",
25 doc = "<div class=\"warning\"><b>Hint:</b> The scheduler is not required for IEEE 802.15.4.</div>"
26)]
27#![doc = esp_hal::before_snippet!()]
36#![cfg_attr(
49 wifi_driver_supported,
50 doc = r#"
51
52if let Ok(controller) = esp_radio::wifi::WifiController::new(
53 peripherals.WIFI,
54 Default::default(),
55) {}
56"#
57)]
58#![cfg_attr(
59 all(bt_driver_supported, not(wifi_driver_supported)),
60 doc = r#"
61
62# use esp_radio::ble::controller::BleConnector;
63if let Ok(controller) = BleConnector::new(peripherals.BT, Default::default()) {}
64"#
65)]
66#![doc = esp_hal::after_snippet!()]
67#![doc = concat!(r#"features = [""#, chip!(), r#"", "wifi", "esp-now", "esp-alloc"]"#)]
72#![doc = concat!(r#"features = [""#, chip!(), r#"", "esp-radio", "esp-alloc"]"#)]
74#![doc = concat!(r#"features = [""#, chip!(), r#""]"#)]
76#![cfg_attr(
121 multi_core,
122 doc = concat!(
123 "## Running on the second core",
124 "\n\n",
125 "BLE and Wi-Fi can also be run on the second core.",
126 "\n\n",
127 "`esp_radio::init` is recommended to be called on the first core. The tasks ",
128 "created by `esp-radio` are pinned to the first core.",
129 "\n\n",
130 "It's also important to allocate adequate stack for the second core; in many ",
131 "cases 8kB is not enough, and 16kB or more may be required depending on your ",
132 "use case. Failing to allocate adequate stack may result in strange behaviour, ",
133 "such as your application silently failing at some point during execution."
134 )
135)]
136#![doc = document_features::document_features!(feature_label = r#"<span class="stab portability"><code>{feature}</code></span>"#)]
146#![doc = ""]
153#![doc = include_str!(concat!(env!("OUT_DIR"), "/esp_radio_config_table.md"))]
154#![doc(html_logo_url = "https://docs.espressif.com/projects/rust/esp-rs-grey-bg.svg")]
155#![no_std]
156#![deny(missing_docs, rust_2018_idioms, rustdoc::all)]
157#![cfg_attr(
158 not(any(feature = "wifi", feature = "ble")),
159 allow(
160 unused,
161 reason = "There are a number of places where code is needed for either wifi or ble,
162 and cfg-ing them out would make the code less readable just to avoid warnings in the
163 less common case. Truly unused code will be flagged by the check that enables either
164 ble or wifi."
165 )
166)]
167#![cfg_attr(docsrs, feature(doc_cfg, custom_inner_attributes, proc_macro_hygiene))]
168
169#[macro_use]
170extern crate esp_metadata_generated;
171
172extern crate alloc;
173
174mod coex_utils;
176mod fmt;
177pub(crate) mod reg_access;
178
179use core::marker::PhantomData;
180
181use esp_hal as hal;
182#[instability::unstable]
183pub use esp_phy::CalibrationResult;
184use esp_radio_rtos_driver as preempt;
185#[cfg(feature = "wifi")]
186use hal::{after_snippet, before_snippet};
187use sys::include::esp_phy_calibration_data_t;
188pub(crate) mod sys {
189 #[cfg(esp32)]
190 pub use esp_wifi_sys_esp32::*;
191 #[cfg(esp32c2)]
192 pub use esp_wifi_sys_esp32c2::*;
193 #[cfg(esp32c3)]
194 pub use esp_wifi_sys_esp32c3::*;
195 #[cfg(esp32c5)]
196 pub use esp_wifi_sys_esp32c5::*;
197 #[cfg(esp32c6)]
198 pub use esp_wifi_sys_esp32c6::*;
199 #[cfg(esp32c61)]
200 pub use esp_wifi_sys_esp32c61::*;
201 #[cfg(esp32h2)]
202 pub use esp_wifi_sys_esp32h2::*;
203 #[cfg(esp32s2)]
204 pub use esp_wifi_sys_esp32s2::*;
205 #[cfg(esp32s3)]
206 pub use esp_wifi_sys_esp32s3::*;
207 #[cfg(esp32s31)]
208 pub use esp_wifi_sys_esp32s31::*;
209}
210
211use crate::refcount::Refcount;
212#[cfg(feature = "wifi")]
213use crate::wifi::WifiError;
214
215#[doc(hidden)]
217macro_rules! unstable_module {
218 ($(
219 $(#[$meta:meta])*
220 pub mod $module:ident;
221 )*) => {
222 $(
223 $(#[$meta])*
224 #[cfg(feature = "unstable")]
225 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
226 pub mod $module;
227
228 $(#[$meta])*
229 #[cfg(not(feature = "unstable"))]
230 #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))]
231 #[allow(unused)]
232 pub(crate) mod $module;
233 )*
234 };
235}
236
237mod asynch;
238mod compat;
239#[cfg(esp32s31)]
240mod compiler_rt_abi;
241mod interrupt_dispatch;
242mod radio_clocks;
243mod refcount;
244mod time;
245
246#[cfg(feature = "wifi")]
247pub mod wifi;
248
249unstable_module! {
250 #[cfg(feature = "esp-now")]
251 #[cfg_attr(docsrs, doc(cfg(feature = "esp-now")))]
252 pub mod esp_now;
253 #[cfg(feature = "ble")]
254 #[cfg_attr(docsrs, doc(cfg(feature = "ble")))]
255 pub mod ble;
256 #[cfg(feature = "ieee802154")]
257 #[cfg_attr(docsrs, doc(cfg(feature = "ieee802154")))]
258 pub mod ieee802154;
259}
260
261pub(crate) mod common_adapter;
262
263#[cfg(all(feature = "ble", bt_controller = "npl"))]
264pub(crate) static ESP_RADIO_LOCK: esp_sync::RawMutex = esp_sync::RawMutex::new();
265
266#[allow(clippy::assertions_on_constants)] const _: () = {
269 #[cfg(wifi_driver_supported)]
270 {
271 core::assert!(sys::include::CONFIG_ESP_WIFI_STATIC_RX_BUFFER_NUM == 10);
272 core::assert!(sys::include::CONFIG_ESP_WIFI_DYNAMIC_RX_BUFFER_NUM == 32);
273 core::assert!(sys::include::WIFI_STATIC_TX_BUFFER_NUM == 0);
274 core::assert!(sys::include::CONFIG_ESP_WIFI_DYNAMIC_TX_BUFFER_NUM == 32);
275 core::assert!(sys::include::CONFIG_ESP_WIFI_AMPDU_RX_ENABLED == 1);
276 core::assert!(sys::include::CONFIG_ESP_WIFI_AMPDU_TX_ENABLED == 1);
277 core::assert!(sys::include::WIFI_AMSDU_TX_ENABLED == 0);
278 core::assert!(sys::include::CONFIG_ESP32_WIFI_RX_BA_WIN == 6);
279 };
280};
281
282#[procmacros::doc_replace]
283#[cfg_attr(
299 esp32,
300 doc = " - The function may return an error if ADC2 is already in use."
301)]
302pub(crate) fn init() {
305 esp_hal::if_unstable_hal! {
306 #[cfg(esp32)]
307 if hal::analog::adc::try_claim_adc2(unsafe { hal::Internal::conjure() }).is_err() {
308 panic!(
309 "ADC2 is currently in use by esp-hal, but esp-radio requires it for Wi-Fi operation."
310 );
311 }
312 esp_hal::rtc_cntl::WakeLock::acquire();
313 }
314
315 if !preempt::initialized() {
316 panic!("The scheduler must be initialized before initializing the radio.");
317 }
318
319 const MIN_CLOCK: u32 = 80;
321 let cpu_clock = esp_hal::clock::cpu_clock().as_mhz();
322 if cpu_clock < MIN_CLOCK {
323 panic!(
324 "CPU clock {} MHz is too slow for Wi-Fi operation, minimum required is {} MHz",
325 cpu_clock, MIN_CLOCK
326 );
327 }
328
329 radio_clocks::init_radio_clocks();
334
335 crate::common_adapter::enable_wifi_power_domain();
336
337 wifi_set_log_verbose();
338
339 #[cfg(feature = "coex")]
340 match crate::wifi::coex_initialize() {
341 0 => {}
342 error => panic!("Failed to initialize coexistence, error code: {}", error),
343 }
344
345 debug!("Radio initialized");
346}
347
348pub(crate) fn deinit() {
349 #[cfg(feature = "coex")]
351 {
352 unsafe { crate::wifi::os_adapter::coex_disable() };
353 unsafe { crate::wifi::os_adapter::coex_deinit() };
354 }
355
356 #[cfg(feature = "wifi")]
357 wifi::shutdown_wifi_isr();
358 #[cfg(feature = "ble")]
359 ble::shutdown_ble_isr();
360
361 #[cfg(feature = "ble")]
368 crate::radio_clocks::clocks_ll::enable_bt(false);
369 crate::common_adapter::disable_wifi_power_domain();
370 crate::radio_clocks::deinit_radio_clocks();
371
372 #[cfg(esp32c3)]
378 unsafe {
379 crate::sys::include::phy_init_flag()
380 };
381
382 esp_hal::if_unstable_hal! {
383 #[cfg(esp32)]
385 hal::analog::adc::release_adc2(unsafe { esp_hal::Internal::conjure() });
386
387 esp_hal::rtc_cntl::WakeLock::release();
388 }
389
390 debug!("Radio deinitialized");
391}
392
393#[derive(Debug)]
396#[cfg_attr(feature = "defmt", derive(defmt::Format))]
397pub(crate) struct RadioRefGuard {
398 _private: PhantomData<()>,
399}
400
401static RADIO_REFCOUNT: Refcount = Refcount::new();
402
403impl RadioRefGuard {
404 pub(crate) fn new() -> Self {
407 debug!("Creating RadioRefGuard");
408
409 RADIO_REFCOUNT.increment(init);
410 RadioRefGuard {
411 _private: PhantomData,
412 }
413 }
414}
415
416impl Drop for RadioRefGuard {
417 fn drop(&mut self) {
419 debug!("Dropping RadioRefGuard");
420
421 RADIO_REFCOUNT.decrement(deinit);
422 }
423}
424
425#[instability::unstable]
428pub fn wifi_set_log_verbose() {
429 #[cfg(all(feature = "print-logs-from-driver", not(esp32h2)))]
430 unsafe {
431 use crate::sys::include::{
432 esp_wifi_internal_set_log_level,
433 wifi_log_level_t_WIFI_LOG_VERBOSE,
434 };
435
436 esp_wifi_internal_set_log_level(wifi_log_level_t_WIFI_LOG_VERBOSE);
437 }
438}
439
440#[instability::unstable]
447pub fn phy_calibration_data(data: &mut [u8; esp_phy::PHY_CALIBRATION_DATA_LENGTH]) {
448 let _ = esp_phy::backup_phy_calibration_data(data);
449}
450
451#[instability::unstable]
455pub fn set_phy_calibration_data(data: &[u8; core::mem::size_of::<esp_phy_calibration_data_t>()]) {
456 let _ = esp_phy::set_phy_calibration_data(data);
459}
460
461#[instability::unstable]
466pub fn last_calibration_result() -> Option<CalibrationResult> {
467 esp_phy::last_calibration_result()
468}