Skip to content

Commit

Permalink
Simplify initialization APIs (#1957)
Browse files Browse the repository at this point in the history
* Accept more types in embassy::init

* Apply the same treatment to esp-wifi

* Changelog

* Clean up

* Add doc examples

* Fix Alarm generic parameters
  • Loading branch information
bugadani authored Aug 16, 2024
1 parent 6e706c5 commit f95ab0d
Show file tree
Hide file tree
Showing 47 changed files with 331 additions and 452 deletions.
1 change: 1 addition & 0 deletions esp-hal-embassy/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Updated to latest release (`0.6.0`) for `embassy-executor` (#1942)
- Changed `init` to accept timers of multiple types (#1957)

### Fixed

Expand Down
1 change: 1 addition & 0 deletions esp-hal-embassy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ esp-hal = { version = "0.19.0", path = "../esp-hal" }
log = { version = "0.4.22", optional = true }
macros = { version = "0.12.0", features = ["embassy"], package = "esp-hal-procmacros", path = "../esp-hal-procmacros" }
portable-atomic = "1.6.0"
static_cell = "2.1.0"

[build-dependencies]
cfg-if = "1.0.0"
Expand Down
106 changes: 102 additions & 4 deletions esp-hal-embassy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@
// MUST be the first module
mod fmt;

use esp_hal::clock::Clocks;
#[cfg(not(feature = "esp32"))]
use esp_hal::timer::systimer::Alarm;
use esp_hal::{
clock::Clocks,
timer::{timg::Timer as TimgTimer, ErasedTimer},
};
pub use macros::main;

#[cfg(feature = "executors")]
Expand All @@ -47,7 +52,100 @@ use self::time_driver::{EmbassyTimer, Timer};
mod executor;
mod time_driver;

/// Initialize embassy
pub fn init(clocks: &Clocks, time_driver: &'static mut [Timer]) {
EmbassyTimer::init(clocks, time_driver)
macro_rules! mk_static {
($t:ty,$val:expr) => {{
static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
#[deny(unused_attributes)]
let x = STATIC_CELL.uninit().write(($val));
x
}};
}

/// A trait to allow better UX for initializing the timers.
///
/// This trait is meant to be used only for the `init` function.
/// Calling `timers()` multiple times may panic.
pub trait TimerCollection {
/// Returns the timers as a slice.
fn timers(self) -> &'static mut [Timer];
}

/// Helper trait to reduce boilerplate.
///
/// We can't blanket-implement for `Into<ErasedTimer>` because of possible
/// conflicting implementations.
trait IntoErasedTimer: Into<ErasedTimer> {}

impl IntoErasedTimer for ErasedTimer {}

impl<T, DM> IntoErasedTimer for TimgTimer<T, DM>
where
DM: esp_hal::Mode,
Self: Into<ErasedTimer>,
{
}

#[cfg(not(feature = "esp32"))]
impl<T, DM, COMP, UNIT> IntoErasedTimer for Alarm<'_, T, DM, COMP, UNIT>
where
DM: esp_hal::Mode,
Self: Into<ErasedTimer>,
{
}

impl<T> TimerCollection for T
where
T: IntoErasedTimer,
{
fn timers(self) -> &'static mut [Timer] {
Timer::new(self.into()).timers()
}
}

impl TimerCollection for Timer {
fn timers(self) -> &'static mut [Timer] {
let timers = mk_static!([Timer; 1], [self]);
timers.timers()
}
}

impl TimerCollection for &'static mut [Timer] {
fn timers(self) -> &'static mut [Timer] {
self
}
}

impl<const N: usize> TimerCollection for &'static mut [Timer; N] {
fn timers(self) -> &'static mut [Timer] {
self.as_mut()
}
}

/// Initialize embassy.
///
/// Call this as soon as possible, before the first timer-related operation.
///
/// The time driver can be one of a number of different options:
///
/// - A timg `Timer` instance
/// - A systimer `Alarm` instance
/// - An `ErasedTimer` instance
/// - A `OneShotTimer` instance
/// - A mutable static slice of `OneShotTimer` instances
/// - A mutable static array of `OneShotTimer` instances
///
/// # Examples
///
/// ```rust, no_run
#[doc = esp_hal::before_snippet!()]
/// use esp_hal::timg::TimerGroup;
///
/// let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
/// esp_hal_embassy::init(&clocks, timg0.timer0);
///
/// // ... now you can spawn embassy tasks or use `Timer::after` etc.
/// # }
/// ```
pub fn init(clocks: &Clocks, time_driver: impl TimerCollection) {
EmbassyTimer::init(clocks, time_driver.timers())
}
10 changes: 8 additions & 2 deletions esp-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,10 @@ unsafe extern "C" fn stack_chk_fail() {
#[macro_export]
macro_rules! before_snippet {
() => {
core::include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/doc-helper/before"))
core::include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../esp-hal/doc-helper/before"
))
};
}

