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 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/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/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 51e0216c..6ad75ab2 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(any(feature = "radio", feature = "usbd"))] 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::{ @@ -32,26 +32,24 @@ 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; #[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 @@ -65,14 +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, + 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 @@ -323,10 +328,10 @@ 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")] + #[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 +348,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 +407,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 }, @@ -418,12 +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) }, + ep0in: unsafe { usbd::Ep0In::new(&EP0IN_BUF) }, + #[cfg(any(feature = "radio", feature = "usbd"))] + clocks, }) } @@ -433,11 +449,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 +497,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 +509,74 @@ 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 +} + +/// 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-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/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 57f4e9ad..6a275eff 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(any(feature = "radio", feature = "usbd"))] 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::{ @@ -32,26 +32,24 @@ 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; #[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 @@ -63,14 +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, + 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 @@ -297,10 +302,10 @@ 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")] + #[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 +322,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 +375,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 }, @@ -380,12 +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) }, + ep0in: unsafe { usbd::Ep0In::new(&EP0IN_BUF) }, + #[cfg(any(feature = "radio", feature = "usbd"))] + clocks, }) } @@ -395,11 +411,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 +459,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 +471,74 @@ 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 +} + +/// 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/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/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..eb80b671 100644 --- a/nrf52-code/boards/dongle/src/lib.rs +++ b/nrf52-code/boards/dongle/src/lib.rs @@ -15,8 +15,8 @@ use core::{ use cortex_m::peripheral::NVIC; use cortex_m_semihosting::debug; use embedded_hal::digital::{OutputPin, StatefulOutputPin}; +use grounded::uninit::GroundedCell; -pub use hal::{self, ieee802154}; use hal::{ clocks::{self, Clocks}, gpio::{p0, p1, Level, Output, Pin, Port, PushPull}, @@ -27,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}; @@ -35,7 +38,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 { @@ -223,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 { @@ -282,21 +244,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 +335,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 +364,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 +376,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/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/bin/blinky.rs b/nrf52-code/hal-app/src/bin/blinky.rs index fb44471a..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 at {:?}", dk::uptime()); + defmt::debug!("LED toggled @ {=u64:tus}", dk::uptime_us()); } dk::exit() 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/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 4cc8e3ca..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", @@ -182,6 +188,7 @@ dependencies = [ "defmt", "defmt-rtt", "embedded-hal 1.0.0", + "grounded", "heapless", "nrf52840-hal", "panic-probe", @@ -212,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" @@ -230,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,14 +265,51 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "917d82402c7eb9755fdd87d52117701dae9e413a6abb309fac2a13af693b6080" +dependencies = [ + "portable-atomic", ] [[package]] @@ -281,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" @@ -308,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", @@ -406,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" @@ -461,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 = [ + "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 = [ - "getrandom", + "critical-section", + "embedded-hal 1.0.0", + "embedded-hal-async", + "fugit", + "futures-util", + "rtic-common", ] [[package]] @@ -516,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", @@ -574,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", @@ -610,6 +728,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" dependencies = [ + "defmt", "heapless", "portable-atomic", ] @@ -620,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", @@ -642,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", @@ -690,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..44f3e137 100644 --- a/nrf52-code/loopback-fw/src/main.rs +++ b/nrf52-code/loopback-fw/src/main.rs @@ -2,313 +2,391 @@ //! //! 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>, + /// The status LEDs + leds: dongle::Leds, + /// Handles the lower-level USB Device interface + usb_device: usb_device::device::UsbDevice<'static, dongle::UsbBus>, + } - 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>, + } - 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, + }; + 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, + usb_device, + }; - // 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, 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=loopback-fw", + dongle::deviceid1(), + dongle::deviceid0(), + ctx.local.current_channel + ); + + ctx.local.leds.ld1.on(); + ctx.local.leds.ld2_blue.on(); - 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(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; + // 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, 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 { + 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()); diff --git a/nrf52-code/puzzle-fw/Cargo.lock b/nrf52-code/puzzle-fw/Cargo.lock index 9b5a9682..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", @@ -182,6 +188,7 @@ dependencies = [ "defmt", "defmt-rtt", "embedded-hal 1.0.0", + "grounded", "heapless", "nrf52840-hal", "panic-probe", @@ -212,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" @@ -230,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" @@ -242,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" @@ -253,6 +314,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" @@ -281,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" @@ -389,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" @@ -440,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", @@ -491,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" @@ -611,6 +779,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" dependencies = [ + "defmt", "heapless", "portable-atomic", ] @@ -621,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", @@ -643,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..b15f82c1 100644 --- a/nrf52-code/puzzle-fw/src/main.rs +++ b/nrf52-code/puzzle-fw/src/main.rs @@ -2,415 +2,508 @@ //! //! 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, + /// Handles the lower-level USB Device interface + usb_device: usb_device::device::UsbDevice<'static, dongle::UsbBus>, + } + + #[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>, + } -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, + }; + 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, + usb_device, + }; + + 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, 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 { + 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.is_empty() { + 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()); 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/bin/blinky.rs b/nrf52-code/radio-app/src/bin/blinky.rs index 76b920ad..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 at {:?}", dk::uptime()); + defmt::debug!("LED toggled @ {=u64:tus}", dk::uptime_us()); } dk::exit() 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/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/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-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/.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/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` 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());