mirror of
https://github.com/ferrous-systems/embedded-trainings-2020.git
synced 2025-01-25 07:18:08 +00:00
Merge pull request #163 from ferrous-systems/add-dongle-elfs
Add dongle elfs
This commit is contained in:
commit
94d3f558fc
24 changed files with 19 additions and 414 deletions
|
@ -47,7 +47,7 @@ to: [81, 78, 109, 61, 120, 87, 125, 98, 100, 91, 97, 66, 57, 117, 49, 64, 48, 85
|
|||
secret: "<p=-*Uh5&Ph6=PQ_z_6=Q_-Zh_-h&IPh?cj?>>?>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"<p=-*Uh5&Ph6=PQ_z_6=Q_-Zh_-h&IPh?cj?>>?>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 <some number between 11 and 26>` 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
|
||||
|
||||
|
|
5
boards/dongle/deprecated_hex/README.md
Normal file
5
boards/dongle/deprecated_hex/README.md
Normal file
|
@ -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.
|
|
@ -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)
|
||||
}
|
BIN
boards/dongle/loopback-nousb11
Executable file
BIN
boards/dongle/loopback-nousb11
Executable file
Binary file not shown.
BIN
boards/dongle/loopback-nousb16
Executable file
BIN
boards/dongle/loopback-nousb16
Executable file
Binary file not shown.
BIN
boards/dongle/loopback-nousb21
Executable file
BIN
boards/dongle/loopback-nousb21
Executable file
Binary file not shown.
BIN
boards/dongle/loopback-nousb26
Executable file
BIN
boards/dongle/loopback-nousb26
Executable file
Binary file not shown.
|
@ -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::<consts::U128>::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::<consts::U128>::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)
|
||||
}
|
|
@ -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] = &[
|
||||
// <redacted>
|
||||
];
|
||||
|
||||
static TO: &[u8] = &[
|
||||
// <redacted>
|
||||
];
|
||||
|
||||
// store the secret rather than the plaintext -- otherwise `strings $elf` will reveal the answer
|
||||
static SECRET: &[u8] = b"<redacted>";
|
||||
|
||||
#[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)
|
||||
}
|
BIN
boards/dongle/puzzle-nousb11
Executable file
BIN
boards/dongle/puzzle-nousb11
Executable file
Binary file not shown.
BIN
boards/dongle/puzzle-nousb16
Executable file
BIN
boards/dongle/puzzle-nousb16
Executable file
Binary file not shown.
BIN
boards/dongle/puzzle-nousb21
Executable file
BIN
boards/dongle/puzzle-nousb21
Executable file
Binary file not shown.
BIN
boards/dongle/puzzle-nousb26
Executable file
BIN
boards/dongle/puzzle-nousb26
Executable file
Binary file not shown.
|
@ -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] = &[
|
||||
// <redacted>
|
||||
];
|
||||
|
||||
static TO: &[u8] = &[
|
||||
// <redacted>
|
||||
];
|
||||
|
||||
// store the secret rather than the plaintext -- otherwise `strings $elf` will reveal the answer
|
||||
static SECRET: &[u8] = b"<redacted>";
|
||||
|
||||
#[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::<consts::U128>::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::<consts::U128>::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)
|
||||
}
|
Loading…
Reference in a new issue