This repo provides a crate with a Rust Logger implementation for use on an embedded device with Zephyr RTOS. bindgen
and cbindgen
are used to bind Rust calls to Zephyr RTOS's log2 implementation. Since this crate is targetting NRF52 and NRF53 deployments, it is no_std
and does not allocate.
Include this crate in another crate that needs a logger implementation and make the usual log macro calls like log::trace!("2.0 * 2.0 = {}", 2. * 2.);
. With a high initialization priority, the global logger is initialized to call the matching LOGDBG, LOGINF, LOGWRN, or LOGERR macro in the bridging C.
In order to build there are several tools to install
thumbv7em-none-eabihf
thumbv8m.main-none-eabihf
cargo install cargo-make,cbindgen
brew install llvm
llvm-config
needs to be in your PATH
echo 'export PATH="/opt/homebrew/opt/llvm/bin:$PATH"' >> ~/.zshrc
sudo xcode-select --install
If you have all of that, then cargo make test
should work.
In the example, we have a blinky
application compiled for NRF52 or NRF53. The CMakeLists.txt of the sample project adds library that needs a logger, but is built as a static library for the main.c of Zephyr RTOS. The example project includes logz as a crate dependency and adds a lib/logz submodule. The submodule holds the C headers and src file to include in the example CMakeLists.txt.
The full example is here: https://github.com/trueb2/logz-example-rs
In the example CMakeLists.txt, we build the project with a static library and the bridge.c of logz ```cmake cmakeminimumrequired(VERSION 3.20.0) findpackage(Zephyr REQUIRED HINTS $ENV{ZEPHYRBASE}) project(blinky)
set(LOGZEXAMPLELIBSRCDIR ${CMAKECURRENTSOURCEDIR}/lib/logz-example-rs) set(LOGZLIBSRCDIR ${LOGZEXAMPLELIBSRCDIR}/lib/logz)
set(LOGZEXAMPLELIBDIR ${LOGZEXAMPLELIBSRCDIR}/target/thumbv8m.main-none-eabihf/release) includedirectories(AFTER ${LOGZEXAMPLELIBSRCDIR}/include ${LOGZEXAMPLELIBSRCDIR}/include/generated ${LOGZLIBSRCDIR}/include/generated) addlibrary(liblogzexamplers STATIC IMPORTED GLOBAL) settargetproperties(liblogzexamplers PROPERTIES IMPORTEDLOCATION ${LOGZEXAMPLELIBDIR}/liblogzexamplers.a)
addcustomtarget( liblogzexamplerstarget ALL BYPRODUCTS ${LOGZEXAMPLELIBDIR}/liblogzexamplers.a WORKINGDIRECTORY ${LOGZEXAMPLELIBSRCDIR} COMMAND cargo make build ) adddependencies(app liblogzexamplers_target)
targetlinklibraries(app PRIVATE ${LOGZEXAMPLELIBDIR}/liblogzexample_rs.a -Wl,--allow-multiple-definition)
targetsources(app PRIVATE src/main.c ${LOGZLIBSRCDIR}/src/bridge.c) ```
This makes sure that the log macro calls will be piped to an initialized Logger instance that writes its logs to the Zephyr LOG2 implementation as a string formatted in Rust
In Zephyr, we call a Rust library function, example_foo()
C
void flip_timer(struct k_timer* timer) {
LOG_INF("LED: %d", (int) on);
gpio_pin_set(led_dev, PIN, (int)on);
on = !on;
example_foo();
}
In Rust, we format the logs and invoke the LOG2 macros ```rust
pub extern "C" fn examplefoo() {
log::trace!("Foo");
log::debug!("Bar");
log::info!("Fizz");
log::warn!("Buzz");
log::error!("Fizzle");
}
C
void loginf(const char *restrict msg)
{
LOG_INF("%s", msg);
}
```
In the UART, RTT, or whatever you have configured in your Kconfig, we get normal logs.
[00:04:32.166,320] <inf> rs: logz_example_rs: Fizz
[00:04:32.166,351] <wrn> rs: logz_example_rs: Buzz
[00:04:32.166,381] <err> rs: logz_example_rs: Fizzle
[00:04:32.416,198] <inf> blinky: LED: 0
[00:04:32.416,259] <inf> rs: logz_example_rs: Foo
[00:04:32.416,290] <inf> rs: logz_example_rs: Bar
[00:04:32.416,320] <inf> rs: logz_example_rs: Fizz
[00:04:32.416,351] <wrn> rs: logz_example_rs: Buzz
[00:04:32.416,412] <err> rs: logz_example_rs: Fizzle
[00:04:32.666,198] <inf> blinky: LED: 1
[00:04:32.666,259] <inf> rs: logz_example_rs: Foo
[00:04:32.666,290] <inf> rs: logz_example_rs: Bar
[00:04:32.666,351] <inf> rs: logz_example_rs: Fizz
[00:04:32.666,381] <wrn> rs: logz_example_rs: Buzz
[00:04:32.666,412] <err> rs: logz_example_rs: Fizzle
[00:04:32.916,229] <inf> blinky: LED: 0
[00:04:32.916,290] <inf> rs: logz_example_rs: Foo
[00:04:32.916,320] <inf> rs: logz_example_rs: Bar
[00:04:32.916,351] <inf> rs: logz_example_rs: Fizz
[00:04:32.916,381] <wrn> rs: logz_example_rs: Buzz
[00:04:32.916,442] <err> rs: logz_example_rs: Fizzle