From e5ede7362d7207562a00b1a9d910080395d2426c Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Tue, 10 Dec 2024 14:41:07 +0000 Subject: [PATCH 01/10] Fixup RTC driver. No more static mut. Plus we have functions that return microseconds, which is what defmt::timestamps really wants. --- nrf52-code/boards/dk-solution/src/lib.rs | 106 +++++++++++------- nrf52-code/boards/dk/src/lib.rs | 106 +++++++++++------- nrf52-code/boards/dongle/Cargo.toml | 1 + nrf52-code/boards/dongle/src/lib.rs | 132 +++++++++++++++-------- nrf52-code/loopback-fw/Cargo.lock | 10 ++ nrf52-code/puzzle-fw/Cargo.lock | 10 ++ 6 files changed, 241 insertions(+), 124 deletions(-) diff --git a/nrf52-code/boards/dk-solution/src/lib.rs b/nrf52-code/boards/dk-solution/src/lib.rs index 51e0216c..91045c06 100644 --- a/nrf52-code/boards/dk-solution/src/lib.rs +++ b/nrf52-code/boards/dk-solution/src/lib.rs @@ -15,11 +15,11 @@ use core::{ use cortex_m::peripheral::NVIC; use cortex_m_semihosting::debug; use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin}; -#[cfg(any(feature = "advanced"))] +#[cfg(feature = "advanced")] use grounded::uninit::GroundedArrayCell; -#[cfg(any(feature = "radio"))] +#[cfg(feature = "radio")] use grounded::uninit::GroundedCell; -#[cfg(any(feature = "radio"))] +#[cfg(feature = "radio")] pub use hal::ieee802154; pub use hal::pac::{interrupt, Interrupt, NVIC_PRIO_BITS, RTC0}; use hal::{ @@ -323,7 +323,7 @@ pub fn init() -> Result { let Some(periph) = hal::pac::Peripherals::take() else { return Err(Error::DoubleInit); }; - // NOTE(static mut) this branch runs at most once + // NOTE: this branch runs at most once #[cfg(feature = "advanced")] static EP0IN_BUF: GroundedArrayCell = GroundedArrayCell::const_init(); #[cfg(feature = "radio")] @@ -433,11 +433,14 @@ static OVERFLOWS: AtomicU32 = AtomicU32::new(0); // NOTE this will run at the highest priority, higher priority than RTIC tasks #[interrupt] fn RTC0() { - let curr = OVERFLOWS.load(Ordering::Relaxed); - OVERFLOWS.store(curr + 1, Ordering::Relaxed); - - // clear the EVENT register - unsafe { core::mem::transmute::<_, RTC0>(()).events_ovrflw.reset() } + OVERFLOWS.fetch_add(1, Ordering::Release); + // # Safety + // Concurrent access to this field within the RTC is acceptable. + unsafe { + let rtc = hal::pac::Peripherals::steal().RTC0; + // clear the EVENT register + rtc.events_ovrflw.reset(); + } } /// Exits the application successfully when the program is executed through the @@ -478,10 +481,10 @@ pub fn fail() -> ! { /// Returns the time elapsed since the call to the `dk::init` function /// -/// The clock that is read to compute this value has a resolution of 30 microseconds. +/// The time is in 32,768 Hz units (i.e. 32768 = 1 second) /// /// Calling this function before calling `dk::init` will return a value of `0` nanoseconds. -pub fn uptime() -> Duration { +pub fn uptime_ticks() -> u64 { // here we are going to perform a 64-bit read of the number of ticks elapsed // // a 64-bit load operation cannot performed in a single instruction so the operation can be @@ -490,35 +493,60 @@ pub fn uptime() -> Duration { // the loop below will load both the lower and upper parts of the 64-bit value while preventing // the issue of mixing a low value with an "old" high value -- note that, due to interrupts, an // arbitrary amount of time may elapse between the `hi1` load and the `low` load - let overflows = &OVERFLOWS as *const AtomicU32 as *const u32; - let ticks = loop { - unsafe { - // NOTE volatile is used to order these load operations among themselves - let hi1 = overflows.read_volatile(); - let low = core::mem::transmute::<_, RTC0>(()) - .counter - .read() - .counter() - .bits(); - let hi2 = overflows.read_volatile(); - - if hi1 == hi2 { - break u64::from(low) | (u64::from(hi1) << 24); - } + + // # Safety + // Concurrent access to this field within the RTC is acceptable. + let rtc_counter = unsafe { &hal::pac::Peripherals::steal().RTC0.counter }; + + loop { + // NOTE volatile is used to order these load operations among themselves + let hi1 = OVERFLOWS.load(Ordering::Acquire); + let low = rtc_counter.read().counter().bits(); + let hi2 = OVERFLOWS.load(Ordering::Relaxed); + + if hi1 == hi2 { + break u64::from(low) | (u64::from(hi1) << 24); } - }; + } +} + +/// Returns the time elapsed since the call to the `dk::init` function +/// +/// The clock that is read to compute this value has a resolution of 30 microseconds. +/// +/// Calling this function before calling `dk::init` will return a value of `0` nanoseconds. +pub fn uptime() -> Duration { + // We have a time in 32,768 Hz units. + let mut ticks = uptime_ticks(); + + // turn it into 32_768_000_000 units + ticks = ticks.wrapping_mul(1_000_000); + // turn it into microsecond units + ticks >>= 15; + // turn it into nanosecond units + ticks = ticks.wrapping_mul(1_000); + + // NB: 64-bit nanoseconds handles around 584 years. + + let secs = ticks / 1_000_000_000; + let nanos = ticks % 1_000_000_000; - // 2**15 ticks = 1 second - let freq = 1 << 15; - let secs = ticks / freq; - // subsec ticks - let ticks = (ticks % freq) as u32; - // one tick is equal to `1e9 / 32768` nanos - // the fraction can be reduced to `1953125 / 64` - // which can be further decomposed as `78125 * (5 / 4) * (5 / 4) * (1 / 4)`. - // Doing the operation this way we can stick to 32-bit arithmetic without overflowing the value - // at any stage - let nanos = - (((ticks % 32768).wrapping_mul(78125) >> 2).wrapping_mul(5) >> 2).wrapping_mul(5) >> 2; Duration::new(secs, nanos as u32) } + +/// Returns the time elapsed since the call to the `dk::init` function, in microseconds. +/// +/// The clock that is read to compute this value has a resolution of 30 microseconds. +/// +/// Calling this function before calling `dk::init` will return a value of `0` nanoseconds. +pub fn uptime_us() -> u64 { + // We have a time in 32,768 Hz units. + let mut ticks = uptime_ticks(); + + // turn it into 32_768_000_000 units + ticks = ticks.wrapping_mul(1_000_000); + // turn it into microsecond units + ticks >>= 15; + + ticks +} diff --git a/nrf52-code/boards/dk/src/lib.rs b/nrf52-code/boards/dk/src/lib.rs index 57f4e9ad..88ac36c8 100644 --- a/nrf52-code/boards/dk/src/lib.rs +++ b/nrf52-code/boards/dk/src/lib.rs @@ -15,11 +15,11 @@ use core::{ use cortex_m::peripheral::NVIC; use cortex_m_semihosting::debug; use embedded_hal::digital::{OutputPin, StatefulOutputPin}; -#[cfg(any(feature = "advanced"))] +#[cfg(feature = "advanced")] use grounded::uninit::GroundedArrayCell; -#[cfg(any(feature = "radio"))] +#[cfg(feature = "radio")] use grounded::uninit::GroundedCell; -#[cfg(any(feature = "radio"))] +#[cfg(feature = "radio")] pub use hal::ieee802154; pub use hal::pac::{interrupt, Interrupt, NVIC_PRIO_BITS, RTC0}; use hal::{ @@ -297,7 +297,7 @@ pub fn init() -> Result { let Some(periph) = hal::pac::Peripherals::take() else { return Err(Error::DoubleInit); }; - // NOTE(static mut) this branch runs at most once + // NOTE: this branch runs at most once #[cfg(feature = "advanced")] static EP0IN_BUF: GroundedArrayCell = GroundedArrayCell::const_init(); #[cfg(feature = "radio")] @@ -395,11 +395,14 @@ static OVERFLOWS: AtomicU32 = AtomicU32::new(0); // NOTE this will run at the highest priority, higher priority than RTIC tasks #[interrupt] fn RTC0() { - let curr = OVERFLOWS.load(Ordering::Relaxed); - OVERFLOWS.store(curr + 1, Ordering::Relaxed); - - // clear the EVENT register - unsafe { core::mem::transmute::<_, RTC0>(()).events_ovrflw.reset() } + OVERFLOWS.fetch_add(1, Ordering::Release); + // # Safety + // Concurrent access to this field within the RTC is acceptable. + unsafe { + let rtc = hal::pac::Peripherals::steal().RTC0; + // clear the EVENT register + rtc.events_ovrflw.reset(); + } } /// Exits the application successfully when the program is executed through the @@ -440,10 +443,10 @@ pub fn fail() -> ! { /// Returns the time elapsed since the call to the `dk::init` function /// -/// The clock that is read to compute this value has a resolution of 30 microseconds. +/// The time is in 32,768 Hz units (i.e. 32768 = 1 second) /// /// Calling this function before calling `dk::init` will return a value of `0` nanoseconds. -pub fn uptime() -> Duration { +pub fn uptime_ticks() -> u64 { // here we are going to perform a 64-bit read of the number of ticks elapsed // // a 64-bit load operation cannot performed in a single instruction so the operation can be @@ -452,35 +455,60 @@ pub fn uptime() -> Duration { // the loop below will load both the lower and upper parts of the 64-bit value while preventing // the issue of mixing a low value with an "old" high value -- note that, due to interrupts, an // arbitrary amount of time may elapse between the `hi1` load and the `low` load - let overflows = &OVERFLOWS as *const AtomicU32 as *const u32; - let ticks = loop { - unsafe { - // NOTE volatile is used to order these load operations among themselves - let hi1 = overflows.read_volatile(); - let low = core::mem::transmute::<_, RTC0>(()) - .counter - .read() - .counter() - .bits(); - let hi2 = overflows.read_volatile(); - - if hi1 == hi2 { - break u64::from(low) | (u64::from(hi1) << 24); - } + + // # Safety + // Concurrent access to this field within the RTC is acceptable. + let rtc_counter = unsafe { &hal::pac::Peripherals::steal().RTC0.counter }; + + loop { + // NOTE volatile is used to order these load operations among themselves + let hi1 = OVERFLOWS.load(Ordering::Acquire); + let low = rtc_counter.read().counter().bits(); + let hi2 = OVERFLOWS.load(Ordering::Relaxed); + + if hi1 == hi2 { + break u64::from(low) | (u64::from(hi1) << 24); } - }; + } +} + +/// Returns the time elapsed since the call to the `dk::init` function +/// +/// The clock that is read to compute this value has a resolution of 30 microseconds. +/// +/// Calling this function before calling `dk::init` will return a value of `0` nanoseconds. +pub fn uptime() -> Duration { + // We have a time in 32,768 Hz units. + let mut ticks = uptime_ticks(); + + // turn it into 32_768_000_000 units + ticks = ticks.wrapping_mul(1_000_000); + // turn it into microsecond units + ticks >>= 15; + // turn it into nanosecond units + ticks = ticks.wrapping_mul(1_000); + + // NB: 64-bit nanoseconds handles around 584 years. + + let secs = ticks / 1_000_000_000; + let nanos = ticks % 1_000_000_000; - // 2**15 ticks = 1 second - let freq = 1 << 15; - let secs = ticks / freq; - // subsec ticks - let ticks = (ticks % freq) as u32; - // one tick is equal to `1e9 / 32768` nanos - // the fraction can be reduced to `1953125 / 64` - // which can be further decomposed as `78125 * (5 / 4) * (5 / 4) * (1 / 4)`. - // Doing the operation this way we can stick to 32-bit arithmetic without overflowing the value - // at any stage - let nanos = - (((ticks % 32768).wrapping_mul(78125) >> 2).wrapping_mul(5) >> 2).wrapping_mul(5) >> 2; Duration::new(secs, nanos as u32) } + +/// Returns the time elapsed since the call to the `dk::init` function, in microseconds. +/// +/// The clock that is read to compute this value has a resolution of 30 microseconds. +/// +/// Calling this function before calling `dk::init` will return a value of `0` nanoseconds. +pub fn uptime_us() -> u64 { + // We have a time in 32,768 Hz units. + let mut ticks = uptime_ticks(); + + // turn it into 32_768_000_000 units + ticks = ticks.wrapping_mul(1_000_000); + // turn it into microsecond units + ticks >>= 15; + + ticks +} diff --git a/nrf52-code/boards/dongle/Cargo.toml b/nrf52-code/boards/dongle/Cargo.toml index a4756f39..faadb470 100644 --- a/nrf52-code/boards/dongle/Cargo.toml +++ b/nrf52-code/boards/dongle/Cargo.toml @@ -13,6 +13,7 @@ critical-section = "1.2.0" defmt = "0.3.8" defmt-rtt = "0.4" embedded-hal = "1.0" +grounded = { version = "0.2.0", features = ["cas"] } hal = { package = "nrf52840-hal", version = "0.18.0" } heapless = "0.8.0" panic-probe = { version = "0.3.0", features = ["print-defmt"] } diff --git a/nrf52-code/boards/dongle/src/lib.rs b/nrf52-code/boards/dongle/src/lib.rs index fcaf5dbf..88659f88 100644 --- a/nrf52-code/boards/dongle/src/lib.rs +++ b/nrf52-code/boards/dongle/src/lib.rs @@ -15,7 +15,9 @@ use core::{ use cortex_m::peripheral::NVIC; use cortex_m_semihosting::debug; use embedded_hal::digital::{OutputPin, StatefulOutputPin}; +use grounded::uninit::GroundedCell; +use hal::pac::interrupt; pub use hal::{self, ieee802154}; use hal::{ clocks::{self, Clocks}, @@ -35,7 +37,11 @@ pub mod peripheral { /// A short-hand for the nRF52 USB types pub type UsbBus = hal::usbd::Usbd>; -use peripheral::interrupt; +struct ClockSyncWrapper { + clocks: Clocks, +} + +unsafe impl Sync for ClockSyncWrapper {} /// Components on the board pub struct Board { @@ -282,21 +288,31 @@ pub fn init() -> Result { let Some(periph) = hal::pac::Peripherals::take() else { return Err(Error::DoubleInit); }; - // NOTE(static mut) this branch runs at most once - static mut CLOCKS: Option< - Clocks, - > = None; - + // NOTE: this branch runs at most once + // We need the wrapper to make this type Sync, as it contains raw pointers + static CLOCKS: GroundedCell< + ClockSyncWrapper< + clocks::ExternalOscillator, + clocks::ExternalOscillator, + clocks::LfOscStarted, + >, + > = GroundedCell::uninit(); defmt::debug!("Initializing the board"); let clocks = Clocks::new(periph.CLOCK); let clocks = clocks.enable_ext_hfosc(); let clocks = clocks.set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass); let clocks = clocks.start_lfclk(); - let _clocks = clocks.enable_ext_hfosc(); + let clocks = clocks.enable_ext_hfosc(); // extend lifetime to `'static` - let clocks = unsafe { CLOCKS.get_or_insert(_clocks) }; - + let clocks = unsafe { + let clocks_ptr = CLOCKS.get(); + clocks_ptr.write(ClockSyncWrapper { clocks }); + // Now it's initialised, we can take a static reference to the clocks + // object it contains. + let clock_wrapper: &'static ClockSyncWrapper<_, _, _> = &*clocks_ptr; + &clock_wrapper.clocks + }; defmt::debug!("Clocks configured"); let mut rtc = Rtc::new(periph.RTC0, 0).unwrap(); @@ -363,14 +379,13 @@ static OVERFLOWS: AtomicU32 = AtomicU32::new(0); // NOTE this will run at the highest priority, higher priority than RTIC tasks #[interrupt] fn RTC0() { - let curr = OVERFLOWS.load(Ordering::Relaxed); - OVERFLOWS.store(curr + 1, Ordering::Relaxed); - - // clear the EVENT register + OVERFLOWS.fetch_add(1, Ordering::Release); + // # Safety + // Concurrent access to this field within the RTC is acceptable. unsafe { - core::mem::transmute::<_, hal::pac::RTC0>(()) - .events_ovrflw - .reset() + let rtc = hal::pac::Peripherals::steal().RTC0; + // clear the EVENT register + rtc.events_ovrflw.reset(); } } @@ -393,10 +408,10 @@ pub fn exit() -> ! { /// Returns the time elapsed since the call to the `dk::init` function /// -/// The clock that is read to compute this value has a resolution of 30 microseconds. +/// The time is in 32,768 Hz units (i.e. 32768 = 1 second) /// /// Calling this function before calling `dk::init` will return a value of `0` nanoseconds. -pub fn uptime() -> Duration { +pub fn uptime_ticks() -> u64 { // here we are going to perform a 64-bit read of the number of ticks elapsed // // a 64-bit load operation cannot performed in a single instruction so the operation can be @@ -405,39 +420,64 @@ pub fn uptime() -> Duration { // the loop below will load both the lower and upper parts of the 64-bit value while preventing // the issue of mixing a low value with an "old" high value -- note that, due to interrupts, an // arbitrary amount of time may elapse between the `hi1` load and the `low` load - let overflows = &OVERFLOWS as *const AtomicU32 as *const u32; - let ticks = loop { - unsafe { - // NOTE volatile is used to order these load operations among themselves - let hi1 = overflows.read_volatile(); - let low = core::mem::transmute::<_, hal::pac::RTC0>(()) - .counter - .read() - .counter() - .bits(); - let hi2 = overflows.read_volatile(); - - if hi1 == hi2 { - break u64::from(low) | (u64::from(hi1) << 24); - } + + // # Safety + // Concurrent access to this field within the RTC is acceptable. + let rtc_counter = unsafe { &hal::pac::Peripherals::steal().RTC0.counter }; + + loop { + // NOTE volatile is used to order these load operations among themselves + let hi1 = OVERFLOWS.load(Ordering::Acquire); + let low = rtc_counter.read().counter().bits(); + let hi2 = OVERFLOWS.load(Ordering::Relaxed); + + if hi1 == hi2 { + break u64::from(low) | (u64::from(hi1) << 24); } - }; + } +} + +/// Returns the time elapsed since the call to the `dk::init` function +/// +/// The clock that is read to compute this value has a resolution of 30 microseconds. +/// +/// Calling this function before calling `dk::init` will return a value of `0` nanoseconds. +pub fn uptime() -> Duration { + // We have a time in 32,768 Hz units. + let mut ticks = uptime_ticks(); + + // turn it into 32_768_000_000 units + ticks = ticks.wrapping_mul(1_000_000); + // turn it into microsecond units + ticks >>= 15; + // turn it into nanosecond units + ticks = ticks.wrapping_mul(1_000); + + // NB: 64-bit nanoseconds handles around 584 years. + + let secs = ticks / 1_000_000_000; + let nanos = ticks % 1_000_000_000; - // 2**15 ticks = 1 second - let freq = 1 << 15; - let secs = ticks / freq; - // subsec ticks - let ticks = (ticks % freq) as u32; - // one tick is equal to `1e9 / 32768` nanos - // the fraction can be reduced to `1953125 / 64` - // which can be further decomposed as `78125 * (5 / 4) * (5 / 4) * (1 / 4)`. - // Doing the operation this way we can stick to 32-bit arithmetic without overflowing the value - // at any stage - let nanos = - (((ticks % 32768).wrapping_mul(78125) >> 2).wrapping_mul(5) >> 2).wrapping_mul(5) >> 2; Duration::new(secs, nanos as u32) } +/// Returns the time elapsed since the call to the `dk::init` function, in microseconds. +/// +/// The clock that is read to compute this value has a resolution of 30 microseconds. +/// +/// Calling this function before calling `dk::init` will return a value of `0` nanoseconds. +pub fn uptime_us() -> u64 { + // We have a time in 32,768 Hz units. + let mut ticks = uptime_ticks(); + + // turn it into 32_768_000_000 units + ticks = ticks.wrapping_mul(1_000_000); + // turn it into microsecond units + ticks >>= 15; + + ticks +} + /// Returns the least-significant bits of the device identifier pub fn deviceid0() -> u32 { // NOTE(unsafe) read-only registers, and no other use of the block diff --git a/nrf52-code/loopback-fw/Cargo.lock b/nrf52-code/loopback-fw/Cargo.lock index 4cc8e3ca..05da8a29 100644 --- a/nrf52-code/loopback-fw/Cargo.lock +++ b/nrf52-code/loopback-fw/Cargo.lock @@ -182,6 +182,7 @@ dependencies = [ "defmt", "defmt-rtt", "embedded-hal 1.0.0", + "grounded", "heapless", "nrf52840-hal", "panic-probe", @@ -253,6 +254,15 @@ dependencies = [ "wasi", ] +[[package]] +name = "grounded" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917d82402c7eb9755fdd87d52117701dae9e413a6abb309fac2a13af693b6080" +dependencies = [ + "portable-atomic", +] + [[package]] name = "half" version = "2.4.1" diff --git a/nrf52-code/puzzle-fw/Cargo.lock b/nrf52-code/puzzle-fw/Cargo.lock index 9b5a9682..f6d1b7ae 100644 --- a/nrf52-code/puzzle-fw/Cargo.lock +++ b/nrf52-code/puzzle-fw/Cargo.lock @@ -182,6 +182,7 @@ dependencies = [ "defmt", "defmt-rtt", "embedded-hal 1.0.0", + "grounded", "heapless", "nrf52840-hal", "panic-probe", @@ -253,6 +254,15 @@ dependencies = [ "wasi", ] +[[package]] +name = "grounded" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917d82402c7eb9755fdd87d52117701dae9e413a6abb309fac2a13af693b6080" +dependencies = [ + "portable-atomic", +] + [[package]] name = "half" version = "2.4.1" From 70357a80596430c3d5473b8e1935a6c4512f443d Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Tue, 10 Dec 2024 14:41:33 +0000 Subject: [PATCH 02/10] Pick a better log format. Also has optional timestamps. --- exercise-book/src/nrf52-radio-running-from-vsc.md | 7 ++++++- nrf52-code/hal-app/.cargo/config.toml | 12 +++++++++++- nrf52-code/hal-app/src/lib.rs | 2 ++ nrf52-code/radio-app/.cargo/config.toml | 12 +++++++++++- nrf52-code/radio-app/src/lib.rs | 2 ++ nrf52-code/usb-app-solutions/.cargo/config.toml | 12 +++++++++++- nrf52-code/usb-app-solutions/src/lib.rs | 2 ++ nrf52-code/usb-app/.cargo/config.toml | 12 +++++++++++- nrf52-code/usb-app/src/lib.rs | 2 ++ 9 files changed, 58 insertions(+), 5 deletions(-) diff --git a/exercise-book/src/nrf52-radio-running-from-vsc.md b/exercise-book/src/nrf52-radio-running-from-vsc.md index 0c51b6d3..30d8a548 100644 --- a/exercise-book/src/nrf52-radio-running-from-vsc.md +++ b/exercise-book/src/nrf52-radio-running-from-vsc.md @@ -79,7 +79,12 @@ Should you need to configure the `probe-rs` invocation to e.g. flash a different ```toml [target.thumbv7em-none-eabihf] -runner = "probe-rs run --chip nRF52840_xxAA" # <- add/remove/modify flags here +runner = [ + "probe-rs", + "run", + "--chip", + "nRF52840_xxAA" +] # .. ``` diff --git a/nrf52-code/hal-app/.cargo/config.toml b/nrf52-code/hal-app/.cargo/config.toml index 75a7d205..040c82ab 100644 --- a/nrf52-code/hal-app/.cargo/config.toml +++ b/nrf52-code/hal-app/.cargo/config.toml @@ -1,7 +1,17 @@ [target.thumbv7em-none-eabihf] # set custom cargo runner to flash & run on embedded target when we call `cargo run` # for more information, check out https://github.com/probe-rs -runner = "probe-rs run --chip nRF52840_xxAA --allow-erase-all" +runner = [ + "probe-rs", + "run", + "--chip", + "nRF52840_xxAA", + "--allow-erase-all", + "--log-format", + "{[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" +] +# Or use "{t} {[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" to enable timestamps + rustflags = [ "-C", "link-arg=-Tlink.x", # use the cortex-m-rt linker script "-C", "linker=flip-link", # adds stack overflow protection diff --git a/nrf52-code/hal-app/src/lib.rs b/nrf52-code/hal-app/src/lib.rs index f104b329..2907e773 100644 --- a/nrf52-code/hal-app/src/lib.rs +++ b/nrf52-code/hal-app/src/lib.rs @@ -18,3 +18,5 @@ unsafe fn HardFault(_ef: &cortex_m_rt::ExceptionFrame) -> ! { fn defmt_panic() -> ! { dk::fail(); } + +defmt::timestamp!("{=u64:tus}", dk::uptime_us()); diff --git a/nrf52-code/radio-app/.cargo/config.toml b/nrf52-code/radio-app/.cargo/config.toml index 75a7d205..040c82ab 100644 --- a/nrf52-code/radio-app/.cargo/config.toml +++ b/nrf52-code/radio-app/.cargo/config.toml @@ -1,7 +1,17 @@ [target.thumbv7em-none-eabihf] # set custom cargo runner to flash & run on embedded target when we call `cargo run` # for more information, check out https://github.com/probe-rs -runner = "probe-rs run --chip nRF52840_xxAA --allow-erase-all" +runner = [ + "probe-rs", + "run", + "--chip", + "nRF52840_xxAA", + "--allow-erase-all", + "--log-format", + "{[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" +] +# Or use "{t} {[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" to enable timestamps + rustflags = [ "-C", "link-arg=-Tlink.x", # use the cortex-m-rt linker script "-C", "linker=flip-link", # adds stack overflow protection diff --git a/nrf52-code/radio-app/src/lib.rs b/nrf52-code/radio-app/src/lib.rs index f104b329..2907e773 100644 --- a/nrf52-code/radio-app/src/lib.rs +++ b/nrf52-code/radio-app/src/lib.rs @@ -18,3 +18,5 @@ unsafe fn HardFault(_ef: &cortex_m_rt::ExceptionFrame) -> ! { fn defmt_panic() -> ! { dk::fail(); } + +defmt::timestamp!("{=u64:tus}", dk::uptime_us()); diff --git a/nrf52-code/usb-app-solutions/.cargo/config.toml b/nrf52-code/usb-app-solutions/.cargo/config.toml index 75a7d205..040c82ab 100644 --- a/nrf52-code/usb-app-solutions/.cargo/config.toml +++ b/nrf52-code/usb-app-solutions/.cargo/config.toml @@ -1,7 +1,17 @@ [target.thumbv7em-none-eabihf] # set custom cargo runner to flash & run on embedded target when we call `cargo run` # for more information, check out https://github.com/probe-rs -runner = "probe-rs run --chip nRF52840_xxAA --allow-erase-all" +runner = [ + "probe-rs", + "run", + "--chip", + "nRF52840_xxAA", + "--allow-erase-all", + "--log-format", + "{[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" +] +# Or use "{t} {[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" to enable timestamps + rustflags = [ "-C", "link-arg=-Tlink.x", # use the cortex-m-rt linker script "-C", "linker=flip-link", # adds stack overflow protection diff --git a/nrf52-code/usb-app-solutions/src/lib.rs b/nrf52-code/usb-app-solutions/src/lib.rs index f104b329..2907e773 100644 --- a/nrf52-code/usb-app-solutions/src/lib.rs +++ b/nrf52-code/usb-app-solutions/src/lib.rs @@ -18,3 +18,5 @@ unsafe fn HardFault(_ef: &cortex_m_rt::ExceptionFrame) -> ! { fn defmt_panic() -> ! { dk::fail(); } + +defmt::timestamp!("{=u64:tus}", dk::uptime_us()); diff --git a/nrf52-code/usb-app/.cargo/config.toml b/nrf52-code/usb-app/.cargo/config.toml index 50b16995..dd62079b 100644 --- a/nrf52-code/usb-app/.cargo/config.toml +++ b/nrf52-code/usb-app/.cargo/config.toml @@ -1,7 +1,17 @@ [target.thumbv7em-none-eabihf] # set custom cargo runner to flash & run on embedded target when we call `cargo run` # for more information, check out https://github.com/probe-rs -runner = "probe-rs run --chip nRF52840_xxAA --allow-erase-all" +runner = [ + "probe-rs", + "run", + "--chip", + "nRF52840_xxAA", + "--allow-erase-all", + "--log-format", + "{[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" +] +# Or use "{t} {[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" to enable timestamps + linker = "flip-link" # adds stack overflow protection rustflags = [ "-C", "link-arg=-Tlink.x", # use the cortex-m-rt linker script diff --git a/nrf52-code/usb-app/src/lib.rs b/nrf52-code/usb-app/src/lib.rs index f104b329..2907e773 100644 --- a/nrf52-code/usb-app/src/lib.rs +++ b/nrf52-code/usb-app/src/lib.rs @@ -18,3 +18,5 @@ unsafe fn HardFault(_ef: &cortex_m_rt::ExceptionFrame) -> ! { fn defmt_panic() -> ! { dk::fail(); } + +defmt::timestamp!("{=u64:tus}", dk::uptime_us()); From 6543e23b5cce4c481d278dd61dc6c79ee7bcfa17 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Tue, 10 Dec 2024 14:56:07 +0000 Subject: [PATCH 03/10] Better timestamp output. --- nrf52-code/hal-app/src/bin/blinky.rs | 2 +- nrf52-code/radio-app/src/bin/blinky.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nrf52-code/hal-app/src/bin/blinky.rs b/nrf52-code/hal-app/src/bin/blinky.rs index fb44471a..483cf388 100644 --- a/nrf52-code/hal-app/src/bin/blinky.rs +++ b/nrf52-code/hal-app/src/bin/blinky.rs @@ -19,7 +19,7 @@ fn main() -> ! { for _ in 0..10 { led.toggle(); timer.wait(Duration::from_secs(1)); - defmt::println!("LED toggled at {:?}", dk::uptime()); + defmt::println!("LED toggled @ {=u64:tus}", dk::uptime_us()); } dk::exit() diff --git a/nrf52-code/radio-app/src/bin/blinky.rs b/nrf52-code/radio-app/src/bin/blinky.rs index 76b920ad..5bb29659 100644 --- a/nrf52-code/radio-app/src/bin/blinky.rs +++ b/nrf52-code/radio-app/src/bin/blinky.rs @@ -19,7 +19,7 @@ fn main() -> ! { for _ in 0..10 { led.toggle(); timer.wait(Duration::from_secs(1)); - defmt::println!("LED toggled at {:?}", dk::uptime()); + defmt::println!("LED toggled @ {=u64:tus}", dk::uptime_us()); } dk::exit() From 016f19d2b740c0baf1809272da4c05df8363f249 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Tue, 10 Dec 2024 17:02:27 +0000 Subject: [PATCH 04/10] Use log levels in the nRF52 Workshops. Also regenerated the trace files. --- .../nrf52-usb-getting-device-configured.md | 91 +++++++------- exercise-book/src/nrf52-usb-idle-state.md | 94 +++++++------- nrf52-code/boards/dk-solution/src/usbd.rs | 6 +- nrf52-code/boards/dk/src/usbd.rs | 6 +- nrf52-code/hal-app/src/bin/blinky.rs | 2 +- nrf52-code/radio-app/src/bin/blinky.rs | 2 +- nrf52-code/usb-app-solutions/src/bin/usb-1.rs | 2 +- nrf52-code/usb-app-solutions/src/bin/usb-2.rs | 8 +- nrf52-code/usb-app-solutions/src/bin/usb-3.rs | 8 +- nrf52-code/usb-app-solutions/src/bin/usb-4.rs | 14 +-- nrf52-code/usb-app-solutions/src/bin/usb-5.rs | 16 +-- .../traces/linux-configured.txt | 94 +++++++------- .../traces/linux-enumeration.txt | 115 +++++++++++------- .../traces/macos-configured.txt | 72 ++++++----- .../traces/macos-enumeration.txt | 86 +++++++------ .../traces/win-configured.txt | 78 ++++++------ .../traces/win-enumeration.txt | 97 +++++++++++---- nrf52-code/usb-app/src/bin/usb-1.rs | 2 +- nrf52-code/usb-app/src/bin/usb-2.rs | 8 +- nrf52-code/usb-app/src/bin/usb-3.rs | 8 +- nrf52-code/usb-app/src/bin/usb-4.rs | 12 +- 21 files changed, 457 insertions(+), 364 deletions(-) diff --git a/exercise-book/src/nrf52-usb-getting-device-configured.md b/exercise-book/src/nrf52-usb-getting-device-configured.md index f9a0fa5d..c670e675 100644 --- a/exercise-book/src/nrf52-usb-getting-device-configured.md +++ b/exercise-book/src/nrf52-usb-getting-device-configured.md @@ -49,59 +49,58 @@ NOTE: On Windows, you may get a `GET_STATUS` request *before* the `SET_CONFIGURA ## Expected output -✅ Run the progam and check the log output. +✅ Run the program and check the log output. Once you are correctly handling the `SET_CONFIGURATION` request you should get logs like these: -```console -INFO:usb_5 -- USB: UsbReset @ 397.15576ms -INFO:usb_5 -- USB reset condition detected -INFO:usb_5 -- USB: UsbEp0Setup @ 470.00122ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: Device, length: 64 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_5 -- USB: UsbEp0DataDone @ 470.306395ms -INFO:usb_5 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5 -- USB: UsbReset @ 520.721433ms -INFO:usb_5 -- USB reset condition detected -INFO:usb_5 -- USB: UsbEp0Setup @ 593.292235ms -INFO:usb_5 -- EP0: SetAddress { address: Some(21) } -INFO:usb_5 -- USB: UsbEp0Setup @ 609.954832ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: Device, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_5 -- USB: UsbEp0DataDone @ 610.260008ms -INFO:usb_5 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5 -- USB: UsbEp0Setup @ 610.443113ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -WARN:usb_5 -- EP0IN: stalled -INFO:usb_5 -- USB: UsbEp0Setup @ 610.809325ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -WARN:usb_5 -- EP0IN: stalled -INFO:usb_5 -- USB: UsbEp0Setup @ 611.175535ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -WARN:usb_5 -- EP0IN: stalled -INFO:usb_5 -- USB: UsbEp0Setup @ 611.511228ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } -INFO:dk::usbd -- EP0IN: start 9B transfer -INFO:usb_5 -- USB: UsbEp0DataDone @ 611.846922ms -INFO:usb_5 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5 -- USB: UsbEp0Setup @ 612.030027ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_5 -- USB: UsbEp0DataDone @ 612.365721ms -INFO:usb_5 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5 -- USB: UsbEp0Setup @ 612.640378ms -INFO:usb_5 -- EP0: SetConfiguration { value: Some(42) } -INFO:usb_5 -- entering the configured state +```text +[DEBUG] Initializing the board (dk dk/src/lib.rs:312) +[DEBUG] Clocks configured (dk dk/src/lib.rs:330) +[DEBUG] RTC started (dk dk/src/lib.rs:349) +[DEBUG] I/O pins have been configured for digital output (dk dk/src/lib.rs:359) +[DEBUG] USB: UsbReset @ 00:00:00.324523 (usb_5 src/bin/usb-5.rs:56) +[WARN ] USB reset condition detected (usb_5 src/bin/usb-5.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.367462 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 5, wlength: 0, windex: 0x0000, wvalue: 0x000b (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: SetAddress { address: Some(11) } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.370758 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 8, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 8 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 8B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.371337 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.371917 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 18 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.372497 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.373046 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 9, windex: 0x0000, wvalue: 0x0200 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 9B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.373748 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.373901 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0200 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.374603 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.379211 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_5 src/bin/usb-5.rs:99) +[INFO ] entering the configured state (usb_5 src/bin/usb-5.rs:198) ``` These logs are from a Linux host. You can find traces for other OSes in these files (they are in the [`nrf52-code/usb-app-solutions/traces`](../../nrf52-code/usb-app-solutions/traces) folder): -- `linux-configured.txt` (same logs as the ones shown above) +- `linux-configured.txt` - `win-configured.txt`, this file only contains the logs produced by running `cargo xtask usb-descriptors` -- `macos-configured.txt` +- `macos-configured.txt` (same logs as the ones shown above) You can find a solution to this part of the exercise in [`nrf52-code/usb-app-solutions/src/bin/usb-5.rs`](../../nrf52-code/usb-app-solutions/src/bin/usb-5.rs). diff --git a/exercise-book/src/nrf52-usb-idle-state.md b/exercise-book/src/nrf52-usb-idle-state.md index 2b160edb..b1f75fd7 100644 --- a/exercise-book/src/nrf52-usb-idle-state.md +++ b/exercise-book/src/nrf52-usb-idle-state.md @@ -3,67 +3,61 @@ Once you have handled all the previously covered requests the device should be enumerated and remain idle awaiting for a new host request. Your logs may look like this: ```console -INFO:usb_4 -- USB: UsbReset @ 318.66455ms -INFO:usb_4 -- USB reset condition detected -INFO:usb_4 -- USB: UsbEp0Setup @ 391.418456ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: Device, length: 64 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_4 -- USB: UsbEp0DataDone @ 391.723632ms -INFO:usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4 -- USB: UsbReset @ 442.016601ms -INFO:usb_4 -- USB reset condition detected -INFO:usb_4 -- USB: UsbEp0Setup @ 514.709471ms -INFO:usb_4 -- EP0: SetAddress { address: Some(17) } -INFO:usb_4 -- USB: UsbEp0Setup @ 531.37207ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: Device, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_4 -- USB: UsbEp0DataDone @ 531.646727ms -INFO:usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4 -- USB: UsbEp0Setup @ 531.829832ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -ERROR:usb_4 -- EP0IN: unexpected request; stalling the endpoint -INFO:usb_4 -- USB: UsbEp0Setup @ 532.226562ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -ERROR:usb_4 -- EP0IN: unexpected request; stalling the endpoint -INFO:usb_4 -- USB: UsbEp0Setup @ 532.592772ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -ERROR:usb_4 -- EP0IN: unexpected request; stalling the endpoint -INFO:usb_4 -- USB: UsbEp0Setup @ 533.020018ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } -INFO:dk::usbd -- EP0IN: start 9B transfer -INFO:usb_4 -- USB: UsbEp0DataDone @ 533.386228ms -INFO:usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4 -- USB: UsbEp0Setup @ 533.569335ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_4 -- USB: UsbEp0DataDone @ 533.935546ms -INFO:usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4 -- USB: UsbEp0Setup @ 534.118651ms -INFO:usb_4 -- EP0: SetConfiguration { value: Some(42) } -ERROR:usb_4 -- EP0IN: unexpected request; stalling the endpoint +[DEBUG] USB: UsbReset @ 00:00:00.347259 (usb_4 src/bin/usb-4.rs:56) +[WARN ] USB reset condition detected (usb_4 src/bin/usb-4.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.389770 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 5, wlength: 0, windex: 0x0000, wvalue: 0x000a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetAddress { address: Some(10) } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.393066 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 8, windex: 0x0000, wvalue: 0x0100 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 8 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 8B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.393585 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.394409 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0100 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 18 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.394958 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.395385 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 9, windex: 0x0000, wvalue: 0x0200 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 9B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.396057 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.396270 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0200 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.396942 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.401824 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) ``` -Note that these logs are from a Linux host where a `SET_CONFIGURATION` request is sent after the `SET_ADDRESS` request. On other OSes you may not get that request before the bus goes idle. Also note that there are some `GET_DESCRIPTOR DeviceQualifier` requests in this case; you do not need to parse them in the `usb` crate as they'll be rejected (stalled) anyways. +Note that these logs are from a macOS host where a `SET_ADDRESS` request is sent first, and then a `GET_DESCRIPTOR` request. On other OSes the messages may be in a different order. Also note that there are some `GET_DESCRIPTOR DeviceQualifier` requests in this case; you do not need to parse them in the `usb` crate as they'll be rejected (stalled) anyways. You can find traces for other OSes in these files (they are in the [`nrf52-code/usb-app-solutions/traces`](../../nrf52-code/usb-app-solutions/traces) folder): -- `linux-enumeration.txt` (same logs as the ones shown above) -- `macos-enumeration.txt` +- `linux-enumeration.txt` +- `macos-enumeration.txt` (same logs as the ones shown above) - `win-enumeration.txt` -✅ Double check that the enumeration works by running [`cyme`](./nrf52-usb-listing-usb-devices.md) while `usb-4.rs` is running. +✅ Double check that the enumeration works by running `cargo xtask usb-list`](./nrf52-tools.md) while `usb-4.rs` is running. ```console -$ cyme +$ cargo xtask usb-list (...) random other USB devices will be listed - 2 15  0x1366 0x1051 J-Link 001050255503 12.0 Mb/s - 2 16  0x1209 0x0717 composite_device - 12.0 Mb/s +Bus 004 Device 001: ID 1209:0717 <-- nRF52840 on the nRF52840 Development Kit ``` -Both the J-Link and the device implemented by your firmware should appear in the list. +You can also try `cyme`, but we've found that on Windows, the device may not appear in the tool's output. Possibly this is because it's only showing devices which have accepted a Configuration. You can find a working solution up to this point in [`nrf52-code/usb-app-solutions/src/bin/usb-4.rs`](../../nrf52-code/usb-app-solutions/src/bin/usb-4.rs). Note that the solution uses the `usb2` crate to parse SETUP packets and that crate supports parsing all standard requests. diff --git a/nrf52-code/boards/dk-solution/src/usbd.rs b/nrf52-code/boards/dk-solution/src/usbd.rs index 41dd4ea4..603ba93b 100644 --- a/nrf52-code/boards/dk-solution/src/usbd.rs +++ b/nrf52-code/boards/dk-solution/src/usbd.rs @@ -56,7 +56,7 @@ impl Ep0In { self.busy = true; - defmt::println!("EP0IN: start {}B transfer", n); + defmt::debug!("EP0IN: start {}B transfer", n); // start DMA transfer dma_start(); @@ -80,7 +80,7 @@ impl Ep0In { usbd.events_ep0datadone.reset(); self.busy = false; - defmt::println!("EP0IN: transfer done"); + defmt::info!("EP0IN: transfer done"); } } } @@ -115,7 +115,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::println!("waiting for USB connection on port J3"); + defmt::info!("waiting for USB connection on port J3"); once = false; } diff --git a/nrf52-code/boards/dk/src/usbd.rs b/nrf52-code/boards/dk/src/usbd.rs index 41dd4ea4..603ba93b 100644 --- a/nrf52-code/boards/dk/src/usbd.rs +++ b/nrf52-code/boards/dk/src/usbd.rs @@ -56,7 +56,7 @@ impl Ep0In { self.busy = true; - defmt::println!("EP0IN: start {}B transfer", n); + defmt::debug!("EP0IN: start {}B transfer", n); // start DMA transfer dma_start(); @@ -80,7 +80,7 @@ impl Ep0In { usbd.events_ep0datadone.reset(); self.busy = false; - defmt::println!("EP0IN: transfer done"); + defmt::info!("EP0IN: transfer done"); } } } @@ -115,7 +115,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::println!("waiting for USB connection on port J3"); + defmt::info!("waiting for USB connection on port J3"); once = false; } diff --git a/nrf52-code/hal-app/src/bin/blinky.rs b/nrf52-code/hal-app/src/bin/blinky.rs index 483cf388..6153f2f7 100644 --- a/nrf52-code/hal-app/src/bin/blinky.rs +++ b/nrf52-code/hal-app/src/bin/blinky.rs @@ -19,7 +19,7 @@ fn main() -> ! { for _ in 0..10 { led.toggle(); timer.wait(Duration::from_secs(1)); - defmt::println!("LED toggled @ {=u64:tus}", dk::uptime_us()); + defmt::debug!("LED toggled @ {=u64:tus}", dk::uptime_us()); } dk::exit() diff --git a/nrf52-code/radio-app/src/bin/blinky.rs b/nrf52-code/radio-app/src/bin/blinky.rs index 5bb29659..3a1f6bec 100644 --- a/nrf52-code/radio-app/src/bin/blinky.rs +++ b/nrf52-code/radio-app/src/bin/blinky.rs @@ -19,7 +19,7 @@ fn main() -> ! { for _ in 0..10 { led.toggle(); timer.wait(Duration::from_secs(1)); - defmt::println!("LED toggled @ {=u64:tus}", dk::uptime_us()); + defmt::debug!("LED toggled @ {=u64:tus}", dk::uptime_us()); } dk::exit() diff --git a/nrf52-code/usb-app-solutions/src/bin/usb-1.rs b/nrf52-code/usb-app-solutions/src/bin/usb-1.rs index dbae90dd..d2702075 100644 --- a/nrf52-code/usb-app-solutions/src/bin/usb-1.rs +++ b/nrf52-code/usb-app-solutions/src/bin/usb-1.rs @@ -42,7 +42,7 @@ mod app { } fn on_event(_usbd: &USBD, event: Event) { - defmt::println!("USB: {} @ {}", event, dk::uptime()); + defmt::debug!("USB: {} @ {=u64:tus}", event, dk::uptime_us()); match event { Event::UsbReset => { diff --git a/nrf52-code/usb-app-solutions/src/bin/usb-2.rs b/nrf52-code/usb-app-solutions/src/bin/usb-2.rs index 58fab8ed..f64ceaab 100644 --- a/nrf52-code/usb-app-solutions/src/bin/usb-2.rs +++ b/nrf52-code/usb-app-solutions/src/bin/usb-2.rs @@ -40,7 +40,7 @@ mod app { } fn on_event(usbd: &USBD, event: Event) { - defmt::println!("USB: {} @ {}", event, dk::uptime()); + defmt::debug!("USB: {} @ {=u64:tus}", event, dk::uptime_us()); match event { Event::UsbReset => { @@ -75,8 +75,8 @@ mod app { // let windex = usbd::windex(usbd); // let wvalue = usbd::wvalue(usbd); - defmt::println!( - "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + defmt::debug!( + "SETUP: bmrequesttype: 0b{=u8:08b}, brequest: {=u8}, wlength: {=u16}, windex: 0x{=u16:04x}, wvalue: 0x{=u16:04x}", bmrequesttype, brequest, wlength, @@ -90,7 +90,7 @@ mod app { Request::GetDescriptor { descriptor, length } if descriptor == Descriptor::Device => { - defmt::println!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); defmt::println!("Goal reached; move to the next section"); dk::exit() diff --git a/nrf52-code/usb-app-solutions/src/bin/usb-3.rs b/nrf52-code/usb-app-solutions/src/bin/usb-3.rs index 1f566675..08cc7965 100644 --- a/nrf52-code/usb-app-solutions/src/bin/usb-3.rs +++ b/nrf52-code/usb-app-solutions/src/bin/usb-3.rs @@ -47,7 +47,7 @@ mod app { } fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { - defmt::println!("USB: {} @ {}", event, dk::uptime()); + defmt::debug!("USB: {} @ {=u64:tus}", event, dk::uptime_us()); match event { Event::UsbReset => { @@ -63,8 +63,8 @@ mod app { let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - defmt::println!( - "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + defmt::debug!( + "SETUP: bmrequesttype: 0b{=u8:08b}, brequest: {=u8}, wlength: {=u16}, windex: 0x{=u16:04x}, wvalue: 0x{=u16:04x}", bmrequesttype, brequest, wlength, @@ -79,7 +79,7 @@ mod app { Request::GetDescriptor { descriptor, length } if descriptor == Descriptor::Device => { - defmt::println!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); let desc = usb2::device::Descriptor { bDeviceClass: 0, diff --git a/nrf52-code/usb-app-solutions/src/bin/usb-4.rs b/nrf52-code/usb-app-solutions/src/bin/usb-4.rs index 24d25f88..c7211bf2 100644 --- a/nrf52-code/usb-app-solutions/src/bin/usb-4.rs +++ b/nrf52-code/usb-app-solutions/src/bin/usb-4.rs @@ -53,16 +53,16 @@ mod app { } fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - defmt::println!("USB: {} @ {}", event, dk::uptime()); + defmt::debug!("USB: {} @ {=u64:tus}", event, dk::uptime_us()); match event { Event::UsbReset => { - defmt::println!("USB reset condition detected"); + defmt::warn!("USB reset condition detected"); *state = State::Default; } Event::UsbEp0DataDone => { - defmt::println!("EP0IN: transfer complete"); + defmt::info!("EP0IN: transfer complete"); ep0in.end(usbd); } @@ -85,8 +85,8 @@ mod app { let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - defmt::println!( - "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + defmt::debug!( + "SETUP: bmrequesttype: 0b{=u8:08b}, brequest: {=u8}, wlength: {=u16}, windex: 0x{=u16:04x}, wvalue: 0x{=u16:04x}", bmrequesttype, brequest, wlength, @@ -96,9 +96,9 @@ mod app { let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); - defmt::println!("EP0: {}", defmt::Debug2Format(&request)); + defmt::info!("EP0: {}", defmt::Debug2Format(&request)); // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log - // `StandardRequest` with `defmt` + // `Request` with `defmt` match request { // section 9.4.3 // this request is valid in any state diff --git a/nrf52-code/usb-app-solutions/src/bin/usb-5.rs b/nrf52-code/usb-app-solutions/src/bin/usb-5.rs index 888b300d..cee1b2b3 100644 --- a/nrf52-code/usb-app-solutions/src/bin/usb-5.rs +++ b/nrf52-code/usb-app-solutions/src/bin/usb-5.rs @@ -53,16 +53,16 @@ mod app { } fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - defmt::println!("USB: {} @ {}", event, dk::uptime()); + defmt::debug!("USB: {} @ {=u64:tus}", event, dk::uptime_us()); match event { Event::UsbReset => { - defmt::println!("USB reset condition detected"); + defmt::warn!("USB reset condition detected"); *state = State::Default; } Event::UsbEp0DataDone => { - defmt::println!("EP0IN: transfer complete"); + defmt::info!("EP0IN: transfer complete"); ep0in.end(usbd); } @@ -85,8 +85,8 @@ mod app { let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - defmt::println!( - "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + defmt::debug!( + "SETUP: bmrequesttype: 0b{=u8:08b}, brequest: {=u8}, wlength: {=u16}, windex: 0x{=u16:04x}, wvalue: 0x{=u16:04x}", bmrequesttype, brequest, wlength, @@ -96,9 +96,9 @@ mod app { let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); - defmt::println!("EP0: {}", defmt::Debug2Format(&request)); + defmt::info!("EP0: {}", defmt::Debug2Format(&request)); // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log - // `StandardRequest` with `defmt` + // `Request` with `defmt` match request { // section 9.4.3 @@ -195,7 +195,7 @@ mod app { State::Address(address) => { if let Some(value) = value { if value.get() == CONFIG_VAL { - defmt::println!("entering the configured state"); + defmt::info!("entering the configured state"); *state = State::Configured { address, value }; } else { defmt::error!("unsupported configuration value"); diff --git a/nrf52-code/usb-app-solutions/traces/linux-configured.txt b/nrf52-code/usb-app-solutions/traces/linux-configured.txt index 2eaaba35..fe37e763 100644 --- a/nrf52-code/usb-app-solutions/traces/linux-configured.txt +++ b/nrf52-code/usb-app-solutions/traces/linux-configured.txt @@ -1,42 +1,52 @@ -INFO:usb_5 -- USB: UsbReset @ 397.15576ms -INFO:usb_5 -- USB reset condition detected -INFO:usb_5 -- USB: UsbEp0Setup @ 470.00122ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: Device, length: 64 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_5 -- USB: UsbEp0DataDone @ 470.306395ms -INFO:usb_5 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5 -- USB: UsbReset @ 520.721433ms -INFO:usb_5 -- USB reset condition detected -INFO:usb_5 -- USB: UsbEp0Setup @ 593.292235ms -INFO:usb_5 -- EP0: SetAddress { address: Some(21) } -INFO:usb_5 -- USB: UsbEp0Setup @ 609.954832ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: Device, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_5 -- USB: UsbEp0DataDone @ 610.260008ms -INFO:usb_5 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5 -- USB: UsbEp0Setup @ 610.443113ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -WARN:usb_5 -- EP0IN: stalled -INFO:usb_5 -- USB: UsbEp0Setup @ 610.809325ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -WARN:usb_5 -- EP0IN: stalled -INFO:usb_5 -- USB: UsbEp0Setup @ 611.175535ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -WARN:usb_5 -- EP0IN: stalled -INFO:usb_5 -- USB: UsbEp0Setup @ 611.511228ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } -INFO:dk::usbd -- EP0IN: start 9B transfer -INFO:usb_5 -- USB: UsbEp0DataDone @ 611.846922ms -INFO:usb_5 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5 -- USB: UsbEp0Setup @ 612.030027ms -INFO:usb_5 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_5 -- USB: UsbEp0DataDone @ 612.365721ms -INFO:usb_5 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5 -- USB: UsbEp0Setup @ 612.640378ms -INFO:usb_5 -- EP0: SetConfiguration { value: Some(42) } -INFO:usb_5 -- entering the configured state +[DEBUG] Initializing the board (dk dk/src/lib.rs:312) +[DEBUG] Clocks configured (dk dk/src/lib.rs:330) +[DEBUG] RTC started (dk dk/src/lib.rs:349) +[DEBUG] I/O pins have been configured for digital output (dk dk/src/lib.rs:359) +[DEBUG] USB: UsbReset @ 00:00:00.196411 (usb_5 src/bin/usb-5.rs:56) +[WARN ] USB reset condition detected (usb_5 src/bin/usb-5.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.239105 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 5, wlength: 0, windex: 0x0000, wvalue: 0x000b (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: SetAddress { address: Some(11) } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.242248 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 8, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 8 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 8B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.242797 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.243377 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.243927 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.244232 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 9, windex: 0x0000, wvalue: 0x0200 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 9B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.244903 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.245056 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0200 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.245819 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.253479 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_5 src/bin/usb-5.rs:99) +[INFO ] entering the configured state (usb_5 src/bin/usb-5.rs:198) +[DEBUG] USB: UsbEp0Setup @ 00:00:04.825073 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 10, windex: 0x0000, wvalue: 0x0600 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } (usb_5 src/bin/usb-5.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_5 src/bin/usb-5.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:04.827301 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 10, windex: 0x0000, wvalue: 0x0600 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } (usb_5 src/bin/usb-5.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_5 src/bin/usb-5.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:04.828948 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 10, windex: 0x0000, wvalue: 0x0600 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } (usb_5 src/bin/usb-5.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_5 src/bin/usb-5.rs:71) diff --git a/nrf52-code/usb-app-solutions/traces/linux-enumeration.txt b/nrf52-code/usb-app-solutions/traces/linux-enumeration.txt index 89c900c3..63dd68b1 100644 --- a/nrf52-code/usb-app-solutions/traces/linux-enumeration.txt +++ b/nrf52-code/usb-app-solutions/traces/linux-enumeration.txt @@ -1,42 +1,73 @@ -INFO:usb_4 -- USB: UsbReset @ 318.66455ms -INFO:usb_4 -- USB reset condition detected -INFO:usb_4 -- USB: UsbEp0Setup @ 391.418456ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: Device, length: 64 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_4 -- USB: UsbEp0DataDone @ 391.723632ms -INFO:usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4 -- USB: UsbReset @ 442.016601ms -INFO:usb_4 -- USB reset condition detected -INFO:usb_4 -- USB: UsbEp0Setup @ 514.709471ms -INFO:usb_4 -- EP0: SetAddress { address: Some(17) } -INFO:usb_4 -- USB: UsbEp0Setup @ 531.37207ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: Device, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_4 -- USB: UsbEp0DataDone @ 531.646727ms -INFO:usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4 -- USB: UsbEp0Setup @ 531.829832ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -ERROR:usb_4 -- EP0IN: unexpected request; stalling the endpoint -INFO:usb_4 -- USB: UsbEp0Setup @ 532.226562ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -ERROR:usb_4 -- EP0IN: unexpected request; stalling the endpoint -INFO:usb_4 -- USB: UsbEp0Setup @ 532.592772ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -ERROR:usb_4 -- EP0IN: unexpected request; stalling the endpoint -INFO:usb_4 -- USB: UsbEp0Setup @ 533.020018ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } -INFO:dk::usbd -- EP0IN: start 9B transfer -INFO:usb_4 -- USB: UsbEp0DataDone @ 533.386228ms -INFO:usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4 -- USB: UsbEp0Setup @ 533.569335ms -INFO:usb_4 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_4 -- USB: UsbEp0DataDone @ 533.935546ms -INFO:usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4 -- USB: UsbEp0Setup @ 534.118651ms -INFO:usb_4 -- EP0: SetConfiguration { value: Some(42) } -ERROR:usb_4 -- EP0IN: unexpected request; stalling the endpoint +[DEBUG] Initializing the board (dk dk/src/lib.rs:312) +[DEBUG] Clocks configured (dk dk/src/lib.rs:330) +[DEBUG] RTC started (dk dk/src/lib.rs:349) +[DEBUG] I/O pins have been configured for digital output (dk dk/src/lib.rs:359) +[DEBUG] USB: UsbReset @ 00:00:00.148071 (usb_4 src/bin/usb-4.rs:56) +[WARN ] USB reset condition detected (usb_4 src/bin/usb-4.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.190612 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 5, wlength: 0, windex: 0x0000, wvalue: 0x000b (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetAddress { address: Some(11) } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.193878 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 8, windex: 0x0000, wvalue: 0x0100 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 8 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 8B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.194427 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.194976 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0100 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 18 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.195617 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.195861 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 9, windex: 0x0000, wvalue: 0x0200 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 9B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.196533 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.196777 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0200 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.197448 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.201904 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.304077 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.406646 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:04.554229 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 10, windex: 0x0000, wvalue: 0x0600 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:04.557098 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 10, windex: 0x0000, wvalue: 0x0600 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:04.558868 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 10, windex: 0x0000, wvalue: 0x0600 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:04.561523 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:04.664123 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:04.767517 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) diff --git a/nrf52-code/usb-app-solutions/traces/macos-configured.txt b/nrf52-code/usb-app-solutions/traces/macos-configured.txt index d30ff2c5..4f11bb66 100644 --- a/nrf52-code/usb-app-solutions/traces/macos-configured.txt +++ b/nrf52-code/usb-app-solutions/traces/macos-configured.txt @@ -1,31 +1,41 @@ -INFO:usb_5_solution -- USB: UsbReset @ 101.104735ms -INFO:usb_5_solution -- USB reset condition detected -INFO:usb_5_solution -- USB: UsbEp0Setup @ 166.68701ms -INFO:usb_5_solution -- EP0: SetAddress { address: Some(21) } -INFO:usb_5_solution -- USB: UsbEp0Setup @ 168.853758ms -INFO:usb_5_solution -- EP0: GetDescriptor { descriptor: Device, length: 8 } -INFO:dk::usbd -- EP0IN: start 8B transfer -INFO:usb_5_solution -- USB: UsbEp0DataDone @ 169.128416ms -INFO:usb_5_solution -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5_solution -- USB: UsbEp0Setup @ 169.372557ms -INFO:usb_5_solution -- EP0: GetDescriptor { descriptor: Device, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_5_solution -- USB: UsbEp0DataDone @ 169.677733ms -INFO:usb_5_solution -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5_solution -- USB: UsbEp0Setup @ 172.180175ms -INFO:usb_5_solution -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } -INFO:dk::usbd -- EP0IN: start 9B transfer -INFO:usb_5_solution -- USB: UsbEp0DataDone @ 172.515868ms -INFO:usb_5_solution -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5_solution -- USB: UsbEp0Setup @ 172.698972ms -INFO:usb_5_solution -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_5_solution -- USB: UsbEp0DataDone @ 173.00415ms -INFO:usb_5_solution -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_5_solution -- USB: UsbEp0Setup @ 237.945556ms -INFO:usb_5_solution -- EP0: SetConfiguration { value: Some(42) } -INFO:usb_5_solution -- entering the configured state +[DEBUG] Initializing the board (dk dk/src/lib.rs:312) +[DEBUG] Clocks configured (dk dk/src/lib.rs:330) +[DEBUG] RTC started (dk dk/src/lib.rs:349) +[DEBUG] I/O pins have been configured for digital output (dk dk/src/lib.rs:359) +[DEBUG] USB: UsbReset @ 00:00:00.324523 (usb_5 src/bin/usb-5.rs:56) +[WARN ] USB reset condition detected (usb_5 src/bin/usb-5.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.367462 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 5, wlength: 0, windex: 0x0000, wvalue: 0x000b (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: SetAddress { address: Some(11) } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.370758 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 8, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 8 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 8B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.371337 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.371917 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 18 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.372497 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.373046 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 9, windex: 0x0000, wvalue: 0x0200 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 9B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.373748 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.373901 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0200 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.374603 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.379211 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_5 src/bin/usb-5.rs:99) +[INFO ] entering the configured state (usb_5 src/bin/usb-5.rs:198) diff --git a/nrf52-code/usb-app-solutions/traces/macos-enumeration.txt b/nrf52-code/usb-app-solutions/traces/macos-enumeration.txt index 9a4945fa..35b5735e 100644 --- a/nrf52-code/usb-app-solutions/traces/macos-enumeration.txt +++ b/nrf52-code/usb-app-solutions/traces/macos-enumeration.txt @@ -1,37 +1,49 @@ -INFO:usb_4_solution -- USB: UsbReset @ 101.135252ms -INFO:usb_4_solution -- USB reset condition detected -INFO:usb_4_solution -- USB: UsbEp0Setup @ 166.625976ms -INFO:usb_4_solution -- EP0: SetAddress { address: Some(20) } -INFO:usb_4_solution -- USB: UsbEp0Setup @ 168.823241ms -INFO:usb_4_solution -- EP0: GetDescriptor { descriptor: Device, length: 8 } -INFO:dk::usbd -- EP0IN: start 8B transfer -INFO:usb_4_solution -- USB: UsbEp0DataDone @ 169.0979ms -INFO:usb_4_solution -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4_solution -- USB: UsbEp0Setup @ 169.34204ms -INFO:usb_4_solution -- EP0: GetDescriptor { descriptor: Device, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_4_solution -- USB: UsbEp0DataDone @ 169.616697ms -INFO:usb_4_solution -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4_solution -- USB: UsbEp0Setup @ 171.905516ms -INFO:usb_4_solution -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } -INFO:dk::usbd -- EP0IN: start 9B transfer -INFO:usb_4_solution -- USB: UsbEp0DataDone @ 172.210691ms -INFO:usb_4_solution -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4_solution -- USB: UsbEp0Setup @ 172.393797ms -INFO:usb_4_solution -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:usb_4_solution -- USB: UsbEp0DataDone @ 172.729491ms -INFO:usb_4_solution -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:usb_4_solution -- USB: UsbEp0Setup @ 237.640378ms -INFO:usb_4_solution -- EP0: SetConfiguration { value: Some(42) } -WARN:usb_4_solution -- EP0IN: unexpected request; stalling the endpoint -INFO:usb_4_solution -- USB: UsbEp0Setup @ 338.012695ms -INFO:usb_4_solution -- EP0: SetConfiguration { value: Some(42) } -WARN:usb_4_solution -- EP0IN: unexpected request; stalling the endpoint -INFO:usb_4_solution -- USB: UsbEp0Setup @ 438.385008ms -INFO:usb_4_solution -- EP0: SetConfiguration { value: Some(42) } -WARN:usb_4_solution -- EP0IN: unexpected request; stalling the endpoint +[DEBUG] Initializing the board (dk dk/src/lib.rs:312) +[DEBUG] Clocks configured (dk dk/src/lib.rs:330) +[DEBUG] RTC started (dk dk/src/lib.rs:349) +[DEBUG] I/O pins have been configured for digital output (dk dk/src/lib.rs:359) +[DEBUG] USB: UsbReset @ 00:00:00.347259 (usb_4 src/bin/usb-4.rs:56) +[WARN ] USB reset condition detected (usb_4 src/bin/usb-4.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.389770 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 5, wlength: 0, windex: 0x0000, wvalue: 0x000a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetAddress { address: Some(10) } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.393066 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 8, windex: 0x0000, wvalue: 0x0100 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 8 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 8B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.393585 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.394409 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0100 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 18 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.394958 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.395385 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 9, windex: 0x0000, wvalue: 0x0200 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 9B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.396057 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.396270 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0200 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.396942 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.401824 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.505432 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.608215 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 9, wlength: 0, windex: 0x0000, wvalue: 0x002a (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetConfiguration { value: Some(42) } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) diff --git a/nrf52-code/usb-app-solutions/traces/win-configured.txt b/nrf52-code/usb-app-solutions/traces/win-configured.txt index 31358b33..0a033944 100644 --- a/nrf52-code/usb-app-solutions/traces/win-configured.txt +++ b/nrf52-code/usb-app-solutions/traces/win-configured.txt @@ -1,42 +1,36 @@ -INFO:rtic_usb_4 -- USB: UsbReset @ 305.594085691s -INFO:rtic_usb_4 -- USB reset condition detected -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 305.681701658s -INFO:rtic_usb_4 -- EP0: GetDescriptor { descriptor: Device, length: 64 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:rtic_usb_4 -- USB: UsbEp0DataDone @ 305.682037352s -INFO:rtic_usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:rtic_usb_4 -- USB: UsbReset @ 305.682220457s -INFO:rtic_usb_4 -- USB reset condition detected -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 305.769470213s -INFO:rtic_usb_4 -- EP0: SetAddress { address: Some(7) } -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 305.780456541s -INFO:rtic_usb_4 -- EP0: GetDescriptor { descriptor: Device, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:rtic_usb_4 -- USB: UsbEp0DataDone @ 305.780761718s -INFO:rtic_usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 305.784606932s -INFO:rtic_usb_4 -- EP0: GetDescriptor { descriptor: Device, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:rtic_usb_4 -- USB: UsbEp0DataDone @ 305.784912108s -INFO:rtic_usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 305.785095213s -INFO:rtic_usb_4 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 9 } -INFO:dk::usbd -- EP0IN: start 9B transfer -INFO:rtic_usb_4 -- USB: UsbEp0DataDone @ 305.78540039s -INFO:rtic_usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 305.785583495s -INFO:rtic_usb_4 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:rtic_usb_4 -- USB: UsbEp0DataDone @ 305.785919188s -INFO:rtic_usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 305.786102293s -INFO:rtic_usb_4 -- EP0: GetStatus(Device) -WARN:rtic_usb_4 -- EP0IN: stalled -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 305.786621093s -INFO:rtic_usb_4 -- EP0: SetConfiguration { value: Some(42) } -INFO:rtic_usb_4 -- entering the configured stat +[DEBUG] Initializing the board (dk dk/src/lib.rs:312) +[DEBUG] Clocks configured (dk dk/src/lib.rs:330) +[DEBUG] RTC started (dk dk/src/lib.rs:349) +[DEBUG] I/O pins have been configured for digital output (dk dk/src/lib.rs:359) +[DEBUG] USB: UsbReset @ 00:00:00.101654 (usb_4 src/bin/usb-4.rs:56) +[WARN ] USB reset condition detected (usb_4 src/bin/usb-4.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.184112 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 64, windex: 0x0000, wvalue: 0x0100 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 64 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.185272 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbReset @ 00:00:00.186340 (usb_4 src/bin/usb-4.rs:56) +[WARN ] USB reset condition detected (usb_4 src/bin/usb-4.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.268707 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 5, wlength: 0, windex: 0x0000, wvalue: 0x0002 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: SetAddress { address: Some(2) } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.279815 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0100 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 18 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.281250 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.291351 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 255, windex: 0x0000, wvalue: 0x0200 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 255 } (usb_4 src/bin/usb-4.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.292266 (usb_4 src/bin/usb-4.rs:56) +[INFO ] EP0IN: transfer complete (usb_4 src/bin/usb-4.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.294281 (usb_4 src/bin/usb-4.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 10, windex: 0x0000, wvalue: 0x0600 (usb_4 src/bin/usb-4.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } (usb_4 src/bin/usb-4.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_4 src/bin/usb-4.rs:71) diff --git a/nrf52-code/usb-app-solutions/traces/win-enumeration.txt b/nrf52-code/usb-app-solutions/traces/win-enumeration.txt index 9429763f..cea851ed 100644 --- a/nrf52-code/usb-app-solutions/traces/win-enumeration.txt +++ b/nrf52-code/usb-app-solutions/traces/win-enumeration.txt @@ -1,27 +1,70 @@ -INFO:rtic_usb_4 -- USB: UsbReset @ 101.837157ms -INFO:rtic_usb_4 -- USB reset condition detected -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 190.216063ms -INFO:rtic_usb_4 -- EP0: GetDescriptor { descriptor: Device, length: 64 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:rtic_usb_4 -- USB: UsbEp0DataDone @ 190.551757ms -INFO:rtic_usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:rtic_usb_4 -- USB: UsbReset @ 190.734862ms -INFO:rtic_usb_4 -- USB reset condition detected -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 277.954101ms -INFO:rtic_usb_4 -- EP0: SetAddress { address: Some(6) } -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 288.940428ms -INFO:rtic_usb_4 -- EP0: GetDescriptor { descriptor: Device, length: 18 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:rtic_usb_4 -- USB: UsbEp0DataDone @ 289.245603ms -INFO:rtic_usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 296.783446ms -INFO:rtic_usb_4 -- EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 255 } -INFO:dk::usbd -- EP0IN: start 18B transfer -INFO:rtic_usb_4 -- USB: UsbEp0DataDone @ 297.11914ms -INFO:rtic_usb_4 -- EP0IN: transfer complete -INFO:dk::usbd -- EP0IN: transfer done -INFO:rtic_usb_4 -- USB: UsbEp0Setup @ 297.302245ms -INFO:rtic_usb_4 -- EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } -WARN:rtic_usb_4 -- EP0IN: stalled +[DEBUG] Initializing the board (dk dk/src/lib.rs:312) +[DEBUG] Clocks configured (dk dk/src/lib.rs:330) +[DEBUG] RTC started (dk dk/src/lib.rs:349) +[DEBUG] I/O pins have been configured for digital output (dk dk/src/lib.rs:359) +[DEBUG] USB: UsbReset @ 00:00:00.102142 (usb_5 src/bin/usb-5.rs:56) +[WARN ] USB reset condition detected (usb_5 src/bin/usb-5.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.184967 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 64, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 64 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.185607 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbReset @ 00:00:00.186950 (usb_5 src/bin/usb-5.rs:56) +[WARN ] USB reset condition detected (usb_5 src/bin/usb-5.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.270324 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 5, wlength: 0, windex: 0x0000, wvalue: 0x0002 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: SetAddress { address: Some(2) } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.281280 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 18 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.282623 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.288482 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 255, windex: 0x0000, wvalue: 0x0200 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 255 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:00:00.289611 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:00:00.291625 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 10, windex: 0x0000, wvalue: 0x0600 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } (usb_5 src/bin/usb-5.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_5 src/bin/usb-5.rs:71) +[DEBUG] USB: UsbReset @ 00:02:16.382995 (usb_5 src/bin/usb-5.rs:56) +[WARN ] USB reset condition detected (usb_5 src/bin/usb-5.rs:60) +[DEBUG] USB: UsbReset @ 00:02:21.911010 (usb_5 src/bin/usb-5.rs:56) +[WARN ] USB reset condition detected (usb_5 src/bin/usb-5.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:02:21.993957 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 64, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 64 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:02:21.994781 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbReset @ 00:02:21.995849 (usb_5 src/bin/usb-5.rs:56) +[WARN ] USB reset condition detected (usb_5 src/bin/usb-5.rs:60) +[DEBUG] USB: UsbEp0Setup @ 00:02:22.078247 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b00000000, brequest: 5, wlength: 0, windex: 0x0000, wvalue: 0x0002 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: SetAddress { address: Some(2) } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] USB: UsbEp0Setup @ 00:02:22.089233 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 18, windex: 0x0000, wvalue: 0x0100 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Device, length: 18 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:02:22.090789 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:02:22.097961 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 255, windex: 0x0000, wvalue: 0x0200 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: Configuration { index: 0 }, length: 255 } (usb_5 src/bin/usb-5.rs:99) +[DEBUG] EP0IN: start 18B transfer (dk dk/src/usbd.rs:59) +[DEBUG] USB: UsbEp0DataDone @ 00:02:22.098785 (usb_5 src/bin/usb-5.rs:56) +[INFO ] EP0IN: transfer complete (usb_5 src/bin/usb-5.rs:65) +[INFO ] EP0IN: transfer done (dk dk/src/usbd.rs:83) +[DEBUG] USB: UsbEp0Setup @ 00:02:22.100769 (usb_5 src/bin/usb-5.rs:56) +[DEBUG] SETUP: bmrequesttype: 0b10000000, brequest: 6, wlength: 10, windex: 0x0000, wvalue: 0x0600 (usb_5 src/bin/usb-5.rs:88) +[INFO ] EP0: GetDescriptor { descriptor: DeviceQualifier, length: 10 } (usb_5 src/bin/usb-5.rs:99) +[WARN ] EP0IN: unexpected request; stalling the endpoint (usb_5 src/bin/usb-5.rs:71) diff --git a/nrf52-code/usb-app/src/bin/usb-1.rs b/nrf52-code/usb-app/src/bin/usb-1.rs index f44f506e..4595c191 100644 --- a/nrf52-code/usb-app/src/bin/usb-1.rs +++ b/nrf52-code/usb-app/src/bin/usb-1.rs @@ -42,7 +42,7 @@ mod app { } fn on_event(_usbd: &USBD, event: Event) { - defmt::println!("USB: {} @ {}", event, dk::uptime()); + defmt::debug!("USB: {} @ {=u64:tus}", event, dk::uptime_us()); match event { Event::UsbReset => todo!(), diff --git a/nrf52-code/usb-app/src/bin/usb-2.rs b/nrf52-code/usb-app/src/bin/usb-2.rs index 84fb0923..3cbdcb4b 100644 --- a/nrf52-code/usb-app/src/bin/usb-2.rs +++ b/nrf52-code/usb-app/src/bin/usb-2.rs @@ -40,7 +40,7 @@ mod app { } fn on_event(_usbd: &USBD, event: Event) { - defmt::println!("USB: {} @ {}", event, dk::uptime()); + defmt::debug!("USB: {} @ {=u64:tus}", event, dk::uptime_us()); match event { Event::UsbReset => { @@ -67,8 +67,8 @@ mod app { // composed of a high register (WVALUEH) and a low register (WVALUEL) let wvalue: u16 = 0; - defmt::println!( - "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + defmt::debug!( + "SETUP: bmrequesttype: 0b{=u8:08b}, brequest: {=u8}, wlength: {=u16}, windex: 0x{=u16:04x}, wvalue: 0x{=u16:04x}", bmrequesttype, brequest, wlength, @@ -85,7 +85,7 @@ mod app { // TODO modify `Request::parse()` in `nrf52-code/usb-lib/src/lib.rs` // so that this branch is reached - defmt::println!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); defmt::println!("Goal reached; move to the next section"); dk::exit() diff --git a/nrf52-code/usb-app/src/bin/usb-3.rs b/nrf52-code/usb-app/src/bin/usb-3.rs index 5721fd15..1e6c8114 100644 --- a/nrf52-code/usb-app/src/bin/usb-3.rs +++ b/nrf52-code/usb-app/src/bin/usb-3.rs @@ -47,7 +47,7 @@ mod app { } fn on_event(usbd: &USBD, ep0in: &mut Ep0In, event: Event) { - defmt::println!("USB: {} @ {}", event, dk::uptime()); + defmt::debug!("USB: {} @ {=u64:tus}", event, dk::uptime_us()); match event { Event::UsbReset => { @@ -63,8 +63,8 @@ mod app { let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - defmt::println!( - "SETUP: bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + defmt::debug!( + "SETUP: bmrequesttype: 0b{=u8:08b}, brequest: {=u8}, wlength: {=u16}, windex: 0x{=u16:04x}, wvalue: 0x{=u16:04x}", bmrequesttype, brequest, wlength, @@ -79,7 +79,7 @@ mod app { Request::GetDescriptor { descriptor, length } if descriptor == Descriptor::Device => { - defmt::println!("GET_DESCRIPTOR Device [length={}]", length); + defmt::info!("GET_DESCRIPTOR Device [length={}]", length); // TODO send back a valid device descriptor, truncated to `length` bytes // let desc = usb2::device::Descriptor { .. }; diff --git a/nrf52-code/usb-app/src/bin/usb-4.rs b/nrf52-code/usb-app/src/bin/usb-4.rs index 3b8d7878..1a412762 100644 --- a/nrf52-code/usb-app/src/bin/usb-4.rs +++ b/nrf52-code/usb-app/src/bin/usb-4.rs @@ -54,17 +54,17 @@ mod app { } fn on_event(usbd: &USBD, ep0in: &mut Ep0In, state: &mut State, event: Event) { - defmt::println!("USB: {} @ {}", event, dk::uptime()); + defmt::debug!("USB: {} @ {=u64:tus}", event, dk::uptime_us()); 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"); + defmt::warn!("USB reset condition detected"); todo!(); } Event::UsbEp0DataDone => { - defmt::println!("EP0IN: transfer complete"); + defmt::info!("EP0IN: transfer complete"); ep0in.end(usbd); } @@ -85,8 +85,8 @@ mod app { let windex = usbd::windex(usbd); let wvalue = usbd::wvalue(usbd); - defmt::println!( - "bmrequesttype: {}, brequest: {}, wlength: {}, windex: {}, wvalue: {}", + defmt::debug!( + "SETUP: bmrequesttype: 0b{=u8:08b}, brequest: {=u8}, wlength: {=u16}, windex: 0x{=u16:04x}, wvalue: 0x{=u16:04x}", bmrequesttype, brequest, wlength, @@ -96,7 +96,7 @@ mod app { let request = Request::parse(bmrequesttype, brequest, wvalue, windex, wlength) .expect("Error parsing request"); - defmt::println!("EP0: {}", defmt::Debug2Format(&request)); + defmt::info!("EP0: {}", defmt::Debug2Format(&request)); // ^^^^^^^^^^^^^^^^^^^ this adapter is currently needed to log // `StandardRequest` with `defmt` From ff4df13d57be354b217991bac06246395c0b9414 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Tue, 10 Dec 2024 18:02:45 +0000 Subject: [PATCH 05/10] Revert to latest stable Rust --- .github/workflows/build.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 604c3fa8..c4805e10 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,8 +19,6 @@ jobs: - name: Install targets run: | - rustup install 1.82 --profile=default - rustup default 1.82 rustup target add thumbv7em-none-eabihf rustup component add rust-src rustup component add rustfmt From 9d7a18a5c7ece211d734bedd61b702a99955ee54 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Wed, 11 Dec 2024 11:59:07 +0000 Subject: [PATCH 06/10] Starting on RTIC version of loopback-fw. Currently it operates a USB Serial port. --- build.sh | 5 + nrf52-code/boards/dk/Cargo.toml | 1 + nrf52-code/boards/dk/src/lib.rs | 28 +- .../loopback-fw-rtic/.cargo/config.toml | 23 + nrf52-code/loopback-fw-rtic/.gitignore | 1 + nrf52-code/loopback-fw-rtic/Cargo.lock | 665 ++++++++++++++++++ nrf52-code/loopback-fw-rtic/Cargo.toml | 16 + nrf52-code/loopback-fw-rtic/src/main.rs | 113 +++ 8 files changed, 847 insertions(+), 5 deletions(-) create mode 100644 nrf52-code/loopback-fw-rtic/.cargo/config.toml create mode 100644 nrf52-code/loopback-fw-rtic/.gitignore create mode 100644 nrf52-code/loopback-fw-rtic/Cargo.lock create mode 100644 nrf52-code/loopback-fw-rtic/Cargo.toml create mode 100644 nrf52-code/loopback-fw-rtic/src/main.rs diff --git a/build.sh b/build.sh index c675c148..66339e5e 100755 --- a/build.sh +++ b/build.sh @@ -72,6 +72,10 @@ pushd loopback-fw cargo build --target=thumbv7em-none-eabihf --release cargo fmt --check popd +pushd loopback-fw-rtic +cargo build --target=thumbv7em-none-eabihf --release +cargo fmt --check +popd popd # Only build the templates (they will panic at run-time due to the use of todo!) @@ -105,5 +109,6 @@ cp -r ./.cargo "${OUTPUT_NAME}/" cp -r ./tools "${OUTPUT_NAME}/" cp ./nrf52-code/puzzle-fw/target/thumbv7em-none-eabihf/release/puzzle-fw "${OUTPUT_NAME}/nrf52-code/boards/dongle-fw/puzzle-fw" cp ./nrf52-code/loopback-fw/target/thumbv7em-none-eabihf/release/loopback-fw "${OUTPUT_NAME}/nrf52-code/boards/dongle-fw/loopback-fw" +cp ./nrf52-code/loopback-fw-rtic/target/thumbv7em-none-eabihf/release/loopback-fw-rtic "${OUTPUT_NAME}/nrf52-code/boards/dongle-fw/loopback-fw-rtic" find "${OUTPUT_NAME}" -name target -type d -print0 | xargs -0 rm -rf zip -r "${OUTPUT_NAME}.zip" "${OUTPUT_NAME}" diff --git a/nrf52-code/boards/dk/Cargo.toml b/nrf52-code/boards/dk/Cargo.toml index 4fc4c4d1..e8d19e94 100644 --- a/nrf52-code/boards/dk/Cargo.toml +++ b/nrf52-code/boards/dk/Cargo.toml @@ -18,3 +18,4 @@ hal = { package = "nrf52840-hal", version = "0.18.0" } [features] advanced = [] radio = [] +usbd = [] diff --git a/nrf52-code/boards/dk/src/lib.rs b/nrf52-code/boards/dk/src/lib.rs index 88ac36c8..6c22505a 100644 --- a/nrf52-code/boards/dk/src/lib.rs +++ b/nrf52-code/boards/dk/src/lib.rs @@ -17,7 +17,7 @@ use cortex_m_semihosting::debug; use embedded_hal::digital::{OutputPin, StatefulOutputPin}; #[cfg(feature = "advanced")] use grounded::uninit::GroundedArrayCell; -#[cfg(feature = "radio")] +#[cfg(any(feature = "radio", feature = "usbd"))] use grounded::uninit::GroundedCell; #[cfg(feature = "radio")] pub use hal::ieee802154; @@ -44,14 +44,18 @@ pub mod peripheral; #[cfg(feature = "advanced")] pub mod usbd; -#[cfg(feature = "radio")] +#[cfg(any(feature = "radio", feature = "usbd"))] struct ClockSyncWrapper { clocks: Clocks, } -#[cfg(feature = "radio")] +#[cfg(any(feature = "radio", feature = "usbd"))] unsafe impl Sync for ClockSyncWrapper {} +/// Our USB Device +#[cfg(feature = "usbd")] +pub type UsbDevice = hal::usbd::Usbd>; + /// Components on the board pub struct Board { /// LEDs @@ -71,6 +75,9 @@ pub struct Board { /// USB control endpoint 0 #[cfg(feature = "advanced")] pub ep0in: Ep0In, + /// A configured USB Device + #[cfg(feature = "usbd")] + pub usbd: UsbDevice, } /// All LEDs on the board @@ -300,7 +307,7 @@ pub fn init() -> Result { // NOTE: this branch runs at most once #[cfg(feature = "advanced")] static EP0IN_BUF: GroundedArrayCell = GroundedArrayCell::const_init(); - #[cfg(feature = "radio")] + #[cfg(any(feature = "radio", feature = "usbd"))] // We need the wrapper to make this type Sync, as it contains raw pointers static CLOCKS: GroundedCell< ClockSyncWrapper< @@ -317,7 +324,7 @@ pub fn init() -> Result { let clocks = clocks.start_lfclk(); let _clocks = clocks.enable_ext_hfosc(); // extend lifetime to `'static` - #[cfg(feature = "radio")] + #[cfg(any(feature = "radio", feature = "usbd"))] let clocks = unsafe { let clocks_ptr = CLOCKS.get(); clocks_ptr.write(ClockSyncWrapper { clocks: _clocks }); @@ -370,6 +377,15 @@ pub fn init() -> Result { radio }; + #[cfg(feature = "usbd")] + { + defmt::debug!("Enabling SOF interrupts..."); + periph.USBD.inten.modify(|_r, w| { + w.sof().set_bit(); + w + }); + } + Ok(Board { leds: Leds { _1: Led { inner: led1pin }, @@ -386,6 +402,8 @@ pub fn init() -> Result { power: periph.POWER, #[cfg(feature = "advanced")] ep0in: unsafe { Ep0In::new(&EP0IN_BUF) }, + #[cfg(feature = "usbd")] + usbd: UsbDevice::new(hal::usbd::UsbPeripheral::new(periph.USBD, clocks)), }) } diff --git a/nrf52-code/loopback-fw-rtic/.cargo/config.toml b/nrf52-code/loopback-fw-rtic/.cargo/config.toml new file mode 100644 index 00000000..436cc4fb --- /dev/null +++ b/nrf52-code/loopback-fw-rtic/.cargo/config.toml @@ -0,0 +1,23 @@ +[target.thumbv7em-none-eabihf] +# set custom cargo runner to flash & run on embedded target when we call `cargo run` +# for more information, check out https://github.com/probe-rs +runner = [ + "probe-rs", + "run", + "--chip", + "nRF52840_xxAA", + "--allow-erase-all", + "--log-format", + "{t} {[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" +] +# Or use "{[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" to disable timestamps + +linker = "flip-link" # adds stack overflow protection +rustflags = [ + "-C", "link-arg=-Tlink.x", # use the cortex-m-rt linker script + "-C", "link-arg=-Tdefmt.x", # defmt support +] + +[build] +# cross-compile to this target +target = "thumbv7em-none-eabihf" # = ARM Cortex-M4 with FPU diff --git a/nrf52-code/loopback-fw-rtic/.gitignore b/nrf52-code/loopback-fw-rtic/.gitignore new file mode 100644 index 00000000..eb5a316c --- /dev/null +++ b/nrf52-code/loopback-fw-rtic/.gitignore @@ -0,0 +1 @@ +target diff --git a/nrf52-code/loopback-fw-rtic/Cargo.lock b/nrf52-code/loopback-fw-rtic/Cargo.lock new file mode 100644 index 00000000..881e4ec4 --- /dev/null +++ b/nrf52-code/loopback-fw-rtic/Cargo.lock @@ -0,0 +1,665 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytemuck" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "consts" +version = "0.1.0" + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal 0.2.5", + "bitfield", + "critical-section", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "cortex-m-semihosting" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" +dependencies = [ + "cortex-m", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "defmt" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f6162c53f659f65d00619fe31f14556a6e9f8752ccc4a41bd177ffcf3d6130" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d135dd939bad62d7490b0002602d35b358dce5fd9233a709d3c1ef467d4bde6" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3" +dependencies = [ + "thiserror", +] + +[[package]] +name = "defmt-rtt" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab697b3dbbc1750b7c8b821aa6f6e7f2480b47a99bc057a2ed7b170ebef0c51" +dependencies = [ + "critical-section", + "defmt", +] + +[[package]] +name = "dk" +version = "0.0.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "cortex-m-semihosting", + "defmt", + "defmt-rtt", + "embedded-hal 1.0.0", + "grounded", + "nrf52840-hal", +] + +[[package]] +name = "embedded-dma" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" +dependencies = [ + "stable_deref_trait", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + +[[package]] +name = "embedded-storage" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "fixed" +version = "1.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" +dependencies = [ + "az", + "bytemuck", + "half", + "typenum", +] + +[[package]] +name = "fugit" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" +dependencies = [ + "gcd", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + +[[package]] +name = "grounded" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917d82402c7eb9755fdd87d52117701dae9e413a6abb309fac2a13af693b6080" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + +[[package]] +name = "heapless" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "loopback-fw-rtic" +version = "0.0.0" +dependencies = [ + "consts", + "defmt", + "defmt-rtt", + "dk", + "rtic", + "rtic-monotonics", + "usb-device", + "usbd-serial", +] + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "nrf-hal-common" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c134de1f2f0191aed3fc24d3831da8808d1e636b06edf81a5717103095f625d" +dependencies = [ + "cast", + "cfg-if", + "cortex-m", + "embedded-dma", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-io", + "embedded-storage", + "fixed", + "nb 1.1.0", + "nrf-usbd", + "nrf52840-pac", + "rand_core", + "void", +] + +[[package]] +name = "nrf-usbd" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf862f941154442271ae9914777bd1c93f6d2e0dc9db4cafa160e55ffb9085" +dependencies = [ + "cortex-m", + "critical-section", + "usb-device", + "vcell", +] + +[[package]] +name = "nrf52840-hal" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433cfd866da18dfc58376880bdebd092c130444837debc513f44edcd0d6a6558" +dependencies = [ + "nrf-hal-common", + "nrf52840-pac", +] + +[[package]] +name = "nrf52840-pac" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30713f36f1be02e5bc9abefa30eae4a1f943d810f199d4923d3ad062d1be1b3d" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "vcell", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rtic" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "401961431a1e491124cdd216a313fada2d395aa2b5bee2867c872fc8af7c1bc1" +dependencies = [ + "bare-metal 1.0.0", + "cortex-m", + "critical-section", + "portable-atomic", + "rtic-core", + "rtic-macros", +] + +[[package]] +name = "rtic-common" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c" +dependencies = [ + "critical-section", +] + +[[package]] +name = "rtic-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" + +[[package]] +name = "rtic-macros" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac22ab522d80079b48f46ac66ded4d349e1adf81b52430d6a74faa3a7790ed80" +dependencies = [ + "indexmap", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "rtic-monotonics" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1cb90bcfdbbacf3ca37340cdab52ec2de5611c744095ef7889e9c50c233b748" +dependencies = [ + "cfg-if", + "cortex-m", + "fugit", + "portable-atomic", + "rtic-time", +] + +[[package]] +name = "rtic-time" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7b1d853fa50dc125695414ce4510567a0d420221e455b1568cfa8c9aece9614" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", + "embedded-hal-async", + "fugit", + "futures-util", + "rtic-common", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" + +[[package]] +name = "usb-device" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" +dependencies = [ + "defmt", + "heapless", + "portable-atomic", +] + +[[package]] +name = "usbd-serial" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "065e4eaf93db81d5adac82d9cef8f8da314cb640fa7f89534b972383f1cf80fc" +dependencies = [ + "embedded-hal 0.2.7", + "embedded-io", + "nb 1.1.0", + "usb-device", +] + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] diff --git a/nrf52-code/loopback-fw-rtic/Cargo.toml b/nrf52-code/loopback-fw-rtic/Cargo.toml new file mode 100644 index 00000000..eddb7d51 --- /dev/null +++ b/nrf52-code/loopback-fw-rtic/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["Ferrous Systems"] +edition = "2021" +license = "MIT OR Apache-2.0" +name = "loopback-fw-rtic" +version = "0.0.0" + +[dependencies] +consts = { version = "0.1.0", path = "../consts" } +defmt = "0.3.10" +defmt-rtt = "0.4.1" +dk = { version = "0.0.0", path = "../boards/dk", features = ["usbd"] } +rtic = { version = "2.1.2", features = ["thumbv7-backend"] } +rtic-monotonics = { version = "2.0.3", features = ["cortex-m-systick"] } +usb-device = { version = "0.3.2", features = ["defmt"] } +usbd-serial = "0.2.2" diff --git a/nrf52-code/loopback-fw-rtic/src/main.rs b/nrf52-code/loopback-fw-rtic/src/main.rs new file mode 100644 index 00000000..acd2aaf7 --- /dev/null +++ b/nrf52-code/loopback-fw-rtic/src/main.rs @@ -0,0 +1,113 @@ +//! The Loopback Firmware, written using RTIC +//! +//! Currently this runs on the Developer Kit and not the Dongle, because it's +//! easier to debug. +//! +//! And it doesn't do any radio stuff - just USB Serial. + +#![no_main] +#![no_std] + +use defmt_rtt as _; + +#[rtic::app(device = dk, peripherals = false)] +mod app { + use core::mem::MaybeUninit; + use rtic_monotonics::systick::prelude::*; + + systick_monotonic!(Mono, 100); + + #[local] + struct MyLocalResources {} + + #[shared] + struct MySharedResources { + usb_serial: usbd_serial::SerialPort<'static, dk::UsbDevice>, + usb_device: usb_device::device::UsbDevice<'static, dk::UsbDevice>, + } + + #[init(local = [ + usb_alloc: MaybeUninit> = MaybeUninit::uninit() + ])] + fn init(cx: init::Context) -> (MySharedResources, MyLocalResources) { + let board = dk::init().unwrap(); + Mono::start(cx.core.SYST, 64_000_000); + + defmt::debug!("Building USB allocator..."); + let usb_alloc = cx + .local + .usb_alloc + .write(usb_device::bus::UsbBusAllocator::new(board.usbd)); + + defmt::debug!("Creating usb_serial..."); + let usb_serial = usbd_serial::SerialPort::new(usb_alloc); + + defmt::debug!("Building USB Strings..."); + let strings = usb_device::device::StringDescriptors::new(usb_device::LangID::EN) + .manufacturer("Ferrous Systems") + .product("Test Device"); + + defmt::debug!("Building VID and PID..."); + let vid_pid = + usb_device::device::UsbVidPid(consts::USB_VID_DEMO, consts::USB_PID_DONGLE_LOOPBACK); + + defmt::debug!("Building USB Device..."); + let usb_device = usb_device::device::UsbDeviceBuilder::new(usb_alloc, vid_pid) + .composite_with_iads() + .strings(&[strings]) + .expect("Adding strings") + .max_packet_size_0(64) + .expect("set_packet_size") + .build(); + + defmt::debug!("Spawning task..."); + foo::spawn().ok(); + + defmt::debug!("Building structures..."); + let shared = MySharedResources { + usb_serial, + usb_device, + }; + let local = MyLocalResources {}; + + defmt::debug!("Init Complete!"); + + (shared, local) + } + + #[task(shared = [usb_serial])] + async fn foo(mut cx: foo::Context) { + loop { + defmt::info!("hello from foo"); + let _ = cx.shared.usb_serial.lock(|usb_serial| { + usb_serial.write(b"Boopity boop"); + }); + Mono::delay(1000.millis()).await; + } + } + + /// USB Interrupt Handler + /// + /// USB Device is set to fire this whenever there's a Start of Frame from + /// the USB Host. + #[task(binds = USBD, shared = [usb_serial, usb_device])] + fn usb_isr(cx: usb_isr::Context) { + (cx.shared.usb_serial, cx.shared.usb_device).lock(|usb_serial, usb_device| { + usb_device.poll(&mut [usb_serial]); + }); + } +} + +#[panic_handler] +fn panic(info: &core::panic::PanicInfo) -> ! { + if let Some(location) = info.location() { + defmt::error!("Panic at {}:{}", location.file(), location.line()); + } else { + defmt::error!("Panic at unknown location"); + } + loop { + core::hint::spin_loop(); + } +} + +defmt::timestamp!("{=u64:tus}", dk::uptime_us()); From 405380c54ae98524142edcf3599aad1fb36abe98 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Wed, 11 Dec 2024 17:32:14 +0000 Subject: [PATCH 07/10] loopback-fw-rtic now works. ) Tested HID channel change. ) Tested USB Serial interface ) Tested radio loopback. Just needs changing to run on the dongle and not the DK. --- nrf52-code/boards/dk-solution/Cargo.toml | 1 + nrf52-code/boards/dk-solution/src/lib.rs | 42 +++- nrf52-code/boards/dk/src/lib.rs | 14 ++ nrf52-code/loopback-fw-rtic/Cargo.lock | 167 +++++++++++++- nrf52-code/loopback-fw-rtic/Cargo.toml | 4 +- nrf52-code/loopback-fw-rtic/src/main.rs | 281 +++++++++++++++++++++-- 6 files changed, 476 insertions(+), 33 deletions(-) diff --git a/nrf52-code/boards/dk-solution/Cargo.toml b/nrf52-code/boards/dk-solution/Cargo.toml index 4fc4c4d1..e8d19e94 100644 --- a/nrf52-code/boards/dk-solution/Cargo.toml +++ b/nrf52-code/boards/dk-solution/Cargo.toml @@ -18,3 +18,4 @@ hal = { package = "nrf52840-hal", version = "0.18.0" } [features] advanced = [] radio = [] +usbd = [] diff --git a/nrf52-code/boards/dk-solution/src/lib.rs b/nrf52-code/boards/dk-solution/src/lib.rs index 91045c06..94dddb22 100644 --- a/nrf52-code/boards/dk-solution/src/lib.rs +++ b/nrf52-code/boards/dk-solution/src/lib.rs @@ -17,7 +17,7 @@ use cortex_m_semihosting::debug; use embedded_hal::digital::{InputPin, OutputPin, StatefulOutputPin}; #[cfg(feature = "advanced")] use grounded::uninit::GroundedArrayCell; -#[cfg(feature = "radio")] +#[cfg(any(feature = "radio", feature = "usbd"))] use grounded::uninit::GroundedCell; #[cfg(feature = "radio")] pub use hal::ieee802154; @@ -44,14 +44,18 @@ pub mod peripheral; #[cfg(feature = "advanced")] pub mod usbd; -#[cfg(feature = "radio")] +#[cfg(any(feature = "radio", feature = "usbd"))] struct ClockSyncWrapper { clocks: Clocks, } -#[cfg(feature = "radio")] +#[cfg(any(feature = "radio", feature = "usbd"))] unsafe impl Sync for ClockSyncWrapper {} +/// Our USB Device +#[cfg(feature = "usbd")] +pub type UsbDevice = hal::usbd::Usbd>; + /// Components on the board pub struct Board { /// LEDs @@ -73,6 +77,9 @@ pub struct Board { /// USB control endpoint 0 #[cfg(feature = "advanced")] pub ep0in: Ep0In, + /// A configured USB Device + #[cfg(feature = "usbd")] + pub usbd: UsbDevice, } /// All LEDs on the board @@ -326,7 +333,7 @@ pub fn init() -> Result { // NOTE: this branch runs at most once #[cfg(feature = "advanced")] static EP0IN_BUF: GroundedArrayCell = GroundedArrayCell::const_init(); - #[cfg(feature = "radio")] + #[cfg(any(feature = "radio", feature = "usbd"))] // We need the wrapper to make this type Sync, as it contains raw pointers static CLOCKS: GroundedCell< ClockSyncWrapper< @@ -343,7 +350,7 @@ pub fn init() -> Result { let clocks = clocks.start_lfclk(); let _clocks = clocks.enable_ext_hfosc(); // extend lifetime to `'static` - #[cfg(feature = "radio")] + #[cfg(any(feature = "radio", feature = "usbd"))] let clocks = unsafe { let clocks_ptr = CLOCKS.get(); clocks_ptr.write(ClockSyncWrapper { clocks: _clocks }); @@ -402,6 +409,15 @@ pub fn init() -> Result { radio }; + #[cfg(feature = "usbd")] + { + defmt::debug!("Enabling SOF interrupts..."); + periph.USBD.inten.modify(|_r, w| { + w.sof().set_bit(); + w + }); + } + Ok(Board { leds: Leds { _1: Led { inner: led1pin }, @@ -424,6 +440,8 @@ pub fn init() -> Result { power: periph.POWER, #[cfg(feature = "advanced")] ep0in: unsafe { Ep0In::new(&EP0IN_BUF) }, + #[cfg(feature = "usbd")] + usbd: UsbDevice::new(hal::usbd::UsbPeripheral::new(periph.USBD, clocks)), }) } @@ -550,3 +568,17 @@ pub fn uptime_us() -> u64 { ticks } + +/// Returns the least-significant bits of the device identifier +pub fn deviceid0() -> u32 { + // NOTE(unsafe) read-only registers, and no other use of the block + let ficr = unsafe { &*hal::pac::FICR::ptr() }; + ficr.deviceid[0].read().deviceid().bits() +} + +/// Returns the most-significant bits of the device identifier +pub fn deviceid1() -> u32 { + // NOTE(unsafe) read-only registers, and no other use of the block + let ficr = unsafe { &*hal::pac::FICR::ptr() }; + ficr.deviceid[1].read().deviceid().bits() +} diff --git a/nrf52-code/boards/dk/src/lib.rs b/nrf52-code/boards/dk/src/lib.rs index 6c22505a..414d42cd 100644 --- a/nrf52-code/boards/dk/src/lib.rs +++ b/nrf52-code/boards/dk/src/lib.rs @@ -530,3 +530,17 @@ pub fn uptime_us() -> u64 { ticks } + +/// Returns the least-significant bits of the device identifier +pub fn deviceid0() -> u32 { + // NOTE(unsafe) read-only registers, and no other use of the block + let ficr = unsafe { &*hal::pac::FICR::ptr() }; + ficr.deviceid[0].read().deviceid().bits() +} + +/// Returns the most-significant bits of the device identifier +pub fn deviceid1() -> u32 { + // NOTE(unsafe) read-only registers, and no other use of the block + let ficr = unsafe { &*hal::pac::FICR::ptr() }; + ficr.deviceid[1].read().deviceid().bits() +} diff --git a/nrf52-code/loopback-fw-rtic/Cargo.lock b/nrf52-code/loopback-fw-rtic/Cargo.lock index 881e4ec4..02db2311 100644 --- a/nrf52-code/loopback-fw-rtic/Cargo.lock +++ b/nrf52-code/loopback-fw-rtic/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "az" version = "1.2.1" @@ -29,6 +41,12 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + [[package]] name = "bitflags" version = "1.3.2" @@ -70,7 +88,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" dependencies = [ "bare-metal 0.2.5", - "bitfield", + "bitfield 0.13.2", "critical-section", "embedded-hal 0.2.7", "volatile-register", @@ -93,7 +111,7 @@ checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -137,7 +155,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -219,6 +237,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "equivalent" version = "1.0.1" @@ -304,6 +328,15 @@ dependencies = [ "byteorder", ] +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + [[package]] name = "hashbrown" version = "0.15.2" @@ -316,6 +349,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ + "defmt", "hash32", "stable_deref_trait", ] @@ -327,9 +361,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.15.2", ] +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + [[package]] name = "loopback-fw-rtic" version = "0.0.0" @@ -338,9 +378,11 @@ dependencies = [ "defmt", "defmt-rtt", "dk", + "heapless", "rtic", "rtic-monotonics", "usb-device", + "usbd-hid", "usbd-serial", ] @@ -414,6 +456,12 @@ dependencies = [ "vcell", ] +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -451,7 +499,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -517,7 +565,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -571,12 +619,53 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "serde" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "ssmarshal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3e6ad23b128192ed337dfa4f1b8099ced0c2bf30d61e551b65fda5916dbb850" +dependencies = [ + "encode_unicode", + "serde", +] + [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.90" @@ -605,7 +694,7 @@ checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.90", ] [[package]] @@ -631,6 +720,44 @@ dependencies = [ "portable-atomic", ] +[[package]] +name = "usbd-hid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c" +dependencies = [ + "defmt", + "serde", + "ssmarshal", + "usb-device", + "usbd-hid-macros", +] + +[[package]] +name = "usbd-hid-descriptors" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee54712c5d778d2fb2da43b1ce5a7b5060886ef7b09891baeb4bf36910a3ed" +dependencies = [ + "bitfield 0.14.0", +] + +[[package]] +name = "usbd-hid-macros" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38" +dependencies = [ + "byteorder", + "hashbrown 0.13.2", + "log", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", + "usbd-hid-descriptors", +] + [[package]] name = "usbd-serial" version = "0.2.2" @@ -649,6 +776,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + [[package]] name = "void" version = "1.0.2" @@ -663,3 +796,23 @@ checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" dependencies = [ "vcell", ] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] diff --git a/nrf52-code/loopback-fw-rtic/Cargo.toml b/nrf52-code/loopback-fw-rtic/Cargo.toml index eddb7d51..e935db78 100644 --- a/nrf52-code/loopback-fw-rtic/Cargo.toml +++ b/nrf52-code/loopback-fw-rtic/Cargo.toml @@ -9,8 +9,10 @@ version = "0.0.0" consts = { version = "0.1.0", path = "../consts" } defmt = "0.3.10" defmt-rtt = "0.4.1" -dk = { version = "0.0.0", path = "../boards/dk", features = ["usbd"] } +dk = { version = "0.0.0", path = "../boards/dk", features = ["usbd", "radio"] } +heapless = { version = "0.8.0", features = ["defmt-03"] } rtic = { version = "2.1.2", features = ["thumbv7-backend"] } rtic-monotonics = { version = "2.0.3", features = ["cortex-m-systick"] } usb-device = { version = "0.3.2", features = ["defmt"] } +usbd-hid = { version = "0.8.2", features = ["defmt"] } usbd-serial = "0.2.2" diff --git a/nrf52-code/loopback-fw-rtic/src/main.rs b/nrf52-code/loopback-fw-rtic/src/main.rs index acd2aaf7..7a33a451 100644 --- a/nrf52-code/loopback-fw-rtic/src/main.rs +++ b/nrf52-code/loopback-fw-rtic/src/main.rs @@ -14,27 +14,76 @@ use defmt_rtt as _; mod app { use core::mem::MaybeUninit; use rtic_monotonics::systick::prelude::*; + const QUEUE_LEN: usize = 8; systick_monotonic!(Mono, 100); + /// An adapter that lets us writeln! into any closure that takes a byte. + /// + /// This is useful if writing a byte requires taking a lock, and you don't + /// want to hold the lock for the duration of the write. + struct Writer(F) + where + F: FnMut(&[u8]); + + impl core::fmt::Write for Writer + where + F: FnMut(&[u8]), + { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + (self.0)(s.as_bytes()); + Ok(()) + } + } + #[local] - struct MyLocalResources {} + struct MyLocalResources { + /// The radio subsystem + radio: dk::ieee802154::Radio<'static>, + /// Which channel are we on + current_channel: u8, + /// Holds one package, for receive or transmit + packet: dk::ieee802154::Packet, + /// Used to measure elapsed time + timer: dk::Timer, + /// How many packets have been received OK? + rx_count: u32, + /// How many packets have been received with errors? + err_count: u32, + /// A place to read the message queue + msg_queue_out: heapless::spsc::Consumer<'static, Message, QUEUE_LEN>, + /// A place to write to the message queue + msg_queue_in: heapless::spsc::Producer<'static, Message, QUEUE_LEN>, + /// A status LED + led: dk::Led, + } + + #[derive(Debug, defmt::Format, Copy, Clone, PartialEq, Eq)] + enum Message { + ChangeChannel(u8), + WantInfo, + } #[shared] struct MySharedResources { + /// Handles the USB Serial interface, including a ring buffer usb_serial: usbd_serial::SerialPort<'static, dk::UsbDevice>, + /// Handles the USB HID interface + usb_hid: usbd_hid::hid_class::HIDClass<'static, dk::UsbDevice>, + /// Handles the lower-level USB Device interface usb_device: usb_device::device::UsbDevice<'static, dk::UsbDevice>, } #[init(local = [ - usb_alloc: MaybeUninit> = MaybeUninit::uninit() + usb_alloc: MaybeUninit> = MaybeUninit::uninit(), + queue: heapless::spsc::Queue = heapless::spsc::Queue::new(), ])] - fn init(cx: init::Context) -> (MySharedResources, MyLocalResources) { - let board = dk::init().unwrap(); - Mono::start(cx.core.SYST, 64_000_000); + fn init(ctx: init::Context) -> (MySharedResources, MyLocalResources) { + let mut board = dk::init().unwrap(); + Mono::start(ctx.core.SYST, 64_000_000); defmt::debug!("Building USB allocator..."); - let usb_alloc = cx + let usb_alloc = ctx .local .usb_alloc .write(usb_device::bus::UsbBusAllocator::new(board.usbd)); @@ -42,6 +91,34 @@ mod app { defmt::debug!("Creating usb_serial..."); let usb_serial = usbd_serial::SerialPort::new(usb_alloc); + defmt::debug!("Creating usb_hid..."); + let desc = &[ + 0x06, 0x00, 0xFF, // Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0xA1, 0x01, // Item(Main ): Collection, data= [ 0x01 ] 1 + // Application + 0x15, 0x00, // Item(Global): Logical Minimum, data= [ 0x00 ] 0 + 0x26, 0xFF, 0x00, // Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + 0x75, 0x08, // Item(Global): Report Size, data= [ 0x08 ] 8 + 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0x81, 0x02, // Item(Main ): Input, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0x91, 0x02, // Item(Main ): Output, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0x95, 0x01, // Item(Global): Report Count, data= [ 0x01 ] 1 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0xB1, 0x02, // Item(Main ): Feature, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0xC0, // Item(Main ): End Collection, data=none + ]; + let usb_hid = usbd_hid::hid_class::HIDClass::new(usb_alloc, desc, 100); + defmt::debug!("Building USB Strings..."); let strings = usb_device::device::StringDescriptors::new(usb_device::LangID::EN) .manufacturer("Ferrous Systems") @@ -60,29 +137,167 @@ mod app { .expect("set_packet_size") .build(); - defmt::debug!("Spawning task..."); - foo::spawn().ok(); + defmt::debug!("Configuring radio..."); + board.radio.set_channel(dk::ieee802154::Channel::_20); + let current_channel = 20; + + let (msg_queue_in, msg_queue_out) = ctx.local.queue.split(); defmt::debug!("Building structures..."); let shared = MySharedResources { usb_serial, + usb_hid, usb_device, }; - let local = MyLocalResources {}; + let local = MyLocalResources { + radio: board.radio, + current_channel, + packet: dk::ieee802154::Packet::new(), + timer: board.timer, + rx_count: 0, + err_count: 0, + msg_queue_out, + msg_queue_in, + led: board.leds._1, + }; defmt::debug!("Init Complete!"); (shared, local) } - #[task(shared = [usb_serial])] - async fn foo(mut cx: foo::Context) { + #[idle(local = [radio, current_channel, packet, timer, rx_count, err_count, msg_queue_out, led], shared = [usb_serial])] + fn idle(mut ctx: idle::Context) -> ! { + use core::fmt::Write as _; + let mut writer = Writer(|b: &[u8]| { + ctx.shared.usb_serial.lock(|usb_serial| { + let _ = usb_serial.write(b); + }) + }); + + defmt::info!( + "deviceid={=u32:08x}{=u32:08x} channel={=u8} TxPower=+8dBm app=loopback-fw", + dk::deviceid1(), + dk::deviceid0(), + ctx.local.current_channel + ); + loop { - defmt::info!("hello from foo"); - let _ = cx.shared.usb_serial.lock(|usb_serial| { - usb_serial.write(b"Boopity boop"); - }); - Mono::delay(1000.millis()).await; + while let Some(msg) = ctx.local.msg_queue_out.dequeue() { + match msg { + Message::WantInfo => { + defmt::info!( + "rx={=u32}, err={=u32}, ch={=u8}, app=loopback-fw", + ctx.local.rx_count, + ctx.local.err_count, + ctx.local.current_channel + ); + let _ = writeln!( + writer, + "\nrx={}, err={}, ch={}, app=loopback-fw", + ctx.local.rx_count, ctx.local.err_count, ctx.local.current_channel + ); + } + Message::ChangeChannel(n) => { + defmt::info!("Changing Channel to {}", n); + let _ = writeln!(writer, "\nChanging Channel to {}", n); + match n { + 11 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_11); + } + 12 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_12); + } + 13 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_13); + } + 14 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_14); + } + 15 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_15); + } + 16 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_16); + } + 17 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_17); + } + 18 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_18); + } + 19 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_19); + } + 20 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_20); + } + 21 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_21); + } + 22 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_22); + } + 23 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_23); + } + 24 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_24); + } + 25 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_25); + } + 26 => { + ctx.local.radio.set_channel(dk::ieee802154::Channel::_26); + } + _ => { + defmt::info!("Bad Channel {}!", n); + } + } + } + } + } + + defmt::debug!("Waiting for packet.."); + match ctx.local.radio.recv_timeout( + &mut ctx.local.packet, + &mut ctx.local.timer, + 1_000_000, + ) { + Ok(crc) => { + ctx.local.led.toggle(); + defmt::info!( + "Received {=u8} bytes (CRC=0x{=u16:04x}, LQI={})", + ctx.local.packet.len(), + crc, + ctx.local.packet.lqi(), + ); + let _ = writeln!( + writer, + "\nReceived {} bytes (CRC=0x{:04x}, LQI={})", + ctx.local.packet.len(), + crc, + ctx.local.packet.lqi(), + ); + *ctx.local.rx_count += 1; + // reverse the bytes, so olleh -> hello + ctx.local.packet.reverse(); + // send packet after 5ms (we know the client waits for 10ms and + // we want to ensure they are definitely in receive mode by the + // time we send this reply) + ctx.local.timer.delay(5000); + ctx.local.radio.send(ctx.local.packet); + } + Err(dk::ieee802154::Error::Crc(_)) => { + defmt::debug!("RX fail!"); + let _ = write!(writer, "!"); + *ctx.local.err_count += 1; + } + Err(dk::ieee802154::Error::Timeout) => { + defmt::debug!("RX timeout..."); + let _ = write!(writer, "."); + } + } } } @@ -90,10 +305,36 @@ mod app { /// /// USB Device is set to fire this whenever there's a Start of Frame from /// the USB Host. - #[task(binds = USBD, shared = [usb_serial, usb_device])] - fn usb_isr(cx: usb_isr::Context) { - (cx.shared.usb_serial, cx.shared.usb_device).lock(|usb_serial, usb_device| { - usb_device.poll(&mut [usb_serial]); + #[task(binds = USBD, local = [msg_queue_in], shared = [usb_serial, usb_hid, usb_device])] + fn usb_isr(mut ctx: usb_isr::Context) { + let mut all = ( + &mut ctx.shared.usb_serial, + &mut ctx.shared.usb_hid, + &mut ctx.shared.usb_device, + ); + all.lock(|usb_serial, usb_hid, usb_device| { + if usb_device.poll(&mut [usb_serial, usb_hid]) { + let mut buffer = [0u8; 64]; + if let Ok(n) = usb_serial.read(&mut buffer) { + if n > 0 { + for b in &buffer[0..n] { + if *b == b'?' { + // User pressed "?" in the terminal + _ = ctx.local.msg_queue_in.enqueue(Message::WantInfo); + } + } + } + } + if let Ok(n) = usb_hid.pull_raw_output(&mut buffer) { + // Linux sends 1 byte, Windows sends 64 (with 63 zero bytes) + if n == 1 || n == 64 { + _ = ctx + .local + .msg_queue_in + .enqueue(Message::ChangeChannel(buffer[0])); + } + } + } }); } } From 20f464eec5efa8f7d0c594c5c613426be0c8e4c8 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Wed, 11 Dec 2024 18:20:47 +0000 Subject: [PATCH 08/10] Moved loopback-fw over to the RTIC version, on the dongle. Tested on macOS 15, Windows 10 and Debian 12. --- build.sh | 5 - nrf52-code/boards/dk-solution/src/lib.rs | 32 +- nrf52-code/boards/dk/src/lib.rs | 32 +- nrf52-code/boards/dongle/src/lib.rs | 5 +- .../loopback-fw-rtic/.cargo/config.toml | 23 - nrf52-code/loopback-fw-rtic/.gitignore | 1 - nrf52-code/loopback-fw-rtic/Cargo.lock | 818 ------------------ nrf52-code/loopback-fw-rtic/Cargo.toml | 18 - nrf52-code/loopback-fw-rtic/src/main.rs | 354 -------- nrf52-code/loopback-fw/.cargo/config.toml | 5 +- nrf52-code/loopback-fw/Cargo.lock | 213 +++-- nrf52-code/loopback-fw/Cargo.toml | 37 +- nrf52-code/loopback-fw/src/main.rs | 633 ++++++++------ 13 files changed, 558 insertions(+), 1618 deletions(-) delete mode 100644 nrf52-code/loopback-fw-rtic/.cargo/config.toml delete mode 100644 nrf52-code/loopback-fw-rtic/.gitignore delete mode 100644 nrf52-code/loopback-fw-rtic/Cargo.lock delete mode 100644 nrf52-code/loopback-fw-rtic/Cargo.toml delete mode 100644 nrf52-code/loopback-fw-rtic/src/main.rs diff --git a/build.sh b/build.sh index 66339e5e..c675c148 100755 --- a/build.sh +++ b/build.sh @@ -72,10 +72,6 @@ pushd loopback-fw cargo build --target=thumbv7em-none-eabihf --release cargo fmt --check popd -pushd loopback-fw-rtic -cargo build --target=thumbv7em-none-eabihf --release -cargo fmt --check -popd popd # Only build the templates (they will panic at run-time due to the use of todo!) @@ -109,6 +105,5 @@ cp -r ./.cargo "${OUTPUT_NAME}/" cp -r ./tools "${OUTPUT_NAME}/" cp ./nrf52-code/puzzle-fw/target/thumbv7em-none-eabihf/release/puzzle-fw "${OUTPUT_NAME}/nrf52-code/boards/dongle-fw/puzzle-fw" cp ./nrf52-code/loopback-fw/target/thumbv7em-none-eabihf/release/loopback-fw "${OUTPUT_NAME}/nrf52-code/boards/dongle-fw/loopback-fw" -cp ./nrf52-code/loopback-fw-rtic/target/thumbv7em-none-eabihf/release/loopback-fw-rtic "${OUTPUT_NAME}/nrf52-code/boards/dongle-fw/loopback-fw-rtic" find "${OUTPUT_NAME}" -name target -type d -print0 | xargs -0 rm -rf zip -r "${OUTPUT_NAME}.zip" "${OUTPUT_NAME}" diff --git a/nrf52-code/boards/dk-solution/src/lib.rs b/nrf52-code/boards/dk-solution/src/lib.rs index 94dddb22..6ad75ab2 100644 --- a/nrf52-code/boards/dk-solution/src/lib.rs +++ b/nrf52-code/boards/dk-solution/src/lib.rs @@ -32,12 +32,6 @@ use hal::{ #[cfg(any(feature = "radio", feature = "advanced"))] use defmt_rtt as _; // global logger -#[cfg(feature = "advanced")] -use crate::{ - peripheral::{POWER, USBD}, - usbd::Ep0In, -}; - #[cfg(feature = "advanced")] mod errata; pub mod peripheral; @@ -69,17 +63,21 @@ pub struct Board { #[cfg(feature = "radio")] pub radio: ieee802154::Radio<'static>, /// USBD (Universal Serial Bus Device) peripheral - #[cfg(feature = "advanced")] - pub usbd: USBD, + #[cfg(any(feature = "advanced", feature = "usbd"))] + pub usbd: hal::pac::USBD, /// POWER (Power Supply) peripheral #[cfg(feature = "advanced")] - pub power: POWER, + pub power: hal::pac::POWER, /// USB control endpoint 0 #[cfg(feature = "advanced")] - pub ep0in: Ep0In, - /// A configured USB Device - #[cfg(feature = "usbd")] - pub usbd: UsbDevice, + pub ep0in: usbd::Ep0In, + /// Represents our current clock setup + #[cfg(any(feature = "radio", feature = "usbd"))] + pub clocks: &'static Clocks< + clocks::ExternalOscillator, + clocks::ExternalOscillator, + clocks::LfOscStarted, + >, } /// All LEDs on the board @@ -434,14 +432,14 @@ pub fn init() -> Result { #[cfg(feature = "radio")] radio, timer: Timer { inner: timer }, - #[cfg(feature = "advanced")] + #[cfg(any(feature = "advanced", feature = "usbd"))] usbd: periph.USBD, #[cfg(feature = "advanced")] power: periph.POWER, #[cfg(feature = "advanced")] - ep0in: unsafe { Ep0In::new(&EP0IN_BUF) }, - #[cfg(feature = "usbd")] - usbd: UsbDevice::new(hal::usbd::UsbPeripheral::new(periph.USBD, clocks)), + ep0in: unsafe { usbd::Ep0In::new(&EP0IN_BUF) }, + #[cfg(any(feature = "radio", feature = "usbd"))] + clocks, }) } diff --git a/nrf52-code/boards/dk/src/lib.rs b/nrf52-code/boards/dk/src/lib.rs index 414d42cd..6a275eff 100644 --- a/nrf52-code/boards/dk/src/lib.rs +++ b/nrf52-code/boards/dk/src/lib.rs @@ -32,12 +32,6 @@ use hal::{ #[cfg(any(feature = "radio", feature = "advanced"))] use defmt_rtt as _; // global logger -#[cfg(feature = "advanced")] -use crate::{ - peripheral::{POWER, USBD}, - usbd::Ep0In, -}; - #[cfg(feature = "advanced")] mod errata; pub mod peripheral; @@ -67,17 +61,21 @@ pub struct Board { #[cfg(feature = "radio")] pub radio: ieee802154::Radio<'static>, /// USBD (Universal Serial Bus Device) peripheral - #[cfg(feature = "advanced")] - pub usbd: USBD, + #[cfg(any(feature = "advanced", feature = "usbd"))] + pub usbd: hal::pac::USBD, /// POWER (Power Supply) peripheral #[cfg(feature = "advanced")] - pub power: POWER, + pub power: hal::pac::POWER, /// USB control endpoint 0 #[cfg(feature = "advanced")] - pub ep0in: Ep0In, - /// A configured USB Device - #[cfg(feature = "usbd")] - pub usbd: UsbDevice, + pub ep0in: usbd::Ep0In, + /// Represents our current clock setup + #[cfg(any(feature = "radio", feature = "usbd"))] + pub clocks: &'static Clocks< + clocks::ExternalOscillator, + clocks::ExternalOscillator, + clocks::LfOscStarted, + >, } /// All LEDs on the board @@ -396,14 +394,14 @@ pub fn init() -> Result { #[cfg(feature = "radio")] radio, timer: Timer { inner: timer }, - #[cfg(feature = "advanced")] + #[cfg(any(feature = "advanced", feature = "usbd"))] usbd: periph.USBD, #[cfg(feature = "advanced")] power: periph.POWER, #[cfg(feature = "advanced")] - ep0in: unsafe { Ep0In::new(&EP0IN_BUF) }, - #[cfg(feature = "usbd")] - usbd: UsbDevice::new(hal::usbd::UsbPeripheral::new(periph.USBD, clocks)), + ep0in: unsafe { usbd::Ep0In::new(&EP0IN_BUF) }, + #[cfg(any(feature = "radio", feature = "usbd"))] + clocks, }) } diff --git a/nrf52-code/boards/dongle/src/lib.rs b/nrf52-code/boards/dongle/src/lib.rs index 88659f88..4a0dc4c3 100644 --- a/nrf52-code/boards/dongle/src/lib.rs +++ b/nrf52-code/boards/dongle/src/lib.rs @@ -17,8 +17,6 @@ use cortex_m_semihosting::debug; use embedded_hal::digital::{OutputPin, StatefulOutputPin}; use grounded::uninit::GroundedCell; -use hal::pac::interrupt; -pub use hal::{self, ieee802154}; use hal::{ clocks::{self, Clocks}, gpio::{p0, p1, Level, Output, Pin, Port, PushPull}, @@ -29,6 +27,9 @@ use hal::{ use defmt_rtt as _; // global logger +pub use hal::pac::{interrupt, Interrupt, NVIC_PRIO_BITS, RTC0}; +pub use hal::{self, ieee802154}; + /// Exports PAC peripherals pub mod peripheral { pub use hal::pac::{interrupt, Interrupt, POWER, USBD}; diff --git a/nrf52-code/loopback-fw-rtic/.cargo/config.toml b/nrf52-code/loopback-fw-rtic/.cargo/config.toml deleted file mode 100644 index 436cc4fb..00000000 --- a/nrf52-code/loopback-fw-rtic/.cargo/config.toml +++ /dev/null @@ -1,23 +0,0 @@ -[target.thumbv7em-none-eabihf] -# set custom cargo runner to flash & run on embedded target when we call `cargo run` -# for more information, check out https://github.com/probe-rs -runner = [ - "probe-rs", - "run", - "--chip", - "nRF52840_xxAA", - "--allow-erase-all", - "--log-format", - "{t} {[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" -] -# Or use "{[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" to disable timestamps - -linker = "flip-link" # adds stack overflow protection -rustflags = [ - "-C", "link-arg=-Tlink.x", # use the cortex-m-rt linker script - "-C", "link-arg=-Tdefmt.x", # defmt support -] - -[build] -# cross-compile to this target -target = "thumbv7em-none-eabihf" # = ARM Cortex-M4 with FPU diff --git a/nrf52-code/loopback-fw-rtic/.gitignore b/nrf52-code/loopback-fw-rtic/.gitignore deleted file mode 100644 index eb5a316c..00000000 --- a/nrf52-code/loopback-fw-rtic/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/nrf52-code/loopback-fw-rtic/Cargo.lock b/nrf52-code/loopback-fw-rtic/Cargo.lock deleted file mode 100644 index 02db2311..00000000 --- a/nrf52-code/loopback-fw-rtic/Cargo.lock +++ /dev/null @@ -1,818 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "az" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bare-metal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "bitfield" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bytemuck" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "consts" -version = "0.1.0" - -[[package]] -name = "cortex-m" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" -dependencies = [ - "bare-metal 0.2.5", - "bitfield 0.13.2", - "critical-section", - "embedded-hal 0.2.7", - "volatile-register", -] - -[[package]] -name = "cortex-m-rt" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" -dependencies = [ - "cortex-m-rt-macros", -] - -[[package]] -name = "cortex-m-rt-macros" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "cortex-m-semihosting" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" -dependencies = [ - "cortex-m", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "defmt" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f6162c53f659f65d00619fe31f14556a6e9f8752ccc4a41bd177ffcf3d6130" -dependencies = [ - "bitflags", - "defmt-macros", -] - -[[package]] -name = "defmt-macros" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d135dd939bad62d7490b0002602d35b358dce5fd9233a709d3c1ef467d4bde6" -dependencies = [ - "defmt-parser", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "defmt-parser" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3" -dependencies = [ - "thiserror", -] - -[[package]] -name = "defmt-rtt" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab697b3dbbc1750b7c8b821aa6f6e7f2480b47a99bc057a2ed7b170ebef0c51" -dependencies = [ - "critical-section", - "defmt", -] - -[[package]] -name = "dk" -version = "0.0.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "cortex-m-semihosting", - "defmt", - "defmt-rtt", - "embedded-hal 1.0.0", - "grounded", - "nrf52840-hal", -] - -[[package]] -name = "embedded-dma" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "embedded-hal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" - -[[package]] -name = "embedded-hal-async" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" -dependencies = [ - "embedded-hal 1.0.0", -] - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "embedded-storage" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fixed" -version = "1.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" -dependencies = [ - "az", - "bytemuck", - "half", - "typenum", -] - -[[package]] -name = "fugit" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" -dependencies = [ - "gcd", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "gcd" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" - -[[package]] -name = "grounded" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917d82402c7eb9755fdd87d52117701dae9e413a6abb309fac2a13af693b6080" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "defmt", - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "indexmap" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" -dependencies = [ - "equivalent", - "hashbrown 0.15.2", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "loopback-fw-rtic" -version = "0.0.0" -dependencies = [ - "consts", - "defmt", - "defmt-rtt", - "dk", - "heapless", - "rtic", - "rtic-monotonics", - "usb-device", - "usbd-hid", - "usbd-serial", -] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "nrf-hal-common" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c134de1f2f0191aed3fc24d3831da8808d1e636b06edf81a5717103095f625d" -dependencies = [ - "cast", - "cfg-if", - "cortex-m", - "embedded-dma", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-io", - "embedded-storage", - "fixed", - "nb 1.1.0", - "nrf-usbd", - "nrf52840-pac", - "rand_core", - "void", -] - -[[package]] -name = "nrf-usbd" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf862f941154442271ae9914777bd1c93f6d2e0dc9db4cafa160e55ffb9085" -dependencies = [ - "cortex-m", - "critical-section", - "usb-device", - "vcell", -] - -[[package]] -name = "nrf52840-hal" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433cfd866da18dfc58376880bdebd092c130444837debc513f44edcd0d6a6558" -dependencies = [ - "nrf-hal-common", - "nrf52840-pac", -] - -[[package]] -name = "nrf52840-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30713f36f1be02e5bc9abefa30eae4a1f943d810f199d4923d3ad062d1be1b3d" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "portable-atomic" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - -[[package]] -name = "rtic" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "401961431a1e491124cdd216a313fada2d395aa2b5bee2867c872fc8af7c1bc1" -dependencies = [ - "bare-metal 1.0.0", - "cortex-m", - "critical-section", - "portable-atomic", - "rtic-core", - "rtic-macros", -] - -[[package]] -name = "rtic-common" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c" -dependencies = [ - "critical-section", -] - -[[package]] -name = "rtic-core" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" - -[[package]] -name = "rtic-macros" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac22ab522d80079b48f46ac66ded4d349e1adf81b52430d6a74faa3a7790ed80" -dependencies = [ - "indexmap", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "rtic-monotonics" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1cb90bcfdbbacf3ca37340cdab52ec2de5611c744095ef7889e9c50c233b748" -dependencies = [ - "cfg-if", - "cortex-m", - "fugit", - "portable-atomic", - "rtic-time", -] - -[[package]] -name = "rtic-time" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7b1d853fa50dc125695414ce4510567a0d420221e455b1568cfa8c9aece9614" -dependencies = [ - "critical-section", - "embedded-hal 1.0.0", - "embedded-hal-async", - "fugit", - "futures-util", - "rtic-common", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.216" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.216" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "ssmarshal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e6ad23b128192ed337dfa4f1b8099ced0c2bf30d61e551b65fda5916dbb850" -dependencies = [ - "encode_unicode", - "serde", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "usb-device" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" -dependencies = [ - "defmt", - "heapless", - "portable-atomic", -] - -[[package]] -name = "usbd-hid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c" -dependencies = [ - "defmt", - "serde", - "ssmarshal", - "usb-device", - "usbd-hid-macros", -] - -[[package]] -name = "usbd-hid-descriptors" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee54712c5d778d2fb2da43b1ce5a7b5060886ef7b09891baeb4bf36910a3ed" -dependencies = [ - "bitfield 0.14.0", -] - -[[package]] -name = "usbd-hid-macros" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38" -dependencies = [ - "byteorder", - "hashbrown 0.13.2", - "log", - "proc-macro2", - "quote", - "serde", - "syn 1.0.109", - "usbd-hid-descriptors", -] - -[[package]] -name = "usbd-serial" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065e4eaf93db81d5adac82d9cef8f8da314cb640fa7f89534b972383f1cf80fc" -dependencies = [ - "embedded-hal 0.2.7", - "embedded-io", - "nb 1.1.0", - "usb-device", -] - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" -dependencies = [ - "vcell", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] diff --git a/nrf52-code/loopback-fw-rtic/Cargo.toml b/nrf52-code/loopback-fw-rtic/Cargo.toml deleted file mode 100644 index e935db78..00000000 --- a/nrf52-code/loopback-fw-rtic/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -authors = ["Ferrous Systems"] -edition = "2021" -license = "MIT OR Apache-2.0" -name = "loopback-fw-rtic" -version = "0.0.0" - -[dependencies] -consts = { version = "0.1.0", path = "../consts" } -defmt = "0.3.10" -defmt-rtt = "0.4.1" -dk = { version = "0.0.0", path = "../boards/dk", features = ["usbd", "radio"] } -heapless = { version = "0.8.0", features = ["defmt-03"] } -rtic = { version = "2.1.2", features = ["thumbv7-backend"] } -rtic-monotonics = { version = "2.0.3", features = ["cortex-m-systick"] } -usb-device = { version = "0.3.2", features = ["defmt"] } -usbd-hid = { version = "0.8.2", features = ["defmt"] } -usbd-serial = "0.2.2" diff --git a/nrf52-code/loopback-fw-rtic/src/main.rs b/nrf52-code/loopback-fw-rtic/src/main.rs deleted file mode 100644 index 7a33a451..00000000 --- a/nrf52-code/loopback-fw-rtic/src/main.rs +++ /dev/null @@ -1,354 +0,0 @@ -//! The Loopback Firmware, written using RTIC -//! -//! Currently this runs on the Developer Kit and not the Dongle, because it's -//! easier to debug. -//! -//! And it doesn't do any radio stuff - just USB Serial. - -#![no_main] -#![no_std] - -use defmt_rtt as _; - -#[rtic::app(device = dk, peripherals = false)] -mod app { - use core::mem::MaybeUninit; - use rtic_monotonics::systick::prelude::*; - const QUEUE_LEN: usize = 8; - - systick_monotonic!(Mono, 100); - - /// An adapter that lets us writeln! into any closure that takes a byte. - /// - /// This is useful if writing a byte requires taking a lock, and you don't - /// want to hold the lock for the duration of the write. - struct Writer(F) - where - F: FnMut(&[u8]); - - impl core::fmt::Write for Writer - where - F: FnMut(&[u8]), - { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - (self.0)(s.as_bytes()); - Ok(()) - } - } - - #[local] - struct MyLocalResources { - /// The radio subsystem - radio: dk::ieee802154::Radio<'static>, - /// Which channel are we on - current_channel: u8, - /// Holds one package, for receive or transmit - packet: dk::ieee802154::Packet, - /// Used to measure elapsed time - timer: dk::Timer, - /// How many packets have been received OK? - rx_count: u32, - /// How many packets have been received with errors? - err_count: u32, - /// A place to read the message queue - msg_queue_out: heapless::spsc::Consumer<'static, Message, QUEUE_LEN>, - /// A place to write to the message queue - msg_queue_in: heapless::spsc::Producer<'static, Message, QUEUE_LEN>, - /// A status LED - led: dk::Led, - } - - #[derive(Debug, defmt::Format, Copy, Clone, PartialEq, Eq)] - enum Message { - ChangeChannel(u8), - WantInfo, - } - - #[shared] - struct MySharedResources { - /// Handles the USB Serial interface, including a ring buffer - usb_serial: usbd_serial::SerialPort<'static, dk::UsbDevice>, - /// Handles the USB HID interface - usb_hid: usbd_hid::hid_class::HIDClass<'static, dk::UsbDevice>, - /// Handles the lower-level USB Device interface - usb_device: usb_device::device::UsbDevice<'static, dk::UsbDevice>, - } - - #[init(local = [ - usb_alloc: MaybeUninit> = MaybeUninit::uninit(), - queue: heapless::spsc::Queue = heapless::spsc::Queue::new(), - ])] - fn init(ctx: init::Context) -> (MySharedResources, MyLocalResources) { - let mut board = dk::init().unwrap(); - Mono::start(ctx.core.SYST, 64_000_000); - - defmt::debug!("Building USB allocator..."); - let usb_alloc = ctx - .local - .usb_alloc - .write(usb_device::bus::UsbBusAllocator::new(board.usbd)); - - defmt::debug!("Creating usb_serial..."); - let usb_serial = usbd_serial::SerialPort::new(usb_alloc); - - defmt::debug!("Creating usb_hid..."); - let desc = &[ - 0x06, 0x00, 0xFF, // Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xA1, 0x01, // Item(Main ): Collection, data= [ 0x01 ] 1 - // Application - 0x15, 0x00, // Item(Global): Logical Minimum, data= [ 0x00 ] 0 - 0x26, 0xFF, 0x00, // Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 - 0x75, 0x08, // Item(Global): Report Size, data= [ 0x08 ] 8 - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x81, 0x02, // Item(Main ): Input, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x91, 0x02, // Item(Main ): Output, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x01, // Item(Global): Report Count, data= [ 0x01 ] 1 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xB1, 0x02, // Item(Main ): Feature, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0xC0, // Item(Main ): End Collection, data=none - ]; - let usb_hid = usbd_hid::hid_class::HIDClass::new(usb_alloc, desc, 100); - - defmt::debug!("Building USB Strings..."); - let strings = usb_device::device::StringDescriptors::new(usb_device::LangID::EN) - .manufacturer("Ferrous Systems") - .product("Test Device"); - - defmt::debug!("Building VID and PID..."); - let vid_pid = - usb_device::device::UsbVidPid(consts::USB_VID_DEMO, consts::USB_PID_DONGLE_LOOPBACK); - - defmt::debug!("Building USB Device..."); - let usb_device = usb_device::device::UsbDeviceBuilder::new(usb_alloc, vid_pid) - .composite_with_iads() - .strings(&[strings]) - .expect("Adding strings") - .max_packet_size_0(64) - .expect("set_packet_size") - .build(); - - defmt::debug!("Configuring radio..."); - board.radio.set_channel(dk::ieee802154::Channel::_20); - let current_channel = 20; - - let (msg_queue_in, msg_queue_out) = ctx.local.queue.split(); - - defmt::debug!("Building structures..."); - let shared = MySharedResources { - usb_serial, - usb_hid, - usb_device, - }; - let local = MyLocalResources { - radio: board.radio, - current_channel, - packet: dk::ieee802154::Packet::new(), - timer: board.timer, - rx_count: 0, - err_count: 0, - msg_queue_out, - msg_queue_in, - led: board.leds._1, - }; - - defmt::debug!("Init Complete!"); - - (shared, local) - } - - #[idle(local = [radio, current_channel, packet, timer, rx_count, err_count, msg_queue_out, led], shared = [usb_serial])] - fn idle(mut ctx: idle::Context) -> ! { - use core::fmt::Write as _; - let mut writer = Writer(|b: &[u8]| { - ctx.shared.usb_serial.lock(|usb_serial| { - let _ = usb_serial.write(b); - }) - }); - - defmt::info!( - "deviceid={=u32:08x}{=u32:08x} channel={=u8} TxPower=+8dBm app=loopback-fw", - dk::deviceid1(), - dk::deviceid0(), - ctx.local.current_channel - ); - - loop { - while let Some(msg) = ctx.local.msg_queue_out.dequeue() { - match msg { - Message::WantInfo => { - defmt::info!( - "rx={=u32}, err={=u32}, ch={=u8}, app=loopback-fw", - ctx.local.rx_count, - ctx.local.err_count, - ctx.local.current_channel - ); - let _ = writeln!( - writer, - "\nrx={}, err={}, ch={}, app=loopback-fw", - ctx.local.rx_count, ctx.local.err_count, ctx.local.current_channel - ); - } - Message::ChangeChannel(n) => { - defmt::info!("Changing Channel to {}", n); - let _ = writeln!(writer, "\nChanging Channel to {}", n); - match n { - 11 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_11); - } - 12 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_12); - } - 13 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_13); - } - 14 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_14); - } - 15 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_15); - } - 16 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_16); - } - 17 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_17); - } - 18 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_18); - } - 19 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_19); - } - 20 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_20); - } - 21 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_21); - } - 22 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_22); - } - 23 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_23); - } - 24 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_24); - } - 25 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_25); - } - 26 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_26); - } - _ => { - defmt::info!("Bad Channel {}!", n); - } - } - } - } - } - - defmt::debug!("Waiting for packet.."); - match ctx.local.radio.recv_timeout( - &mut ctx.local.packet, - &mut ctx.local.timer, - 1_000_000, - ) { - Ok(crc) => { - ctx.local.led.toggle(); - defmt::info!( - "Received {=u8} bytes (CRC=0x{=u16:04x}, LQI={})", - ctx.local.packet.len(), - crc, - ctx.local.packet.lqi(), - ); - let _ = writeln!( - writer, - "\nReceived {} bytes (CRC=0x{:04x}, LQI={})", - ctx.local.packet.len(), - crc, - ctx.local.packet.lqi(), - ); - *ctx.local.rx_count += 1; - // reverse the bytes, so olleh -> hello - ctx.local.packet.reverse(); - // send packet after 5ms (we know the client waits for 10ms and - // we want to ensure they are definitely in receive mode by the - // time we send this reply) - ctx.local.timer.delay(5000); - ctx.local.radio.send(ctx.local.packet); - } - Err(dk::ieee802154::Error::Crc(_)) => { - defmt::debug!("RX fail!"); - let _ = write!(writer, "!"); - *ctx.local.err_count += 1; - } - Err(dk::ieee802154::Error::Timeout) => { - defmt::debug!("RX timeout..."); - let _ = write!(writer, "."); - } - } - } - } - - /// USB Interrupt Handler - /// - /// USB Device is set to fire this whenever there's a Start of Frame from - /// the USB Host. - #[task(binds = USBD, local = [msg_queue_in], shared = [usb_serial, usb_hid, usb_device])] - fn usb_isr(mut ctx: usb_isr::Context) { - let mut all = ( - &mut ctx.shared.usb_serial, - &mut ctx.shared.usb_hid, - &mut ctx.shared.usb_device, - ); - all.lock(|usb_serial, usb_hid, usb_device| { - if usb_device.poll(&mut [usb_serial, usb_hid]) { - let mut buffer = [0u8; 64]; - if let Ok(n) = usb_serial.read(&mut buffer) { - if n > 0 { - for b in &buffer[0..n] { - if *b == b'?' { - // User pressed "?" in the terminal - _ = ctx.local.msg_queue_in.enqueue(Message::WantInfo); - } - } - } - } - if let Ok(n) = usb_hid.pull_raw_output(&mut buffer) { - // Linux sends 1 byte, Windows sends 64 (with 63 zero bytes) - if n == 1 || n == 64 { - _ = ctx - .local - .msg_queue_in - .enqueue(Message::ChangeChannel(buffer[0])); - } - } - } - }); - } -} - -#[panic_handler] -fn panic(info: &core::panic::PanicInfo) -> ! { - if let Some(location) = info.location() { - defmt::error!("Panic at {}:{}", location.file(), location.line()); - } else { - defmt::error!("Panic at unknown location"); - } - loop { - core::hint::spin_loop(); - } -} - -defmt::timestamp!("{=u64:tus}", dk::uptime_us()); diff --git a/nrf52-code/loopback-fw/.cargo/config.toml b/nrf52-code/loopback-fw/.cargo/config.toml index 51849431..89475d21 100644 --- a/nrf52-code/loopback-fw/.cargo/config.toml +++ b/nrf52-code/loopback-fw/.cargo/config.toml @@ -1,9 +1,10 @@ [target.thumbv7em-none-eabihf] -# set custom cargo runner to DFU the dongle +# set custom cargo runner to flash & run on embedded target when we call `cargo run` +# for more information, check out https://github.com/probe-rs runner = "nrfdfu" +linker = "flip-link" # adds stack overflow protection rustflags = [ "-C", "link-arg=-Tlink.x", # use the cortex-m-rt linker script - "-C", "linker=flip-link", # adds stack overflow protection "-C", "link-arg=-Tdefmt.x", # defmt support ] diff --git a/nrf52-code/loopback-fw/Cargo.lock b/nrf52-code/loopback-fw/Cargo.lock index 05da8a29..6cc3a835 100644 --- a/nrf52-code/loopback-fw/Cargo.lock +++ b/nrf52-code/loopback-fw/Cargo.lock @@ -29,6 +29,12 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + [[package]] name = "bitfield" version = "0.13.2" @@ -81,7 +87,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" dependencies = [ - "bare-metal", + "bare-metal 0.2.5", "bitfield 0.13.2", "critical-section", "embedded-hal 0.2.7", @@ -213,6 +219,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + [[package]] name = "embedded-io" version = "0.6.1" @@ -231,6 +246,12 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fixed" version = "1.28.0" @@ -244,16 +265,44 @@ dependencies = [ ] [[package]] -name = "getrandom" -version = "0.2.15" +name = "fugit" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" dependencies = [ - "cfg-if", - "libc", - "wasi", + "gcd", ] +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + [[package]] name = "grounded" version = "0.2.0" @@ -291,21 +340,32 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "heapless" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ + "defmt", "hash32", "stable_deref_trait", ] [[package]] -name = "libc" -version = "0.2.167" +name = "indexmap" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", +] [[package]] name = "log" @@ -318,12 +378,12 @@ name = "loopback-fw" version = "0.0.0" dependencies = [ "consts", - "cortex-m", - "cortex-m-rt", - "critical-section", + "defmt", + "defmt-rtt", "dongle", - "embedded-hal 1.0.0", - "rand", + "heapless", + "rtic", + "rtic-monotonics", "usb-device", "usbd-hid", "usbd-serial", @@ -416,19 +476,22 @@ dependencies = [ ] [[package]] -name = "portable-atomic" -version = "1.10.0" +name = "pin-project-lite" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] -name = "ppv-lite86" -version = "0.2.20" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "proc-macro-error-attr2" @@ -471,33 +534,78 @@ dependencies = [ ] [[package]] -name = "rand" -version = "0.8.5" +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rtic" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "401961431a1e491124cdd216a313fada2d395aa2b5bee2867c872fc8af7c1bc1" dependencies = [ - "libc", - "rand_chacha", - "rand_core", + "bare-metal 1.0.0", + "cortex-m", + "critical-section", + "portable-atomic", + "rtic-core", + "rtic-macros", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "rtic-common" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c" dependencies = [ - "ppv-lite86", - "rand_core", + "critical-section", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "rtic-core" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" + +[[package]] +name = "rtic-macros" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac22ab522d80079b48f46ac66ded4d349e1adf81b52430d6a74faa3a7790ed80" dependencies = [ - "getrandom", + "indexmap", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "rtic-monotonics" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1cb90bcfdbbacf3ca37340cdab52ec2de5611c744095ef7889e9c50c233b748" +dependencies = [ + "cfg-if", + "cortex-m", + "fugit", + "portable-atomic", + "rtic-time", +] + +[[package]] +name = "rtic-time" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7b1d853fa50dc125695414ce4510567a0d420221e455b1568cfa8c9aece9614" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", + "embedded-hal-async", + "fugit", + "futures-util", + "rtic-common", ] [[package]] @@ -526,18 +634,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -584,18 +692,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.4" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.4" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" dependencies = [ "proc-macro2", "quote", @@ -620,6 +728,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" dependencies = [ + "defmt", "heapless", "portable-atomic", ] @@ -630,6 +739,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c" dependencies = [ + "defmt", "serde", "ssmarshal", "usb-device", @@ -652,7 +762,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38" dependencies = [ "byteorder", - "hashbrown", + "hashbrown 0.13.2", "log", "proc-macro2", "quote", @@ -700,19 +810,12 @@ dependencies = [ "vcell", ] -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "byteorder", "zerocopy-derive", ] diff --git a/nrf52-code/loopback-fw/Cargo.toml b/nrf52-code/loopback-fw/Cargo.toml index 4fad8c8f..3ad226e0 100644 --- a/nrf52-code/loopback-fw/Cargo.toml +++ b/nrf52-code/loopback-fw/Cargo.toml @@ -7,33 +7,12 @@ version = "0.0.0" [dependencies] consts = { path = "../consts" } -cortex-m = {version = "0.7.7", features = ["critical-section-single-core"]} -cortex-m-rt = "0.7.5" -critical-section = "1.2.0" +defmt = "0.3.10" +defmt-rtt = "0.4.1" dongle = { path = "../boards/dongle" } -embedded-hal = "1.0" -usb-device = "0.3" -usbd-hid = "0.8" -usbd-serial = "0.2" - -[build-dependencies] -rand = "0.8.5" - -# optimize code in both profiles -[profile.dev] -codegen-units = 1 -debug = 2 -debug-assertions = true # ! -incremental = false -lto = "fat" -opt-level = 'z' # ! -overflow-checks = false - -[profile.release] -codegen-units = 1 -debug = 2 -debug-assertions = false -incremental = false -lto = "fat" -opt-level = 3 -overflow-checks = false +heapless = { version = "0.8.0", features = ["defmt-03"] } +rtic = { version = "2.1.2", features = ["thumbv7-backend"] } +rtic-monotonics = { version = "2.0.3", features = ["cortex-m-systick"] } +usb-device = { version = "0.3.2", features = ["defmt"] } +usbd-hid = { version = "0.8.2", features = ["defmt"] } +usbd-serial = "0.2.2" diff --git a/nrf52-code/loopback-fw/src/main.rs b/nrf52-code/loopback-fw/src/main.rs index 002e58be..c8f512f4 100644 --- a/nrf52-code/loopback-fw/src/main.rs +++ b/nrf52-code/loopback-fw/src/main.rs @@ -2,313 +2,392 @@ //! //! Sets up a USB Serial port and listens for radio packets. -#![no_std] #![no_main] +#![no_std] -use core::fmt::Write; -use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; - -use cortex_m_rt::entry; -use usb_device::class_prelude::UsbBusAllocator; -use usb_device::device::{StringDescriptors, UsbDevice, UsbDeviceBuilder, UsbVidPid}; -use usb_device::LangID; -use usbd_hid::hid_class::HIDClass; -use usbd_serial::SerialPort; - -use dongle::peripheral::interrupt; -use dongle::{ - hal::usbd, - ieee802154::{Channel, Packet}, - GlobalIrqState, LocalIrqState, UsbBus, -}; - -/// A buffer for holding bytes we want to send to the USB Serial port -static RING_BUFFER: dongle::Ringbuffer = dongle::Ringbuffer::new(); - -/// The USB Device Driver (owned by the USBD interrupt). -static USB_DEVICE: GlobalIrqState> = GlobalIrqState::new(); - -/// The USB Serial Device Driver (owned by the USBD interrupt). -static USB_SERIAL: GlobalIrqState> = GlobalIrqState::new(); - -/// The USB Human Interface Device Driver (owned by the USBD interrupt). -static USB_HID: GlobalIrqState> = GlobalIrqState::new(); - -/// Track how many CRC successes we had receiving radio packets -static RX_COUNT: AtomicU32 = AtomicU32::new(0); - -/// Track how many CRC failures we had receiving radio packets -static ERR_COUNT: AtomicU32 = AtomicU32::new(0); - -/// The USB interrupt sets this to < u32::MAX when a new channel is sent over HID. -/// -/// The main loop handles it and sets it back to u32::MAX when processed. -static NEW_CHANNEL: AtomicU32 = AtomicU32::new(u32::MAX); - -/// Set to true when we get a ?. -/// -/// We print some info in response. -static WANT_INFO: AtomicBool = AtomicBool::new(false); - -#[entry] -fn main() -> ! { - // The USB Bus, statically allocated - static mut USB_BUS: Option> = None; - - let mut board = dongle::init().unwrap(); - - board.usbd.inten.modify(|_r, w| { - w.sof().set_bit(); - w - }); - - let usb_bus = UsbBusAllocator::new(usbd::Usbd::new(usbd::UsbPeripheral::new( - board.usbd, - board.clocks, - ))); - USB_BUS.replace(usb_bus); - - // Grab a reference to the USB Bus allocator. We are promising to the - // compiler not to take mutable access to this global variable whilst this - // reference exists! - let bus_ref = USB_BUS.as_ref().unwrap(); +use defmt_rtt as _; + +#[rtic::app(device = dongle, peripherals = false)] +mod app { + use core::mem::MaybeUninit; + use rtic_monotonics::systick::prelude::*; + const QUEUE_LEN: usize = 8; + + systick_monotonic!(Mono, 100); + + /// An adapter that lets us writeln! into any closure that takes a byte. + /// + /// This is useful if writing a byte requires taking a lock, and you don't + /// want to hold the lock for the duration of the write. + struct Writer(F) + where + F: FnMut(&[u8]); + + impl core::fmt::Write for Writer + where + F: FnMut(&[u8]), + { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + (self.0)(s.as_bytes()); + Ok(()) + } + } - USB_SERIAL.load(SerialPort::new(bus_ref)); + #[local] + struct MyLocalResources { + /// The radio subsystem + radio: dongle::ieee802154::Radio<'static>, + /// Which channel are we on + current_channel: u8, + /// Holds one package, for receive or transmit + packet: dongle::ieee802154::Packet, + /// Used to measure elapsed time + timer: dongle::Timer, + /// How many packets have been received OK? + rx_count: u32, + /// How many packets have been received with errors? + err_count: u32, + /// A place to read the message queue + msg_queue_out: heapless::spsc::Consumer<'static, Message, QUEUE_LEN>, + /// A place to write to the message queue + msg_queue_in: heapless::spsc::Producer<'static, Message, QUEUE_LEN>, + /// A status LED + led: dongle::Led, + } - let desc = &[ - 0x06, 0x00, 0xFF, // Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xA1, 0x01, // Item(Main ): Collection, data= [ 0x01 ] 1 - // Application - 0x15, 0x00, // Item(Global): Logical Minimum, data= [ 0x00 ] 0 - 0x26, 0xFF, 0x00, // Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 - 0x75, 0x08, // Item(Global): Report Size, data= [ 0x08 ] 8 - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x81, 0x02, // Item(Main ): Input, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x91, 0x02, // Item(Main ): Output, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x01, // Item(Global): Report Count, data= [ 0x01 ] 1 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xB1, 0x02, // Item(Main ): Feature, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0xC0, // Item(Main ): End Collection, data=none - ]; - USB_HID.load(HIDClass::new(bus_ref, desc, 100)); + #[derive(Debug, defmt::Format, Copy, Clone, PartialEq, Eq)] + enum Message { + ChangeChannel(u8), + WantInfo, + } - let strings = StringDescriptors::new(LangID::EN) - .manufacturer("Ferrous Systems") - .product("Dongle Puzzle"); + #[shared] + struct MySharedResources { + /// Handles the USB Serial interface, including a ring buffer + usb_serial: usbd_serial::SerialPort<'static, dongle::UsbBus>, + /// Handles the USB HID interface + usb_hid: usbd_hid::hid_class::HIDClass<'static, dongle::UsbBus>, + /// Handles the lower-level USB Device interface + usb_device: usb_device::device::UsbDevice<'static, dongle::UsbBus>, + } - let vid_pid = UsbVidPid(consts::USB_VID_DEMO, consts::USB_PID_DONGLE_LOOPBACK); - // See https://www.usb.org/sites/default/files/iadclasscode_r10.pdf - // and https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-interface-association-descriptor - USB_DEVICE.load( - UsbDeviceBuilder::new(bus_ref, vid_pid) + #[init(local = [ + usb_alloc: MaybeUninit> = MaybeUninit::uninit(), + queue: heapless::spsc::Queue = heapless::spsc::Queue::new(), + ])] + fn init(ctx: init::Context) -> (MySharedResources, MyLocalResources) { + let mut board = dongle::init().unwrap(); + Mono::start(ctx.core.SYST, 64_000_000); + + defmt::debug!("Enabling interrupts..."); + board.usbd.inten.modify(|_r, w| { + w.sof().set_bit(); + w + }); + + defmt::debug!("Building USB allocator..."); + let usbd = dongle::UsbBus::new(dongle::hal::usbd::UsbPeripheral::new( + board.usbd, + board.clocks, + )); + let usb_alloc = ctx + .local + .usb_alloc + .write(usb_device::bus::UsbBusAllocator::new(usbd)); + + defmt::debug!("Creating usb_serial..."); + let usb_serial = usbd_serial::SerialPort::new(usb_alloc); + + defmt::debug!("Creating usb_hid..."); + let desc = &[ + 0x06, 0x00, 0xFF, // Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0xA1, 0x01, // Item(Main ): Collection, data= [ 0x01 ] 1 + // Application + 0x15, 0x00, // Item(Global): Logical Minimum, data= [ 0x00 ] 0 + 0x26, 0xFF, 0x00, // Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + 0x75, 0x08, // Item(Global): Report Size, data= [ 0x08 ] 8 + 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0x81, 0x02, // Item(Main ): Input, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0x91, 0x02, // Item(Main ): Output, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0x95, 0x01, // Item(Global): Report Count, data= [ 0x01 ] 1 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0xB1, 0x02, // Item(Main ): Feature, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0xC0, // Item(Main ): End Collection, data=none + ]; + let usb_hid = usbd_hid::hid_class::HIDClass::new(usb_alloc, desc, 100); + + defmt::debug!("Building USB Strings..."); + let strings = usb_device::device::StringDescriptors::new(usb_device::LangID::EN) + .manufacturer("Ferrous Systems") + .product("Test Device"); + + defmt::debug!("Building VID and PID..."); + let vid_pid = + usb_device::device::UsbVidPid(consts::USB_VID_DEMO, consts::USB_PID_DONGLE_LOOPBACK); + + defmt::debug!("Building USB Device..."); + let usb_device = usb_device::device::UsbDeviceBuilder::new(usb_alloc, vid_pid) .composite_with_iads() .strings(&[strings]) - .expect("adding strings") - // (makes control transfers 8x faster) + .expect("Adding strings") .max_packet_size_0(64) - .expect("set packet size") - .build(), - ); + .expect("set_packet_size") + .build(); - let mut current_ch_id = 20; - board.radio.set_channel(dongle::ieee802154::Channel::_20); + defmt::debug!("Configuring radio..."); + board.radio.set_channel(dongle::ieee802154::Channel::_20); + let current_channel = 20; - // Turn on USB interrupts... - unsafe { - cortex_m::peripheral::NVIC::unmask(dongle::peripheral::Interrupt::USBD); - }; + let (msg_queue_in, msg_queue_out) = ctx.local.queue.split(); - let _ = writeln!( - &RING_BUFFER, - "deviceid={:08x}{:08x} channel={} TxPower=+8dBm app=loopback-fw", - dongle::deviceid1(), - dongle::deviceid0(), - current_ch_id - ); - - board.leds.ld1.on(); - board.leds.ld2_blue.on(); - let mut pkt = Packet::new(); - loop { - // Wait up to 1 second for a radio packet - match board - .radio - .recv_timeout(&mut pkt, &mut board.timer, 1_000_000) - { - Ok(crc) => { - board.leds.ld1.toggle(); - let _ = writeln!( - &RING_BUFFER, - "received {} bytes (CRC=Ok(0x{:04x}), LQI={})", - pkt.len(), - crc, - pkt.lqi() - ); - // reverse the bytes, so olleh -> hello - pkt.reverse(); - // send packet after 5ms (we know the client waits for 10ms and - // we want to ensure they are definitely in receive mode by the - // time we send this reply) - board.timer.delay(5000); - board.radio.send(&mut pkt); - RX_COUNT.fetch_add(1, Ordering::Relaxed); - } - Err(dongle::ieee802154::Error::Crc(_)) => { - ERR_COUNT.fetch_add(1, Ordering::Relaxed); - } - Err(dongle::ieee802154::Error::Timeout) => { - // do nothing - } - } + defmt::debug!("Building structures..."); + let shared = MySharedResources { + usb_serial, + usb_hid, + usb_device, + }; + let local = MyLocalResources { + radio: board.radio, + current_channel, + packet: dongle::ieee802154::Packet::new(), + timer: board.timer, + rx_count: 0, + err_count: 0, + msg_queue_out, + msg_queue_in, + led: board.leds.ld1, + }; - // Handle channel changes - let ch_id = NEW_CHANNEL.load(Ordering::Relaxed); - if ch_id != u32::MAX { - NEW_CHANNEL.store(u32::MAX, Ordering::Relaxed); - if let Some(channel) = match ch_id { - 11 => Some(Channel::_11), - 12 => Some(Channel::_12), - 13 => Some(Channel::_13), - 14 => Some(Channel::_14), - 15 => Some(Channel::_15), - 16 => Some(Channel::_16), - 17 => Some(Channel::_17), - 18 => Some(Channel::_18), - 19 => Some(Channel::_19), - 20 => Some(Channel::_20), - 21 => Some(Channel::_21), - 22 => Some(Channel::_22), - 23 => Some(Channel::_23), - 24 => Some(Channel::_24), - 25 => Some(Channel::_25), - 26 => Some(Channel::_26), - _ => None, - } { - board.radio.set_channel(channel); - let _ = writeln!(&RING_BUFFER, "now listening on channel {}", ch_id); - current_ch_id = ch_id; - } else { - let _ = writeln!(&RING_BUFFER, "Channel {} invalid", ch_id); - } - } + defmt::debug!("Init Complete!"); - // Print help text when ? is pressed - if WANT_INFO.load(Ordering::Relaxed) { - WANT_INFO.store(false, Ordering::Relaxed); - let _ = writeln!( - &RING_BUFFER, - "rx={}, err={}, ch={}, app=loopback-fw", - RX_COUNT.load(Ordering::Relaxed), - ERR_COUNT.load(Ordering::Relaxed), - current_ch_id, - ); - } + (shared, local) } -} - -/// Handles USB interrupts -/// -/// Polls all the USB devices, and copies bytes from [`RING_BUFFER`] into the -/// USB UART. -#[interrupt] -fn USBD() { - static mut LOCAL_USB_DEVICE: LocalIrqState> = LocalIrqState::new(); - static mut LOCAL_USB_SERIAL: LocalIrqState> = LocalIrqState::new(); - static mut LOCAL_USB_HID: LocalIrqState> = LocalIrqState::new(); - static mut IS_PENDING: Option = None; - // Grab a reference to our local vars, moving the object out of the global as required... - let usb_dev = LOCAL_USB_DEVICE.get_or_init_with(&USB_DEVICE); - let serial = LOCAL_USB_SERIAL.get_or_init_with(&USB_SERIAL); - let hid = LOCAL_USB_HID.get_or_init_with(&USB_HID); + #[idle(local = [radio, current_channel, packet, timer, rx_count, err_count, msg_queue_out, led], shared = [usb_serial])] + fn idle(mut ctx: idle::Context) -> ! { + use core::fmt::Write as _; + let mut writer = Writer(|b: &[u8]| { + ctx.shared.usb_serial.lock(|usb_serial| { + let _ = usb_serial.write(b); + }) + }); + + defmt::info!( + "deviceid={=u32:08x}{=u32:08x} channel={=u8} TxPower=+8dBm app=loopback-fw", + dongle::deviceid1(), + dongle::deviceid0(), + ctx.local.current_channel + ); - let mut buf = [0u8; 64]; - - // Poll the USB driver with all of our supported USB Classes - if usb_dev.poll(&mut [serial, hid]) { - match serial.read(&mut buf) { - Err(_e) => { - // Do nothing - } - Ok(0) => { - // Do nothing - } - Ok(count) => { - for item in &buf[0..count] { - // Look for question marks - if *item == b'?' { - WANT_INFO.store(true, Ordering::Relaxed); + loop { + while let Some(msg) = ctx.local.msg_queue_out.dequeue() { + match msg { + Message::WantInfo => { + defmt::info!( + "rx={=u32}, err={=u32}, ch={=u8}, app=loopback-fw", + ctx.local.rx_count, + ctx.local.err_count, + ctx.local.current_channel + ); + let _ = writeln!( + writer, + "\nrx={}, err={}, ch={}, app=loopback-fw", + ctx.local.rx_count, ctx.local.err_count, ctx.local.current_channel + ); + } + Message::ChangeChannel(n) => { + defmt::info!("Changing Channel to {}", n); + let _ = writeln!(writer, "\nChanging Channel to {}", n); + match n { + 11 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_11); + } + 12 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_12); + } + 13 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_13); + } + 14 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_14); + } + 15 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_15); + } + 16 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_16); + } + 17 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_17); + } + 18 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_18); + } + 19 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_19); + } + 20 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_20); + } + 21 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_21); + } + 22 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_22); + } + 23 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_23); + } + 24 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_24); + } + 25 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_25); + } + 26 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_26); + } + _ => { + defmt::info!("Bad Channel {}!", n); + } + } } } } - } - let hid_byte = match hid.pull_raw_output(&mut buf) { - Ok(64) => { - // Windows zero-pads the packet - Some(buf[0]) - } - Ok(1) => { - // macOS/Linux sends a single byte - Some(buf[0]) - } - Ok(_n) => { - // Ignore any other size packet - None - } - Err(_e) => None, - }; - if let Some(ch) = hid_byte { - NEW_CHANNEL.store(ch as u32, Ordering::Relaxed); - } - } - // Is there a pending byte from last time? - if let Some(n) = IS_PENDING { - match serial.write(core::slice::from_ref(n)) { - Ok(_) => { - // it took our pending byte - *IS_PENDING = None; - } - Err(_) => { - // serial buffer is full - return; + defmt::debug!("Waiting for packet.."); + match ctx.local.radio.recv_timeout( + &mut ctx.local.packet, + &mut ctx.local.timer, + 1_000_000, + ) { + Ok(crc) => { + ctx.local.led.toggle(); + defmt::info!( + "Received {=u8} bytes (CRC=0x{=u16:04x}, LQI={})", + ctx.local.packet.len(), + crc, + ctx.local.packet.lqi(), + ); + let _ = writeln!( + writer, + "\nReceived {} bytes (CRC=0x{:04x}, LQI={})", + ctx.local.packet.len(), + crc, + ctx.local.packet.lqi(), + ); + *ctx.local.rx_count += 1; + // reverse the bytes, so olleh -> hello + ctx.local.packet.reverse(); + // send packet after 5ms (we know the client waits for 10ms and + // we want to ensure they are definitely in receive mode by the + // time we send this reply) + ctx.local.timer.delay(5000); + ctx.local.radio.send(ctx.local.packet); + } + Err(dongle::ieee802154::Error::Crc(_)) => { + defmt::debug!("RX fail!"); + let _ = write!(writer, "!"); + *ctx.local.err_count += 1; + } + Err(dongle::ieee802154::Error::Timeout) => { + defmt::debug!("RX timeout..."); + let _ = write!(writer, "."); + } } } } - // Copy some more from the ring-buffer to the USB Serial interface, - // until the serial interface is full. - while let Some(item) = RING_BUFFER.read() { - let s = &[item]; - if serial.write(s).is_err() { - // the USB UART can't take this byte right now - *IS_PENDING = Some(item); - break; - } + /// USB Interrupt Handler + /// + /// USB Device is set to fire this whenever there's a Start of Frame from + /// the USB Host. + #[task(binds = USBD, local = [msg_queue_in], shared = [usb_serial, usb_hid, usb_device])] + fn usb_isr(mut ctx: usb_isr::Context) { + let mut all = ( + &mut ctx.shared.usb_serial, + &mut ctx.shared.usb_hid, + &mut ctx.shared.usb_device, + ); + all.lock(|usb_serial, usb_hid, usb_device| { + if usb_device.poll(&mut [usb_serial, usb_hid]) { + let mut buffer = [0u8; 64]; + if let Ok(n) = usb_serial.read(&mut buffer) { + if n > 0 { + for b in &buffer[0..n] { + if *b == b'?' { + // User pressed "?" in the terminal + _ = ctx.local.msg_queue_in.enqueue(Message::WantInfo); + } + } + } + } + if let Ok(n) = usb_hid.pull_raw_output(&mut buffer) { + // Linux sends 1 byte, Windows sends 64 (with 63 zero bytes) + if n == 1 || n == 64 { + _ = ctx + .local + .msg_queue_in + .enqueue(Message::ChangeChannel(buffer[0])); + } + } + } + }); } - - cortex_m::asm::sev(); } #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { - let _ = writeln!(&RING_BUFFER, "Panic: {:?}", info); - cortex_m::asm::delay(64_000_000 * 2); - unsafe { - loop { - core::arch::asm!("bkpt 0x00"); - } + if let Some(location) = info.location() { + defmt::error!("Panic at {}:{}", location.file(), location.line()); + } else { + defmt::error!("Panic at unknown location"); + } + loop { + core::hint::spin_loop(); } } -// End of file +defmt::timestamp!("{=u64:tus}", dongle::uptime_us()); From f27c694c81bddf94f11003aa6b532d4ae0f870d2 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Thu, 12 Dec 2024 12:36:58 +0000 Subject: [PATCH 09/10] Switch puzzle-fw to use RTIC as well --- nrf52-code/boards/dongle/src/lib.rs | 45 -- nrf52-code/puzzle-fw/Cargo.lock | 176 +++++- nrf52-code/puzzle-fw/Cargo.toml | 35 +- nrf52-code/puzzle-fw/src/main.rs | 851 ++++++++++++++++------------ 4 files changed, 650 insertions(+), 457 deletions(-) diff --git a/nrf52-code/boards/dongle/src/lib.rs b/nrf52-code/boards/dongle/src/lib.rs index 4a0dc4c3..eb80b671 100644 --- a/nrf52-code/boards/dongle/src/lib.rs +++ b/nrf52-code/boards/dongle/src/lib.rs @@ -230,51 +230,6 @@ impl core::fmt::Write for &Ringbuffer { } } -/// The global type for sharing things with an interrupt handler -pub struct GlobalIrqState { - inner: critical_section::Mutex>>, -} - -impl GlobalIrqState { - /// Create a new, empty, object - pub const fn new() -> GlobalIrqState { - GlobalIrqState { - inner: critical_section::Mutex::new(core::cell::RefCell::new(None)), - } - } - - /// Load a value into the global - /// - /// Returns the old value, if any - pub fn load(&self, value: T) -> Option { - critical_section::with(|cs| self.inner.borrow(cs).replace(Some(value))) - } -} - -/// The local type for sharing things with an interrupt handler -pub struct LocalIrqState { - inner: Option, -} - -impl LocalIrqState { - /// Create a new, empty, object - pub const fn new() -> LocalIrqState { - LocalIrqState { inner: None } - } - - /// Grab a mutable reference to the contents. - /// - /// If the value is empty, the contents are taken from a mutex-locked global - /// variable. That global must have been initialised before calling this - /// function. If not, this function panics. - pub fn get_or_init_with(&mut self, global: &GlobalIrqState) -> &mut T { - let result = self.inner.get_or_insert_with(|| { - critical_section::with(|cs| global.inner.borrow(cs).replace(None).unwrap()) - }); - result - } -} - /// The ways that initialisation can fail #[derive(Debug, Copy, Clone, defmt::Format)] pub enum Error { diff --git a/nrf52-code/puzzle-fw/Cargo.lock b/nrf52-code/puzzle-fw/Cargo.lock index f6d1b7ae..4d2689a0 100644 --- a/nrf52-code/puzzle-fw/Cargo.lock +++ b/nrf52-code/puzzle-fw/Cargo.lock @@ -29,6 +29,12 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + [[package]] name = "bitfield" version = "0.13.2" @@ -81,7 +87,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" dependencies = [ - "bare-metal", + "bare-metal 0.2.5", "bitfield 0.13.2", "critical-section", "embedded-hal 0.2.7", @@ -213,6 +219,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + [[package]] name = "embedded-io" version = "0.6.1" @@ -231,6 +246,12 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fixed" version = "1.28.0" @@ -243,6 +264,45 @@ dependencies = [ "typenum", ] +[[package]] +name = "fugit" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" +dependencies = [ + "gcd", +] + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + [[package]] name = "getrandom" version = "0.2.15" @@ -291,21 +351,38 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "heapless" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ + "defmt", "hash32", "stable_deref_trait", ] +[[package]] +name = "indexmap" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", +] + [[package]] name = "libc" -version = "0.2.167" +version = "0.2.168" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d" [[package]] name = "log" @@ -399,6 +476,18 @@ dependencies = [ "defmt", ] +[[package]] +name = "pin-project-lite" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "portable-atomic" version = "1.10.0" @@ -450,13 +539,13 @@ name = "puzzle-fw" version = "0.0.0" dependencies = [ "consts", - "cortex-m", - "cortex-m-rt", - "critical-section", + "defmt", + "defmt-rtt", "dongle", - "embedded-hal 1.0.0", "heapless", "rand", + "rtic", + "rtic-monotonics", "usb-device", "usbd-hid", "usbd-serial", @@ -501,6 +590,75 @@ dependencies = [ "getrandom", ] +[[package]] +name = "rtic" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "401961431a1e491124cdd216a313fada2d395aa2b5bee2867c872fc8af7c1bc1" +dependencies = [ + "bare-metal 1.0.0", + "cortex-m", + "critical-section", + "portable-atomic", + "rtic-core", + "rtic-macros", +] + +[[package]] +name = "rtic-common" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c" +dependencies = [ + "critical-section", +] + +[[package]] +name = "rtic-core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" + +[[package]] +name = "rtic-macros" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac22ab522d80079b48f46ac66ded4d349e1adf81b52430d6a74faa3a7790ed80" +dependencies = [ + "indexmap", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "rtic-monotonics" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1cb90bcfdbbacf3ca37340cdab52ec2de5611c744095ef7889e9c50c233b748" +dependencies = [ + "cfg-if", + "cortex-m", + "fugit", + "portable-atomic", + "rtic-time", +] + +[[package]] +name = "rtic-time" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7b1d853fa50dc125695414ce4510567a0d420221e455b1568cfa8c9aece9614" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", + "embedded-hal-async", + "fugit", + "futures-util", + "rtic-common", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -621,6 +779,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" dependencies = [ + "defmt", "heapless", "portable-atomic", ] @@ -631,6 +790,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c" dependencies = [ + "defmt", "serde", "ssmarshal", "usb-device", @@ -653,7 +813,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38" dependencies = [ "byteorder", - "hashbrown", + "hashbrown 0.13.2", "log", "proc-macro2", "quote", diff --git a/nrf52-code/puzzle-fw/Cargo.toml b/nrf52-code/puzzle-fw/Cargo.toml index 20b7fa37..0669339e 100644 --- a/nrf52-code/puzzle-fw/Cargo.toml +++ b/nrf52-code/puzzle-fw/Cargo.toml @@ -7,34 +7,15 @@ version = "0.0.0" [dependencies] consts = { path = "../consts" } -cortex-m = {version = "0.7.7", features = ["critical-section-single-core"]} -cortex-m-rt = "0.7.5" -critical-section = "1.2.0" +defmt = "0.3.10" +defmt-rtt = "0.4.1" dongle = { path = "../boards/dongle" } -embedded-hal = "1.0" -heapless = "0.8" -usb-device = "0.3" -usbd-hid = "0.8" -usbd-serial = "0.2" +heapless = { version = "0.8.0", features = ["defmt-03"] } +rtic = { version = "2.1.2", features = ["thumbv7-backend"] } +rtic-monotonics = { version = "2.0.3", features = ["cortex-m-systick"] } +usb-device = { version = "0.3.2", features = ["defmt"] } +usbd-hid = { version = "0.8.2", features = ["defmt"] } +usbd-serial = "0.2.2" [build-dependencies] rand = "0.8.5" - -# optimize code in both profiles -[profile.dev] -codegen-units = 1 -debug = 2 -debug-assertions = true # ! -incremental = false -lto = "fat" -opt-level = 'z' # ! -overflow-checks = false - -[profile.release] -codegen-units = 1 -debug = 2 -debug-assertions = false -incremental = false -lto = "fat" -opt-level = 3 -overflow-checks = false diff --git a/nrf52-code/puzzle-fw/src/main.rs b/nrf52-code/puzzle-fw/src/main.rs index 9bfbc246..2bc3eed5 100644 --- a/nrf52-code/puzzle-fw/src/main.rs +++ b/nrf52-code/puzzle-fw/src/main.rs @@ -2,415 +2,512 @@ //! //! Sets up a USB Serial port and listens for radio packets. -#![no_std] #![no_main] +#![no_std] + +use defmt_rtt as _; + +#[rtic::app(device = dongle, peripherals = false)] +mod app { + use core::mem::MaybeUninit; + use rtic_monotonics::systick::prelude::*; + const QUEUE_LEN: usize = 8; + + /// The secret message, but encoded. + /// + /// We do this rather than the plaintext -- otherwise `strings $elf` will reveal the answer + static ENCODED_MESSAGE: &[u8] = + include_bytes!(concat!(env!("OUT_DIR"), "/ENCODED_MESSAGE.txt")); + + /// The plaintext side of the map + static PLAIN_LETTERS: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/PLAIN_LETTERS.txt")); + + /// The ciphertext side of the map + static CIPHER_LETTERS: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/CIPHER_LETTERS.txt")); + + /// How many address bytes we reflect back + const ADDR_BYTES: usize = 6; + + systick_monotonic!(Mono, 100); + + /// An adapter that lets us writeln! into any closure that takes a byte. + /// + /// This is useful if writing a byte requires taking a lock, and you don't + /// want to hold the lock for the duration of the write. + struct Writer(F) + where + F: FnMut(&[u8]); + + impl core::fmt::Write for Writer + where + F: FnMut(&[u8]), + { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + (self.0)(s.as_bytes()); + Ok(()) + } + } + + #[local] + struct MyLocalResources { + /// The radio subsystem + radio: dongle::ieee802154::Radio<'static>, + /// Which channel are we on + current_channel: u8, + /// Holds one package, for receive or transmit + packet: dongle::ieee802154::Packet, + /// Used to measure elapsed time + timer: dongle::Timer, + /// How many packets have been received OK? + rx_count: u32, + /// How many packets have been received with errors? + err_count: u32, + /// A place to read the message queue + msg_queue_out: heapless::spsc::Consumer<'static, Message, QUEUE_LEN>, + /// A place to write to the message queue + msg_queue_in: heapless::spsc::Producer<'static, Message, QUEUE_LEN>, + /// The status LEDs + leds: dongle::Leds, + } + + #[derive(Debug, defmt::Format, Copy, Clone, PartialEq, Eq)] + enum Message { + ChangeChannel(u8), + WantInfo, + } + + #[shared] + struct MySharedResources { + /// Handles the USB Serial interface, including a ring buffer + usb_serial: usbd_serial::SerialPort<'static, dongle::UsbBus>, + /// Handles the USB HID interface + usb_hid: usbd_hid::hid_class::HIDClass<'static, dongle::UsbBus>, + /// Handles the lower-level USB Device interface + usb_device: usb_device::device::UsbDevice<'static, dongle::UsbBus>, + } -use core::fmt::Write; -use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; - -use cortex_m_rt::entry; -use usb_device::class_prelude::UsbBusAllocator; -use usb_device::device::{StringDescriptors, UsbDevice, UsbDeviceBuilder, UsbVidPid}; -use usb_device::LangID; -use usbd_hid::hid_class::HIDClass; -use usbd_serial::SerialPort; - -use dongle::peripheral::interrupt; -use dongle::{ - hal::usbd, - ieee802154::{Channel, Packet}, - GlobalIrqState, LocalIrqState, UsbBus, -}; - -/// The secret message, but encoded. -/// -/// We do this rather than the plaintext -- otherwise `strings $elf` will reveal the answer -static ENCODED_MESSAGE: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/ENCODED_MESSAGE.txt")); - -/// The plaintext side of the map -static PLAIN_LETTERS: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/PLAIN_LETTERS.txt")); - -/// The ciphertext side of the map -static CIPHER_LETTERS: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/CIPHER_LETTERS.txt")); - -/// A buffer for holding bytes we want to send to the USB Serial port -static RING_BUFFER: dongle::Ringbuffer = dongle::Ringbuffer::new(); - -/// The USB Device Driver (owned by the USBD interrupt). -static USB_DEVICE: GlobalIrqState> = GlobalIrqState::new(); - -/// The USB Serial Device Driver (owned by the USBD interrupt). -static USB_SERIAL: GlobalIrqState> = GlobalIrqState::new(); - -/// The USB Human Interface Device Driver (owned by the USBD interrupt). -static USB_HID: GlobalIrqState> = GlobalIrqState::new(); - -/// Track how many CRC successes we had receiving radio packets -static RX_COUNT: AtomicU32 = AtomicU32::new(0); - -/// Track how many CRC failures we had receiving radio packets -static ERR_COUNT: AtomicU32 = AtomicU32::new(0); - -/// The USB interrupt sets this to < u32::MAX when a new channel is sent over HID. -/// -/// The main loop handles it and sets it back to u32::MAX when processed. -static NEW_CHANNEL: AtomicU32 = AtomicU32::new(u32::MAX); - -/// Set to true when we get a ?. -/// -/// We print some info in response. -static WANT_INFO: AtomicBool = AtomicBool::new(false); - -/// How many address bytes we reflect back -const ADDR_BYTES: usize = 6; - -#[entry] -fn main() -> ! { - // The USB Bus, statically allocated - static mut USB_BUS: Option> = None; - - let mut board = dongle::init().unwrap(); - - board.usbd.inten.modify(|_r, w| { - w.sof().set_bit(); - w - }); - - let usb_bus = UsbBusAllocator::new(usbd::Usbd::new(usbd::UsbPeripheral::new( - board.usbd, - board.clocks, - ))); - USB_BUS.replace(usb_bus); - - // Grab a reference to the USB Bus allocator. We are promising to the - // compiler not to take mutable access to this global variable whilst this - // reference exists! - let bus_ref = USB_BUS.as_ref().unwrap(); - - USB_SERIAL.load(SerialPort::new(bus_ref)); - - let desc = &[ - 0x06, 0x00, 0xFF, // Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xA1, 0x01, // Item(Main ): Collection, data= [ 0x01 ] 1 - // Application - 0x15, 0x00, // Item(Global): Logical Minimum, data= [ 0x00 ] 0 - 0x26, 0xFF, 0x00, // Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 - 0x75, 0x08, // Item(Global): Report Size, data= [ 0x08 ] 8 - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x81, 0x02, // Item(Main ): Input, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x91, 0x02, // Item(Main ): Output, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x01, // Item(Global): Report Count, data= [ 0x01 ] 1 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xB1, 0x02, // Item(Main ): Feature, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0xC0, // Item(Main ): End Collection, data=none - ]; - USB_HID.load(HIDClass::new(bus_ref, desc, 100)); - - let strings = StringDescriptors::new(LangID::EN) - .manufacturer("Ferrous Systems") - .product("Dongle Puzzle"); - - let vid_pid = UsbVidPid(consts::USB_VID_DEMO, consts::USB_PID_DONGLE_PUZZLE); - // See https://www.usb.org/sites/default/files/iadclasscode_r10.pdf - // and https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-interface-association-descriptor - USB_DEVICE.load( - UsbDeviceBuilder::new(bus_ref, vid_pid) + #[init(local = [ + usb_alloc: MaybeUninit> = MaybeUninit::uninit(), + queue: heapless::spsc::Queue = heapless::spsc::Queue::new(), + ])] + fn init(ctx: init::Context) -> (MySharedResources, MyLocalResources) { + let mut board = dongle::init().unwrap(); + Mono::start(ctx.core.SYST, 64_000_000); + + defmt::debug!("Enabling interrupts..."); + board.usbd.inten.modify(|_r, w| { + w.sof().set_bit(); + w + }); + + defmt::debug!("Building USB allocator..."); + let usbd = dongle::UsbBus::new(dongle::hal::usbd::UsbPeripheral::new( + board.usbd, + board.clocks, + )); + let usb_alloc = ctx + .local + .usb_alloc + .write(usb_device::bus::UsbBusAllocator::new(usbd)); + + defmt::debug!("Creating usb_serial..."); + let usb_serial = usbd_serial::SerialPort::new(usb_alloc); + + defmt::debug!("Creating usb_hid..."); + let desc = &[ + 0x06, 0x00, 0xFF, // Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0xA1, 0x01, // Item(Main ): Collection, data= [ 0x01 ] 1 + // Application + 0x15, 0x00, // Item(Global): Logical Minimum, data= [ 0x00 ] 0 + 0x26, 0xFF, 0x00, // Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + 0x75, 0x08, // Item(Global): Report Size, data= [ 0x08 ] 8 + 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0x81, 0x02, // Item(Main ): Input, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0x91, 0x02, // Item(Main ): Output, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0x95, 0x01, // Item(Global): Report Count, data= [ 0x01 ] 1 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0xB1, 0x02, // Item(Main ): Feature, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0xC0, // Item(Main ): End Collection, data=none + ]; + let usb_hid = usbd_hid::hid_class::HIDClass::new(usb_alloc, desc, 100); + + defmt::debug!("Building USB Strings..."); + let strings = usb_device::device::StringDescriptors::new(usb_device::LangID::EN) + .manufacturer("Ferrous Systems") + .product("Test Device"); + + defmt::debug!("Building VID and PID..."); + let vid_pid = + usb_device::device::UsbVidPid(consts::USB_VID_DEMO, consts::USB_PID_DONGLE_LOOPBACK); + + defmt::debug!("Building USB Device..."); + let usb_device = usb_device::device::UsbDeviceBuilder::new(usb_alloc, vid_pid) .composite_with_iads() .strings(&[strings]) - .expect("adding strings") - // (makes control transfers 8x faster) + .expect("Adding strings") .max_packet_size_0(64) - .expect("set packet size") - .build(), - ); - - let mut current_ch_id = 25; - board.radio.set_channel(dongle::ieee802154::Channel::_25); - - // Turn on USB interrupts... - unsafe { - cortex_m::peripheral::NVIC::unmask(dongle::peripheral::Interrupt::USBD); - }; - - let _ = writeln!( - &RING_BUFFER, - "deviceid={:08x}{:08x} channel={} TxPower=+8dBm app=puzzle-fw", - dongle::deviceid1(), - dongle::deviceid0(), - current_ch_id - ); - - board.leds.ld1.on(); - board.leds.ld2_green.on(); - - let mut dict: heapless::LinearMap = heapless::LinearMap::new(); - for (&plain, &cipher) in PLAIN_LETTERS.iter().zip(CIPHER_LETTERS.iter()) { - let _ = dict.insert(plain, cipher); + .expect("set_packet_size") + .build(); + + defmt::debug!("Configuring radio..."); + board.radio.set_channel(dongle::ieee802154::Channel::_25); + let current_channel = 25; + + let (msg_queue_in, msg_queue_out) = ctx.local.queue.split(); + + defmt::debug!("Building structures..."); + let shared = MySharedResources { + usb_serial, + usb_hid, + usb_device, + }; + let local = MyLocalResources { + radio: board.radio, + current_channel, + packet: dongle::ieee802154::Packet::new(), + timer: board.timer, + rx_count: 0, + err_count: 0, + msg_queue_out, + msg_queue_in, + leds: board.leds, + }; + + defmt::debug!("Init Complete!"); + + (shared, local) } - let mut pkt = Packet::new(); - loop { - // Wait up to 1 second for a radio packet - match board - .radio - .recv_timeout(&mut pkt, &mut board.timer, 1_000_000) - { - Ok(crc) => { - board.leds.ld1.toggle(); - let _ = writeln!( - &RING_BUFFER, - "\nRX CRC {:04x}, LQI {}, LEN {}", - crc, - pkt.lqi(), - pkt.len() - ); - let mut reply = true; - match handle_packet(&mut pkt, &dict) { - None => { - // not enough bytes - send nothing back - reply = false; + #[idle(local = [radio, current_channel, packet, timer, rx_count, err_count, msg_queue_out, leds], shared = [usb_serial])] + fn idle(mut ctx: idle::Context) -> ! { + use core::fmt::Write as _; + let mut writer = Writer(|b: &[u8]| { + ctx.shared.usb_serial.lock(|usb_serial| { + let _ = usb_serial.write(b); + }) + }); + + defmt::info!( + "deviceid={=u32:08x}{=u32:08x} channel={=u8} TxPower=+8dBm app=puzzle-fw", + dongle::deviceid1(), + dongle::deviceid0(), + ctx.local.current_channel + ); + + ctx.local.leds.ld1.on(); + ctx.local.leds.ld2_green.on(); + + let mut dict: heapless::LinearMap = heapless::LinearMap::new(); + for (&plain, &cipher) in PLAIN_LETTERS.iter().zip(CIPHER_LETTERS.iter()) { + let _ = dict.insert(plain, cipher); + } + + loop { + while let Some(msg) = ctx.local.msg_queue_out.dequeue() { + match msg { + Message::WantInfo => { + defmt::info!( + "rx={=u32}, err={=u32}, ch={=u8}, app=puzzle-fw", + ctx.local.rx_count, + ctx.local.err_count, + ctx.local.current_channel + ); + let _ = writeln!( + writer, + "\nrx={}, err={}, ch={}, app=puzzle-fw", + ctx.local.rx_count, ctx.local.err_count, ctx.local.current_channel + ); } - Some(Command::SendSecret) => { - pkt.set_len(ENCODED_MESSAGE.len() as u8 + ADDR_BYTES as u8); - for (src, dest) in ENCODED_MESSAGE.iter().zip(&mut pkt[ADDR_BYTES..]) { - *dest = *src; + Message::ChangeChannel(n) => { + defmt::info!("Changing Channel to {}", n); + let _ = writeln!(writer, "\nChanging Channel to {}", n); + match n { + 11 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_11); + } + 12 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_12); + } + 13 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_13); + } + 14 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_14); + } + 15 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_15); + } + 16 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_16); + } + 17 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_17); + } + 18 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_18); + } + 19 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_19); + } + 20 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_20); + } + 21 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_21); + } + 22 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_22); + } + 23 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_23); + } + 24 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_24); + } + 25 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_25); + } + 26 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_26); + } + _ => { + defmt::info!("Bad Channel {}!", n); + } } - let _ = writeln!(&RING_BUFFER, "TX Secret"); - board.leds.ld2_blue.on(); - board.leds.ld2_green.off(); - board.leds.ld2_red.off(); - } - Some(Command::MapChar(plain, cipher)) => { - pkt.set_len(1 + ADDR_BYTES as u8); - pkt[ADDR_BYTES] = cipher; - let _ = writeln!(&RING_BUFFER, "TX Map({plain}) => {cipher}"); - board.leds.ld2_blue.off(); - board.leds.ld2_green.on(); - board.leds.ld2_red.off(); } - Some(Command::Correct) => { - let message = b"correct"; - pkt.set_len(message.len() as u8 + ADDR_BYTES as u8); - for (src, dest) in message.iter().zip(&mut pkt[ADDR_BYTES..]) { - *dest = *src; + } + } + + defmt::debug!("Waiting for packet.."); + match ctx + .local + .radio + .recv_timeout(ctx.local.packet, ctx.local.timer, 1_000_000) + { + Ok(crc) => { + ctx.local.leds.ld1.toggle(); + defmt::info!( + "Received {=u8} bytes (CRC=0x{=u16:04x}, LQI={})", + ctx.local.packet.len(), + crc, + ctx.local.packet.lqi(), + ); + let _ = writeln!( + writer, + "\nReceived {} bytes (CRC=0x{:04x}, LQI={})", + ctx.local.packet.len(), + crc, + ctx.local.packet.lqi(), + ); + *ctx.local.rx_count += 1; + let mut reply = true; + match handle_packet(ctx.local.packet, &dict) { + None => { + // not enough bytes - send nothing back + reply = false; } - let _ = writeln!(&RING_BUFFER, "TX Correct"); - board.leds.ld2_blue.on(); - board.leds.ld2_green.on(); - board.leds.ld2_red.on(); - } - Some(Command::Wrong) => { - let message = b"incorrect"; - pkt.set_len(message.len() as u8 + ADDR_BYTES as u8); - for (src, dest) in message.iter().zip(&mut pkt[ADDR_BYTES..]) { - *dest = *src; + Some(Command::SendSecret) => { + ctx.local + .packet + .set_len(ENCODED_MESSAGE.len() as u8 + ADDR_BYTES as u8); + for (src, dest) in ENCODED_MESSAGE + .iter() + .zip(&mut ctx.local.packet[ADDR_BYTES..]) + { + *dest = *src; + } + let _ = writeln!(writer, "TX Secret"); + ctx.local.leds.ld2_blue.on(); + ctx.local.leds.ld2_green.off(); + ctx.local.leds.ld2_red.off(); + } + Some(Command::MapChar(plain, cipher)) => { + ctx.local.packet.set_len(1 + ADDR_BYTES as u8); + ctx.local.packet[ADDR_BYTES] = cipher; + let _ = writeln!(writer, "TX Map({plain}) => {cipher}"); + ctx.local.leds.ld2_blue.off(); + ctx.local.leds.ld2_green.on(); + ctx.local.leds.ld2_red.off(); + } + Some(Command::Correct) => { + let message = b"correct"; + ctx.local + .packet + .set_len(message.len() as u8 + ADDR_BYTES as u8); + for (src, dest) in + message.iter().zip(&mut ctx.local.packet[ADDR_BYTES..]) + { + *dest = *src; + } + let _ = writeln!(writer, "TX Correct"); + ctx.local.leds.ld2_blue.on(); + ctx.local.leds.ld2_green.on(); + ctx.local.leds.ld2_red.on(); + } + Some(Command::Wrong) => { + let message = b"incorrect"; + ctx.local + .packet + .set_len(message.len() as u8 + ADDR_BYTES as u8); + for (src, dest) in + message.iter().zip(&mut ctx.local.packet[ADDR_BYTES..]) + { + *dest = *src; + } + let _ = writeln!(writer, "TX Incorrect"); + ctx.local.leds.ld2_blue.off(); + ctx.local.leds.ld2_green.on(); + ctx.local.leds.ld2_red.on(); } - let _ = writeln!(&RING_BUFFER, "TX Incorrect"); - board.leds.ld2_blue.off(); - board.leds.ld2_green.on(); - board.leds.ld2_red.on(); + } + // send packet after 500us (we know the client waits for 10ms and + // we want to ensure they are definitely in receive mode by the + // time we send this reply) + if reply { + ctx.local.timer.delay(500); + ctx.local.radio.send(ctx.local.packet); } } - // send packet after 500us (we know the client waits for 10ms and - // we want to ensure they are definitely in receive mode by the - // time we send this reply) - if reply { - board.timer.delay(500); - board.radio.send(&mut pkt); + Err(dongle::ieee802154::Error::Crc(_)) => { + defmt::debug!("RX fail!"); + let _ = write!(writer, "!"); + *ctx.local.err_count += 1; + } + Err(dongle::ieee802154::Error::Timeout) => { + defmt::debug!("RX timeout..."); + let _ = write!(writer, "."); } - RX_COUNT.fetch_add(1, Ordering::Relaxed); - } - Err(dongle::ieee802154::Error::Crc(_)) => { - ERR_COUNT.fetch_add(1, Ordering::Relaxed); - } - Err(dongle::ieee802154::Error::Timeout) => { - // Show that we are alive - let _ = write!(&RING_BUFFER, "."); - } - } - - // Handle channel changes - let ch_id = NEW_CHANNEL.load(Ordering::Relaxed); - if ch_id != u32::MAX { - NEW_CHANNEL.store(u32::MAX, Ordering::Relaxed); - if let Some(channel) = match ch_id { - 11 => Some(Channel::_11), - 12 => Some(Channel::_12), - 13 => Some(Channel::_13), - 14 => Some(Channel::_14), - 15 => Some(Channel::_15), - 16 => Some(Channel::_16), - 17 => Some(Channel::_17), - 18 => Some(Channel::_18), - 19 => Some(Channel::_19), - 20 => Some(Channel::_20), - 21 => Some(Channel::_21), - 22 => Some(Channel::_22), - 23 => Some(Channel::_23), - 24 => Some(Channel::_24), - 25 => Some(Channel::_25), - 26 => Some(Channel::_26), - _ => None, - } { - board.radio.set_channel(channel); - let _ = writeln!(&RING_BUFFER, "now listening on channel {}", ch_id); - current_ch_id = ch_id; - } else { - let _ = writeln!(&RING_BUFFER, "Channel {} invalid", ch_id); - } - } - - // Print help text when ? is pressed - if WANT_INFO.load(Ordering::Relaxed) { - WANT_INFO.store(false, Ordering::Relaxed); - let _ = writeln!( - &RING_BUFFER, - "rx={}, err={}, ch={}, app=puzzle-fw", - RX_COUNT.load(Ordering::Relaxed), - ERR_COUNT.load(Ordering::Relaxed), - current_ch_id, - ); - } - } -} - -enum Command { - SendSecret, - MapChar(u8, u8), - Correct, - Wrong, -} - -fn handle_packet(packet: &mut Packet, dict: &heapless::LinearMap) -> Option { - let payload = packet.get_mut(ADDR_BYTES..)?; - if payload.len() == 0 { - Some(Command::SendSecret) - } else if payload.len() == 1 { - // They give us plaintext, we give them ciphertext - let plain = payload[0]; - let cipher = *dict.get(&plain).unwrap_or(&0); - Some(Command::MapChar(plain, cipher)) - } else { - // They give us plaintext, we tell them if it is correct - // Encrypt every byte of plaintext they give us - for slot in payload.iter_mut() { - if let Some(c) = dict.get(slot) { - *slot = *c; - } else { - *slot = 0; } } - if &payload[..] == ENCODED_MESSAGE { - Some(Command::Correct) - } else { - Some(Command::Wrong) - } } -} -/// Handles USB interrupts -/// -/// Polls all the USB devices, and copies bytes from [`RING_BUFFER`] into the -/// USB UART. -#[interrupt] -fn USBD() { - static mut LOCAL_USB_DEVICE: LocalIrqState> = LocalIrqState::new(); - static mut LOCAL_USB_SERIAL: LocalIrqState> = LocalIrqState::new(); - static mut LOCAL_USB_HID: LocalIrqState> = LocalIrqState::new(); - static mut IS_PENDING: Option = None; - - // Grab a reference to our local vars, moving the object out of the global as required... - let usb_dev = LOCAL_USB_DEVICE.get_or_init_with(&USB_DEVICE); - let serial = LOCAL_USB_SERIAL.get_or_init_with(&USB_SERIAL); - let hid = LOCAL_USB_HID.get_or_init_with(&USB_HID); - - let mut buf = [0u8; 64]; - - // Poll the USB driver with all of our supported USB Classes - if usb_dev.poll(&mut [serial, hid]) { - match serial.read(&mut buf) { - Err(_e) => { - // Do nothing - } - Ok(0) => { - // Do nothing - } - Ok(count) => { - for item in &buf[0..count] { - // Look for question marks - if *item == b'?' { - WANT_INFO.store(true, Ordering::Relaxed); + /// USB Interrupt Handler + /// + /// USB Device is set to fire this whenever there's a Start of Frame from + /// the USB Host. + #[task(binds = USBD, local = [msg_queue_in], shared = [usb_serial, usb_hid, usb_device])] + fn usb_isr(mut ctx: usb_isr::Context) { + let mut all = ( + &mut ctx.shared.usb_serial, + &mut ctx.shared.usb_hid, + &mut ctx.shared.usb_device, + ); + all.lock(|usb_serial, usb_hid, usb_device| { + if usb_device.poll(&mut [usb_serial, usb_hid]) { + let mut buffer = [0u8; 64]; + if let Ok(n) = usb_serial.read(&mut buffer) { + if n > 0 { + for b in &buffer[0..n] { + if *b == b'?' { + // User pressed "?" in the terminal + _ = ctx.local.msg_queue_in.enqueue(Message::WantInfo); + } + } + } + } + if let Ok(n) = usb_hid.pull_raw_output(&mut buffer) { + // Linux sends 1 byte, Windows sends 64 (with 63 zero bytes) + if n == 1 || n == 64 { + _ = ctx + .local + .msg_queue_in + .enqueue(Message::ChangeChannel(buffer[0])); } } } - } - let hid_byte = match hid.pull_raw_output(&mut buf) { - Ok(64) => { - // Windows zero-pads the packet - Some(buf[0]) - } - Ok(1) => { - // macOS/Linux sends a single byte - Some(buf[0]) - } - Ok(_n) => { - // Ignore any other size packet - None - } - Err(_e) => None, - }; - if let Some(ch) = hid_byte { - NEW_CHANNEL.store(ch as u32, Ordering::Relaxed); - } + }); } - // Is there a pending byte from last time? - if let Some(n) = IS_PENDING { - match serial.write(core::slice::from_ref(n)) { - Ok(_) => { - // it took our pending byte - *IS_PENDING = None; - } - Err(_) => { - // serial buffer is full - return; - } - } + enum Command { + SendSecret, + MapChar(u8, u8), + Correct, + Wrong, } - // Copy some more from the ring-buffer to the USB Serial interface, - // until the serial interface is full. - while let Some(item) = RING_BUFFER.read() { - let s = &[item]; - if serial.write(s).is_err() { - // the USB UART can't take this byte right now - *IS_PENDING = Some(item); - break; + fn handle_packet( + packet: &mut dongle::ieee802154::Packet, + dict: &heapless::LinearMap, + ) -> Option { + let payload = packet.get_mut(ADDR_BYTES..)?; + if payload.len() == 0 { + Some(Command::SendSecret) + } else if payload.len() == 1 { + // They give us plaintext, we give them ciphertext + let plain = payload[0]; + let cipher = *dict.get(&plain).unwrap_or(&0); + Some(Command::MapChar(plain, cipher)) + } else { + // They give us plaintext, we tell them if it is correct + // Encrypt every byte of plaintext they give us + for slot in payload.iter_mut() { + if let Some(c) = dict.get(slot) { + *slot = *c; + } else { + *slot = 0; + } + } + if &payload[..] == ENCODED_MESSAGE { + Some(Command::Correct) + } else { + Some(Command::Wrong) + } } } - - cortex_m::asm::sev(); } #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { - let _ = writeln!(&RING_BUFFER, "Panic: {:?}", info); - cortex_m::asm::delay(64_000_000 * 2); - unsafe { - loop { - core::arch::asm!("bkpt 0x00"); - } + if let Some(location) = info.location() { + defmt::error!("Panic at {}:{}", location.file(), location.line()); + } else { + defmt::error!("Panic at unknown location"); + } + loop { + core::hint::spin_loop(); } } -// End of file +defmt::timestamp!("{=u64:tus}", dongle::uptime_us()); From 64b7bebfa4644b3e7f4e71713f267ce1b683b1be Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Thu, 12 Dec 2024 13:56:46 +0000 Subject: [PATCH 10/10] Clippy fixes and clean ups. The usb_device is only used in the ISR, so it can be a local. Saves us a lock. --- nrf52-code/loopback-fw/src/main.rs | 43 +++++++++++++++--------------- nrf52-code/puzzle-fw/src/main.rs | 22 +++++++-------- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/nrf52-code/loopback-fw/src/main.rs b/nrf52-code/loopback-fw/src/main.rs index c8f512f4..44f3e137 100644 --- a/nrf52-code/loopback-fw/src/main.rs +++ b/nrf52-code/loopback-fw/src/main.rs @@ -51,8 +51,10 @@ mod app { msg_queue_out: heapless::spsc::Consumer<'static, Message, QUEUE_LEN>, /// A place to write to the message queue msg_queue_in: heapless::spsc::Producer<'static, Message, QUEUE_LEN>, - /// A status LED - led: dongle::Led, + /// The status LEDs + leds: dongle::Leds, + /// Handles the lower-level USB Device interface + usb_device: usb_device::device::UsbDevice<'static, dongle::UsbBus>, } #[derive(Debug, defmt::Format, Copy, Clone, PartialEq, Eq)] @@ -67,8 +69,6 @@ mod app { usb_serial: usbd_serial::SerialPort<'static, dongle::UsbBus>, /// Handles the USB HID interface usb_hid: usbd_hid::hid_class::HIDClass<'static, dongle::UsbBus>, - /// Handles the lower-level USB Device interface - usb_device: usb_device::device::UsbDevice<'static, dongle::UsbBus>, } #[init(local = [ @@ -154,7 +154,6 @@ mod app { let shared = MySharedResources { usb_serial, usb_hid, - usb_device, }; let local = MyLocalResources { radio: board.radio, @@ -165,7 +164,8 @@ mod app { err_count: 0, msg_queue_out, msg_queue_in, - led: board.leds.ld1, + leds: board.leds, + usb_device, }; defmt::debug!("Init Complete!"); @@ -173,7 +173,7 @@ mod app { (shared, local) } - #[idle(local = [radio, current_channel, packet, timer, rx_count, err_count, msg_queue_out, led], shared = [usb_serial])] + #[idle(local = [radio, current_channel, packet, timer, rx_count, err_count, msg_queue_out, leds], shared = [usb_serial])] fn idle(mut ctx: idle::Context) -> ! { use core::fmt::Write as _; let mut writer = Writer(|b: &[u8]| { @@ -189,6 +189,9 @@ mod app { ctx.local.current_channel ); + ctx.local.leds.ld1.on(); + ctx.local.leds.ld2_blue.on(); + loop { while let Some(msg) = ctx.local.msg_queue_out.dequeue() { match msg { @@ -298,13 +301,13 @@ mod app { } defmt::debug!("Waiting for packet.."); - match ctx.local.radio.recv_timeout( - &mut ctx.local.packet, - &mut ctx.local.timer, - 1_000_000, - ) { + match ctx + .local + .radio + .recv_timeout(ctx.local.packet, ctx.local.timer, 1_000_000) + { Ok(crc) => { - ctx.local.led.toggle(); + ctx.local.leds.ld1.toggle(); defmt::info!( "Received {=u8} bytes (CRC=0x{=u16:04x}, LQI={})", ctx.local.packet.len(), @@ -344,15 +347,11 @@ mod app { /// /// USB Device is set to fire this whenever there's a Start of Frame from /// the USB Host. - #[task(binds = USBD, local = [msg_queue_in], shared = [usb_serial, usb_hid, usb_device])] - fn usb_isr(mut ctx: usb_isr::Context) { - let mut all = ( - &mut ctx.shared.usb_serial, - &mut ctx.shared.usb_hid, - &mut ctx.shared.usb_device, - ); - all.lock(|usb_serial, usb_hid, usb_device| { - if usb_device.poll(&mut [usb_serial, usb_hid]) { + #[task(binds = USBD, local = [msg_queue_in, usb_device], shared = [usb_serial, usb_hid])] + fn usb_isr(ctx: usb_isr::Context) { + let mut all = (ctx.shared.usb_serial, ctx.shared.usb_hid); + all.lock(|usb_serial, usb_hid| { + if ctx.local.usb_device.poll(&mut [usb_serial, usb_hid]) { let mut buffer = [0u8; 64]; if let Ok(n) = usb_serial.read(&mut buffer) { if n > 0 { diff --git a/nrf52-code/puzzle-fw/src/main.rs b/nrf52-code/puzzle-fw/src/main.rs index 2bc3eed5..b15f82c1 100644 --- a/nrf52-code/puzzle-fw/src/main.rs +++ b/nrf52-code/puzzle-fw/src/main.rs @@ -68,6 +68,8 @@ mod app { msg_queue_in: heapless::spsc::Producer<'static, Message, QUEUE_LEN>, /// The status LEDs leds: dongle::Leds, + /// Handles the lower-level USB Device interface + usb_device: usb_device::device::UsbDevice<'static, dongle::UsbBus>, } #[derive(Debug, defmt::Format, Copy, Clone, PartialEq, Eq)] @@ -82,8 +84,6 @@ mod app { usb_serial: usbd_serial::SerialPort<'static, dongle::UsbBus>, /// Handles the USB HID interface usb_hid: usbd_hid::hid_class::HIDClass<'static, dongle::UsbBus>, - /// Handles the lower-level USB Device interface - usb_device: usb_device::device::UsbDevice<'static, dongle::UsbBus>, } #[init(local = [ @@ -169,7 +169,6 @@ mod app { let shared = MySharedResources { usb_serial, usb_hid, - usb_device, }; let local = MyLocalResources { radio: board.radio, @@ -181,6 +180,7 @@ mod app { msg_queue_out, msg_queue_in, leds: board.leds, + usb_device, }; defmt::debug!("Init Complete!"); @@ -427,15 +427,11 @@ mod app { /// /// USB Device is set to fire this whenever there's a Start of Frame from /// the USB Host. - #[task(binds = USBD, local = [msg_queue_in], shared = [usb_serial, usb_hid, usb_device])] - fn usb_isr(mut ctx: usb_isr::Context) { - let mut all = ( - &mut ctx.shared.usb_serial, - &mut ctx.shared.usb_hid, - &mut ctx.shared.usb_device, - ); - all.lock(|usb_serial, usb_hid, usb_device| { - if usb_device.poll(&mut [usb_serial, usb_hid]) { + #[task(binds = USBD, local = [msg_queue_in, usb_device], shared = [usb_serial, usb_hid])] + fn usb_isr(ctx: usb_isr::Context) { + let mut all = (ctx.shared.usb_serial, ctx.shared.usb_hid); + all.lock(|usb_serial, usb_hid| { + if ctx.local.usb_device.poll(&mut [usb_serial, usb_hid]) { let mut buffer = [0u8; 64]; if let Ok(n) = usb_serial.read(&mut buffer) { if n > 0 { @@ -472,7 +468,7 @@ mod app { dict: &heapless::LinearMap, ) -> Option { let payload = packet.get_mut(ADDR_BYTES..)?; - if payload.len() == 0 { + if payload.is_empty() { Some(Command::SendSecret) } else if payload.len() == 1 { // They give us plaintext, we give them ciphertext