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.