From fcf0e310ab3cffd374a4a5b9c36c3342baaeb87d Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Tue, 16 Jun 2020 10:16:25 +0200 Subject: [PATCH] - rework RTIC resources section in the adv. material - change the USB PID so it matches the date of the workshop --- advanced/README.md | 22 ++- advanced/common/consts/src/lib.rs | 2 +- advanced/firmware/src/bin/rtic-resource.rs | 35 ++-- advanced/host/print-descs/Cargo.lock | 190 +++++++++++++++++++++ advanced/host/print-descs/Cargo.toml | 12 ++ advanced/host/print-descs/src/main.rs | 16 ++ tools/usb-list/src/main.rs | 11 +- 7 files changed, 258 insertions(+), 30 deletions(-) create mode 100644 advanced/host/print-descs/Cargo.lock create mode 100644 advanced/host/print-descs/Cargo.toml create mode 100644 advanced/host/print-descs/src/main.rs diff --git a/advanced/README.md b/advanced/README.md index e9827f8..7cdcbbb 100644 --- a/advanced/README.md +++ b/advanced/README.md @@ -58,7 +58,7 @@ Bus 002 Device 001: ID 1d6b:0003 Bus 001 Device 002: ID 0cf3:e300 Bus 001 Device 003: ID 0c45:6713 Bus 001 Device 001: ID 1d6b:0002 -Bus 001 Device 059: ID 2020:0705 <- nRF52840 on the nRF52840 Development Kit +Bus 001 Device 059: ID 2020:0717 <- nRF52840 on the nRF52840 Development Kit ``` ## Hello, world! @@ -130,19 +130,31 @@ Below the `idle` function you'll see a `#[task]` handler (function). This *task* Note that all tasks will be prioritized over the `idle` function so the execution of `idle` will be interrupted (paused) by the `on_power_event` task. When the `on_power_event` task finishes (returns) the execution of the `idle` will be resumed. This will become more obvious in the next section. +Try this: add an infinite loop to `init` so that it never returns. Now run the program and connect the USB cable. What behavior do you observe? + ## Task state -Open the `src/bin/rtic-resources.rs` file. +Now let's say we want to change the previous program to count how many times the USB cable (port J3) has been connected and disconnected. -> TODO +Tasks run from start to finish, like functions, in response to events. To preserve some state between the different executions of a task we can add a *resource* to the task. In RTIC, resources are the mechanism used to share data between different tasks in a memory safe manner but they can also be used to hold task state. -You should always disconnect the device from the host before halting the device. Otherwise, the host will observe an unresponsive USB device and try power cycling the whole USB hub / bus. +To get the desired behavior we'll want to store some counter in the state of the `on_power_event` task. + +Open the `src/bin/rtic-resources.rs` file. The starter code shows the syntax to declare a resource, the `Resources` struct, and the syntax to associate a resource to a task, the `resources` list in the `#[task]` attribute. + +In the starter code a resource is used to *move* the POWER peripheral from `init` to the `on_power_event` task. The POWER peripheral then becomes part of the state of the `on_power_event` task. The resources of a task are available via the `Context` argument of the task. + +We have moved the POWER peripheral into the task because we want to clear the USBDETECTED interrupt flag after it has been set by the hardware. If we miss this step the `on_power_event` task (function) will be called again once it returns and then again and again and again (ad infinitum). + +Also note that in the starter code the `idle` function has been modified. Pay attention to the logs when you run the starter code. + +Your task in this section will be to modify the program so that it prints the number of times the USB cable has been connected to the DK each time the cable is connected. ## USB basics Some basics about the USB protocol. The protocol is complex so we'll leave out many details and focus on the concepts required to get enumeration working. -A USB device, the nRF52840 in our case, can be one of these three states: the Default state, the Address state or the Configured state. +A USB device, the nRF52840 in our case, can be one of these three states: the Default state, the Address state or the Configured state. After being powered the device will start in the Default state. The enumeration process will take the device from the Default state to the Address state. As a result of the enumeration process the device will be assigned an address, in the range `1..=127`, by the host. diff --git a/advanced/common/consts/src/lib.rs b/advanced/common/consts/src/lib.rs index 040f1a6..d9f78db 100644 --- a/advanced/common/consts/src/lib.rs +++ b/advanced/common/consts/src/lib.rs @@ -1,4 +1,4 @@ #![no_std] pub const VID: u16 = 0x2020; -pub const PID: u16 = 0x0715; +pub const PID: u16 = 0x0717; diff --git a/advanced/firmware/src/bin/rtic-resource.rs b/advanced/firmware/src/bin/rtic-resource.rs index 308df7f..c59c798 100644 --- a/advanced/firmware/src/bin/rtic-resource.rs +++ b/advanced/firmware/src/bin/rtic-resource.rs @@ -2,37 +2,42 @@ #![no_std] use cortex_m::asm; -use dk::{peripheral::USBD, usbd}; +use dk::peripheral::POWER; use panic_log as _; // panic handler #[rtic::app(device = dk)] const APP: () = { struct Resources { - usbd: USBD, + power: POWER, } #[init] fn init(_cx: init::Context) -> init::LateResources { let board = dk::init().unwrap(); - // initialize the USB peripheral; will block until the USB cable is physically connected - usbd::init(board.power, &board.usbd); + let power = board.power; - // electrically connects the device to the host - usbd::connect(&board.usbd); + power.intenset.write(|w| w.usbdetected().set_bit()); - init::LateResources { usbd: board.usbd } + log::info!("USBDETECTED interrupt enabled"); + + init::LateResources { power } } - #[task(binds = USBD, resources = [usbd])] - fn usb(cx: usb::Context) { - let usbd = cx.resources.usbd; + #[idle] + fn idle(_cx: idle::Context) -> ! { + loop { + log::info!("idle: going to sleep"); + asm::wfi(); + log::info!("idle: woke up"); + } + } - log::info!("USB event occurred"); + #[task(binds = POWER_CLOCK, resources = [power])] + fn on_power_event(cx: on_power_event::Context) { + log::info!("POWER event occurred"); - // electrically disconnects the device to the host - usbd::disconnect(usbd); - - asm::bkpt(); + // clear the interrupt flag; otherwise this task will run again after it returns + cx.resources.power.events_usbdetected.reset(); } }; diff --git a/advanced/host/print-descs/Cargo.lock b/advanced/host/print-descs/Cargo.lock new file mode 100644 index 0000000..11ecca4 --- /dev/null +++ b/advanced/host/print-descs/Cargo.lock @@ -0,0 +1,190 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "adler32" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2" + +[[package]] +name = "anyhow" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f" + +[[package]] +name = "bit-set" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3" + +[[package]] +name = "cc" +version = "1.0.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "consts" +version = "0.1.0" + +[[package]] +name = "crc32fast" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "filetime" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "affc17579b132fc2461adf7c575cc6e8b134ebca52c51f5411388965227dc695" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "winapi", +] + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "libflate" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9135df43b1f5d0e333385cb6e7897ecd1a43d7d11b91ac003f4d2c2d2401fdd" +dependencies = [ + "adler32", + "crc32fast", + "rle-decode-fast", + "take_mut", +] + +[[package]] +name = "libusb1-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d9ddd446b6f233a79ef7e6f73de63a58f3a9047d60c46f15cda31452a8f86e" +dependencies = [ + "cc", + "libc", + "libflate", + "pkg-config", + "tar", + "vcpkg", +] + +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" + +[[package]] +name = "print-descs" +version = "0.1.0" +dependencies = [ + "anyhow", + "consts", + "rusb", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "rle-decode-fast" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cabe4fa914dec5870285fa7f71f602645da47c486e68486d2b4ceb4a343e90ac" + +[[package]] +name = "rusb" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d10caa3e5fc7ad1879a679bf16d3304ea10614b8f2f1a1386be4ec942d44062a" +dependencies = [ + "bit-set", + "libc", + "libusb1-sys", +] + +[[package]] +name = "take_mut" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60" + +[[package]] +name = "tar" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c058ad0bd6ccb84faa24cc44d4fc99bee8a5d7ba9ff33aa4d993122d1aeeac2" +dependencies = [ + "filetime", + "libc", + "redox_syscall", + "xattr", +] + +[[package]] +name = "vcpkg" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6454029bf181f092ad1b853286f23e2c507d8e8194d01d92da4a55c274a5508c" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "xattr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +dependencies = [ + "libc", +] diff --git a/advanced/host/print-descs/Cargo.toml b/advanced/host/print-descs/Cargo.toml new file mode 100644 index 0000000..3829d2e --- /dev/null +++ b/advanced/host/print-descs/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "print-descs" +version = "0.1.0" +authors = ["Jorge Aparicio "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rusb = "0.5.5" +anyhow = "1.0.31" +consts = { path = "../../common/consts/" } diff --git a/advanced/host/print-descs/src/main.rs b/advanced/host/print-descs/src/main.rs new file mode 100644 index 0000000..cd5819f --- /dev/null +++ b/advanced/host/print-descs/src/main.rs @@ -0,0 +1,16 @@ +use anyhow::anyhow; + +fn main() -> Result<(), anyhow::Error> { + for dev in rusb::devices()?.iter() { + let dev_desc = dev.device_descriptor()?; + if dev_desc.vendor_id() == consts::VID && dev_desc.product_id() == consts::PID { + println!("{:#?}", dev_desc); + for i in 0..dev_desc.num_configurations() { + println!("{}: {:#?}", i, dev.config_descriptor(i)?); + } + return Ok(()); + } + } + + Err(anyhow!("nRF52840 USB device not found")) +} diff --git a/tools/usb-list/src/main.rs b/tools/usb-list/src/main.rs index 50d4fd1..0cbe641 100644 --- a/tools/usb-list/src/main.rs +++ b/tools/usb-list/src/main.rs @@ -3,23 +3,16 @@ use std::error::Error; fn main() -> Result<(), Box> { for dev in rusb::devices()?.iter() { let desc = dev.device_descriptor()?; - let mut show_config = false; let suffix = match (desc.vendor_id(), desc.product_id()) { (0x1366, 0x1015) => " <- J-Link on the nRF52840 Development Kit", (0x1915, 0x521f) => " <- nRF52840 Dongle (in bootloader mode)", (0x2020, 0x0309) => " <- nRF52840 Dongle (loopback.hex)", - (consts::VID, consts::PID) => { - show_config = true; - " <- nRF52840 on the nRF52840 Development Kit" - } + (0x2020, 0x0310) => " <- nRF52840 Dongle (puzzle.hex)", + (consts::VID, consts::PID) => " <- nRF52840 on the nRF52840 Development Kit", _ => "", }; println!("{:?}{}", dev, suffix); - if show_config { - let desc = dev.config_descriptor(0)?; - println!("> {:?}", desc); - } } Ok(())