mirror of
https://github.com/ferrous-systems/embedded-trainings-2020.git
synced 2025-01-22 22:08:08 +00:00
remove outdated code; add puzzle source code
This commit is contained in:
parent
ae9d58aa43
commit
e093f48807
6 changed files with 117 additions and 421 deletions
|
@ -1,54 +0,0 @@
|
||||||
[package]
|
|
||||||
authors = ["Jorge Aparicio <jorge.aparicio@ferrous-systems.com>"]
|
|
||||||
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"
|
|
|
@ -16,11 +16,11 @@ use panic_abort as _;
|
||||||
fn main() -> ! {
|
fn main() -> ! {
|
||||||
let mut stx = usbd::serial();
|
let mut stx = usbd::serial();
|
||||||
let (mut rtx, mut rrx) = radio::claim(Channel::_20);
|
let (mut rtx, mut rrx) = radio::claim(Channel::_20);
|
||||||
let mut output = String::<consts::U64>::new();
|
let mut output = String::::new();
|
||||||
|
|
||||||
output.push_str("deviceid=").ok();
|
output.push_str("deviceid=").ok();
|
||||||
write!(output, "{:08x}{:08x}", hal::deviceid1(), hal::deviceid0()).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 task = async {
|
||||||
let mut packet = Packet::new().await;
|
let mut packet = Packet::new().await;
|
||||||
|
@ -28,7 +28,8 @@ fn main() -> ! {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let crcres = rrx.read(&mut packet).await;
|
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())
|
Some(packet.lqi())
|
||||||
} else {
|
} else {
|
||||||
// packet is too small; LQI is not valid
|
// packet is too small; LQI is not valid
|
||||||
|
@ -37,12 +38,11 @@ fn main() -> ! {
|
||||||
|
|
||||||
let mut busy = false;
|
let mut busy = false;
|
||||||
if crcres.is_ok() {
|
if crcres.is_ok() {
|
||||||
// packet.reverse();
|
packet.reverse();
|
||||||
busy = rtx.write(&packet).await.is_err();
|
busy = rtx.write(&packet).await.is_err();
|
||||||
}
|
}
|
||||||
|
|
||||||
output.clear();
|
output.clear();
|
||||||
let len = packet.len();
|
|
||||||
write!(
|
write!(
|
||||||
&mut output,
|
&mut output,
|
||||||
"received {} byte{}",
|
"received {} byte{}",
|
||||||
|
|
112
boards/dongle/puzzle.rs
Normal file
112
boards/dongle/puzzle.rs
Normal file
|
@ -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] = &[
|
||||||
|
// <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 mut stx = usbd::serial();
|
||||||
|
let (mut 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 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)
|
||||||
|
}
|
|
@ -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<Output<PushPull>>,
|
|
||||||
configured: AtomicBool,
|
|
||||||
green: P0_06<Output<PushPull>>,
|
|
||||||
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<Clocks<ExternalOscillator, Internal, LfOscStopped>> = None;
|
|
||||||
static mut USB_BUS: Option<UsbBusAllocator<Usbd<'static>>> = 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::<heapless::consts::U64>::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();
|
|
||||||
}
|
|
||||||
};
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue