From 34d65f2fb66cb29474338ffd27b4d3da037cf629 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Thu, 8 Apr 2021 11:27:00 +0200 Subject: [PATCH 01/29] wip --- beginner/apps/Cargo.toml | 19 ++++++++++++++++++- beginner/apps/src/bin/hello.rs | 5 +++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/beginner/apps/Cargo.toml b/beginner/apps/Cargo.toml index 991b60d..f457b4f 100644 --- a/beginner/apps/Cargo.toml +++ b/beginner/apps/Cargo.toml @@ -10,8 +10,10 @@ cortex-m = "0.6.4" cortex-m-rt = "0.6.13" dk = { path = "../../boards/dk", features = ["beginner"] } heapless = "0.5.5" -log = "0.4.8" panic-log = { path = "../../common/panic-log" } +panic-probe = { version = "0.2.0", features = ["print-defmt"] } +defmt = "0.2.0" +defmt-rtt = "0.2.0" # optimize code in both profiles [profile.dev] @@ -31,3 +33,18 @@ incremental = false lto = "fat" opt-level = 3 overflow-checks = false + +[features] +# set logging levels here +default = [ + "defmt-default", + # "dependency-a/defmt-trace", +] + +# do NOT modify these features +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] \ No newline at end of file diff --git a/beginner/apps/src/bin/hello.rs b/beginner/apps/src/bin/hello.rs index 62a8ad0..e1ec04c 100644 --- a/beginner/apps/src/bin/hello.rs +++ b/beginner/apps/src/bin/hello.rs @@ -3,14 +3,15 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // the panicking behavior +use defmt_rtt as _; // global logger +use panic_probe as _; // the panicking behavior #[entry] fn main() -> ! { // initializes the peripherals dk::init().unwrap(); - log::info!("Hello, world!"); // :wave: + defmt::info!("Hello, world!"); // :wave: loop { // breakpoint: halts the program's execution From bebe390f0e66b614ad139b829447885e9131a70a Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Thu, 8 Apr 2021 13:59:01 +0200 Subject: [PATCH 02/29] k: move to defmt --- boards/dk/Cargo.toml | 20 ++++++++++++-- boards/dk/src/lib.rs | 62 ++++++++++---------------------------------- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/boards/dk/Cargo.toml b/boards/dk/Cargo.toml index e844710..4008bce 100644 --- a/boards/dk/Cargo.toml +++ b/boards/dk/Cargo.toml @@ -11,8 +11,24 @@ cortex-m-rt = "0.6.13" embedded-hal = "0.2.3" hal = { package = "nrf52840-hal", version = "0.12.1" } log = "0.4.8" -rtt-target = { version = "0.2.0", features = ["cortex-m"] } +defmt = "0.2.1" +defmt-rtt = "0.2.0" +panic-probe = { version = "0.2.0", features = ["print-defmt" ] } [features] beginner = [] -advanced = [] \ No newline at end of file +advanced = [] + +# defmt logging levels +default = [ + "defmt-debug", + # "dependency-a/defmt-trace", +] + +# do NOT modify these features +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] diff --git a/boards/dk/src/lib.rs b/boards/dk/src/lib.rs index aaa1005..62b410b 100644 --- a/boards/dk/src/lib.rs +++ b/boards/dk/src/lib.rs @@ -21,10 +21,11 @@ use hal::{ rtc::{Rtc, RtcInterrupt}, timer::OneShot, }; -use log::{LevelFilter, Log}; -use rtt_target::rprintln; + +use defmt; #[cfg(any(feature = "beginner", feature = "advanced"))] -use rtt_target::rtt_init_print; +use defmt_rtt as _; // global logger + #[cfg(feature = "advanced")] use crate::{ @@ -79,7 +80,7 @@ pub struct Led { impl Led { /// Turns on the LED pub fn on(&mut self) { - log::trace!( + defmt::trace!( "setting P{}.{} low (LED on)", if self.inner.port() == Port::Port1 { '1' @@ -137,7 +138,7 @@ pub struct Timer { impl Timer { /// Blocks program execution for at least the specified `duration` pub fn wait(&mut self, duration: Duration) { - log::trace!("blocking for {:?} ...", duration); + defmt::trace!("blocking for {:?} ...", duration); // 1 cycle = 1 microsecond const NANOS_IN_ONE_MICRO: u32 = 1_000; @@ -164,7 +165,7 @@ impl Timer { self.inner.delay(cycles) } - log::trace!("... DONE"); + defmt::trace!("... DONE"); } } @@ -195,21 +196,7 @@ pub fn init() -> Result { Clocks, > = None; - // NOTE this must be executed as early as possible or the tool will timeout - // NOTE the unsafety of this macro is incorrect; it must be run at most once - #[cfg(feature = "beginner")] - rtt_init_print!(BlockIfFull, 16384); - #[cfg(feature = "advanced")] - rtt_init_print!(NoBlockSkip, 16384); - - log::set_logger(&Logger).unwrap(); - - // if not configured in the application we default to the `Info` level - if log::max_level() == LevelFilter::Off { - log::set_max_level(LevelFilter::Info) - } - - log::debug!("Initializing the board"); + defmt::debug!("Initializing the board"); let clocks = Clocks::new(periph.CLOCK); let clocks = clocks.enable_ext_hfosc(); @@ -220,7 +207,7 @@ pub fn init() -> Result { #[cfg(feature = "beginner")] let clocks = unsafe { CLOCKS.get_or_insert(_clocks) }; - log::debug!("Clocks configured"); + defmt::debug!("Clocks configured"); let mut rtc = Rtc::new(periph.RTC0, 0).unwrap(); rtc.enable_interrupt(RtcInterrupt::Overflow, None); @@ -239,7 +226,7 @@ pub fn init() -> Result { // mechanism) unsafe { NVIC::unmask(Interrupt::RTC0) }; - log::debug!("RTC started"); + defmt::debug!("RTC started"); let pins = p0::Parts::new(periph.P0); @@ -249,7 +236,7 @@ pub fn init() -> Result { let _3 = pins.p0_15.degrade().into_push_pull_output(Level::High); let _4 = pins.p0_16.degrade().into_push_pull_output(Level::High); - log::debug!("I/O pins have been configured for digital output"); + defmt::debug!("I/O pins have been configured for digital output"); let timer = hal::Timer::new(periph.TIMER0); @@ -259,7 +246,7 @@ pub fn init() -> Result { // set TX power to its maximum value radio.set_txpower(ieee802154::TxPower::Pos8dBm); - log::debug!("Radio initialized and configured with TX power set to the maximum value"); + defmt::debug!("Radio initialized and configured with TX power set to the maximum value"); radio }; @@ -285,29 +272,6 @@ pub fn init() -> Result { } } -struct Logger; - -impl Log for Logger { - fn enabled(&self, metadata: &log::Metadata) -> bool { - metadata.level() <= log::STATIC_MAX_LEVEL - } - - fn log(&self, record: &log::Record) { - if !self.enabled(record.metadata()) { - return; - } - - rprintln!( - "{}:{} -- {}", - record.level(), - record.target(), - record.args() - ); - } - - fn flush(&self) {} -} - // Counter of OVERFLOW events -- an OVERFLOW occurs every (1<<24) ticks static OVERFLOWS: AtomicU32 = AtomicU32::new(0); @@ -324,7 +288,7 @@ fn RTC0() { /// Exits the application and prints a backtrace when the program is executed through the `probe-run` /// Cargo runner pub fn exit() -> ! { - log::info!("`dk::exit() called; exiting ...`"); + defmt::info!("`dk::exit() called; exiting ...`"); // force any pending memory operation to complete before the BKPT instruction that follows atomic::compiler_fence(Ordering::SeqCst); loop { From e1f740caba56b47b685bc8844c5b331f7dcb2b5a Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Thu, 8 Apr 2021 14:16:26 +0200 Subject: [PATCH 03/29] wip: move beginner to defmt --- beginner/apps/.cargo/config.toml | 1 + beginner/apps/Cargo.toml | 3 +-- beginner/apps/src/bin/blinky.rs | 5 +++-- beginner/apps/src/bin/hello.rs | 4 ++-- beginner/apps/src/bin/led.rs | 3 ++- beginner/apps/src/bin/panic.rs | 6 ++++-- beginner/apps/src/bin/radio-puzzle-1.rs | 11 ++++++----- beginner/apps/src/bin/radio-puzzle-2.rs | 7 ++++--- beginner/apps/src/lib.rs | 17 +++++++++++++++++ 9 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 beginner/apps/src/lib.rs diff --git a/beginner/apps/.cargo/config.toml b/beginner/apps/.cargo/config.toml index be9aeec..b697f78 100644 --- a/beginner/apps/.cargo/config.toml +++ b/beginner/apps/.cargo/config.toml @@ -2,6 +2,7 @@ # (..) rustflags = [ "-C", "linker=flip-link", # adds stack overflow protection + "-C", "link-arg=-Tdefmt.x", # defmt support # (..) ] diff --git a/beginner/apps/Cargo.toml b/beginner/apps/Cargo.toml index f457b4f..83d9d28 100644 --- a/beginner/apps/Cargo.toml +++ b/beginner/apps/Cargo.toml @@ -10,7 +10,6 @@ cortex-m = "0.6.4" cortex-m-rt = "0.6.13" dk = { path = "../../boards/dk", features = ["beginner"] } heapless = "0.5.5" -panic-log = { path = "../../common/panic-log" } panic-probe = { version = "0.2.0", features = ["print-defmt"] } defmt = "0.2.0" defmt-rtt = "0.2.0" @@ -18,7 +17,7 @@ defmt-rtt = "0.2.0" # optimize code in both profiles [profile.dev] codegen-units = 1 -debug = 1 +debug = 2 debug-assertions = true # ! incremental = false lto = "fat" diff --git a/beginner/apps/src/bin/blinky.rs b/beginner/apps/src/bin/blinky.rs index 1548525..5ba6da6 100644 --- a/beginner/apps/src/bin/blinky.rs +++ b/beginner/apps/src/bin/blinky.rs @@ -4,7 +4,8 @@ use core::time::Duration; use cortex_m_rt::entry; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { @@ -19,7 +20,7 @@ fn main() -> ! { for _ in 0..10 { led.toggle(); timer.wait(Duration::from_secs(1)); - log::info!("LED toggled at {:?}", dk::uptime()); + defmt::debug!("LED toggled at {:?}", dk::uptime()); } dk::exit() diff --git a/beginner/apps/src/bin/hello.rs b/beginner/apps/src/bin/hello.rs index e1ec04c..fbb5eba 100644 --- a/beginner/apps/src/bin/hello.rs +++ b/beginner/apps/src/bin/hello.rs @@ -3,8 +3,8 @@ use cortex_m::asm; use cortex_m_rt::entry; -use defmt_rtt as _; // global logger -use panic_probe as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { diff --git a/beginner/apps/src/bin/led.rs b/beginner/apps/src/bin/led.rs index f037c3f..8b3aa61 100644 --- a/beginner/apps/src/bin/led.rs +++ b/beginner/apps/src/bin/led.rs @@ -3,7 +3,8 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { diff --git a/beginner/apps/src/bin/panic.rs b/beginner/apps/src/bin/panic.rs index eb86bc7..b3c139d 100644 --- a/beginner/apps/src/bin/panic.rs +++ b/beginner/apps/src/bin/panic.rs @@ -3,7 +3,9 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; + #[entry] fn main() -> ! { @@ -28,7 +30,7 @@ fn bar() { let array = [0, 1, 2]; let x = array[i]; // out of bounds access - log::info!("{}", x); + defmt::info!("{}", x); } fn index() -> usize { diff --git a/beginner/apps/src/bin/radio-puzzle-1.rs b/beginner/apps/src/bin/radio-puzzle-1.rs index 3c9ad08..5c798b3 100644 --- a/beginner/apps/src/bin/radio-puzzle-1.rs +++ b/beginner/apps/src/bin/radio-puzzle-1.rs @@ -4,7 +4,8 @@ use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -36,15 +37,15 @@ fn main() -> ! { if packet.len() == 1 { let destination = packet[0]; - log::info!("{} -> {}", source, destination); + defmt::info!("{} -> {}", source, destination); // or cast to `char` for a more readable output - log::info!("{:?} -> {:?}", source as char, destination as char); + defmt::info!("{:?} -> {:?}", source as char, destination as char); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } diff --git a/beginner/apps/src/bin/radio-puzzle-2.rs b/beginner/apps/src/bin/radio-puzzle-2.rs index cfb8d53..083ed35 100644 --- a/beginner/apps/src/bin/radio-puzzle-2.rs +++ b/beginner/apps/src/bin/radio-puzzle-2.rs @@ -7,7 +7,8 @@ use cortex_m_rt::entry; // lookup performance when the dictionary contains a large number of items but performance is // not important for this exercise use heapless::{consts, LinearMap}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { @@ -25,9 +26,9 @@ fn main() -> ! { let key = b'A'; let value = dict[&key]; // the key needs to be passed by reference - log::info!("{} -> {}", key, value); + defmt::info!("{} -> {}", key, value); // more readable - log::info!("{:?} -> {:?}", key as char, value as char); + defmt::info!("{:?} -> {:?}", key as char, value as char); // TODO try another insertion // TODO try looking up a key not contained in the dictionary diff --git a/beginner/apps/src/lib.rs b/beginner/apps/src/lib.rs new file mode 100644 index 0000000..7480423 --- /dev/null +++ b/beginner/apps/src/lib.rs @@ -0,0 +1,17 @@ +#![no_std] + +use panic_probe as _; + +// same panicking *behavior* as `panic-probe` but doesn't print a panic message +// this prevents the panic message being printed *twice* when `defmt::panic` is invoked +#[defmt::panic_handler] +fn panic() -> ! { + cortex_m::asm::udf() +} + +/// Terminates the application and makes `probe-run` exit with exit-code = 0 +pub fn exit() -> ! { + loop { + cortex_m::asm::bkpt(); + } +} From 622707bab702ce69848b36b74008f6a938f5d5f7 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Mon, 12 Apr 2021 11:51:44 +0200 Subject: [PATCH 04/29] convert all beginner code snippets --- beginner/apps/src/bin/radio-puzzle-3.rs | 11 +++++++---- beginner/apps/src/bin/radio-puzzle-4.rs | 12 ++++++++---- beginner/apps/src/bin/radio-puzzle-5.rs | 9 +++++---- beginner/apps/src/bin/radio-puzzle-6.rs | 13 +++++++------ beginner/apps/src/bin/radio-puzzle-7.rs | 17 +++++++++-------- .../apps/src/bin/radio-puzzle-solution-2.rs | 17 +++++++++-------- beginner/apps/src/bin/radio-puzzle-solution.rs | 17 +++++++++-------- beginner/apps/src/bin/radio-puzzle.rs | 9 +++++---- beginner/apps/src/bin/radio-recv.rs | 14 ++++++++------ beginner/apps/src/bin/radio-send.rs | 5 +++-- beginner/apps/src/bin/stack_overflow.rs | 5 +++-- 11 files changed, 73 insertions(+), 56 deletions(-) diff --git a/beginner/apps/src/bin/radio-puzzle-3.rs b/beginner/apps/src/bin/radio-puzzle-3.rs index 845f0e9..ef9336f 100644 --- a/beginner/apps/src/bin/radio-puzzle-3.rs +++ b/beginner/apps/src/bin/radio-puzzle-3.rs @@ -5,7 +5,8 @@ use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -36,16 +37,18 @@ fn main() -> ! { // TODO insert the key-value pair // dict.insert(/* ? */, /* ? */).expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } - log::info!("{:?}", dict); + defmt::info!("{:?}", defmt::Debug2Format(&dict)); + // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log `heapless` + // data structures (like `LinearMap` here) with `defmt` dk::exit() } diff --git a/beginner/apps/src/bin/radio-puzzle-4.rs b/beginner/apps/src/bin/radio-puzzle-4.rs index 585b481..afce214 100644 --- a/beginner/apps/src/bin/radio-puzzle-4.rs +++ b/beginner/apps/src/bin/radio-puzzle-4.rs @@ -6,7 +6,8 @@ use core::str; use cortex_m_rt::entry; use heapless::{consts, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { @@ -21,10 +22,13 @@ fn main() -> ! { buffer.push(b'i').expect("buffer full"); // look into the contents so far - log::info!("{:?}", buffer); + defmt::info!("{:?}", defmt::Debug2Format(&buffer)); + // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log `heapless` + // data structures (like `Vec` here) with `defmt` + // or more readable - // NOTE as long as you only push bytes in the ASCII range (0..=127) the conversion should work - log::info!( + // NOTE utf-8 conversion works as long as you only push bytes in the ASCII range (0..=127) + defmt::info!( "{}", str::from_utf8(&buffer).expect("content was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle-5.rs b/beginner/apps/src/bin/radio-puzzle-5.rs index 50dc9da..80be341 100644 --- a/beginner/apps/src/bin/radio-puzzle-5.rs +++ b/beginner/apps/src/bin/radio-puzzle-5.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -27,11 +28,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -47,7 +48,7 @@ fn main() -> ! { buf.push(output).expect("buffer full"); } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&buf).expect("buffer contains non-UTF-8 data") ); diff --git a/beginner/apps/src/bin/radio-puzzle-6.rs b/beginner/apps/src/bin/radio-puzzle-6.rs index 4d9ca39..9ff925b 100644 --- a/beginner/apps/src/bin/radio-puzzle-6.rs +++ b/beginner/apps/src/bin/radio-puzzle-6.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -37,11 +38,11 @@ fn main() -> ! { // TODO insert the key-value pair // dict.insert(/* ? */, /* ? */).expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } @@ -51,11 +52,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -71,7 +72,7 @@ fn main() -> ! { buffer.push(value).expect("buffer full"); } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") ); diff --git a/beginner/apps/src/bin/radio-puzzle-7.rs b/beginner/apps/src/bin/radio-puzzle-7.rs index 933f0d9..be25024 100644 --- a/beginner/apps/src/bin/radio-puzzle-7.rs +++ b/beginner/apps/src/bin/radio-puzzle-7.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -37,11 +38,11 @@ fn main() -> ! { // TODO insert the key-value pair // dict.insert(/* ? */, /* ? */).expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } @@ -51,11 +52,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -71,7 +72,7 @@ fn main() -> ! { buffer.push(value).expect("buffer full"); } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") ); @@ -82,11 +83,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "Dongle response: {}", str::from_utf8(&packet).expect("response was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle-solution-2.rs b/beginner/apps/src/bin/radio-puzzle-solution-2.rs index 385b632..1752e5b 100644 --- a/beginner/apps/src/bin/radio-puzzle-solution-2.rs +++ b/beginner/apps/src/bin/radio-puzzle-solution-2.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -37,11 +38,11 @@ fn main() -> ! { dict.insert(cipherletter, plainletter) .expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } @@ -51,11 +52,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -73,7 +74,7 @@ fn main() -> ! { *spot = plainletter; } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&packet).expect("buffer contains non-UTF-8 data") ); @@ -82,11 +83,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "Dongle response: {}", str::from_utf8(&packet).expect("response was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle-solution.rs b/beginner/apps/src/bin/radio-puzzle-solution.rs index 5808d5e..6c834a6 100644 --- a/beginner/apps/src/bin/radio-puzzle-solution.rs +++ b/beginner/apps/src/bin/radio-puzzle-solution.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -40,11 +41,11 @@ fn main() -> ! { dict.insert(cipherletter, plainletter) .expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } @@ -54,11 +55,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -75,7 +76,7 @@ fn main() -> ! { buffer.push(plainletter).expect("buffer full"); } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") ); @@ -86,11 +87,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "Dongle response: {}", str::from_utf8(&packet).expect("response was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle.rs b/beginner/apps/src/bin/radio-puzzle.rs index 619905f..522cb99 100644 --- a/beginner/apps/src/bin/radio-puzzle.rs +++ b/beginner/apps/src/bin/radio-puzzle.rs @@ -6,7 +6,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -33,19 +34,19 @@ fn main() -> ! { // let msg = b"Hello?"; packet.copy_from_slice(msg); - log::info!( + defmt::info!( "sending: {}", str::from_utf8(msg).expect("msg was not valid UTF-8 data") ); radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_ok() { - log::info!( + defmt::info!( "received: {}", str::from_utf8(&packet).expect("response was not valid UTF-8 data") ); } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); } dk::exit() } diff --git a/beginner/apps/src/bin/radio-recv.rs b/beginner/apps/src/bin/radio-recv.rs index 732f311..d1f4fe3 100644 --- a/beginner/apps/src/bin/radio-recv.rs +++ b/beginner/apps/src/bin/radio-recv.rs @@ -6,7 +6,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Error, Packet}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -24,7 +25,7 @@ fn main() -> ! { let msg = b"olleh"; packet.copy_from_slice(msg); - log::info!( + defmt::info!( "sending: {}", str::from_utf8(msg).expect("message is not valid UTF-8") ); @@ -37,14 +38,15 @@ fn main() -> ! { match res { Ok(crc) => { - log::info!( - "received: {} (CRC={})", + defmt::info!( + "received: {} (CRC = {:X})", + // ^^ print as uppercase hexadecimal str::from_utf8(&*packet).expect("response is not valid UTF-8"), crc ); } - Err(Error::Crc(crc)) => log::error!("invalid CRC: {:06x}", crc), - Err(Error::Timeout) => log::error!("no response within {} ms", TEN_MS / 1_000), + Err(Error::Crc(crc)) => defmt::error!("invalid CRC: {=u16:x}", crc), + Err(Error::Timeout) => defmt::error!("no response within {} ms", TEN_MS / 1_000), } dk::exit() diff --git a/beginner/apps/src/bin/radio-send.rs b/beginner/apps/src/bin/radio-send.rs index 4f411df..4d09180 100644 --- a/beginner/apps/src/bin/radio-send.rs +++ b/beginner/apps/src/bin/radio-send.rs @@ -6,7 +6,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet, TxPower}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { @@ -25,7 +26,7 @@ fn main() -> ! { // let msg: &[u8; 5] = &[b'H', b'e', b'l', b'l', b'o']; // let msg: &[u8; 5] = b"Hello"; - log::info!( + defmt::info!( "sending: {}", str::from_utf8(msg).expect("msg is not valid UTF-8 data") ); diff --git a/beginner/apps/src/bin/stack_overflow.rs b/beginner/apps/src/bin/stack_overflow.rs index e5930e8..b06cb53 100644 --- a/beginner/apps/src/bin/stack_overflow.rs +++ b/beginner/apps/src/bin/stack_overflow.rs @@ -3,14 +3,15 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { // board initialization dk::init().unwrap(); - log::info!("fib(100) = {:?}", fib(100)); + defmt::info!("fib(100) = {:?}", fib(100)); loop { asm::bkpt(); From 8d0c55d36fa0ec665da4a1c3a89a4fac9c80297d Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Mon, 12 Apr 2021 11:52:04 +0200 Subject: [PATCH 05/29] dk lib: minor formatting improvement --- boards/dk/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/boards/dk/src/lib.rs b/boards/dk/src/lib.rs index 62b410b..2de1bd7 100644 --- a/boards/dk/src/lib.rs +++ b/boards/dk/src/lib.rs @@ -288,7 +288,7 @@ fn RTC0() { /// Exits the application and prints a backtrace when the program is executed through the `probe-run` /// Cargo runner pub fn exit() -> ! { - defmt::info!("`dk::exit() called; exiting ...`"); + defmt::info!("`dk::exit()` called; exiting ..."); // force any pending memory operation to complete before the BKPT instruction that follows atomic::compiler_fence(Ordering::SeqCst); loop { From e8ed24d893115b4c2f0000b629b0ebfaaf17c6ce Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Mon, 12 Apr 2021 17:09:38 +0200 Subject: [PATCH 06/29] start converting advanced apps --- advanced/firmware/.cargo/config.toml | 1 + advanced/firmware/Cargo.toml | 22 ++++++++++++++++--- advanced/firmware/src/bin/events.rs | 13 ++++++----- advanced/firmware/src/bin/hello.rs | 5 +++-- .../firmware/src/bin/resource-solution.rs | 13 ++++++----- advanced/firmware/src/bin/resource.rs | 11 +++++----- advanced/firmware/src/bin/rtic-hello.rs | 7 +++--- advanced/firmware/src/lib.rs | 17 ++++++++++++++ 8 files changed, 64 insertions(+), 25 deletions(-) create mode 100644 advanced/firmware/src/lib.rs diff --git a/advanced/firmware/.cargo/config.toml b/advanced/firmware/.cargo/config.toml index 5ccd822..4c4601e 100644 --- a/advanced/firmware/.cargo/config.toml +++ b/advanced/firmware/.cargo/config.toml @@ -2,6 +2,7 @@ # (..) rustflags = [ "-C", "linker=flip-link", # adds stack overflow protection + "-C", "link-arg=-Tdefmt.x", # defmt support # (..) ] diff --git a/advanced/firmware/Cargo.toml b/advanced/firmware/Cargo.toml index dafce5e..eb052bb 100644 --- a/advanced/firmware/Cargo.toml +++ b/advanced/firmware/Cargo.toml @@ -17,15 +17,16 @@ cortex-m-rt = "0.6.13" cortex-m-rtic = "0.5.1" dk = { path = "../../boards/dk", features = ["advanced"] } heapless = "0.5.5" -log = "0.4.8" -panic-log = { path = "../../common/panic-log" } +panic-probe = { version = "0.2.0", features = ["print-defmt"] } +defmt = "0.2.0" +defmt-rtt = "0.2.0" usb = { path = "../common/usb" } usb2 = "0.0.1" # optimize code in both profiles [profile.dev] codegen-units = 1 -debug = 1 +debug = 2 debug-assertions = true # ! incremental = false lto = "fat" @@ -40,3 +41,18 @@ incremental = false lto = "fat" opt-level = 3 overflow-checks = false + +[features] + # set defmt logging levels here + default = [ + "defmt-default", + # "dependency-a/defmt-trace", + ] + + # do NOT modify these features + defmt-default = [] + defmt-trace = [] + defmt-debug = [] + defmt-info = [] + defmt-warn = [] + defmt-error = [] \ No newline at end of file diff --git a/advanced/firmware/src/bin/events.rs b/advanced/firmware/src/bin/events.rs index bb02c23..bf8d40d 100644 --- a/advanced/firmware/src/bin/events.rs +++ b/advanced/firmware/src/bin/events.rs @@ -2,7 +2,8 @@ #![no_std] use cortex_m::asm; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -22,7 +23,7 @@ const APP: () = { w.usbdetected().set_bit() }); - log::info!("USBDETECTED interrupt enabled"); + defmt::info!("USBDETECTED interrupt enabled"); // read the whole 32-bit usb supply register // the `read()` method returns a reader which can then be used to access the register content @@ -30,19 +31,19 @@ const APP: () = { // (the layout of the USBREGSTATUS register can be found in section 5.3.7.13 of the PS) let regstatus: u32 = power.usbregstatus.read().bits(); // ^^^^ complete register content - log::info!("USBREGSTATUS: {:b}", regstatus); + defmt::info!("USBREGSTATUS: {:b}", regstatus); // read the 1-bit VBUSDETECT field that is part of the USBREGSTATUS register content // to show that its contents reflect our usb connection status // (the USBDETECTED event that will trigger `on_power_event()` is derived from this information) let vbusdetect: bool = power.usbregstatus.read().vbusdetect().bits(); // ^^^^^^^^^^ bitfield name - log::info!("USBREGSTATUS.VBUSDETECT: {}", vbusdetect); + defmt::info!("USBREGSTATUS.VBUSDETECT: {}", vbusdetect); } #[idle] fn main(_cx: main::Context) -> ! { - log::info!("idle: going to sleep"); + defmt::info!("idle: going to sleep"); // sleep in the background loop { @@ -52,7 +53,7 @@ const APP: () = { #[task(binds = POWER_CLOCK)] fn on_power_event(_cx: on_power_event::Context) { - log::info!("POWER event occurred"); + defmt::info!("POWER event occurred"); dk::exit() } }; diff --git a/advanced/firmware/src/bin/hello.rs b/advanced/firmware/src/bin/hello.rs index 8ae0ce5..af489e8 100644 --- a/advanced/firmware/src/bin/hello.rs +++ b/advanced/firmware/src/bin/hello.rs @@ -3,14 +3,15 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[entry] fn main() -> ! { // board initialization dk::init().unwrap(); - log::info!("Hello, world!"); + defmt::info!("Hello, world!"); loop { asm::bkpt(); diff --git a/advanced/firmware/src/bin/resource-solution.rs b/advanced/firmware/src/bin/resource-solution.rs index 89b5c5d..ecc0b66 100644 --- a/advanced/firmware/src/bin/resource-solution.rs +++ b/advanced/firmware/src/bin/resource-solution.rs @@ -3,7 +3,8 @@ use cortex_m::asm; use dk::peripheral::POWER; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -20,7 +21,7 @@ const APP: () = { power.intenset.write(|w| w.usbdetected().set_bit()); - log::info!("USBDETECTED interrupt enabled"); + defmt::info!("USBDETECTED interrupt enabled"); init::LateResources { power, @@ -31,23 +32,23 @@ const APP: () = { #[idle] fn main(_cx: main::Context) -> ! { loop { - log::info!("idle: going to sleep"); + defmt::info!("idle: going to sleep"); asm::wfi(); - log::info!("idle: woke up"); + defmt::info!("idle: woke up"); } } #[task(binds = POWER_CLOCK, resources = [power, counter])] // ^^^^^^^ we want to access the resource from here fn on_power_event(cx: on_power_event::Context) { - log::debug!("POWER event occurred"); + defmt::debug!("POWER event occurred"); let power = cx.resources.power; let counter = cx.resources.counter; *counter += 1; let n = *counter; - log::info!( + defmt::info!( "on_power_event: cable connected {} time{}", n, if n != 1 { "s" } else { "" } diff --git a/advanced/firmware/src/bin/resource.rs b/advanced/firmware/src/bin/resource.rs index 9cd2e1c..b43e6c7 100644 --- a/advanced/firmware/src/bin/resource.rs +++ b/advanced/firmware/src/bin/resource.rs @@ -3,7 +3,8 @@ use cortex_m::asm; use dk::peripheral::POWER; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -19,7 +20,7 @@ const APP: () = { power.intenset.write(|w| w.usbdetected().set_bit()); - log::info!("USBDETECTED interrupt enabled"); + defmt::info!("USBDETECTED interrupt enabled"); init::LateResources { power, // <- resource initialization @@ -29,16 +30,16 @@ const APP: () = { #[idle] fn main(_cx: main::Context) -> ! { loop { - log::info!("idle: going to sleep"); + defmt::info!("idle: going to sleep"); asm::wfi(); - log::info!("idle: woke up"); + defmt::info!("idle: woke up"); } } #[task(binds = POWER_CLOCK, resources = [power])] // ^^^^^^^ resource access list fn on_power_event(cx: on_power_event::Context) { - log::info!("POWER event occurred"); + defmt::info!("POWER event occurred"); // resources available to this task let resources = cx.resources; diff --git a/advanced/firmware/src/bin/rtic-hello.rs b/advanced/firmware/src/bin/rtic-hello.rs index 055f490..68869ff 100644 --- a/advanced/firmware/src/bin/rtic-hello.rs +++ b/advanced/firmware/src/bin/rtic-hello.rs @@ -2,7 +2,8 @@ #![no_std] use cortex_m::asm; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -10,12 +11,12 @@ const APP: () = { fn init(_cx: init::Context) { dk::init().unwrap(); - log::info!("Hello"); + defmt::info!("Hello"); } #[idle] fn main(_cx: main::Context) -> ! { - log::info!("world!"); + defmt::info!("world!"); loop { asm::bkpt(); diff --git a/advanced/firmware/src/lib.rs b/advanced/firmware/src/lib.rs new file mode 100644 index 0000000..7480423 --- /dev/null +++ b/advanced/firmware/src/lib.rs @@ -0,0 +1,17 @@ +#![no_std] + +use panic_probe as _; + +// same panicking *behavior* as `panic-probe` but doesn't print a panic message +// this prevents the panic message being printed *twice* when `defmt::panic` is invoked +#[defmt::panic_handler] +fn panic() -> ! { + cortex_m::asm::udf() +} + +/// Terminates the application and makes `probe-run` exit with exit-code = 0 +pub fn exit() -> ! { + loop { + cortex_m::asm::bkpt(); + } +} From 354fcc37d33548914b22c5e5fce344e87015ace9 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Wed, 14 Apr 2021 11:49:34 +0200 Subject: [PATCH 07/29] finish advanced defmt port --- advanced/firmware/src/bin/stack_overflow.rs | 25 +++++++++---------- advanced/firmware/src/bin/usb-1-solution.rs | 9 ++++--- advanced/firmware/src/bin/usb-1.rs | 9 ++++--- advanced/firmware/src/bin/usb-2-solution.rs | 11 +++++---- advanced/firmware/src/bin/usb-2.rs | 12 +++++---- advanced/firmware/src/bin/usb-3-solution.rs | 11 +++++---- advanced/firmware/src/bin/usb-3.rs | 11 +++++---- advanced/firmware/src/bin/usb-4-solution.rs | 17 +++++++------ advanced/firmware/src/bin/usb-4.rs | 17 +++++++------ advanced/firmware/src/bin/usb-5-solution.rs | 27 ++++++++++++--------- boards/dk/src/usbd.rs | 2 +- 11 files changed, 82 insertions(+), 69 deletions(-) diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index da80959..2546126 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -3,15 +3,15 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[entry] fn main() -> ! { // board initialization dk::init().unwrap(); - log::info!("provoking stack overflow..."); - spam(0); + defmt::info!("fib(100) = {:?}", fib(100)); loop { asm::bkpt(); @@ -19,16 +19,13 @@ fn main() -> ! { } #[inline(never)] -fn spam(n: u32) { - // allocate and initialize 4 kilobytes of stack memory to provoke stack overflow - let use_stack = [n; 1024]; +fn fib(n: u32) -> u32 { + // allocate and initialize one kilobyte of stack memory to provoke stack overflow + let _use_stack = [0xAA; 1024]; - log::info!( - "address of current `use_stack` at recursion depth {:?}: {:?}", - use_stack[1023], // "use" use_stack to prevent it from being optimized out - &use_stack as *const u32 - ); - - let next = n + 1; - spam(next); // infinite recursion + if n < 2 { + 1 + } else { + fib(n - 1) + fib(n - 2) // recursion + } } diff --git a/advanced/firmware/src/bin/usb-1-solution.rs b/advanced/firmware/src/bin/usb-1-solution.rs index d9bcfbc..a8e35bf 100644 --- a/advanced/firmware/src/bin/usb-1-solution.rs +++ b/advanced/firmware/src/bin/usb-1-solution.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -33,18 +34,18 @@ const APP: () = { }; fn on_event(_usbd: &USBD, event: Event) { - log::info!("USB: {:?}", event); + defmt::info!("USB: {:?}", event); match event { Event::UsbReset => { // going from the Default state to the Default state is a no-operation - log::info!("returning to the Default state"); + defmt::info!("returning to the Default state"); } Event::UsbEp0DataDone => todo!(), Event::UsbEp0Setup => { - log::info!("goal reached; move to the next section"); + defmt::info!("goal reached; move to the next section"); dk::exit() } } diff --git a/advanced/firmware/src/bin/usb-1.rs b/advanced/firmware/src/bin/usb-1.rs index 62d2b02..c297f43 100644 --- a/advanced/firmware/src/bin/usb-1.rs +++ b/advanced/firmware/src/bin/usb-1.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -21,7 +22,7 @@ const APP: () = { // NOTE this will block if the USB cable is not connected to port J3 usbd::init(board.power, &board.usbd); - log::info!("USBD initialized"); + defmt::info!("USBD initialized"); init::LateResources { usbd: board.usbd } } @@ -37,7 +38,7 @@ const APP: () = { }; fn on_event(_usbd: &USBD, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => todo!(), @@ -45,7 +46,7 @@ fn on_event(_usbd: &USBD, event: Event) { Event::UsbEp0DataDone => todo!(), Event::UsbEp0Setup => { - log::info!("goal reached; move to the next section"); + defmt::info!("goal reached; move to the next section"); dk::exit() } } diff --git a/advanced/firmware/src/bin/usb-2-solution.rs b/advanced/firmware/src/bin/usb-2-solution.rs index fe2ce55..cd8a858 100644 --- a/advanced/firmware/src/bin/usb-2-solution.rs +++ b/advanced/firmware/src/bin/usb-2-solution.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb::{Descriptor, Request}; #[rtic::app(device = dk)] @@ -34,7 +35,7 @@ const APP: () = { }; fn on_event(usbd: &USBD, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { @@ -69,7 +70,7 @@ fn on_event(usbd: &USBD, event: Event) { // let windex = usbd::windex(usbd); // let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -84,9 +85,9 @@ fn on_event(usbd: &USBD, event: Event) { Request::GetDescriptor { descriptor, length } if descriptor == Descriptor::Device => { - log::info!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); - log::info!("Goal reached; move to the next section"); + defmt::info!("Goal reached; move to the next section"); dk::exit() } Request::SetAddress { .. } => { diff --git a/advanced/firmware/src/bin/usb-2.rs b/advanced/firmware/src/bin/usb-2.rs index c8b07f2..648c475 100644 --- a/advanced/firmware/src/bin/usb-2.rs +++ b/advanced/firmware/src/bin/usb-2.rs @@ -5,7 +5,9 @@ use dk::{ peripheral::USBD, usbd::{self, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; + use usb::{Descriptor, Request}; #[rtic::app(device = dk)] @@ -34,7 +36,7 @@ const APP: () = { }; fn on_event(_usbd: &USBD, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { @@ -61,7 +63,7 @@ fn on_event(_usbd: &USBD, event: Event) { // composed of a high register (WVALUEH) and a low register (WVALUEL) let wvalue: u16 = 0; - log::info!( + defmt::info!( "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -79,9 +81,9 @@ fn on_event(_usbd: &USBD, event: Event) { // TODO modify `Request::parse()` in `advanced/common/usb/lib.rs` // so that this branch is reached - log::info!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); - log::info!("Goal reached; move to the next section"); + defmt::info!("Goal reached; move to the next section"); dk::exit() } Request::SetAddress { .. } => { diff --git a/advanced/firmware/src/bin/usb-3-solution.rs b/advanced/firmware/src/bin/usb-3-solution.rs index f4d0fa0..f5a4476 100644 --- a/advanced/firmware/src/bin/usb-3-solution.rs +++ b/advanced/firmware/src/bin/usb-3-solution.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb::{Descriptor, Request}; #[rtic::app(device = dk)] @@ -39,7 +40,7 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { @@ -55,7 +56,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -71,7 +72,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { Request::GetDescriptor { descriptor, length } if descriptor == Descriptor::Device => { - log::info!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); let desc = usb2::device::Descriptor { bDeviceClass: 0, @@ -96,7 +97,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { // but for now it's OK to do nothing. } _ => { - log::error!( + defmt::error!( "unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" ); dk::exit() diff --git a/advanced/firmware/src/bin/usb-3.rs b/advanced/firmware/src/bin/usb-3.rs index bd3799b..6e74b22 100644 --- a/advanced/firmware/src/bin/usb-3.rs +++ b/advanced/firmware/src/bin/usb-3.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb::{Descriptor, Request}; #[rtic::app(device = dk)] @@ -39,7 +40,7 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { @@ -55,7 +56,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -71,7 +72,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { Request::GetDescriptor { descriptor, length } if descriptor == Descriptor::Device => { - log::info!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); // TODO send back a valid device descriptor, truncated to `length` bytes // let desc = usb2::device::Descriptor { .. }; @@ -84,7 +85,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { // but for now it's OK to do nothing. } _ => { - log::error!( + defmt::error!( "unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" ); dk::exit() diff --git a/advanced/firmware/src/bin/usb-4-solution.rs b/advanced/firmware/src/bin/usb-4-solution.rs index 2301173..b8e473d 100644 --- a/advanced/firmware/src/bin/usb-4-solution.rs +++ b/advanced/firmware/src/bin/usb-4-solution.rs @@ -7,7 +7,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State}; #[rtic::app(device = dk)] @@ -44,22 +45,22 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { - log::info!("USB reset condition detected"); + defmt::info!("USB reset condition detected"); *state = State::Default; } Event::UsbEp0DataDone => { - log::info!("EP0IN: transfer complete"); + defmt::info!("EP0IN: transfer complete"); ep0in.end(usbd); } Event::UsbEp0Setup => { if ep0setup(usbd, ep0in, state).is_err() { - log::warn!("EP0IN: unexpected request; stalling the endpoint"); + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); usbd::ep0stall(usbd); } } @@ -76,7 +77,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -87,7 +88,9 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); - log::info!("EP0: {:?}", request); + defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); + // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log + // `StandardRequest` with `defmt` match request { // section 9.4.3 diff --git a/advanced/firmware/src/bin/usb-4.rs b/advanced/firmware/src/bin/usb-4.rs index 3375ef5..ad6a91b 100644 --- a/advanced/firmware/src/bin/usb-4.rs +++ b/advanced/firmware/src/bin/usb-4.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb2::State; // HEADS UP to use *your* USB packet parser uncomment line 12 and remove line 13 @@ -46,17 +47,17 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { // TODO change `state` as specified in chapter 9.1 USB Device States, of the USB specification Event::UsbReset => { - log::info!("USB reset condition detected"); + defmt::info!("USB reset condition detected"); todo!(); } Event::UsbEp0DataDone => { - log::info!("EP0IN: transfer complete"); + defmt::info!("EP0IN: transfer complete"); ep0in.end(usbd); } @@ -64,7 +65,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { if ep0setup(usbd, ep0in, state).is_err() { // unsupported or invalid request: // TODO: add code to stall the endpoint - log::warn!("EP0IN: unexpected request; stalling the endpoint"); + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); } } } @@ -77,7 +78,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), () let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -88,7 +89,9 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), () let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); - log::info!("EP0: {:?}", request); + defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); + // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log + // `StandardRequest` with `defmt` match request { Request::GetDescriptor { descriptor, length } => match descriptor { diff --git a/advanced/firmware/src/bin/usb-5-solution.rs b/advanced/firmware/src/bin/usb-5-solution.rs index 34f0228..b36d8a1 100644 --- a/advanced/firmware/src/bin/usb-5-solution.rs +++ b/advanced/firmware/src/bin/usb-5-solution.rs @@ -7,7 +7,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State}; #[rtic::app(device = dk)] @@ -44,22 +45,22 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { - log::info!("USB reset condition detected"); + defmt::info!("USB reset condition detected"); *state = State::Default; } Event::UsbEp0DataDone => { - log::info!("EP0IN: transfer complete"); + defmt::info!("EP0IN: transfer complete"); ep0in.end(usbd); } Event::UsbEp0Setup => { if ep0setup(usbd, ep0in, state).is_err() { - log::warn!("EP0IN: unexpected request; stalling the endpoint"); + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); usbd::ep0stall(usbd); } } @@ -76,7 +77,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -87,7 +88,9 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); - log::info!("EP0: {:?}", request); + defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); + // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log + // `StandardRequest` with `defmt` match request { // section 9.4.3 @@ -185,10 +188,10 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> State::Address(address) => { if let Some(value) = value { if value.get() == CONFIG_VAL { - log::info!("entering the configured state"); + defmt::info!("entering the configured state"); *state = State::Configured { address, value }; } else { - log::error!("unsupported configuration value"); + defmt::error!("unsupported configuration value"); return Err(()); } } else { @@ -203,18 +206,18 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> if let Some(new_value) = value { if new_value.get() == CONFIG_VAL { if new_value != curr_value { - log::info!("changing configuration"); + defmt::info!("changing configuration"); *state = State::Configured { address, value: new_value, }; } } else { - log::error!("unsupported configuration value"); + defmt::error!("unsupported configuration value"); return Err(()); } } else { - log::info!("returned to the address state"); + defmt::info!("returned to the address state"); *state = State::Address(address); } } diff --git a/boards/dk/src/usbd.rs b/boards/dk/src/usbd.rs index 4973413..7ee6d7e 100644 --- a/boards/dk/src/usbd.rs +++ b/boards/dk/src/usbd.rs @@ -161,7 +161,7 @@ pub fn ep0stall(usbd: &USBD) { } /// USBD.EVENTS registers mapped to an enum -#[derive(Debug)] +#[derive(Debug, defmt::Format)] pub enum Event { /// `EVENTS_USBRESET` register was active UsbReset, From 27dd89493cac66ce055f2ded677126caaf9b351d Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Wed, 14 Apr 2021 11:55:43 +0200 Subject: [PATCH 08/29] advanced/common/usb: move to defmt --- advanced/common/usb/Cargo.toml | 17 ++++++++++++++++- advanced/common/usb/src/lib.rs | 3 ++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/advanced/common/usb/Cargo.toml b/advanced/common/usb/Cargo.toml index a5273c1..b77a48e 100644 --- a/advanced/common/usb/Cargo.toml +++ b/advanced/common/usb/Cargo.toml @@ -6,4 +6,19 @@ name = "usb" version = "0.0.0" [dependencies] -log = "0.4.8" +defmt = "0.2.0" + +[features] +# set defmt logging levels here +default = [ +"defmt-default", +# "dependency-a/defmt-trace", +] + +# do NOT modify these features +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] \ No newline at end of file diff --git a/advanced/common/usb/src/lib.rs b/advanced/common/usb/src/lib.rs index e3762d9..6e2dde6 100644 --- a/advanced/common/usb/src/lib.rs +++ b/advanced/common/usb/src/lib.rs @@ -5,6 +5,7 @@ #![no_std] use core::num::NonZeroU8; +use defmt; /// Device address assigned by the host; will be in the range 1..=127 pub type Address = NonZeroU8; @@ -77,7 +78,7 @@ impl Request { Err(()) } } else { - log::warn!("unhandled case in `Request` parser"); + defmt::warn!("unhandled case in `Request` parser"); Err(()) } } From 739df4dac9bbf3d672d30a08d173d985dc7c7c26 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Wed, 14 Apr 2021 12:02:02 +0200 Subject: [PATCH 09/29] fix typo --- advanced/firmware/src/bin/usb-4-solution.rs | 2 +- advanced/firmware/src/bin/usb-4.rs | 2 +- advanced/firmware/src/bin/usb-5-solution.rs | 2 +- beginner/apps/src/bin/radio-puzzle-3.rs | 2 +- beginner/apps/src/bin/radio-puzzle-4.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/advanced/firmware/src/bin/usb-4-solution.rs b/advanced/firmware/src/bin/usb-4-solution.rs index b8e473d..49ef01a 100644 --- a/advanced/firmware/src/bin/usb-4-solution.rs +++ b/advanced/firmware/src/bin/usb-4-solution.rs @@ -89,7 +89,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); - // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log // `StandardRequest` with `defmt` match request { diff --git a/advanced/firmware/src/bin/usb-4.rs b/advanced/firmware/src/bin/usb-4.rs index ad6a91b..a9c1e14 100644 --- a/advanced/firmware/src/bin/usb-4.rs +++ b/advanced/firmware/src/bin/usb-4.rs @@ -90,7 +90,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), () let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); - // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log // `StandardRequest` with `defmt` match request { diff --git a/advanced/firmware/src/bin/usb-5-solution.rs b/advanced/firmware/src/bin/usb-5-solution.rs index b36d8a1..853bda1 100644 --- a/advanced/firmware/src/bin/usb-5-solution.rs +++ b/advanced/firmware/src/bin/usb-5-solution.rs @@ -89,7 +89,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); - // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log // `StandardRequest` with `defmt` match request { diff --git a/beginner/apps/src/bin/radio-puzzle-3.rs b/beginner/apps/src/bin/radio-puzzle-3.rs index ef9336f..dea6b6d 100644 --- a/beginner/apps/src/bin/radio-puzzle-3.rs +++ b/beginner/apps/src/bin/radio-puzzle-3.rs @@ -47,7 +47,7 @@ fn main() -> ! { } defmt::info!("{:?}", defmt::Debug2Format(&dict)); - // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log `heapless` + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log `heapless` // data structures (like `LinearMap` here) with `defmt` dk::exit() diff --git a/beginner/apps/src/bin/radio-puzzle-4.rs b/beginner/apps/src/bin/radio-puzzle-4.rs index afce214..7b5950d 100644 --- a/beginner/apps/src/bin/radio-puzzle-4.rs +++ b/beginner/apps/src/bin/radio-puzzle-4.rs @@ -23,7 +23,7 @@ fn main() -> ! { // look into the contents so far defmt::info!("{:?}", defmt::Debug2Format(&buffer)); - // ^^^^^^^^^^^^^^^^^^^ this adapter iscurrently needed to log `heapless` + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log `heapless` // data structures (like `Vec` here) with `defmt` // or more readable From 8dbde637bbec65623da2b36b42b6670f39b4f7d3 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Wed, 14 Apr 2021 12:12:02 +0200 Subject: [PATCH 10/29] use defmt in panic-log --- common/panic-log/Cargo.toml | 18 +++++++++++++++++- common/panic-log/src/lib.rs | 2 +- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/common/panic-log/Cargo.toml b/common/panic-log/Cargo.toml index 4129601..84ca06a 100644 --- a/common/panic-log/Cargo.toml +++ b/common/panic-log/Cargo.toml @@ -7,4 +7,20 @@ version = "0.0.0" [dependencies] cortex-m = "0.6.4" -log = "0.4.8" +defmt = "0.2.1" + + +[features] +# defmt logging levels +default = [ + "defmt-debug", + # "dependency-a/defmt-trace", +] + +# do NOT modify these features +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] \ No newline at end of file diff --git a/common/panic-log/src/lib.rs b/common/panic-log/src/lib.rs index 5a08462..70f0b89 100644 --- a/common/panic-log/src/lib.rs +++ b/common/panic-log/src/lib.rs @@ -6,7 +6,7 @@ use cortex_m::asm; #[panic_handler] fn panic(info: &PanicInfo) -> ! { - log::error!("{}", info); + defmt::error!("{}", defmt::Debug2Format(&info)); // abort instruction: triggers a HardFault exception which causes probe-run to exit asm::udf() From c80e9fd620b7a9fc2efc01419dafca5b4a8c2b39 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Wed, 14 Apr 2021 12:13:12 +0200 Subject: [PATCH 11/29] [untested] switch rest of dk over to defmt as well --- boards/dk/Cargo.toml | 1 - boards/dk/src/lib.rs | 2 +- boards/dk/src/usbd.rs | 6 +++--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/boards/dk/Cargo.toml b/boards/dk/Cargo.toml index 4008bce..6918d1b 100644 --- a/boards/dk/Cargo.toml +++ b/boards/dk/Cargo.toml @@ -10,7 +10,6 @@ cortex-m = "0.6.4" cortex-m-rt = "0.6.13" embedded-hal = "0.2.3" hal = { package = "nrf52840-hal", version = "0.12.1" } -log = "0.4.8" defmt = "0.2.1" defmt-rtt = "0.2.0" panic-probe = { version = "0.2.0", features = ["print-defmt" ] } diff --git a/boards/dk/src/lib.rs b/boards/dk/src/lib.rs index 2de1bd7..d010023 100644 --- a/boards/dk/src/lib.rs +++ b/boards/dk/src/lib.rs @@ -96,7 +96,7 @@ impl Led { /// Turns off the LED pub fn off(&mut self) { - log::trace!( + defmt::trace!( "setting P{}.{} high (LED off)", if self.inner.port() == Port::Port1 { '1' diff --git a/boards/dk/src/usbd.rs b/boards/dk/src/usbd.rs index 7ee6d7e..d1ee75c 100644 --- a/boards/dk/src/usbd.rs +++ b/boards/dk/src/usbd.rs @@ -51,7 +51,7 @@ impl Ep0In { self.busy = true; - log::info!("EP0IN: start {}B transfer", n); + defmt::info!("EP0IN: start {}B transfer", n); // start DMA transfer dma_start(); @@ -75,7 +75,7 @@ impl Ep0In { usbd.events_ep0datadone.reset(); self.busy = false; - log::info!("EP0IN: transfer done"); + defmt::info!("EP0IN: transfer done"); } } } @@ -110,7 +110,7 @@ pub fn init(power: POWER, usbd: &USBD) { // wait until the USB cable has been connected while power.events_usbdetected.read().bits() == 0 { if once { - log::info!("waiting for USB connection on port J3"); + defmt::info!("waiting for USB connection on port J3"); once = false; } From 7e3cda9cadbb2b44bf2af84d1c5abb17f2acd665 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Wed, 14 Apr 2021 12:13:32 +0200 Subject: [PATCH 12/29] whoops. forgot to port advanced/vec --- advanced/firmware/src/bin/vec.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/advanced/firmware/src/bin/vec.rs b/advanced/firmware/src/bin/vec.rs index a6580ca..f8b42b2 100644 --- a/advanced/firmware/src/bin/vec.rs +++ b/advanced/firmware/src/bin/vec.rs @@ -4,7 +4,8 @@ use cortex_m_rt::entry; use heapless::{consts, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[entry] fn main() -> ! { @@ -16,13 +17,16 @@ fn main() -> ! { // `heapless::Vec` exposes the same API surface as `std::Vec` but some of its methods return a // `Result` to indicate whether the operation failed due to the `heapless::Vec` being full - log::info!("start: {:?}", buffer); + defmt::info!("start: {:?}", defmt::Debug2Format(&buffer)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log + // `heapless` data structures (like `Vec` here) + // with `defmt` buffer.push(0).expect("buffer full"); - log::info!("after `push`: {:?}", buffer); + defmt::info!("after `push`: {:?}", defmt::Debug2Format(&buffer)); buffer.extend_from_slice(&[1, 2, 3]).expect("buffer full"); - log::info!("after `extend`: {:?}", buffer); + defmt::info!("after `extend`: {:?}", defmt::Debug2Format(&buffer)); // TODO try this operation // buffer.extend_from_slice(&[4, 5, 6, 7]).expect("buffer full"); From 1be6f2fc5aed5420715f8bd737f4eb09c6e9c433 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Wed, 14 Apr 2021 12:14:41 +0200 Subject: [PATCH 13/29] better comments --- beginner/apps/Cargo.toml | 2 +- beginner/apps/src/bin/blinky.rs | 4 ++-- beginner/apps/src/bin/led.rs | 4 ++-- boards/dk/Cargo.toml | 2 +- common/panic-log/Cargo.toml | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/beginner/apps/Cargo.toml b/beginner/apps/Cargo.toml index 83d9d28..0670b4a 100644 --- a/beginner/apps/Cargo.toml +++ b/beginner/apps/Cargo.toml @@ -34,7 +34,7 @@ opt-level = 3 overflow-checks = false [features] -# set logging levels here +# set defmt logging levels here default = [ "defmt-default", # "dependency-a/defmt-trace", diff --git a/beginner/apps/src/bin/blinky.rs b/beginner/apps/src/bin/blinky.rs index 5ba6da6..abf020c 100644 --- a/beginner/apps/src/bin/blinky.rs +++ b/beginner/apps/src/bin/blinky.rs @@ -9,8 +9,8 @@ use apps as _; #[entry] fn main() -> ! { - // uncomment to enable more verbose logs - // log::set_max_level(log::LevelFilter::Trace); + // to enable more verbose logs, go to your `Cargo.toml` and set defmt logging levels + // to `defmt-trace` by changing the `default = []` entry in `[features]` let board = dk::init().unwrap(); diff --git a/beginner/apps/src/bin/led.rs b/beginner/apps/src/bin/led.rs index 8b3aa61..2131134 100644 --- a/beginner/apps/src/bin/led.rs +++ b/beginner/apps/src/bin/led.rs @@ -8,8 +8,8 @@ use apps as _; #[entry] fn main() -> ! { - // uncomment to make logs more verbose - // log::set_max_level(log::LevelFilter::Trace); + // to enable more verbose logs, go to your `Cargo.toml` and set defmt logging levels + // to `defmt-trace` by changing the `default = []` entry in `[features]` let board = dk::init().unwrap(); diff --git a/boards/dk/Cargo.toml b/boards/dk/Cargo.toml index 6918d1b..b946e92 100644 --- a/boards/dk/Cargo.toml +++ b/boards/dk/Cargo.toml @@ -18,7 +18,7 @@ panic-probe = { version = "0.2.0", features = ["print-defmt" ] } beginner = [] advanced = [] -# defmt logging levels +# set defmt logging levels here default = [ "defmt-debug", # "dependency-a/defmt-trace", diff --git a/common/panic-log/Cargo.toml b/common/panic-log/Cargo.toml index 84ca06a..5b61b67 100644 --- a/common/panic-log/Cargo.toml +++ b/common/panic-log/Cargo.toml @@ -11,7 +11,7 @@ defmt = "0.2.1" [features] -# defmt logging levels +# set defmt logging levels here default = [ "defmt-debug", # "dependency-a/defmt-trace", From b5538a89d52d89c1051000aa3ea78980fa2edfeb Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Wed, 14 Apr 2021 12:16:22 +0200 Subject: [PATCH 14/29] use 0.2.1 everywhere --- advanced/common/usb/Cargo.toml | 2 +- advanced/firmware/Cargo.toml | 2 +- beginner/apps/Cargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/advanced/common/usb/Cargo.toml b/advanced/common/usb/Cargo.toml index b77a48e..9b476d4 100644 --- a/advanced/common/usb/Cargo.toml +++ b/advanced/common/usb/Cargo.toml @@ -6,7 +6,7 @@ name = "usb" version = "0.0.0" [dependencies] -defmt = "0.2.0" +defmt = "0.2.1" [features] # set defmt logging levels here diff --git a/advanced/firmware/Cargo.toml b/advanced/firmware/Cargo.toml index eb052bb..85fd4a6 100644 --- a/advanced/firmware/Cargo.toml +++ b/advanced/firmware/Cargo.toml @@ -18,7 +18,7 @@ cortex-m-rtic = "0.5.1" dk = { path = "../../boards/dk", features = ["advanced"] } heapless = "0.5.5" panic-probe = { version = "0.2.0", features = ["print-defmt"] } -defmt = "0.2.0" +defmt = "0.2.1" defmt-rtt = "0.2.0" usb = { path = "../common/usb" } usb2 = "0.0.1" diff --git a/beginner/apps/Cargo.toml b/beginner/apps/Cargo.toml index 0670b4a..589ef2c 100644 --- a/beginner/apps/Cargo.toml +++ b/beginner/apps/Cargo.toml @@ -11,7 +11,7 @@ cortex-m-rt = "0.6.13" dk = { path = "../../boards/dk", features = ["beginner"] } heapless = "0.5.5" panic-probe = { version = "0.2.0", features = ["print-defmt"] } -defmt = "0.2.0" +defmt = "0.2.1" defmt-rtt = "0.2.0" # optimize code in both profiles From f8db9818acb834ea31f5ec966aa4b850f1958e22 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Thu, 8 Apr 2021 11:27:00 +0200 Subject: [PATCH 15/29] use `defmt` in training materials --- advanced/common/usb/Cargo.toml | 17 ++++- advanced/common/usb/src/lib.rs | 3 +- advanced/firmware/.cargo/config.toml | 1 + advanced/firmware/Cargo.toml | 22 ++++++- advanced/firmware/src/bin/events.rs | 13 ++-- advanced/firmware/src/bin/hello.rs | 5 +- .../firmware/src/bin/resource-solution.rs | 13 ++-- advanced/firmware/src/bin/resource.rs | 11 ++-- advanced/firmware/src/bin/rtic-hello.rs | 7 +- advanced/firmware/src/bin/stack_overflow.rs | 25 ++++--- advanced/firmware/src/bin/usb-1-solution.rs | 9 +-- advanced/firmware/src/bin/usb-1.rs | 10 +-- advanced/firmware/src/bin/usb-2-solution.rs | 11 ++-- advanced/firmware/src/bin/usb-2.rs | 12 ++-- advanced/firmware/src/bin/usb-3-solution.rs | 11 ++-- advanced/firmware/src/bin/usb-3.rs | 11 ++-- advanced/firmware/src/bin/usb-4-solution.rs | 17 +++-- advanced/firmware/src/bin/usb-4.rs | 17 +++-- advanced/firmware/src/bin/usb-5-solution.rs | 27 ++++---- advanced/firmware/src/bin/vec.rs | 12 ++-- advanced/firmware/src/lib.rs | 17 +++++ beginner/apps/.cargo/config.toml | 1 + beginner/apps/Cargo.toml | 22 ++++++- beginner/apps/src/bin/blinky.rs | 9 +-- beginner/apps/src/bin/hello.rs | 5 +- beginner/apps/src/bin/led.rs | 7 +- beginner/apps/src/bin/panic.rs | 5 +- beginner/apps/src/bin/radio-puzzle-1.rs | 11 ++-- beginner/apps/src/bin/radio-puzzle-2.rs | 7 +- beginner/apps/src/bin/radio-puzzle-3.rs | 11 ++-- beginner/apps/src/bin/radio-puzzle-4.rs | 12 ++-- beginner/apps/src/bin/radio-puzzle-5.rs | 9 +-- beginner/apps/src/bin/radio-puzzle-6.rs | 13 ++-- beginner/apps/src/bin/radio-puzzle-7.rs | 17 ++--- .../apps/src/bin/radio-puzzle-solution-2.rs | 17 ++--- .../apps/src/bin/radio-puzzle-solution.rs | 17 ++--- beginner/apps/src/bin/radio-puzzle.rs | 9 +-- beginner/apps/src/bin/radio-recv.rs | 14 ++-- beginner/apps/src/bin/radio-send.rs | 5 +- beginner/apps/src/bin/stack_overflow.rs | 5 +- beginner/apps/src/lib.rs | 17 +++++ boards/dk/Cargo.toml | 21 +++++- boards/dk/src/lib.rs | 65 +++++-------------- boards/dk/src/usbd.rs | 8 +-- common/panic-log/Cargo.toml | 18 ++++- common/panic-log/src/lib.rs | 2 +- embedded-workshop-book/src/error-handling.md | 4 +- embedded-workshop-book/src/interfaces.md | 2 +- embedded-workshop-book/src/messages.md | 8 +-- .../src/radio-puzzle-help.md | 2 +- embedded-workshop-book/src/time.md | 2 +- embedded-workshop-book/src/using-hal.md | 11 +++- 52 files changed, 381 insertions(+), 246 deletions(-) create mode 100644 advanced/firmware/src/lib.rs create mode 100644 beginner/apps/src/lib.rs diff --git a/advanced/common/usb/Cargo.toml b/advanced/common/usb/Cargo.toml index a5273c1..9b476d4 100644 --- a/advanced/common/usb/Cargo.toml +++ b/advanced/common/usb/Cargo.toml @@ -6,4 +6,19 @@ name = "usb" version = "0.0.0" [dependencies] -log = "0.4.8" +defmt = "0.2.1" + +[features] +# set defmt logging levels here +default = [ +"defmt-default", +# "dependency-a/defmt-trace", +] + +# do NOT modify these features +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] \ No newline at end of file diff --git a/advanced/common/usb/src/lib.rs b/advanced/common/usb/src/lib.rs index ce4b997..65fe58b 100644 --- a/advanced/common/usb/src/lib.rs +++ b/advanced/common/usb/src/lib.rs @@ -5,6 +5,7 @@ #![no_std] use core::num::NonZeroU8; +use defmt; /// Device address assigned by the host; will be in the range 1..=127 pub type Address = NonZeroU8; @@ -78,7 +79,7 @@ impl Request { Err(()) } } else { - log::warn!("unhandled case in `Request` parser"); + defmt::warn!("unhandled case in `Request` parser"); Err(()) } } diff --git a/advanced/firmware/.cargo/config.toml b/advanced/firmware/.cargo/config.toml index 5ccd822..4c4601e 100644 --- a/advanced/firmware/.cargo/config.toml +++ b/advanced/firmware/.cargo/config.toml @@ -2,6 +2,7 @@ # (..) rustflags = [ "-C", "linker=flip-link", # adds stack overflow protection + "-C", "link-arg=-Tdefmt.x", # defmt support # (..) ] diff --git a/advanced/firmware/Cargo.toml b/advanced/firmware/Cargo.toml index dafce5e..e8fb0cd 100644 --- a/advanced/firmware/Cargo.toml +++ b/advanced/firmware/Cargo.toml @@ -15,17 +15,18 @@ consts = { path = "../common/consts" } cortex-m = "0.6.4" cortex-m-rt = "0.6.13" cortex-m-rtic = "0.5.1" +defmt = "0.2.1" +defmt-rtt = "0.2.0" dk = { path = "../../boards/dk", features = ["advanced"] } heapless = "0.5.5" -log = "0.4.8" -panic-log = { path = "../../common/panic-log" } +panic-probe = { version = "0.2.0", features = ["print-defmt"] } usb = { path = "../common/usb" } usb2 = "0.0.1" # optimize code in both profiles [profile.dev] codegen-units = 1 -debug = 1 +debug = 2 debug-assertions = true # ! incremental = false lto = "fat" @@ -40,3 +41,18 @@ incremental = false lto = "fat" opt-level = 3 overflow-checks = false + +[features] + # set defmt logging levels here + default = [ + "defmt-default", + # "dependency-a/defmt-trace", + ] + + # do NOT modify these features + defmt-default = [] + defmt-trace = [] + defmt-debug = [] + defmt-info = [] + defmt-warn = [] + defmt-error = [] \ No newline at end of file diff --git a/advanced/firmware/src/bin/events.rs b/advanced/firmware/src/bin/events.rs index bb02c23..bf8d40d 100644 --- a/advanced/firmware/src/bin/events.rs +++ b/advanced/firmware/src/bin/events.rs @@ -2,7 +2,8 @@ #![no_std] use cortex_m::asm; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -22,7 +23,7 @@ const APP: () = { w.usbdetected().set_bit() }); - log::info!("USBDETECTED interrupt enabled"); + defmt::info!("USBDETECTED interrupt enabled"); // read the whole 32-bit usb supply register // the `read()` method returns a reader which can then be used to access the register content @@ -30,19 +31,19 @@ const APP: () = { // (the layout of the USBREGSTATUS register can be found in section 5.3.7.13 of the PS) let regstatus: u32 = power.usbregstatus.read().bits(); // ^^^^ complete register content - log::info!("USBREGSTATUS: {:b}", regstatus); + defmt::info!("USBREGSTATUS: {:b}", regstatus); // read the 1-bit VBUSDETECT field that is part of the USBREGSTATUS register content // to show that its contents reflect our usb connection status // (the USBDETECTED event that will trigger `on_power_event()` is derived from this information) let vbusdetect: bool = power.usbregstatus.read().vbusdetect().bits(); // ^^^^^^^^^^ bitfield name - log::info!("USBREGSTATUS.VBUSDETECT: {}", vbusdetect); + defmt::info!("USBREGSTATUS.VBUSDETECT: {}", vbusdetect); } #[idle] fn main(_cx: main::Context) -> ! { - log::info!("idle: going to sleep"); + defmt::info!("idle: going to sleep"); // sleep in the background loop { @@ -52,7 +53,7 @@ const APP: () = { #[task(binds = POWER_CLOCK)] fn on_power_event(_cx: on_power_event::Context) { - log::info!("POWER event occurred"); + defmt::info!("POWER event occurred"); dk::exit() } }; diff --git a/advanced/firmware/src/bin/hello.rs b/advanced/firmware/src/bin/hello.rs index 8ae0ce5..af489e8 100644 --- a/advanced/firmware/src/bin/hello.rs +++ b/advanced/firmware/src/bin/hello.rs @@ -3,14 +3,15 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[entry] fn main() -> ! { // board initialization dk::init().unwrap(); - log::info!("Hello, world!"); + defmt::info!("Hello, world!"); loop { asm::bkpt(); diff --git a/advanced/firmware/src/bin/resource-solution.rs b/advanced/firmware/src/bin/resource-solution.rs index 89b5c5d..ecc0b66 100644 --- a/advanced/firmware/src/bin/resource-solution.rs +++ b/advanced/firmware/src/bin/resource-solution.rs @@ -3,7 +3,8 @@ use cortex_m::asm; use dk::peripheral::POWER; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -20,7 +21,7 @@ const APP: () = { power.intenset.write(|w| w.usbdetected().set_bit()); - log::info!("USBDETECTED interrupt enabled"); + defmt::info!("USBDETECTED interrupt enabled"); init::LateResources { power, @@ -31,23 +32,23 @@ const APP: () = { #[idle] fn main(_cx: main::Context) -> ! { loop { - log::info!("idle: going to sleep"); + defmt::info!("idle: going to sleep"); asm::wfi(); - log::info!("idle: woke up"); + defmt::info!("idle: woke up"); } } #[task(binds = POWER_CLOCK, resources = [power, counter])] // ^^^^^^^ we want to access the resource from here fn on_power_event(cx: on_power_event::Context) { - log::debug!("POWER event occurred"); + defmt::debug!("POWER event occurred"); let power = cx.resources.power; let counter = cx.resources.counter; *counter += 1; let n = *counter; - log::info!( + defmt::info!( "on_power_event: cable connected {} time{}", n, if n != 1 { "s" } else { "" } diff --git a/advanced/firmware/src/bin/resource.rs b/advanced/firmware/src/bin/resource.rs index 9cd2e1c..b43e6c7 100644 --- a/advanced/firmware/src/bin/resource.rs +++ b/advanced/firmware/src/bin/resource.rs @@ -3,7 +3,8 @@ use cortex_m::asm; use dk::peripheral::POWER; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -19,7 +20,7 @@ const APP: () = { power.intenset.write(|w| w.usbdetected().set_bit()); - log::info!("USBDETECTED interrupt enabled"); + defmt::info!("USBDETECTED interrupt enabled"); init::LateResources { power, // <- resource initialization @@ -29,16 +30,16 @@ const APP: () = { #[idle] fn main(_cx: main::Context) -> ! { loop { - log::info!("idle: going to sleep"); + defmt::info!("idle: going to sleep"); asm::wfi(); - log::info!("idle: woke up"); + defmt::info!("idle: woke up"); } } #[task(binds = POWER_CLOCK, resources = [power])] // ^^^^^^^ resource access list fn on_power_event(cx: on_power_event::Context) { - log::info!("POWER event occurred"); + defmt::info!("POWER event occurred"); // resources available to this task let resources = cx.resources; diff --git a/advanced/firmware/src/bin/rtic-hello.rs b/advanced/firmware/src/bin/rtic-hello.rs index 055f490..68869ff 100644 --- a/advanced/firmware/src/bin/rtic-hello.rs +++ b/advanced/firmware/src/bin/rtic-hello.rs @@ -2,7 +2,8 @@ #![no_std] use cortex_m::asm; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -10,12 +11,12 @@ const APP: () = { fn init(_cx: init::Context) { dk::init().unwrap(); - log::info!("Hello"); + defmt::info!("Hello"); } #[idle] fn main(_cx: main::Context) -> ! { - log::info!("world!"); + defmt::info!("world!"); loop { asm::bkpt(); diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index da80959..2546126 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -3,15 +3,15 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[entry] fn main() -> ! { // board initialization dk::init().unwrap(); - log::info!("provoking stack overflow..."); - spam(0); + defmt::info!("fib(100) = {:?}", fib(100)); loop { asm::bkpt(); @@ -19,16 +19,13 @@ fn main() -> ! { } #[inline(never)] -fn spam(n: u32) { - // allocate and initialize 4 kilobytes of stack memory to provoke stack overflow - let use_stack = [n; 1024]; +fn fib(n: u32) -> u32 { + // allocate and initialize one kilobyte of stack memory to provoke stack overflow + let _use_stack = [0xAA; 1024]; - log::info!( - "address of current `use_stack` at recursion depth {:?}: {:?}", - use_stack[1023], // "use" use_stack to prevent it from being optimized out - &use_stack as *const u32 - ); - - let next = n + 1; - spam(next); // infinite recursion + if n < 2 { + 1 + } else { + fib(n - 1) + fib(n - 2) // recursion + } } diff --git a/advanced/firmware/src/bin/usb-1-solution.rs b/advanced/firmware/src/bin/usb-1-solution.rs index d9bcfbc..a8e35bf 100644 --- a/advanced/firmware/src/bin/usb-1-solution.rs +++ b/advanced/firmware/src/bin/usb-1-solution.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -33,18 +34,18 @@ const APP: () = { }; fn on_event(_usbd: &USBD, event: Event) { - log::info!("USB: {:?}", event); + defmt::info!("USB: {:?}", event); match event { Event::UsbReset => { // going from the Default state to the Default state is a no-operation - log::info!("returning to the Default state"); + defmt::info!("returning to the Default state"); } Event::UsbEp0DataDone => todo!(), Event::UsbEp0Setup => { - log::info!("goal reached; move to the next section"); + defmt::info!("goal reached; move to the next section"); dk::exit() } } diff --git a/advanced/firmware/src/bin/usb-1.rs b/advanced/firmware/src/bin/usb-1.rs index c95b045..0f6dd2e 100644 --- a/advanced/firmware/src/bin/usb-1.rs +++ b/advanced/firmware/src/bin/usb-1.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[rtic::app(device = dk)] const APP: () = { @@ -21,7 +22,7 @@ const APP: () = { // NOTE this will block if the USB cable is not connected to port J3 usbd::init(board.power, &board.usbd); - log::info!("USBD initialized"); + defmt::info!("USBD initialized"); init::LateResources { usbd: board.usbd } } @@ -37,7 +38,7 @@ const APP: () = { }; fn on_event(_usbd: &USBD, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => todo!(), @@ -45,7 +46,8 @@ fn on_event(_usbd: &USBD, event: Event) { Event::UsbEp0DataDone => todo!(), // leave this at it is for now. Event::UsbEp0Setup => { - log::info!("goal reached; move to the next section"); + defmt::info!("goal reached; move to the next section"); + dk::exit() } } } diff --git a/advanced/firmware/src/bin/usb-2-solution.rs b/advanced/firmware/src/bin/usb-2-solution.rs index fe2ce55..cd8a858 100644 --- a/advanced/firmware/src/bin/usb-2-solution.rs +++ b/advanced/firmware/src/bin/usb-2-solution.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb::{Descriptor, Request}; #[rtic::app(device = dk)] @@ -34,7 +35,7 @@ const APP: () = { }; fn on_event(usbd: &USBD, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { @@ -69,7 +70,7 @@ fn on_event(usbd: &USBD, event: Event) { // let windex = usbd::windex(usbd); // let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -84,9 +85,9 @@ fn on_event(usbd: &USBD, event: Event) { Request::GetDescriptor { descriptor, length } if descriptor == Descriptor::Device => { - log::info!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); - log::info!("Goal reached; move to the next section"); + defmt::info!("Goal reached; move to the next section"); dk::exit() } Request::SetAddress { .. } => { diff --git a/advanced/firmware/src/bin/usb-2.rs b/advanced/firmware/src/bin/usb-2.rs index c8b07f2..648c475 100644 --- a/advanced/firmware/src/bin/usb-2.rs +++ b/advanced/firmware/src/bin/usb-2.rs @@ -5,7 +5,9 @@ use dk::{ peripheral::USBD, usbd::{self, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; + use usb::{Descriptor, Request}; #[rtic::app(device = dk)] @@ -34,7 +36,7 @@ const APP: () = { }; fn on_event(_usbd: &USBD, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { @@ -61,7 +63,7 @@ fn on_event(_usbd: &USBD, event: Event) { // composed of a high register (WVALUEH) and a low register (WVALUEL) let wvalue: u16 = 0; - log::info!( + defmt::info!( "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -79,9 +81,9 @@ fn on_event(_usbd: &USBD, event: Event) { // TODO modify `Request::parse()` in `advanced/common/usb/lib.rs` // so that this branch is reached - log::info!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); - log::info!("Goal reached; move to the next section"); + defmt::info!("Goal reached; move to the next section"); dk::exit() } Request::SetAddress { .. } => { diff --git a/advanced/firmware/src/bin/usb-3-solution.rs b/advanced/firmware/src/bin/usb-3-solution.rs index f4d0fa0..f5a4476 100644 --- a/advanced/firmware/src/bin/usb-3-solution.rs +++ b/advanced/firmware/src/bin/usb-3-solution.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb::{Descriptor, Request}; #[rtic::app(device = dk)] @@ -39,7 +40,7 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { @@ -55,7 +56,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -71,7 +72,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { Request::GetDescriptor { descriptor, length } if descriptor == Descriptor::Device => { - log::info!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); let desc = usb2::device::Descriptor { bDeviceClass: 0, @@ -96,7 +97,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { // but for now it's OK to do nothing. } _ => { - log::error!( + defmt::error!( "unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" ); dk::exit() diff --git a/advanced/firmware/src/bin/usb-3.rs b/advanced/firmware/src/bin/usb-3.rs index bd3799b..6e74b22 100644 --- a/advanced/firmware/src/bin/usb-3.rs +++ b/advanced/firmware/src/bin/usb-3.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb::{Descriptor, Request}; #[rtic::app(device = dk)] @@ -39,7 +40,7 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { @@ -55,7 +56,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -71,7 +72,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { Request::GetDescriptor { descriptor, length } if descriptor == Descriptor::Device => { - log::info!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); // TODO send back a valid device descriptor, truncated to `length` bytes // let desc = usb2::device::Descriptor { .. }; @@ -84,7 +85,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { // but for now it's OK to do nothing. } _ => { - log::error!( + defmt::error!( "unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" ); dk::exit() diff --git a/advanced/firmware/src/bin/usb-4-solution.rs b/advanced/firmware/src/bin/usb-4-solution.rs index 2301173..49ef01a 100644 --- a/advanced/firmware/src/bin/usb-4-solution.rs +++ b/advanced/firmware/src/bin/usb-4-solution.rs @@ -7,7 +7,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State}; #[rtic::app(device = dk)] @@ -44,22 +45,22 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { - log::info!("USB reset condition detected"); + defmt::info!("USB reset condition detected"); *state = State::Default; } Event::UsbEp0DataDone => { - log::info!("EP0IN: transfer complete"); + defmt::info!("EP0IN: transfer complete"); ep0in.end(usbd); } Event::UsbEp0Setup => { if ep0setup(usbd, ep0in, state).is_err() { - log::warn!("EP0IN: unexpected request; stalling the endpoint"); + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); usbd::ep0stall(usbd); } } @@ -76,7 +77,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -87,7 +88,9 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); - log::info!("EP0: {:?}", request); + defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log + // `StandardRequest` with `defmt` match request { // section 9.4.3 diff --git a/advanced/firmware/src/bin/usb-4.rs b/advanced/firmware/src/bin/usb-4.rs index 3375ef5..a9c1e14 100644 --- a/advanced/firmware/src/bin/usb-4.rs +++ b/advanced/firmware/src/bin/usb-4.rs @@ -5,7 +5,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb2::State; // HEADS UP to use *your* USB packet parser uncomment line 12 and remove line 13 @@ -46,17 +47,17 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { // TODO change `state` as specified in chapter 9.1 USB Device States, of the USB specification Event::UsbReset => { - log::info!("USB reset condition detected"); + defmt::info!("USB reset condition detected"); todo!(); } Event::UsbEp0DataDone => { - log::info!("EP0IN: transfer complete"); + defmt::info!("EP0IN: transfer complete"); ep0in.end(usbd); } @@ -64,7 +65,7 @@ fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { if ep0setup(usbd, ep0in, state).is_err() { // unsupported or invalid request: // TODO: add code to stall the endpoint - log::warn!("EP0IN: unexpected request; stalling the endpoint"); + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); } } } @@ -77,7 +78,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), () let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -88,7 +89,9 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), () let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); - log::info!("EP0: {:?}", request); + defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log + // `StandardRequest` with `defmt` match request { Request::GetDescriptor { descriptor, length } => match descriptor { diff --git a/advanced/firmware/src/bin/usb-5-solution.rs b/advanced/firmware/src/bin/usb-5-solution.rs index 34f0228..853bda1 100644 --- a/advanced/firmware/src/bin/usb-5-solution.rs +++ b/advanced/firmware/src/bin/usb-5-solution.rs @@ -7,7 +7,8 @@ use dk::{ peripheral::USBD, usbd::{self, Ep0In, Event}, }; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State}; #[rtic::app(device = dk)] @@ -44,22 +45,22 @@ const APP: () = { }; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - log::info!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event { Event::UsbReset => { - log::info!("USB reset condition detected"); + defmt::info!("USB reset condition detected"); *state = State::Default; } Event::UsbEp0DataDone => { - log::info!("EP0IN: transfer complete"); + defmt::info!("EP0IN: transfer complete"); ep0in.end(usbd); } Event::UsbEp0Setup => { if ep0setup(usbd, ep0in, state).is_err() { - log::warn!("EP0IN: unexpected request; stalling the endpoint"); + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); usbd::ep0stall(usbd); } } @@ -76,7 +77,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - log::info!( + defmt::info!( "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype, brequest, @@ -87,7 +88,9 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); - log::info!("EP0: {:?}", request); + defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log + // `StandardRequest` with `defmt` match request { // section 9.4.3 @@ -185,10 +188,10 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> State::Address(address) => { if let Some(value) = value { if value.get() == CONFIG_VAL { - log::info!("entering the configured state"); + defmt::info!("entering the configured state"); *state = State::Configured { address, value }; } else { - log::error!("unsupported configuration value"); + defmt::error!("unsupported configuration value"); return Err(()); } } else { @@ -203,18 +206,18 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> if let Some(new_value) = value { if new_value.get() == CONFIG_VAL { if new_value != curr_value { - log::info!("changing configuration"); + defmt::info!("changing configuration"); *state = State::Configured { address, value: new_value, }; } } else { - log::error!("unsupported configuration value"); + defmt::error!("unsupported configuration value"); return Err(()); } } else { - log::info!("returned to the address state"); + defmt::info!("returned to the address state"); *state = State::Address(address); } } diff --git a/advanced/firmware/src/bin/vec.rs b/advanced/firmware/src/bin/vec.rs index a6580ca..f8b42b2 100644 --- a/advanced/firmware/src/bin/vec.rs +++ b/advanced/firmware/src/bin/vec.rs @@ -4,7 +4,8 @@ use cortex_m_rt::entry; use heapless::{consts, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use firmware as _; #[entry] fn main() -> ! { @@ -16,13 +17,16 @@ fn main() -> ! { // `heapless::Vec` exposes the same API surface as `std::Vec` but some of its methods return a // `Result` to indicate whether the operation failed due to the `heapless::Vec` being full - log::info!("start: {:?}", buffer); + defmt::info!("start: {:?}", defmt::Debug2Format(&buffer)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log + // `heapless` data structures (like `Vec` here) + // with `defmt` buffer.push(0).expect("buffer full"); - log::info!("after `push`: {:?}", buffer); + defmt::info!("after `push`: {:?}", defmt::Debug2Format(&buffer)); buffer.extend_from_slice(&[1, 2, 3]).expect("buffer full"); - log::info!("after `extend`: {:?}", buffer); + defmt::info!("after `extend`: {:?}", defmt::Debug2Format(&buffer)); // TODO try this operation // buffer.extend_from_slice(&[4, 5, 6, 7]).expect("buffer full"); diff --git a/advanced/firmware/src/lib.rs b/advanced/firmware/src/lib.rs new file mode 100644 index 0000000..7480423 --- /dev/null +++ b/advanced/firmware/src/lib.rs @@ -0,0 +1,17 @@ +#![no_std] + +use panic_probe as _; + +// same panicking *behavior* as `panic-probe` but doesn't print a panic message +// this prevents the panic message being printed *twice* when `defmt::panic` is invoked +#[defmt::panic_handler] +fn panic() -> ! { + cortex_m::asm::udf() +} + +/// Terminates the application and makes `probe-run` exit with exit-code = 0 +pub fn exit() -> ! { + loop { + cortex_m::asm::bkpt(); + } +} diff --git a/beginner/apps/.cargo/config.toml b/beginner/apps/.cargo/config.toml index 4b518a8..abfd4b6 100644 --- a/beginner/apps/.cargo/config.toml +++ b/beginner/apps/.cargo/config.toml @@ -2,6 +2,7 @@ # (..) rustflags = [ "-C", "linker=flip-link", # adds stack overflow protection + "-C", "link-arg=-Tdefmt.x", # defmt support # (..) ] diff --git a/beginner/apps/Cargo.toml b/beginner/apps/Cargo.toml index 991b60d..8ec6de1 100644 --- a/beginner/apps/Cargo.toml +++ b/beginner/apps/Cargo.toml @@ -8,15 +8,16 @@ version = "0.0.0" [dependencies] cortex-m = "0.6.4" cortex-m-rt = "0.6.13" +defmt = "0.2.1" +defmt-rtt = "0.2.0" dk = { path = "../../boards/dk", features = ["beginner"] } heapless = "0.5.5" -log = "0.4.8" -panic-log = { path = "../../common/panic-log" } +panic-probe = { version = "0.2.0", features = ["print-defmt"] } # optimize code in both profiles [profile.dev] codegen-units = 1 -debug = 1 +debug = 2 debug-assertions = true # ! incremental = false lto = "fat" @@ -31,3 +32,18 @@ incremental = false lto = "fat" opt-level = 3 overflow-checks = false + +[features] +# set defmt logging levels here +default = [ + "defmt-default", + # "dependency-a/defmt-trace", +] + +# do NOT modify these features +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] \ No newline at end of file diff --git a/beginner/apps/src/bin/blinky.rs b/beginner/apps/src/bin/blinky.rs index 1548525..a3e10b1 100644 --- a/beginner/apps/src/bin/blinky.rs +++ b/beginner/apps/src/bin/blinky.rs @@ -4,12 +4,13 @@ use core::time::Duration; use cortex_m_rt::entry; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { - // uncomment to enable more verbose logs - // log::set_max_level(log::LevelFilter::Trace); + // to enable more verbose logs, go to your `Cargo.toml` and set defmt logging levels + // to `defmt-trace` by changing the `default = []` entry in `[features]` let board = dk::init().unwrap(); @@ -19,7 +20,7 @@ fn main() -> ! { for _ in 0..10 { led.toggle(); timer.wait(Duration::from_secs(1)); - log::info!("LED toggled at {:?}", dk::uptime()); + defmt::info!("LED toggled at {:?}", dk::uptime()); } dk::exit() diff --git a/beginner/apps/src/bin/hello.rs b/beginner/apps/src/bin/hello.rs index 8a5605d..0c40dce 100644 --- a/beginner/apps/src/bin/hello.rs +++ b/beginner/apps/src/bin/hello.rs @@ -6,7 +6,8 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; // the custom entry point // vvvvv @@ -18,7 +19,7 @@ fn main() -> ! { // initializes the peripherals dk::init().unwrap(); - log::info!("Hello, world!"); // :wave: + defmt::info!("Hello, world!"); // :wave: loop { // breakpoint: halts the program's execution diff --git a/beginner/apps/src/bin/led.rs b/beginner/apps/src/bin/led.rs index f037c3f..2131134 100644 --- a/beginner/apps/src/bin/led.rs +++ b/beginner/apps/src/bin/led.rs @@ -3,12 +3,13 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { - // uncomment to make logs more verbose - // log::set_max_level(log::LevelFilter::Trace); + // to enable more verbose logs, go to your `Cargo.toml` and set defmt logging levels + // to `defmt-trace` by changing the `default = []` entry in `[features]` let board = dk::init().unwrap(); diff --git a/beginner/apps/src/bin/panic.rs b/beginner/apps/src/bin/panic.rs index eb86bc7..31ab30a 100644 --- a/beginner/apps/src/bin/panic.rs +++ b/beginner/apps/src/bin/panic.rs @@ -3,7 +3,8 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { @@ -28,7 +29,7 @@ fn bar() { let array = [0, 1, 2]; let x = array[i]; // out of bounds access - log::info!("{}", x); + defmt::info!("{}", x); } fn index() -> usize { diff --git a/beginner/apps/src/bin/radio-puzzle-1.rs b/beginner/apps/src/bin/radio-puzzle-1.rs index 916df34..95f1946 100644 --- a/beginner/apps/src/bin/radio-puzzle-1.rs +++ b/beginner/apps/src/bin/radio-puzzle-1.rs @@ -4,7 +4,8 @@ use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -37,15 +38,15 @@ fn main() -> ! { if packet.len() == 1 { let destination = packet[0]; - log::info!("{} -> {}", source, destination); + defmt::info!("{} -> {}", source, destination); // or cast to `char` for a more readable output - log::info!("{:?} -> {:?}", source as char, destination as char); + defmt::info!("{:?} -> {:?}", source as char, destination as char); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } diff --git a/beginner/apps/src/bin/radio-puzzle-2.rs b/beginner/apps/src/bin/radio-puzzle-2.rs index cfb8d53..083ed35 100644 --- a/beginner/apps/src/bin/radio-puzzle-2.rs +++ b/beginner/apps/src/bin/radio-puzzle-2.rs @@ -7,7 +7,8 @@ use cortex_m_rt::entry; // lookup performance when the dictionary contains a large number of items but performance is // not important for this exercise use heapless::{consts, LinearMap}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { @@ -25,9 +26,9 @@ fn main() -> ! { let key = b'A'; let value = dict[&key]; // the key needs to be passed by reference - log::info!("{} -> {}", key, value); + defmt::info!("{} -> {}", key, value); // more readable - log::info!("{:?} -> {:?}", key as char, value as char); + defmt::info!("{:?} -> {:?}", key as char, value as char); // TODO try another insertion // TODO try looking up a key not contained in the dictionary diff --git a/beginner/apps/src/bin/radio-puzzle-3.rs b/beginner/apps/src/bin/radio-puzzle-3.rs index 845f0e9..dea6b6d 100644 --- a/beginner/apps/src/bin/radio-puzzle-3.rs +++ b/beginner/apps/src/bin/radio-puzzle-3.rs @@ -5,7 +5,8 @@ use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -36,16 +37,18 @@ fn main() -> ! { // TODO insert the key-value pair // dict.insert(/* ? */, /* ? */).expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } - log::info!("{:?}", dict); + defmt::info!("{:?}", defmt::Debug2Format(&dict)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log `heapless` + // data structures (like `LinearMap` here) with `defmt` dk::exit() } diff --git a/beginner/apps/src/bin/radio-puzzle-4.rs b/beginner/apps/src/bin/radio-puzzle-4.rs index 585b481..7b5950d 100644 --- a/beginner/apps/src/bin/radio-puzzle-4.rs +++ b/beginner/apps/src/bin/radio-puzzle-4.rs @@ -6,7 +6,8 @@ use core::str; use cortex_m_rt::entry; use heapless::{consts, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { @@ -21,10 +22,13 @@ fn main() -> ! { buffer.push(b'i').expect("buffer full"); // look into the contents so far - log::info!("{:?}", buffer); + defmt::info!("{:?}", defmt::Debug2Format(&buffer)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log `heapless` + // data structures (like `Vec` here) with `defmt` + // or more readable - // NOTE as long as you only push bytes in the ASCII range (0..=127) the conversion should work - log::info!( + // NOTE utf-8 conversion works as long as you only push bytes in the ASCII range (0..=127) + defmt::info!( "{}", str::from_utf8(&buffer).expect("content was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle-5.rs b/beginner/apps/src/bin/radio-puzzle-5.rs index 50dc9da..80be341 100644 --- a/beginner/apps/src/bin/radio-puzzle-5.rs +++ b/beginner/apps/src/bin/radio-puzzle-5.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -27,11 +28,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -47,7 +48,7 @@ fn main() -> ! { buf.push(output).expect("buffer full"); } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&buf).expect("buffer contains non-UTF-8 data") ); diff --git a/beginner/apps/src/bin/radio-puzzle-6.rs b/beginner/apps/src/bin/radio-puzzle-6.rs index 4d9ca39..9ff925b 100644 --- a/beginner/apps/src/bin/radio-puzzle-6.rs +++ b/beginner/apps/src/bin/radio-puzzle-6.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -37,11 +38,11 @@ fn main() -> ! { // TODO insert the key-value pair // dict.insert(/* ? */, /* ? */).expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } @@ -51,11 +52,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -71,7 +72,7 @@ fn main() -> ! { buffer.push(value).expect("buffer full"); } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") ); diff --git a/beginner/apps/src/bin/radio-puzzle-7.rs b/beginner/apps/src/bin/radio-puzzle-7.rs index 933f0d9..be25024 100644 --- a/beginner/apps/src/bin/radio-puzzle-7.rs +++ b/beginner/apps/src/bin/radio-puzzle-7.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -37,11 +38,11 @@ fn main() -> ! { // TODO insert the key-value pair // dict.insert(/* ? */, /* ? */).expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } @@ -51,11 +52,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -71,7 +72,7 @@ fn main() -> ! { buffer.push(value).expect("buffer full"); } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") ); @@ -82,11 +83,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "Dongle response: {}", str::from_utf8(&packet).expect("response was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle-solution-2.rs b/beginner/apps/src/bin/radio-puzzle-solution-2.rs index 5683bc9..75205d0 100644 --- a/beginner/apps/src/bin/radio-puzzle-solution-2.rs +++ b/beginner/apps/src/bin/radio-puzzle-solution-2.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -38,11 +39,11 @@ fn main() -> ! { dict.insert(cipherletter, plainletter) .expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } @@ -52,11 +53,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -74,7 +75,7 @@ fn main() -> ! { *spot = plainletter; } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&packet).expect("buffer contains non-UTF-8 data") ); @@ -83,11 +84,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "Dongle response: {}", str::from_utf8(&packet).expect("response was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle-solution.rs b/beginner/apps/src/bin/radio-puzzle-solution.rs index cb12287..4988ddd 100644 --- a/beginner/apps/src/bin/radio-puzzle-solution.rs +++ b/beginner/apps/src/bin/radio-puzzle-solution.rs @@ -7,7 +7,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; use heapless::{consts, LinearMap, Vec}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -41,11 +42,11 @@ fn main() -> ! { dict.insert(cipherletter, plainletter) .expect("dictionary full"); } else { - log::error!("response packet was not a single byte"); + defmt::error!("response packet was not a single byte"); dk::exit() } } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } } @@ -55,11 +56,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -76,7 +77,7 @@ fn main() -> ! { buffer.push(plainletter).expect("buffer full"); } - log::info!( + defmt::info!( "plaintext: {}", str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") ); @@ -87,11 +88,11 @@ fn main() -> ! { radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_err() { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); dk::exit() } - log::info!( + defmt::info!( "Dongle response: {}", str::from_utf8(&packet).expect("response was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle.rs b/beginner/apps/src/bin/radio-puzzle.rs index 619905f..522cb99 100644 --- a/beginner/apps/src/bin/radio-puzzle.rs +++ b/beginner/apps/src/bin/radio-puzzle.rs @@ -6,7 +6,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -33,19 +34,19 @@ fn main() -> ! { // let msg = b"Hello?"; packet.copy_from_slice(msg); - log::info!( + defmt::info!( "sending: {}", str::from_utf8(msg).expect("msg was not valid UTF-8 data") ); radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_ok() { - log::info!( + defmt::info!( "received: {}", str::from_utf8(&packet).expect("response was not valid UTF-8 data") ); } else { - log::error!("no response or response packet was corrupted"); + defmt::error!("no response or response packet was corrupted"); } dk::exit() } diff --git a/beginner/apps/src/bin/radio-recv.rs b/beginner/apps/src/bin/radio-recv.rs index 732f311..d1f4fe3 100644 --- a/beginner/apps/src/bin/radio-recv.rs +++ b/beginner/apps/src/bin/radio-recv.rs @@ -6,7 +6,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Error, Packet}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; const TEN_MS: u32 = 10_000; @@ -24,7 +25,7 @@ fn main() -> ! { let msg = b"olleh"; packet.copy_from_slice(msg); - log::info!( + defmt::info!( "sending: {}", str::from_utf8(msg).expect("message is not valid UTF-8") ); @@ -37,14 +38,15 @@ fn main() -> ! { match res { Ok(crc) => { - log::info!( - "received: {} (CRC={})", + defmt::info!( + "received: {} (CRC = {:X})", + // ^^ print as uppercase hexadecimal str::from_utf8(&*packet).expect("response is not valid UTF-8"), crc ); } - Err(Error::Crc(crc)) => log::error!("invalid CRC: {:06x}", crc), - Err(Error::Timeout) => log::error!("no response within {} ms", TEN_MS / 1_000), + Err(Error::Crc(crc)) => defmt::error!("invalid CRC: {=u16:x}", crc), + Err(Error::Timeout) => defmt::error!("no response within {} ms", TEN_MS / 1_000), } dk::exit() diff --git a/beginner/apps/src/bin/radio-send.rs b/beginner/apps/src/bin/radio-send.rs index 4f411df..4d09180 100644 --- a/beginner/apps/src/bin/radio-send.rs +++ b/beginner/apps/src/bin/radio-send.rs @@ -6,7 +6,8 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet, TxPower}; -use panic_log as _; // the panicking behavior +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { @@ -25,7 +26,7 @@ fn main() -> ! { // let msg: &[u8; 5] = &[b'H', b'e', b'l', b'l', b'o']; // let msg: &[u8; 5] = b"Hello"; - log::info!( + defmt::info!( "sending: {}", str::from_utf8(msg).expect("msg is not valid UTF-8 data") ); diff --git a/beginner/apps/src/bin/stack_overflow.rs b/beginner/apps/src/bin/stack_overflow.rs index e5930e8..b06cb53 100644 --- a/beginner/apps/src/bin/stack_overflow.rs +++ b/beginner/apps/src/bin/stack_overflow.rs @@ -3,14 +3,15 @@ use cortex_m::asm; use cortex_m_rt::entry; -use panic_log as _; // panic handler +// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior +use apps as _; #[entry] fn main() -> ! { // board initialization dk::init().unwrap(); - log::info!("fib(100) = {:?}", fib(100)); + defmt::info!("fib(100) = {:?}", fib(100)); loop { asm::bkpt(); diff --git a/beginner/apps/src/lib.rs b/beginner/apps/src/lib.rs new file mode 100644 index 0000000..7480423 --- /dev/null +++ b/beginner/apps/src/lib.rs @@ -0,0 +1,17 @@ +#![no_std] + +use panic_probe as _; + +// same panicking *behavior* as `panic-probe` but doesn't print a panic message +// this prevents the panic message being printed *twice* when `defmt::panic` is invoked +#[defmt::panic_handler] +fn panic() -> ! { + cortex_m::asm::udf() +} + +/// Terminates the application and makes `probe-run` exit with exit-code = 0 +pub fn exit() -> ! { + loop { + cortex_m::asm::bkpt(); + } +} diff --git a/boards/dk/Cargo.toml b/boards/dk/Cargo.toml index e844710..c79c839 100644 --- a/boards/dk/Cargo.toml +++ b/boards/dk/Cargo.toml @@ -8,11 +8,26 @@ version = "0.0.0" [dependencies] cortex-m = "0.6.4" cortex-m-rt = "0.6.13" +defmt = "0.2.1" +defmt-rtt = "0.2.0" embedded-hal = "0.2.3" hal = { package = "nrf52840-hal", version = "0.12.1" } -log = "0.4.8" -rtt-target = { version = "0.2.0", features = ["cortex-m"] } +panic-probe = { version = "0.2.0", features = ["print-defmt" ] } [features] +advanced = [] beginner = [] -advanced = [] \ No newline at end of file + +# set defmt logging levels here +default = [ + "defmt-info", + # "dependency-a/defmt-trace", +] + +# do NOT modify these features +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] diff --git a/boards/dk/src/lib.rs b/boards/dk/src/lib.rs index aaa1005..a368db6 100644 --- a/boards/dk/src/lib.rs +++ b/boards/dk/src/lib.rs @@ -21,10 +21,10 @@ use hal::{ rtc::{Rtc, RtcInterrupt}, timer::OneShot, }; -use log::{LevelFilter, Log}; -use rtt_target::rprintln; + +use defmt; #[cfg(any(feature = "beginner", feature = "advanced"))] -use rtt_target::rtt_init_print; +use defmt_rtt as _; // global logger #[cfg(feature = "advanced")] use crate::{ @@ -79,7 +79,7 @@ pub struct Led { impl Led { /// Turns on the LED pub fn on(&mut self) { - log::trace!( + defmt::trace!( "setting P{}.{} low (LED on)", if self.inner.port() == Port::Port1 { '1' @@ -95,7 +95,7 @@ impl Led { /// Turns off the LED pub fn off(&mut self) { - log::trace!( + defmt::trace!( "setting P{}.{} high (LED off)", if self.inner.port() == Port::Port1 { '1' @@ -137,7 +137,7 @@ pub struct Timer { impl Timer { /// Blocks program execution for at least the specified `duration` pub fn wait(&mut self, duration: Duration) { - log::trace!("blocking for {:?} ...", duration); + defmt::trace!("blocking for {:?} ...", duration); // 1 cycle = 1 microsecond const NANOS_IN_ONE_MICRO: u32 = 1_000; @@ -164,7 +164,7 @@ impl Timer { self.inner.delay(cycles) } - log::trace!("... DONE"); + defmt::trace!("... DONE"); } } @@ -195,21 +195,7 @@ pub fn init() -> Result { Clocks, > = None; - // NOTE this must be executed as early as possible or the tool will timeout - // NOTE the unsafety of this macro is incorrect; it must be run at most once - #[cfg(feature = "beginner")] - rtt_init_print!(BlockIfFull, 16384); - #[cfg(feature = "advanced")] - rtt_init_print!(NoBlockSkip, 16384); - - log::set_logger(&Logger).unwrap(); - - // if not configured in the application we default to the `Info` level - if log::max_level() == LevelFilter::Off { - log::set_max_level(LevelFilter::Info) - } - - log::debug!("Initializing the board"); + defmt::debug!("Initializing the board"); let clocks = Clocks::new(periph.CLOCK); let clocks = clocks.enable_ext_hfosc(); @@ -220,7 +206,7 @@ pub fn init() -> Result { #[cfg(feature = "beginner")] let clocks = unsafe { CLOCKS.get_or_insert(_clocks) }; - log::debug!("Clocks configured"); + defmt::debug!("Clocks configured"); let mut rtc = Rtc::new(periph.RTC0, 0).unwrap(); rtc.enable_interrupt(RtcInterrupt::Overflow, None); @@ -239,7 +225,7 @@ pub fn init() -> Result { // mechanism) unsafe { NVIC::unmask(Interrupt::RTC0) }; - log::debug!("RTC started"); + defmt::debug!("RTC started"); let pins = p0::Parts::new(periph.P0); @@ -249,7 +235,7 @@ pub fn init() -> Result { let _3 = pins.p0_15.degrade().into_push_pull_output(Level::High); let _4 = pins.p0_16.degrade().into_push_pull_output(Level::High); - log::debug!("I/O pins have been configured for digital output"); + defmt::debug!("I/O pins have been configured for digital output"); let timer = hal::Timer::new(periph.TIMER0); @@ -259,7 +245,9 @@ pub fn init() -> Result { // set TX power to its maximum value radio.set_txpower(ieee802154::TxPower::Pos8dBm); - log::debug!("Radio initialized and configured with TX power set to the maximum value"); + defmt::debug!( + "Radio initialized and configured with TX power set to the maximum value" + ); radio }; @@ -285,29 +273,6 @@ pub fn init() -> Result { } } -struct Logger; - -impl Log for Logger { - fn enabled(&self, metadata: &log::Metadata) -> bool { - metadata.level() <= log::STATIC_MAX_LEVEL - } - - fn log(&self, record: &log::Record) { - if !self.enabled(record.metadata()) { - return; - } - - rprintln!( - "{}:{} -- {}", - record.level(), - record.target(), - record.args() - ); - } - - fn flush(&self) {} -} - // Counter of OVERFLOW events -- an OVERFLOW occurs every (1<<24) ticks static OVERFLOWS: AtomicU32 = AtomicU32::new(0); @@ -324,7 +289,7 @@ fn RTC0() { /// Exits the application and prints a backtrace when the program is executed through the `probe-run` /// Cargo runner pub fn exit() -> ! { - log::info!("`dk::exit() called; exiting ...`"); + defmt::info!("`dk::exit()` called; exiting ..."); // force any pending memory operation to complete before the BKPT instruction that follows atomic::compiler_fence(Ordering::SeqCst); loop { diff --git a/boards/dk/src/usbd.rs b/boards/dk/src/usbd.rs index 4973413..d1ee75c 100644 --- a/boards/dk/src/usbd.rs +++ b/boards/dk/src/usbd.rs @@ -51,7 +51,7 @@ impl Ep0In { self.busy = true; - log::info!("EP0IN: start {}B transfer", n); + defmt::info!("EP0IN: start {}B transfer", n); // start DMA transfer dma_start(); @@ -75,7 +75,7 @@ impl Ep0In { usbd.events_ep0datadone.reset(); self.busy = false; - log::info!("EP0IN: transfer done"); + defmt::info!("EP0IN: transfer done"); } } } @@ -110,7 +110,7 @@ pub fn init(power: POWER, usbd: &USBD) { // wait until the USB cable has been connected while power.events_usbdetected.read().bits() == 0 { if once { - log::info!("waiting for USB connection on port J3"); + defmt::info!("waiting for USB connection on port J3"); once = false; } @@ -161,7 +161,7 @@ pub fn ep0stall(usbd: &USBD) { } /// USBD.EVENTS registers mapped to an enum -#[derive(Debug)] +#[derive(Debug, defmt::Format)] pub enum Event { /// `EVENTS_USBRESET` register was active UsbReset, diff --git a/common/panic-log/Cargo.toml b/common/panic-log/Cargo.toml index 4129601..5b61b67 100644 --- a/common/panic-log/Cargo.toml +++ b/common/panic-log/Cargo.toml @@ -7,4 +7,20 @@ version = "0.0.0" [dependencies] cortex-m = "0.6.4" -log = "0.4.8" +defmt = "0.2.1" + + +[features] +# set defmt logging levels here +default = [ + "defmt-debug", + # "dependency-a/defmt-trace", +] + +# do NOT modify these features +defmt-default = [] +defmt-trace = [] +defmt-debug = [] +defmt-info = [] +defmt-warn = [] +defmt-error = [] \ No newline at end of file diff --git a/common/panic-log/src/lib.rs b/common/panic-log/src/lib.rs index 5a08462..70f0b89 100644 --- a/common/panic-log/src/lib.rs +++ b/common/panic-log/src/lib.rs @@ -6,7 +6,7 @@ use cortex_m::asm; #[panic_handler] fn panic(info: &PanicInfo) -> ! { - log::error!("{}", info); + defmt::error!("{}", defmt::Debug2Format(&info)); // abort instruction: triggers a HardFault exception which causes probe-run to exit asm::udf() diff --git a/embedded-workshop-book/src/error-handling.md b/embedded-workshop-book/src/error-handling.md index fc7b2e6..3f7937a 100644 --- a/embedded-workshop-book/src/error-handling.md +++ b/embedded-workshop-book/src/error-handling.md @@ -10,7 +10,7 @@ fn on_event(/* parameters */) { if ep0setup(/* arguments */).is_err() { // unsupported or invalid request: // TODO add code to stall the endpoint - log::warn!("EP0: unexpected request; stalling the endpoint"); + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); } } } @@ -32,4 +32,4 @@ Note that there's a difference between the error handling done here and the erro (3) stopping the program, and e.g. requiring the user to reset it to make it work again, may not be desirable behavior. For these reasons in embedded software errors tend to be handled as early as possible rather than propagated all the way up. -This does not preclude error *reporting*. The above snippet includes error reporting in the form of a `log::warn!` statement. This log statement may not be included in the final release of the program as it may not be useful, or even visible, to an end user but it is useful during development. +This does not preclude error *reporting*. The above snippet includes error reporting in the form of a `defmt::warn!` statement. This log statement may not be included in the final release of the program as it may not be useful, or even visible, to an end user but it is useful during development. diff --git a/embedded-workshop-book/src/interfaces.md b/embedded-workshop-book/src/interfaces.md index 2d639fb..56f942d 100644 --- a/embedded-workshop-book/src/interfaces.md +++ b/embedded-workshop-book/src/interfaces.md @@ -10,7 +10,7 @@ Inside the 'configuration 1' rectangle there are two rectangles labeled 'control Inside the 'interface 0' rectangle there are three rectangles labeled 'endpoint 1 IN', 'endpoint 2 IN' and 'endpoint 2 OUT'. Between these three rectangle there is a label that says 'bNumEndpoints=3'; it indicates that this interface has only three endpoints.">

