diff --git a/examples/usbnoise.rs b/examples/usbnoise.rs index 8e6eeaece71a9bb81979ba771a4bd76ed2b17d90..8fcb66d601e5559d18a82be1e7ddfb1ad26a14a4 100644 --- a/examples/usbnoise.rs +++ b/examples/usbnoise.rs @@ -136,58 +136,33 @@ async fn run<'d, T: Instance + 'd>(pin: &mut impl Pin, class: &mut CdcAcmClass<' // max packet is 64 bytes. we hex encode and add newline, 31*2+1 const CHUNK: usize = 31; - let mut buf = [false; CHUNK * 8 * 10]; - let mut a = None; - let mut pos = 0u32; - let deci = 40u32; + let low_cycles = caprand::cap::best_low_time(pin, 10..=90u32).unwrap(); + trace!("low_cycles = {}", low_cycles); + let low_cycles = 54; + trace!("low_cycles = {}", low_cycles); + let noise = caprand::cap::Noise::new(pin, low_cycles, 5)? + .extract(); + let mut noise = caprand::cap::bits_to_bytes(noise); + + loop { + let mut buf = [0u8; CHUNK]; let mut b = buf.iter_mut(); - let low_delay = 30; - // XXX should discard first iter or something. - caprand::cap::noise(pin, low_delay, - |v| { - pos = pos.wrapping_add(1); - if pos % deci == 0 { - let v = v as u8; - if a.is_none() { - a = Some(v); - true - } else { - let aa = a.take().unwrap(); - if aa != v { - if let Some(i) = b.next() { - *i = aa > v; - true - } else { - false - } - } else { - true - } - } - - } else { - // discard - true - } - }).unwrap(); - - for chunk in buf.chunks(CHUNK*8) { - // write!(&mut buf, "{:?}", chunk); - let mut hex = ['B' as u8; CHUNK*2+1]; - let mut c = chunk.iter(); - let mut m = hex.iter_mut(); - for _ in 0..CHUNK { - let mut x = 0u8; - for b in 0..8 { - x |= (*c.next().unwrap() as u8) << b; - } - *m.next().unwrap() = nibble_hex(x >> 4); - *m.next().unwrap() = nibble_hex(x & 0xf); + loop { + match b.next() { + Some(b) => *b = noise.next().unwrap()?, + None => break } - *m.next().unwrap() = b'\n'; - class.write_packet(&hex).await.unwrap(); } + + let mut hex = ['B' as u8; CHUNK*2+1]; + let mut m = hex.iter_mut(); + for c in buf { + *m.next().unwrap() = nibble_hex(c >> 4); + *m.next().unwrap() = nibble_hex(c & 0xf); + } + *m.next().unwrap() = b'\n'; + class.write_packet(&hex).await.unwrap(); } } diff --git a/src/cap.rs b/src/cap.rs index fe395ac383414a970354962881d89adc5d085d12..5f13b439da87caa05e62fd3318ba06a1303f095c 100644 --- a/src/cap.rs +++ b/src/cap.rs @@ -5,12 +5,13 @@ use log::{debug, info, warn, error, trace}; use defmt::{error, debug, info, panic, trace}; use core::arch::asm; +use core::mem::replace; use embassy_rp::gpio::Pin; use embassy_rp::pac; /// Extra iterations prior to taking output. -const WARMUP: usize = 16; +const WARMUP: u8 = 16; /// Drives a pin low for an exact number of cycles. /// Call with interrupts disabled if it's important. @@ -234,6 +235,104 @@ pub fn lsb(v: u32) -> usize { return 32 } +pub struct Noise<'a, P: Pin> { + pin: &'a mut P, + low_cycles: u32, + skip: u8, + _setup: PinSetup, +} + +impl<'a, P: Pin> Noise<'a, P> { + pub fn new(pin: &'a mut P, low_cycles: u32, skip: u8) -> Result<Self, ()> { + let setup = PinSetup::new(pin.pin()); + let mut s = Self { + pin, + low_cycles, + skip, + _setup: setup, + }; + + for _ in 0..WARMUP { + // OK unwrap: iterator never ends + s.next().unwrap()?; + } + Ok(s) + } + + pub fn extract(self) -> impl Iterator<Item = Result<bool, ()>> + 'a { + // reduce rate to decorrelate + let skip = self.skip as usize; + let i = self.step_by(skip); + + // von Neumann extractor + Pairs { iter: i } + .filter_map(|(a,b)| { + if let (Ok(a), Ok(b)) = (a,b) { + if a == b { + None + } else { + // trace!("{} {}", a, b); + Some(Ok(a > b)) + } + } else { + Some(Err(())) + } + }) + } +} + +impl<P: Pin> Iterator for Noise<'_, P> { + type Item = Result<u8, ()>; + + fn next(&mut self) -> Option<Self::Item> { + let r = critical_section::with(|_cs| { + let r = time_rise(self.pin, self.low_cycles)?; + Ok(r as u8) + }); + Some(r) + } +} + +pub fn bits_to_bytes(i: impl Iterator<Item = Result<bool, ()>>) -> + impl Iterator<Item = Result<u8, ()>> { + let mut pos = 0; + let mut acc = 0; + i.filter_map(move |r| { + if let Ok(r) = r { + // trace!("{}", r as u8); + acc |= (r as u8) << pos; + pos += 1; + if pos == 8 { + pos = 0; + Some(Ok(replace(&mut acc, 0))) + } else { + None + } + } else { + Some(Err(())) + } + }) +} + + +pub struct Pairs<I> { + iter: I, +} + +impl<I> Iterator for Pairs<I> + where I: Iterator<Item = Result<u8, ()>> +{ + type Item = (I::Item, I::Item); + + fn next(&mut self) -> Option<Self::Item> { + let a = self.iter.next()?; + let b = self.iter.next()?; + // trace!("{} {}", a, b); + + Some((a,b)) + } +} + // `f()` is called on each output `u32`. pub fn noise<'d, F>( pin: &mut impl Pin,