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