info! -> println!

This commit is contained in:
Mirabellensaft 2022-01-07 17:24:21 +01:00
parent b975a07698
commit ca262675e8
38 changed files with 931 additions and 853 deletions

View file

@ -23,7 +23,7 @@ const APP: () = {
w.usbdetected().set_bit() w.usbdetected().set_bit()
}); });
defmt::info!("USBDETECTED interrupt enabled"); defmt::println!("USBDETECTED interrupt enabled");
// read the whole 32-bit usb supply register // read the whole 32-bit usb supply register
// the `read()` method returns a reader which can then be used to access the register content // 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) // (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(); let regstatus: u32 = power.usbregstatus.read().bits();
// ^^^^ complete register content // ^^^^ 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 // read the 1-bit VBUSDETECT field that is part of the USBREGSTATUS register content
// to show that its contents reflect our usb connection status // to show that its contents reflect our usb connection status
// (the USBDETECTED event that will trigger `on_power_event()` is derived from this information) // (the USBDETECTED event that will trigger `on_power_event()` is derived from this information)
let vbusdetect: bool = power.usbregstatus.read().vbusdetect().bits(); let vbusdetect: bool = power.usbregstatus.read().vbusdetect().bits();
// ^^^^^^^^^^ bitfield name // ^^^^^^^^^^ bitfield name
defmt::info!("USBREGSTATUS.VBUSDETECT: {}", vbusdetect); defmt::println!("USBREGSTATUS.VBUSDETECT: {}", vbusdetect);
} }
#[idle] #[idle]
fn main(_cx: main::Context) -> ! { fn main(_cx: main::Context) -> ! {
defmt::info!("idle: going to sleep"); defmt::println!("idle: going to sleep");
// sleep in the background // sleep in the background
loop { loop {
@ -53,7 +53,7 @@ const APP: () = {
#[task(binds = POWER_CLOCK)] #[task(binds = POWER_CLOCK)]
fn on_power_event(_cx: on_power_event::Context) { fn on_power_event(_cx: on_power_event::Context) {
defmt::info!("POWER event occurred"); defmt::println!("POWER event occurred");
dk::exit() asm::bkpt();
} }
}; };

View file

@ -11,7 +11,7 @@ fn main() -> ! {
// board initialization // board initialization
dk::init().unwrap(); dk::init().unwrap();
defmt::info!("Hello, world!"); defmt::println!("Hello, world!");
loop { loop {
asm::bkpt(); asm::bkpt();

View file

@ -21,7 +21,7 @@ const APP: () = {
power.intenset.write(|w| w.usbdetected().set_bit()); power.intenset.write(|w| w.usbdetected().set_bit());
defmt::info!("USBDETECTED interrupt enabled"); defmt::println!("USBDETECTED interrupt enabled");
init::LateResources { init::LateResources {
power, power,
@ -32,9 +32,9 @@ const APP: () = {
#[idle] #[idle]
fn main(_cx: main::Context) -> ! { fn main(_cx: main::Context) -> ! {
loop { loop {
defmt::info!("idle: going to sleep"); defmt::println!("idle: going to sleep");
asm::wfi(); asm::wfi();
defmt::info!("idle: woke up"); defmt::println!("idle: woke up");
} }
} }
@ -48,7 +48,7 @@ const APP: () = {
*counter += 1; *counter += 1;
let n = *counter; let n = *counter;
defmt::info!( defmt::println!(
"on_power_event: cable connected {} time{}", "on_power_event: cable connected {} time{}",
n, n,
if n != 1 { "s" } else { "" } if n != 1 { "s" } else { "" }

View file

@ -20,7 +20,7 @@ const APP: () = {
power.intenset.write(|w| w.usbdetected().set_bit()); power.intenset.write(|w| w.usbdetected().set_bit());
defmt::info!("USBDETECTED interrupt enabled"); defmt::println!("USBDETECTED interrupt enabled");
init::LateResources { init::LateResources {
power, // <- resource initialization power, // <- resource initialization
@ -30,16 +30,16 @@ const APP: () = {
#[idle] #[idle]
fn main(_cx: main::Context) -> ! { fn main(_cx: main::Context) -> ! {
loop { loop {
defmt::info!("idle: going to sleep"); defmt::println!("idle: going to sleep");
asm::wfi(); asm::wfi();
defmt::info!("idle: woke up"); defmt::println!("idle: woke up");
} }
} }
#[task(binds = POWER_CLOCK, resources = [power])] #[task(binds = POWER_CLOCK, resources = [power])]
// ^^^^^^^ resource access list // ^^^^^^^ resource access list
fn on_power_event(cx: on_power_event::Context) { fn on_power_event(cx: on_power_event::Context) {
defmt::info!("POWER event occurred"); defmt::println!("POWER event occurred");
// resources available to this task // resources available to this task
let resources = cx.resources; let resources = cx.resources;

View file

@ -5,7 +5,7 @@
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; use firmware as _;
#[rtic::app(device = dk, peripherals = true)] #[rtic::app(device = dk, peripherals = false)]
mod app { mod app {
use cortex_m::asm; use cortex_m::asm;
use dk::Peripherals; use dk::Peripherals;
@ -23,13 +23,13 @@ mod app {
fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
dk::init().unwrap(); dk::init().unwrap();
defmt::info!("Hello"); defmt::println!("Hello");
(MySharedResources {}, MyLocalResources {}, init::Monotonics()) (MySharedResources {}, MyLocalResources {}, init::Monotonics())
} }
#[idle] #[idle]
fn idle(_cx: idle::Context) -> ! { fn idle(_cx: idle::Context) -> ! {
defmt::info!("world!"); defmt::println!("world!");
loop { loop {
asm::bkpt(); asm::bkpt();

View file

@ -22,7 +22,7 @@ fn main() -> ! {
fn fib(n: u32) -> u32 { fn fib(n: u32) -> u32 {
// allocate and initialize one kilobyte of stack memory to provoke stack overflow // 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); defmt::println!("allocating [{}; 1024]; round #{}", use_stack[1023], n);
if n < 2 { if n < 2 {
1 1

View file

@ -1,52 +1,67 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use dk::{
peripheral::USBD,
usbd::{self, Event},
};
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; use firmware as _;
#[rtic::app(device = dk)] #[rtic::app(device = dk, peripherals = false)]
const APP: () = { mod app {
struct Resources { use dk::{
peripheral::USBD,
usbd::{self, Event},
Peripherals,
};
#[local]
struct MyLocalResources {
usbd: USBD, usbd: USBD,
} }
#[init] #[shared]
fn init(_cx: init::Context) -> init::LateResources { struct MySharedResources {
let board = dk::init().unwrap();
usbd::init(board.power, &board.usbd);
init::LateResources { usbd: board.usbd }
} }
#[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) { fn main(cx: main::Context) {
let usbd = cx.resources.usbd; let usbd = cx.local.usbd;
while let Some(event) = usbd::next_event(usbd) { while let Some(event) = usbd::next_event(usbd) {
on_event(usbd, event) on_event(usbd, event)
} }
} }
};
fn on_event(_usbd: &USBD, event: Event) { fn on_event(_usbd: &USBD, event: Event) {
defmt::info!("USB: {:?}", event); defmt::println("USB: {:?}", event);
match event { match event {
Event::UsbReset => { Event::UsbReset => {
// going from the Default state to the Default state is a no-operation // going from the Default state to the Default state is a no-operation
defmt::info!("returning to the Default state"); defmt::println("returning to the Default state");
} }
Event::UsbEp0DataDone => todo!(), Event::UsbEp0DataDone => todo!(),
Event::UsbEp0Setup => { Event::UsbEp0Setup => {
defmt::info!("goal reached; move to the next section"); defmt::println("goal reached; move to the next section");
dk::exit() dk::exit()
}
} }
} }
} }

View file

@ -8,46 +8,60 @@ use dk::{
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; use firmware as _;
#[rtic::app(device = dk)] #[rtic::app(device = dk, peripherals = false)]
const APP: () = { mod app {
struct Resources { use dk::{
peripheral::USBD,
usbd::{self, Event},
Peripherals,
};
#[local]
struct MyLocalResources {
usbd: USBD, usbd: USBD,
} }
#[shared]
struct MySharedResources {
}
#[init] #[init]
fn init(_cx: init::Context) -> init::LateResources { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
let board = dk::init().unwrap(); let board = dk::init().unwrap();
// initialize the USBD peripheral // initialize the USBD peripheral
// NOTE this will block if the USB cable is not connected to port J3 // NOTE this will block if the USB cable is not connected to port J3
usbd::init(board.power, &board.usbd); 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) { fn main(cx: main::Context) {
let usbd = cx.resources.usbd; let usbd = cx.local.usbd;
while let Some(event) = usbd::next_event(usbd) { while let Some(event) = usbd::next_event(usbd) {
on_event(usbd, event) on_event(usbd, event)
} }
} }
};
fn on_event(_usbd: &USBD, event: Event) { fn on_event(_usbd: &USBD, event: Event) {
defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); defmt::println!("USB: {:?} @ {:?}", event, dk::uptime());
match event { match event {
Event::UsbReset => todo!(), Event::UsbReset => todo!(),
Event::UsbEp0DataDone => todo!(), Event::UsbEp0DataDone => todo!(),
// leave this at it is for now. // leave this at it is for now.
Event::UsbEp0Setup => { Event::UsbEp0Setup => {
defmt::info!("goal reached; move to the next section"); defmt::println!("goal reached; move to the next section");
dk::exit() dk::exit()
}
} }
} }
} }

View file

@ -1,102 +1,112 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use dk::{
peripheral::USBD,
usbd::{self, Event},
};
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; use firmware as _;
use usb::{Descriptor, Request};
#[rtic::app(device = dk)] #[rtic::app(device = dk, peripherals = false)]
const APP: () = { mod app {
struct Resources { use dk::{
peripheral::USBD,
usbd::{self, Event},
Peripherals,
};
use usb::{Descriptor, Request};
#[local]
struct MyLocalResources {
usbd: USBD, usbd: USBD,
} }
#[shared]
struct MySharedResources {
}
#[init] #[init]
fn init(_cx: init::Context) -> init::LateResources { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
let board = dk::init().unwrap(); let board = dk::init().unwrap();
usbd::init(board.power, &board.usbd); 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) { fn main(cx: main::Context) {
let usbd = cx.resources.usbd; let usbd = cx.local.usbd;
while let Some(event) = usbd::next_event(usbd) { while let Some(event) = usbd::next_event(usbd) {
on_event(usbd, event) on_event(usbd, event)
} }
} }
}; fn on_event(usbd: &USBD, event: Event) {
defmt::println!("USB: {:?} @ {:?}", event, dk::uptime());
fn on_event(usbd: &USBD, event: Event) {
defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event {
Event::UsbReset => {
match event { // nothing to do here at the moment
Event::UsbReset => { }
// nothing to do here at the moment
} Event::UsbEp0DataDone => todo!(),
Event::UsbEp0DataDone => todo!(), Event::UsbEp0Setup => {
// the BMREQUESTTYPE register contains information about data recipient, transfer type and direction
Event::UsbEp0Setup => { let bmrequesttype = usbd.bmrequesttype.read().bits() as u8;
// the BMREQUESTTYPE register contains information about data recipient, transfer type and direction // the BREQUEST register stores the type of the current request (e.g. SET_ADDRESS, GET_DESCRIPTOR, ...)
let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; let brequest = usbd.brequest.read().brequest().bits();
// the BREQUEST register stores the type of the current request (e.g. SET_ADDRESS, GET_DESCRIPTOR, ...) // wLength denotes the number of bytes to transfer (if any)
let brequest = usbd.brequest.read().brequest().bits(); // composed of a high register (WLENGTHH) and a low register (WLENGTHL)
// wLength denotes the number of bytes to transfer (if any) let wlength = (u16::from(usbd.wlengthh.read().wlengthh().bits()) << 8)
// composed of a high register (WLENGTHH) and a low register (WLENGTHL) | u16::from(usbd.wlengthl.read().wlengthl().bits());
let wlength = (u16::from(usbd.wlengthh.read().wlengthh().bits()) << 8) // wIndex is a generic index field whose meaning depends on the request type
| u16::from(usbd.wlengthl.read().wlengthl().bits()); // composed of a high register (WINDEXH) and a low register (WINDEXL)
// wIndex is a generic index field whose meaning depends on the request type let windex = (u16::from(usbd.windexh.read().windexh().bits()) << 8)
// composed of a high register (WINDEXH) and a low register (WINDEXL) | u16::from(usbd.windexl.read().windexl().bits());
let windex = (u16::from(usbd.windexh.read().windexh().bits()) << 8) // wValue is a generic paremeter field meaning depends on the request type (e.g. contains the device
| u16::from(usbd.windexl.read().windexl().bits()); // address in SET_ADRESS requests)
// wValue is a generic paremeter field meaning depends on the request type (e.g. contains the device // composed of a high register (WVALUEH) and a low register (WVALUEL)
// address in SET_ADRESS requests) let wvalue = (u16::from(usbd.wvalueh.read().wvalueh().bits()) << 8)
// composed of a high register (WVALUEH) and a low register (WVALUEL) | u16::from(usbd.wvaluel.read().wvaluel().bits());
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);
// NOTE the `dk` crate contains helper functions for the above operations // let brequest = usbd::brequest(usbd);
// let bmrequesttype = usbd::bmrequesttype(usbd); // let wlength = usbd::wlength(usbd);
// let brequest = usbd::brequest(usbd); // let windex = usbd::windex(usbd);
// let wlength = usbd::wlength(usbd); // let wvalue = usbd::wvalue(usbd);
// let windex = usbd::windex(usbd);
// let wvalue = usbd::wvalue(usbd); defmt::println!(
"SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}",
defmt::info!( bmrequesttype,
"SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", brequest,
bmrequesttype, wlength,
brequest, windex,
wlength, wvalue
windex, );
wvalue
); let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength)
.expect("Error parsing request");
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) match request {
.expect("Error parsing request"); Request::GetDescriptor { descriptor, length }
match request { if descriptor == Descriptor::Device =>
Request::GetDescriptor { descriptor, length } {
if descriptor == Descriptor::Device => defmt::println!("GET_DESCRIPTOR Device [length={}]", length);
{
defmt::info!("GET_DESCRIPTOR Device [length={}]", length); defmt::println!("Goal reached; move to the next section");
dk::exit()
defmt::info!("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
} }
} }
} }
} }

View file

@ -1,98 +1,108 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use dk::{
peripheral::USBD,
usbd::{self, Event},
};
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; 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)] use usb::{Descriptor, Request};
const APP: () = {
struct Resources { #[local]
struct MyLocalResources {
usbd: USBD, usbd: USBD,
} }
#[shared]
struct MySharedResources {
}
#[init] #[init]
fn init(_cx: init::Context) -> init::LateResources { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
let board = dk::init().unwrap(); let board = dk::init().unwrap();
usbd::init(board.power, &board.usbd); 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) { fn main(cx: main::Context) {
let usbd = cx.resources.usbd; let usbd = cx.local.usbd;
while let Some(event) = usbd::next_event(usbd) { while let Some(event) = usbd::next_event(usbd) {
on_event(usbd, event) on_event(usbd, event)
} }
} }
};
fn on_event(_usbd: &USBD, event: Event) { fn on_event(_usbd: &USBD, event: Event) {
defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); defmt::println!("USB: {:?} @ {:?}", event, dk::uptime());
match event { match event {
Event::UsbReset => { Event::UsbReset => {
// nothing to do here at the moment // nothing to do here at the moment
} }
Event::UsbEp0DataDone => todo!(), Event::UsbEp0DataDone => todo!(),
Event::UsbEp0Setup => { Event::UsbEp0Setup => {
// TODO read USBD registers // TODO read USBD registers
// the BMREQUESTTYPE register contains information about data recipient, transfer type and direction // the BMREQUESTTYPE register contains information about data recipient, transfer type and direction
let bmrequesttype: u8 = 0; let bmrequesttype: u8 = 0;
// the BREQUEST register stores the type of the current request (e.g. SET_ADDRESS, GET_DESCRIPTOR, ...) // the BREQUEST register stores the type of the current request (e.g. SET_ADDRESS, GET_DESCRIPTOR, ...)
let brequest: u8 = 0; let brequest: u8 = 0;
// wLength denotes the number of bytes to transfer (if any) // wLength denotes the number of bytes to transfer (if any)
// composed of a high register (WLENGTHH) and a low register (WLENGTHL) // composed of a high register (WLENGTHH) and a low register (WLENGTHL)
let wlength: u16 = 0; let wlength: u16 = 0;
// wIndex is a generic index field whose meaning depends on the request type // wIndex is a generic index field whose meaning depends on the request type
// composed of a high register (WINDEXH) and a low register (WINDEXL) // composed of a high register (WINDEXH) and a low register (WINDEXL)
let windex: u16 = 0; let windex: u16 = 0;
// wValue is a generic paremeter field meaning depends on the request type (e.g. contains the device // wValue is a generic paremeter field meaning depends on the request type (e.g. contains the device
// address in SET_ADRESS requests) // address in SET_ADRESS requests)
// composed of a high register (WVALUEH) and a low register (WVALUEL) // composed of a high register (WVALUEH) and a low register (WVALUEL)
let wvalue: u16 = 0; let wvalue: u16 = 0;
defmt::info!( defmt::println!(
"SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}",
bmrequesttype, bmrequesttype,
brequest, brequest,
wlength, wlength,
windex, windex,
wvalue wvalue
); );
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength)
.expect("Error parsing request"); .expect("Error parsing request");
match request { match request {
Request::GetDescriptor { descriptor, length } Request::GetDescriptor { descriptor, length }
if descriptor == Descriptor::Device => if descriptor == Descriptor::Device =>
{ {
// TODO modify `Request::parse()` in `advanced/common/usb/lib.rs` // TODO modify `Request::parse()` in `advanced/common/usb/lib.rs`
// so that this branch is reached // so that this branch is reached
defmt::info!("GET_DESCRIPTOR Device [length={}]", length); defmt::println!("GET_DESCRIPTOR Device [length={}]", length);
defmt::info!("Goal reached; move to the next section"); defmt::println!("Goal reached; move to the next section");
dk::exit() 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
} }
} }
} }
} }

View file

@ -1,108 +1,115 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use dk::{
peripheral::USBD,
usbd::{self, Ep0In, Event},
};
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; use firmware as _;
use usb::{Descriptor, Request};
#[rtic::app(device = dk)] #[rtic::app(device = dk, peripherals = false)]
const APP: () = { mod app {
struct Resources { use dk::{
peripheral::USBD,
usbd::{self, Ep0In, Event},
Peripherals,
};
use usb::{Descriptor, Request};
#[local]
struct MyLocalResources {
usbd: USBD, usbd: USBD,
ep0in: Ep0In, ep0in: Ep0In,
} }
#[shared]
struct MySharedResources {
}
#[init] #[init]
fn init(_cx: init::Context) -> init::LateResources { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
let board = dk::init().unwrap(); let board = dk::init().unwrap();
usbd::init(board.power, &board.usbd); usbd::init(board.power, &board.usbd);
init::LateResources { (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, }, init::Monotonics())
ep0in: board.ep0in,
usbd: board.usbd,
}
} }
#[task(binds = USBD, resources = [usbd, ep0in])] #[task(binds = USBD, local = [usbd, ep0in])]
fn main(cx: main::Context) { fn main(cx: main::Context) {
let usbd = cx.resources.usbd; let usbd = cx.local.usbd;
let ep0in = cx.resources.ep0in; let ep0in = cx.local.ep0in;
while let Some(event) = usbd::next_event(usbd) { while let Some(event) = usbd::next_event(usbd) {
on_event(usbd, ep0in, event) on_event(usbd, ep0in, event)
} }
} }
};
fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) {
defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); defmt::println!("USB: {:?} @ {:?}", event, dk::uptime());
match event { match event {
Event::UsbReset => { Event::UsbReset => {
// nothing to do here at the moment // nothing to do here at the moment
} }
Event::UsbEp0DataDone => ep0in.end(usbd), Event::UsbEp0DataDone => ep0in.end(usbd),
Event::UsbEp0Setup => { Event::UsbEp0Setup => {
let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; let bmrequesttype = usbd.bmrequesttype.read().bits() as u8;
let brequest = usbd.brequest.read().brequest().bits(); let brequest = usbd.brequest.read().brequest().bits();
let wlength = usbd::wlength(usbd); let wlength = usbd::wlength(usbd);
let windex = usbd::windex(usbd); let windex = usbd::windex(usbd);
let wvalue = usbd::wvalue(usbd); let wvalue = usbd::wvalue(usbd);
defmt::info!( defmt::println!(
"SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}",
bmrequesttype, bmrequesttype,
brequest, brequest,
wlength, wlength,
windex, windex,
wvalue wvalue
); );
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect( let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect(
"Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)", "Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)",
); );
match request { match request {
Request::GetDescriptor { descriptor, length } Request::GetDescriptor { descriptor, length }
if descriptor == Descriptor::Device => if descriptor == Descriptor::Device =>
{ {
defmt::info!("GET_DESCRIPTOR Device [length={}]", length); defmt::println!("GET_DESCRIPTOR Device [length={}]", length);
let desc = usb2::device::Descriptor { let desc = usb2::device::Descriptor {
bDeviceClass: 0, bDeviceClass: 0,
bDeviceProtocol: 0, bDeviceProtocol: 0,
bDeviceSubClass: 0, bDeviceSubClass: 0,
bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64,
bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(),
bcdDevice: 0x01_00, // 1.00 bcdDevice: 0x01_00, // 1.00
iManufacturer: None, iManufacturer: None,
iProduct: None, iProduct: None,
iSerialNumber: None, iSerialNumber: None,
idProduct: consts::PID, idProduct: consts::PID,
idVendor: consts::VID, idVendor: consts::VID,
}; };
let desc_bytes = desc.bytes(); let desc_bytes = desc.bytes();
let resp = &desc_bytes[..core::cmp::min(desc_bytes.len(), usize::from(length))]; let resp = &desc_bytes[..core::cmp::min(desc_bytes.len(), usize::from(length))];
ep0in.start(&resp, usbd); ep0in.start(&resp, usbd);
} }
Request::SetAddress { .. } => { Request::SetAddress { .. } => {
// On Mac OS you'll get this request before the GET_DESCRIPTOR request so we // 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 // need to catch it here. We'll properly handle this request later
// but for now it's OK to do nothing. // but for now it's OK to do nothing.
} }
_ => { _ => {
defmt::error!( defmt::error!(
"unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" "unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)"
); );
dk::exit() dk::exit()
}
} }
} }
} }
} }
} }

View file

@ -1,99 +1,102 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use dk::{
peripheral::USBD,
usbd::{self, Ep0In, Event},
};
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; use firmware as _;
use usb::{Descriptor, Request};
#[rtic::app(device = dk)] #[rtic::app(device = dk, peripherals = false)]
const APP: () = { mod app {
struct Resources { use dk::{
peripheral::USBD,
usbd::{self, Ep0In, Event},
Peripherals,
};
use usb::{Descriptor, Request};
#[local]
struct MyLocalResources {
usbd: USBD, usbd: USBD,
ep0in: Ep0In, ep0in: Ep0In,
} }
#[shared]
struct MySharedResources {
}
#[init] #[init]
fn init(_cx: init::Context) -> init::LateResources { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
let board = dk::init().unwrap(); let board = dk::init().unwrap();
usbd::init(board.power, &board.usbd); usbd::init(board.power, &board.usbd);
init::LateResources { (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, }, init::Monotonics())
ep0in: board.ep0in,
usbd: board.usbd,
}
} }
#[task(binds = USBD, resources = [usbd, ep0in])] #[task(binds = USBD, local = [usbd, ep0in])]
fn main(cx: main::Context) { fn main(cx: main::Context) {
let usbd = cx.resources.usbd; let usbd = cx.local.usbd;
let ep0in = cx.resources.ep0in; let ep0in = cx.local.ep0in;
while let Some(event) = usbd::next_event(usbd) { while let Some(event) = usbd::next_event(usbd) {
on_event(usbd, ep0in, event) on_event(usbd, ep0in, event)
} }
} }
};
fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) {
defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); defmt::println!("USB: {:?} @ {:?}", event, dk::uptime());
match event { match event {
Event::UsbReset => { Event::UsbReset => {
// nothing to do here at the moment // nothing to do here at the moment
} }
Event::UsbEp0DataDone => todo!(), // <- TODO Event::UsbEp0DataDone => todo!(), // <- TODO
Event::UsbEp0Setup => { Event::UsbEp0Setup => {
let bmrequesttype = usbd::bmrequesttype(usbd); let bmrequesttype = usbd::bmrequesttype(usbd);
let brequest = usbd::brequest(usbd); let brequest = usbd::brequest(usbd);
let wlength = usbd::wlength(usbd); let wlength = usbd::wlength(usbd);
let windex = usbd::windex(usbd); let windex = usbd::windex(usbd);
let wvalue = usbd::wvalue(usbd); let wvalue = usbd::wvalue(usbd);
defmt::info!( defmt::println!(
"SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}",
bmrequesttype, bmrequesttype,
brequest, brequest,
wlength, wlength,
windex, windex,
wvalue wvalue
); );
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect( let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect(
"Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)", "Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)",
); );
match request { match request {
Request::GetDescriptor { descriptor, length } Request::GetDescriptor { descriptor, length }
if descriptor == Descriptor::Device => if descriptor == Descriptor::Device =>
{ {
defmt::info!("GET_DESCRIPTOR Device [length={}]", length); defmt::println!("GET_DESCRIPTOR Device [length={}]", length);
// TODO send back a valid device descriptor, truncated to `length` bytes // TODO send back a valid device descriptor, truncated to `length` bytes
// let desc = usb2::device::Descriptor { .. }; // let desc = usb2::device::Descriptor { .. };
let resp = []; let resp = [];
ep0in.start(&resp, usbd);
// ensure we're not overstepping boundaries }
assert!(resp.len() <= length as usize); Request::SetAddress { .. } => {
ep0in.start(&resp, usbd); // 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
Request::SetAddress { .. } => { // but for now it's OK to do nothing.
// 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)"
_ => { );
defmt::error!( dk::exit()
"unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)" }
);
dk::exit()
} }
} }
} }
} }
} }

View file

@ -1,187 +1,192 @@
#![no_main] #![no_main]
#![no_std] #![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 // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; use firmware as _;
use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State};
#[rtic::app(device = dk)] #[rtic::app(device = dk, peripherals = false)]
const APP: () = { mod app {
struct Resources {
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, usbd: USBD,
ep0in: Ep0In, ep0in: Ep0In,
state: State, state: State,
} }
#[shared]
struct MySharedResources {
}
#[init] #[init]
fn init(_cx: init::Context) -> init::LateResources { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
let board = dk::init().unwrap(); let board = dk::init().unwrap();
usbd::init(board.power, &board.usbd); usbd::init(board.power, &board.usbd);
init::LateResources { (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, state: State::Default, }, init::Monotonics())
usbd: board.usbd,
state: State::Default,
ep0in: board.ep0in,
}
} }
#[task(binds = USBD, resources = [usbd, ep0in, state])] #[task(binds = USBD, local = [usbd, ep0in, state])]
fn main(cx: main::Context) { fn main(cx: main::Context) {
let usbd = cx.resources.usbd; let usbd = cx.local.usbd;
let ep0in = cx.resources.ep0in; let ep0in = cx.local.ep0in;
let state = cx.resources.state; let state = cx.local.state;
while let Some(event) = usbd::next_event(usbd) { while let Some(event) = usbd::next_event(usbd) {
on_event(usbd, ep0in, state, event) on_event(usbd, ep0in, state, event)
} }
} }
}; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) {
defmt::println!("USB: {:?} @ {:?}", event, dk::uptime());
fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) {
defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event {
Event::UsbReset => {
match event { defmt::println!("USB reset condition detected");
Event::UsbReset => { *state = State::Default;
defmt::info!("USB reset condition detected"); }
*state = State::Default;
} Event::UsbEp0DataDone => {
defmt::println!("EP0IN: transfer complete");
Event::UsbEp0DataDone => { ep0in.end(usbd);
defmt::info!("EP0IN: transfer complete"); }
ep0in.end(usbd);
} Event::UsbEp0Setup => {
if ep0setup(usbd, ep0in, state).is_err() {
Event::UsbEp0Setup => { defmt::warn!("EP0IN: unexpected request; stalling the endpoint");
if ep0setup(usbd, ep0in, state).is_err() { usbd::ep0stall(usbd);
defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); }
usbd::ep0stall(usbd);
} }
} }
} }
}
/// The `bConfigurationValue` of the only supported configuration
/// The `bConfigurationValue` of the only supported configuration const CONFIG_VAL: u8 = 42;
const CONFIG_VAL: u8 = 42;
fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> {
fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> { let bmrequesttype = usbd.bmrequesttype.read().bits() as u8;
let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; let brequest = usbd.brequest.read().brequest().bits();
let brequest = usbd.brequest.read().brequest().bits(); let wlength = usbd::wlength(usbd);
let wlength = usbd::wlength(usbd); let windex = usbd::windex(usbd);
let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd);
let wvalue = usbd::wvalue(usbd);
defmt::println!(
defmt::info!( "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}",
"bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype,
bmrequesttype, brequest,
brequest, wlength,
wlength, windex,
windex, wvalue
wvalue );
);
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength)
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request");
.expect("Error parsing request"); defmt::println!("EP0: {:?}", defmt::Debug2Format(&request));
defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log
// ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log // `StandardRequest` with `defmt`
// `StandardRequest` with `defmt` match request {
match request { // section 9.4.3
// section 9.4.3 // this request is valid in any state
// this request is valid in any state Request::GetDescriptor { descriptor, length } => match descriptor {
Request::GetDescriptor { descriptor, length } => match descriptor { Descriptor::Device => {
Descriptor::Device => { let desc = usb2::device::Descriptor {
let desc = usb2::device::Descriptor { bDeviceClass: 0,
bDeviceClass: 0, bDeviceProtocol: 0,
bDeviceProtocol: 0, bDeviceSubClass: 0,
bDeviceSubClass: 0, bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64,
bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(),
bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), bcdDevice: 0x01_00, // 1.00
bcdDevice: 0x01_00, // 1.00 iManufacturer: None,
iManufacturer: None, iProduct: None,
iProduct: None, iSerialNumber: None,
iSerialNumber: None, idProduct: consts::PID,
idProduct: consts::PID, idVendor: consts::VID,
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::<u8, 64>::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 bytes = desc.bytes();
let iface_desc = usb2::interface::Descriptor { let _ = ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd);
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(());
} }
Descriptor::Configuration { index } => {
if index == 0 {
let mut resp = heapless::Vec::<u8, 64>::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(()), _ => 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 Ok(())
_ => return Err(()),
} }
Ok(())
} }

View file

@ -1,135 +1,143 @@
#![no_main] #![no_main]
#![no_std] #![no_std]
use dk::{
peripheral::USBD,
usbd::{self, Ep0In, Event},
};
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; 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)] #[rtic::app(device = dk, peripherals = false)]
const APP: () = { mod app {
struct Resources {
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, usbd: USBD,
ep0in: Ep0In, ep0in: Ep0In,
state: State, state: State,
} }
#[shared]
struct MySharedResources {
}
#[init] #[init]
fn init(_cx: init::Context) -> init::LateResources { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
let board = dk::init().unwrap(); let board = dk::init().unwrap();
usbd::init(board.power, &board.usbd); usbd::init(board.power, &board.usbd);
init::LateResources { (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, state: State::Default, }, init::Monotonics())
usbd: board.usbd,
state: State::Default,
ep0in: board.ep0in,
}
} }
#[task(binds = USBD, resources = [usbd, ep0in, state])] #[task(binds = USBD, local = [usbd, ep0in, state])]
fn main(cx: main::Context) { fn main(cx: main::Context) {
let usbd = cx.resources.usbd; let usbd = cx.local.usbd;
let ep0in = cx.resources.ep0in; let ep0in = cx.local.ep0in;
let state = cx.resources.state; let state = cx.local.state;
while let Some(event) = usbd::next_event(usbd) { while let Some(event) = usbd::next_event(usbd) {
on_event(usbd, ep0in, state, event) on_event(usbd, ep0in, state, event)
} }
} }
};
fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) {
defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); defmt::println!("USB: {:?} @ {:?}", event, dk::uptime());
match event { match event {
// TODO change `state` as specified in chapter 9.1 USB Device States, of the USB specification // TODO change `state` as specified in chapter 9.1 USB Device States, of the USB specification
Event::UsbReset => { Event::UsbReset => {
defmt::info!("USB reset condition detected"); defmt::println!("USB reset condition detected");
todo!(); todo!();
} }
Event::UsbEp0DataDone => { Event::UsbEp0DataDone => {
defmt::info!("EP0IN: transfer complete"); defmt::println!("EP0IN: transfer complete");
ep0in.end(usbd); ep0in.end(usbd);
} }
Event::UsbEp0Setup => { Event::UsbEp0Setup => {
if ep0setup(usbd, ep0in, state).is_err() { if ep0setup(usbd, ep0in, state).is_err() {
// unsupported or invalid request: // unsupported or invalid request:
// TODO: add code to stall the endpoint // TODO: add code to stall the endpoint
defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); defmt::warn!("EP0IN: unexpected request; stalling the endpoint");
}
} }
} }
} }
}
fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), ()> {
fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, _state: &mut State) -> Result<(), ()> { let bmrequesttype = usbd.bmrequesttype.read().bits() as u8;
let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; let brequest = usbd.brequest.read().brequest().bits();
let brequest = usbd.brequest.read().brequest().bits(); let wlength = usbd::wlength(usbd);
let wlength = usbd::wlength(usbd); let windex = usbd::windex(usbd);
let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd);
let wvalue = usbd::wvalue(usbd);
defmt::println!(
defmt::info!( "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}",
"bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype,
bmrequesttype, brequest,
brequest, wlength,
wlength, windex,
windex, wvalue
wvalue );
);
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength)
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request");
.expect("Error parsing request"); defmt::println!("EP0: {:?}", defmt::Debug2Format(&request));
defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log
// ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log // `StandardRequest` with `defmt`
// `StandardRequest` with `defmt`
match request {
match request { Request::GetDescriptor { descriptor, length } => match descriptor {
Request::GetDescriptor { descriptor, length } => match descriptor { Descriptor::Device => {
Descriptor::Device => { let desc = usb2::device::Descriptor {
let desc = usb2::device::Descriptor { bDeviceClass: 0,
bDeviceClass: 0, bDeviceProtocol: 0,
bDeviceProtocol: 0, bDeviceSubClass: 0,
bDeviceSubClass: 0, bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64,
bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(),
bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), bcdDevice: 0x01_00, // 1.00
bcdDevice: 0x01_00, // 1.00 iManufacturer: None,
iManufacturer: None, iProduct: None,
iProduct: None, iSerialNumber: None,
iSerialNumber: None, idProduct: consts::PID,
idProduct: consts::PID, idVendor: consts::VID,
idVendor: consts::VID, };
}; let bytes = desc.bytes();
let bytes = desc.bytes(); let _ = ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd);
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 // stall any other request
_ => return Err(()), _ => 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 Ok(())
_ => return Err(()),
} }
Ok(())
} }

View file

@ -1,235 +1,240 @@
#![no_main] #![no_main]
#![no_std] #![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 // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use firmware as _; use firmware as _;
use usb2::{GetDescriptor as Descriptor, StandardRequest as Request, State};
#[rtic::app(device = dk)] #[rtic::app(device = dk, peripherals = false)]
const APP: () = { mod app {
struct Resources {
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, usbd: USBD,
ep0in: Ep0In, ep0in: Ep0In,
state: State, state: State,
} }
#[shared]
struct MySharedResources {
}
#[init] #[init]
fn init(_cx: init::Context) -> init::LateResources { fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
let board = dk::init().unwrap(); let board = dk::init().unwrap();
usbd::init(board.power, &board.usbd); usbd::init(board.power, &board.usbd);
init::LateResources { (MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, state: State::Default, }, init::Monotonics())
usbd: board.usbd,
state: State::Default,
ep0in: board.ep0in,
}
} }
#[task(binds = USBD, resources = [usbd, ep0in, state])] #[task(binds = USBD, local = [usbd, ep0in, state])]
fn main(cx: main::Context) { fn main(cx: main::Context) {
let usbd = cx.resources.usbd; let usbd = cx.local.usbd;
let ep0in = cx.resources.ep0in; let ep0in = cx.local.ep0in;
let state = cx.resources.state; let state = cx.local.state;
while let Some(event) = usbd::next_event(usbd) { while let Some(event) = usbd::next_event(usbd) {
on_event(usbd, ep0in, state, event) on_event(usbd, ep0in, state, event)
} }
} }
}; fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) {
defmt::println!("USB: {:?} @ {:?}", event, dk::uptime());
fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) {
defmt::info!("USB: {:?} @ {:?}", event, dk::uptime()); match event {
Event::UsbReset => {
match event { defmt::println!("USB reset condition detected");
Event::UsbReset => { *state = State::Default;
defmt::info!("USB reset condition detected"); }
*state = State::Default;
} Event::UsbEp0DataDone => {
defmt::println!("EP0IN: transfer complete");
Event::UsbEp0DataDone => { ep0in.end(usbd);
defmt::info!("EP0IN: transfer complete"); }
ep0in.end(usbd);
} Event::UsbEp0Setup => {
if ep0setup(usbd, ep0in, state).is_err() {
Event::UsbEp0Setup => { defmt::warn!("EP0IN: unexpected request; stalling the endpoint");
if ep0setup(usbd, ep0in, state).is_err() { usbd::ep0stall(usbd);
defmt::warn!("EP0IN: unexpected request; stalling the endpoint"); }
usbd::ep0stall(usbd);
} }
} }
} }
}
/// The `bConfigurationValue` of the only supported configuration
/// The `bConfigurationValue` of the only supported configuration const CONFIG_VAL: u8 = 42;
const CONFIG_VAL: u8 = 42;
fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> {
fn ep0setup(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State) -> Result<(), ()> { let bmrequesttype = usbd.bmrequesttype.read().bits() as u8;
let bmrequesttype = usbd.bmrequesttype.read().bits() as u8; let brequest = usbd.brequest.read().brequest().bits();
let brequest = usbd.brequest.read().brequest().bits(); let wlength = usbd::wlength(usbd);
let wlength = usbd::wlength(usbd); let windex = usbd::windex(usbd);
let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd);
let wvalue = usbd::wvalue(usbd);
defmt::println!(
defmt::info!( "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}",
"bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", bmrequesttype,
bmrequesttype, brequest,
brequest, wlength,
wlength, windex,
windex, wvalue
wvalue );
);
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength)
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request");
.expect("Error parsing request"); defmt::println!("EP0: {:?}", defmt::Debug2Format(&request));
defmt::info!("EP0: {:?}", defmt::Debug2Format(&request)); // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log
// ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log // `StandardRequest` with `defmt`
// `StandardRequest` with `defmt`
match request {
match request { // section 9.4.3
// section 9.4.3 // this request is valid in any state
// this request is valid in any state Request::GetDescriptor { descriptor, length } => match descriptor {
Request::GetDescriptor { descriptor, length } => match descriptor { Descriptor::Device => {
Descriptor::Device => { let desc = usb2::device::Descriptor {
let desc = usb2::device::Descriptor { bDeviceClass: 0,
bDeviceClass: 0, bDeviceProtocol: 0,
bDeviceProtocol: 0, bDeviceSubClass: 0,
bDeviceSubClass: 0, bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64,
bMaxPacketSize0: usb2::device::bMaxPacketSize0::B64, bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(),
bNumConfigurations: core::num::NonZeroU8::new(1).unwrap(), bcdDevice: 0x01_00, // 1.00
bcdDevice: 0x01_00, // 1.00 iManufacturer: None,
iManufacturer: None, iProduct: None,
iProduct: None, iSerialNumber: None,
iSerialNumber: None, idProduct: consts::PID,
idProduct: consts::PID, idVendor: consts::VID,
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::<u8, 64>::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 bytes = desc.bytes();
let iface_desc = usb2::interface::Descriptor { let _ = ep0in.start(&bytes[..core::cmp::min(bytes.len(), length.into())], usbd);
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(());
} }
}
Descriptor::Configuration { index } => {
_ => return Err(()), if index == 0 {
}, let mut resp = heapless::Vec::<u8, 64>::new();
Request::SetAddress { address } => { let conf_desc = usb2::configuration::Descriptor {
match state { wTotalLength: (usb2::configuration::Descriptor::SIZE
State::Default => { + usb2::interface::Descriptor::SIZE)
if let Some(address) = address { .into(),
*state = State::Address(address); 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 { } else {
// stay in the default state // out of bounds access: stall the endpoint
return Err(());
} }
} }
State::Address(..) => { _ => return Err(()),
if let Some(address) = address { },
// use the new address
*state = State::Address(address); Request::SetAddress { address } => {
} else { match state {
*state = State::Default; State::Default => {
} if let Some(address) = address {
} *state = State::Address(address);
// 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 };
} else { } else {
defmt::error!("unsupported configuration value"); // stay in the default state
return Err(());
} }
} 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 { // the response to this request is handled in hardware
address, }
value: curr_value,
} => { Request::SetConfiguration { value } => {
if let Some(new_value) = value { match *state {
if new_value.get() == CONFIG_VAL { // unspecified behavior
if new_value != curr_value { State::Default => return Err(()),
defmt::info!("changing configuration");
*state = State::Configured { State::Address(address) => {
address, if let Some(value) = value {
value: new_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 { } else {
defmt::error!("unsupported configuration value"); // stay in the address mode
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::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 // stall any other request
.write(|w| w.tasks_ep0status().set_bit()); _ => return Err(()),
} }
// stall any other request Ok(())
_ => return Err(()),
} }
Ok(())
} }

View file

@ -17,13 +17,13 @@ fn main() -> ! {
// `heapless::Vec` exposes the same API surface as `std::Vec` but some of its methods return a // `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 // `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"); 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"); buffer.extend_from_slice(&[1, 2, 3]).expect("buffer full");
defmt::info!("after `extend`: {:?}", &buffer); defmt::println!("after `extend`: {:?}", &buffer);
// TODO try this operation // TODO try this operation
// buffer.extend_from_slice(&[4, 5, 6, 7]).expect("buffer full"); // buffer.extend_from_slice(&[4, 5, 6, 7]).expect("buffer full");

View file

@ -20,7 +20,7 @@ fn main() -> ! {
for _ in 0..10 { for _ in 0..10 {
led.toggle(); led.toggle();
timer.wait(Duration::from_secs(1)); timer.wait(Duration::from_secs(1));
defmt::info!("LED toggled at {:?}", dk::uptime()); defmt::println!("LED toggled at {:?}", dk::uptime());
} }
dk::exit() dk::exit()

View file

@ -19,7 +19,7 @@ fn main() -> ! {
// initializes the peripherals // initializes the peripherals
dk::init().unwrap(); dk::init().unwrap();
defmt::info!("Hello, world!"); // :wave: defmt::println!("Hello, world!"); // :wave:
loop { loop {
// breakpoint: halts the program's execution // breakpoint: halts the program's execution

View file

@ -4,7 +4,7 @@
use cortex_m::asm; use cortex_m::asm;
use cortex_m_rt::entry; use cortex_m_rt::entry;
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior // this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
use apps as _; // use apps as _;
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
@ -29,7 +29,7 @@ fn bar() {
let array = [0, 1, 2]; let array = [0, 1, 2];
let x = array[i]; // out of bounds access let x = array[i]; // out of bounds access
defmt::info!("{}", x); defmt::println!("{}", x);
} }
fn index() -> usize { fn index() -> usize {

View file

@ -38,9 +38,9 @@ fn main() -> ! {
if packet.len() == 1 { if packet.len() == 1 {
let destination = packet[0]; let destination = packet[0];
defmt::info!("{} -> {}", source, destination); defmt::println!("{} -> {}", source, destination);
// or cast to `char` for a more readable output // 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 { } else {
defmt::error!("response packet was not a single byte"); defmt::error!("response packet was not a single byte");
dk::exit() dk::exit()

View file

@ -27,9 +27,9 @@ fn main() -> ! {
let key = b'A'; let key = b'A';
let value = dict[&key]; // the key needs to be passed by reference let value = dict[&key]; // the key needs to be passed by reference
defmt::info!("{} -> {}", key, value); defmt::println!("{} -> {}", key, value);
// more readable // more readable
defmt::info!("{:?} -> {:?}", key as char, value as char); defmt::println!("{:?} -> {:?}", key as char, value as char);
// TODO try another insertion // TODO try another insertion
// TODO try looking up a key not contained in the dictionary // TODO try looking up a key not contained in the dictionary

View file

@ -46,7 +46,7 @@ fn main() -> ! {
} }
} }
defmt::info!("{:?}", defmt::Debug2Format(&dict)); defmt::println!("{:?}", defmt::Debug2Format(&dict));
// ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log `heapless` // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log `heapless`
// data structures (like `LinearMap` here) with `defmt` // data structures (like `LinearMap` here) with `defmt`

View file

@ -22,11 +22,11 @@ fn main() -> ! {
buffer.push(b'i').expect("buffer full"); buffer.push(b'i').expect("buffer full");
// look into the contents so far // look into the contents so far
defmt::info!("{:?}", buffer); defmt::println!("{:?}", buffer);
// or more readable // or more readable
// NOTE utf-8 conversion works as long as you only push bytes in the ASCII range (0..=127) // 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") str::from_utf8(&buffer).expect("content was not UTF-8")
); );

View file

@ -32,7 +32,7 @@ fn main() -> ! {
dk::exit() dk::exit()
} }
defmt::info!( defmt::println!(
"ciphertext: {}", "ciphertext: {}",
str::from_utf8(&packet).expect("packet was not valid UTF-8") str::from_utf8(&packet).expect("packet was not valid UTF-8")
); );
@ -48,7 +48,7 @@ fn main() -> ! {
buf.push(output).expect("buffer full"); buf.push(output).expect("buffer full");
} }
defmt::info!( defmt::println!(
"plaintext: {}", "plaintext: {}",
str::from_utf8(&buf).expect("buffer contains non-UTF-8 data") str::from_utf8(&buf).expect("buffer contains non-UTF-8 data")
); );

View file

@ -56,7 +56,7 @@ fn main() -> ! {
dk::exit() dk::exit()
} }
defmt::info!( defmt::println!(
"ciphertext: {}", "ciphertext: {}",
str::from_utf8(&packet).expect("packet was not valid UTF-8") str::from_utf8(&packet).expect("packet was not valid UTF-8")
); );
@ -72,7 +72,7 @@ fn main() -> ! {
buffer.push(value).expect("buffer full"); buffer.push(value).expect("buffer full");
} }
defmt::info!( defmt::println!(
"plaintext: {}", "plaintext: {}",
str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data")
); );

View file

@ -56,7 +56,7 @@ fn main() -> ! {
dk::exit() dk::exit()
} }
defmt::info!( defmt::println!(
"ciphertext: {}", "ciphertext: {}",
str::from_utf8(&packet).expect("packet was not valid UTF-8") str::from_utf8(&packet).expect("packet was not valid UTF-8")
); );
@ -72,7 +72,7 @@ fn main() -> ! {
buffer.push(value).expect("buffer full"); buffer.push(value).expect("buffer full");
} }
defmt::info!( defmt::println!(
"plaintext: {}", "plaintext: {}",
str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data")
); );
@ -87,7 +87,7 @@ fn main() -> ! {
dk::exit() dk::exit()
} }
defmt::info!( defmt::println!(
"Dongle response: {}", "Dongle response: {}",
str::from_utf8(&packet).expect("response was not UTF-8") str::from_utf8(&packet).expect("response was not UTF-8")
); );

View file

@ -57,7 +57,7 @@ fn main() -> ! {
dk::exit() dk::exit()
} }
defmt::info!( defmt::println!(
"ciphertext: {}", "ciphertext: {}",
str::from_utf8(&packet).expect("packet was not valid UTF-8") str::from_utf8(&packet).expect("packet was not valid UTF-8")
); );
@ -75,7 +75,7 @@ fn main() -> ! {
*spot = plainletter; *spot = plainletter;
} }
defmt::info!( defmt::println!(
"plaintext: {}", "plaintext: {}",
str::from_utf8(&packet).expect("buffer contains non-UTF-8 data") str::from_utf8(&packet).expect("buffer contains non-UTF-8 data")
); );
@ -88,7 +88,7 @@ fn main() -> ! {
dk::exit() dk::exit()
} }
defmt::info!( defmt::println!(
"Dongle response: {}", "Dongle response: {}",
str::from_utf8(&packet).expect("response was not UTF-8") str::from_utf8(&packet).expect("response was not UTF-8")
); );

View file

@ -60,7 +60,7 @@ fn main() -> ! {
dk::exit() dk::exit()
} }
defmt::info!( defmt::println!(
"ciphertext: {}", "ciphertext: {}",
str::from_utf8(&packet).expect("packet was not valid UTF-8") str::from_utf8(&packet).expect("packet was not valid UTF-8")
); );
@ -77,7 +77,7 @@ fn main() -> ! {
buffer.push(plainletter).expect("buffer full"); buffer.push(plainletter).expect("buffer full");
} }
defmt::info!( defmt::println!(
"plaintext: {}", "plaintext: {}",
str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data") str::from_utf8(&buffer).expect("buffer contains non-UTF-8 data")
); );
@ -92,7 +92,7 @@ fn main() -> ! {
dk::exit() dk::exit()
} }
defmt::info!( defmt::println!(
"Dongle response: {}", "Dongle response: {}",
str::from_utf8(&packet).expect("response was not UTF-8") str::from_utf8(&packet).expect("response was not UTF-8")
); );

View file

@ -34,14 +34,14 @@ fn main() -> ! {
// let msg = b"Hello?"; // let msg = b"Hello?";
packet.copy_from_slice(msg); packet.copy_from_slice(msg);
defmt::info!( defmt::println!(
"sending: {}", "sending: {}",
str::from_utf8(msg).expect("msg was not valid UTF-8 data") str::from_utf8(msg).expect("msg was not valid UTF-8 data")
); );
radio.send(&mut packet); radio.send(&mut packet);
if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_ok() { if radio.recv_timeout(&mut packet, &mut timer, TEN_MS).is_ok() {
defmt::info!( defmt::println!(
"received: {}", "received: {}",
str::from_utf8(&packet).expect("response was not valid UTF-8 data") str::from_utf8(&packet).expect("response was not valid UTF-8 data")
); );

View file

@ -25,7 +25,7 @@ fn main() -> ! {
let msg = b"olleh"; let msg = b"olleh";
packet.copy_from_slice(msg); packet.copy_from_slice(msg);
defmt::info!( defmt::println!(
"sending: {}", "sending: {}",
str::from_utf8(msg).expect("message is not valid UTF-8") str::from_utf8(msg).expect("message is not valid UTF-8")
); );
@ -38,7 +38,7 @@ fn main() -> ! {
match res { match res {
Ok(crc) => { Ok(crc) => {
defmt::info!( defmt::println!(
"received: {} (CRC = {:X})", "received: {} (CRC = {:X})",
// ^^ print as uppercase hexadecimal // ^^ print as uppercase hexadecimal
str::from_utf8(&*packet).expect("response is not valid UTF-8"), str::from_utf8(&*packet).expect("response is not valid UTF-8"),

View file

@ -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'H', b'e', b'l', b'l', b'o'];
// let msg: &[u8; 5] = b"Hello"; // let msg: &[u8; 5] = b"Hello";
defmt::info!( defmt::println!(
"sending: {}", "sending: {}",
str::from_utf8(msg).expect("msg is not valid UTF-8 data") str::from_utf8(msg).expect("msg is not valid UTF-8 data")
); );

View file

@ -22,7 +22,7 @@ fn main() -> ! {
fn fib(n: u32) -> u32 { fn fib(n: u32) -> u32 {
// allocate and initialize one kilobyte of stack memory to provoke stack overflow // 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); defmt::println!("allocating [{}; 1024]; round #{}", use_stack[1023], n);
if n < 2 { if n < 2 {
1 1

View file

@ -14,7 +14,8 @@ use cortex_m::{asm, peripheral::NVIC};
use embedded_hal::digital::v2::{OutputPin as _, StatefulOutputPin}; use embedded_hal::digital::v2::{OutputPin as _, StatefulOutputPin};
#[cfg(feature = "beginner")] #[cfg(feature = "beginner")]
pub use hal::ieee802154; 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::{ use hal::{
clocks::{self, Clocks}, clocks::{self, Clocks},
gpio::{p0, Level, Output, Pin, Port, PushPull}, 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` /// Exits the application and prints a backtrace when the program is executed through the `probe-run`
/// Cargo runner /// Cargo runner
pub fn exit() -> ! { 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 // force any pending memory operation to complete before the BKPT instruction that follows
atomic::compiler_fence(Ordering::SeqCst); atomic::compiler_fence(Ordering::SeqCst);
loop { loop {

View file

@ -51,7 +51,7 @@ impl Ep0In {
self.busy = true; self.busy = true;
defmt::info!("EP0IN: start {}B transfer", n); defmt::println!("EP0IN: start {}B transfer", n);
// start DMA transfer // start DMA transfer
dma_start(); dma_start();
@ -75,7 +75,7 @@ impl Ep0In {
usbd.events_ep0datadone.reset(); usbd.events_ep0datadone.reset();
self.busy = false; 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 // wait until the USB cable has been connected
while power.events_usbdetected.read().bits() == 0 { while power.events_usbdetected.read().bits() == 0 {
if once { if once {
defmt::info!("waiting for USB connection on port J3"); defmt::println!("waiting for USB connection on port J3");
once = false; once = false;
} }

View file

@ -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."> 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.">
<p> <p>
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. 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.

View file

@ -32,11 +32,11 @@ let array1: [u8; 3] = [0, 1, 2];
let array2: [u8; 4] = [0, 1, 2, 3]; let array2: [u8; 4] = [0, 1, 2, 3];
let mut slice: &[u8] = &array1; let mut slice: &[u8] = &array1;
defmt::info!("{:?}", slice); // length = 3 defmt::println!("{:?}", slice); // length = 3
// now point to the other array // now point to the other array
slice = &array2; slice = &array2;
defmt::info!("{:?}", slice); // length = 4 defmt::println!("{:?}", slice); // length = 4
``` ```
## Byte literals ## 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. 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. 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)`. 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)`.

View file

@ -56,7 +56,7 @@ fn main() -> ! {
for plainletter in 0..=127 { for plainletter in 0..=127 {
/* ... send letter to dongle ... */ /* ... send letter to dongle ... */
defmt::info!("got response"); defmt::println!("got response");
/* ... store output ... */ /* ... store output ... */
timer.wait(Duration::from_millis(20)); timer.wait(Duration::from_millis(20));

View file

@ -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? ✅ 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.