mirror of
https://github.com/ferrous-systems/embedded-trainings-2020.git
synced 2025-01-25 07:18:08 +00:00
info! -> println!
This commit is contained in:
parent
d71d2da3f4
commit
c588bb64fc
38 changed files with 931 additions and 850 deletions
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ fn main() -> ! {
|
|||
// board initialization
|
||||
dk::init().unwrap();
|
||||
|
||||
defmt::info!("Hello, world!");
|
||||
defmt::println!("Hello, world!");
|
||||
|
||||
loop {
|
||||
asm::bkpt();
|
||||
|
|
|
@ -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 { "" }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,96 +1,102 @@
|
|||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use dk::{
|
||||
peripheral::USBD,
|
||||
usbd::{self, Ep0In, Event},
|
||||
};
|
||||
// this imports `beginner/apps/lib.rs` to retrieve our global logger + panicking-behavior
|
||||
use firmware as _;
|
||||
use usb::{Descriptor, Request};
|
||||
|
||||
#[rtic::app(device = dk)]
|
||||
const APP: () = {
|
||||
struct Resources {
|
||||
#[rtic::app(device = dk, peripherals = false)]
|
||||
mod app {
|
||||
use dk::{
|
||||
peripheral::USBD,
|
||||
usbd::{self, Ep0In, Event},
|
||||
Peripherals,
|
||||
};
|
||||
use usb::{Descriptor, Request};
|
||||
|
||||
#[local]
|
||||
struct MyLocalResources {
|
||||
usbd: USBD,
|
||||
ep0in: Ep0In,
|
||||
}
|
||||
|
||||
#[shared]
|
||||
struct MySharedResources {
|
||||
|
||||
}
|
||||
#[init]
|
||||
fn init(_cx: init::Context) -> init::LateResources {
|
||||
fn init(_cx: init::Context) -> (MySharedResources, MyLocalResources, init::Monotonics) {
|
||||
let board = dk::init().unwrap();
|
||||
|
||||
usbd::init(board.power, &board.usbd);
|
||||
|
||||
init::LateResources {
|
||||
ep0in: board.ep0in,
|
||||
usbd: board.usbd,
|
||||
}
|
||||
(MySharedResources {}, MyLocalResources { usbd: board.usbd, ep0in: board.ep0in, }, init::Monotonics())
|
||||
}
|
||||
|
||||
#[task(binds = USBD, resources = [usbd, ep0in])]
|
||||
#[task(binds = USBD, local = [usbd, ep0in])]
|
||||
fn main(cx: main::Context) {
|
||||
let usbd = cx.resources.usbd;
|
||||
let ep0in = cx.resources.ep0in;
|
||||
let usbd = cx.local.usbd;
|
||||
let ep0in = cx.local.ep0in;
|
||||
|
||||
while let Some(event) = usbd::next_event(usbd) {
|
||||
on_event(usbd, ep0in, event)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) {
|
||||
defmt::info!("USB: {:?} @ {:?}", event, dk::uptime());
|
||||
|
||||
match event {
|
||||
Event::UsbReset => {
|
||||
// nothing to do here at the moment
|
||||
}
|
||||
|
||||
Event::UsbEp0DataDone => todo!(), // <- TODO
|
||||
|
||||
Event::UsbEp0Setup => {
|
||||
let bmrequesttype = usbd::bmrequesttype(usbd);
|
||||
let brequest = usbd::brequest(usbd);
|
||||
let wlength = usbd::wlength(usbd);
|
||||
let windex = usbd::windex(usbd);
|
||||
let wvalue = usbd::wvalue(usbd);
|
||||
|
||||
defmt::info!(
|
||||
"SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}",
|
||||
bmrequesttype,
|
||||
brequest,
|
||||
wlength,
|
||||
windex,
|
||||
wvalue
|
||||
);
|
||||
|
||||
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect(
|
||||
"Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)",
|
||||
);
|
||||
match request {
|
||||
Request::GetDescriptor { descriptor, length }
|
||||
if descriptor == Descriptor::Device =>
|
||||
{
|
||||
defmt::info!("GET_DESCRIPTOR Device [length={}]", length);
|
||||
|
||||
// TODO send back a valid device descriptor, truncated to `length` bytes
|
||||
// let desc = usb2::device::Descriptor { .. };
|
||||
let resp = [];
|
||||
ep0in.start(&resp, usbd);
|
||||
}
|
||||
Request::SetAddress { .. } => {
|
||||
// On Mac OS you'll get this request before the GET_DESCRIPTOR request so we
|
||||
// need to catch it here. We'll properly handle this request later
|
||||
// but for now it's OK to do nothing.
|
||||
}
|
||||
_ => {
|
||||
defmt::error!(
|
||||
"unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)"
|
||||
);
|
||||
dk::exit()
|
||||
fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) {
|
||||
defmt::println!("USB: {:?} @ {:?}", event, dk::uptime());
|
||||
|
||||
match event {
|
||||
Event::UsbReset => {
|
||||
// nothing to do here at the moment
|
||||
}
|
||||
|
||||
Event::UsbEp0DataDone => todo!(), // <- TODO
|
||||
|
||||
Event::UsbEp0Setup => {
|
||||
let bmrequesttype = usbd::bmrequesttype(usbd);
|
||||
let brequest = usbd::brequest(usbd);
|
||||
let wlength = usbd::wlength(usbd);
|
||||
let windex = usbd::windex(usbd);
|
||||
let wvalue = usbd::wvalue(usbd);
|
||||
|
||||
defmt::println!(
|
||||
"SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}",
|
||||
bmrequesttype,
|
||||
brequest,
|
||||
wlength,
|
||||
windex,
|
||||
wvalue
|
||||
);
|
||||
|
||||
let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength).expect(
|
||||
"Error parsing request (goal achieved if GET_DESCRIPTOR Device was handled before)",
|
||||
);
|
||||
match request {
|
||||
Request::GetDescriptor { descriptor, length }
|
||||
if descriptor == Descriptor::Device =>
|
||||
{
|
||||
defmt::println!("GET_DESCRIPTOR Device [length={}]", length);
|
||||
|
||||
// TODO send back a valid device descriptor, truncated to `length` bytes
|
||||
// let desc = usb2::device::Descriptor { .. };
|
||||
let resp = [];
|
||||
ep0in.start(&resp, usbd);
|
||||
}
|
||||
Request::SetAddress { .. } => {
|
||||
// On Mac OS you'll get this request before the GET_DESCRIPTOR request so we
|
||||
// need to catch it here. We'll properly handle this request later
|
||||
// but for now it's OK to do nothing.
|
||||
}
|
||||
_ => {
|
||||
defmt::error!(
|
||||
"unknown request (goal achieved if GET_DESCRIPTOR Device was handled before)"
|
||||
);
|
||||
dk::exit()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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(())
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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(())
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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(())
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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`
|
||||
|
||||
|
|
|
@ -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")
|
||||
);
|
||||
|
|
|
@ -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")
|
||||
);
|
||||
|
|
|
@ -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")
|
||||
);
|
||||
|
|
|
@ -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")
|
||||
);
|
||||
|
|
|
@ -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")
|
||||
);
|
||||
|
|
|
@ -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")
|
||||
);
|
||||
|
|
|
@ -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")
|
||||
);
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -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")
|
||||
);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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)`.
|
|
@ -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));
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue