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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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
// `Result` to indicate whether the operation failed due to the `heapless::Vec` being full
defmt::info!("start: {:?}", buffer);
defmt::println!("start: {:?}", buffer);
buffer.push(0).expect("buffer full");
defmt::info!("after `push`: {:?}", buffer);
defmt::println!("after `push`: {:?}", buffer);
buffer.extend_from_slice(&[1, 2, 3]).expect("buffer full");
defmt::info!("after `extend`: {:?}", &buffer);
defmt::println!("after `extend`: {:?}", &buffer);
// TODO try this operation
// buffer.extend_from_slice(&[4, 5, 6, 7]).expect("buffer full");

View File

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

View File

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

View File

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

View File

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

View File

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

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`
// data structures (like `LinearMap` here) with `defmt`

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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"Hello";
defmt::info!(
defmt::println!(
"sending: {}",
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 {
// allocate and initialize one kilobyte of stack memory to provoke stack overflow
let use_stack = [0xAA; 1024];
defmt::info!("allocating [{}; 1024]; round #{}", use_stack[1023], n);
defmt::println!("allocating [{}; 1024]; round #{}", use_stack[1023], n);
if n < 2 {
1

View File

@ -14,7 +14,8 @@ use cortex_m::{asm, peripheral::NVIC};
use embedded_hal::digital::v2::{OutputPin as _, StatefulOutputPin};
#[cfg(feature = "beginner")]
pub use hal::ieee802154;
pub use hal::pac::{interrupt, Interrupt, NVIC_PRIO_BITS, RTC0};
#[doc(hidden)]
pub use hal::pac::{Peripherals, interrupt, Interrupt, NVIC_PRIO_BITS, RTC0};
use hal::{
clocks::{self, Clocks},
gpio::{p0, Level, Output, Pin, Port, PushPull},
@ -289,7 +290,7 @@ fn RTC0() {
/// Exits the application and prints a backtrace when the program is executed through the `probe-run`
/// Cargo runner
pub fn exit() -> ! {
defmt::info!("`dk::exit()` called; exiting ...");
defmt::println!("`dk::exit()` called; exiting ...");
// force any pending memory operation to complete before the BKPT instruction that follows
atomic::compiler_fence(Ordering::SeqCst);
loop {

View File

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

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

View File

@ -32,11 +32,11 @@ let array1: [u8; 3] = [0, 1, 2];
let array2: [u8; 4] = [0, 1, 2, 3];
let mut slice: &[u8] = &array1;
defmt::info!("{:?}", slice); // length = 3
defmt::println!("{:?}", slice); // length = 3
// now point to the other array
slice = &array2;
defmt::info!("{:?}", slice); // length = 4
defmt::println!("{:?}", slice); // length = 4
```
## Byte literals
@ -82,8 +82,8 @@ On the other hand, `"Hello"` is a string literal with type `&str`. `str` strings
In this workshop we'll work with ASCII strings so byte string literals that contain no escaped characters are OK to use as packet payloads.
You'll note that `defmt::info!("{:?}", b"Hello")` will print `[72, 101, 108, 108, 111]` rather than `"Hello"` and that the `{}` format specifier (`Display`) does not work. This is because the type of the literal is `&[u8; N]` and in Rust this type means "bytes"; those bytes could be ASCII data, UTF-8 data or something else.
You'll note that `defmt::println!("{:?}", b"Hello")` will print `[72, 101, 108, 108, 111]` rather than `"Hello"` and that the `{}` format specifier (`Display`) does not work. This is because the type of the literal is `&[u8; N]` and in Rust this type means "bytes"; those bytes could be ASCII data, UTF-8 data or something else.
To print this you'll need to convert the slice `&[u8]` into a string (`&str`) using the `str::from_utf8` function. This function will verify that the slice contains well formed UTF-8 data and interpret it as a UTF-8 string (`&str`). As long as we use ASCII data (printable ASCII characters) this conversion will not fail.
Something similar will happen with byte literals: `defmt::info!("{}", b'A')` will print `65` rather than `A`. To get the `A` output you can cast the byte literal (`u8` value) to the `char` type: `defmt::info!("{}", b'A' as char)`.
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 {
/* ... send letter to dongle ... */
defmt::info!("got response");
defmt::println!("got response");
/* ... store output ... */
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?
❗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.