-
Notifications
You must be signed in to change notification settings - Fork 254
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add the
esp-println
package to the repository (#1575)
* Add the `esp-println` package to the repository * Update esp-println version in README.md Co-authored-by: Sergio Gasquez Arcos <sergio.gasquez@gmail.com> --------- Co-authored-by: Scott Mabin <scott@mabez.dev> Co-authored-by: Sergio Gasquez Arcos <sergio.gasquez@gmail.com>
- Loading branch information
1 parent
5facb75
commit cc28c3e
Showing
8 changed files
with
745 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
[package] | ||
name = "esp-println" | ||
version = "0.9.1" | ||
edition = "2021" | ||
description = "Provides `print!` and `println!` implementations various Espressif devices" | ||
repository = "https://github.com/esp-rs/esp-hal" | ||
license = "MIT OR Apache-2.0" | ||
|
||
[package.metadata.docs.rs] | ||
cargo-args = ["-Z", "build-std=core"] | ||
default-target = "riscv32imc-unknown-none-elf" | ||
features = ["esp32c3"] | ||
|
||
[dependencies] | ||
critical-section = { version = "1.1.2", optional = true } | ||
defmt = { version = "0.3.7", optional = true } | ||
log = { version = "0.4.21", optional = true } | ||
portable-atomic = { version = "1.6.0", optional = true, default-features = false } | ||
|
||
[build-dependencies] | ||
esp-build = { version = "0.1.0", path = "../esp-build" } | ||
|
||
[features] | ||
default = ["dep:critical-section", "colors", "uart"] | ||
log = ["dep:log"] | ||
|
||
# You must enable exactly 1 of the below features to support the correct chip: | ||
esp32 = [] | ||
esp32c2 = [] | ||
esp32c3 = [] | ||
esp32c6 = [] | ||
esp32h2 = [] | ||
esp32p4 = [] | ||
esp32s2 = [] | ||
esp32s3 = [] | ||
|
||
# You must enable exactly 1 of the below features to enable to intended | ||
# communication method (note that "uart" is enabled by default): | ||
jtag-serial = ["dep:portable-atomic"] # C3, C6, H2, P4, and S3 only! | ||
no-op = [] | ||
uart = [] | ||
|
||
# Enables a `defmt` backend usable with espflash. We force rzcobs encoding to simplify implementation | ||
defmt-espflash = ["dep:defmt", "defmt?/encoding-rzcobs"] | ||
|
||
# logging sub-features | ||
colors = [] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
# esp-println | ||
|
||
A library that provides `print!`, `println!`, `dbg!` implementations and | ||
logging capabilities for Espressif devices. | ||
|
||
- Supports all Espressif ESP32 family devices. | ||
- Supports different communication methods: | ||
- UART (Default) | ||
- JTAG-Serial (Only available in ESP32-C3, ESP32-C6, ESP32-H2, ESP32-S3) | ||
- No-op: Turns printing into a no-op | ||
- Supports [`defmt`] backend | ||
|
||
# Usage | ||
|
||
```toml | ||
esp-println = { version = "0.9.1", features = ["esp32c2"] } | ||
``` | ||
|
||
or `cargo add esp-println --features esp32c2` | ||
It's important to specify your target device as feature. | ||
|
||
Then in your program: | ||
|
||
```rust | ||
use esp_println::println; | ||
``` | ||
|
||
You can now `println!("Hello world")` as usual. | ||
|
||
# Features | ||
|
||
- There is one feature for each supported target: `esp32`, `esp32c2`, | ||
`esp32c3`, `esp32c6`, `esp32h2`, `esp32s2`, and `esp32s3`. | ||
- One of these features must be enabled. | ||
- Only one of these features can be enabled at a time. | ||
- There is one feature for each supported communication method: `uart`, `jtag-serial` and `no-op`. | ||
- Only one of these features can be enabled at a time. | ||
- `log`: Enables logging using [`log` crate]. | ||
- `colors` enable colored logging. | ||
- Only effective when using the `log` feature. | ||
- `critical-section` enables critical sections. | ||
- `defmt-espflash`: This is intended to be used with [`espflash`], see `-L/--log-format` argument | ||
of `flash` or `monitor` subcommands of `espflash` and `cargo-espflash`. Uses [rzCOBS] encoding | ||
and adds framing. | ||
|
||
## Default Features | ||
|
||
By default, we use the `uart`, `critial-section` and `colors` features. | ||
Which means that it will print to the UART, use critical sections and output | ||
messages will be colored. | ||
If we want to use a communication method that is not `uart`, the default | ||
one, we need to [disable the default features]. | ||
|
||
## Logging | ||
|
||
With the feature `log` activated you can initialize a simple logger like this | ||
|
||
```rust | ||
init_logger(log::LevelFilter::Info); | ||
``` | ||
|
||
There is a default feature `colors` which enables colored log output. | ||
|
||
Additionally, you can use | ||
|
||
```rust | ||
init_logger_from_env(); | ||
``` | ||
|
||
In this case the following environment variables are used: | ||
|
||
- `ESP_LOGLEVEL` sets the log level, use values like `trace`, `info` etc. | ||
- `ESP_LOGTARGETS` if set you should provide the crate names of crates (optionally with a path e.g. `esp_wifi::compat::common`) which should get logged, separated by `,` and no additional whitespace between | ||
|
||
If this simple logger implementation isn't sufficient for your needs, you can implement your own logger on top of `esp-println`. See [Implementing a Logger section log documentaion] | ||
|
||
## `defmt` | ||
|
||
Using the `defmt-espflash` feature, `esp-println` will install a `defmt` global logger. The logger will | ||
output to the same data stream as `println!()`, and adds framing bytes so it can be used even with | ||
other, non-`defmt` output. Using the `defmt-espflash` feature automatically uses the [rzCOBS] encoding and does | ||
not allow changing the encoding. | ||
|
||
Follow the [`defmt` book's setup instructions] on how to | ||
set up `defmt`. Remember, the global logger is already installed for you by `esp-println`! | ||
|
||
Please note that `defmt` does _not_ provide MSRV guarantees with releases, and as such we are not able to make any MSRV guarantees when this feature is enabled. For more information refer to the MSRV section of `defmt`'s README: | ||
https://github.com/knurling-rs/defmt?tab=readme-ov-file#msrv | ||
|
||
[`defmt`]: https://github.com/knurling-rs/defmt | ||
[`log` crate]: https://github.com/rust-lang/log | ||
[rzCOBS]: https://github.com/Dirbaio/rzcobs | ||
[`espflash`]: https://github.com/esp-rs/espflash | ||
[disable the default features]: https://doc.rust-lang.org/cargo/reference/features.html#the-default-feature | ||
[Implementing a Logger section log documentaion]: https://docs.rs/log/0.4.17/log/#implementing-a-logger | ||
[`defmt` book's setup instructions]: https://defmt.ferrous-systems.com/setup | ||
|
||
# Troubleshooting linker errors | ||
|
||
If you experience linker errors, make sure you have _some_ reference to `esp_println` in your code. | ||
If you don't use `esp_println` directly, you'll need to add e.g. `use esp_println as _;` to your | ||
import statements. This ensures that the global logger will not be removed by the compiler. | ||
|
||
# License | ||
|
||
Licensed under either of: | ||
|
||
- Apache License, Version 2.0 ([LICENSE-APACHE](../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) | ||
- MIT license ([LICENSE-MIT](../LICENSE-MIT) or http://opensource.org/licenses/MIT) | ||
|
||
at your option. | ||
|
||
# Contribution | ||
|
||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in | ||
the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without | ||
any additional terms or conditions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
use esp_build::assert_unique_used_features; | ||
|
||
fn main() { | ||
// Ensure that only a single chip is specified | ||
assert_unique_used_features!( | ||
"esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32p4", "esp32s2", "esp32s3" | ||
); | ||
|
||
// Ensure that only a single communication method is specified | ||
assert_unique_used_features!("jtag-serial", "uart"); | ||
|
||
// Ensure that, if the `jtag-serial` communication method feature is enabled, | ||
// either the `esp32c3`, `esp32c6`, `esp32h2`, or `esp32s3` chip feature is | ||
// enabled. | ||
if cfg!(feature = "jtag-serial") | ||
&& !(cfg!(feature = "esp32c3") | ||
|| cfg!(feature = "esp32c6") | ||
|| cfg!(feature = "esp32h2") | ||
|| cfg!(feature = "esp32p4") | ||
|| cfg!(feature = "esp32s3")) | ||
{ | ||
panic!( | ||
"The `jtag-serial` feature is only supported by the ESP32-C3, ESP32-C6, ESP32-H2, ESP32-P4, and ESP32-S3" | ||
); | ||
} | ||
|
||
// Ensure that, if the `colors` is used with `log`.` | ||
if cfg!(feature = "colors") && !cfg!(feature = "log") { | ||
println!( | ||
"cargo:warning=The `colors` feature is only effective when using the `log` feature" | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
//! defmt global logger implementation. | ||
// Implementation taken from defmt-rtt, with a custom framing prefix | ||
|
||
#[cfg(feature = "critical-section")] | ||
use critical_section::RestoreState; | ||
|
||
use super::Printer; | ||
|
||
/// Global logger lock. | ||
#[cfg(feature = "critical-section")] | ||
static mut TAKEN: bool = false; | ||
#[cfg(feature = "critical-section")] | ||
static mut CS_RESTORE: RestoreState = RestoreState::invalid(); | ||
static mut ENCODER: defmt::Encoder = defmt::Encoder::new(); | ||
|
||
#[defmt::global_logger] | ||
pub struct Logger; | ||
unsafe impl defmt::Logger for Logger { | ||
fn acquire() { | ||
#[cfg(feature = "critical-section")] | ||
unsafe { | ||
// safety: Must be paired with corresponding call to release(), see below | ||
let restore = critical_section::acquire(); | ||
|
||
// safety: accessing the `static mut` is OK because we have acquired a critical | ||
// section. | ||
if TAKEN { | ||
panic!("defmt logger taken reentrantly") | ||
} | ||
|
||
// safety: accessing the `static mut` is OK because we have acquired a critical | ||
// section. | ||
TAKEN = true; | ||
|
||
// safety: accessing the `static mut` is OK because we have acquired a critical | ||
// section. | ||
CS_RESTORE = restore; | ||
} | ||
|
||
// If not disabled, write a non-UTF8 sequence to indicate the start of a defmt | ||
// frame. We need this to distinguish defmt frames from other data that | ||
// might be written to the printer. | ||
do_write(&[0xFF, 0x00]); | ||
|
||
// safety: accessing the `static mut` is OK because we have acquired a critical | ||
// section. | ||
unsafe { ENCODER.start_frame(do_write) } | ||
} | ||
|
||
unsafe fn release() { | ||
// safety: accessing the `static mut` is OK because we have acquired a critical | ||
// section. | ||
ENCODER.end_frame(do_write); | ||
|
||
Printer.flush(); | ||
|
||
#[cfg(feature = "critical-section")] | ||
{ | ||
// We don't need to write a custom end-of-frame sequence because: | ||
// - using `defmt`, the rzcobs encoding already includes a terminating zero | ||
// - using `defmt-raw`, we don't add any additional framing data | ||
|
||
// safety: accessing the `static mut` is OK because we have acquired a critical | ||
// section. | ||
TAKEN = false; | ||
|
||
// safety: accessing the `static mut` is OK because we have acquired a critical | ||
// section. | ||
let restore = CS_RESTORE; | ||
|
||
// safety: Must be paired with corresponding call to acquire(), see above | ||
critical_section::release(restore); | ||
} | ||
} | ||
|
||
unsafe fn flush() { | ||
Printer.flush(); | ||
} | ||
|
||
unsafe fn write(bytes: &[u8]) { | ||
// safety: accessing the `static mut` is OK because we have acquired a critical | ||
// section. | ||
ENCODER.write(bytes, do_write); | ||
} | ||
} | ||
|
||
fn do_write(bytes: &[u8]) { | ||
Printer.write_bytes_assume_cs(bytes) | ||
} |
Oops, something went wrong.