diff --git a/boards/dongle/Cargo.toml b/boards/dongle/Cargo.toml deleted file mode 100644 index fc12195..0000000 --- a/boards/dongle/Cargo.toml +++ /dev/null @@ -1,54 +0,0 @@ -[package] -authors = ["Jorge Aparicio "] -edition = "2018" -name = "dongle" -version = "0.1.0" - -[dependencies] -consts = { path = "../../common/consts" } -cortex-m-rt = "0.6.12" -cortex-m-rtfm = "0.5.1" -embedded-hal = "0.2.3" -hal = { package = "nrf52840-hal", git = "https://github.com/japaric/nrf-hal", branch = "143+144" } -heapless = "0.5.5" -panic-halt = "0.2.0" -usb-device = "0.2.5" -usbd-serial = "0.1.0" - -# optimize code in both profiles -[profile.dev] -codegen-units = 1 -debug = 1 -debug-assertions = true # ! -incremental = false -lto = "fat" -opt-level = 'z' # ! -overflow-checks = false - -[profile.release] -codegen-units = 1 -debug = 1 -debug-assertions = false -incremental = false -lto = "fat" -opt-level = 3 -overflow-checks = false - -# faster builds from scratch -[profile.dev.build-override] -codegen-units = 8 -debug = false -debug-assertions = false -opt-level = 0 -overflow-checks = false - -[profile.release.build-override] -codegen-units = 8 -debug = false -debug-assertions = false -opt-level = 0 -overflow-checks = false - -[patch.crates-io.usb-device] -git = "https://github.com/jonas-schievink/usb-device.git" -branch = "inhibit-setaddr-resp" diff --git a/boards/dongle/loopback.rs b/boards/dongle/loopback.rs index a0b1723..cc82c9c 100644 --- a/boards/dongle/loopback.rs +++ b/boards/dongle/loopback.rs @@ -16,11 +16,11 @@ use panic_abort as _; fn main() -> ! { let mut stx = usbd::serial(); let (mut rtx, mut rrx) = radio::claim(Channel::_20); - let mut output = String::::new(); + let mut output = String::::new(); output.push_str("deviceid=").ok(); write!(output, "{:08x}{:08x}", hal::deviceid1(), hal::deviceid0()).ok(); - write!(output, " channel={} TxPower=+8dBm\n", rtx.channel()).ok(); + write!(output, " channel={} TxPower=+8dBm app=loopback.hex\n", rtx.channel()).ok(); let task = async { let mut packet = Packet::new().await; @@ -28,7 +28,8 @@ fn main() -> ! { loop { let crcres = rrx.read(&mut packet).await; - let lqi = if packet.len() >= 3 { + let len = packet.len(); + let lqi = if len >= 3 { Some(packet.lqi()) } else { // packet is too small; LQI is not valid @@ -37,12 +38,11 @@ fn main() -> ! { let mut busy = false; if crcres.is_ok() { - // packet.reverse(); + packet.reverse(); busy = rtx.write(&packet).await.is_err(); } output.clear(); - let len = packet.len(); write!( &mut output, "received {} byte{}", diff --git a/boards/dongle/puzzle.rs b/boards/dongle/puzzle.rs new file mode 100644 index 0000000..ac79f35 --- /dev/null +++ b/boards/dongle/puzzle.rs @@ -0,0 +1,112 @@ +// f6c27c0a5af464795d1a64c45fa1b3039f44a62a +#![deny(unused_must_use)] +#![no_main] +#![no_std] + +use core::fmt::Write as _; + +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 mut stx = usbd::serial(); + let (mut 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 task = async { + let mut packet = Packet::new().await; + stx.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.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.write(output.as_bytes()); + } + + stx.write(output.as_bytes()); + } + }; + + executor::run!(task) +} diff --git a/boards/dongle/src/bin/dual.rs b/boards/dongle/src/bin/dual.rs deleted file mode 100644 index 51f3889..0000000 --- a/boards/dongle/src/bin/dual.rs +++ /dev/null @@ -1,203 +0,0 @@ -//! `radio` & `usb` apps merged into a single application - -#![no_std] -#![no_main] - -use core::fmt::Write as _; -use core::sync::atomic::{AtomicBool, Ordering}; - -use embedded_hal::digital::v2::{OutputPin as _, StatefulOutputPin as _}; -use hal::{ - clocks::{Clocks, ExternalOscillator, Internal, LfOscStopped}, - gpio::{ - p0::{self, P0_06, P0_12}, - Level, Output, PushPull, - }, - ieee802154::{Packet, Radio}, - target::USBD, - usbd::Usbd, -}; -use heapless::String; -use panic_halt as _; // panic handler -use usb_device::{bus::UsbBusAllocator, prelude::*}; -use usbd_serial::{SerialPort, USB_CLASS_CDC}; - -// TODO make channel configurable via a single `const`ant - -#[rtfm::app(device = hal::target, peripherals = true)] -const APP: () = { - struct Resources { - blue: P0_12>, - configured: AtomicBool, - green: P0_06>, - radio: Radio<'static>, - serial_port: SerialPort<'static, Usbd<'static>>, - usb_dev: UsbDevice<'static, Usbd<'static>>, - } - - #[init] - fn init(cx: init::Context) -> init::LateResources { - static mut EP_BUF: [u8; 1024] = [0; 1024]; - static mut CLOCKS: Option> = None; - static mut USB_BUS: Option>> = None; - - let periph = cx.device; - - let port = p0::Parts::new(periph.P0); - // P0.6: green LED indicates USB is working - // P0.12: blue LED is toggled on each new packet - let green = port.p0_06.into_push_pull_output(Level::High); - let blue = port.p0_12.into_push_pull_output(Level::High); - - let clocks = Clocks::new(periph.CLOCK); - // extend lifetime to `'static` - let clocks = CLOCKS.get_or_insert(clocks.enable_ext_hfosc()); - - let mut radio = Radio::init(periph.RADIO, clocks); - // set TX power to its maximum value - radio.set_txpower(8); - - // these loops should always terminate - // detected USB power? (device is USB powered) - while !periph - .POWER - .usbregstatus - .read() - .vbusdetect() - .is_vbus_present() - {} - - // wait until USB 3.3V supply (internal regulator) is stable - while !periph - .POWER - .events_usbpwrrdy - .read() - .events_usbpwrrdy() - .bit_is_clear() - {} - - // enable all interrupts - periph.USBD.intenset.write(|w| { - w.endepin0().set_bit(); - w.endepin1().set_bit(); - w.endepin2().set_bit(); - w.endepout0().set_bit(); - w.endepout1().set_bit(); - w.endepout2().set_bit(); - w.ep0datadone().set_bit(); - w.ep0setup().set_bit(); - w.epdata().set_bit(); - w.usbevent().set_bit(); - w.usbreset().set_bit(); - w.sof().set_bit(); - w - }); - - let usb_bus = USB_BUS.get_or_insert(Usbd::new_alloc(periph.USBD, EP_BUF, clocks)); - let serial_port = SerialPort::new(usb_bus); - - let usb_dev = UsbDeviceBuilder::new(usb_bus, UsbVidPid(consts::VID, consts::PID)) - .device_class(USB_CLASS_CDC) - .max_packet_size_0(64) // (makes control transfers 8x faster) - .build(); - - init::LateResources { - blue, - green, - configured: AtomicBool::new(false), - radio, - usb_dev, - serial_port, - } - } - - #[idle(resources = [blue, &configured, radio, serial_port])] - fn idle(cx: idle::Context) -> ! { - let blue = cx.resources.blue; - let configured = cx.resources.configured; - let mut serial_port = cx.resources.serial_port; - let radio = cx.resources.radio; - - // TODO run Radio in parallel to the USBD task - let mut packet = Packet::new(); - let mut buf = String::::new(); - loop { - // let res = radio.recv(&mut packet); - // let lqi = packet.lqi(); - // let len = packet.len(); - // if res.is_ok() { - // if blue.is_set_low() == Ok(true) { - // blue.set_high().ok(); - // } else { - // blue.set_low().ok(); - // } - - // // loopback the packet - // radio.send(&packet); - // } - - let is_configured = configured.load(Ordering::Relaxed); - - if is_configured { - blue.set_low().ok(); - // buf.clear(); - - // // TODO switch to a single `uwriteln!` - // if res.is_ok() { - // buf.push_str("CRC OK").ok() - // } else { - // buf.push_str("BAD CRC").ok() - // }; - // buf.push_str(" - LQI: ").ok(); - // write!(buf, "{}", lqi).ok(); - // buf.push_str(" - payload: ").ok(); - // write!(buf, "{}", len).ok(); - // buf.push_str(" bytes\n").ok(); - - // serial_port.lock(|port| port.write(buf.as_bytes()).ok()); - } - } - } - - #[task(binds = USBD, resources = [&configured, green, usb_dev, serial_port])] - fn usbd(cx: usbd::Context) { - let configured = cx.resources.configured; - let green = cx.resources.green; - let serial_port = cx.resources.serial_port; - let usb_dev = cx.resources.usb_dev; - - usb_dev.poll(&mut [serial_port]); - if !configured.load(Ordering::Relaxed) { - if usb_dev.state() == UsbDeviceState::Configured { - // off - green.set_high().ok(); - configured.store(true, Ordering::Relaxed); - let _ = serial_port.write(b"bChannel: 20\nTX power: +8 dBm\n"); - } - } else { - // blink until configured - if green.is_set_low() == Ok(true) { - green.set_high().ok(); - } else { - green.set_low().ok(); - } - } - - // FIXME `hal::Usbd` is not clearing all EVENTS? - let usbd: USBD = unsafe { core::mem::transmute(()) }; - if usbd.events_epdata.read().bits() != 0 && usbd.epdatastatus.read().bits() == 0 { - usbd.events_epdata.reset(); - } - if usbd.events_sof.read().bits() != 0 { - usbd.events_sof.reset(); - } - // usbd.events_endepout[0].reset(); - // usbd.events_endepout[1].reset(); - // usbd.events_endepout[2].reset(); - // usbd.events_ep0setup.reset(); - // usbd.events_ep0datadone.reset(); - // usbd.events_epdata.reset(); - // usbd.events_usbevent.reset(); - // usbd.events_usbreset.reset(); - } -}; diff --git a/boards/dongle/src/bin/radio.rs b/boards/dongle/src/bin/radio.rs deleted file mode 100644 index 349d08d..0000000 --- a/boards/dongle/src/bin/radio.rs +++ /dev/null @@ -1,63 +0,0 @@ -//! Test program, mainly for debugging purposes - -#![no_main] -#![no_std] - -use cortex_m_rt::entry; -use embedded_hal::digital::v2::{OutputPin as _, StatefulOutputPin as _}; -use hal::{ - clocks::Clocks, - gpio::{p0, Level}, - ieee802154::{Packet, Radio}, - target as pac, -}; -use panic_halt as _; - -#[entry] -fn main() -> ! { - let periph = pac::Peripherals::take().unwrap(); - - let clocks = Clocks::new(periph.CLOCK); - let clocks = clocks.enable_ext_hfosc(); - - let port = p0::Parts::new(periph.P0); - - // NOTE LEDs turn on when the output level is low (0V) - let mut green = port.p0_06.into_push_pull_output(Level::High); // LD1 - - let mut blue = port.p0_12.into_push_pull_output(Level::High); // LD2 (RGB LED) - let mut red = port.p0_08.into_push_pull_output(Level::High); // LD2 (RGB LED) - - let mut radio = Radio::init(periph.RADIO, &clocks); - - // turn on green LED to indicate the radio has been initialized - green.set_low().ok(); - - // set TX power to its maximum value - radio.set_txpower(8); - - let mut packet = Packet::new(); - loop { - let res = radio.recv(&mut packet); - - if res.is_ok() { - // CRC check passed - // clear visual error state (turn off the red LED) - red.set_high().ok(); - - // toggle blue LED on each successfully received packet - if blue.is_set_low() == Ok(true) { - blue.set_high().ok(); - } else { - blue.set_low().ok(); - } - - // return packet with the contents unchanged - radio.send(&packet); - } else { - // CRC check failed - // indicate error using the red LED - red.set_low().ok(); - } - } -} diff --git a/boards/dongle/src/bin/usb.rs b/boards/dongle/src/bin/usb.rs deleted file mode 100644 index e489f0d..0000000 --- a/boards/dongle/src/bin/usb.rs +++ /dev/null @@ -1,96 +0,0 @@ -//! Test program used to debug the `serial-term` tool - -#![no_main] -#![no_std] - -use cortex_m_rt::entry; -use embedded_hal::digital::v2::OutputPin as _; -use hal::{ - clocks::Clocks, - gpio::{p0, Level}, - target as pac, - usbd::Usbd, -}; -use panic_halt as _; -use usb_device::device::{UsbDeviceBuilder, UsbDeviceState, UsbVidPid}; -use usbd_serial::{SerialPort, USB_CLASS_CDC}; - -#[entry] -fn main() -> ! { - static mut EP_BUF: [u8; 1024] = [0; 1024]; - - let periph = pac::Peripherals::take().unwrap(); - - let clocks = Clocks::new(periph.CLOCK); - let clocks = clocks.enable_ext_hfosc(); - - let port = p0::Parts::new(periph.P0); - - // NOTE LEDs turn on when the output level is low (0V) - let mut green = port.p0_06.into_push_pull_output(Level::High); // LD1 - let mut blue = port.p0_12.into_push_pull_output(Level::High); // LD2 (RGB LED) - let mut red = port.p0_08.into_push_pull_output(Level::High); // LD2 (RGB LED) - - // these loops should always terminate - // detected USB power? (device is USB powered) - while !periph - .POWER - .usbregstatus - .read() - .vbusdetect() - .is_vbus_present() - { - continue; - } - - // wait until USB 3.3V supply (internal regulator) is stable - while !periph - .POWER - .events_usbpwrrdy - .read() - .events_usbpwrrdy() - .bit_is_clear() - { - continue; - } - - // turn on green LED to show the program is working - green.set_low().ok(); - - let usb_bus = Usbd::new_alloc(periph.USBD, EP_BUF, &clocks); - let mut serial_port = SerialPort::new(&usb_bus); - - let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(consts::VID, consts::PID)) - .device_class(USB_CLASS_CDC) - .max_packet_size_0(64) // (makes control transfers 8x faster) - .build(); - - let mut buf = [0; 64]; - let mut once = true; - loop { - if !usb_dev.poll(&mut [&mut serial_port]) { - continue; - } - - if usb_dev.state() == UsbDeviceState::Configured { - // turn on the blue LED to show the device has been configured - blue.set_low().ok(); - - if once { - once = false; - - serial_port.write(b"Hello, world!\n").ok(); - serial_port.flush().ok(); - } - - if serial_port.read(&mut buf).is_ok() { - // received data from the PC. I'm interpreting this as an error but it may actually - // be part of the CDC/ACM protocol? -- we never send data to the device - red.set_low().ok(); - } - } else { - // otherwise turn it off - blue.set_high().ok(); - } - } -}