-An interface is closest to a USB device's function. For example, a USB mouse may expose a single HID (Human Interface Device) interface to report user input to the host. USB devices can expose multiple interfaces within a configuration. For example, the nRF52840 Dongle could expose both a CDC ACM interface (AKA virtual serial port) *and* a HID interface; the first interface could be used for (`log::info!`-style) logs; and the second one could provide a RPC (Remote Procedure Call) interface to the host for controlling the nRF52840's radio. +An interface is closest to a USB device's function. For example, a USB mouse may expose a single HID (Human Interface Device) interface to report user input to the host. USB devices can expose multiple interfaces within a configuration. For example, the nRF52840 Dongle could expose both a CDC ACM interface (AKA virtual serial port) *and* a HID interface; the first interface could be used for (`defmt::info!`-style) logs; and the second one could provide a RPC (Remote Procedure Call) interface to the host for controlling the nRF52840's radio. An interface is made up of one or more *endpoints*. To give an example, a HID interface can use two (interrupt) endpoints, one IN and one OUT, for bidirectional communication with the host. A single endpoint cannot be used by more than one interface with the exception of the special "endpoint 0", which can be (and usually is) shared by all interfaces. diff --git a/embedded-workshop-book/src/messages.md b/embedded-workshop-book/src/messages.md index c0a765d..c6df898 100644 --- a/embedded-workshop-book/src/messages.md +++ b/embedded-workshop-book/src/messages.md @@ -32,11 +32,11 @@ let array1: [u8; 3] = [0, 1, 2]; let array2: [u8; 4] = [0, 1, 2, 3]; let mut slice: &[u8] = &array1; -log::info!("{:?}", slice); // length = 3 +defmt::info!("{:?}", slice); // length = 3 // now point to the other array slice = &array2; -log::info!("{:?}", slice); // length = 4 +defmt::info!("{:?}", slice); // length = 4 ``` ## Byte literals @@ -82,8 +82,8 @@ On the other hand, `"Hello"` is a string literal with type `&str`. `str` strings In this workshop we'll work with ASCII strings so byte string literals that contain no escaped characters are OK to use as packet payloads. -You'll note that `log::info!("{:?}", b"Hello")` will print `[72, 101, 108, 108, 111]` rather than `"Hello"` and that the `{}` format specifier (`Display`) does not work. This is because the type of the literal is `&[u8; N]` and in Rust this type means "bytes"; those bytes could be ASCII data, UTF-8 data or something else. +You'll note that `defmt::info!("{:?}", b"Hello")` will print `[72, 101, 108, 108, 111]` rather than `"Hello"` and that the `{}` format specifier (`Display`) does not work. This is because the type of the literal is `&[u8; N]` and in Rust this type means "bytes"; those bytes could be ASCII data, UTF-8 data or something else. To print this you'll need to convert the slice `&[u8]` into a string (`&str`) using the `str::from_utf8` function. This function will verify that the slice contains well formed UTF-8 data and interpret it as a UTF-8 string (`&str`). As long as we use ASCII data (printable ASCII characters) this conversion will not fail. -Something similar will happen with byte literals: `log::info!("{}", b'A')` will print `65` rather than `A`. To get the `A` output you can cast the byte literal (`u8` value) to the `char` type: `log::info!("{}", b'A' as char)`. \ No newline at end of file +Something similar will happen with byte literals: `defmt::info!("{}", b'A')` will print `65` rather than `A`. To get the `A` output you can cast the byte literal (`u8` value) to the `char` type: `defmt::info!("{}", b'A' as char)`. \ No newline at end of file diff --git a/embedded-workshop-book/src/radio-puzzle-help.md b/embedded-workshop-book/src/radio-puzzle-help.md index f94eb7f..f529514 100644 --- a/embedded-workshop-book/src/radio-puzzle-help.md +++ b/embedded-workshop-book/src/radio-puzzle-help.md @@ -56,7 +56,7 @@ fn main() -> ! { for plainletter in 0..=127 { /* ... send letter to dongle ... */ - log::info!("got response"); + defmt::info!("got response"); /* ... store output ... */ timer.wait(Duration::from_millis(20)); diff --git a/embedded-workshop-book/src/time.md b/embedded-workshop-book/src/time.md index 7992495..91b6cc5 100644 --- a/embedded-workshop-book/src/time.md +++ b/embedded-workshop-book/src/time.md @@ -12,4 +12,4 @@ The other time related API exposed by the `dk` HAL is the `dk::uptime` function. ✅ Try changing the `Duration` value passed to `Timer.wait`. Try values larger than one second and smaller than one second. What values of `Duration` make the blinking imperceptible? -❗If you set the duration to below 100ms, try removing the `log::info!` command in the loop. Too much logging will fill the logging buffer and cause the loop to slow down, resulting in the blink frequency to reduce after a while. +❗If you set the duration to below 2ms, try removing the `defmt::info!` command in the loop. Too much logging will fill the logging buffer and cause the loop to slow down, resulting in the blink frequency to reduce after a while. diff --git a/embedded-workshop-book/src/using-hal.md b/embedded-workshop-book/src/using-hal.md index a6f9dc1..1537497 100644 --- a/embedded-workshop-book/src/using-hal.md +++ b/embedded-workshop-book/src/using-hal.md @@ -28,7 +28,16 @@ $ cargo doc -p dk --open ✅ Check the API docs of the `Led` abstraction. Change the `led` program, so that the bottom two LEDs are turned on, and the top two are turned off. -✅ Uncomment the `log::set_max_level` line. This will make the logs more verbose; they will now include logs from the board initialization function (`dk::init`) and from the `Led` API. +🔎 If you want to see logs from Led API of the `dk` Hardware Abstraction Layer, go to `boards/dk/Cargo.toml` and change the log level of the `dk` crate: + +```diff +# set defmt logging levels here +default = [ +- "defmt-debug", ++ "defmt-trace", + # "dependency-a/defmt-trace", +] +``` Among the logs you'll find the line "I/O pins have been configured for digital output". At this point the electrical pins of the nRF52840 microcontroller have been configured to drive the 4 LEDs on the board. From bd9a4b4f6af51b51a3e293f23e1ce2d7e2557c04 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 4 Jun 2021 13:41:31 +0200 Subject: [PATCH 16/29] move to heapless 0.7 --- advanced/firmware/Cargo.toml | 5 ++++- advanced/firmware/src/bin/usb-4-solution.rs | 3 +-- advanced/firmware/src/bin/usb-5-solution.rs | 2 +- advanced/firmware/src/bin/vec.rs | 15 ++++++--------- beginner/apps/Cargo.toml | 5 ++++- beginner/apps/src/bin/radio-puzzle-2.rs | 7 ++++--- beginner/apps/src/bin/radio-puzzle-3.rs | 4 ++-- beginner/apps/src/bin/radio-puzzle-4.rs | 10 ++++------ beginner/apps/src/bin/radio-puzzle-5.rs | 4 ++-- beginner/apps/src/bin/radio-puzzle-6.rs | 6 +++--- beginner/apps/src/bin/radio-puzzle-7.rs | 6 +++--- beginner/apps/src/bin/radio-puzzle-solution-2.rs | 4 ++-- beginner/apps/src/bin/radio-puzzle-solution.rs | 8 ++++---- 13 files changed, 40 insertions(+), 39 deletions(-) diff --git a/advanced/firmware/Cargo.toml b/advanced/firmware/Cargo.toml index e8fb0cd..cf2f9dd 100644 --- a/advanced/firmware/Cargo.toml +++ b/advanced/firmware/Cargo.toml @@ -18,11 +18,14 @@ cortex-m-rtic = "0.5.1" defmt = "0.2.1" defmt-rtt = "0.2.0" dk = { path = "../../boards/dk", features = ["advanced"] } -heapless = "0.5.5" panic-probe = { version = "0.2.0", features = ["print-defmt"] } usb = { path = "../common/usb" } usb2 = "0.0.1" +[dependencies.heapless] +version = "0.7.1" +features = ["defmt-impl"] + # optimize code in both profiles [profile.dev] codegen-units = 1 diff --git a/advanced/firmware/src/bin/usb-4-solution.rs b/advanced/firmware/src/bin/usb-4-solution.rs index 49ef01a..53c30e2 100644 --- a/advanced/firmware/src/bin/usb-4-solution.rs +++ b/advanced/firmware/src/bin/usb-4-solution.rs @@ -91,7 +91,6 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log // `StandardRequest` with `defmt` - match request { // section 9.4.3 // this request is valid in any state @@ -116,7 +115,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> Descriptor::Configuration { index } => { if index == 0 { - let mut resp = heapless::Vec::::new(); + let mut resp = heapless::Vec::::new(); let conf_desc = usb2::configuration::Descriptor { wTotalLength: (usb2::configuration::Descriptor::SIZE diff --git a/advanced/firmware/src/bin/usb-5-solution.rs b/advanced/firmware/src/bin/usb-5-solution.rs index 853bda1..bf12ddf 100644 --- a/advanced/firmware/src/bin/usb-5-solution.rs +++ b/advanced/firmware/src/bin/usb-5-solution.rs @@ -116,7 +116,7 @@ fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> Descriptor::Configuration { index } => { if index == 0 { - let mut resp = heapless::Vec::::new(); + let mut resp = heapless::Vec::::new(); let conf_desc = usb2::configuration::Descriptor { wTotalLength: (usb2::configuration::Descriptor::SIZE diff --git a/advanced/firmware/src/bin/vec.rs b/advanced/firmware/src/bin/vec.rs index f8b42b2..f009ee6 100644 --- a/advanced/firmware/src/bin/vec.rs +++ b/advanced/firmware/src/bin/vec.rs @@ -3,7 +3,7 @@ #![no_std] use cortex_m_rt::entry; -use heapless::{consts, Vec}; +use heapless::Vec; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; @@ -12,21 +12,18 @@ fn main() -> ! { dk::init().unwrap(); // a stack-allocated `Vec` with capacity for 6 bytes - let mut buffer = Vec::::new(); - // ^^ capacity; this is a type not a value + let mut buffer = Vec::::new(); + // content type ^^ ^ capacity // `heapless::Vec` exposes the same API surface as `std::Vec` but some of its methods return a // `Result` to indicate whether the operation failed due to the `heapless::Vec` being full - defmt::info!("start: {:?}", defmt::Debug2Format(&buffer)); - // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log - // `heapless` data structures (like `Vec` here) - // with `defmt` + defmt::info!("start: {:?}", buffer); buffer.push(0).expect("buffer full"); - defmt::info!("after `push`: {:?}", defmt::Debug2Format(&buffer)); + defmt::info!("after `push`: {:?}", buffer); buffer.extend_from_slice(&[1, 2, 3]).expect("buffer full"); - defmt::info!("after `extend`: {:?}", defmt::Debug2Format(&buffer)); + defmt::info!("after `extend`: {:?}", &buffer); // TODO try this operation // buffer.extend_from_slice(&[4, 5, 6, 7]).expect("buffer full"); diff --git a/beginner/apps/Cargo.toml b/beginner/apps/Cargo.toml index 8ec6de1..c5f8681 100644 --- a/beginner/apps/Cargo.toml +++ b/beginner/apps/Cargo.toml @@ -11,9 +11,12 @@ cortex-m-rt = "0.6.13" defmt = "0.2.1" defmt-rtt = "0.2.0" dk = { path = "../../boards/dk", features = ["beginner"] } -heapless = "0.5.5" panic-probe = { version = "0.2.0", features = ["print-defmt"] } +[dependencies.heapless] +version = "0.7.1" +features = ["defmt-impl"] + # optimize code in both profiles [profile.dev] codegen-units = 1 diff --git a/beginner/apps/src/bin/radio-puzzle-2.rs b/beginner/apps/src/bin/radio-puzzle-2.rs index 083ed35..edab631 100644 --- a/beginner/apps/src/bin/radio-puzzle-2.rs +++ b/beginner/apps/src/bin/radio-puzzle-2.rs @@ -6,7 +6,7 @@ use cortex_m_rt::entry; // NOTE you can use `FnvIndexMap` instead of `LinearMap`; the former may have better // lookup performance when the dictionary contains a large number of items but performance is // not important for this exercise -use heapless::{consts, LinearMap}; +use heapless::LinearMap; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use apps as _; @@ -15,8 +15,9 @@ fn main() -> ! { dk::init().unwrap(); // a dictionary with capacity for 2 elements - let mut dict = LinearMap::<_, _, consts::U2>::new(); - // ^^ capacity; this is a type not a value + let mut dict = LinearMap::<_, _, 2>::new(); + // content types ^^ ^^ ^ capacity + // (inferred by rust) // do some insertions dict.insert(b'A', b'*').expect("dictionary full"); diff --git a/beginner/apps/src/bin/radio-puzzle-3.rs b/beginner/apps/src/bin/radio-puzzle-3.rs index dea6b6d..96f9e39 100644 --- a/beginner/apps/src/bin/radio-puzzle-3.rs +++ b/beginner/apps/src/bin/radio-puzzle-3.rs @@ -4,7 +4,7 @@ use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use heapless::{consts, LinearMap}; +use heapless::LinearMap; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use apps as _; @@ -20,7 +20,7 @@ fn main() -> ! { radio.set_channel(Channel::_25); // capacity (128) should be large enough for the ASCII range - let dict = LinearMap::::new(); + let mut dict = LinearMap::::new(); let mut packet = Packet::new(); // TODO do the whole ASCII range [0, 127] diff --git a/beginner/apps/src/bin/radio-puzzle-4.rs b/beginner/apps/src/bin/radio-puzzle-4.rs index 7b5950d..e4a8c69 100644 --- a/beginner/apps/src/bin/radio-puzzle-4.rs +++ b/beginner/apps/src/bin/radio-puzzle-4.rs @@ -5,7 +5,7 @@ use core::str; use cortex_m_rt::entry; -use heapless::{consts, Vec}; +use heapless::Vec; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use apps as _; @@ -14,17 +14,15 @@ fn main() -> ! { dk::init().unwrap(); // a buffer with capacity for 2 bytes - let mut buffer = Vec::::new(); - // ^^ capacity; this is a type not a value + let mut buffer = Vec::::new(); + // content type ^^ ^ capacity // do some insertions buffer.push(b'H').expect("buffer full"); buffer.push(b'i').expect("buffer full"); // look into the contents so far - defmt::info!("{:?}", defmt::Debug2Format(&buffer)); - // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log `heapless` - // data structures (like `Vec` here) with `defmt` + defmt::info!("{:?}", buffer); // or more readable // NOTE utf-8 conversion works as long as you only push bytes in the ASCII range (0..=127) diff --git a/beginner/apps/src/bin/radio-puzzle-5.rs b/beginner/apps/src/bin/radio-puzzle-5.rs index 80be341..e46643a 100644 --- a/beginner/apps/src/bin/radio-puzzle-5.rs +++ b/beginner/apps/src/bin/radio-puzzle-5.rs @@ -6,7 +6,7 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use heapless::{consts, Vec}; +use heapless::Vec; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use apps as _; @@ -38,7 +38,7 @@ fn main() -> ! { ); /* # Decrypt the string */ - let mut buf = Vec::::new(); + let mut buf = Vec::::new(); // iterate over the bytes for input in packet.iter() { diff --git a/beginner/apps/src/bin/radio-puzzle-6.rs b/beginner/apps/src/bin/radio-puzzle-6.rs index 9ff925b..d1c326c 100644 --- a/beginner/apps/src/bin/radio-puzzle-6.rs +++ b/beginner/apps/src/bin/radio-puzzle-6.rs @@ -6,7 +6,7 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use heapless::{consts, LinearMap, Vec}; +use heapless::{LinearMap, Vec}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use apps as _; @@ -22,7 +22,7 @@ fn main() -> ! { radio.set_channel(Channel::_25); /* # Build a dictionary */ - let dict = LinearMap::::new(); + let dict = LinearMap::::new(); let mut packet = Packet::new(); for source in 0..=127 { @@ -62,7 +62,7 @@ fn main() -> ! { ); /* # Decrypt the string */ - let mut buffer = Vec::::new(); + let mut buffer = Vec::::new(); // iterate over the bytes for byte in packet.iter() { diff --git a/beginner/apps/src/bin/radio-puzzle-7.rs b/beginner/apps/src/bin/radio-puzzle-7.rs index be25024..9116db8 100644 --- a/beginner/apps/src/bin/radio-puzzle-7.rs +++ b/beginner/apps/src/bin/radio-puzzle-7.rs @@ -6,7 +6,7 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use heapless::{consts, LinearMap, Vec}; +use heapless::{LinearMap, Vec}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use apps as _; @@ -22,7 +22,7 @@ fn main() -> ! { radio.set_channel(Channel::_25); /* # Build a dictionary */ - let dict = LinearMap::::new(); + let dict = LinearMap::::new(); let mut packet = Packet::new(); for source in 0..=127 { @@ -62,7 +62,7 @@ fn main() -> ! { ); /* # Decrypt the string */ - let mut buffer = Vec::::new(); + let mut buffer = Vec::::new(); // iterate over the bytes for byte in packet.iter() { diff --git a/beginner/apps/src/bin/radio-puzzle-solution-2.rs b/beginner/apps/src/bin/radio-puzzle-solution-2.rs index 75205d0..6007f0f 100644 --- a/beginner/apps/src/bin/radio-puzzle-solution-2.rs +++ b/beginner/apps/src/bin/radio-puzzle-solution-2.rs @@ -6,7 +6,7 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use heapless::{consts, LinearMap}; +use heapless::LinearMap; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use apps as _; @@ -22,7 +22,7 @@ fn main() -> ! { radio.set_channel(Channel::_25); /* # Build a dictionary */ - let mut dict = LinearMap::::new(); + let mut dict = LinearMap::::new(); // the IEEE 802.15.4 packet that will carry our data let mut packet = Packet::new(); diff --git a/beginner/apps/src/bin/radio-puzzle-solution.rs b/beginner/apps/src/bin/radio-puzzle-solution.rs index 4988ddd..4a7e00f 100644 --- a/beginner/apps/src/bin/radio-puzzle-solution.rs +++ b/beginner/apps/src/bin/radio-puzzle-solution.rs @@ -6,7 +6,7 @@ use core::str; use cortex_m_rt::entry; use dk::ieee802154::{Channel, Packet}; -use heapless::{consts, LinearMap, Vec}; +use heapless::{LinearMap, Vec}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use apps as _; @@ -22,8 +22,8 @@ fn main() -> ! { radio.set_channel(Channel::_25); /* # Build a dictionary */ - let mut dict = LinearMap::::new(); - // ^^^^^^^^^^^^ NOTE larger capacity + let mut dict = LinearMap::::new(); + // ^^^ NOTE larger capacity // the IEEE 802.15.4 packet that will carry our data let mut packet = Packet::new(); @@ -66,7 +66,7 @@ fn main() -> ! { ); /* # Decrypt the string */ - let mut buffer = Vec::::new(); + let mut buffer = Vec::::new(); // iterate over the bytes for cipherletter in packet.iter() { From 9e9b74e93dbde8dbca379c9c803cfaf2e55f13e9 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 4 Jun 2021 14:20:24 +0200 Subject: [PATCH 17/29] rm superfluous exit() --- advanced/firmware/src/lib.rs | 7 ------- beginner/apps/src/lib.rs | 7 ------- 2 files changed, 14 deletions(-) diff --git a/advanced/firmware/src/lib.rs b/advanced/firmware/src/lib.rs index 7480423..3446a8d 100644 --- a/advanced/firmware/src/lib.rs +++ b/advanced/firmware/src/lib.rs @@ -8,10 +8,3 @@ use panic_probe as _; fn panic() -> ! { cortex_m::asm::udf() } - -/// Terminates the application and makes `probe-run` exit with exit-code = 0 -pub fn exit() -> ! { - loop { - cortex_m::asm::bkpt(); - } -} diff --git a/beginner/apps/src/lib.rs b/beginner/apps/src/lib.rs index 7480423..3446a8d 100644 --- a/beginner/apps/src/lib.rs +++ b/beginner/apps/src/lib.rs @@ -8,10 +8,3 @@ use panic_probe as _; fn panic() -> ! { cortex_m::asm::udf() } - -/// Terminates the application and makes `probe-run` exit with exit-code = 0 -pub fn exit() -> ! { - loop { - cortex_m::asm::bkpt(); - } -} From eaa60131fb47fd5e391aa2c834acd3eb3d371749 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 4 Jun 2021 16:57:49 +0200 Subject: [PATCH 18/29] uncomplicate crc printing --- beginner/apps/src/bin/radio-recv.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beginner/apps/src/bin/radio-recv.rs b/beginner/apps/src/bin/radio-recv.rs index d1f4fe3..e3642b0 100644 --- a/beginner/apps/src/bin/radio-recv.rs +++ b/beginner/apps/src/bin/radio-recv.rs @@ -45,7 +45,7 @@ fn main() -> ! { crc ); } - Err(Error::Crc(crc)) => defmt::error!("invalid CRC: {=u16:x}", crc), + Err(Error::Crc(crc)) => defmt::error!("invalid CRC: {:X}", crc), Err(Error::Timeout) => defmt::error!("no response within {} ms", TEN_MS / 1_000), } From 370d5e0731d60e986e113feda753299f843a7cc8 Mon Sep 17 00:00:00 2001 From: Lotte Steenbrink Date: Fri, 4 Jun 2021 17:04:23 +0200 Subject: [PATCH 19/29] adjust stack_overflow --- advanced/firmware/src/bin/stack_overflow.rs | 5 +++-- beginner/apps/src/bin/stack_overflow.rs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index 2546126..ab08067 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -11,7 +11,7 @@ fn main() -> ! { // board initialization dk::init().unwrap(); - defmt::info!("fib(100) = {:?}", fib(100)); + fib(100); loop { asm::bkpt(); @@ -21,7 +21,8 @@ fn main() -> ! { #[inline(never)] fn fib(n: u32) -> u32 { // allocate and initialize one kilobyte of stack memory to provoke stack overflow - let _use_stack = [0xAA; 1024]; + let use_stack = [0xAA; 1024]; + defmt::info!("allocating [{}; 1024]; round #{}", use_stack[1023], n); if n < 2 { 1 diff --git a/beginner/apps/src/bin/stack_overflow.rs b/beginner/apps/src/bin/stack_overflow.rs index b06cb53..24c73da 100644 --- a/beginner/apps/src/bin/stack_overflow.rs +++ b/beginner/apps/src/bin/stack_overflow.rs @@ -11,7 +11,7 @@ fn main() -> ! { // board initialization dk::init().unwrap(); - defmt::info!("fib(100) = {:?}", fib(100)); + fib(100); loop { asm::bkpt(); @@ -21,7 +21,8 @@ fn main() -> ! { #[inline(never)] fn fib(n: u32) -> u32 { // allocate and initialize one kilobyte of stack memory to provoke stack overflow - let _use_stack = [0xAA; 1024]; + let use_stack = [0xAA; 1024]; + defmt::info!("allocating [{}; 1024]; round #{}", use_stack[1023], n); if n < 2 { 1 From 35457c44546342a80243390ad995626b83f4c362 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Mon, 20 Dec 2021 15:37:28 +0100 Subject: [PATCH 20/29] bring all tooling to current versions --beginner --- beginner/apps/Cargo.toml | 12 ++--- beginner/apps/src/bin/panic.rs | 8 +++- boards/dk/Cargo.toml | 14 +++--- embedded-workshop-book/src/installation.md | 4 +- embedded-workshop-book/src/panicking.md | 46 ++++++++++++------- embedded-workshop-book/src/radio-setup.md | 2 +- .../src/running-from-vsc.md | 20 +++----- 7 files changed, 58 insertions(+), 48 deletions(-) diff --git a/beginner/apps/Cargo.toml b/beginner/apps/Cargo.toml index 589ef2c..633f9b2 100644 --- a/beginner/apps/Cargo.toml +++ b/beginner/apps/Cargo.toml @@ -6,13 +6,13 @@ name = "apps" version = "0.0.0" [dependencies] -cortex-m = "0.6.4" -cortex-m-rt = "0.6.13" +cortex-m = "0.7.3" +cortex-m-rt = "0.7.1" dk = { path = "../../boards/dk", features = ["beginner"] } -heapless = "0.5.5" -panic-probe = { version = "0.2.0", features = ["print-defmt"] } -defmt = "0.2.1" -defmt-rtt = "0.2.0" +heapless = "0.7.9" +panic-probe = { version = "0.3.0", features = ["print-defmt"] } +defmt = "0.3.0" +defmt-rtt = "0.3.1" # optimize code in both profiles [profile.dev] diff --git a/beginner/apps/src/bin/panic.rs b/beginner/apps/src/bin/panic.rs index b3c139d..272f2b6 100644 --- a/beginner/apps/src/bin/panic.rs +++ b/beginner/apps/src/bin/panic.rs @@ -3,8 +3,7 @@ use cortex_m::asm; use cortex_m_rt::entry; -// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior -use apps as _; +// use apps as _; // this defines the panicking behaviour #[entry] @@ -36,3 +35,8 @@ fn bar() { fn index() -> usize { 3 } + +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + defmt::panic!("lalal {}", info); +} \ No newline at end of file diff --git a/boards/dk/Cargo.toml b/boards/dk/Cargo.toml index b946e92..989c418 100644 --- a/boards/dk/Cargo.toml +++ b/boards/dk/Cargo.toml @@ -6,13 +6,13 @@ name = "dk" version = "0.0.0" [dependencies] -cortex-m = "0.6.4" -cortex-m-rt = "0.6.13" -embedded-hal = "0.2.3" -hal = { package = "nrf52840-hal", version = "0.12.1" } -defmt = "0.2.1" -defmt-rtt = "0.2.0" -panic-probe = { version = "0.2.0", features = ["print-defmt" ] } +cortex-m = "0.7.3" +cortex-m-rt = "0.7.1" +embedded-hal = "0.2.6" +hal = { package = "nrf52840-hal", version = "0.14.0" } +panic-probe = { version = "0.3.0", features = ["print-defmt"] } +defmt = "0.3.0" +defmt-rtt = "0.3.1" [features] beginner = [] diff --git a/embedded-workshop-book/src/installation.md b/embedded-workshop-book/src/installation.md index 4f0e5c0..47fb3f5 100644 --- a/embedded-workshop-book/src/installation.md +++ b/embedded-workshop-book/src/installation.md @@ -152,11 +152,11 @@ Install the [`flip-link`](https://crates.io/crates/flip-link) and [`probe-run`]( $ cargo install probe-run (..) -Installed package `probe-run v0.1.8` (..) +Installed package `probe-run v0.3.1` (..) $ cargo install flip-link (..) -Installed package `flip-link v0.1.2` (..) +Installed package `flip-link v0.1.5` (..) ``` ## Python diff --git a/embedded-workshop-book/src/panicking.md b/embedded-workshop-book/src/panicking.md index 0093782..451ad16 100644 --- a/embedded-workshop-book/src/panicking.md +++ b/embedded-workshop-book/src/panicking.md @@ -5,31 +5,45 @@ This program attempts to index an array beyond its length and this results in a panic. ``` console -ERROR:panic_log -- panicked at 'index out of bounds: the len is 3 but the index is 3', src/bin/panic.rs:29:13 +──────────────────────────────────────────────────────────────────────────────── +ERROR panicked at 'index out of bounds: the len is 3 but the index is 3', src/bin/panic.rs:32:13 +──────────────────────────────────────────────────────────────────────────────── stack backtrace: - 0: 0x000022f0 - __bkpt - 1: 0x00002010 - rust_begin_unwind - 2: 0x00000338 - core::panicking::panic_fmt - 3: 0x00000216 - core::panicking::panic_bounds_check - 4: 0x0000016a - panic::bar - 5: 0x00000158 - panic::foo - 6: 0x00000192 - panic::__cortex_m_rt_main - 7: 0x00000178 - main - 8: 0x0000199e - Reset + 0: HardFaultTrampoline + + 1: lib::inline::__udf + at ./asm/inline.rs:172:5 + 2: __udf + at ./asm/lib.rs:49:17 + 3: cortex_m::asm::udf + at /Users/name/.cargo/registry/src/github.com-1ecc6299db9ec823/cortex-m-0.7.3/src/asm.rs:43:5 + 4: rust_begin_unwind + at /Users/name/.cargo/registry/src/github.com-1ecc6299db9ec823/panic-probe-0.3.0/src/lib.rs:72:9 + 5: core::panicking::panic_fmt + at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/core/src/panicking.rs:100:14 + 6: core::panicking::panic_bounds_check + at /rustc/f1edd0429582dd29cccacaf50fd134b05593bd9c/library/core/src/panicking.rs:76:5 + 7: panic::bar + at src/bin/panic.rs:32:13 + 8: panic::foo + at src/bin/panic.rs:25:5 + 9: panic::__cortex_m_rt_main + at src/bin/panic.rs:15:5 + 10: main + at src/bin/panic.rs:11:1 + 11: Reset +(HOST) ERROR the program panicked ``` In `no_std` programs the behavior of panic is defined using the `#[panic_handler]` attribute. In the example, the *panic handler* is defined in the `panic_log` crate but we can also implement it manually: -✅ Comment out the `panic_log` import and add the following function to the example: +✅ Comment out the `panic_probe` import and add the following function to the example: ``` rust #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { - log::error!("{}", info); - loop { - asm::bkpt() - } + defmt::panic!("{}", info); } ``` -Now run the program again. Try changing the format string of the `error!` macro. +Now run the program again. Try changing the format string of the `panic!` macro. diff --git a/embedded-workshop-book/src/radio-setup.md b/embedded-workshop-book/src/radio-setup.md index 9ddf2b4..dabddd0 100644 --- a/embedded-workshop-book/src/radio-setup.md +++ b/embedded-workshop-book/src/radio-setup.md @@ -7,7 +7,7 @@ ``` console $ cargo xtask serial-term deviceid=588c06af0877c8f2 channel=20 TxPower=+8dBm app=loopback.hex -received 5 bytes (LQI=49) +received 5 bytes (CRC=Ok(0xdad9), LQI=53) ``` The program broadcasts a radio packet that contains the 5-byte string `Hello` over channel 20 (which has a center frequency of 2450 MHz). The `loopback` program running on the Dongle is listening to all packets sent over channel 20; every time it receives a new packet it reports its length and the Link Quality Indicator (LQI) metric of the transmission over the USB/serial interface. As the name implies the LQI metric indicates how good the connection between the sender and the receiver is. diff --git a/embedded-workshop-book/src/running-from-vsc.md b/embedded-workshop-book/src/running-from-vsc.md index b3a44ef..be59374 100644 --- a/embedded-workshop-book/src/running-from-vsc.md +++ b/embedded-workshop-book/src/running-from-vsc.md @@ -13,21 +13,13 @@ Expected output: ``` console $ cargo run --bin hello - Running `probe-run --chip nRF52840_xxAA target/thumbv7em-none-eabihf/debug/hello` - (HOST) INFO flashing program (30.09 KiB) - (HOST) INFO success! + Running `probe-run --chip nRF52840_xxAA target/thumbv7em-none-eabihf/debug/hello` +(HOST) INFO flashing program (4 pages / 16.00 KiB) +(HOST) INFO success! ──────────────────────────────────────────────────────────────────────────────── INFO:hello -- Hello, world! -stack backtrace: - 0: __bkpt - 1: hello::__cortex_m_rt_main - at src/bin/hello.rs:15 - 2: main - at src/bin/hello.rs:8 - 3: ResetTrampoline - at $REGISTRY/cortex-m-rt-0.6.13/src/lib.rs:547 - 4: Reset - at $REGISTRY/cortex-m-rt-0.6.13/src/lib.rs:550 +──────────────────────────────────────────────────────────────────────────────── +(HOST) INFO device halted without error ``` `cargo run` will compile the application and then invoke the `probe-run` tool with its argument set to the path of the output ELF file. @@ -36,7 +28,7 @@ The `probe-run` tool will - flash (load) the program on the microcontroller - reset the microcontroller to make it execute the new program - collect logs from the microcontroller and print them to the console -- print a backtrace of the program and exit when the devices reaches a breakpoint (`asm::bkpt()`) +- print a backtrace of the program if the halt was due to an error. Should you need to configure the `probe-run` invocation to e.g. flash a different microcontroller you can do that in the `.cargo/config.toml` file. From 440c40a4ca64948ebb4133b3bc5ad30d9c55b240 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Tue, 21 Dec 2021 17:43:54 +0100 Subject: [PATCH 21/29] fix appearing interrupt --- beginner/apps/Cargo.toml | 2 +- boards/dk/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/beginner/apps/Cargo.toml b/beginner/apps/Cargo.toml index eecc55e..293d88c 100644 --- a/beginner/apps/Cargo.toml +++ b/beginner/apps/Cargo.toml @@ -7,7 +7,7 @@ version = "0.0.0" [dependencies] cortex-m = "0.7.3" -cortex-m-rt = "0.7.1" +cortex-m-rt = "0.6.15" dk = { path = "../../boards/dk", features = ["beginner"] } panic-probe = { version = "0.3.0", features = ["print-defmt"] } defmt = "0.3.0" diff --git a/boards/dk/Cargo.toml b/boards/dk/Cargo.toml index a4213f6..0ebd7a5 100644 --- a/boards/dk/Cargo.toml +++ b/boards/dk/Cargo.toml @@ -7,9 +7,9 @@ version = "0.0.0" [dependencies] cortex-m = "0.7.3" -cortex-m-rt = "0.7.1" +cortex-m-rt = "0.6.15" embedded-hal = "0.2.6" -hal = { package = "nrf52840-hal", version = "0.14.0" } +hal = { package = "nrf52840-hal", version = "0.13.0" } panic-probe = { version = "0.3.0", features = ["print-defmt"] } defmt = "0.3.0" defmt-rtt = "0.3.1" From 2782a4ff3947a4c3d3f8e81d0d9c1dfacbaf81bc Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Tue, 21 Dec 2021 17:55:24 +0100 Subject: [PATCH 22/29] add set log level --- .../src/running-from-vsc.md | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/embedded-workshop-book/src/running-from-vsc.md b/embedded-workshop-book/src/running-from-vsc.md index be59374..ea519bb 100644 --- a/embedded-workshop-book/src/running-from-vsc.md +++ b/embedded-workshop-book/src/running-from-vsc.md @@ -1,5 +1,27 @@ # Running the Program +## Setting the log level + +Enter the appropriate command into the terminal you're using. This will set the log level for this session. + +### MacOS & Linux + +```console +$ export DEFMT_LOG=warn +``` + +### PowerShell +```console +$ Env: DEFMT_LOG = "warn" +``` + +### Windows + +```console +$ set DEFMT_LOG=warn +``` +## Running the Program + ✅ Open the `src/bin/hello.rs` file and click the "Run" button that's hovering over the `main` function. > Note: you will get the "Run" button if the Rust analyzer's workspace is set to the `beginner/apps` folder. This will be the case if the current folder in VS code (left side panel) is set to `beginner/apps`. @@ -14,7 +36,7 @@ Expected output: ``` console $ cargo run --bin hello Running `probe-run --chip nRF52840_xxAA target/thumbv7em-none-eabihf/debug/hello` -(HOST) INFO flashing program (4 pages / 16.00 KiB) +(HOST) INFO flashing program (2 pages / 16.00 KiB) (HOST) INFO success! ──────────────────────────────────────────────────────────────────────────────── INFO:hello -- Hello, world! From 10a7153779bd58ece2a84d22f689352a7f48f799 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Thu, 23 Dec 2021 12:41:33 +0100 Subject: [PATCH 23/29] update dependencies --- advanced/common/usb/Cargo.toml | 15 +-------------- advanced/firmware/Cargo.toml | 28 +++++++--------------------- 2 files changed, 8 insertions(+), 35 deletions(-) diff --git a/advanced/common/usb/Cargo.toml b/advanced/common/usb/Cargo.toml index 9b476d4..3d4d8b9 100644 --- a/advanced/common/usb/Cargo.toml +++ b/advanced/common/usb/Cargo.toml @@ -6,19 +6,6 @@ name = "usb" version = "0.0.0" [dependencies] -defmt = "0.2.1" +defmt = "0.3.0" -[features] -# set defmt logging levels here -default = [ -"defmt-default", -# "dependency-a/defmt-trace", -] -# do NOT modify these features -defmt-default = [] -defmt-trace = [] -defmt-debug = [] -defmt-info = [] -defmt-warn = [] -defmt-error = [] \ No newline at end of file diff --git a/advanced/firmware/Cargo.toml b/advanced/firmware/Cargo.toml index cf2f9dd..b6ff3b1 100644 --- a/advanced/firmware/Cargo.toml +++ b/advanced/firmware/Cargo.toml @@ -12,18 +12,18 @@ usb2 = "0.0.1" [dependencies] consts = { path = "../common/consts" } -cortex-m = "0.6.4" -cortex-m-rt = "0.6.13" -cortex-m-rtic = "0.5.1" -defmt = "0.2.1" -defmt-rtt = "0.2.0" +cortex-m = "0.7.3" +cortex-m-rt = "0.6.15" +cortex-m-rtic = "0.5.9" +defmt = "0.3.0" +defmt-rtt = "0.3.1" dk = { path = "../../boards/dk", features = ["advanced"] } -panic-probe = { version = "0.2.0", features = ["print-defmt"] } +panic-probe = { version = "0.3.0", features = ["print-defmt"] } usb = { path = "../common/usb" } usb2 = "0.0.1" [dependencies.heapless] -version = "0.7.1" +version = "0.7.9" features = ["defmt-impl"] # optimize code in both profiles @@ -45,17 +45,3 @@ lto = "fat" opt-level = 3 overflow-checks = false -[features] - # set defmt logging levels here - default = [ - "defmt-default", - # "dependency-a/defmt-trace", - ] - - # do NOT modify these features - defmt-default = [] - defmt-trace = [] - defmt-debug = [] - defmt-info = [] - defmt-warn = [] - defmt-error = [] \ No newline at end of file From cf5dc3a3f2f89ba0d90ff7d5dda5082cbcee4eb6 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Thu, 6 Jan 2022 14:37:39 +0100 Subject: [PATCH 24/29] bump nrf-hal version up again --- advanced/firmware/Cargo.toml | 2 +- beginner/apps/Cargo.toml | 2 +- boards/dk/Cargo.toml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/advanced/firmware/Cargo.toml b/advanced/firmware/Cargo.toml index b6ff3b1..d2f094d 100644 --- a/advanced/firmware/Cargo.toml +++ b/advanced/firmware/Cargo.toml @@ -13,7 +13,7 @@ usb2 = "0.0.1" [dependencies] consts = { path = "../common/consts" } cortex-m = "0.7.3" -cortex-m-rt = "0.6.15" +cortex-m-rt = "0.7.1" cortex-m-rtic = "0.5.9" defmt = "0.3.0" defmt-rtt = "0.3.1" diff --git a/beginner/apps/Cargo.toml b/beginner/apps/Cargo.toml index 293d88c..eecc55e 100644 --- a/beginner/apps/Cargo.toml +++ b/beginner/apps/Cargo.toml @@ -7,7 +7,7 @@ version = "0.0.0" [dependencies] cortex-m = "0.7.3" -cortex-m-rt = "0.6.15" +cortex-m-rt = "0.7.1" dk = { path = "../../boards/dk", features = ["beginner"] } panic-probe = { version = "0.3.0", features = ["print-defmt"] } defmt = "0.3.0" diff --git a/boards/dk/Cargo.toml b/boards/dk/Cargo.toml index 0ebd7a5..a4213f6 100644 --- a/boards/dk/Cargo.toml +++ b/boards/dk/Cargo.toml @@ -7,9 +7,9 @@ version = "0.0.0" [dependencies] cortex-m = "0.7.3" -cortex-m-rt = "0.6.15" +cortex-m-rt = "0.7.1" embedded-hal = "0.2.6" -hal = { package = "nrf52840-hal", version = "0.13.0" } +hal = { package = "nrf52840-hal", version = "0.14.0" } panic-probe = { version = "0.3.0", features = ["print-defmt"] } defmt = "0.3.0" defmt-rtt = "0.3.1" From d71d2da3f44723c3ec4649d3485411575da8f15c Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Fri, 7 Jan 2022 12:34:53 +0100 Subject: [PATCH 25/29] bump rtic --- advanced/common/usb/src/lib.rs | 39 ++++++++++++++++--------- advanced/firmware/Cargo.toml | 2 +- advanced/firmware/src/bin/rtic-hello.rs | 25 ++++++++++++---- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/advanced/common/usb/src/lib.rs b/advanced/common/usb/src/lib.rs index 65fe58b..e153265 100644 --- a/advanced/common/usb/src/lib.rs +++ b/advanced/common/usb/src/lib.rs @@ -1,11 +1,11 @@ //! Some USB 2.0 data types +// NOTE this is a partial solution to exercise `usb-2` #![deny(missing_docs)] #![deny(warnings)] #![no_std] use core::num::NonZeroU8; -use defmt; /// Device address assigned by the host; will be in the range 1..=127 pub type Address = NonZeroU8; @@ -51,22 +51,33 @@ impl Request { windex: u16, wlength: u16, ) -> Result { - // Request Codes // see table 9-4 (USB specification) const SET_ADDRESS: u8 = 5; + const GET_DESCRIPTOR: u8 = 6; - // TODO implement another branch handling GET_DESCRIPTOR requests: - // - // 1. get descriptor type and descriptor index from `wValue` - // - // 2. confirm that - // - the descriptor type is DEVICE, i.e. of value 1 and - // - the descriptor index is 0 (i.e. it is the first implemented descriptor for this type) and - // - `wIndex` is 0 (i.e. no language ID since it's not a string descriptor) - // - // For more details, see https://embedded-trainings.ferrous-systems.com/setup-stage.html - if bmrequesttype == 0b00000000 && brequest == SET_ADDRESS { + if bmrequesttype == 0b10000000 && brequest == GET_DESCRIPTOR { + // see table 9-5 + const DEVICE: u8 = 1; + + // 1. get descriptor type and descriptor index from wValue + let desc_ty = (wvalue >> 8) as u8; + let desc_index = wvalue as u8; + let langid = windex; + + // 2. confirm that the descriptor + // - is of type DEVICE and + // - has descriptor index 0 (i.e. it is the first implemented descriptor for this type) and + // - has wIndex 0 (i.e. no language ID since it's not a string descriptor) + if desc_ty == DEVICE && desc_index == 0 && langid == 0 { + Ok(Request::GetDescriptor { + descriptor: Descriptor::Device, + length: wlength, + }) + } else { + Err(()) + } + } else if bmrequesttype == 0b00000000 && brequest == SET_ADDRESS { // Set the device address for all future accesses. // (Needed to successfully init when conected to Apple devices) // Section 9.4.6 Set Address of the USB specification explains which values for wvalue, @@ -79,7 +90,6 @@ impl Request { Err(()) } } else { - defmt::warn!("unhandled case in `Request` parser"); Err(()) } } @@ -198,3 +208,4 @@ mod tests { // ^ } } + diff --git a/advanced/firmware/Cargo.toml b/advanced/firmware/Cargo.toml index d2f094d..2938341 100644 --- a/advanced/firmware/Cargo.toml +++ b/advanced/firmware/Cargo.toml @@ -14,7 +14,7 @@ usb2 = "0.0.1" consts = { path = "../common/consts" } cortex-m = "0.7.3" cortex-m-rt = "0.7.1" -cortex-m-rtic = "0.5.9" +cortex-m-rtic = "1.0.0" defmt = "0.3.0" defmt-rtt = "0.3.1" dk = { path = "../../boards/dk", features = ["advanced"] } diff --git a/advanced/firmware/src/bin/rtic-hello.rs b/advanced/firmware/src/bin/rtic-hello.rs index 68869ff..9c4889c 100644 --- a/advanced/firmware/src/bin/rtic-hello.rs +++ b/advanced/firmware/src/bin/rtic-hello.rs @@ -1,25 +1,38 @@ #![no_main] #![no_std] -use cortex_m::asm; + // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -#[rtic::app(device = dk)] -const APP: () = { +#[rtic::app(device = dk, peripherals = true)] +mod app { + use cortex_m::asm; + use dk::Peripherals; + + #[local] + struct MyLocalResources { + } + + #[shared] + struct MySharedResources { + + } + #[init] - fn init(_cx: init::Context) { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { dk::init().unwrap(); defmt::info!("Hello"); + (MySharedResources {}, MyLocalResources {}, init::Monotonics()) } #[idle] - fn main(_cx: main::Context) -> ! { + fn idle(_cx: idle::Context) -> ! { defmt::info!("world!"); loop { asm::bkpt(); } } -}; +} \ No newline at end of file From c588bb64fc5245ad5f0f839d755b8083ff03d873 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Fri, 7 Jan 2022 17:24:21 +0100 Subject: [PATCH 26/29] info! -> println! --- advanced/firmware/src/bin/events.rs | 12 +- advanced/firmware/src/bin/hello.rs | 2 +- .../firmware/src/bin/resource-solution.rs | 8 +- advanced/firmware/src/bin/resource.rs | 8 +- advanced/firmware/src/bin/rtic-hello.rs | 6 +- advanced/firmware/src/bin/stack_overflow.rs | 2 +- advanced/firmware/src/bin/usb-1-solution.rs | 77 ++-- advanced/firmware/src/bin/usb-1.rs | 54 ++- advanced/firmware/src/bin/usb-2-solution.rs | 160 ++++---- advanced/firmware/src/bin/usb-2.rs | 150 +++---- advanced/firmware/src/bin/usb-3-solution.rs | 165 ++++---- advanced/firmware/src/bin/usb-3.rs | 140 ++++--- advanced/firmware/src/bin/usb-4-solution.rs | 313 +++++++------- advanced/firmware/src/bin/usb-4.rs | 208 +++++----- advanced/firmware/src/bin/usb-5-solution.rs | 385 +++++++++--------- advanced/firmware/src/bin/vec.rs | 6 +- beginner/apps/src/bin/blinky.rs | 2 +- beginner/apps/src/bin/hello.rs | 2 +- beginner/apps/src/bin/panic.rs | 4 +- beginner/apps/src/bin/radio-puzzle-1.rs | 4 +- beginner/apps/src/bin/radio-puzzle-2.rs | 4 +- beginner/apps/src/bin/radio-puzzle-3.rs | 2 +- beginner/apps/src/bin/radio-puzzle-4.rs | 4 +- beginner/apps/src/bin/radio-puzzle-5.rs | 4 +- beginner/apps/src/bin/radio-puzzle-6.rs | 4 +- beginner/apps/src/bin/radio-puzzle-7.rs | 6 +- .../apps/src/bin/radio-puzzle-solution-2.rs | 6 +- .../apps/src/bin/radio-puzzle-solution.rs | 6 +- beginner/apps/src/bin/radio-puzzle.rs | 4 +- beginner/apps/src/bin/radio-recv.rs | 4 +- beginner/apps/src/bin/radio-send.rs | 2 +- beginner/apps/src/bin/stack_overflow.rs | 2 +- boards/dk/src/lib.rs | 5 +- boards/dk/src/usbd.rs | 6 +- embedded-workshop-book/src/interfaces.md | 2 +- embedded-workshop-book/src/messages.md | 8 +- .../src/radio-puzzle-help.md | 2 +- embedded-workshop-book/src/time.md | 2 +- 38 files changed, 931 insertions(+), 850 deletions(-) diff --git a/advanced/firmware/src/bin/events.rs b/advanced/firmware/src/bin/events.rs index bf8d40d..aee1170 100644 --- a/advanced/firmware/src/bin/events.rs +++ b/advanced/firmware/src/bin/events.rs @@ -23,7 +23,7 @@ const APP: () = { w.usbdetected().set_bit() }); - defmt::info!("USBDETECTED interrupt enabled"); + defmt::println!("USBDETECTED interrupt enabled"); // read the whole 32-bit usb supply register // the `read()` method returns a reader which can then be used to access the register content @@ -31,19 +31,19 @@ const APP: () = { // (the layout of the USBREGSTATUS register can be found in section 5.3.7.13 of the PS) let regstatus: u32 = power.usbregstatus.read().bits(); // ^^^^ complete register content - defmt::info!("USBREGSTATUS: {:b}", regstatus); + defmt::println!("USBREGSTATUS: {:b}", regstatus); // read the 1-bit VBUSDETECT field that is part of the USBREGSTATUS register content // to show that its contents reflect our usb connection status // (the USBDETECTED event that will trigger `on_power_event()` is derived from this information) let vbusdetect: bool = power.usbregstatus.read().vbusdetect().bits(); // ^^^^^^^^^^ bitfield name - defmt::info!("USBREGSTATUS.VBUSDETECT: {}", vbusdetect); + defmt::println!("USBREGSTATUS.VBUSDETECT: {}", vbusdetect); } #[idle] fn main(_cx: main::Context) -> ! { - defmt::info!("idle: going to sleep"); + defmt::println!("idle: going to sleep"); // sleep in the background loop { @@ -53,7 +53,7 @@ const APP: () = { #[task(binds = POWER_CLOCK)] fn on_power_event(_cx: on_power_event::Context) { - defmt::info!("POWER event occurred"); - dk::exit() + defmt::println!("POWER event occurred"); + asm::bkpt(); } }; diff --git a/advanced/firmware/src/bin/hello.rs b/advanced/firmware/src/bin/hello.rs index af489e8..71b7b06 100644 --- a/advanced/firmware/src/bin/hello.rs +++ b/advanced/firmware/src/bin/hello.rs @@ -11,7 +11,7 @@ fn main() -> ! { // board initialization dk::init().unwrap(); - defmt::info!("Hello, world!"); + defmt::println!("Hello, world!"); loop { asm::bkpt(); diff --git a/advanced/firmware/src/bin/resource-solution.rs b/advanced/firmware/src/bin/resource-solution.rs index ecc0b66..f5e3367 100644 --- a/advanced/firmware/src/bin/resource-solution.rs +++ b/advanced/firmware/src/bin/resource-solution.rs @@ -21,7 +21,7 @@ const APP: () = { power.intenset.write(|w| w.usbdetected().set_bit()); - defmt::info!("USBDETECTED interrupt enabled"); + defmt::println!("USBDETECTED interrupt enabled"); init::LateResources { power, @@ -32,9 +32,9 @@ const APP: () = { #[idle] fn main(_cx: main::Context) -> ! { loop { - defmt::info!("idle: going to sleep"); + defmt::println!("idle: going to sleep"); asm::wfi(); - defmt::info!("idle: woke up"); + defmt::println!("idle: woke up"); } } @@ -48,7 +48,7 @@ const APP: () = { *counter += 1; let n = *counter; - defmt::info!( + defmt::println!( "on_power_event: cable connected {} time{}", n, if n != 1 { "s" } else { "" } diff --git a/advanced/firmware/src/bin/resource.rs b/advanced/firmware/src/bin/resource.rs index b43e6c7..96ff984 100644 --- a/advanced/firmware/src/bin/resource.rs +++ b/advanced/firmware/src/bin/resource.rs @@ -20,7 +20,7 @@ const APP: () = { power.intenset.write(|w| w.usbdetected().set_bit()); - defmt::info!("USBDETECTED interrupt enabled"); + defmt::println!("USBDETECTED interrupt enabled"); init::LateResources { power, // <- resource initialization @@ -30,16 +30,16 @@ const APP: () = { #[idle] fn main(_cx: main::Context) -> ! { loop { - defmt::info!("idle: going to sleep"); + defmt::println!("idle: going to sleep"); asm::wfi(); - defmt::info!("idle: woke up"); + defmt::println!("idle: woke up"); } } #[task(binds = POWER_CLOCK, resources = [power])] // ^^^^^^^ resource access list fn on_power_event(cx: on_power_event::Context) { - defmt::info!("POWER event occurred"); + defmt::println!("POWER event occurred"); // resources available to this task let resources = cx.resources; diff --git a/advanced/firmware/src/bin/rtic-hello.rs b/advanced/firmware/src/bin/rtic-hello.rs index 9c4889c..cd57d3a 100644 --- a/advanced/firmware/src/bin/rtic-hello.rs +++ b/advanced/firmware/src/bin/rtic-hello.rs @@ -5,7 +5,7 @@ // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -#[rtic::app(device = dk, peripherals = true)] +#[rtic::app(device = dk, peripherals = false)] mod app { use cortex_m::asm; use dk::Peripherals; @@ -23,13 +23,13 @@ mod app { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { dk::init().unwrap(); - defmt::info!("Hello"); + defmt::println!("Hello"); (MySharedResources {}, MyLocalResources {}, init::Monotonics()) } #[idle] fn idle(_cx: idle::Context) -> ! { - defmt::info!("world!"); + defmt::println!("world!"); loop { asm::bkpt(); diff --git a/advanced/firmware/src/bin/stack_overflow.rs b/advanced/firmware/src/bin/stack_overflow.rs index ab08067..35d37df 100644 --- a/advanced/firmware/src/bin/stack_overflow.rs +++ b/advanced/firmware/src/bin/stack_overflow.rs @@ -22,7 +22,7 @@ fn main() -> ! { fn fib(n: u32) -> u32 { // allocate and initialize one kilobyte of stack memory to provoke stack overflow let use_stack = [0xAA; 1024]; - defmt::info!("allocating [{}; 1024]; round #{}", use_stack[1023], n); + defmt::println!("allocating [{}; 1024]; round #{}", use_stack[1023], n); if n < 2 { 1 diff --git a/advanced/firmware/src/bin/usb-1-solution.rs b/advanced/firmware/src/bin/usb-1-solution.rs index a8e35bf..91ef9d1 100644 --- a/advanced/firmware/src/bin/usb-1-solution.rs +++ b/advanced/firmware/src/bin/usb-1-solution.rs @@ -1,52 +1,67 @@ #![no_main] #![no_std] -use dk::{ - peripheral::USBD, - usbd::{self, Event}, -}; + // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { +#[rtic::app(device = dk, peripherals = false)] +mod app { + use dk::{ + peripheral::USBD, + usbd::{self, Event}, + Peripherals, + }; + + #[local] + struct MyLocalResources { usbd: USBD, } - #[init] - fn init(_cx: init::Context) -> init::LateResources { - let board = dk::init().unwrap(); - - usbd::init(board.power, &board.usbd); - - init::LateResources { usbd: board.usbd } + #[shared] + struct MySharedResources { + } - #[task(binds = USBD, resources = [usbd])] + #[init] + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { + let board = dk::init().unwrap(); + + // initialize the USBD peripheral + // NOTE this will block if the USB cable is not connected to port J3 + dk::usbd::init(board.power, &board.usbd); + + defmt::println!("USBD initialized"); + + (MySharedResources {}, MyLocalResources {usbd: board.usbd }, init::Monotonics()) + } + + #[task(binds = USBD, local = [usbd])] fn main(cx: main::Context) { - let usbd = cx.resources.usbd; + let usbd = cx.local.usbd; while let Some(event) = usbd::next_event(usbd) { on_event(usbd, event) } } -}; -fn on_event(_usbd: &USBD, event: Event) { - defmt::info!("USB: {:?}", event); - - match event { - Event::UsbReset => { - // going from the Default state to the Default state is a no-operation - defmt::info!("returning to the Default state"); - } - - Event::UsbEp0DataDone => todo!(), - - Event::UsbEp0Setup => { - defmt::info!("goal reached; move to the next section"); - dk::exit() + fn on_event(_usbd: &USBD, event: Event) { + defmt::println("USB: {:?}", event); + + match event { + Event::UsbReset => { + // going from the Default state to the Default state is a no-operation + defmt::println("returning to the Default state"); + } + + Event::UsbEp0DataDone => todo!(), + + Event::UsbEp0Setup => { + defmt::println("goal reached; move to the next section"); + dk::exit() + } } } } + + diff --git a/advanced/firmware/src/bin/usb-1.rs b/advanced/firmware/src/bin/usb-1.rs index 0f6dd2e..a5293e1 100644 --- a/advanced/firmware/src/bin/usb-1.rs +++ b/advanced/firmware/src/bin/usb-1.rs @@ -8,46 +8,60 @@ use dk::{ // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { +#[rtic::app(device = dk, peripherals = false)] +mod app { + use dk::{ + peripheral::USBD, + usbd::{self, Event}, + Peripherals, + }; + + #[local] + struct MyLocalResources { usbd: USBD, } + #[shared] + struct MySharedResources { + + } + #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); // initialize the USBD peripheral // NOTE this will block if the USB cable is not connected to port J3 usbd::init(board.power, &board.usbd); - defmt::info!("USBD initialized"); + defmt::println!("USBD initialized"); - init::LateResources { usbd: board.usbd } + (MySharedResources {}, MyLocalResources { usbd: board.usbd }, init::Monotonics()) } - #[task(binds = USBD, resources = [usbd])] + #[task(binds = USBD, local = [usbd])] fn main(cx: main::Context) { - let usbd = cx.resources.usbd; + let usbd = cx.local.usbd; while let Some(event) = usbd::next_event(usbd) { on_event(usbd, event) } } -}; -fn on_event(_usbd: &USBD, event: Event) { - defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); - - match event { - Event::UsbReset => todo!(), - - Event::UsbEp0DataDone => todo!(), - // leave this at it is for now. - Event::UsbEp0Setup => { - defmt::info!("goal reached; move to the next section"); - dk::exit() + fn on_event(_usbd: &USBD, event: Event) { + defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + + match event { + Event::UsbReset => todo!(), + + Event::UsbEp0DataDone => todo!(), + // leave this at it is for now. + Event::UsbEp0Setup => { + defmt::println!("goal reached; move to the next section"); + dk::exit() + } } } } + + diff --git a/advanced/firmware/src/bin/usb-2-solution.rs b/advanced/firmware/src/bin/usb-2-solution.rs index cd8a858..323a004 100644 --- a/advanced/firmware/src/bin/usb-2-solution.rs +++ b/advanced/firmware/src/bin/usb-2-solution.rs @@ -1,102 +1,112 @@ #![no_main] #![no_std] -use dk::{ - peripheral::USBD, - usbd::{self, Event}, -}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -use usb::{Descriptor, Request}; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { +#[rtic::app(device = dk, peripherals = false)] +mod app { + use dk::{ + peripheral::USBD, + usbd::{self, Event}, + Peripherals, + }; + + use usb::{Descriptor, Request}; + + #[local] + struct MyLocalResources { usbd: USBD, } + #[shared] + struct MySharedResources { + + } + #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); usbd::init(board.power, &board.usbd); - init::LateResources { usbd: board.usbd } + (MySharedResources {}, MyLocalResources { usbd: board.usbd }, init::Monotonics()) } - #[task(binds = USBD, resources = [usbd])] + #[task(binds = USBD, local = [usbd])] fn main(cx: main::Context) { - let usbd = cx.resources.usbd; + let usbd = cx.local.usbd; while let Some(event) = usbd::next_event(usbd) { on_event(usbd, event) } } -}; - -fn on_event(usbd: &USBD, event: Event) { - defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); - - match event { - Event::UsbReset => { - // nothing to do here at the moment - } - - Event::UsbEp0DataDone => todo!(), - - Event::UsbEp0Setup => { - // the BMREQUESTTYPE register contains information about data recipient, transfer type and direction - let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; - // the BREQUEST register stores the type of the current request (e.g. SET_ADDRESS, GET_DESCRIPTOR, ...) - let brequest = usbd.brequest.read().brequest().bits(); - // wLength denotes the number of bytes to transfer (if any) - // composed of a high register (WLENGTHH) and a low register (WLENGTHL) - let wlength = (u16::from(usbd.wlengthh.read().wlengthh().bits()) << 8) - | u16::from(usbd.wlengthl.read().wlengthl().bits()); - // wIndex is a generic index field whose meaning depends on the request type - // composed of a high register (WINDEXH) and a low register (WINDEXL) - let windex = (u16::from(usbd.windexh.read().windexh().bits()) << 8) - | u16::from(usbd.windexl.read().windexl().bits()); - // wValue is a generic paremeter field meaning depends on the request type (e.g. contains the device - // address in SET_ADRESS requests) - // composed of a high register (WVALUEH) and a low register (WVALUEL) - let wvalue = (u16::from(usbd.wvalueh.read().wvalueh().bits()) << 8) - | u16::from(usbd.wvaluel.read().wvaluel().bits()); - - // NOTE the `dk` crate contains helper functions for the above operations - // let bmrequesttype = usbd::bmrequesttype(usbd); - // let brequest = usbd::brequest(usbd); - // let wlength = usbd::wlength(usbd); - // let windex = usbd::windex(usbd); - // let wvalue = usbd::wvalue(usbd); - - defmt::info!( - "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", - bmrequesttype, - brequest, - wlength, - windex, - wvalue - ); - - let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) - .expect("Error parsing request"); - match request { - Request::GetDescriptor { descriptor, length } - if descriptor == Descriptor::Device => - { - defmt::info!("GET_DESCRIPTOR Device [length={}]", length); - - defmt::info!("Goal reached; move to the next section"); - dk::exit() + fn on_event(usbd: &USBD, event: Event) { + defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + + match event { + Event::UsbReset => { + // nothing to do here at the moment + } + + Event::UsbEp0DataDone => todo!(), + + Event::UsbEp0Setup => { + // the BMREQUESTTYPE register contains information about data recipient, transfer type and direction + let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; + // the BREQUEST register stores the type of the current request (e.g. SET_ADDRESS, GET_DESCRIPTOR, ...) + let brequest = usbd.brequest.read().brequest().bits(); + // wLength denotes the number of bytes to transfer (if any) + // composed of a high register (WLENGTHH) and a low register (WLENGTHL) + let wlength = (u16::from(usbd.wlengthh.read().wlengthh().bits()) << 8) + | u16::from(usbd.wlengthl.read().wlengthl().bits()); + // wIndex is a generic index field whose meaning depends on the request type + // composed of a high register (WINDEXH) and a low register (WINDEXL) + let windex = (u16::from(usbd.windexh.read().windexh().bits()) << 8) + | u16::from(usbd.windexl.read().windexl().bits()); + // wValue is a generic paremeter field meaning depends on the request type (e.g. contains the device + // address in SET_ADRESS requests) + // composed of a high register (WVALUEH) and a low register (WVALUEL) + let wvalue = (u16::from(usbd.wvalueh.read().wvalueh().bits()) << 8) + | u16::from(usbd.wvaluel.read().wvaluel().bits()); + + // NOTE the `dk` crate contains helper functions for the above operations + // let bmrequesttype = usbd::bmrequesttype(usbd); + // let brequest = usbd::brequest(usbd); + // let wlength = usbd::wlength(usbd); + // let windex = usbd::windex(usbd); + // let wvalue = usbd::wvalue(usbd); + + defmt::println!( + "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + bmrequesttype, + brequest, + wlength, + windex, + wvalue + ); + + let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) + .expect("Error parsing request"); + match request { + Request::GetDescriptor { descriptor, length } + if descriptor == Descriptor::Device => + { + defmt::println!("GET_DESCRIPTOR Device [length={}]", length); + + defmt::println!("Goal reached; move to the next section"); + dk::exit() + } + Request::SetAddress { .. } => { + // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we + // need to catch it here. We'll properly handle this request later + // but for now it's OK to do nothing. + } + _ => unreachable!(), // we don't handle any other Requests } - Request::SetAddress { .. } => { - // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we - // need to catch it here. We'll properly handle this request later - // but for now it's OK to do nothing. - } - _ => unreachable!(), // we don't handle any other Requests } } } + } + diff --git a/advanced/firmware/src/bin/usb-2.rs b/advanced/firmware/src/bin/usb-2.rs index 648c475..8c827a1 100644 --- a/advanced/firmware/src/bin/usb-2.rs +++ b/advanced/firmware/src/bin/usb-2.rs @@ -1,98 +1,108 @@ #![no_main] #![no_std] -use dk::{ - peripheral::USBD, - usbd::{self, Event}, -}; + // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -use usb::{Descriptor, Request}; +#[rtic::app(device = dk, peripherals = false)] +mod app { + use dk::{ + peripheral::USBD, + usbd::{self, Event}, + Peripherals, + }; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { + use usb::{Descriptor, Request}; + + #[local] + struct MyLocalResources { usbd: USBD, } + #[shared] + struct MySharedResources { + + } + #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); usbd::init(board.power, &board.usbd); - init::LateResources { usbd: board.usbd } + (MySharedResources {}, MyLocalResources { usbd: board.usbd }, init::Monotonics()) } - #[task(binds = USBD, resources = [usbd])] + #[task(binds = USBD, local = [usbd])] fn main(cx: main::Context) { - let usbd = cx.resources.usbd; + let usbd = cx.local.usbd; while let Some(event) = usbd::next_event(usbd) { on_event(usbd, event) } } -}; -fn on_event(_usbd: &USBD, event: Event) { - defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); - - match event { - Event::UsbReset => { - // nothing to do here at the moment - } - - Event::UsbEp0DataDone => todo!(), - - Event::UsbEp0Setup => { - // TODO read USBD registers - - // the BMREQUESTTYPE register contains information about data recipient, transfer type and direction - let bmrequesttype: u8 = 0; - // the BREQUEST register stores the type of the current request (e.g. SET_ADDRESS, GET_DESCRIPTOR, ...) - let brequest: u8 = 0; - // wLength denotes the number of bytes to transfer (if any) - // composed of a high register (WLENGTHH) and a low register (WLENGTHL) - let wlength: u16 = 0; - // wIndex is a generic index field whose meaning depends on the request type - // composed of a high register (WINDEXH) and a low register (WINDEXL) - let windex: u16 = 0; - // wValue is a generic paremeter field meaning depends on the request type (e.g. contains the device - // address in SET_ADRESS requests) - // composed of a high register (WVALUEH) and a low register (WVALUEL) - let wvalue: u16 = 0; - - defmt::info!( - "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", - bmrequesttype, - brequest, - wlength, - windex, - wvalue - ); - - let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) - .expect("Error parsing request"); - match request { - Request::GetDescriptor { descriptor, length } - if descriptor == Descriptor::Device => - { - // TODO modify `Request::parse()` in `advanced/common/usb/lib.rs` - // so that this branch is reached - - defmt::info!("GET_DESCRIPTOR Device [length={}]", length); - - defmt::info!("Goal reached; move to the next section"); - dk::exit() + fn on_event(_usbd: &USBD, event: Event) { + defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + + match event { + Event::UsbReset => { + // nothing to do here at the moment + } + + Event::UsbEp0DataDone => todo!(), + + Event::UsbEp0Setup => { + // TODO read USBD registers + + // the BMREQUESTTYPE register contains information about data recipient, transfer type and direction + let bmrequesttype: u8 = 0; + // the BREQUEST register stores the type of the current request (e.g. SET_ADDRESS, GET_DESCRIPTOR, ...) + let brequest: u8 = 0; + // wLength denotes the number of bytes to transfer (if any) + // composed of a high register (WLENGTHH) and a low register (WLENGTHL) + let wlength: u16 = 0; + // wIndex is a generic index field whose meaning depends on the request type + // composed of a high register (WINDEXH) and a low register (WINDEXL) + let windex: u16 = 0; + // wValue is a generic paremeter field meaning depends on the request type (e.g. contains the device + // address in SET_ADRESS requests) + // composed of a high register (WVALUEH) and a low register (WVALUEL) + let wvalue: u16 = 0; + + defmt::println!( + "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + bmrequesttype, + brequest, + wlength, + windex, + wvalue + ); + + let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) + .expect("Error parsing request"); + match request { + Request::GetDescriptor { descriptor, length } + if descriptor == Descriptor::Device => + { + // TODO modify `Request::parse()` in `advanced/common/usb/lib.rs` + // so that this branch is reached + + defmt::println!("GET_DESCRIPTOR Device [length={}]", length); + + defmt::println!("Goal reached; move to the next section"); + dk::exit() + } + Request::SetAddress { .. } => { + // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we + // need to catch it here. We'll properly handle this request later + // but for now it's OK to do nothing. + } + _ => unreachable!(), // we don't handle any other Requests } - Request::SetAddress { .. } => { - // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we - // need to catch it here. We'll properly handle this request later - // but for now it's OK to do nothing. - } - _ => unreachable!(), // we don't handle any other Requests } } - } + } } + diff --git a/advanced/firmware/src/bin/usb-3-solution.rs b/advanced/firmware/src/bin/usb-3-solution.rs index f5a4476..d784282 100644 --- a/advanced/firmware/src/bin/usb-3-solution.rs +++ b/advanced/firmware/src/bin/usb-3-solution.rs @@ -1,108 +1,115 @@ #![no_main] #![no_std] -use dk::{ - peripheral::USBD, - usbd::{self, Ep0In, Event}, -}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -use usb::{Descriptor, Request}; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { +#[rtic::app(device = dk, peripherals = false)] +mod app { + use dk::{ + peripheral::USBD, + usbd::{self, Ep0In, Event}, + Peripherals, + }; + use usb::{Descriptor, Request}; + + #[local] + struct MyLocalResources { usbd: USBD, ep0in: Ep0In, } + #[shared] + struct MySharedResources { + + } + #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); usbd::init(board.power, &board.usbd); - init::LateResources { - ep0in: board.ep0in, - usbd: board.usbd, - } + (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, }, init::Monotonics()) } - #[task(binds = USBD, resources = [usbd, ep0in])] + #[task(binds = USBD, local = [usbd, ep0in])] fn main(cx: main::Context) { - let usbd = cx.resources.usbd; - let ep0in = cx.resources.ep0in; + let usbd = cx.local.usbd; + let ep0in = cx.local.ep0in; while let Some(event) = usbd::next_event(usbd) { on_event(usbd, ep0in, event) } } -}; -fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { - defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); - - match event { - Event::UsbReset => { - // nothing to do here at the moment - } - - Event::UsbEp0DataDone => ep0in.end(usbd), - - Event::UsbEp0Setup => { - let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; - let brequest = usbd.brequest.read().brequest().bits(); - let wlength = usbd::wlength(usbd); - let windex = usbd::windex(usbd); - let wvalue = usbd::wvalue(usbd); - - defmt::info!( - "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", - bmrequesttype, - brequest, - wlength, - windex, - wvalue - ); - - let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect( - "Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)", - ); - match request { - Request::GetDescriptor { descriptor, length } - if descriptor == Descriptor::Device => - { - defmt::info!("GET_DESCRIPTOR Device [length={}]", length); - - let desc = usb2::device::Descriptor { - bDeviceClass: 0, - bDeviceProtocol: 0, - bDeviceSubClass: 0, - bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, - bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), - bcdDevice: 0x01_00, // 1.00 - iManufacturer: None, - iProduct: None, - iSerialNumber: None, - idProduct: consts::PID, - idVendor: consts::VID, - }; - let desc_bytes = desc.bytes(); - let resp = &desc_bytes[..core::cmp::min(desc_bytes.len(), usize::from(length))]; - ep0in.start(&resp, usbd); - } - Request::SetAddress { .. } => { - // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we - // need to catch it here. We'll properly handle this request later - // but for now it's OK to do nothing. - } - _ => { - defmt::error!( - "unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" - ); - dk::exit() + fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { + defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + + match event { + Event::UsbReset => { + // nothing to do here at the moment + } + + Event::UsbEp0DataDone => ep0in.end(usbd), + + Event::UsbEp0Setup => { + let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; + let brequest = usbd.brequest.read().brequest().bits(); + let wlength = usbd::wlength(usbd); + let windex = usbd::windex(usbd); + let wvalue = usbd::wvalue(usbd); + + defmt::println!( + "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + bmrequesttype, + brequest, + wlength, + windex, + wvalue + ); + + let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect( + "Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)", + ); + match request { + Request::GetDescriptor { descriptor, length } + if descriptor == Descriptor::Device => + { + defmt::println!("GET_DESCRIPTOR Device [length={}]", length); + + let desc = usb2::device::Descriptor { + bDeviceClass: 0, + bDeviceProtocol: 0, + bDeviceSubClass: 0, + bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, + bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), + bcdDevice: 0x01_00, // 1.00 + iManufacturer: None, + iProduct: None, + iSerialNumber: None, + idProduct: consts::PID, + idVendor: consts::VID, + }; + let desc_bytes = desc.bytes(); + let resp = &desc_bytes[..core::cmp::min(desc_bytes.len(), usize::from(length))]; + ep0in.start(&resp, usbd); + } + Request::SetAddress { .. } => { + // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we + // need to catch it here. We'll properly handle this request later + // but for now it's OK to do nothing. + } + _ => { + defmt::error!( + "unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" + ); + dk::exit() + } } } } } + } + diff --git a/advanced/firmware/src/bin/usb-3.rs b/advanced/firmware/src/bin/usb-3.rs index 6e74b22..4336183 100644 --- a/advanced/firmware/src/bin/usb-3.rs +++ b/advanced/firmware/src/bin/usb-3.rs @@ -1,96 +1,102 @@ #![no_main] #![no_std] -use dk::{ - peripheral::USBD, - usbd::{self, Ep0In, Event}, -}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -use usb::{Descriptor, Request}; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { +#[rtic::app(device = dk, peripherals = false)] +mod app { + use dk::{ + peripheral::USBD, + usbd::{self, Ep0In, Event}, + Peripherals, + }; + use usb::{Descriptor, Request}; + + #[local] + struct MyLocalResources { usbd: USBD, ep0in: Ep0In, } + #[shared] + struct MySharedResources { + + } #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); usbd::init(board.power, &board.usbd); - init::LateResources { - ep0in: board.ep0in, - usbd: board.usbd, - } + (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, }, init::Monotonics()) } - #[task(binds = USBD, resources = [usbd, ep0in])] + #[task(binds = USBD, local = [usbd, ep0in])] fn main(cx: main::Context) { - let usbd = cx.resources.usbd; - let ep0in = cx.resources.ep0in; + let usbd = cx.local.usbd; + let ep0in = cx.local.ep0in; while let Some(event) = usbd::next_event(usbd) { on_event(usbd, ep0in, event) } } -}; -fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { - defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); - - match event { - Event::UsbReset => { - // nothing to do here at the moment - } - - Event::UsbEp0DataDone => todo!(), // <- TODO - - Event::UsbEp0Setup => { - let bmrequesttype = usbd::bmrequesttype(usbd); - let brequest = usbd::brequest(usbd); - let wlength = usbd::wlength(usbd); - let windex = usbd::windex(usbd); - let wvalue = usbd::wvalue(usbd); - - defmt::info!( - "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", - bmrequesttype, - brequest, - wlength, - windex, - wvalue - ); - - let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect( - "Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)", - ); - match request { - Request::GetDescriptor { descriptor, length } - if descriptor == Descriptor::Device => - { - defmt::info!("GET_DESCRIPTOR Device [length={}]", length); - - // TODO send back a valid device descriptor, truncated to `length` bytes - // let desc = usb2::device::Descriptor { .. }; - let resp = []; - ep0in.start(&resp, usbd); - } - Request::SetAddress { .. } => { - // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we - // need to catch it here. We'll properly handle this request later - // but for now it's OK to do nothing. - } - _ => { - defmt::error!( - "unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" - ); - dk::exit() + fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { + defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + + match event { + Event::UsbReset => { + // nothing to do here at the moment + } + + Event::UsbEp0DataDone => todo!(), // <- TODO + + Event::UsbEp0Setup => { + let bmrequesttype = usbd::bmrequesttype(usbd); + let brequest = usbd::brequest(usbd); + let wlength = usbd::wlength(usbd); + let windex = usbd::windex(usbd); + let wvalue = usbd::wvalue(usbd); + + defmt::println!( + "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + bmrequesttype, + brequest, + wlength, + windex, + wvalue + ); + + let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect( + "Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)", + ); + match request { + Request::GetDescriptor { descriptor, length } + if descriptor == Descriptor::Device => + { + defmt::println!("GET_DESCRIPTOR Device [length={}]", length); + + // TODO send back a valid device descriptor, truncated to `length` bytes + // let desc = usb2::device::Descriptor { .. }; + let resp = []; + ep0in.start(&resp, usbd); + } + Request::SetAddress { .. } => { + // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we + // need to catch it here. We'll properly handle this request later + // but for now it's OK to do nothing. + } + _ => { + defmt::error!( + "unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" + ); + dk::exit() + } } } } } + } + diff --git a/advanced/firmware/src/bin/usb-4-solution.rs b/advanced/firmware/src/bin/usb-4-solution.rs index 53c30e2..51035a9 100644 --- a/advanced/firmware/src/bin/usb-4-solution.rs +++ b/advanced/firmware/src/bin/usb-4-solution.rs @@ -1,187 +1,192 @@ #![no_main] #![no_std] -use core::num::NonZeroU8; - -use dk::{ - peripheral::USBD, - usbd::{self, Ep0In, Event}, -}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State}; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { +#[rtic::app(device = dk, peripherals = false)] +mod app { + + use core::num::NonZeroU8; + + use dk::{ + peripheral::USBD, + usbd::{self, Ep0In, Event}, + Peripherals, + }; + use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State}; + + #[local] + struct MyLocalResources { usbd: USBD, ep0in: Ep0In, state: State, } + #[shared] + struct MySharedResources { + + } #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); usbd::init(board.power, &board.usbd); - - init::LateResources { - usbd: board.usbd, - state: State::Default, - ep0in: board.ep0in, - } + + (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, state: State::Default, }, init::Monotonics()) } - #[task(binds = USBD, resources = [usbd, ep0in, state])] + #[task(binds = USBD, local = [usbd, ep0in, state])] fn main(cx: main::Context) { - let usbd = cx.resources.usbd; - let ep0in = cx.resources.ep0in; - let state = cx.resources.state; + let usbd = cx.local.usbd; + let ep0in = cx.local.ep0in; + let state = cx.local.state; while let Some(event) = usbd::next_event(usbd) { on_event(usbd, ep0in, state, event) } } -}; - -fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); - - match event { - Event::UsbReset => { - defmt::info!("USB reset condition detected"); - *state = State::Default; - } - - Event::UsbEp0DataDone => { - defmt::info!("EP0IN: transfer complete"); - ep0in.end(usbd); - } - - Event::UsbEp0Setup => { - if ep0setup(usbd, ep0in, state).is_err() { - defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); - usbd::ep0stall(usbd); + fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { + defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + + match event { + Event::UsbReset => { + defmt::println!("USB reset condition detected"); + *state = State::Default; + } + + Event::UsbEp0DataDone => { + defmt::println!("EP0IN: transfer complete"); + ep0in.end(usbd); + } + + Event::UsbEp0Setup => { + if ep0setup(usbd, ep0in, state).is_err() { + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); + usbd::ep0stall(usbd); + } } } } -} - -/// The `bConfigurationValue` of the only supported configuration -const CONFIG_VAL: u8 = 42; - -fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> { - let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; - let brequest = usbd.brequest.read().brequest().bits(); - let wlength = usbd::wlength(usbd); - let windex = usbd::windex(usbd); - let wvalue = usbd::wvalue(usbd); - - defmt::info!( - "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", - bmrequesttype, - brequest, - wlength, - windex, - wvalue - ); - - let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) - .expect("Error parsing request"); - defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); - // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log - // `StandardRequest` with `defmt` - match request { - // section 9.4.3 - // this request is valid in any state - Request::GetDescriptor { descriptor, length } => match descriptor { - Descriptor::Device => { - let desc = usb2::device::Descriptor { - bDeviceClass: 0, - bDeviceProtocol: 0, - bDeviceSubClass: 0, - bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, - bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), - bcdDevice: 0x01_00, // 1.00 - iManufacturer: None, - iProduct: None, - iSerialNumber: None, - idProduct: consts::PID, - idVendor: consts::VID, - }; - let bytes = desc.bytes(); - let _ = ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd); - } - - Descriptor::Configuration { index } => { - if index == 0 { - let mut resp = heapless::Vec::::new(); - - let conf_desc = usb2::configuration::Descriptor { - wTotalLength: (usb2::configuration::Descriptor::SIZE - + usb2::interface::Descriptor::SIZE) - .into(), - bNumInterfaces: NonZeroU8::new(1).unwrap(), - bConfigurationValue: core::num::NonZeroU8::new(CONFIG_VAL).unwrap(), - iConfiguration: None, - bmAttributes: usb2::configuration::bmAttributes { - self_powered: true, - remote_wakeup: false, - }, - bMaxPower: 250, // 500 mA + + /// The `bConfigurationValue` of the only supported configuration + const CONFIG_VAL: u8 = 42; + + fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> { + let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; + let brequest = usbd.brequest.read().brequest().bits(); + let wlength = usbd::wlength(usbd); + let windex = usbd::windex(usbd); + let wvalue = usbd::wvalue(usbd); + + defmt::println!( + "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + bmrequesttype, + brequest, + wlength, + windex, + wvalue + ); + + let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) + .expect("Error parsing request"); + defmt::println!("EP0: {:?}", defmt::Debug2Format(&request)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log + // `StandardRequest` with `defmt` + match request { + // section 9.4.3 + // this request is valid in any state + Request::GetDescriptor { descriptor, length } => match descriptor { + Descriptor::Device => { + let desc = usb2::device::Descriptor { + bDeviceClass: 0, + bDeviceProtocol: 0, + bDeviceSubClass: 0, + bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, + bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), + bcdDevice: 0x01_00, // 1.00 + iManufacturer: None, + iProduct: None, + iSerialNumber: None, + idProduct: consts::PID, + idVendor: consts::VID, }; - - let iface_desc = usb2::interface::Descriptor { - bInterfaceNumber: 0, - bAlternativeSetting: 0, - bNumEndpoints: 0, - bInterfaceClass: 0, - bInterfaceSubClass: 0, - bInterfaceProtocol: 0, - iInterface: None, - }; - - resp.extend_from_slice(&conf_desc.bytes()).unwrap(); - resp.extend_from_slice(&iface_desc.bytes()).unwrap(); - ep0in.start(&resp[..core::cmp::min(resp.len(), length.into())], usbd); - } else { - // out of bounds access: stall the endpoint - return Err(()); + let bytes = desc.bytes(); + let _ = ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd); } + + Descriptor::Configuration { index } => { + if index == 0 { + let mut resp = heapless::Vec::::new(); + + let conf_desc = usb2::configuration::Descriptor { + wTotalLength: (usb2::configuration::Descriptor::SIZE + + usb2::interface::Descriptor::SIZE) + .into(), + bNumInterfaces: NonZeroU8::new(1).unwrap(), + bConfigurationValue: core::num::NonZeroU8::new(CONFIG_VAL).unwrap(), + iConfiguration: None, + bmAttributes: usb2::configuration::bmAttributes { + self_powered: true, + remote_wakeup: false, + }, + bMaxPower: 250, // 500 mA + }; + + let iface_desc = usb2::interface::Descriptor { + bInterfaceNumber: 0, + bAlternativeSetting: 0, + bNumEndpoints: 0, + bInterfaceClass: 0, + bInterfaceSubClass: 0, + bInterfaceProtocol: 0, + iInterface: None, + }; + + resp.extend_from_slice(&conf_desc.bytes()).unwrap(); + resp.extend_from_slice(&iface_desc.bytes()).unwrap(); + ep0in.start(&resp[..core::cmp::min(resp.len(), length.into())], usbd); + } else { + // out of bounds access: stall the endpoint + return Err(()); + } + } + + _ => return Err(()), + }, + + Request::SetAddress { address } => { + match state { + State::Default => { + if let Some(address) = address { + *state = State::Address(address); + } else { + // stay in the default state + } + } + + State::Address(..) => { + if let Some(address) = address { + // use the new address + *state = State::Address(address); + } else { + *state = State::Default; + } + } + + // unspecified behavior + State::Configured { .. } => return Err(()), + } + + // the response to this request is handled in hardware } - + + // stall any other request _ => return Err(()), - }, - - Request::SetAddress { address } => { - match state { - State::Default => { - if let Some(address) = address { - *state = State::Address(address); - } else { - // stay in the default state - } - } - - State::Address(..) => { - if let Some(address) = address { - // use the new address - *state = State::Address(address); - } else { - *state = State::Default; - } - } - - // unspecified behavior - State::Configured { .. } => return Err(()), - } - - // the response to this request is handled in hardware } - - // stall any other request - _ => return Err(()), + + Ok(()) } - - Ok(()) + } + diff --git a/advanced/firmware/src/bin/usb-4.rs b/advanced/firmware/src/bin/usb-4.rs index a9c1e14..3746502 100644 --- a/advanced/firmware/src/bin/usb-4.rs +++ b/advanced/firmware/src/bin/usb-4.rs @@ -1,135 +1,143 @@ #![no_main] #![no_std] -use dk::{ - peripheral::USBD, - usbd::{self, Ep0In, Event}, -}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -use usb2::State; -// HEADS UP to use *your* USB packet parser uncomment line 12 and remove line 13 -// use usb::{Request, Descriptor}; -use usb2::{GetDescriptor as Descriptor, StandardRequest as Request}; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { +#[rtic::app(device = dk, peripherals = false)] +mod app { + + use core::num::NonZeroU8; + + use dk::{ + peripheral::USBD, + usbd::{self, Ep0In, Event}, + Peripherals, + }; + use usb2::State; + // HEADS UP to use *your* USB packet parser uncomment line 12 and remove line 13 + // use usb::{Request, Descriptor}; + use usb2::{GetDescriptor as Descriptor, StandardRequest as Request}; + + #[local] + struct MyLocalResources { usbd: USBD, ep0in: Ep0In, state: State, } + #[shared] + struct MySharedResources { + } + #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); usbd::init(board.power, &board.usbd); - init::LateResources { - usbd: board.usbd, - state: State::Default, - ep0in: board.ep0in, - } + (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, state: State::Default, }, init::Monotonics()) } - #[task(binds = USBD, resources = [usbd, ep0in, state])] + #[task(binds = USBD, local = [usbd, ep0in, state])] fn main(cx: main::Context) { - let usbd = cx.resources.usbd; - let ep0in = cx.resources.ep0in; - let state = cx.resources.state; + let usbd = cx.local.usbd; + let ep0in = cx.local.ep0in; + let state = cx.local.state; while let Some(event) = usbd::next_event(usbd) { on_event(usbd, ep0in, state, event) } } -}; -fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); - - match event { - // TODO change `state` as specified in chapter 9.1 USB Device States, of the USB specification - Event::UsbReset => { - defmt::info!("USB reset condition detected"); - todo!(); - } - - Event::UsbEp0DataDone => { - defmt::info!("EP0IN: transfer complete"); - ep0in.end(usbd); - } - - Event::UsbEp0Setup => { - if ep0setup(usbd, ep0in, state).is_err() { - // unsupported or invalid request: - // TODO: add code to stall the endpoint - defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); + fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { + defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + + match event { + // TODO change `state` as specified in chapter 9.1 USB Device States, of the USB specification + Event::UsbReset => { + defmt::println!("USB reset condition detected"); + todo!(); + } + + Event::UsbEp0DataDone => { + defmt::println!("EP0IN: transfer complete"); + ep0in.end(usbd); + } + + Event::UsbEp0Setup => { + if ep0setup(usbd, ep0in, state).is_err() { + // unsupported or invalid request: + // TODO: add code to stall the endpoint + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); + } } } } -} - -fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), ()> { - let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; - let brequest = usbd.brequest.read().brequest().bits(); - let wlength = usbd::wlength(usbd); - let windex = usbd::windex(usbd); - let wvalue = usbd::wvalue(usbd); - - defmt::info!( - "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", - bmrequesttype, - brequest, - wlength, - windex, - wvalue - ); - - let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) - .expect("Error parsing request"); - defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); - // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log - // `StandardRequest` with `defmt` - - match request { - Request::GetDescriptor { descriptor, length } => match descriptor { - Descriptor::Device => { - let desc = usb2::device::Descriptor { - bDeviceClass: 0, - bDeviceProtocol: 0, - bDeviceSubClass: 0, - bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, - bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), - bcdDevice: 0x01_00, // 1.00 - iManufacturer: None, - iProduct: None, - iSerialNumber: None, - idProduct: consts::PID, - idVendor: consts::VID, - }; - let bytes = desc.bytes(); - let _ = ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd); + + fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), ()> { + let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; + let brequest = usbd.brequest.read().brequest().bits(); + let wlength = usbd::wlength(usbd); + let windex = usbd::windex(usbd); + let wvalue = usbd::wvalue(usbd); + + defmt::println!( + "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + bmrequesttype, + brequest, + wlength, + windex, + wvalue + ); + + let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) + .expect("Error parsing request"); + defmt::println!("EP0: {:?}", defmt::Debug2Format(&request)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log + // `StandardRequest` with `defmt` + + match request { + Request::GetDescriptor { descriptor, length } => match descriptor { + Descriptor::Device => { + let desc = usb2::device::Descriptor { + bDeviceClass: 0, + bDeviceProtocol: 0, + bDeviceSubClass: 0, + bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, + bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), + bcdDevice: 0x01_00, // 1.00 + iManufacturer: None, + iProduct: None, + iSerialNumber: None, + idProduct: consts::PID, + idVendor: consts::VID, + }; + let bytes = desc.bytes(); + let _ = ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd); + } + + // TODO implement Configuration descriptor + // Descriptor::Configuration { .. } => todo!(), + + // stall any other request + _ => return Err(()), + }, + Request::SetAddress { .. } => { + // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we + // need to catch it here. + + // TODO: handle this request properly now. + todo!() } - - // TODO implement Configuration descriptor - // Descriptor::Configuration { .. } => todo!(), - + // stall any other request _ => return Err(()), - }, - Request::SetAddress { .. } => { - // On Mac OS you'll get this request before the GET_DESCRIPTOR request so we - // need to catch it here. - - // TODO: handle this request properly now. - todo!() } - - // stall any other request - _ => return Err(()), + + Ok(()) } - - Ok(()) + } + diff --git a/advanced/firmware/src/bin/usb-5-solution.rs b/advanced/firmware/src/bin/usb-5-solution.rs index bf12ddf..bacff4d 100644 --- a/advanced/firmware/src/bin/usb-5-solution.rs +++ b/advanced/firmware/src/bin/usb-5-solution.rs @@ -1,235 +1,240 @@ #![no_main] #![no_std] -use core::num::NonZeroU8; - -use dk::{ - peripheral::USBD, - usbd::{self, Ep0In, Event}, -}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State}; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { +#[rtic::app(device = dk, peripherals = false)] +mod app { + + use core::num::NonZeroU8; + + use dk::{ + peripheral::USBD, + usbd::{self, Ep0In, Event}, + Peripherals, + }; + use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State}; + + #[local] + struct MyLocalResources { usbd: USBD, ep0in: Ep0In, state: State, } + #[shared] + struct MySharedResources { + + } #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); usbd::init(board.power, &board.usbd); - init::LateResources { - usbd: board.usbd, - state: State::Default, - ep0in: board.ep0in, - } + (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, state: State::Default, }, init::Monotonics()) } - #[task(binds = USBD, resources = [usbd, ep0in, state])] + #[task(binds = USBD, local = [usbd, ep0in, state])] fn main(cx: main::Context) { - let usbd = cx.resources.usbd; - let ep0in = cx.resources.ep0in; - let state = cx.resources.state; + let usbd = cx.local.usbd; + let ep0in = cx.local.ep0in; + let state = cx.local.state; while let Some(event) = usbd::next_event(usbd) { on_event(usbd, ep0in, state, event) } } -}; - -fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); - - match event { - Event::UsbReset => { - defmt::info!("USB reset condition detected"); - *state = State::Default; - } - - Event::UsbEp0DataDone => { - defmt::info!("EP0IN: transfer complete"); - ep0in.end(usbd); - } - - Event::UsbEp0Setup => { - if ep0setup(usbd, ep0in, state).is_err() { - defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); - usbd::ep0stall(usbd); + fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { + defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + + match event { + Event::UsbReset => { + defmt::println!("USB reset condition detected"); + *state = State::Default; + } + + Event::UsbEp0DataDone => { + defmt::println!("EP0IN: transfer complete"); + ep0in.end(usbd); + } + + Event::UsbEp0Setup => { + if ep0setup(usbd, ep0in, state).is_err() { + defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); + usbd::ep0stall(usbd); + } } } } -} - -/// The `bConfigurationValue` of the only supported configuration -const CONFIG_VAL: u8 = 42; - -fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> { - let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; - let brequest = usbd.brequest.read().brequest().bits(); - let wlength = usbd::wlength(usbd); - let windex = usbd::windex(usbd); - let wvalue = usbd::wvalue(usbd); - - defmt::info!( - "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", - bmrequesttype, - brequest, - wlength, - windex, - wvalue - ); - - let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) - .expect("Error parsing request"); - defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); - // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log - // `StandardRequest` with `defmt` - - match request { - // section 9.4.3 - // this request is valid in any state - Request::GetDescriptor { descriptor, length } => match descriptor { - Descriptor::Device => { - let desc = usb2::device::Descriptor { - bDeviceClass: 0, - bDeviceProtocol: 0, - bDeviceSubClass: 0, - bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, - bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), - bcdDevice: 0x01_00, // 1.00 - iManufacturer: None, - iProduct: None, - iSerialNumber: None, - idProduct: consts::PID, - idVendor: consts::VID, - }; - let bytes = desc.bytes(); - let _ = ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd); - } - - Descriptor::Configuration { index } => { - if index == 0 { - let mut resp = heapless::Vec::::new(); - - let conf_desc = usb2::configuration::Descriptor { - wTotalLength: (usb2::configuration::Descriptor::SIZE - + usb2::interface::Descriptor::SIZE) - .into(), - bNumInterfaces: NonZeroU8::new(1).unwrap(), - bConfigurationValue: core::num::NonZeroU8::new(CONFIG_VAL).unwrap(), - iConfiguration: None, - bmAttributes: usb2::configuration::bmAttributes { - self_powered: true, - remote_wakeup: false, - }, - bMaxPower: 250, // 500 mA + + /// The `bConfigurationValue` of the only supported configuration + const CONFIG_VAL: u8 = 42; + + fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> { + let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; + let brequest = usbd.brequest.read().brequest().bits(); + let wlength = usbd::wlength(usbd); + let windex = usbd::windex(usbd); + let wvalue = usbd::wvalue(usbd); + + defmt::println!( + "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + bmrequesttype, + brequest, + wlength, + windex, + wvalue + ); + + let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) + .expect("Error parsing request"); + defmt::println!("EP0: {:?}", defmt::Debug2Format(&request)); + // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log + // `StandardRequest` with `defmt` + + match request { + // section 9.4.3 + // this request is valid in any state + Request::GetDescriptor { descriptor, length } => match descriptor { + Descriptor::Device => { + let desc = usb2::device::Descriptor { + bDeviceClass: 0, + bDeviceProtocol: 0, + bDeviceSubClass: 0, + bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, + bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), + bcdDevice: 0x01_00, // 1.00 + iManufacturer: None, + iProduct: None, + iSerialNumber: None, + idProduct: consts::PID, + idVendor: consts::VID, }; - - let iface_desc = usb2::interface::Descriptor { - bInterfaceNumber: 0, - bAlternativeSetting: 0, - bNumEndpoints: 0, - bInterfaceClass: 0, - bInterfaceSubClass: 0, - bInterfaceProtocol: 0, - iInterface: None, - }; - - resp.extend_from_slice(&conf_desc.bytes()).unwrap(); - resp.extend_from_slice(&iface_desc.bytes()).unwrap(); - ep0in.start(&resp[..core::cmp::min(resp.len(), length.into())], usbd); - } else { - // out of bounds access: stall the endpoint - return Err(()); + let bytes = desc.bytes(); + let _ = ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd); } - } - - _ => return Err(()), - }, - - Request::SetAddress { address } => { - match state { - State::Default => { - if let Some(address) = address { - *state = State::Address(address); + + Descriptor::Configuration { index } => { + if index == 0 { + let mut resp = heapless::Vec::::new(); + + let conf_desc = usb2::configuration::Descriptor { + wTotalLength: (usb2::configuration::Descriptor::SIZE + + usb2::interface::Descriptor::SIZE) + .into(), + bNumInterfaces: NonZeroU8::new(1).unwrap(), + bConfigurationValue: core::num::NonZeroU8::new(CONFIG_VAL).unwrap(), + iConfiguration: None, + bmAttributes: usb2::configuration::bmAttributes { + self_powered: true, + remote_wakeup: false, + }, + bMaxPower: 250, // 500 mA + }; + + let iface_desc = usb2::interface::Descriptor { + bInterfaceNumber: 0, + bAlternativeSetting: 0, + bNumEndpoints: 0, + bInterfaceClass: 0, + bInterfaceSubClass: 0, + bInterfaceProtocol: 0, + iInterface: None, + }; + + resp.extend_from_slice(&conf_desc.bytes()).unwrap(); + resp.extend_from_slice(&iface_desc.bytes()).unwrap(); + ep0in.start(&resp[..core::cmp::min(resp.len(), length.into())], usbd); } else { - // stay in the default state + // out of bounds access: stall the endpoint + return Err(()); } } - - State::Address(..) => { - if let Some(address) = address { - // use the new address - *state = State::Address(address); - } else { - *state = State::Default; - } - } - - // unspecified behavior - State::Configured { .. } => return Err(()), - } - - // the response to this request is handled in hardware - } - - Request::SetConfiguration { value } => { - match *state { - // unspecified behavior - State::Default => return Err(()), - - State::Address(address) => { - if let Some(value) = value { - if value.get() == CONFIG_VAL { - defmt::info!("entering the configured state"); - *state = State::Configured { address, value }; + + _ => return Err(()), + }, + + Request::SetAddress { address } => { + match state { + State::Default => { + if let Some(address) = address { + *state = State::Address(address); } else { - defmt::error!("unsupported configuration value"); - return Err(()); + // stay in the default state } - } else { - // stay in the address mode } + + State::Address(..) => { + if let Some(address) = address { + // use the new address + *state = State::Address(address); + } else { + *state = State::Default; + } + } + + // unspecified behavior + State::Configured { .. } => return Err(()), } - - State::Configured { - address, - value: curr_value, - } => { - if let Some(new_value) = value { - if new_value.get() == CONFIG_VAL { - if new_value != curr_value { - defmt::info!("changing configuration"); - *state = State::Configured { - address, - value: new_value, - }; + + // the response to this request is handled in hardware + } + + Request::SetConfiguration { value } => { + match *state { + // unspecified behavior + State::Default => return Err(()), + + State::Address(address) => { + if let Some(value) = value { + if value.get() == CONFIG_VAL { + defmt::println!("entering the configured state"); + *state = State::Configured { address, value }; + } else { + defmt::error!("unsupported configuration value"); + return Err(()); } } else { - defmt::error!("unsupported configuration value"); - return Err(()); + // stay in the address mode + } + } + + State::Configured { + address, + value: curr_value, + } => { + if let Some(new_value) = value { + if new_value.get() == CONFIG_VAL { + if new_value != curr_value { + defmt::println!("changing configuration"); + *state = State::Configured { + address, + value: new_value, + }; + } + } else { + defmt::error!("unsupported configuration value"); + return Err(()); + } + } else { + defmt::println!("returned to the address state"); + *state = State::Address(address); } - } else { - defmt::info!("returned to the address state"); - *state = State::Address(address); } } + + usbd.tasks_ep0status + .write(|w| w.tasks_ep0status().set_bit()); } - - usbd.tasks_ep0status - .write(|w| w.tasks_ep0status().set_bit()); + + // stall any other request + _ => return Err(()), } - - // stall any other request - _ => return Err(()), + + Ok(()) } - - Ok(()) + } + diff --git a/advanced/firmware/src/bin/vec.rs b/advanced/firmware/src/bin/vec.rs index f009ee6..3206b18 100644 --- a/advanced/firmware/src/bin/vec.rs +++ b/advanced/firmware/src/bin/vec.rs @@ -17,13 +17,13 @@ fn main() -> ! { // `heapless::Vec` exposes the same API surface as `std::Vec` but some of its methods return a // `Result` to indicate whether the operation failed due to the `heapless::Vec` being full - defmt::info!("start: {:?}", buffer); + defmt::println!("start: {:?}", buffer); buffer.push(0).expect("buffer full"); - defmt::info!("after `push`: {:?}", buffer); + defmt::println!("after `push`: {:?}", buffer); buffer.extend_from_slice(&[1, 2, 3]).expect("buffer full"); - defmt::info!("after `extend`: {:?}", &buffer); + defmt::println!("after `extend`: {:?}", &buffer); // TODO try this operation // buffer.extend_from_slice(&[4, 5, 6, 7]).expect("buffer full"); diff --git a/beginner/apps/src/bin/blinky.rs b/beginner/apps/src/bin/blinky.rs index a3e10b1..54fdca4 100644 --- a/beginner/apps/src/bin/blinky.rs +++ b/beginner/apps/src/bin/blinky.rs @@ -20,7 +20,7 @@ fn main() -> ! { for _ in 0..10 { led.toggle(); timer.wait(Duration::from_secs(1)); - defmt::info!("LED toggled at {:?}", dk::uptime()); + defmt::println!("LED toggled at {:?}", dk::uptime()); } dk::exit() diff --git a/beginner/apps/src/bin/hello.rs b/beginner/apps/src/bin/hello.rs index 0c40dce..42b4269 100644 --- a/beginner/apps/src/bin/hello.rs +++ b/beginner/apps/src/bin/hello.rs @@ -19,7 +19,7 @@ fn main() -> ! { // initializes the peripherals dk::init().unwrap(); - defmt::info!("Hello, world!"); // :wave: + defmt::println!("Hello, world!"); // :wave: loop { // breakpoint: halts the program's execution diff --git a/beginner/apps/src/bin/panic.rs b/beginner/apps/src/bin/panic.rs index b065acb..befa1c7 100644 --- a/beginner/apps/src/bin/panic.rs +++ b/beginner/apps/src/bin/panic.rs @@ -4,7 +4,7 @@ use cortex_m::asm; use cortex_m_rt::entry; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior -use apps as _; +// use apps as _; #[entry] fn main() -> ! { @@ -29,7 +29,7 @@ fn bar() { let array = [0, 1, 2]; let x = array[i]; // out of bounds access - defmt::info!("{}", x); + defmt::println!("{}", x); } fn index() -> usize { diff --git a/beginner/apps/src/bin/radio-puzzle-1.rs b/beginner/apps/src/bin/radio-puzzle-1.rs index 95f1946..3ced295 100644 --- a/beginner/apps/src/bin/radio-puzzle-1.rs +++ b/beginner/apps/src/bin/radio-puzzle-1.rs @@ -38,9 +38,9 @@ fn main() -> ! { if packet.len() == 1 { let destination = packet[0]; - defmt::info!("{} -> {}", source, destination); + defmt::println!("{} -> {}", source, destination); // or cast to `char` for a more readable output - defmt::info!("{:?} -> {:?}", source as char, destination as char); + defmt::println!("{:?} -> {:?}", source as char, destination as char); } else { defmt::error!("response packet was not a single byte"); dk::exit() diff --git a/beginner/apps/src/bin/radio-puzzle-2.rs b/beginner/apps/src/bin/radio-puzzle-2.rs index edab631..57637ca 100644 --- a/beginner/apps/src/bin/radio-puzzle-2.rs +++ b/beginner/apps/src/bin/radio-puzzle-2.rs @@ -27,9 +27,9 @@ fn main() -> ! { let key = b'A'; let value = dict[&key]; // the key needs to be passed by reference - defmt::info!("{} -> {}", key, value); + defmt::println!("{} -> {}", key, value); // more readable - defmt::info!("{:?} -> {:?}", key as char, value as char); + defmt::println!("{:?} -> {:?}", key as char, value as char); // TODO try another insertion // TODO try looking up a key not contained in the dictionary diff --git a/beginner/apps/src/bin/radio-puzzle-3.rs b/beginner/apps/src/bin/radio-puzzle-3.rs index 96f9e39..10529f4 100644 --- a/beginner/apps/src/bin/radio-puzzle-3.rs +++ b/beginner/apps/src/bin/radio-puzzle-3.rs @@ -46,7 +46,7 @@ fn main() -> ! { } } - defmt::info!("{:?}", defmt::Debug2Format(&dict)); + defmt::println!("{:?}", defmt::Debug2Format(&dict)); // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log `heapless` // data structures (like `LinearMap` here) with `defmt` diff --git a/beginner/apps/src/bin/radio-puzzle-4.rs b/beginner/apps/src/bin/radio-puzzle-4.rs index e4a8c69..49fa4e0 100644 --- a/beginner/apps/src/bin/radio-puzzle-4.rs +++ b/beginner/apps/src/bin/radio-puzzle-4.rs @@ -22,11 +22,11 @@ fn main() -> ! { buffer.push(b'i').expect("buffer full"); // look into the contents so far - defmt::info!("{:?}", buffer); + defmt::println!("{:?}", buffer); // or more readable // NOTE utf-8 conversion works as long as you only push bytes in the ASCII range (0..=127) - defmt::info!( + defmt::println!( "{}", str::from_utf8(&buffer).expect("content was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle-5.rs b/beginner/apps/src/bin/radio-puzzle-5.rs index e46643a..d90699a 100644 --- a/beginner/apps/src/bin/radio-puzzle-5.rs +++ b/beginner/apps/src/bin/radio-puzzle-5.rs @@ -32,7 +32,7 @@ fn main() -> ! { dk::exit() } - defmt::info!( + defmt::println!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -48,7 +48,7 @@ fn main() -> ! { buf.push(output).expect("buffer full"); } - defmt::info!( + defmt::println!( "plaintext: {}", str::from_utf8(&buf).expect("buffer contains non-UTF-8 data") ); diff --git a/beginner/apps/src/bin/radio-puzzle-6.rs b/beginner/apps/src/bin/radio-puzzle-6.rs index d1c326c..172d093 100644 --- a/beginner/apps/src/bin/radio-puzzle-6.rs +++ b/beginner/apps/src/bin/radio-puzzle-6.rs @@ -56,7 +56,7 @@ fn main() -> ! { dk::exit() } - defmt::info!( + defmt::println!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -72,7 +72,7 @@ fn main() -> ! { buffer.push(value).expect("buffer full"); } - defmt::info!( + defmt::println!( "plaintext: {}", str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") ); diff --git a/beginner/apps/src/bin/radio-puzzle-7.rs b/beginner/apps/src/bin/radio-puzzle-7.rs index 9116db8..80171e2 100644 --- a/beginner/apps/src/bin/radio-puzzle-7.rs +++ b/beginner/apps/src/bin/radio-puzzle-7.rs @@ -56,7 +56,7 @@ fn main() -> ! { dk::exit() } - defmt::info!( + defmt::println!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -72,7 +72,7 @@ fn main() -> ! { buffer.push(value).expect("buffer full"); } - defmt::info!( + defmt::println!( "plaintext: {}", str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") ); @@ -87,7 +87,7 @@ fn main() -> ! { dk::exit() } - defmt::info!( + defmt::println!( "Dongle response: {}", str::from_utf8(&packet).expect("response was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle-solution-2.rs b/beginner/apps/src/bin/radio-puzzle-solution-2.rs index 6007f0f..6f809a0 100644 --- a/beginner/apps/src/bin/radio-puzzle-solution-2.rs +++ b/beginner/apps/src/bin/radio-puzzle-solution-2.rs @@ -57,7 +57,7 @@ fn main() -> ! { dk::exit() } - defmt::info!( + defmt::println!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -75,7 +75,7 @@ fn main() -> ! { *spot = plainletter; } - defmt::info!( + defmt::println!( "plaintext: {}", str::from_utf8(&packet).expect("buffer contains non-UTF-8 data") ); @@ -88,7 +88,7 @@ fn main() -> ! { dk::exit() } - defmt::info!( + defmt::println!( "Dongle response: {}", str::from_utf8(&packet).expect("response was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle-solution.rs b/beginner/apps/src/bin/radio-puzzle-solution.rs index 4a7e00f..7874052 100644 --- a/beginner/apps/src/bin/radio-puzzle-solution.rs +++ b/beginner/apps/src/bin/radio-puzzle-solution.rs @@ -60,7 +60,7 @@ fn main() -> ! { dk::exit() } - defmt::info!( + defmt::println!( "ciphertext: {}", str::from_utf8(&packet).expect("packet was not valid UTF-8") ); @@ -77,7 +77,7 @@ fn main() -> ! { buffer.push(plainletter).expect("buffer full"); } - defmt::info!( + defmt::println!( "plaintext: {}", str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") ); @@ -92,7 +92,7 @@ fn main() -> ! { dk::exit() } - defmt::info!( + defmt::println!( "Dongle response: {}", str::from_utf8(&packet).expect("response was not UTF-8") ); diff --git a/beginner/apps/src/bin/radio-puzzle.rs b/beginner/apps/src/bin/radio-puzzle.rs index 522cb99..859bd54 100644 --- a/beginner/apps/src/bin/radio-puzzle.rs +++ b/beginner/apps/src/bin/radio-puzzle.rs @@ -34,14 +34,14 @@ fn main() -> ! { // let msg = b"Hello?"; packet.copy_from_slice(msg); - defmt::info!( + defmt::println!( "sending: {}", str::from_utf8(msg).expect("msg was not valid UTF-8 data") ); radio.send(&mut packet); if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_ok() { - defmt::info!( + defmt::println!( "received: {}", str::from_utf8(&packet).expect("response was not valid UTF-8 data") ); diff --git a/beginner/apps/src/bin/radio-recv.rs b/beginner/apps/src/bin/radio-recv.rs index e3642b0..5338d3f 100644 --- a/beginner/apps/src/bin/radio-recv.rs +++ b/beginner/apps/src/bin/radio-recv.rs @@ -25,7 +25,7 @@ fn main() -> ! { let msg = b"olleh"; packet.copy_from_slice(msg); - defmt::info!( + defmt::println!( "sending: {}", str::from_utf8(msg).expect("message is not valid UTF-8") ); @@ -38,7 +38,7 @@ fn main() -> ! { match res { Ok(crc) => { - defmt::info!( + defmt::println!( "received: {} (CRC = {:X})", // ^^ print as uppercase hexadecimal str::from_utf8(&*packet).expect("response is not valid UTF-8"), diff --git a/beginner/apps/src/bin/radio-send.rs b/beginner/apps/src/bin/radio-send.rs index 4d09180..7d34d98 100644 --- a/beginner/apps/src/bin/radio-send.rs +++ b/beginner/apps/src/bin/radio-send.rs @@ -26,7 +26,7 @@ fn main() -> ! { // let msg: &[u8; 5] = &[b'H', b'e', b'l', b'l', b'o']; // let msg: &[u8; 5] = b"Hello"; - defmt::info!( + defmt::println!( "sending: {}", str::from_utf8(msg).expect("msg is not valid UTF-8 data") ); diff --git a/beginner/apps/src/bin/stack_overflow.rs b/beginner/apps/src/bin/stack_overflow.rs index 24c73da..ff4b37c 100644 --- a/beginner/apps/src/bin/stack_overflow.rs +++ b/beginner/apps/src/bin/stack_overflow.rs @@ -22,7 +22,7 @@ fn main() -> ! { fn fib(n: u32) -> u32 { // allocate and initialize one kilobyte of stack memory to provoke stack overflow let use_stack = [0xAA; 1024]; - defmt::info!("allocating [{}; 1024]; round #{}", use_stack[1023], n); + defmt::println!("allocating [{}; 1024]; round #{}", use_stack[1023], n); if n < 2 { 1 diff --git a/boards/dk/src/lib.rs b/boards/dk/src/lib.rs index a368db6..3ece095 100644 --- a/boards/dk/src/lib.rs +++ b/boards/dk/src/lib.rs @@ -14,7 +14,8 @@ use cortex_m::{asm, peripheral::NVIC}; use embedded_hal::digital::v2::{OutputPin as _, StatefulOutputPin}; #[cfg(feature = "beginner")] pub use hal::ieee802154; -pub use hal::pac::{interrupt, Interrupt, NVIC_PRIO_BITS, RTC0}; +#[doc(hidden)] +pub use hal::pac::{Peripherals, interrupt, Interrupt, NVIC_PRIO_BITS, RTC0}; use hal::{ clocks::{self, Clocks}, gpio::{p0, Level, Output, Pin, Port, PushPull}, @@ -289,7 +290,7 @@ fn RTC0() { /// Exits the application and prints a backtrace when the program is executed through the `probe-run` /// Cargo runner pub fn exit() -> ! { - defmt::info!("`dk::exit()` called; exiting ..."); + defmt::println!("`dk::exit()` called; exiting ..."); // force any pending memory operation to complete before the BKPT instruction that follows atomic::compiler_fence(Ordering::SeqCst); loop { diff --git a/boards/dk/src/usbd.rs b/boards/dk/src/usbd.rs index d1ee75c..ae77157 100644 --- a/boards/dk/src/usbd.rs +++ b/boards/dk/src/usbd.rs @@ -51,7 +51,7 @@ impl Ep0In { self.busy = true; - defmt::info!("EP0IN: start {}B transfer", n); + defmt::println!("EP0IN: start {}B transfer", n); // start DMA transfer dma_start(); @@ -75,7 +75,7 @@ impl Ep0In { usbd.events_ep0datadone.reset(); self.busy = false; - defmt::info!("EP0IN: transfer done"); + defmt::println!("EP0IN: transfer done"); } } } @@ -110,7 +110,7 @@ pub fn init(power: POWER, usbd: &USBD) { // wait until the USB cable has been connected while power.events_usbdetected.read().bits() == 0 { if once { - defmt::info!("waiting for USB connection on port J3"); + defmt::println!("waiting for USB connection on port J3"); once = false; } diff --git a/embedded-workshop-book/src/interfaces.md b/embedded-workshop-book/src/interfaces.md index 56f942d..9f1f518 100644 --- a/embedded-workshop-book/src/interfaces.md +++ b/embedded-workshop-book/src/interfaces.md @@ -10,7 +10,7 @@ Inside the 'configuration 1' rectangle there are two rectangles labeled 'control Inside the 'interface 0' rectangle there are three rectangles labeled 'endpoint 1 IN', 'endpoint 2 IN' and 'endpoint 2 OUT'. Between these three rectangle there is a label that says 'bNumEndpoints=3'; it indicates that this interface has only three endpoints.">

