diff --git a/boards/dongle/README.md b/boards/dongle/README.md index cb24652..f7f8968 100644 --- a/boards/dongle/README.md +++ b/boards/dongle/README.md @@ -47,7 +47,7 @@ to: [81, 78, 109, 61, 120, 87, 125, 98, 100, 91, 97, 66, 57, 117, 49, 64, 48, 85 secret: ">?>h$IUQhL&P*Up&6w" ``` -### Generate `puzzle.hex` +### Generate `puzzle` ELF ``` console $ git clone --branch dongle-puzzle https://github.com/japaric/embedded2020 @@ -55,9 +55,9 @@ $ git clone --branch dongle-puzzle https://github.com/japaric/embedded2020 $ cd embedded2020/firmware/apps ``` -Copy the `puzzle.rs` from this folder into the `embedded2020/firmware/apps/src/bin` folder. +Find `puzzle.rs` in the `embedded2020/firmware/apps/src/bin` folder. -Update that copy of `puzzle.rs` with the `FROM`, `TO` and `SECRET` data that you got from `puzzlegen` +Update `puzzle.rs` with the `FROM`, `TO` and `SECRET` data that you got from `puzzlegen` ```` rust static FROM: &[u8] = &[ @@ -80,38 +80,34 @@ static TO: &[u8] = &[ static SECRET: &[u8] = b">?>h$IUQhL&P*Up&6w"; ```` -Build the program; this will produce an ELF file. +Build the program; this will produce an ELF file called `puzzle` (no file ending). ``` console $ cargo build --bin puzzle --release ``` -Convert that ELF file into a .hex file. +Copy this ELF file from `embedded2020/firmware/target/thumbv7em-none-eabi/release` to `embedded-trainings-2020/boards/dongle` -``` console -$ arm-none-eabi-objcopy -O ihex ../target/thumbv7em-none-eabi/release/puzzle puzzle.hex -``` +Test the produced `puzzle` file: -Test the produced `puzzle.hex` file: - -- flash it onto a dongle using `cargo xtask dongle-flash`. The green LED on the dongle should turn on +- flash it onto a dongle using `nrfdfu puzzle`. The green LED on the dongle should turn on - run `cargo xtask serial-term`; you should see the following output. `deviceid` will be different ``` text -deviceid=d90eedf1978d5fd2 channel=25 TxPower=+8dBm app=puzzle.hex +deviceid=d90eedf1978d5fd2 channel=25 TxPower=+8dBm app=puzzle ``` - run the `radio-puzzle-solution` program on a DK; it should be able to decrypt the new secret - run `cargo xtask change-channel ` to test changing the Dongle's radio channel - modify and re-run the `radio-puzzle-solution` program on a DK to solve the puzzle using a the channel you set in the previous step -### Generate `puzzle-nousb-*.hex` +### Generate `puzzle-nousb-*` -The procedure is similar to the one for generating the `puzzle.hex`. The differences are: +The procedure is similar to the one for generating the `puzzle` ELF file. The differences are: -- you copy `puzzle-nousb.rs` into the `embedded2020` repository -- you also need to change `const CHANNEL` in the `puzzle-nousb.rs` copy -- you need to produce one hex file per hard-coded radio channel. +- you build `puzzle-nousb.rs` in the `embedded2020` repository and copy `embedded2020/firmware/target/thumbv7em-none-eabi/release/puzzle-nousb` over +- you also need to change `const CHANNEL` in `puzzle-nousb.rs` +- you need to produce one ELF file per hard-coded radio channel. -Also test these `nousb` .hex files. Note that the green LED won't turn on when the dongle restarts! The green LED will toggle when a new packet is received and the blue LED will turn on when the decoded secret is received. Also, `cargo xtask change-channel` won't work with the `nousb` variants so you can skip that test. +Also test these `nousb` ELF files. Note that the green LED won't turn on when the dongle restarts! The green LED will toggle when a new packet is received and the blue LED will turn on when the decoded secret is received. Also, `cargo xtask change-channel` won't work with the `nousb` variants so you can skip that test. ## References diff --git a/boards/dongle/deprecated_hex/README.md b/boards/dongle/deprecated_hex/README.md new file mode 100644 index 0000000..c633af8 --- /dev/null +++ b/boards/dongle/deprecated_hex/README.md @@ -0,0 +1,5 @@ +# For `nrfutil` Users only + +The files in this directory are only relevant if you are still using the `nrfutil` python tool distributed by Nordic Semiconductors. + +For a smoother installation and usage experience, we recommend you install [`nrfdfu`](https://crates.io/crates/nrfdfu) if at all possible. \ No newline at end of file diff --git a/boards/dongle/loopback-nousb11.hex b/boards/dongle/deprecated_hex/loopback-nousb11.hex similarity index 100% rename from boards/dongle/loopback-nousb11.hex rename to boards/dongle/deprecated_hex/loopback-nousb11.hex diff --git a/boards/dongle/loopback-nousb16.hex b/boards/dongle/deprecated_hex/loopback-nousb16.hex similarity index 100% rename from boards/dongle/loopback-nousb16.hex rename to boards/dongle/deprecated_hex/loopback-nousb16.hex diff --git a/boards/dongle/loopback-nousb21.hex b/boards/dongle/deprecated_hex/loopback-nousb21.hex similarity index 100% rename from boards/dongle/loopback-nousb21.hex rename to boards/dongle/deprecated_hex/loopback-nousb21.hex diff --git a/boards/dongle/loopback-nousb26.hex b/boards/dongle/deprecated_hex/loopback-nousb26.hex similarity index 100% rename from boards/dongle/loopback-nousb26.hex rename to boards/dongle/deprecated_hex/loopback-nousb26.hex diff --git a/boards/dongle/loopback.hex b/boards/dongle/deprecated_hex/loopback.hex similarity index 100% rename from boards/dongle/loopback.hex rename to boards/dongle/deprecated_hex/loopback.hex diff --git a/boards/dongle/puzzle-nousb11.hex b/boards/dongle/deprecated_hex/puzzle-nousb11.hex similarity index 100% rename from boards/dongle/puzzle-nousb11.hex rename to boards/dongle/deprecated_hex/puzzle-nousb11.hex diff --git a/boards/dongle/puzzle-nousb16.hex b/boards/dongle/deprecated_hex/puzzle-nousb16.hex similarity index 100% rename from boards/dongle/puzzle-nousb16.hex rename to boards/dongle/deprecated_hex/puzzle-nousb16.hex diff --git a/boards/dongle/puzzle-nousb21.hex b/boards/dongle/deprecated_hex/puzzle-nousb21.hex similarity index 100% rename from boards/dongle/puzzle-nousb21.hex rename to boards/dongle/deprecated_hex/puzzle-nousb21.hex diff --git a/boards/dongle/puzzle-nousb26.hex b/boards/dongle/deprecated_hex/puzzle-nousb26.hex similarity index 100% rename from boards/dongle/puzzle-nousb26.hex rename to boards/dongle/deprecated_hex/puzzle-nousb26.hex diff --git a/boards/dongle/puzzle.hex b/boards/dongle/deprecated_hex/puzzle.hex similarity index 100% rename from boards/dongle/puzzle.hex rename to boards/dongle/deprecated_hex/puzzle.hex diff --git a/boards/dongle/loopback-nousb.rs b/boards/dongle/loopback-nousb.rs deleted file mode 100644 index 2283049..0000000 --- a/boards/dongle/loopback-nousb.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![deny(unused_must_use)] -#![no_main] -#![no_std] - -use hal::{radio::{self, Channel}, led}; -use panic_abort as _; - -#[no_mangle] -fn main() -> ! { - let (mut rtx, mut rrx) = radio::claim(Channel::_21); // <- change this - let led = led::Green; - - let task = async { - let mut packet = radio::Packet::new().await; - let mut on = true; - - loop { - let crcres = rrx.read(&mut packet).await; - // togle LED on each new packet - if on { - led.on(); - } else { - led.off(); - } - on = !on; - - if crcres.is_ok() { - packet.reverse(); - rtx.write(&packet).await.ok(); - } - } - }; - - executor::run!(task) -} diff --git a/boards/dongle/loopback-nousb11 b/boards/dongle/loopback-nousb11 new file mode 100755 index 0000000..ab0a0b1 Binary files /dev/null and b/boards/dongle/loopback-nousb11 differ diff --git a/boards/dongle/loopback-nousb16 b/boards/dongle/loopback-nousb16 new file mode 100755 index 0000000..d38f561 Binary files /dev/null and b/boards/dongle/loopback-nousb16 differ diff --git a/boards/dongle/loopback-nousb21 b/boards/dongle/loopback-nousb21 new file mode 100755 index 0000000..41c0f9f Binary files /dev/null and b/boards/dongle/loopback-nousb21 differ diff --git a/boards/dongle/loopback-nousb26 b/boards/dongle/loopback-nousb26 new file mode 100755 index 0000000..5b53798 Binary files /dev/null and b/boards/dongle/loopback-nousb26 differ diff --git a/boards/dongle/loopback.rs b/boards/dongle/loopback.rs deleted file mode 100644 index 65a886c..0000000 --- a/boards/dongle/loopback.rs +++ /dev/null @@ -1,125 +0,0 @@ -#![deny(unused_must_use)] -#![no_main] -#![no_std] - -use core::{convert::TryFrom, fmt::Write as _}; - -use async_core::unsync::Mutex; -use hal::{ - radio::{self, Channel}, - usbd, -}; -use heapless::{consts, String}; -use panic_abort as _; - -#[no_mangle] -fn main() -> ! { - let stx = Mutex::new(usbd::serial()); - let (mut hidout, _) = usbd::hid(); - let (rtx, mut rrx) = radio::claim(Channel::_20); - - let mut output = String::::new(); - - output.push_str("deviceid=").ok(); - write!(output, "{:08x}{:08x}", hal::deviceid1(), hal::deviceid0()).ok(); - write!( - output, - " channel={} TxPower=+8dBm app=loopback.hex\n", - rtx.channel() - ) - .ok(); - - let rtx = Mutex::new(rtx); - - let t1 = async { - let mut output = String::::new(); - let mut hidbuf = usbd::Packet::new().await; - let zlp = radio::Packet::new().await; - - loop { - hidout.recv(&mut hidbuf).await; - semidap::info!("HID: {}", *hidbuf); - - let arg = if hidbuf.len() == 1 { - // Linux / macOS - Some(hidbuf[0]) - } else if hidbuf.len() == 64 { - // Windows (it zero pads the packet) - Some(hidbuf[0]) - } else { - None - }; - - if let Some(arg) = arg { - if let Ok(chan) = Channel::try_from(arg) { - let mut rtx = rtx.lock().await; - rtx.set_channel(chan); - // send a zero-length packet to force the radio to listen on the new channel - rtx.write(&zlp).await.ok(); - drop(rtx); - - output.clear(); - writeln!(output, "now listening on channel {}", chan).ok(); - stx.lock().await.write(output.as_bytes()); - } else { - stx.lock() - .await - .write(b"requested channel is out of range (11-26)\n"); - } - } else { - stx.lock().await.write(b"invalid HID packet\n"); - } - } - }; - - let t2 = async { - let mut packet = radio::Packet::new().await; - stx.lock().await.write(output.as_bytes()); - - loop { - let crcres = rrx.read(&mut packet).await; - let len = packet.len(); - let lqi = if len >= 3 { - Some(packet.lqi()) - } else { - // packet is too small; LQI is not valid - None - }; - - let mut busy = false; - if crcres.is_ok() { - packet.reverse(); - busy = rtx.lock().await.write(&packet).await.is_err(); - } - - output.clear(); - write!( - &mut output, - "received {} byte{}", - len, - if len == 1 { "" } else { "s" } - ) - .ok(); - - let (res, crc) = match crcres { - Ok(x) => ("Ok", x), - Err(x) => ("Err", x), - }; - - write!(&mut output, " (CRC={}({:#06x})", res, crc).ok(); - if let Some(lqi) = lqi { - write!(&mut output, ", LQI={}", lqi).ok(); - } - output.push_str(")\n").ok(); - - if busy { - output.push_str("didn't reply -- channel was busy\n").ok(); - stx.lock().await.write(output.as_bytes()); - } - - stx.lock().await.write(output.as_bytes()); - } - }; - - executor::run!(t1, t2) -} diff --git a/boards/dongle/puzzle-nousb.rs b/boards/dongle/puzzle-nousb.rs deleted file mode 100644 index b1962c8..0000000 --- a/boards/dongle/puzzle-nousb.rs +++ /dev/null @@ -1,80 +0,0 @@ -#![deny(unused_must_use)] -#![no_main] -#![no_std] - -use hal::{ - led, - radio::{self, Channel, Packet}, -}; -use heapless::{consts, LinearMap}; -use panic_abort as _; - -const CHANNEL: Channel = Channel::_26; - -static FROM: &[u8] = &[ - // -]; - -static TO: &[u8] = &[ - // -]; - -// store the secret rather than the plaintext -- otherwise `strings $elf` will reveal the answer -static SECRET: &[u8] = b""; - -#[no_mangle] -fn main() -> ! { - let (mut rtx, mut rrx) = radio::claim(CHANNEL); - let led = led::Green; - - let mut dict = LinearMap::<_, _, consts::U128>::new(); - for (&from, &to) in FROM.iter().zip(TO.iter()) { - dict.insert(from, to).ok(); - } - - let task = async { - let mut packet = Packet::new().await; - let mut on = true; - - loop { - let crcres = rrx.read(&mut packet).await; - // toggle LED on each new packet - if on { - led.on(); - } else { - led.off(); - } - on = !on; - - if crcres.is_ok() { - if packet.is_empty() { - packet.copy_from_slice(SECRET); - } else if packet.len() == 1 { - let p = packet[0]; - let c = dict.get(&p).unwrap_or(&p); - packet.copy_from_slice(&[*c]); - } else { - // encrypt - for slot in packet.iter_mut() { - if let Some(c) = dict.get(slot) { - *slot = *c; - } - } - - let matches = &packet[..] == SECRET; - packet.copy_from_slice(if matches { - led::Blue.on(); - b"correct" - } else { - led::Blue.off(); - b"incorrect" - }); - } - - rtx.write(&packet).await.ok(); - } - } - }; - - executor::run!(task) -} diff --git a/boards/dongle/puzzle-nousb11 b/boards/dongle/puzzle-nousb11 new file mode 100755 index 0000000..0dc9aea Binary files /dev/null and b/boards/dongle/puzzle-nousb11 differ diff --git a/boards/dongle/puzzle-nousb16 b/boards/dongle/puzzle-nousb16 new file mode 100755 index 0000000..c470aa2 Binary files /dev/null and b/boards/dongle/puzzle-nousb16 differ diff --git a/boards/dongle/puzzle-nousb21 b/boards/dongle/puzzle-nousb21 new file mode 100755 index 0000000..f5e9915 Binary files /dev/null and b/boards/dongle/puzzle-nousb21 differ diff --git a/boards/dongle/puzzle-nousb26 b/boards/dongle/puzzle-nousb26 new file mode 100755 index 0000000..3e1591e Binary files /dev/null and b/boards/dongle/puzzle-nousb26 differ diff --git a/boards/dongle/puzzle.rs b/boards/dongle/puzzle.rs deleted file mode 100644 index c2b9727..0000000 --- a/boards/dongle/puzzle.rs +++ /dev/null @@ -1,156 +0,0 @@ -#![deny(unused_must_use)] -#![no_main] -#![no_std] - -use core::{fmt::Write as _, convert::TryFrom}; - -use async_core::unsync::Mutex; -use hal::{radio::{self, Packet, Channel}, usbd, led}; -use heapless::{consts, LinearMap, String}; -use panic_abort as _; - -static FROM: &[u8] = &[ - // -]; - -static TO: &[u8] = &[ - // -]; - -// store the secret rather than the plaintext -- otherwise `strings $elf` will reveal the answer -static SECRET: &[u8] = b""; - -#[no_mangle] -fn main() -> ! { - // so we can visually differentiate this one from `loopback.hex` - led::Green.on(); - - let stx = Mutex::new(usbd::serial()); - let (mut hidout, _) = usbd::hid(); - let (rtx, mut rrx) = radio::claim(Channel::_25); - let mut output = String::::new(); - - let mut dict = LinearMap::<_, _, consts::U128>::new(); - for (&from, &to) in FROM.iter().zip(TO.iter()) { - dict.insert(from, to).ok(); - } - - output.push_str("deviceid=").ok(); - write!(output, "{:08x}{:08x}", hal::deviceid1(), hal::deviceid0()).ok(); - write!(output, " channel={} TxPower=+8dBm app=puzzle.hex\n", rtx.channel()).ok(); - - let rtx = Mutex::new(rtx); - - let t1 = async { - let mut output = String::::new(); - let mut hidbuf = usbd::Packet::new().await; - let zlp = radio::Packet::new().await; - - loop { - hidout.recv(&mut hidbuf).await; - semidap::info!("HID: {}", *hidbuf); - - let arg = if hidbuf.len() == 1 { - // Linux / macOS - Some(hidbuf[0]) - } else if hidbuf.len() == 64 { - // Windows (it zero pads the packet) - Some(hidbuf[0]) - } else { - None - }; - - if let Some(arg) = arg { - if let Ok(chan) = Channel::try_from(arg) { - let mut rtx = rtx.lock().await; - rtx.set_channel(chan); - // send a zero-length packet to force the radio to listen on the new channel - rtx.write(&zlp).await.ok(); - drop(rtx); - - output.clear(); - writeln!(output, "now listening on channel {}", chan).ok(); - stx.lock().await.write(output.as_bytes()); - } else { - stx.lock() - .await - .write(b"requested channel is out of range (11-26)\n"); - } - } else { - stx.lock().await.write(b"invalid HID packet\n"); - } - } - }; - - let t2 = async { - let mut packet = Packet::new().await; - stx.lock().await.write(output.as_bytes()); - - loop { - let crcres = rrx.read(&mut packet).await; - let len = packet.len(); - let lqi = if len >= 3 { - Some(packet.lqi()) - } else { - // packet is too small; LQI is not valid - None - }; - - let mut busy = false; - if crcres.is_ok() { - if packet.is_empty() { - packet.copy_from_slice(SECRET); - } else if packet.len() == 1 { - let p = packet[0]; - let c = dict.get(&p).unwrap_or(&p); - packet.copy_from_slice(&[*c]); - } else { - // encrypt - for slot in packet.iter_mut() { - if let Some(c) = dict.get(slot) { - *slot = *c; - } - } - - let matches = &packet[..] == SECRET; - packet.copy_from_slice(if matches { - b"correct" - } else { - b"incorrect" - }); - } - - busy = rtx.lock().await.write(&packet).await.is_err(); - } - - output.clear(); - write!( - &mut output, - "received {} byte{}", - len, - if len == 1 { "" } else { "s" } - ) - .ok(); - - let (res, crc) = match crcres { - Ok(x) => ("Ok", x), - Err(x) => ("Err", x), - }; - - write!(&mut output, " (CRC={}({:#06x})", res, crc).ok(); - if let Some(lqi) = lqi { - write!(&mut output, ", LQI={}", lqi).ok(); - } - output.push_str(")\n").ok(); - - if busy { - output.push_str("didn't reply -- channel was busy\n").ok(); - stx.lock().await.write(output.as_bytes()); - } - - stx.lock().await.write(output.as_bytes()); - } - }; - - executor::run!(t1, t2) -}