From 20f464eec5efa8f7d0c594c5c613426be0c8e4c8 Mon Sep 17 00:00:00 2001 From: Jonathan Pallant Date: Wed, 11 Dec 2024 18:20:47 +0000 Subject: [PATCH] Moved loopback-fw over to the RTIC version, on the dongle. Tested on macOS 15, Windows 10 and Debian 12. --- build.sh | 5 - nrf52-code/boards/dk-solution/src/lib.rs | 32 +- nrf52-code/boards/dk/src/lib.rs | 32 +- nrf52-code/boards/dongle/src/lib.rs | 5 +- .../loopback-fw-rtic/.cargo/config.toml | 23 - nrf52-code/loopback-fw-rtic/.gitignore | 1 - nrf52-code/loopback-fw-rtic/Cargo.lock | 818 ------------------ nrf52-code/loopback-fw-rtic/Cargo.toml | 18 - nrf52-code/loopback-fw-rtic/src/main.rs | 354 -------- nrf52-code/loopback-fw/.cargo/config.toml | 5 +- nrf52-code/loopback-fw/Cargo.lock | 213 +++-- nrf52-code/loopback-fw/Cargo.toml | 37 +- nrf52-code/loopback-fw/src/main.rs | 633 ++++++++------ 13 files changed, 558 insertions(+), 1618 deletions(-) delete mode 100644 nrf52-code/loopback-fw-rtic/.cargo/config.toml delete mode 100644 nrf52-code/loopback-fw-rtic/.gitignore delete mode 100644 nrf52-code/loopback-fw-rtic/Cargo.lock delete mode 100644 nrf52-code/loopback-fw-rtic/Cargo.toml delete mode 100644 nrf52-code/loopback-fw-rtic/src/main.rs diff --git a/build.sh b/build.sh index 66339e5e..c675c148 100755 --- a/build.sh +++ b/build.sh @@ -72,10 +72,6 @@ pushd loopback-fw cargo build --target=thumbv7em-none-eabihf --release cargo fmt --check popd -pushd loopback-fw-rtic -cargo build --target=thumbv7em-none-eabihf --release -cargo fmt --check -popd popd # Only build the templates (they will panic at run-time due to the use of todo!) @@ -109,6 +105,5 @@ cp -r ./.cargo "${OUTPUT_NAME}/" cp -r ./tools "${OUTPUT_NAME}/" cp ./nrf52-code/puzzle-fw/target/thumbv7em-none-eabihf/release/puzzle-fw "${OUTPUT_NAME}/nrf52-code/boards/dongle-fw/puzzle-fw" cp ./nrf52-code/loopback-fw/target/thumbv7em-none-eabihf/release/loopback-fw "${OUTPUT_NAME}/nrf52-code/boards/dongle-fw/loopback-fw" -cp ./nrf52-code/loopback-fw-rtic/target/thumbv7em-none-eabihf/release/loopback-fw-rtic "${OUTPUT_NAME}/nrf52-code/boards/dongle-fw/loopback-fw-rtic" find "${OUTPUT_NAME}" -name target -type d -print0 | xargs -0 rm -rf zip -r "${OUTPUT_NAME}.zip" "${OUTPUT_NAME}" diff --git a/nrf52-code/boards/dk-solution/src/lib.rs b/nrf52-code/boards/dk-solution/src/lib.rs index 94dddb22..6ad75ab2 100644 --- a/nrf52-code/boards/dk-solution/src/lib.rs +++ b/nrf52-code/boards/dk-solution/src/lib.rs @@ -32,12 +32,6 @@ use hal::{ #[cfg(any(feature = "radio", feature = "advanced"))] use defmt_rtt as _; // global logger -#[cfg(feature = "advanced")] -use crate::{ - peripheral::{POWER, USBD}, - usbd::Ep0In, -}; - #[cfg(feature = "advanced")] mod errata; pub mod peripheral; @@ -69,17 +63,21 @@ pub struct Board { #[cfg(feature = "radio")] pub radio: ieee802154::Radio<'static>, /// USBD (Universal Serial Bus Device) peripheral - #[cfg(feature = "advanced")] - pub usbd: USBD, + #[cfg(any(feature = "advanced", feature = "usbd"))] + pub usbd: hal::pac::USBD, /// POWER (Power Supply) peripheral #[cfg(feature = "advanced")] - pub power: POWER, + pub power: hal::pac::POWER, /// USB control endpoint 0 #[cfg(feature = "advanced")] - pub ep0in: Ep0In, - /// A configured USB Device - #[cfg(feature = "usbd")] - pub usbd: UsbDevice, + pub ep0in: usbd::Ep0In, + /// Represents our current clock setup + #[cfg(any(feature = "radio", feature = "usbd"))] + pub clocks: &'static Clocks< + clocks::ExternalOscillator, + clocks::ExternalOscillator, + clocks::LfOscStarted, + >, } /// All LEDs on the board @@ -434,14 +432,14 @@ pub fn init() -> Result { #[cfg(feature = "radio")] radio, timer: Timer { inner: timer }, - #[cfg(feature = "advanced")] + #[cfg(any(feature = "advanced", feature = "usbd"))] usbd: periph.USBD, #[cfg(feature = "advanced")] power: periph.POWER, #[cfg(feature = "advanced")] - ep0in: unsafe { Ep0In::new(&EP0IN_BUF) }, - #[cfg(feature = "usbd")] - usbd: UsbDevice::new(hal::usbd::UsbPeripheral::new(periph.USBD, clocks)), + ep0in: unsafe { usbd::Ep0In::new(&EP0IN_BUF) }, + #[cfg(any(feature = "radio", feature = "usbd"))] + clocks, }) } diff --git a/nrf52-code/boards/dk/src/lib.rs b/nrf52-code/boards/dk/src/lib.rs index 414d42cd..6a275eff 100644 --- a/nrf52-code/boards/dk/src/lib.rs +++ b/nrf52-code/boards/dk/src/lib.rs @@ -32,12 +32,6 @@ use hal::{ #[cfg(any(feature = "radio", feature = "advanced"))] use defmt_rtt as _; // global logger -#[cfg(feature = "advanced")] -use crate::{ - peripheral::{POWER, USBD}, - usbd::Ep0In, -}; - #[cfg(feature = "advanced")] mod errata; pub mod peripheral; @@ -67,17 +61,21 @@ pub struct Board { #[cfg(feature = "radio")] pub radio: ieee802154::Radio<'static>, /// USBD (Universal Serial Bus Device) peripheral - #[cfg(feature = "advanced")] - pub usbd: USBD, + #[cfg(any(feature = "advanced", feature = "usbd"))] + pub usbd: hal::pac::USBD, /// POWER (Power Supply) peripheral #[cfg(feature = "advanced")] - pub power: POWER, + pub power: hal::pac::POWER, /// USB control endpoint 0 #[cfg(feature = "advanced")] - pub ep0in: Ep0In, - /// A configured USB Device - #[cfg(feature = "usbd")] - pub usbd: UsbDevice, + pub ep0in: usbd::Ep0In, + /// Represents our current clock setup + #[cfg(any(feature = "radio", feature = "usbd"))] + pub clocks: &'static Clocks< + clocks::ExternalOscillator, + clocks::ExternalOscillator, + clocks::LfOscStarted, + >, } /// All LEDs on the board @@ -396,14 +394,14 @@ pub fn init() -> Result { #[cfg(feature = "radio")] radio, timer: Timer { inner: timer }, - #[cfg(feature = "advanced")] + #[cfg(any(feature = "advanced", feature = "usbd"))] usbd: periph.USBD, #[cfg(feature = "advanced")] power: periph.POWER, #[cfg(feature = "advanced")] - ep0in: unsafe { Ep0In::new(&EP0IN_BUF) }, - #[cfg(feature = "usbd")] - usbd: UsbDevice::new(hal::usbd::UsbPeripheral::new(periph.USBD, clocks)), + ep0in: unsafe { usbd::Ep0In::new(&EP0IN_BUF) }, + #[cfg(any(feature = "radio", feature = "usbd"))] + clocks, }) } diff --git a/nrf52-code/boards/dongle/src/lib.rs b/nrf52-code/boards/dongle/src/lib.rs index 88659f88..4a0dc4c3 100644 --- a/nrf52-code/boards/dongle/src/lib.rs +++ b/nrf52-code/boards/dongle/src/lib.rs @@ -17,8 +17,6 @@ use cortex_m_semihosting::debug; use embedded_hal::digital::{OutputPin, StatefulOutputPin}; use grounded::uninit::GroundedCell; -use hal::pac::interrupt; -pub use hal::{self, ieee802154}; use hal::{ clocks::{self, Clocks}, gpio::{p0, p1, Level, Output, Pin, Port, PushPull}, @@ -29,6 +27,9 @@ use hal::{ use defmt_rtt as _; // global logger +pub use hal::pac::{interrupt, Interrupt, NVIC_PRIO_BITS, RTC0}; +pub use hal::{self, ieee802154}; + /// Exports PAC peripherals pub mod peripheral { pub use hal::pac::{interrupt, Interrupt, POWER, USBD}; diff --git a/nrf52-code/loopback-fw-rtic/.cargo/config.toml b/nrf52-code/loopback-fw-rtic/.cargo/config.toml deleted file mode 100644 index 436cc4fb..00000000 --- a/nrf52-code/loopback-fw-rtic/.cargo/config.toml +++ /dev/null @@ -1,23 +0,0 @@ -[target.thumbv7em-none-eabihf] -# set custom cargo runner to flash & run on embedded target when we call `cargo run` -# for more information, check out https://github.com/probe-rs -runner = [ - "probe-rs", - "run", - "--chip", - "nRF52840_xxAA", - "--allow-erase-all", - "--log-format", - "{t} {[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" -] -# Or use "{[{L}]%bold} {s} {({c:bold} {fff}:{l:1})%dimmed}" to disable timestamps - -linker = "flip-link" # adds stack overflow protection -rustflags = [ - "-C", "link-arg=-Tlink.x", # use the cortex-m-rt linker script - "-C", "link-arg=-Tdefmt.x", # defmt support -] - -[build] -# cross-compile to this target -target = "thumbv7em-none-eabihf" # = ARM Cortex-M4 with FPU diff --git a/nrf52-code/loopback-fw-rtic/.gitignore b/nrf52-code/loopback-fw-rtic/.gitignore deleted file mode 100644 index eb5a316c..00000000 --- a/nrf52-code/loopback-fw-rtic/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/nrf52-code/loopback-fw-rtic/Cargo.lock b/nrf52-code/loopback-fw-rtic/Cargo.lock deleted file mode 100644 index 02db2311..00000000 --- a/nrf52-code/loopback-fw-rtic/Cargo.lock +++ /dev/null @@ -1,818 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - -[[package]] -name = "az" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" - -[[package]] -name = "bare-metal" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version", -] - -[[package]] -name = "bare-metal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" - -[[package]] -name = "bitfield" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" - -[[package]] -name = "bitfield" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bytemuck" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" - -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "consts" -version = "0.1.0" - -[[package]] -name = "cortex-m" -version = "0.7.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" -dependencies = [ - "bare-metal 0.2.5", - "bitfield 0.13.2", - "critical-section", - "embedded-hal 0.2.7", - "volatile-register", -] - -[[package]] -name = "cortex-m-rt" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" -dependencies = [ - "cortex-m-rt-macros", -] - -[[package]] -name = "cortex-m-rt-macros" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "cortex-m-semihosting" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c23234600452033cc77e4b761e740e02d2c4168e11dbf36ab14a0f58973592b0" -dependencies = [ - "cortex-m", -] - -[[package]] -name = "critical-section" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "defmt" -version = "0.3.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f6162c53f659f65d00619fe31f14556a6e9f8752ccc4a41bd177ffcf3d6130" -dependencies = [ - "bitflags", - "defmt-macros", -] - -[[package]] -name = "defmt-macros" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d135dd939bad62d7490b0002602d35b358dce5fd9233a709d3c1ef467d4bde6" -dependencies = [ - "defmt-parser", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "defmt-parser" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3" -dependencies = [ - "thiserror", -] - -[[package]] -name = "defmt-rtt" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab697b3dbbc1750b7c8b821aa6f6e7f2480b47a99bc057a2ed7b170ebef0c51" -dependencies = [ - "critical-section", - "defmt", -] - -[[package]] -name = "dk" -version = "0.0.0" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "cortex-m-semihosting", - "defmt", - "defmt-rtt", - "embedded-hal 1.0.0", - "grounded", - "nrf52840-hal", -] - -[[package]] -name = "embedded-dma" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446" -dependencies = [ - "stable_deref_trait", -] - -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - -[[package]] -name = "embedded-hal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" - -[[package]] -name = "embedded-hal-async" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" -dependencies = [ - "embedded-hal 1.0.0", -] - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - -[[package]] -name = "embedded-storage" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" - -[[package]] -name = "encode_unicode" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" - -[[package]] -name = "equivalent" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" - -[[package]] -name = "fixed" -version = "1.28.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" -dependencies = [ - "az", - "bytemuck", - "half", - "typenum", -] - -[[package]] -name = "fugit" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" -dependencies = [ - "gcd", -] - -[[package]] -name = "futures-core" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" - -[[package]] -name = "futures-task" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" - -[[package]] -name = "futures-util" -version = "0.3.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" -dependencies = [ - "futures-core", - "futures-task", - "pin-project-lite", - "pin-utils", -] - -[[package]] -name = "gcd" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" - -[[package]] -name = "grounded" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "917d82402c7eb9755fdd87d52117701dae9e413a6abb309fac2a13af693b6080" -dependencies = [ - "portable-atomic", -] - -[[package]] -name = "half" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" -dependencies = [ - "cfg-if", - "crunchy", -] - -[[package]] -name = "hash32" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" -dependencies = [ - "byteorder", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - -[[package]] -name = "hashbrown" -version = "0.15.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" - -[[package]] -name = "heapless" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" -dependencies = [ - "defmt", - "hash32", - "stable_deref_trait", -] - -[[package]] -name = "indexmap" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" -dependencies = [ - "equivalent", - "hashbrown 0.15.2", -] - -[[package]] -name = "log" -version = "0.4.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" - -[[package]] -name = "loopback-fw-rtic" -version = "0.0.0" -dependencies = [ - "consts", - "defmt", - "defmt-rtt", - "dk", - "heapless", - "rtic", - "rtic-monotonics", - "usb-device", - "usbd-hid", - "usbd-serial", -] - -[[package]] -name = "nb" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" -dependencies = [ - "nb 1.1.0", -] - -[[package]] -name = "nb" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" - -[[package]] -name = "nrf-hal-common" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c134de1f2f0191aed3fc24d3831da8808d1e636b06edf81a5717103095f625d" -dependencies = [ - "cast", - "cfg-if", - "cortex-m", - "embedded-dma", - "embedded-hal 0.2.7", - "embedded-hal 1.0.0", - "embedded-io", - "embedded-storage", - "fixed", - "nb 1.1.0", - "nrf-usbd", - "nrf52840-pac", - "rand_core", - "void", -] - -[[package]] -name = "nrf-usbd" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf862f941154442271ae9914777bd1c93f6d2e0dc9db4cafa160e55ffb9085" -dependencies = [ - "cortex-m", - "critical-section", - "usb-device", - "vcell", -] - -[[package]] -name = "nrf52840-hal" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "433cfd866da18dfc58376880bdebd092c130444837debc513f44edcd0d6a6558" -dependencies = [ - "nrf-hal-common", - "nrf52840-pac", -] - -[[package]] -name = "nrf52840-pac" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30713f36f1be02e5bc9abefa30eae4a1f943d810f199d4923d3ad062d1be1b3d" -dependencies = [ - "cortex-m", - "cortex-m-rt", - "vcell", -] - -[[package]] -name = "once_cell" -version = "1.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" - -[[package]] -name = "pin-project-lite" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "portable-atomic" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" - -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "proc-macro2" -version = "1.0.92" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" - -[[package]] -name = "rtic" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "401961431a1e491124cdd216a313fada2d395aa2b5bee2867c872fc8af7c1bc1" -dependencies = [ - "bare-metal 1.0.0", - "cortex-m", - "critical-section", - "portable-atomic", - "rtic-core", - "rtic-macros", -] - -[[package]] -name = "rtic-common" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c" -dependencies = [ - "critical-section", -] - -[[package]] -name = "rtic-core" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" - -[[package]] -name = "rtic-macros" -version = "2.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac22ab522d80079b48f46ac66ded4d349e1adf81b52430d6a74faa3a7790ed80" -dependencies = [ - "indexmap", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "rtic-monotonics" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1cb90bcfdbbacf3ca37340cdab52ec2de5611c744095ef7889e9c50c233b748" -dependencies = [ - "cfg-if", - "cortex-m", - "fugit", - "portable-atomic", - "rtic-time", -] - -[[package]] -name = "rtic-time" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7b1d853fa50dc125695414ce4510567a0d420221e455b1568cfa8c9aece9614" -dependencies = [ - "critical-section", - "embedded-hal 1.0.0", - "embedded-hal-async", - "fugit", - "futures-util", - "rtic-common", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "semver", -] - -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - -[[package]] -name = "serde" -version = "1.0.216" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.216" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "ssmarshal" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3e6ad23b128192ed337dfa4f1b8099ced0c2bf30d61e551b65fda5916dbb850" -dependencies = [ - "encode_unicode", - "serde", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.90" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thiserror" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] - -[[package]] -name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-ident" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" - -[[package]] -name = "usb-device" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" -dependencies = [ - "defmt", - "heapless", - "portable-atomic", -] - -[[package]] -name = "usbd-hid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c" -dependencies = [ - "defmt", - "serde", - "ssmarshal", - "usb-device", - "usbd-hid-macros", -] - -[[package]] -name = "usbd-hid-descriptors" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eee54712c5d778d2fb2da43b1ce5a7b5060886ef7b09891baeb4bf36910a3ed" -dependencies = [ - "bitfield 0.14.0", -] - -[[package]] -name = "usbd-hid-macros" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38" -dependencies = [ - "byteorder", - "hashbrown 0.13.2", - "log", - "proc-macro2", - "quote", - "serde", - "syn 1.0.109", - "usbd-hid-descriptors", -] - -[[package]] -name = "usbd-serial" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065e4eaf93db81d5adac82d9cef8f8da314cb640fa7f89534b972383f1cf80fc" -dependencies = [ - "embedded-hal 0.2.7", - "embedded-io", - "nb 1.1.0", - "usb-device", -] - -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - -[[package]] -name = "version_check" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" - -[[package]] -name = "volatile-register" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" -dependencies = [ - "vcell", -] - -[[package]] -name = "zerocopy" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" -dependencies = [ - "zerocopy-derive", -] - -[[package]] -name = "zerocopy-derive" -version = "0.7.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.90", -] diff --git a/nrf52-code/loopback-fw-rtic/Cargo.toml b/nrf52-code/loopback-fw-rtic/Cargo.toml deleted file mode 100644 index e935db78..00000000 --- a/nrf52-code/loopback-fw-rtic/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -authors = ["Ferrous Systems"] -edition = "2021" -license = "MIT OR Apache-2.0" -name = "loopback-fw-rtic" -version = "0.0.0" - -[dependencies] -consts = { version = "0.1.0", path = "../consts" } -defmt = "0.3.10" -defmt-rtt = "0.4.1" -dk = { version = "0.0.0", path = "../boards/dk", features = ["usbd", "radio"] } -heapless = { version = "0.8.0", features = ["defmt-03"] } -rtic = { version = "2.1.2", features = ["thumbv7-backend"] } -rtic-monotonics = { version = "2.0.3", features = ["cortex-m-systick"] } -usb-device = { version = "0.3.2", features = ["defmt"] } -usbd-hid = { version = "0.8.2", features = ["defmt"] } -usbd-serial = "0.2.2" diff --git a/nrf52-code/loopback-fw-rtic/src/main.rs b/nrf52-code/loopback-fw-rtic/src/main.rs deleted file mode 100644 index 7a33a451..00000000 --- a/nrf52-code/loopback-fw-rtic/src/main.rs +++ /dev/null @@ -1,354 +0,0 @@ -//! The Loopback Firmware, written using RTIC -//! -//! Currently this runs on the Developer Kit and not the Dongle, because it's -//! easier to debug. -//! -//! And it doesn't do any radio stuff - just USB Serial. - -#![no_main] -#![no_std] - -use defmt_rtt as _; - -#[rtic::app(device = dk, peripherals = false)] -mod app { - use core::mem::MaybeUninit; - use rtic_monotonics::systick::prelude::*; - const QUEUE_LEN: usize = 8; - - systick_monotonic!(Mono, 100); - - /// An adapter that lets us writeln! into any closure that takes a byte. - /// - /// This is useful if writing a byte requires taking a lock, and you don't - /// want to hold the lock for the duration of the write. - struct Writer(F) - where - F: FnMut(&[u8]); - - impl core::fmt::Write for Writer - where - F: FnMut(&[u8]), - { - fn write_str(&mut self, s: &str) -> core::fmt::Result { - (self.0)(s.as_bytes()); - Ok(()) - } - } - - #[local] - struct MyLocalResources { - /// The radio subsystem - radio: dk::ieee802154::Radio<'static>, - /// Which channel are we on - current_channel: u8, - /// Holds one package, for receive or transmit - packet: dk::ieee802154::Packet, - /// Used to measure elapsed time - timer: dk::Timer, - /// How many packets have been received OK? - rx_count: u32, - /// How many packets have been received with errors? - err_count: u32, - /// A place to read the message queue - msg_queue_out: heapless::spsc::Consumer<'static, Message, QUEUE_LEN>, - /// A place to write to the message queue - msg_queue_in: heapless::spsc::Producer<'static, Message, QUEUE_LEN>, - /// A status LED - led: dk::Led, - } - - #[derive(Debug, defmt::Format, Copy, Clone, PartialEq, Eq)] - enum Message { - ChangeChannel(u8), - WantInfo, - } - - #[shared] - struct MySharedResources { - /// Handles the USB Serial interface, including a ring buffer - usb_serial: usbd_serial::SerialPort<'static, dk::UsbDevice>, - /// Handles the USB HID interface - usb_hid: usbd_hid::hid_class::HIDClass<'static, dk::UsbDevice>, - /// Handles the lower-level USB Device interface - usb_device: usb_device::device::UsbDevice<'static, dk::UsbDevice>, - } - - #[init(local = [ - usb_alloc: MaybeUninit> = MaybeUninit::uninit(), - queue: heapless::spsc::Queue = heapless::spsc::Queue::new(), - ])] - fn init(ctx: init::Context) -> (MySharedResources, MyLocalResources) { - let mut board = dk::init().unwrap(); - Mono::start(ctx.core.SYST, 64_000_000); - - defmt::debug!("Building USB allocator..."); - let usb_alloc = ctx - .local - .usb_alloc - .write(usb_device::bus::UsbBusAllocator::new(board.usbd)); - - defmt::debug!("Creating usb_serial..."); - let usb_serial = usbd_serial::SerialPort::new(usb_alloc); - - defmt::debug!("Creating usb_hid..."); - let desc = &[ - 0x06, 0x00, 0xFF, // Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xA1, 0x01, // Item(Main ): Collection, data= [ 0x01 ] 1 - // Application - 0x15, 0x00, // Item(Global): Logical Minimum, data= [ 0x00 ] 0 - 0x26, 0xFF, 0x00, // Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 - 0x75, 0x08, // Item(Global): Report Size, data= [ 0x08 ] 8 - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x81, 0x02, // Item(Main ): Input, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x91, 0x02, // Item(Main ): Output, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x01, // Item(Global): Report Count, data= [ 0x01 ] 1 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xB1, 0x02, // Item(Main ): Feature, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0xC0, // Item(Main ): End Collection, data=none - ]; - let usb_hid = usbd_hid::hid_class::HIDClass::new(usb_alloc, desc, 100); - - defmt::debug!("Building USB Strings..."); - let strings = usb_device::device::StringDescriptors::new(usb_device::LangID::EN) - .manufacturer("Ferrous Systems") - .product("Test Device"); - - defmt::debug!("Building VID and PID..."); - let vid_pid = - usb_device::device::UsbVidPid(consts::USB_VID_DEMO, consts::USB_PID_DONGLE_LOOPBACK); - - defmt::debug!("Building USB Device..."); - let usb_device = usb_device::device::UsbDeviceBuilder::new(usb_alloc, vid_pid) - .composite_with_iads() - .strings(&[strings]) - .expect("Adding strings") - .max_packet_size_0(64) - .expect("set_packet_size") - .build(); - - defmt::debug!("Configuring radio..."); - board.radio.set_channel(dk::ieee802154::Channel::_20); - let current_channel = 20; - - let (msg_queue_in, msg_queue_out) = ctx.local.queue.split(); - - defmt::debug!("Building structures..."); - let shared = MySharedResources { - usb_serial, - usb_hid, - usb_device, - }; - let local = MyLocalResources { - radio: board.radio, - current_channel, - packet: dk::ieee802154::Packet::new(), - timer: board.timer, - rx_count: 0, - err_count: 0, - msg_queue_out, - msg_queue_in, - led: board.leds._1, - }; - - defmt::debug!("Init Complete!"); - - (shared, local) - } - - #[idle(local = [radio, current_channel, packet, timer, rx_count, err_count, msg_queue_out, led], shared = [usb_serial])] - fn idle(mut ctx: idle::Context) -> ! { - use core::fmt::Write as _; - let mut writer = Writer(|b: &[u8]| { - ctx.shared.usb_serial.lock(|usb_serial| { - let _ = usb_serial.write(b); - }) - }); - - defmt::info!( - "deviceid={=u32:08x}{=u32:08x} channel={=u8} TxPower=+8dBm app=loopback-fw", - dk::deviceid1(), - dk::deviceid0(), - ctx.local.current_channel - ); - - loop { - while let Some(msg) = ctx.local.msg_queue_out.dequeue() { - match msg { - Message::WantInfo => { - defmt::info!( - "rx={=u32}, err={=u32}, ch={=u8}, app=loopback-fw", - ctx.local.rx_count, - ctx.local.err_count, - ctx.local.current_channel - ); - let _ = writeln!( - writer, - "\nrx={}, err={}, ch={}, app=loopback-fw", - ctx.local.rx_count, ctx.local.err_count, ctx.local.current_channel - ); - } - Message::ChangeChannel(n) => { - defmt::info!("Changing Channel to {}", n); - let _ = writeln!(writer, "\nChanging Channel to {}", n); - match n { - 11 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_11); - } - 12 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_12); - } - 13 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_13); - } - 14 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_14); - } - 15 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_15); - } - 16 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_16); - } - 17 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_17); - } - 18 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_18); - } - 19 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_19); - } - 20 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_20); - } - 21 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_21); - } - 22 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_22); - } - 23 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_23); - } - 24 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_24); - } - 25 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_25); - } - 26 => { - ctx.local.radio.set_channel(dk::ieee802154::Channel::_26); - } - _ => { - defmt::info!("Bad Channel {}!", n); - } - } - } - } - } - - defmt::debug!("Waiting for packet.."); - match ctx.local.radio.recv_timeout( - &mut ctx.local.packet, - &mut ctx.local.timer, - 1_000_000, - ) { - Ok(crc) => { - ctx.local.led.toggle(); - defmt::info!( - "Received {=u8} bytes (CRC=0x{=u16:04x}, LQI={})", - ctx.local.packet.len(), - crc, - ctx.local.packet.lqi(), - ); - let _ = writeln!( - writer, - "\nReceived {} bytes (CRC=0x{:04x}, LQI={})", - ctx.local.packet.len(), - crc, - ctx.local.packet.lqi(), - ); - *ctx.local.rx_count += 1; - // reverse the bytes, so olleh -> hello - ctx.local.packet.reverse(); - // send packet after 5ms (we know the client waits for 10ms and - // we want to ensure they are definitely in receive mode by the - // time we send this reply) - ctx.local.timer.delay(5000); - ctx.local.radio.send(ctx.local.packet); - } - Err(dk::ieee802154::Error::Crc(_)) => { - defmt::debug!("RX fail!"); - let _ = write!(writer, "!"); - *ctx.local.err_count += 1; - } - Err(dk::ieee802154::Error::Timeout) => { - defmt::debug!("RX timeout..."); - let _ = write!(writer, "."); - } - } - } - } - - /// USB Interrupt Handler - /// - /// USB Device is set to fire this whenever there's a Start of Frame from - /// the USB Host. - #[task(binds = USBD, local = [msg_queue_in], shared = [usb_serial, usb_hid, usb_device])] - fn usb_isr(mut ctx: usb_isr::Context) { - let mut all = ( - &mut ctx.shared.usb_serial, - &mut ctx.shared.usb_hid, - &mut ctx.shared.usb_device, - ); - all.lock(|usb_serial, usb_hid, usb_device| { - if usb_device.poll(&mut [usb_serial, usb_hid]) { - let mut buffer = [0u8; 64]; - if let Ok(n) = usb_serial.read(&mut buffer) { - if n > 0 { - for b in &buffer[0..n] { - if *b == b'?' { - // User pressed "?" in the terminal - _ = ctx.local.msg_queue_in.enqueue(Message::WantInfo); - } - } - } - } - if let Ok(n) = usb_hid.pull_raw_output(&mut buffer) { - // Linux sends 1 byte, Windows sends 64 (with 63 zero bytes) - if n == 1 || n == 64 { - _ = ctx - .local - .msg_queue_in - .enqueue(Message::ChangeChannel(buffer[0])); - } - } - } - }); - } -} - -#[panic_handler] -fn panic(info: &core::panic::PanicInfo) -> ! { - if let Some(location) = info.location() { - defmt::error!("Panic at {}:{}", location.file(), location.line()); - } else { - defmt::error!("Panic at unknown location"); - } - loop { - core::hint::spin_loop(); - } -} - -defmt::timestamp!("{=u64:tus}", dk::uptime_us()); diff --git a/nrf52-code/loopback-fw/.cargo/config.toml b/nrf52-code/loopback-fw/.cargo/config.toml index 51849431..89475d21 100644 --- a/nrf52-code/loopback-fw/.cargo/config.toml +++ b/nrf52-code/loopback-fw/.cargo/config.toml @@ -1,9 +1,10 @@ [target.thumbv7em-none-eabihf] -# set custom cargo runner to DFU the dongle +# set custom cargo runner to flash & run on embedded target when we call `cargo run` +# for more information, check out https://github.com/probe-rs runner = "nrfdfu" +linker = "flip-link" # adds stack overflow protection rustflags = [ "-C", "link-arg=-Tlink.x", # use the cortex-m-rt linker script - "-C", "linker=flip-link", # adds stack overflow protection "-C", "link-arg=-Tdefmt.x", # defmt support ] diff --git a/nrf52-code/loopback-fw/Cargo.lock b/nrf52-code/loopback-fw/Cargo.lock index 05da8a29..6cc3a835 100644 --- a/nrf52-code/loopback-fw/Cargo.lock +++ b/nrf52-code/loopback-fw/Cargo.lock @@ -29,6 +29,12 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "bare-metal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" + [[package]] name = "bitfield" version = "0.13.2" @@ -81,7 +87,7 @@ version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" dependencies = [ - "bare-metal", + "bare-metal 0.2.5", "bitfield 0.13.2", "critical-section", "embedded-hal 0.2.7", @@ -213,6 +219,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + [[package]] name = "embedded-io" version = "0.6.1" @@ -231,6 +246,12 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + [[package]] name = "fixed" version = "1.28.0" @@ -244,16 +265,44 @@ dependencies = [ ] [[package]] -name = "getrandom" -version = "0.2.15" +name = "fugit" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" dependencies = [ - "cfg-if", - "libc", - "wasi", + "gcd", ] +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + +[[package]] +name = "futures-task" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" + +[[package]] +name = "futures-util" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + [[package]] name = "grounded" version = "0.2.0" @@ -291,21 +340,32 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" + [[package]] name = "heapless" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" dependencies = [ + "defmt", "hash32", "stable_deref_trait", ] [[package]] -name = "libc" -version = "0.2.167" +name = "indexmap" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +dependencies = [ + "equivalent", + "hashbrown 0.15.2", +] [[package]] name = "log" @@ -318,12 +378,12 @@ name = "loopback-fw" version = "0.0.0" dependencies = [ "consts", - "cortex-m", - "cortex-m-rt", - "critical-section", + "defmt", + "defmt-rtt", "dongle", - "embedded-hal 1.0.0", - "rand", + "heapless", + "rtic", + "rtic-monotonics", "usb-device", "usbd-hid", "usbd-serial", @@ -416,19 +476,22 @@ dependencies = [ ] [[package]] -name = "portable-atomic" -version = "1.10.0" +name = "pin-project-lite" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] -name = "ppv-lite86" -version = "0.2.20" +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" -dependencies = [ - "zerocopy", -] +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "portable-atomic" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "proc-macro-error-attr2" @@ -471,33 +534,78 @@ dependencies = [ ] [[package]] -name = "rand" -version = "0.8.5" +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" + +[[package]] +name = "rtic" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +checksum = "401961431a1e491124cdd216a313fada2d395aa2b5bee2867c872fc8af7c1bc1" dependencies = [ - "libc", - "rand_chacha", - "rand_core", + "bare-metal 1.0.0", + "cortex-m", + "critical-section", + "portable-atomic", + "rtic-core", + "rtic-macros", ] [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "rtic-common" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c" dependencies = [ - "ppv-lite86", - "rand_core", + "critical-section", ] [[package]] -name = "rand_core" -version = "0.6.4" +name = "rtic-core" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42" + +[[package]] +name = "rtic-macros" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac22ab522d80079b48f46ac66ded4d349e1adf81b52430d6a74faa3a7790ed80" dependencies = [ - "getrandom", + "indexmap", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "rtic-monotonics" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1cb90bcfdbbacf3ca37340cdab52ec2de5611c744095ef7889e9c50c233b748" +dependencies = [ + "cfg-if", + "cortex-m", + "fugit", + "portable-atomic", + "rtic-time", +] + +[[package]] +name = "rtic-time" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7b1d853fa50dc125695414ce4510567a0d420221e455b1568cfa8c9aece9614" +dependencies = [ + "critical-section", + "embedded-hal 1.0.0", + "embedded-hal-async", + "fugit", + "futures-util", + "rtic-common", ] [[package]] @@ -526,18 +634,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", @@ -584,18 +692,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.4" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +checksum = "8fec2a1820ebd077e2b90c4df007bebf344cd394098a13c563957d0afc83ea47" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.4" +version = "2.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +checksum = "d65750cab40f4ff1929fb1ba509e9914eb756131cef4210da8d5d700d26f6312" dependencies = [ "proc-macro2", "quote", @@ -620,6 +728,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98816b1accafbb09085168b90f27e93d790b4bfa19d883466b5e53315b5f06a6" dependencies = [ + "defmt", "heapless", "portable-atomic", ] @@ -630,6 +739,7 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f291ab53d428685cc780f08a2eb9d5d6ff58622db2b36e239a4f715f1e184c" dependencies = [ + "defmt", "serde", "ssmarshal", "usb-device", @@ -652,7 +762,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb573c76e7884035ac5e1ab4a81234c187a82b6100140af0ab45757650ccda38" dependencies = [ "byteorder", - "hashbrown", + "hashbrown 0.13.2", "log", "proc-macro2", "quote", @@ -700,19 +810,12 @@ dependencies = [ "vcell", ] -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - [[package]] name = "zerocopy" version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ - "byteorder", "zerocopy-derive", ] diff --git a/nrf52-code/loopback-fw/Cargo.toml b/nrf52-code/loopback-fw/Cargo.toml index 4fad8c8f..3ad226e0 100644 --- a/nrf52-code/loopback-fw/Cargo.toml +++ b/nrf52-code/loopback-fw/Cargo.toml @@ -7,33 +7,12 @@ version = "0.0.0" [dependencies] consts = { path = "../consts" } -cortex-m = {version = "0.7.7", features = ["critical-section-single-core"]} -cortex-m-rt = "0.7.5" -critical-section = "1.2.0" +defmt = "0.3.10" +defmt-rtt = "0.4.1" dongle = { path = "../boards/dongle" } -embedded-hal = "1.0" -usb-device = "0.3" -usbd-hid = "0.8" -usbd-serial = "0.2" - -[build-dependencies] -rand = "0.8.5" - -# optimize code in both profiles -[profile.dev] -codegen-units = 1 -debug = 2 -debug-assertions = true # ! -incremental = false -lto = "fat" -opt-level = 'z' # ! -overflow-checks = false - -[profile.release] -codegen-units = 1 -debug = 2 -debug-assertions = false -incremental = false -lto = "fat" -opt-level = 3 -overflow-checks = false +heapless = { version = "0.8.0", features = ["defmt-03"] } +rtic = { version = "2.1.2", features = ["thumbv7-backend"] } +rtic-monotonics = { version = "2.0.3", features = ["cortex-m-systick"] } +usb-device = { version = "0.3.2", features = ["defmt"] } +usbd-hid = { version = "0.8.2", features = ["defmt"] } +usbd-serial = "0.2.2" diff --git a/nrf52-code/loopback-fw/src/main.rs b/nrf52-code/loopback-fw/src/main.rs index 002e58be..c8f512f4 100644 --- a/nrf52-code/loopback-fw/src/main.rs +++ b/nrf52-code/loopback-fw/src/main.rs @@ -2,313 +2,392 @@ //! //! Sets up a USB Serial port and listens for radio packets. -#![no_std] #![no_main] +#![no_std] -use core::fmt::Write; -use core::sync::atomic::{AtomicBool, AtomicU32, Ordering}; - -use cortex_m_rt::entry; -use usb_device::class_prelude::UsbBusAllocator; -use usb_device::device::{StringDescriptors, UsbDevice, UsbDeviceBuilder, UsbVidPid}; -use usb_device::LangID; -use usbd_hid::hid_class::HIDClass; -use usbd_serial::SerialPort; - -use dongle::peripheral::interrupt; -use dongle::{ - hal::usbd, - ieee802154::{Channel, Packet}, - GlobalIrqState, LocalIrqState, UsbBus, -}; - -/// A buffer for holding bytes we want to send to the USB Serial port -static RING_BUFFER: dongle::Ringbuffer = dongle::Ringbuffer::new(); - -/// The USB Device Driver (owned by the USBD interrupt). -static USB_DEVICE: GlobalIrqState> = GlobalIrqState::new(); - -/// The USB Serial Device Driver (owned by the USBD interrupt). -static USB_SERIAL: GlobalIrqState> = GlobalIrqState::new(); - -/// The USB Human Interface Device Driver (owned by the USBD interrupt). -static USB_HID: GlobalIrqState> = GlobalIrqState::new(); - -/// Track how many CRC successes we had receiving radio packets -static RX_COUNT: AtomicU32 = AtomicU32::new(0); - -/// Track how many CRC failures we had receiving radio packets -static ERR_COUNT: AtomicU32 = AtomicU32::new(0); - -/// The USB interrupt sets this to < u32::MAX when a new channel is sent over HID. -/// -/// The main loop handles it and sets it back to u32::MAX when processed. -static NEW_CHANNEL: AtomicU32 = AtomicU32::new(u32::MAX); - -/// Set to true when we get a ?. -/// -/// We print some info in response. -static WANT_INFO: AtomicBool = AtomicBool::new(false); - -#[entry] -fn main() -> ! { - // The USB Bus, statically allocated - static mut USB_BUS: Option> = None; - - let mut board = dongle::init().unwrap(); - - board.usbd.inten.modify(|_r, w| { - w.sof().set_bit(); - w - }); - - let usb_bus = UsbBusAllocator::new(usbd::Usbd::new(usbd::UsbPeripheral::new( - board.usbd, - board.clocks, - ))); - USB_BUS.replace(usb_bus); - - // Grab a reference to the USB Bus allocator. We are promising to the - // compiler not to take mutable access to this global variable whilst this - // reference exists! - let bus_ref = USB_BUS.as_ref().unwrap(); +use defmt_rtt as _; + +#[rtic::app(device = dongle, peripherals = false)] +mod app { + use core::mem::MaybeUninit; + use rtic_monotonics::systick::prelude::*; + const QUEUE_LEN: usize = 8; + + systick_monotonic!(Mono, 100); + + /// An adapter that lets us writeln! into any closure that takes a byte. + /// + /// This is useful if writing a byte requires taking a lock, and you don't + /// want to hold the lock for the duration of the write. + struct Writer(F) + where + F: FnMut(&[u8]); + + impl core::fmt::Write for Writer + where + F: FnMut(&[u8]), + { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + (self.0)(s.as_bytes()); + Ok(()) + } + } - USB_SERIAL.load(SerialPort::new(bus_ref)); + #[local] + struct MyLocalResources { + /// The radio subsystem + radio: dongle::ieee802154::Radio<'static>, + /// Which channel are we on + current_channel: u8, + /// Holds one package, for receive or transmit + packet: dongle::ieee802154::Packet, + /// Used to measure elapsed time + timer: dongle::Timer, + /// How many packets have been received OK? + rx_count: u32, + /// How many packets have been received with errors? + err_count: u32, + /// A place to read the message queue + msg_queue_out: heapless::spsc::Consumer<'static, Message, QUEUE_LEN>, + /// A place to write to the message queue + msg_queue_in: heapless::spsc::Producer<'static, Message, QUEUE_LEN>, + /// A status LED + led: dongle::Led, + } - let desc = &[ - 0x06, 0x00, 0xFF, // Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xA1, 0x01, // Item(Main ): Collection, data= [ 0x01 ] 1 - // Application - 0x15, 0x00, // Item(Global): Logical Minimum, data= [ 0x00 ] 0 - 0x26, 0xFF, 0x00, // Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 - 0x75, 0x08, // Item(Global): Report Size, data= [ 0x08 ] 8 - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x81, 0x02, // Item(Main ): Input, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0x91, 0x02, // Item(Main ): Output, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0x95, 0x01, // Item(Global): Report Count, data= [ 0x01 ] 1 - 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 - 0xB1, 0x02, // Item(Main ): Feature, data= [ 0x02 ] 2 - // Data Variable Absolute No_Wrap Linear - // Preferred_State No_Null_Position Non_Volatile Bitfield - 0xC0, // Item(Main ): End Collection, data=none - ]; - USB_HID.load(HIDClass::new(bus_ref, desc, 100)); + #[derive(Debug, defmt::Format, Copy, Clone, PartialEq, Eq)] + enum Message { + ChangeChannel(u8), + WantInfo, + } - let strings = StringDescriptors::new(LangID::EN) - .manufacturer("Ferrous Systems") - .product("Dongle Puzzle"); + #[shared] + struct MySharedResources { + /// Handles the USB Serial interface, including a ring buffer + usb_serial: usbd_serial::SerialPort<'static, dongle::UsbBus>, + /// Handles the USB HID interface + usb_hid: usbd_hid::hid_class::HIDClass<'static, dongle::UsbBus>, + /// Handles the lower-level USB Device interface + usb_device: usb_device::device::UsbDevice<'static, dongle::UsbBus>, + } - let vid_pid = UsbVidPid(consts::USB_VID_DEMO, consts::USB_PID_DONGLE_LOOPBACK); - // See https://www.usb.org/sites/default/files/iadclasscode_r10.pdf - // and https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/usb-interface-association-descriptor - USB_DEVICE.load( - UsbDeviceBuilder::new(bus_ref, vid_pid) + #[init(local = [ + usb_alloc: MaybeUninit> = MaybeUninit::uninit(), + queue: heapless::spsc::Queue = heapless::spsc::Queue::new(), + ])] + fn init(ctx: init::Context) -> (MySharedResources, MyLocalResources) { + let mut board = dongle::init().unwrap(); + Mono::start(ctx.core.SYST, 64_000_000); + + defmt::debug!("Enabling interrupts..."); + board.usbd.inten.modify(|_r, w| { + w.sof().set_bit(); + w + }); + + defmt::debug!("Building USB allocator..."); + let usbd = dongle::UsbBus::new(dongle::hal::usbd::UsbPeripheral::new( + board.usbd, + board.clocks, + )); + let usb_alloc = ctx + .local + .usb_alloc + .write(usb_device::bus::UsbBusAllocator::new(usbd)); + + defmt::debug!("Creating usb_serial..."); + let usb_serial = usbd_serial::SerialPort::new(usb_alloc); + + defmt::debug!("Creating usb_hid..."); + let desc = &[ + 0x06, 0x00, 0xFF, // Item(Global): Usage Page, data= [ 0x00 0xff ] 65280 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0xA1, 0x01, // Item(Main ): Collection, data= [ 0x01 ] 1 + // Application + 0x15, 0x00, // Item(Global): Logical Minimum, data= [ 0x00 ] 0 + 0x26, 0xFF, 0x00, // Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255 + 0x75, 0x08, // Item(Global): Report Size, data= [ 0x08 ] 8 + 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0x81, 0x02, // Item(Main ): Input, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0x95, 0x40, // Item(Global): Report Count, data= [ 0x40 ] 64 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0x91, 0x02, // Item(Main ): Output, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0x95, 0x01, // Item(Global): Report Count, data= [ 0x01 ] 1 + 0x09, 0x01, // Item(Local ): Usage, data= [ 0x01 ] 1 + 0xB1, 0x02, // Item(Main ): Feature, data= [ 0x02 ] 2 + // Data Variable Absolute No_Wrap Linear + // Preferred_State No_Null_Position Non_Volatile Bitfield + 0xC0, // Item(Main ): End Collection, data=none + ]; + let usb_hid = usbd_hid::hid_class::HIDClass::new(usb_alloc, desc, 100); + + defmt::debug!("Building USB Strings..."); + let strings = usb_device::device::StringDescriptors::new(usb_device::LangID::EN) + .manufacturer("Ferrous Systems") + .product("Test Device"); + + defmt::debug!("Building VID and PID..."); + let vid_pid = + usb_device::device::UsbVidPid(consts::USB_VID_DEMO, consts::USB_PID_DONGLE_LOOPBACK); + + defmt::debug!("Building USB Device..."); + let usb_device = usb_device::device::UsbDeviceBuilder::new(usb_alloc, vid_pid) .composite_with_iads() .strings(&[strings]) - .expect("adding strings") - // (makes control transfers 8x faster) + .expect("Adding strings") .max_packet_size_0(64) - .expect("set packet size") - .build(), - ); + .expect("set_packet_size") + .build(); - let mut current_ch_id = 20; - board.radio.set_channel(dongle::ieee802154::Channel::_20); + defmt::debug!("Configuring radio..."); + board.radio.set_channel(dongle::ieee802154::Channel::_20); + let current_channel = 20; - // Turn on USB interrupts... - unsafe { - cortex_m::peripheral::NVIC::unmask(dongle::peripheral::Interrupt::USBD); - }; + let (msg_queue_in, msg_queue_out) = ctx.local.queue.split(); - let _ = writeln!( - &RING_BUFFER, - "deviceid={:08x}{:08x} channel={} TxPower=+8dBm app=loopback-fw", - dongle::deviceid1(), - dongle::deviceid0(), - current_ch_id - ); - - board.leds.ld1.on(); - board.leds.ld2_blue.on(); - let mut pkt = Packet::new(); - loop { - // Wait up to 1 second for a radio packet - match board - .radio - .recv_timeout(&mut pkt, &mut board.timer, 1_000_000) - { - Ok(crc) => { - board.leds.ld1.toggle(); - let _ = writeln!( - &RING_BUFFER, - "received {} bytes (CRC=Ok(0x{:04x}), LQI={})", - pkt.len(), - crc, - pkt.lqi() - ); - // reverse the bytes, so olleh -> hello - pkt.reverse(); - // send packet after 5ms (we know the client waits for 10ms and - // we want to ensure they are definitely in receive mode by the - // time we send this reply) - board.timer.delay(5000); - board.radio.send(&mut pkt); - RX_COUNT.fetch_add(1, Ordering::Relaxed); - } - Err(dongle::ieee802154::Error::Crc(_)) => { - ERR_COUNT.fetch_add(1, Ordering::Relaxed); - } - Err(dongle::ieee802154::Error::Timeout) => { - // do nothing - } - } + defmt::debug!("Building structures..."); + let shared = MySharedResources { + usb_serial, + usb_hid, + usb_device, + }; + let local = MyLocalResources { + radio: board.radio, + current_channel, + packet: dongle::ieee802154::Packet::new(), + timer: board.timer, + rx_count: 0, + err_count: 0, + msg_queue_out, + msg_queue_in, + led: board.leds.ld1, + }; - // Handle channel changes - let ch_id = NEW_CHANNEL.load(Ordering::Relaxed); - if ch_id != u32::MAX { - NEW_CHANNEL.store(u32::MAX, Ordering::Relaxed); - if let Some(channel) = match ch_id { - 11 => Some(Channel::_11), - 12 => Some(Channel::_12), - 13 => Some(Channel::_13), - 14 => Some(Channel::_14), - 15 => Some(Channel::_15), - 16 => Some(Channel::_16), - 17 => Some(Channel::_17), - 18 => Some(Channel::_18), - 19 => Some(Channel::_19), - 20 => Some(Channel::_20), - 21 => Some(Channel::_21), - 22 => Some(Channel::_22), - 23 => Some(Channel::_23), - 24 => Some(Channel::_24), - 25 => Some(Channel::_25), - 26 => Some(Channel::_26), - _ => None, - } { - board.radio.set_channel(channel); - let _ = writeln!(&RING_BUFFER, "now listening on channel {}", ch_id); - current_ch_id = ch_id; - } else { - let _ = writeln!(&RING_BUFFER, "Channel {} invalid", ch_id); - } - } + defmt::debug!("Init Complete!"); - // Print help text when ? is pressed - if WANT_INFO.load(Ordering::Relaxed) { - WANT_INFO.store(false, Ordering::Relaxed); - let _ = writeln!( - &RING_BUFFER, - "rx={}, err={}, ch={}, app=loopback-fw", - RX_COUNT.load(Ordering::Relaxed), - ERR_COUNT.load(Ordering::Relaxed), - current_ch_id, - ); - } + (shared, local) } -} - -/// Handles USB interrupts -/// -/// Polls all the USB devices, and copies bytes from [`RING_BUFFER`] into the -/// USB UART. -#[interrupt] -fn USBD() { - static mut LOCAL_USB_DEVICE: LocalIrqState> = LocalIrqState::new(); - static mut LOCAL_USB_SERIAL: LocalIrqState> = LocalIrqState::new(); - static mut LOCAL_USB_HID: LocalIrqState> = LocalIrqState::new(); - static mut IS_PENDING: Option = None; - // Grab a reference to our local vars, moving the object out of the global as required... - let usb_dev = LOCAL_USB_DEVICE.get_or_init_with(&USB_DEVICE); - let serial = LOCAL_USB_SERIAL.get_or_init_with(&USB_SERIAL); - let hid = LOCAL_USB_HID.get_or_init_with(&USB_HID); + #[idle(local = [radio, current_channel, packet, timer, rx_count, err_count, msg_queue_out, led], shared = [usb_serial])] + fn idle(mut ctx: idle::Context) -> ! { + use core::fmt::Write as _; + let mut writer = Writer(|b: &[u8]| { + ctx.shared.usb_serial.lock(|usb_serial| { + let _ = usb_serial.write(b); + }) + }); + + defmt::info!( + "deviceid={=u32:08x}{=u32:08x} channel={=u8} TxPower=+8dBm app=loopback-fw", + dongle::deviceid1(), + dongle::deviceid0(), + ctx.local.current_channel + ); - let mut buf = [0u8; 64]; - - // Poll the USB driver with all of our supported USB Classes - if usb_dev.poll(&mut [serial, hid]) { - match serial.read(&mut buf) { - Err(_e) => { - // Do nothing - } - Ok(0) => { - // Do nothing - } - Ok(count) => { - for item in &buf[0..count] { - // Look for question marks - if *item == b'?' { - WANT_INFO.store(true, Ordering::Relaxed); + loop { + while let Some(msg) = ctx.local.msg_queue_out.dequeue() { + match msg { + Message::WantInfo => { + defmt::info!( + "rx={=u32}, err={=u32}, ch={=u8}, app=loopback-fw", + ctx.local.rx_count, + ctx.local.err_count, + ctx.local.current_channel + ); + let _ = writeln!( + writer, + "\nrx={}, err={}, ch={}, app=loopback-fw", + ctx.local.rx_count, ctx.local.err_count, ctx.local.current_channel + ); + } + Message::ChangeChannel(n) => { + defmt::info!("Changing Channel to {}", n); + let _ = writeln!(writer, "\nChanging Channel to {}", n); + match n { + 11 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_11); + } + 12 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_12); + } + 13 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_13); + } + 14 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_14); + } + 15 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_15); + } + 16 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_16); + } + 17 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_17); + } + 18 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_18); + } + 19 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_19); + } + 20 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_20); + } + 21 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_21); + } + 22 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_22); + } + 23 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_23); + } + 24 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_24); + } + 25 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_25); + } + 26 => { + ctx.local + .radio + .set_channel(dongle::ieee802154::Channel::_26); + } + _ => { + defmt::info!("Bad Channel {}!", n); + } + } } } } - } - let hid_byte = match hid.pull_raw_output(&mut buf) { - Ok(64) => { - // Windows zero-pads the packet - Some(buf[0]) - } - Ok(1) => { - // macOS/Linux sends a single byte - Some(buf[0]) - } - Ok(_n) => { - // Ignore any other size packet - None - } - Err(_e) => None, - }; - if let Some(ch) = hid_byte { - NEW_CHANNEL.store(ch as u32, Ordering::Relaxed); - } - } - // Is there a pending byte from last time? - if let Some(n) = IS_PENDING { - match serial.write(core::slice::from_ref(n)) { - Ok(_) => { - // it took our pending byte - *IS_PENDING = None; - } - Err(_) => { - // serial buffer is full - return; + defmt::debug!("Waiting for packet.."); + match ctx.local.radio.recv_timeout( + &mut ctx.local.packet, + &mut ctx.local.timer, + 1_000_000, + ) { + Ok(crc) => { + ctx.local.led.toggle(); + defmt::info!( + "Received {=u8} bytes (CRC=0x{=u16:04x}, LQI={})", + ctx.local.packet.len(), + crc, + ctx.local.packet.lqi(), + ); + let _ = writeln!( + writer, + "\nReceived {} bytes (CRC=0x{:04x}, LQI={})", + ctx.local.packet.len(), + crc, + ctx.local.packet.lqi(), + ); + *ctx.local.rx_count += 1; + // reverse the bytes, so olleh -> hello + ctx.local.packet.reverse(); + // send packet after 5ms (we know the client waits for 10ms and + // we want to ensure they are definitely in receive mode by the + // time we send this reply) + ctx.local.timer.delay(5000); + ctx.local.radio.send(ctx.local.packet); + } + Err(dongle::ieee802154::Error::Crc(_)) => { + defmt::debug!("RX fail!"); + let _ = write!(writer, "!"); + *ctx.local.err_count += 1; + } + Err(dongle::ieee802154::Error::Timeout) => { + defmt::debug!("RX timeout..."); + let _ = write!(writer, "."); + } } } } - // Copy some more from the ring-buffer to the USB Serial interface, - // until the serial interface is full. - while let Some(item) = RING_BUFFER.read() { - let s = &[item]; - if serial.write(s).is_err() { - // the USB UART can't take this byte right now - *IS_PENDING = Some(item); - break; - } + /// USB Interrupt Handler + /// + /// USB Device is set to fire this whenever there's a Start of Frame from + /// the USB Host. + #[task(binds = USBD, local = [msg_queue_in], shared = [usb_serial, usb_hid, usb_device])] + fn usb_isr(mut ctx: usb_isr::Context) { + let mut all = ( + &mut ctx.shared.usb_serial, + &mut ctx.shared.usb_hid, + &mut ctx.shared.usb_device, + ); + all.lock(|usb_serial, usb_hid, usb_device| { + if usb_device.poll(&mut [usb_serial, usb_hid]) { + let mut buffer = [0u8; 64]; + if let Ok(n) = usb_serial.read(&mut buffer) { + if n > 0 { + for b in &buffer[0..n] { + if *b == b'?' { + // User pressed "?" in the terminal + _ = ctx.local.msg_queue_in.enqueue(Message::WantInfo); + } + } + } + } + if let Ok(n) = usb_hid.pull_raw_output(&mut buffer) { + // Linux sends 1 byte, Windows sends 64 (with 63 zero bytes) + if n == 1 || n == 64 { + _ = ctx + .local + .msg_queue_in + .enqueue(Message::ChangeChannel(buffer[0])); + } + } + } + }); } - - cortex_m::asm::sev(); } #[panic_handler] fn panic(info: &core::panic::PanicInfo) -> ! { - let _ = writeln!(&RING_BUFFER, "Panic: {:?}", info); - cortex_m::asm::delay(64_000_000 * 2); - unsafe { - loop { - core::arch::asm!("bkpt 0x00"); - } + if let Some(location) = info.location() { + defmt::error!("Panic at {}:{}", location.file(), location.line()); + } else { + defmt::error!("Panic at unknown location"); + } + loop { + core::hint::spin_loop(); } } -// End of file +defmt::timestamp!("{=u64:tus}", dongle::uptime_us());