-An interface is closest to a USB device's function. For example, a USB mouse may expose a single HID (Human Interface Device) interface to report user input to the host. USB devices can expose multiple interfaces within a configuration. For example, the nRF52840 Dongle could expose both a CDC ACM interface (AKA virtual serial port) *and* a HID interface; the first interface could be used for (`defmt::info!`-style) logs; and the second one could provide a RPC (Remote Procedure Call) interface to the host for controlling the nRF52840's radio. +An interface is closest to a USB device's function. For example, a USB mouse may expose a single HID (Human Interface Device) interface to report user input to the host. USB devices can expose multiple interfaces within a configuration. For example, the nRF52840 Dongle could expose both a CDC ACM interface (AKA virtual serial port) *and* a HID interface; the first interface could be used for (`defmt::println!`-style) logs; and the second one could provide a RPC (Remote Procedure Call) interface to the host for controlling the nRF52840's radio. An interface is made up of one or more *endpoints*. To give an example, a HID interface can use two (interrupt) endpoints, one IN and one OUT, for bidirectional communication with the host. A single endpoint cannot be used by more than one interface with the exception of the special "endpoint 0", which can be (and usually is) shared by all interfaces. diff --git a/embedded-workshop-book/src/messages.md b/embedded-workshop-book/src/messages.md index c6df898..7da4948 100644 --- a/embedded-workshop-book/src/messages.md +++ b/embedded-workshop-book/src/messages.md @@ -32,11 +32,11 @@ let array1: [u8; 3] = [0, 1, 2]; let array2: [u8; 4] = [0, 1, 2, 3]; let mut slice: &[u8] = &array1; -defmt::info!("{:?}", slice); // length = 3 +defmt::println!("{:?}", slice); // length = 3 // now point to the other array slice = &array2; -defmt::info!("{:?}", slice); // length = 4 +defmt::println!("{:?}", slice); // length = 4 ``` ## Byte literals @@ -82,8 +82,8 @@ On the other hand, `"Hello"` is a string literal with type `&str`. `str` strings In this workshop we'll work with ASCII strings so byte string literals that contain no escaped characters are OK to use as packet payloads. -You'll note that `defmt::info!("{:?}", b"Hello")` will print `[72, 101, 108, 108, 111]` rather than `"Hello"` and that the `{}` format specifier (`Display`) does not work. This is because the type of the literal is `&[u8; N]` and in Rust this type means "bytes"; those bytes could be ASCII data, UTF-8 data or something else. +You'll note that `defmt::println!("{:?}", b"Hello")` will print `[72, 101, 108, 108, 111]` rather than `"Hello"` and that the `{}` format specifier (`Display`) does not work. This is because the type of the literal is `&[u8; N]` and in Rust this type means "bytes"; those bytes could be ASCII data, UTF-8 data or something else. To print this you'll need to convert the slice `&[u8]` into a string (`&str`) using the `str::from_utf8` function. This function will verify that the slice contains well formed UTF-8 data and interpret it as a UTF-8 string (`&str`). As long as we use ASCII data (printable ASCII characters) this conversion will not fail. -Something similar will happen with byte literals: `defmt::info!("{}", b'A')` will print `65` rather than `A`. To get the `A` output you can cast the byte literal (`u8` value) to the `char` type: `defmt::info!("{}", b'A' as char)`. \ No newline at end of file +Something similar will happen with byte literals: `defmt::println!("{}", b'A')` will print `65` rather than `A`. To get the `A` output you can cast the byte literal (`u8` value) to the `char` type: `defmt::println!("{}", b'A' as char)`. \ No newline at end of file diff --git a/embedded-workshop-book/src/radio-puzzle-help.md b/embedded-workshop-book/src/radio-puzzle-help.md index f529514..86e71f6 100644 --- a/embedded-workshop-book/src/radio-puzzle-help.md +++ b/embedded-workshop-book/src/radio-puzzle-help.md @@ -56,7 +56,7 @@ fn main() -> ! { for plainletter in 0..=127 { /* ... send letter to dongle ... */ - defmt::info!("got response"); + defmt::println!("got response"); /* ... store output ... */ timer.wait(Duration::from_millis(20)); diff --git a/embedded-workshop-book/src/time.md b/embedded-workshop-book/src/time.md index 91b6cc5..7598df6 100644 --- a/embedded-workshop-book/src/time.md +++ b/embedded-workshop-book/src/time.md @@ -12,4 +12,4 @@ The other time related API exposed by the `dk` HAL is the `dk::uptime` function. ✅ Try changing the `Duration` value passed to `Timer.wait`. Try values larger than one second and smaller than one second. What values of `Duration` make the blinking imperceptible? -❗If you set the duration to below 2ms, try removing the `defmt::info!` command in the loop. Too much logging will fill the logging buffer and cause the loop to slow down, resulting in the blink frequency to reduce after a while. +❗If you set the duration to below 2ms, try removing the `defmt::println!` command in the loop. Too much logging will fill the logging buffer and cause the loop to slow down, resulting in the blink frequency to reduce after a while. From bea6eb0b21e5f62e382724d3ff0276c4a3f00be2 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Fri, 7 Jan 2022 18:23:35 +0100 Subject: [PATCH 27/29] update book --- advanced/firmware/src/bin/events.rs | 24 +++++++--- .../firmware/src/bin/resource-solution.rs | 45 ++++++++++++------- advanced/firmware/src/bin/resource.rs | 33 ++++++++------ advanced/firmware/src/bin/rtic-hello.rs | 1 - embedded-workshop-book/src/task-state.md | 15 ++++--- 5 files changed, 74 insertions(+), 44 deletions(-) diff --git a/advanced/firmware/src/bin/events.rs b/advanced/firmware/src/bin/events.rs index aee1170..20fa648 100644 --- a/advanced/firmware/src/bin/events.rs +++ b/advanced/firmware/src/bin/events.rs @@ -1,14 +1,24 @@ #![no_main] #![no_std] -use cortex_m::asm; + // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -#[rtic::app(device = dk)] -const APP: () = { +#[rtic::app(device = dk, peripherals = false)] +mod app { + use cortex_m::asm; + + #[local] + struct MyLocalResources { + } + + #[shared] + struct MySharedResources { + } + #[init] - fn init(_cx: init::Context) { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); // `POWER` is a peripheral, or register block @@ -39,10 +49,12 @@ const APP: () = { let vbusdetect: bool = power.usbregstatus.read().vbusdetect().bits(); // ^^^^^^^^^^ bitfield name defmt::println!("USBREGSTATUS.VBUSDETECT: {}", vbusdetect); + + (MySharedResources {}, MyLocalResources {}, init::Monotonics()) } #[idle] - fn main(_cx: main::Context) -> ! { + fn idle(_cx: idle::Context) -> ! { defmt::println!("idle: going to sleep"); // sleep in the background @@ -56,4 +68,4 @@ const APP: () = { defmt::println!("POWER event occurred"); asm::bkpt(); } -}; +} diff --git a/advanced/firmware/src/bin/resource-solution.rs b/advanced/firmware/src/bin/resource-solution.rs index f5e3367..0083b43 100644 --- a/advanced/firmware/src/bin/resource-solution.rs +++ b/advanced/firmware/src/bin/resource-solution.rs @@ -1,20 +1,26 @@ #![no_main] #![no_std] -use cortex_m::asm; -use dk::peripheral::POWER; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { +#[rtic::app(device = dk, peripherals = false)] +mod app { + use cortex_m::asm; + use dk::peripheral::POWER; + + #[local] + struct MyLocalResources { power: POWER, - counter: usize, // <- new resource + counter: usize, + } + + #[shared] + struct MySharedResources { } #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); let power = board.power; @@ -23,14 +29,19 @@ const APP: () = { defmt::println!("USBDETECTED interrupt enabled"); - init::LateResources { - power, - counter: 0, // <- initialize the new resource - } + ( + MySharedResources {}, + MyLocalResources { + power, + counter: 0, // <- initialize the new resource + }, + init::Monotonics() + ) } + #[idle] - fn main(_cx: main::Context) -> ! { + fn idle(_cx: idle::Context) -> ! { loop { defmt::println!("idle: going to sleep"); asm::wfi(); @@ -38,13 +49,13 @@ const APP: () = { } } - #[task(binds = POWER_CLOCK, resources = [power, counter])] - // ^^^^^^^ we want to access the resource from here + #[task(binds = POWER_CLOCK, local = [power, counter])] + // ^^^^^^^ we want to access the resource from here fn on_power_event(cx: on_power_event::Context) { defmt::debug!("POWER event occurred"); - let power = cx.resources.power; - let counter = cx.resources.counter; + let power = cx.local.power; + let counter = cx.local.counter; *counter += 1; let n = *counter; @@ -57,4 +68,4 @@ const APP: () = { // clear the interrupt flag; otherwise this task will run again after it returns power.events_usbdetected.reset(); } -}; +} diff --git a/advanced/firmware/src/bin/resource.rs b/advanced/firmware/src/bin/resource.rs index 96ff984..cb30a46 100644 --- a/advanced/firmware/src/bin/resource.rs +++ b/advanced/firmware/src/bin/resource.rs @@ -1,19 +1,26 @@ #![no_main] #![no_std] -use cortex_m::asm; -use dk::peripheral::POWER; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; -#[rtic::app(device = dk)] -const APP: () = { - struct Resources { - power: POWER, // <- resource declaration +#[rtic::app(device = dk, peripherals = false)] +mod app { + use cortex_m::asm; + use dk::peripheral::POWER; + + #[local] + struct MyLocalResources { + power: POWER, + } + + #[shared] + struct MySharedResources { + } #[init] - fn init(_cx: init::Context) -> init::LateResources { + fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { let board = dk::init().unwrap(); let power = board.power; @@ -22,13 +29,11 @@ const APP: () = { defmt::println!("USBDETECTED interrupt enabled"); - init::LateResources { - power, // <- resource initialization - } + (MySharedResources {}, MyLocalResources {power}, init::Monotonics()) } #[idle] - fn main(_cx: main::Context) -> ! { + fn idle(_cx: idle::Context) -> ! { loop { defmt::println!("idle: going to sleep"); asm::wfi(); @@ -36,13 +41,13 @@ const APP: () = { } } - #[task(binds = POWER_CLOCK, resources = [power])] + #[task(binds = POWER_CLOCK, local = [power])] // ^^^^^^^ resource access list fn on_power_event(cx: on_power_event::Context) { defmt::println!("POWER event occurred"); // resources available to this task - let resources = cx.resources; + let resources = cx.local; // the POWER peripheral can be accessed through a reference let power: &mut POWER = resources.power; @@ -50,4 +55,4 @@ const APP: () = { // clear the interrupt flag; otherwise this task will run again after it returns power.events_usbdetected.reset(); } -}; +} diff --git a/advanced/firmware/src/bin/rtic-hello.rs b/advanced/firmware/src/bin/rtic-hello.rs index cd57d3a..6d0f8c9 100644 --- a/advanced/firmware/src/bin/rtic-hello.rs +++ b/advanced/firmware/src/bin/rtic-hello.rs @@ -8,7 +8,6 @@ use firmware as _; #[rtic::app(device = dk, peripherals = false)] mod app { use cortex_m::asm; - use dk::Peripherals; #[local] struct MyLocalResources { diff --git a/embedded-workshop-book/src/task-state.md b/embedded-workshop-book/src/task-state.md index 1a0b986..7ff1a63 100644 --- a/embedded-workshop-book/src/task-state.md +++ b/embedded-workshop-book/src/task-state.md @@ -21,12 +21,15 @@ Also note that in the starter code the `idle` function has been modified. Pay at ✅ Modify the program so that it prints the number of times the USB cable has been connected to the DK every time the cable is connected, as shown below. ``` console -(..) -INFO:resource -- on_power_event: cable connected 1 time -(..) -INFO:resource -- on_power_event: cable connected 2 times -(..) -INFO:resource -- on_power_event: cable connected 3 times +USBDETECTED interrupt enabled +idle: going to sleep +on_power_event: cable connected 1 time +idle: woke up +idle: going to sleep +on_power_event: cable connected 2 times +idle: woke up +idle: going to sleep +on_power_event: cable connected 3 times ``` You can find a solution to this exercise in the `resource-solution.rs` file. \ No newline at end of file From 901c0f7d2caddf7df4d0167c23ab5b758e89ca15 Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Fri, 7 Jan 2022 19:01:58 +0100 Subject: [PATCH 28/29] update book --- advanced/firmware/src/bin/usb-1-solution.rs | 10 +++++----- advanced/firmware/src/bin/usb-1.rs | 11 +++-------- advanced/firmware/src/bin/usb-2-solution.rs | 5 ++--- embedded-workshop-book/src/usb-enumeration.md | 2 ++ embedded-workshop-book/src/usb-events.md | 10 +++++----- 5 files changed, 17 insertions(+), 21 deletions(-) diff --git a/advanced/firmware/src/bin/usb-1-solution.rs b/advanced/firmware/src/bin/usb-1-solution.rs index 91ef9d1..94e8231 100644 --- a/advanced/firmware/src/bin/usb-1-solution.rs +++ b/advanced/firmware/src/bin/usb-1-solution.rs @@ -7,10 +7,10 @@ use firmware as _; #[rtic::app(device = dk, peripherals = false)] mod app { + use cortex_m::asm; use dk::{ peripheral::USBD, usbd::{self, Event}, - Peripherals, }; #[local] @@ -46,19 +46,19 @@ mod app { } fn on_event(_usbd: &USBD, event: Event) { - defmt::println("USB: {:?}", event); + defmt::println!("USB: {:?}", event); match event { Event::UsbReset => { // going from the Default state to the Default state is a no-operation - defmt::println("returning to the Default state"); + defmt::println!("returning to the Default state"); } Event::UsbEp0DataDone => todo!(), Event::UsbEp0Setup => { - defmt::println("goal reached; move to the next section"); - dk::exit() + defmt::println!("goal reached; move to the next section"); + asm::bkpt(); } } } diff --git a/advanced/firmware/src/bin/usb-1.rs b/advanced/firmware/src/bin/usb-1.rs index a5293e1..82ed77c 100644 --- a/advanced/firmware/src/bin/usb-1.rs +++ b/advanced/firmware/src/bin/usb-1.rs @@ -1,19 +1,15 @@ #![no_main] #![no_std] -use dk::{ - peripheral::USBD, - usbd::{self, Event}, -}; // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior use firmware as _; #[rtic::app(device = dk, peripherals = false)] mod app { + use cortex_m::asm; use dk::{ peripheral::USBD, usbd::{self, Event}, - Peripherals, }; #[local] @@ -22,8 +18,7 @@ mod app { } #[shared] - struct MySharedResources { - + struct MySharedResources { } #[init] @@ -58,7 +53,7 @@ mod app { // leave this at it is for now. Event::UsbEp0Setup => { defmt::println!("goal reached; move to the next section"); - dk::exit() + asm::bkpt() } } } diff --git a/advanced/firmware/src/bin/usb-2-solution.rs b/advanced/firmware/src/bin/usb-2-solution.rs index 323a004..e0eb463 100644 --- a/advanced/firmware/src/bin/usb-2-solution.rs +++ b/advanced/firmware/src/bin/usb-2-solution.rs @@ -21,7 +21,6 @@ mod app { #[shared] struct MySharedResources { - } #[init] @@ -41,6 +40,7 @@ mod app { on_event(usbd, event) } } + fn on_event(usbd: &USBD, event: Event) { defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); @@ -106,7 +106,6 @@ mod app { } } } - } - + } } diff --git a/embedded-workshop-book/src/usb-enumeration.md b/embedded-workshop-book/src/usb-enumeration.md index dbb7c00..8f0802d 100644 --- a/embedded-workshop-book/src/usb-enumeration.md +++ b/embedded-workshop-book/src/usb-enumeration.md @@ -1,5 +1,7 @@ # USB Enumeration +Check this miro board for an [overview](https://miro.com/app/board/uXjVObcQhcc=/?invite_link_id=467100096053). + A USB device, like the nRF52840, can be one of these three states: the Default state, the Address state or the Configured state. After being powered the device will start in the Default state. The enumeration process will take the device from the Default state to the Address state. As a result of the enumeration process the device will be assigned an address, in the range `1..=127`, by the host. The USB protocol is complex so we'll leave out many details and focus only on the concepts required to get enumeration and configuration working. There are also several USB specific terms so we recommend checking chapter 2, "Terms and Abbreviations", of the USB specification (linked at the bottom of this document) every now and then. diff --git a/embedded-workshop-book/src/usb-events.md b/embedded-workshop-book/src/usb-events.md index 5761bb1..a575901 100644 --- a/embedded-workshop-book/src/usb-events.md +++ b/embedded-workshop-book/src/usb-events.md @@ -15,11 +15,11 @@ This code will panic because `USBRESET` is not implemented yet. ✅ Go to `fn on_event`, line 39. In this section you'll need to implement the following USB events `USBRESET` and `EP0SETUP` so that your log output will look like this: ``` console -INFO:usb_1 -- USB: UsbReset -INFO:usb_1 -- returning to the Default state -INFO:usb_1 -- USB: UsbEp0Setup -INFO:usb_1 -- goal reached; move to the next section -INFO:dk -- `dk::exit() called; exiting ... +USBD initialized +USB: UsbReset +returning to the Default state +USB: UsbEp0Setup +goal reached; move to the next section ``` ## Help From d8ba808f7896c91bb8c983cc4ee070e790ae45fc Mon Sep 17 00:00:00 2001 From: Mirabellensaft Date: Mon, 10 Jan 2022 14:16:14 +0100 Subject: [PATCH 29/29] update log statements --- advanced/common/usb/src/lib.rs | 40 ++++++++------------- advanced/firmware/src/bin/usb-1.rs | 2 +- advanced/firmware/src/bin/usb-2-solution.rs | 2 +- advanced/firmware/src/bin/usb-4-solution.rs | 2 +- embedded-workshop-book/src/setup-stage.md | 14 ++++---- 5 files changed, 25 insertions(+), 35 deletions(-) diff --git a/advanced/common/usb/src/lib.rs b/advanced/common/usb/src/lib.rs index e153265..e8f8157 100644 --- a/advanced/common/usb/src/lib.rs +++ b/advanced/common/usb/src/lib.rs @@ -1,5 +1,4 @@ //! Some USB 2.0 data types -// NOTE this is a partial solution to exercise `usb-2` #![deny(missing_docs)] #![deny(warnings)] @@ -51,33 +50,22 @@ impl Request { windex: u16, wlength: u16, ) -> Result { + // Request Codes // see table 9-4 (USB specification) const SET_ADDRESS: u8 = 5; - const GET_DESCRIPTOR: u8 = 6; + // TODO implement another branch handling GET_DESCRIPTOR requests: + // + // 1. get descriptor type and descriptor index from `wValue` + // + // 2. confirm that + // - the descriptor type is DEVICE, i.e. of value 1 and + // - the descriptor index is 0 (i.e. it is the first implemented descriptor for this type) and + // - `wIndex` is 0 (i.e. no language ID since it's not a string descriptor) + // + // For more details, see https://embedded-trainings.ferrous-systems.com/setup-stage.html - if bmrequesttype == 0b10000000 && brequest == GET_DESCRIPTOR { - // see table 9-5 - const DEVICE: u8 = 1; - - // 1. get descriptor type and descriptor index from wValue - let desc_ty = (wvalue >> 8) as u8; - let desc_index = wvalue as u8; - let langid = windex; - - // 2. confirm that the descriptor - // - is of type DEVICE and - // - has descriptor index 0 (i.e. it is the first implemented descriptor for this type) and - // - has wIndex 0 (i.e. no language ID since it's not a string descriptor) - if desc_ty == DEVICE && desc_index == 0 && langid == 0 { - Ok(Request::GetDescriptor { - descriptor: Descriptor::Device, - length: wlength, - }) - } else { - Err(()) - } - } else if bmrequesttype == 0b00000000 && brequest == SET_ADDRESS { + if bmrequesttype == 0b00000000 && brequest == SET_ADDRESS { // Set the device address for all future accesses. // (Needed to successfully init when conected to Apple devices) // Section 9.4.6 Set Address of the USB specification explains which values for wvalue, @@ -90,6 +78,7 @@ impl Request { Err(()) } } else { + defmt::println!("unhandled case in `Request` parser"); Err(()) } } @@ -207,5 +196,4 @@ mod tests { assert!(Request::parse(0b0000_0000, 0x09, 0x00_01, 0, 1).is_err()); // ^ } -} - +} \ No newline at end of file diff --git a/advanced/firmware/src/bin/usb-1.rs b/advanced/firmware/src/bin/usb-1.rs index 82ed77c..412933b 100644 --- a/advanced/firmware/src/bin/usb-1.rs +++ b/advanced/firmware/src/bin/usb-1.rs @@ -44,7 +44,7 @@ mod app { } fn on_event(_usbd: &USBD, event: Event) { - defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::println!("USB: {} @ {}", event, dk::uptime()); match event { Event::UsbReset => todo!(), diff --git a/advanced/firmware/src/bin/usb-2-solution.rs b/advanced/firmware/src/bin/usb-2-solution.rs index e0eb463..a9a0cae 100644 --- a/advanced/firmware/src/bin/usb-2-solution.rs +++ b/advanced/firmware/src/bin/usb-2-solution.rs @@ -42,7 +42,7 @@ mod app { } fn on_event(usbd: &USBD, event: Event) { - defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::println!("USB: {} @ {}", event, dk::uptime()); match event { Event::UsbReset => { diff --git a/advanced/firmware/src/bin/usb-4-solution.rs b/advanced/firmware/src/bin/usb-4-solution.rs index 51035a9..451b5c6 100644 --- a/advanced/firmware/src/bin/usb-4-solution.rs +++ b/advanced/firmware/src/bin/usb-4-solution.rs @@ -47,7 +47,7 @@ mod app { } } fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - defmt::println!("USB: {:?} @ {:?}", event, dk::uptime()); + defmt::println!("USB: {} @ {}", event, dk::uptime()); match event { Event::UsbReset => { diff --git a/embedded-workshop-book/src/setup-stage.md b/embedded-workshop-book/src/setup-stage.md index 684e522..409ae65 100644 --- a/embedded-workshop-book/src/setup-stage.md +++ b/embedded-workshop-book/src/setup-stage.md @@ -72,12 +72,14 @@ modify `usb-2.rs` to read `USBD` registers and parse the SETUP data when an EP0S When you have successfully received a GET_DESCRIPTOR request for a Device descriptor you are done. You should see an output like this: ``` console -INFO:usb_2 -- USB: UsbReset @ 438.842772ms -INFO:usb_2 -- USB: UsbEp0Setup @ 514.984128ms -... -INFO:usb_2 -- SETUP: bmrequesttype: 128, brequest: 6, wlength: 64, windex: 0, wvalue: 256 -INFO:usb_2 -- GET_DESCRIPTOR Device [length=64] -INFO:usb_2 -- Goal reached; move to the next section +USB: UsbReset @ Duration { secs: 0, nanos: 361145018 } +USB: UsbEp0Setup @ Duration { secs: 0, nanos: 402465820 } +SETUP: bmrequesttype: 0, brequest: 5, wlength: 0, windex: 0, wvalue: 10 +USB: UsbEp0Setup @ Duration { secs: 0, nanos: 404754637 } +SETUP: bmrequesttype: 128, brequest: 6, wlength: 8, windex: 0, wvalue: 256 +GET_DESCRIPTOR Device [length=8] +Goal reached; move to the next section +`dk::exit()` called; exiting ... ``` > Note: `wlength` / `length` can vary depending on the OS, USB port (USB 2.0 vs USB 3.0) or the presence of a USB hub so you may see a different value.