This is the 32nd changelog for Knurling-rs, our push to sustainably build better tooling for developing and debugging Rust software for embedded systems. Knurling-rs includes a suite of tools that make it easier to develop, log, debug, and test your embedded Rust libraries and applications!
Knurling-rs is supported by our sponsors on GitHub. If you're interested in seeing more projects like this, consider becoming a sponsor today!
Highlights 🎉
New env_logger
-like filter
We are busy preparing the upcoming 0.3
release, one of the exciting new features is the env_logger
-like filter to disable / enable logging in crates (see PR #519).
Before this release the use of logging levels for the log statements (e.g. defmt::info
, defmt::warn
, ..) was set up by cargo features. The new log filter removes these Cargo features and replaces them with the environment variable DEFMT_LOG
completely. Therefore the previous Cargo features are not the mechanism to specify log filters anymore.
The new DEFMT_LOG
env var specifies which crates emit the defmt logs at which level. Its syntax is based on env_logger
's RUST_LOG
environment variable.
One of the advantages compared to the Cargo features configuration is the new logger mechanism supports filtering with module level granularity.
Note this is a target side emit filter and orthogonal to the host side display filter proposed in this probe-run PR #74.
Disabling logs with this target filter will omit logs from the target program, therefore the resulting binary is smaller (and possibly slightly faster). It reduces the amount of data sent from the target to the host. The proposed host side display filter on the other hand will filter logs after they are sent from the target to the host. The env_logger
-like log filter is kind of a pre-process step, while the host side log filter acts as a post-process step.
Note when the DEFMT_LOG
env var changes all crates that transitively depend on the defmt_macros
crate will be re-compiled. The log filter is a compile-time mechanism.
Given the following code in src/bin/hello.rs
.
#![no_main]
#![no_std]
use test_logger as _;
#[cortex_m_rt::entry]
fn main() -> ! {
defmt::info!("hello");
foo::foo();
bar::bar();
test_logger::exit()
}
mod foo {
pub fn foo() {
defmt::trace!("foo");
}
}
mod bar {
pub fn bar() {
defmt::info!("bar");
}
}
running the program with
$ DEFMT_LOG=trace cargo rb hello
outputs the following lines:
(HOST) INFO flashing program (6.71 KiB)
(HOST) INFO success!
────────────────────────────────────────────────────────────────────────────────
0 INFO hello
└─ hello::__cortex_m_rt_main @ src/bin/hello.rs:8
1 TRACE foo
└─ hello::foo::foo @ src/bin/hello.rs:16
2 INFO bar
└─ hello::bar::bar @ src/bin/hello.rs:22
────────────────────────────────────────────────────────────────────────────────
(HOST) INFO device halted without error
Let's see a few examples using different values for DEFMT_LOG
.
# filter module 'foo'
$ DEFMT_LOG=hello::foo cargo r --bin hello
0 TRACE foo
└─ hello::foo::foo @ src/bin/hello.rs:16
$ DEFMT_LOG=hello::bar cargo r --bin hello
0 INFO bar
└─ hello::bar::bar @ src/bin/hello.rs:22
$ DEFMT_LOG=hello::foo,hello::bar cargo r --bin hello
0 TRACE foo
└─ hello::foo::foo @ src/bin/hello.rs:16
1 INFO bar
└─ hello::bar::bar @ src/bin/hello.rs:22
$ DEFMT_LOG=hello cargo r --bin hello
0 INFO hello
└─ hello::__cortex_m_rt_main @ src/bin/hello.rs:8
1 TRACE foo
└─ hello::foo::foo @ src/bin/hello.rs:16
2 INFO bar
└─ hello::bar::bar @ src/bin/hello.rs:22
The DEFMT_LOG
env var also accepts the logging levels: error
, warn
, info
, debug
, trace
. To disable logging for a module or globally, pass the off
value.
$ DEFMT_LOG=info cargo r --bin hello
0 INFO hello
└─ hello::__cortex_m_rt_main @ src/bin/hello.rs:8
1 INFO bar
└─ hello::bar::bar @ src/bin/hello.rs:22
$ DEFMT_LOG=off cargo r --bin hello
<empty>
Follow the instructions given in pull request #519 if you want to test the new log mechanism.
New defmt::println!
macro
In this release the defmt::println
macro is introduced in PR #569 which is the equivalent to std::println
. It works in the same fashion as the logging macros in that its content is serialized, but it's not associated to any log level. A defmt::println
statement will always serialize the data & display the content to stdout
on the host system.
Log statements using the error
, warn
, info
, debug
, trace
macros can be filtered out using the new DEFMT_LOG
env var.
Using defmt::println
in the defmt-test
crate now displays the output of the test results regardless of any set log level.
Before this change the test suite required a log level to be specified in order to print results, that may have interferred with log statements in the test code itself. With the change the test results are always displayed irrespective of any log level. This brings the behaviour of defmt-test
closer to the #[test]
macro of "standard" Rust.
Implement Format
for arrays of any length
The last highlight in this release (in PR #589) is that the default Format
implementation now supports arrays of any length by using const generics. Before this release the default Format
implementations were defined for a number of fixed sized arrays. Alternatively the user had to provide their own format string in order to display arrays.
To illustrate this the following code example shows what worked before.
// works, implementation for arrays with length 32 exists
defmt::info!("[u8; 32]: {}", [1; 32]);
// fails to compile, no implementation with array length 33
defmt::info!("[u8; 33]: {}", [2; 33]);
// given format string matches the given argument
defmt::info!("[u8; 33]: {=[?;33]}", [3; 33]);
With the update in #589 there is no need to specify a format string, the default version will automatically determine the right size from the argument.
All defmt::info!
statements in the example code above work now.
Improvements 🦀
defmt
- #519 Add target-side
env_logger
-line env filter - #598 Recover from decoding errors in
defmt-print
- #569 Add
defmt::println!
macro - #594 Use UDF instruction on nested panics
- #589 Implement
Format
for arrays of any length - #584 Remove outdated doc "you may only call
write!
once". Thanks to Dirbaio!
probe-run
- #266 Recover from decoding-errors
- #247 Print trouble shooting information on "probe not found" error
- #264 Use new Stream Decoder API
flip-link
- #58 Print message when linking normally fails
Internal Improvements 🧽
defmt
- #601 Move
defmt
code into thedefmt/
folder - #600 Run snapshot & backward compatibility tests in dev mode only
- #592 Add backward compatibility test to xtask
- #580 Re-structure
Truncate
implementations using macro - #591 Remove timestamps from snapshot tests
- #585 Add xtask option to run single snapshot test
- #587 Tweak inline attributes to remove machine code duplication
- #574 Refactor
defmt-rtt
(1/2)
probe-run
- #267 Minimize dependencies by disabling default-features
Fixes 🔨
Sponsor this work
Knurling-rs is mainly funded through GitHub sponsors. Sponsors get early access to the tools we are building and help us to support and grow the knurling tools and courses. Thank you to all of the people already sponsoring our work through the Knurling project!