Expand All @@ -690,6 +693,9 @@ macro_rules! before_snippet {
#[macro_export]
macro_rules! before_snippet {
() => {
core::include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "\\doc-helper\\before"))
core::include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"\\..\\esp-hal\\doc-helper\\before"
))
};
}
2 changes: 1 addition & 1 deletion esp-hal/src/timer/timg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,7 +369,7 @@ where
}
}

/// Block until the timer has elasped.
/// Block until the timer has elapsed.
pub fn wait(&mut self) {
while !self.has_elapsed() {}
}
Expand Down
2 changes: 2 additions & 0 deletions esp-wifi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Changed `init` to accept timers of multiple types (#1957)

### Fixed

- Increased NPL event queue size to prevent overflow (#1891)
Expand Down
5 changes: 3 additions & 2 deletions esp-wifi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ atomic-waker = { version = "1.1.2", default-features = false, features = [
] }

[build-dependencies]
toml-cfg = "0.2.0"
esp-build = { version = "0.1.0", path = "../esp-build" }
toml-cfg = "0.2.0"
esp-build = { version = "0.1.0", path = "../esp-build" }
esp-metadata = { version = "0.2.0", path = "../esp-metadata" }

[features]
default = ["log"]
Expand Down
2 changes: 1 addition & 1 deletion esp-wifi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Minimum supported Rust compiler version: 1.72.0.0

### Importing

Ensure that the right features are enabled for your chip. See [Examples] for more examples.
Ensure that the right features are enabled for your chip. See [Examples](https://github.com/esp-rs/esp-hal/tree/main/examples#examples) for more examples.

```toml
[dependencies.esp-wifi]
Expand Down
70 changes: 39 additions & 31 deletions esp-wifi/build.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,41 @@
use std::{error::Error, str::FromStr};

use esp_build::assert_unique_used_features;
use esp_metadata::{Chip, Config};

fn main() -> Result<(), String> {
fn main() -> Result<(), Box<dyn Error>> {
// Ensure that only a single chip is specified:
assert_unique_used_features!(
"esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32s2", "esp32s3"
);

// NOTE: update when adding new device support!
// Determine the name of the configured device:
let device_name = if cfg!(feature = "esp32") {
"esp32"
} else if cfg!(feature = "esp32c2") {
"esp32c2"
} else if cfg!(feature = "esp32c3") {
"esp32c3"
} else if cfg!(feature = "esp32c6") {
"esp32c6"
} else if cfg!(feature = "esp32h2") {
"esp32h2"
} else if cfg!(feature = "esp32s2") {
"esp32s2"
} else if cfg!(feature = "esp32s3") {
"esp32s3"
} else {
unreachable!() // We've confirmed exactly one known device was selected
};

// Load the configuration file for the configured device:
let chip = Chip::from_str(device_name)?;
let config = Config::for_chip(&chip);

// Define all necessary configuration symbols for the configured device:
config.define_symbols();

#[cfg(all(feature = "ble", feature = "esp32s2"))]
{
panic!(
Expand Down Expand Up @@ -38,39 +68,17 @@ fn main() -> Result<(), String> {
"#
);
}
match std::env::var("OPT_LEVEL") {
Ok(level) => {
if level != "2" && level != "3" {
let message = format!(
"esp-wifi should be built with optimization level 2 or 3 - yours is {level}.
See https://github.com/esp-rs/esp-wifi",
);
print_warning(message);
}
if let Ok(level) = std::env::var("OPT_LEVEL") {
if level != "2" && level != "3" {
let message = format!(
"esp-wifi should be built with optimization level 2 or 3 - yours is {level}.
See https://github.com/esp-rs/esp-wifi",
);
print_warning(message);
}
Err(_err) => (),
}

#[cfg(feature = "esp32")]
println!("cargo:rustc-cfg=esp32");

#[cfg(feature = "esp32c2")]
println!("cargo:rustc-cfg=esp32c2");

#[cfg(feature = "esp32c3")]
println!("cargo:rustc-cfg=esp32c3");

#[cfg(feature = "esp32c6")]
println!("cargo:rustc-cfg=esp32c6");

#[cfg(feature = "esp32h2")]
println!("cargo:rustc-cfg=esp32h2");

#[cfg(feature = "esp32s2")]
println!("cargo:rustc-cfg=esp32s2");

#[cfg(feature = "esp32s3")]
println!("cargo:rustc-cfg=esp32s3");
println!("cargo:rustc-cfg={}", device_name);

#[cfg(feature = "coex")]
{
Expand Down
Loading

0 comments on commit f95ab0d

Please sign in to comment.