diff --git a/CHANGELOG.md b/CHANGELOG.md
index 58c9738c2fd184088a0732e90ad768dbd269679e..fc5b8f8effec693a24d6ff0acb3d17e973b10cd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,11 @@
 # Changelog
 
+## 2021-03-07
+
+- examples/rtic_bare7.rs, using embedded HAL.
+- examples/rtic_bare8.rs, serial communication, bad design.
+- examples/rtic_bare9.rs, serial communication, good design.
+  
 ## 2021-03-05
 
 - examples/rtic_bare6.rs, setup and validate the clock tree.
diff --git a/README.md b/README.md
index 1e6f487ab0fd7ed997338bd4c08e5e45b7ec2e34..88e331d48db4ffeda831a5b47a849869a2062011 100644
--- a/README.md
+++ b/README.md
@@ -80,11 +80,14 @@ Using `vscode` just press F5 to launch and debug the program in the currently ac
 Bare metal programming:
 
 - `examples/rtic_bare1.rs`, in this exercise you learn about debugging, inspecting the generated assembly code, inline assembly, and about checked vs. unchecked (wrapping) arithmetics. Provides essential skills and understanding of low level (bare metal) programming.
-- `examples/rtic_/bare2.rs`, in this exercise you learn how to measure execution time using raw timer access.
+- `examples/rtic_bare2.rs`, in this exercise you learn how to measure execution time using raw timer access.
 - `examples/rtic_bare3.rs`, here you learn more about RTIC timing semantics and timing abstractions.
 - `examples/rtic_bare4.rs`, in this exercise you will encounter a simple bare metal peripheral access API. The API is very unsafe and easy to misuse.
 - `examples/rtic_bare5.rs`, here you will write your own C-like peripheral access API. This API is much safer as you get control over bit-fields in a well defined way, thus less error prone.
 - `examples/rtic_bare6.rs`, in this exercise you learn about clock tree generation and validation.
+- `examples/rtic_bare7.rs`, here you learn more on using embedded HAL abstractions and the use of generics.
+- `examples/rtic_bare8.rs`, in this exercise you will setup serial communication to receive and send data. You will also see that polling may lead to data loss in a bad design.
+- `examples/rtic_bare9.rs`, here you revisit serial communication and implement a good design in RTIC leveraging preemptive scheduling to ensure lossless communication.
 
 ---
 
diff --git a/examples/pmw3389.rs b/examples/pmw3389.rs
index 572479dca79321f097bdb6f34f4433a93295adfb..746cf156cfe2d7dd194ed3d5c80ac8235ef33d81 100644
--- a/examples/pmw3389.rs
+++ b/examples/pmw3389.rs
@@ -3,12 +3,23 @@
 #![no_main]
 #![no_std]
 
-// use cortex_m::{iprintln, peripheral::DWT};
 use embedded_hal::spi::MODE_3;
-// use cortex_m_semihosting::hprintln;
-use panic_halt as _;
-// use rtic::cyccnt::{Instant, U32Ext as _};
-use stm32f4xx_hal::{dwt::Dwt, gpio::Speed, prelude::*, rcc::Clocks, spi::Spi, stm32};
+use panic_rtt_target as _;
+
+use rtic::cyccnt::{Instant, U32Ext as _};
+use stm32f4xx_hal::{
+    dwt::Dwt,
+    gpio::Speed,
+    gpio::{
+        gpiob::{PB10, PB4},
+        gpioc::{PC2, PC3},
+        Alternate, Output, PushPull,
+    },
+    prelude::*,
+    rcc::Clocks,
+    spi::Spi,
+    stm32,
+};
 
 use app::{
     pmw3389::{self, Register},
@@ -16,35 +27,41 @@ use app::{
 };
 use rtt_target::{rprintln, rtt_init_print};
 
+type PMW3389T = pmw3389::Pmw3389<
+    Spi<
+        stm32f4xx_hal::stm32::SPI2,
+        (
+            PB10<Alternate<stm32f4xx_hal::gpio::AF5>>,
+            PC2<Alternate<stm32f4xx_hal::gpio::AF5>>,
+            PC3<Alternate<stm32f4xx_hal::gpio::AF5>>,
+        ),
+    >,
+    PB4<Output<PushPull>>,
+>;
+
 #[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
 const APP: () = {
     struct Resources {
         // late resources
-        GPIOA: stm32::GPIOA,
+        pmw3389: PMW3389T,
     }
-    #[init(schedule = [toggle])]
+    #[init(schedule = [poll])]
     fn init(cx: init::Context) -> init::LateResources {
         rtt_init_print!();
+        rprintln!("init");
 
         let mut core = cx.core;
         let device = cx.device;
 
-        // Configure led:
-        // power on GPIOA, RM0368 6.3.11
-        device.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit());
-        // configure PA5 as output, RM0368 8.4.1
-        device.GPIOA.moder.modify(|_, w| w.moder5().bits(1));
+        // Initialize (enable) the monotonic timer (CYCCNT)
+        core.DCB.enable_trace();
+        core.DWT.enable_cycle_counter();
 
         // setup clocks
         let rcc = device.RCC.constrain();
-
         let clocks = rcc.cfgr.freeze();
-
-        rprintln!("------------");
-        rprintln!("pmw3389");
-
-        // Initialize (enable) the monotonic timer (CYCCNT)
-        core.DCB.enable_trace();
+        rprintln!("clocks:");
+        rprintln!("hclk {}", clocks.hclk().0);
 
         // Configure SPI
         // spi2
@@ -64,812 +81,74 @@ const APP: () = {
         let miso = gpioc.pc2.into_alternate_af5();
         let mosi = gpioc.pc3.into_alternate_af5();
         let cs = gpiob.pb4.into_push_pull_output().set_speed(Speed::High);
-        // let cs = gpiob.pb4.into_push_pull_output();
 
         let spi = Spi::spi2(
             device.SPI2,
             (sck, miso, mosi),
             MODE_3,
-            stm32f4xx_hal::time::KiloHertz(1000).into(),
+            stm32f4xx_hal::time::KiloHertz(2000).into(),
             clocks,
         );
 
         let mut delay = DwtDelay::new(&mut core.DWT, clocks);
-        rprintln!("clocks:");
-        rprintln!("hclk {}", clocks.hclk().0);
-
-        // test the delay
-        let t1 = stm32::DWT::get_cycle_count();
-        delay.delay_us(1000);
-        let t2 = stm32::DWT::get_cycle_count();
-
-        rprintln!("1000us {}", t2.wrapping_sub(t1));
-
-        let t1 = stm32::DWT::get_cycle_count();
-        delay.delay_ms(1000);
-        let t2 = stm32::DWT::get_cycle_count();
-
-        rprintln!("1000ms {}", t2.wrapping_sub(t1));
-
         let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap();
 
-        let mut delay = DwtDelay::new(&mut core.DWT, clocks);
-
-        // loop {
-        //     pmw3389.write_register(Register::Motion, 0x01).ok();
-
-        //     let motion = pmw3389.read_register(Register::Motion).unwrap();
-        //     let xl = pmw3389.read_register(Register::DeltaXL).unwrap();
-        //     let xh = pmw3389.read_register(Register::DeltaXH).unwrap();
-        //     let yl = pmw3389.read_register(Register::DeltaYL).unwrap();
-        //     let yh = pmw3389.read_register(Register::DeltaYH).unwrap();
-
-        //     let x = (xl as u16 + (xh as u16) << 8) as i16;
-        //     let y = (yl as u16 + (yh as u16) << 8) as i16;
-
-        //     let surface = motion & 0x08;
-        //     let motion_detect = motion & 0x80;
-
-        //     rprintln!(
-        //         "motion {}, surface {}, (x, y) {:?}",
-        //         motion_detect,
-        //         surface,
-        //         (x, y),
-        //     );
-        //     delay.delay_ms(200);
-        // }
-
         // set in burst mode
         pmw3389.write_register(Register::MotionBurst, 0x00);
 
-        loop {
-            pmw3389.read_status().unwrap();
-            delay.delay_ms(200);
-        }
-
-        let id = pmw3389.product_id().unwrap();
-        rprintln!("id {}", id);
-
-        let id = pmw3389
-            .read_register(pmw3389::Register::RevisionId)
-            .unwrap();
-        rprintln!("rev {}", id);
-
-        let id = pmw3389
-            .read_register(pmw3389::Register::ShutterLower)
-            .unwrap();
-        rprintln!("lower {}", id);
-
-        let id = pmw3389
-            .read_register(pmw3389::Register::ShutterUpper)
-            .unwrap();
-        rprintln!("upper {}", id);
-
-        let id = pmw3389.read_register(pmw3389::Register::SROMId).unwrap();
-        rprintln!("sromid {}", id);
-
-        let id = pmw3389
-            .read_register(pmw3389::Register::InverseProductID)
-            .unwrap();
-        rprintln!("-id {}", id);
-
-        let id = pmw3389
-            .read_register(pmw3389::Register::RippleControl)
-            .unwrap();
-        rprintln!("ripple_control {:x}", id);
-
         // semantically, the monotonic timer is frozen at time "zero" during `init`
         // NOTE do *not* call `Instant::now` in this context; it will return a nonsense value
-        // let now = cx.start; // the start time of the system
+        let now = cx.start; // the start time of the system
 
-        // Schedule `toggle` to run 8e6 cycles (clock cycles) in the future
-        // cx.schedule.toggle(now + 8_000_000.cycles()).unwrap();
+        cx.schedule.poll(now + 16_000.cycles()).unwrap();
 
         // pass on late resources
-        init::LateResources {
-            GPIOA: device.GPIOA,
-        }
+        init::LateResources { pmw3389 }
     }
 
-    #[task(resources = [GPIOA], schedule = [toggle])]
-    fn toggle(cx: toggle::Context) {
-        static mut TOGGLE: bool = false;
-        rprintln!("toggle  @ {:?}", Instant::now());
+    #[task(priority = 2, resources = [pmw3389], schedule = [poll], spawn = [trace])]
+    fn poll(cx: poll::Context) {
+        static mut COUNTER: u32 = 0;
+        static mut POS_X: i64 = 0;
 
-        if *TOGGLE {
-            cx.resources.GPIOA.bsrr.write(|w| w.bs5().set_bit());
-        } else {
-            cx.resources.GPIOA.bsrr.write(|w| w.br5().set_bit());
+        *COUNTER += 1;
+        if *COUNTER == 1000 / RATIO {
+            cx.spawn.trace(*POS_X).unwrap();
+            *COUNTER = 0;
         }
 
-        *TOGGLE = !*TOGGLE;
+        let (x, _y) = cx.resources.pmw3389.read_status().unwrap();
+        *POS_X += x as i64;
+
+        // task should run each second N ms (16_000 cycles at 16MHz)
         cx.schedule
-            .toggle(cx.scheduled + 8_000_000.cycles())
+            .poll(cx.scheduled + (RATIO * 16_000).cycles())
             .unwrap();
     }
 
+    #[task(priority = 1)]
+    fn trace(_cx: trace::Context, pos: i64) {
+        static mut OLD_POS: i64 = 0;
+        rprintln!(
+            "pos_x {:010}, diff {:010} @{:?}",
+            pos,
+            pos - *OLD_POS,
+            Instant::now()
+        );
+        *OLD_POS = pos;
+    }
+
+    #[idle]
+    fn idle(_cx: idle::Context) -> ! {
+        loop {
+            continue;
+        }
+    }
+
     extern "C" {
         fn EXTI0();
+        fn EXTI1();
     }
 };
 
-// mod pmw3389 {
-//     use super::DwtDelay;
-
-//     use cortex_m::{iprint, iprintln};
-//     use embedded_hal::blocking::spi::{Transfer, Write};
-//     use embedded_hal::digital::v2::OutputPin;
-//     use stm32f4xx_hal::{prelude::*, stm32};
-//     // use stm32f4xx_hal::{dwt::Dwt, gpio::Speed, prelude::*, rcc::Clocks, spi::Spi, stm32};
-
-//     #[allow(dead_code)]
-//     #[derive(Clone, Copy)]
-//     pub enum Register {
-//         ProductId = 0x00,
-//         RevisionId = 0x01,
-//         Motion = 0x02,
-//         DeltaXL = 0x03,
-//         DeltaXH = 0x04,
-//         DeltaYL = 0x05,
-//         DeltaYH = 0x06,
-//         SQUAL = 0x07,
-//         RawDataSum = 0x08,
-//         MaximumRawdata = 0x09,
-//         MinimumRawdata = 0x0A,
-//         ShutterLower = 0x0B,
-//         ShutterUpper = 0x0C,
-//         RippleControl = 0x0D,
-//         ResolutionL = 0x0E,
-//         ResolutionH = 0x0F,
-//         Config2 = 0x10,
-//         AngleTune = 0x11,
-//         FrameCapture = 0x12,
-//         SROMEnable = 0x13,
-//         RunDownshift = 0x14,
-//         Rest1RateLower = 0x15,
-//         Rest1RateUpper = 0x16,
-//         Rest1Downshift = 0x17,
-//         Rest2RateLower = 0x18,
-//         Rest2RateUpper = 0x19,
-//         Rest2Downshift = 0x1A,
-//         Rest3RateLower = 0x1B,
-//         Rest3RateUpper = 0x1C,
-//         Observation = 0x24,
-//         DataOutLower = 0x25,
-//         DataOutUpper = 0x26,
-//         RawDataDump = 0x29,
-//         SROMId = 0x2A,
-//         MinSQRun = 0x2B,
-//         RawDataThreshold = 0x2C,
-//         Control2 = 0x2D,
-//         Config5L = 0x2E,
-//         Config5H = 0x2F,
-//         PowerUpReset = 0x3A,
-//         Shutdown = 0x3B,
-//         InverseProductID = 0x3F,
-//         LiftCutoffTune3 = 0x41,
-//         AngleSnap = 0x42,
-//         LiftCutoffTune1 = 0x4A,
-//         MotionBurst = 0x50,
-//         LiftCutoffTune1Timeout = 0x58,
-//         LiftCutoffTune1MinLength = 0x5A,
-//         SROMLoadBurst = 0x62,
-//         LiftConfig = 0x63,
-//         RawDataBurst = 0x64,
-//         LiftCutoffTune2 = 0x65,
-//         LiftCutoffTune2Timeout = 0x71,
-//         LiftCutoffTune2MinLength = 0x72,
-//         PWMPeriodCnt = 0x73,
-//         PWMWidthCnt = 0x74,
-//     }
-
-//     impl Register {
-//         fn addr(self) -> u8 {
-//             self as u8
-//         }
-//     }
-
-//     pub struct Pmw3389<SPI, CS> {
-//         spi: SPI,
-//         cs: CS,
-//         delay: DwtDelay,
-//     }
-
-//     impl<SPI, CS, E> Pmw3389<SPI, CS>
-//     where
-//         SPI: Transfer<u8, Error = E> + Write<u8, Error = E>,
-//         CS: OutputPin,
-//     {
-//         fn com_begin(&mut self) {
-//             self.cs.set_low().ok();
-//         }
-
-//         fn com_end(&mut self) {
-//             self.cs.set_high().ok();
-//         }
-
-//         /// Creates a new driver from a SPI peripheral and a NCS pin
-//         pub fn new(spi: SPI, cs: CS, delay: DwtDelay, itm: &mut stm32::ITM) -> Result<Self, E> {
-//             let mut pmw3389 = Pmw3389 { spi, cs, delay };
-
-//             iprintln!(&mut itm.stim[0], "pmw3389 - new");
-
-//             // ensure SPI is reset
-//             pmw3389.com_end();
-//             pmw3389.delay.delay_us(40);
-//             pmw3389.com_begin();
-//             pmw3389.delay.delay_us(40);
-//             pmw3389.com_end();
-
-//             // read product id
-//             let id = pmw3389.product_id()?;
-//             iprintln!(&mut itm.stim[0], "product_id 0x{:x}", id);
-
-//             let srom_id = pmw3389.read_register(Register::SROMId)?;
-//             iprintln!(&mut itm.stim[0], "srom_id {}, 0x{:x}", srom_id, srom_id);
-
-//             iprintln!(&mut itm.stim[0], "reset");
-
-//             // shutdown
-
-//             // adns_write_reg(Shutdown, 0xb6); // Shutdown first
-//             // delay(300);
-
-//             // adns_com_begin(); // drop and raise ncs to reset spi port
-//             // delayMicroseconds(40);
-//             // adns_com_end();
-//             // delayMicroseconds(40);
-
-//             // pmw3389.write_register(Register::Shutdown, 0xb6)?;
-//             // pmw3389.delay.delay_ms(300);
-//             // pmw3389.com_begin();
-//             // pmw3389.delay.delay_us(40);
-//             // pmw3389.com_end();
-//             // pmw3389.delay.delay_us(40);
-
-//             // force reset
-//             pmw3389.write_register(Register::PowerUpReset, 0x5a)?;
-
-//             // wait for reboot
-//             pmw3389.delay.delay_ms(50);
-
-//             // read product id
-//             let id = pmw3389.product_id()?;
-//             iprintln!(&mut itm.stim[0], "product_id 0x{:x}", id);
-
-//             let srom_id = pmw3389.read_register(Register::SROMId)?;
-//             iprintln!(&mut itm.stim[0], "srom_id {}, 0x{:x}", srom_id, srom_id);
-
-//             // read registers 0x02 to 0x06 (and discard the data)
-//             pmw3389.read_register(Register::Motion)?;
-//             pmw3389.read_register(Register::DeltaXL)?;
-//             pmw3389.read_register(Register::DeltaXH)?;
-//             pmw3389.read_register(Register::DeltaYL)?;
-//             pmw3389.read_register(Register::DeltaYH)?;
-
-//             pmw3389.upload_firmware(itm)?;
-
-//             pmw3389.delay.delay_ms(1000);
-
-//             iprintln!(&mut itm.stim[0], "Optical Chip Initialized");
-
-//             // read product id
-//             let id = pmw3389.product_id()?;
-//             iprintln!(&mut itm.stim[0], "product_id 0x{:x}", id);
-
-//             let srom_id = pmw3389.read_register(Register::SROMId)?;
-//             iprintln!(&mut itm.stim[0], "srom_id {}, 0x{:x}", srom_id, srom_id);
-
-//             loop {
-//                 pmw3389.write_register(Register::Motion, 0x01)?;
-
-//                 let motion = pmw3389.read_register(Register::Motion)?;
-//                 let xl = pmw3389.read_register(Register::DeltaXL)?;
-//                 let xh = pmw3389.read_register(Register::DeltaXH)?;
-//                 let yl = pmw3389.read_register(Register::DeltaYL)?;
-//                 let yh = pmw3389.read_register(Register::DeltaYH)?;
-
-//                 let x = (xl as u16 + (xh as u16) << 8) as i16;
-//                 let y = (yl as u16 + (yh as u16) << 8) as i16;
-
-//                 let surface = motion & 0x08;
-//                 let motion_detect = motion & 0x80;
-
-//                 iprintln!(
-//                     &mut itm.stim[0],
-//                     "motion {}, surface {}, (x, y) {:?}",
-//                     motion_detect,
-//                     surface,
-//                     (x, y),
-//                 );
-//                 pmw3389.delay.delay_ms(200);
-//             }
-
-//             // self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
-//             // self.delay.delay_ms(35); // waits for tSRAD
-
-//             // loop {
-//             //     pmw3389.read_status(itm)?;
-//             //     pmw3389.delay.delay_ms(10);
-//             // }
-
-//             // Ok(pmw3389)
-//         }
-
-//         pub fn read_register(&mut self, reg: Register) -> Result<u8, E> {
-//             self.com_begin();
-
-//             let mut buffer = [reg.addr() & 0x7f];
-//             self.spi.transfer(&mut buffer)?;
-
-//             // tSRAD
-//             self.delay.delay_us(100);
-//             self.delay.delay_us(120);
-
-//             let mut buffer = [0];
-//             self.spi.transfer(&mut buffer)?;
-
-//             // tSCLK-NCS for read operation is 120ns
-//             self.delay.delay_us(1);
-
-//             self.com_end();
-
-//             // tSRW/tSRR (=20us) minus tSCLK-NCS
-//             self.delay.delay_us(19);
-//             self.delay.delay_us(120);
-
-//             Ok(buffer[0])
-//         }
-
-//         pub fn write_register(&mut self, reg: Register, byte: u8) -> Result<(), E> {
-//             self.com_begin();
-
-//             let mut buffer = [reg.addr() | 0x80];
-//             self.spi.transfer(&mut buffer)?;
-
-//             // send
-//             let mut buffer = [byte];
-//             self.spi.transfer(&mut buffer)?;
-
-//             // tSCLK-NCS for write operation
-//             self.delay.delay_us(20);
-
-//             self.com_end();
-//             // tSWW/tSWR (=120us) minus tSCLK-NCS.
-//             // Could be shortened, but is looks like a safe lower bound
-
-//             self.delay.delay_us(100);
-
-//             Ok(())
-//         }
-
-//         /// Reads the ProductId register; should return `0x47`
-//         pub fn product_id(&mut self) -> Result<u8, E> {
-//             self.read_register(Register::ProductId)
-//         }
-
-//         /// Read status
-//         pub fn read_status(&mut self, itm: &mut stm32::ITM) -> Result<(), E> {
-//             self.com_begin();
-
-//             self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
-//             self.delay.delay_us(35); // waits for tSRAD
-
-//             // read burst buffer
-//             let mut buf = [0u8; 12];
-//             self.spi.transfer(&mut buf)?;
-
-//             // tSCLK-NCS for read operation is 120ns
-//             self.delay.delay_us(120);
-
-//             self.com_end();
-
-//             iprint!(&mut itm.stim[0], "burst [");
-//             for j in buf.iter() {
-//                 iprint!(&mut itm.stim[0], "0x{:02x}, ", j);
-//             }
-//             iprintln!(&mut itm.stim[0], "]");
-
-//             //     SPI.endTransaction(); // Per:Not sure what it does
-//             //     /*
-//             //     BYTE[00] = Motion    = if the 7th bit is 1, a motion is detected.
-//             //            ==> 7 bit: MOT (1 when motion is detected)
-//             //            ==> 3 bit: 0 when chip is on surface / 1 when off surface
-//             //            ] = Observation
-//             //     BYTE[02] = Delta_X_L = dx (LSB)
-//             //     BYTE[03] = Delta_X_H = dx (MSB)
-//             //     BYTE[04] = Delta_Y_L = dy (LSB)
-//             //     BYTE[05] = Delta_Y_H = dy (MSB)
-//             //     BYTE[06] = SQUAL     = Surface Quality register, max 0x80
-//             //                          - Number of features on the surface = SQUAL * 8
-//             //     BYTE[07] = Raw_Data_Sum   = It reports the upper byte of an 18‐bit counter which sums all 1296 raw data in the current frame;
-//             //                                * Avg value = Raw_Data_Sum * 1024 / 1296
-//             //     BYTE[08] = Maximum_Raw_Data  = Max raw data value in current frame, max=127
-//             //     BYTE[09] = Minimum_Raw_Data  = Min raw data value in current frame, max=127
-//             //     BYTE[10] = Shutter_Upper     = Shutter LSB
-//             //     BYTE[11] = Shutter_Lower     = Shutter MSB, Shutter = shutter is adjusted to keep the average raw data values within normal operating ranges
-//             //     */
-//             //     int motion = (burstBuffer[0] & 0x80) > 0;
-//             let motion = buf[0] & 0x80;
-//             let surface = buf[0] & 0x08;
-//             // 0 if on surface / 1 if off surface
-
-//             let x = buf[2] as u16 + (buf[3] as u16) << 8;
-//             let y = buf[4] as u16 + (buf[5] as u16) << 8;
-
-//             let squal = buf[6];
-
-//             iprintln!(
-//                 &mut itm.stim[0],
-//                 "motion {}, surface {}, (x, y) {:?}, squal {}",
-//                 motion,
-//                 surface,
-//                 (x, y),
-//                 squal
-//             );
-
-//             Ok(())
-//         }
-
-//         // Upload the firmware
-//         pub fn upload_firmware(&mut self, itm: &mut stm32::ITM) -> Result<(), E> {
-//             let stim = &mut itm.stim[0];
-//             // send the firmware to the chip, cf p.18 of the datasheet
-//             // Serial.println("Uploading firmware...");
-//             iprintln!(stim, "Uploading firmware...");
-
-//             //Write 0 to Rest_En bit of Config2 register to disable Rest mode.
-//             // adns_write_reg(Config2, 0x20);
-//             // is this correct?
-//             self.write_register(Register::Config2, 0x00)?;
-
-//             // write 0x1d in SROM_enable reg for initializing
-//             // adns_write_reg(SROM_Enable, 0x1d);
-//             self.write_register(Register::SROMEnable, 0x1d)?;
-
-//             // wait for more than one frame period
-//             // delay(10);
-//             // assume that the frame rate is as low as 100fps...
-//             // even if it should never be that low
-//             self.delay.delay_ms(10);
-
-//             // write 0x18 to SROM_enable to start SROM download
-//             // adns_write_reg(SROM_Enable, 0x18);
-//             self.write_register(Register::SROMEnable, 0x18)?;
-
-//             iprintln!(stim, "Begin transfer...");
-
-//             // write the SROM file (=firmware data)
-//             // adns_com_begin();
-//             self.com_begin();
-
-//             // write burst destination address
-//             // SPI.transfer(SROM_Load_Burst | 0x80); // write burst destination address
-//             // delayMicroseconds(15);
-
-//             self.spi
-//                 .transfer(&mut [Register::SROMLoadBurst.addr() | 0x80])?;
-
-//             self.delay.delay_us(15);
-
-//             // send all bytes of the firmware
-//             // unsigned char c;
-//             // for(int i = 0; i < firmware_length; i++){
-//             //   c = (unsigned char)pgm_read_byte(firmware_data + i);
-//             //   SPI.transfer(c);
-//             //   delayMicroseconds(15);
-//             // }
-
-//             for i in FIRMWARE.iter() {
-//                 let mut buff = [*i];
-//                 // iprintln!(stim, "0x{:x}", buff[0]);
-//                 self.spi.transfer(&mut buff)?;
-//                 self.delay.delay_us(15); // 15
-//             }
-
-//             // // Per: added this, seems adequate
-//             self.delay.delay_us(105);
-
-//             self.com_end();
-
-//             //Read the SROM_ID register to verify the ID before any other register reads or writes.
-//             // adns_read_reg(SROM_ID);
-
-//             let srom_id = self.read_register(Register::SROMId)?;
-//             iprintln!(stim, "srom_id {}, 0x{:x}", srom_id, srom_id);
-
-//             // //Write 0x00 to Config2 register for wired mouse or 0x20 for wireless mouse design.
-//             // // adns_write_reg(Config2, 0x00);
-//             self.write_register(Register::Config2, 0x20)?;
-
-//             // // set initial CPI resolution
-//             // // adns_write_reg(Config1, 0x15);
-
-//             //            self.write_register(Register::ResolutionL, 0x15)?;
-//             self.write_register(Register::ResolutionL, 0x5)?;
-//             // self.write_register(Register::ResolutionH, 0x15)?;
-//             self.write_register(Register::ResolutionH, 0x00)?;
-
-//             // adns_com_end(); // why the CS is already high
-//             self.com_end();
-//             Ok(())
-//         }
-//     }
-
-//     // const unsigned char firmware_data[] PROGMEM
-//     const FIRMWARE: [u8; 4094] = [
-//         0x01, 0xe8, 0xba, 0x26, 0x0b, 0xb2, 0xbe, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0xa8, 0xb3,
-//         0xe4, 0x2b, 0xb5, 0xe8, 0x53, 0x07, 0x6d, 0x3b, 0xd1, 0x20, 0xc2, 0x06, 0x6f, 0x3d, 0xd9,
-//         0x11, 0xa0, 0xc2, 0xe7, 0x2d, 0xb9, 0xd1, 0x20, 0xa3, 0xa5, 0xc8, 0xf3, 0x64, 0x4a, 0xf7,
-//         0x4d, 0x18, 0x93, 0xa4, 0xca, 0xf7, 0x6c, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xfe, 0x7e, 0x7e,
-//         0x5f, 0x1d, 0x99, 0xb0, 0xc3, 0xe5, 0x29, 0xd3, 0x03, 0x65, 0x48, 0x12, 0x87, 0x6d, 0x58,
-//         0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xf2, 0x4f, 0xfd, 0x59, 0x11, 0x81, 0x61, 0x21, 0xc0, 0x02,
-//         0x86, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x55, 0x28, 0xb3, 0xe4, 0x4a, 0x16,
-//         0xab, 0xbf, 0xdd, 0x38, 0xf2, 0x66, 0x4e, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xc8,
-//         0x12, 0xa6, 0xaf, 0xdc, 0x3a, 0xd1, 0x41, 0x60, 0x75, 0x58, 0x24, 0x92, 0xd4, 0x72, 0x6c,
-//         0xe0, 0x2f, 0xfd, 0x23, 0x8d, 0x1c, 0x5b, 0xb2, 0x97, 0x36, 0x3d, 0x0b, 0xa2, 0x49, 0xb1,
-//         0x58, 0xf2, 0x1f, 0xc0, 0xcb, 0xf8, 0x41, 0x4f, 0xcd, 0x1e, 0x6b, 0x39, 0xa7, 0x2b, 0xe9,
-//         0x30, 0x16, 0x83, 0xd2, 0x0e, 0x47, 0x8f, 0xe3, 0xb1, 0xdf, 0xa2, 0x15, 0xdb, 0x5d, 0x30,
-//         0xc5, 0x1a, 0xab, 0x31, 0x99, 0xf3, 0xfa, 0xb2, 0x86, 0x69, 0xad, 0x7a, 0xe8, 0xa7, 0x18,
-//         0x6a, 0xcc, 0xc8, 0x65, 0x23, 0x87, 0xa8, 0x5f, 0xf5, 0x21, 0x59, 0x75, 0x09, 0x71, 0x45,
-//         0x55, 0x25, 0x4b, 0xda, 0xa1, 0xc3, 0xf7, 0x41, 0xab, 0x59, 0xd9, 0x74, 0x12, 0x55, 0x5f,
-//         0xbc, 0xaf, 0xd9, 0xfd, 0xb0, 0x1e, 0xa3, 0x0f, 0xff, 0xde, 0x11, 0x16, 0x6a, 0xae, 0x0e,
-//         0xe1, 0x5d, 0x3c, 0x10, 0x43, 0x9a, 0xa1, 0x0b, 0x24, 0x8f, 0x0d, 0x7f, 0x0b, 0x5e, 0x4c,
-//         0x42, 0xa4, 0x84, 0x2c, 0x40, 0xd0, 0x55, 0x39, 0xe6, 0x4b, 0xf8, 0x9b, 0x2f, 0xdc, 0x28,
-//         0xff, 0xfa, 0xb5, 0x85, 0x19, 0xe5, 0x28, 0xa1, 0x77, 0xaa, 0x73, 0xf3, 0x03, 0xc7, 0x62,
-//         0xa6, 0x91, 0x18, 0xc9, 0xb0, 0xcd, 0x05, 0xdc, 0xca, 0x81, 0x26, 0x1a, 0x47, 0x40, 0xda,
-//         0x36, 0x7d, 0x6a, 0x53, 0xc8, 0x5a, 0x77, 0x5d, 0x19, 0xa4, 0x1b, 0x23, 0x83, 0xd0, 0xb2,
-//         0xaa, 0x0e, 0xbf, 0x77, 0x4e, 0x3a, 0x3b, 0x59, 0x00, 0x31, 0x0d, 0x02, 0x1b, 0x88, 0x7a,
-//         0xd4, 0xbd, 0x9d, 0xcc, 0x58, 0x04, 0x69, 0xf6, 0x3b, 0xca, 0x42, 0xe2, 0xfd, 0xc3, 0x3d,
-//         0x39, 0xc5, 0xd0, 0x71, 0xe4, 0xc8, 0xb7, 0x3e, 0x3f, 0xc8, 0xe9, 0xca, 0xc9, 0x3f, 0x04,
-//         0x4e, 0x1b, 0x79, 0xca, 0xa5, 0x61, 0xc2, 0xed, 0x1d, 0xa6, 0xda, 0x5a, 0xe9, 0x7f, 0x65,
-//         0x8c, 0xbe, 0x12, 0x6e, 0xa4, 0x5b, 0x33, 0x2f, 0x84, 0x28, 0x9c, 0x1c, 0x88, 0x2d, 0xff,
-//         0x07, 0xbf, 0xa6, 0xd7, 0x5a, 0x88, 0x86, 0xb0, 0x3f, 0xf6, 0x31, 0x5b, 0x11, 0x6d, 0xf5,
-//         0x58, 0xeb, 0x58, 0x02, 0x9e, 0xb5, 0x9a, 0xb1, 0xff, 0x25, 0x9d, 0x8b, 0x4f, 0xb6, 0x0a,
-//         0xf9, 0xea, 0x3e, 0x3f, 0x21, 0x09, 0x65, 0x21, 0x22, 0xfe, 0x3d, 0x4e, 0x11, 0x5b, 0x9e,
-//         0x5a, 0x59, 0x8b, 0xdd, 0xd8, 0xce, 0xd6, 0xd9, 0x59, 0xd2, 0x1e, 0xfd, 0xef, 0x0d, 0x1b,
-//         0xd9, 0x61, 0x7f, 0xd7, 0x2d, 0xad, 0x62, 0x09, 0xe5, 0x22, 0x63, 0xea, 0xc7, 0x31, 0xd9,
-//         0xa1, 0x38, 0x80, 0x5c, 0xa7, 0x32, 0x82, 0xec, 0x1b, 0xa2, 0x49, 0x5a, 0x06, 0xd2, 0x7c,
-//         0xc9, 0x96, 0x57, 0xbb, 0x17, 0x75, 0xfc, 0x7a, 0x8f, 0x0d, 0x77, 0xb5, 0x7a, 0x8e, 0x3e,
-//         0xf4, 0xba, 0x2f, 0x69, 0x13, 0x26, 0xd6, 0xd9, 0x21, 0x60, 0x2f, 0x21, 0x3e, 0x87, 0xee,
-//         0xfd, 0x87, 0x16, 0x0d, 0xc8, 0x08, 0x00, 0x25, 0x71, 0xac, 0x2c, 0x03, 0x2a, 0x37, 0x2d,
-//         0xb3, 0x34, 0x09, 0x91, 0xe3, 0x06, 0x2c, 0x38, 0x37, 0x95, 0x3b, 0x17, 0x7a, 0xaf, 0xac,
-//         0x99, 0x55, 0xab, 0x41, 0x39, 0x5f, 0x8e, 0xa6, 0x43, 0x80, 0x03, 0x88, 0x6f, 0x7d, 0xbd,
-//         0x5a, 0xb4, 0x2b, 0x32, 0x23, 0x5a, 0xa9, 0x31, 0x32, 0x39, 0x4c, 0x5b, 0xf4, 0x6b, 0xaf,
-//         0x66, 0x6f, 0x3c, 0x8e, 0x2d, 0x82, 0x97, 0x9f, 0x4a, 0x01, 0xdc, 0x99, 0x98, 0x00, 0xec,
-//         0x38, 0x7a, 0x79, 0x70, 0xa6, 0x85, 0xd6, 0x21, 0x63, 0x0d, 0x45, 0x9a, 0x2e, 0x5e, 0xa7,
-//         0xb1, 0xea, 0x66, 0x6a, 0xbc, 0x62, 0x2d, 0x7b, 0x7d, 0x85, 0xea, 0x95, 0x2f, 0xc0, 0xe8,
-//         0x6f, 0x35, 0xa0, 0x3a, 0x02, 0x25, 0xbc, 0xb2, 0x5f, 0x5c, 0x43, 0x96, 0xcc, 0x26, 0xd2,
-//         0x16, 0xb4, 0x96, 0x73, 0xd7, 0x13, 0xc7, 0xae, 0x53, 0x15, 0x31, 0x89, 0x68, 0x66, 0x6d,
-//         0x2c, 0x92, 0x1f, 0xcc, 0x5b, 0xa7, 0x8f, 0x5d, 0xbb, 0xc9, 0xdb, 0xe8, 0x3b, 0x9d, 0x61,
-//         0x74, 0x8b, 0x05, 0xa1, 0x58, 0x52, 0x68, 0xee, 0x3d, 0x39, 0x79, 0xa0, 0x9b, 0xdd, 0xe1,
-//         0x55, 0xc9, 0x60, 0xeb, 0xad, 0xb8, 0x5b, 0xc2, 0x5a, 0xb5, 0x2c, 0x18, 0x55, 0xa9, 0x50,
-//         0xc3, 0xf6, 0x72, 0x5f, 0xcc, 0xe2, 0xf4, 0x55, 0xb5, 0xd6, 0xb5, 0x4a, 0x99, 0xa5, 0x28,
-//         0x74, 0x97, 0x18, 0xe8, 0xc0, 0x84, 0x89, 0x50, 0x03, 0x86, 0x4d, 0x1a, 0xb7, 0x09, 0x90,
-//         0xa2, 0x01, 0x04, 0xbb, 0x73, 0x62, 0xcb, 0x97, 0x22, 0x70, 0x5d, 0x52, 0x41, 0x8e, 0xd9,
-//         0x90, 0x15, 0xaa, 0xab, 0x0a, 0x31, 0x65, 0xb4, 0xda, 0xd0, 0xee, 0x24, 0xc9, 0x41, 0x91,
-//         0x1e, 0xbc, 0x46, 0x70, 0x40, 0x9d, 0xda, 0x0e, 0x2a, 0xe4, 0xb2, 0x4c, 0x9f, 0xf2, 0xfc,
-//         0xf3, 0x84, 0x17, 0x44, 0x1e, 0xd7, 0xca, 0x23, 0x1f, 0x3f, 0x5a, 0x22, 0x3d, 0xaf, 0x9b,
-//         0x2d, 0xfc, 0x41, 0xad, 0x26, 0xb4, 0x45, 0x67, 0x0b, 0x80, 0x0e, 0xf9, 0x61, 0x37, 0xec,
-//         0x3b, 0xf4, 0x4b, 0x14, 0xdf, 0x5a, 0x0c, 0x3a, 0x50, 0x0b, 0x14, 0x0c, 0x72, 0xae, 0xc6,
-//         0xc5, 0xec, 0x35, 0x53, 0x2d, 0x59, 0xed, 0x91, 0x74, 0xe2, 0xc4, 0xc8, 0xf2, 0x25, 0x6b,
-//         0x97, 0x6f, 0xc9, 0x76, 0xce, 0xa9, 0xb1, 0x99, 0x8f, 0x5a, 0x92, 0x3b, 0xc4, 0x8d, 0x54,
-//         0x50, 0x40, 0x72, 0xd6, 0x90, 0x83, 0xfc, 0xe5, 0x49, 0x8b, 0x17, 0xf5, 0xfd, 0x6b, 0x8d,
-//         0x32, 0x02, 0xe9, 0x0a, 0xfe, 0xbf, 0x00, 0x6b, 0xa3, 0xad, 0x5f, 0x09, 0x4b, 0x97, 0x2b,
-//         0x00, 0x58, 0x65, 0x2e, 0x07, 0x49, 0x0a, 0x3b, 0x6b, 0x2e, 0x50, 0x6c, 0x1d, 0xac, 0xb7,
-//         0x6a, 0x26, 0xd8, 0x13, 0xa4, 0xca, 0x16, 0xae, 0xab, 0x93, 0xb9, 0x1c, 0x1c, 0xb4, 0x47,
-//         0x6a, 0x38, 0x36, 0x17, 0x27, 0xc9, 0x7f, 0xc7, 0x64, 0xcb, 0x89, 0x58, 0xc5, 0x61, 0xc2,
-//         0xc6, 0xea, 0x15, 0x0b, 0x34, 0x0c, 0x5d, 0x61, 0x76, 0x6e, 0x2b, 0x62, 0x40, 0x92, 0xa3,
-//         0x6c, 0xef, 0xf4, 0xe4, 0xc3, 0xa1, 0xa8, 0xf5, 0x94, 0x79, 0x0d, 0xd1, 0x3d, 0xcb, 0x3d,
-//         0x40, 0xb6, 0xd0, 0xf0, 0x10, 0x54, 0xd8, 0x47, 0x25, 0x51, 0xc5, 0x41, 0x79, 0x00, 0xe5,
-//         0xa0, 0x72, 0xde, 0xbb, 0x3b, 0x62, 0x17, 0xf6, 0xbc, 0x5d, 0x00, 0x76, 0x2e, 0xa7, 0x3b,
-//         0xb6, 0xf1, 0x98, 0x72, 0x59, 0x2a, 0x73, 0xb0, 0x21, 0xd6, 0x49, 0xe0, 0xc0, 0xd5, 0xeb,
-//         0x02, 0x7d, 0x4b, 0x41, 0x28, 0x70, 0x2d, 0xec, 0x2b, 0x71, 0x1f, 0x0b, 0xb9, 0x71, 0x63,
-//         0x06, 0xe6, 0xbc, 0x60, 0xbb, 0xf4, 0x9a, 0x62, 0x43, 0x09, 0x18, 0x4e, 0x93, 0x06, 0x4d,
-//         0x76, 0xfa, 0x7f, 0xbd, 0x02, 0xe4, 0x50, 0x91, 0x12, 0xe5, 0x86, 0xff, 0x64, 0x1e, 0xaf,
-//         0x7e, 0xb3, 0xb2, 0xde, 0x89, 0xc1, 0xa2, 0x6f, 0x40, 0x7b, 0x41, 0x51, 0x63, 0xea, 0x25,
-//         0xd1, 0x97, 0x57, 0x92, 0xa8, 0x45, 0xa1, 0xa5, 0x45, 0x21, 0x43, 0x7f, 0x83, 0x15, 0x29,
-//         0xd0, 0x30, 0x53, 0x32, 0xb4, 0x5a, 0x17, 0x96, 0xbc, 0xc2, 0x68, 0xa9, 0xb7, 0xaf, 0xac,
-//         0xdf, 0xf1, 0xe3, 0x89, 0xba, 0x24, 0x79, 0x54, 0xc6, 0x14, 0x07, 0x1c, 0x1e, 0x0d, 0x3a,
-//         0x6b, 0xe5, 0x3d, 0x4e, 0x10, 0x60, 0x96, 0xec, 0x6c, 0xda, 0x47, 0xae, 0x03, 0x25, 0x39,
-//         0x1d, 0x74, 0xc8, 0xac, 0x6a, 0xf2, 0x6b, 0x05, 0x2a, 0x9a, 0xe7, 0xe8, 0x92, 0xd6, 0xc2,
-//         0x6d, 0xfa, 0xe8, 0xa7, 0x9d, 0x5f, 0x48, 0xc9, 0x75, 0xf1, 0x66, 0x6a, 0xdb, 0x5d, 0x9a,
-//         0xcd, 0x27, 0xdd, 0xb9, 0x24, 0x04, 0x9c, 0x18, 0xc2, 0x6d, 0x0c, 0x91, 0x34, 0x48, 0x42,
-//         0x6f, 0xe9, 0x59, 0x70, 0xc4, 0x7e, 0x81, 0x0e, 0x32, 0x0a, 0x93, 0x48, 0xb0, 0xc0, 0x15,
-//         0x9e, 0x05, 0xac, 0x36, 0x16, 0xcb, 0x59, 0x65, 0xa0, 0x83, 0xdf, 0x3e, 0xda, 0xfb, 0x1d,
-//         0x1a, 0xdb, 0x65, 0xec, 0x9a, 0xc6, 0xc3, 0x8e, 0x3c, 0x45, 0xfd, 0xc8, 0xf5, 0x1c, 0x6a,
-//         0x67, 0x0d, 0x8f, 0x99, 0x7d, 0x30, 0x21, 0x8c, 0xea, 0x22, 0x87, 0x65, 0xc9, 0xb2, 0x4c,
-//         0xe4, 0x1b, 0x46, 0xba, 0x54, 0xbd, 0x7c, 0xca, 0xd5, 0x8f, 0x5b, 0xa5, 0x01, 0x04, 0xd8,
-//         0x0a, 0x16, 0xbf, 0xb9, 0x50, 0x2e, 0x37, 0x2f, 0x64, 0xf3, 0x70, 0x11, 0x02, 0x05, 0x31,
-//         0x9b, 0xa0, 0xb2, 0x01, 0x5e, 0x4f, 0x19, 0xc9, 0xd4, 0xea, 0xa1, 0x79, 0x54, 0x53, 0xa7,
-//         0xde, 0x2f, 0x49, 0xd3, 0xd1, 0x63, 0xb5, 0x03, 0x15, 0x4e, 0xbf, 0x04, 0xb3, 0x26, 0x8b,
-//         0x20, 0xb2, 0x45, 0xcf, 0xcd, 0x5b, 0x82, 0x32, 0x88, 0x61, 0xa7, 0xa8, 0xb2, 0xa0, 0x72,
-//         0x96, 0xc0, 0xdb, 0x2b, 0xe2, 0x5f, 0xba, 0xe3, 0xf5, 0x8a, 0xde, 0xf1, 0x18, 0x01, 0x16,
-//         0x40, 0xd9, 0x86, 0x12, 0x09, 0x18, 0x1b, 0x05, 0x0c, 0xb1, 0xb5, 0x47, 0xe2, 0x43, 0xab,
-//         0xfe, 0x92, 0x63, 0x7e, 0x95, 0x2b, 0xf0, 0xaf, 0xe1, 0xf1, 0xc3, 0x4a, 0xff, 0x2b, 0x09,
-//         0xbb, 0x4a, 0x0e, 0x9a, 0xc4, 0xd8, 0x64, 0x7d, 0x83, 0xa0, 0x4f, 0x44, 0xdb, 0xc4, 0xa8,
-//         0x58, 0xef, 0xfc, 0x9e, 0x77, 0xf9, 0xa6, 0x8f, 0x58, 0x8b, 0x12, 0xf4, 0xe9, 0x81, 0x12,
-//         0x47, 0x51, 0x41, 0x83, 0xef, 0xf6, 0x73, 0xbc, 0x8e, 0x0f, 0x4c, 0x8f, 0x4e, 0x69, 0x90,
-//         0x77, 0x29, 0x5d, 0x92, 0xb0, 0x6d, 0x06, 0x67, 0x29, 0x60, 0xbd, 0x4b, 0x17, 0xc8, 0x89,
-//         0x69, 0x28, 0x29, 0xd6, 0x78, 0xcb, 0x11, 0x4c, 0xba, 0x8b, 0x68, 0xae, 0x7e, 0x9f, 0xef,
-//         0x95, 0xda, 0xe2, 0x9e, 0x7f, 0xe9, 0x55, 0xe5, 0xe1, 0xe2, 0xb7, 0xe6, 0x5f, 0xbb, 0x2c,
-//         0xa2, 0xe6, 0xee, 0xc7, 0x0a, 0x60, 0xa9, 0xd1, 0x80, 0xdf, 0x7f, 0xd6, 0x97, 0xab, 0x1d,
-//         0x22, 0x25, 0xfc, 0x79, 0x23, 0xe0, 0xae, 0xc5, 0xef, 0x16, 0xa4, 0xa1, 0x0f, 0x92, 0xa9,
-//         0xc7, 0xe3, 0x3a, 0x55, 0xdf, 0x62, 0x49, 0xd9, 0xf5, 0x84, 0x49, 0xc5, 0x90, 0x34, 0xd3,
-//         0xe1, 0xac, 0x99, 0x21, 0xb1, 0x02, 0x76, 0x4a, 0xfa, 0xd4, 0xbb, 0xa4, 0x9c, 0xa2, 0xe2,
-//         0xcb, 0x3d, 0x3b, 0x14, 0x75, 0x60, 0xd1, 0x02, 0xb4, 0xa3, 0xb4, 0x72, 0x06, 0xf9, 0x19,
-//         0x9c, 0xe2, 0xe4, 0xa7, 0x0f, 0x25, 0x88, 0xc6, 0x86, 0xd6, 0x8c, 0x74, 0x4e, 0x6e, 0xfc,
-//         0xa8, 0x48, 0x9e, 0xa7, 0x9d, 0x1a, 0x4b, 0x37, 0x09, 0xc8, 0xb0, 0x10, 0xbe, 0x6f, 0xfe,
-//         0xa3, 0xc4, 0x7a, 0xb5, 0x3d, 0xe8, 0x30, 0xf1, 0x0d, 0xa0, 0xb2, 0x44, 0xfc, 0x9b, 0x8c,
-//         0xf8, 0x61, 0xed, 0x81, 0xd1, 0x62, 0x11, 0xb4, 0xe1, 0xd5, 0x39, 0x52, 0x89, 0xd3, 0xa8,
-//         0x49, 0x31, 0xdf, 0xb6, 0xf9, 0x91, 0xf4, 0x1c, 0x9d, 0x09, 0x95, 0x40, 0x56, 0xe7, 0xe3,
-//         0xcd, 0x5c, 0x92, 0xc1, 0x1d, 0x6b, 0xe9, 0x78, 0x6f, 0x8e, 0x94, 0x42, 0x66, 0xa2, 0xaa,
-//         0xd3, 0xc8, 0x2e, 0xe3, 0xf6, 0x07, 0x72, 0x0b, 0x6b, 0x1e, 0x7b, 0xb9, 0x7c, 0xe0, 0xa0,
-//         0xbc, 0xd9, 0x25, 0xdf, 0x87, 0xa8, 0x5f, 0x9c, 0xcc, 0xf0, 0xdb, 0x42, 0x8e, 0x07, 0x31,
-//         0x13, 0x01, 0x66, 0x32, 0xd1, 0xb8, 0xd6, 0xe3, 0x5e, 0x12, 0x76, 0x61, 0xd3, 0x38, 0x89,
-//         0xe6, 0x17, 0x6f, 0xa5, 0xf2, 0x71, 0x0e, 0xa5, 0xe2, 0x88, 0x30, 0xbb, 0xbe, 0x8a, 0xea,
-//         0xc7, 0x62, 0xc4, 0xcf, 0xb8, 0xcd, 0x33, 0x8d, 0x3d, 0x3e, 0xb5, 0x60, 0x3a, 0x03, 0x92,
-//         0xe4, 0x6d, 0x1b, 0xe0, 0xb4, 0x84, 0x08, 0x55, 0x88, 0xa7, 0x3a, 0xb9, 0x3d, 0x43, 0xc3,
-//         0xc0, 0xfa, 0x07, 0x6a, 0xca, 0x94, 0xad, 0x99, 0x55, 0xf1, 0xf1, 0xc0, 0x23, 0x87, 0x1d,
-//         0x3d, 0x1c, 0xd1, 0x66, 0xa0, 0x57, 0x10, 0x52, 0xa2, 0x7f, 0xbe, 0xf9, 0x88, 0xb6, 0x02,
-//         0xbf, 0x08, 0x23, 0xa9, 0x0c, 0x63, 0x17, 0x2a, 0xae, 0xf5, 0xf7, 0xb7, 0x21, 0x83, 0x92,
-//         0x31, 0x23, 0x0d, 0x20, 0xc3, 0xc2, 0x05, 0x21, 0x62, 0x8e, 0x45, 0xe8, 0x14, 0xc1, 0xda,
-//         0x75, 0xb8, 0xf8, 0x92, 0x01, 0xd0, 0x5d, 0x18, 0x9f, 0x99, 0x11, 0x19, 0xf5, 0x35, 0xe8,
-//         0x7f, 0x20, 0x88, 0x8c, 0x05, 0x75, 0xf5, 0xd7, 0x40, 0x17, 0xbb, 0x1e, 0x36, 0x52, 0xd9,
-//         0xa4, 0x9c, 0xc2, 0x9d, 0x42, 0x81, 0xd8, 0xc7, 0x8a, 0xe7, 0x4c, 0x81, 0xe0, 0xb7, 0x57,
-//         0xed, 0x48, 0x8b, 0xf0, 0x97, 0x15, 0x61, 0xd9, 0x2c, 0x7c, 0x45, 0xaf, 0xc2, 0xcd, 0xfc,
-//         0xaa, 0x13, 0xad, 0x59, 0xcc, 0xb2, 0xb2, 0x6e, 0xdd, 0x63, 0x9c, 0x32, 0x0f, 0xec, 0x83,
-//         0xbe, 0x78, 0xac, 0x91, 0x44, 0x1a, 0x1f, 0xea, 0xfd, 0x5d, 0x8e, 0xb4, 0xc0, 0x84, 0xd4,
-//         0xac, 0xb4, 0x87, 0x5f, 0xac, 0xef, 0xdf, 0xcd, 0x12, 0x56, 0xc8, 0xcd, 0xfe, 0xc5, 0xda,
-//         0xd3, 0xc1, 0x69, 0xf3, 0x61, 0x05, 0xea, 0x25, 0xe2, 0x12, 0x05, 0x8f, 0x39, 0x08, 0x08,
-//         0x7c, 0x37, 0xb6, 0x7e, 0x5b, 0xd8, 0xb1, 0x0e, 0xf2, 0xdb, 0x4b, 0xf1, 0xad, 0x90, 0x01,
-//         0x57, 0xcd, 0xa0, 0xb4, 0x52, 0xe8, 0xf3, 0xd7, 0x8a, 0xbd, 0x4f, 0x9f, 0x21, 0x40, 0x72,
-//         0xa4, 0xfc, 0x0b, 0x01, 0x2b, 0x2f, 0xb6, 0x4c, 0x95, 0x2d, 0x35, 0x33, 0x41, 0x6b, 0xa0,
-//         0x93, 0xe7, 0x2c, 0xf2, 0xd3, 0x72, 0x8b, 0xf4, 0x4f, 0x15, 0x3c, 0xaf, 0xd6, 0x12, 0xde,
-//         0x3f, 0x83, 0x3f, 0xff, 0xf8, 0x7f, 0xf6, 0xcc, 0xa6, 0x7f, 0xc9, 0x9a, 0x6e, 0x1f, 0xc1,
-//         0x0c, 0xfb, 0xee, 0x9c, 0xe7, 0xaf, 0xc9, 0x26, 0x54, 0xef, 0xb0, 0x39, 0xef, 0xb2, 0xe9,
-//         0x23, 0xc4, 0xef, 0xd1, 0xa1, 0xa4, 0x25, 0x24, 0x6f, 0x8d, 0x6a, 0xe5, 0x8a, 0x32, 0x3a,
-//         0xaf, 0xfc, 0xda, 0xce, 0x18, 0x25, 0x42, 0x07, 0x4d, 0x45, 0x8b, 0xdf, 0x85, 0xcf, 0x55,
-//         0xb2, 0x24, 0xfe, 0x9c, 0x69, 0x74, 0xa7, 0x6e, 0xa0, 0xce, 0xc0, 0x39, 0xf4, 0x86, 0xc6,
-//         0x8d, 0xae, 0xb9, 0x48, 0x64, 0x13, 0x0b, 0x40, 0x81, 0xa2, 0xc9, 0xa8, 0x85, 0x51, 0xee,
-//         0x9f, 0xcf, 0xa2, 0x8c, 0x19, 0x52, 0x48, 0xe2, 0xc1, 0xa8, 0x58, 0xb4, 0x10, 0x24, 0x06,
-//         0x58, 0x51, 0xfc, 0xb9, 0x12, 0xec, 0xfd, 0x73, 0xb4, 0x6d, 0x84, 0xfa, 0x06, 0x8b, 0x05,
-//         0x0b, 0x2d, 0xd6, 0xd6, 0x1f, 0x29, 0x82, 0x9f, 0x19, 0x12, 0x1e, 0xb2, 0x04, 0x8f, 0x7f,
-//         0x4d, 0xbd, 0x30, 0x2e, 0xe3, 0xe0, 0x88, 0x29, 0xc5, 0x93, 0xd6, 0x6c, 0x1f, 0x29, 0x45,
-//         0x91, 0xa7, 0x58, 0xcd, 0x05, 0x17, 0xd6, 0x6d, 0xb3, 0xca, 0x66, 0xcc, 0x3c, 0x4a, 0x74,
-//         0xfd, 0x08, 0x10, 0xa6, 0x99, 0x92, 0x10, 0xd2, 0x85, 0xab, 0x6e, 0x1d, 0x0e, 0x8b, 0x26,
-//         0x46, 0xd1, 0x6c, 0x84, 0xc0, 0x26, 0x43, 0x59, 0x68, 0xf0, 0x13, 0x1d, 0xfb, 0xe3, 0xd1,
-//         0xd2, 0xb4, 0x71, 0x9e, 0xf2, 0x59, 0x6a, 0x33, 0x29, 0x79, 0xd2, 0xd7, 0x26, 0xf1, 0xae,
-//         0x78, 0x9e, 0x1f, 0x0f, 0x3f, 0xe3, 0xe8, 0xd0, 0x27, 0x78, 0x77, 0xf6, 0xac, 0x9c, 0x56,
-//         0x39, 0x73, 0x8a, 0x6b, 0x2f, 0x34, 0x78, 0xb1, 0x11, 0xdb, 0xa4, 0x5c, 0x80, 0x01, 0x71,
-//         0x6a, 0xc2, 0xd1, 0x2e, 0x5e, 0x76, 0x28, 0x70, 0x93, 0xae, 0x3e, 0x78, 0xb0, 0x1f, 0x0f,
-//         0xda, 0xbf, 0xfb, 0x8a, 0x67, 0x65, 0x4f, 0x91, 0xed, 0x49, 0x75, 0x78, 0x62, 0xa2, 0x93,
-//         0xb5, 0x70, 0x7f, 0x4d, 0x08, 0x4e, 0x79, 0x61, 0xa8, 0x5f, 0x7f, 0xb4, 0x65, 0x9f, 0x91,
-//         0x54, 0x3a, 0xe8, 0x50, 0x33, 0xd3, 0xd5, 0x8a, 0x7c, 0xf3, 0x9e, 0x8b, 0x77, 0x7b, 0xc6,
-//         0xc6, 0x0c, 0x45, 0x95, 0x1f, 0xb0, 0xd0, 0x0b, 0x27, 0x4a, 0xfd, 0xc7, 0xf7, 0x0d, 0x5a,
-//         0x43, 0xc9, 0x7d, 0x35, 0xb0, 0x7d, 0xc4, 0x9c, 0x57, 0x1e, 0x76, 0x0d, 0xf1, 0x95, 0x30,
-//         0x71, 0xcc, 0xb3, 0x66, 0x3b, 0x63, 0xa8, 0x6c, 0xa3, 0x43, 0xa0, 0x24, 0xcc, 0xb7, 0x53,
-//         0xfe, 0xfe, 0xbc, 0x6e, 0x60, 0x89, 0xaf, 0x16, 0x21, 0xc8, 0x91, 0x6a, 0x89, 0xce, 0x80,
-//         0x2c, 0xf1, 0x59, 0xce, 0xc3, 0x60, 0x61, 0x3b, 0x0b, 0x19, 0xfe, 0x99, 0xac, 0x65, 0x90,
-//         0x15, 0x12, 0x05, 0xac, 0x7e, 0xff, 0x98, 0x7b, 0x66, 0x64, 0x0e, 0x4b, 0x5b, 0xaa, 0x8d,
-//         0x3b, 0xd2, 0x56, 0xcf, 0x99, 0x39, 0xee, 0x22, 0x81, 0xd0, 0x60, 0x06, 0x66, 0x20, 0x81,
-//         0x48, 0x3c, 0x6f, 0x3a, 0x77, 0xba, 0xcb, 0x52, 0xac, 0x79, 0x56, 0xaf, 0xe9, 0x16, 0x17,
-//         0x0a, 0xa3, 0x82, 0x08, 0xd5, 0x3c, 0x97, 0xcb, 0x09, 0xff, 0x7f, 0xf9, 0x4f, 0x60, 0x05,
-//         0xb9, 0x53, 0x26, 0xaa, 0xb8, 0x50, 0xaa, 0x19, 0x25, 0xae, 0x5f, 0xea, 0x8a, 0xd0, 0x89,
-//         0x12, 0x80, 0x43, 0x50, 0x24, 0x12, 0x21, 0x14, 0xcd, 0x77, 0xeb, 0x21, 0xcc, 0x5c, 0x09,
-//         0x64, 0xf3, 0xc7, 0xcb, 0xc5, 0x4b, 0xc3, 0xe7, 0xed, 0xe7, 0x86, 0x2c, 0x1d, 0x8e, 0x19,
-//         0x52, 0x9b, 0x2a, 0x0c, 0x18, 0x72, 0x0b, 0x1e, 0x1b, 0xb0, 0x0f, 0x42, 0x99, 0x04, 0xae,
-//         0xd5, 0xb7, 0x89, 0x1a, 0xb9, 0x4f, 0xd6, 0xaf, 0xf3, 0xc9, 0x93, 0x6f, 0xb0, 0x60, 0x83,
-//         0x6e, 0x6b, 0xd1, 0x5f, 0x3f, 0x1a, 0x83, 0x1e, 0x24, 0x00, 0x87, 0xb5, 0x3e, 0xdb, 0xf9,
-//         0x4d, 0xa7, 0x16, 0x2e, 0x19, 0x5b, 0x8f, 0x1b, 0x0d, 0x47, 0x72, 0x42, 0xe9, 0x0a, 0x11,
-//         0x08, 0x2d, 0x88, 0x1c, 0xbc, 0xc7, 0xb4, 0xbe, 0x29, 0x4d, 0x03, 0x5e, 0xec, 0xdf, 0xf3,
-//         0x3d, 0x2f, 0xe8, 0x1d, 0x9a, 0xd2, 0xd1, 0xab, 0x41, 0x3d, 0x87, 0x11, 0x45, 0xb0, 0x0d,
-//         0x46, 0xf5, 0xe8, 0x95, 0x62, 0x1c, 0x68, 0xf7, 0xa6, 0x5b, 0x39, 0x4e, 0xbf, 0x47, 0xba,
-//         0x5d, 0x7f, 0xb7, 0x6a, 0xf4, 0xba, 0x1d, 0x69, 0xf6, 0xa4, 0xe7, 0xe4, 0x6b, 0x3b, 0x0d,
-//         0x23, 0x16, 0x4a, 0xb2, 0x68, 0xf0, 0xb2, 0x0d, 0x09, 0x17, 0x6a, 0x63, 0x8c, 0x83, 0xd3,
-//         0xbd, 0x05, 0xc9, 0xf6, 0xf0, 0xa1, 0x31, 0x0b, 0x2c, 0xac, 0x83, 0xac, 0x80, 0x34, 0x32,
-//         0xb4, 0xec, 0xd0, 0xbc, 0x54, 0x82, 0x9a, 0xc8, 0xf6, 0xa0, 0x7d, 0xc6, 0x79, 0x73, 0xf4,
-//         0x20, 0x99, 0xf3, 0xb4, 0x01, 0xde, 0x91, 0x27, 0xf2, 0xc0, 0xdc, 0x81, 0x00, 0x4e, 0x7e,
-//         0x07, 0x99, 0xc8, 0x3a, 0x51, 0xbc, 0x38, 0xd6, 0x8a, 0xa2, 0xde, 0x3b, 0x6a, 0x8c, 0x1a,
-//         0x7c, 0x81, 0x0f, 0x3a, 0x1f, 0xe4, 0x05, 0x7b, 0x20, 0x35, 0x6b, 0xa5, 0x6a, 0xa7, 0xe7,
-//         0xbc, 0x9c, 0x20, 0xec, 0x00, 0x15, 0xe2, 0x51, 0xaf, 0x77, 0xeb, 0x29, 0x3c, 0x7d, 0x2e,
-//         0x00, 0x5c, 0x81, 0x21, 0xfa, 0x35, 0x6f, 0x40, 0xef, 0xfb, 0xd1, 0x3f, 0xcc, 0x9d, 0x55,
-//         0x53, 0xfb, 0x5a, 0xa5, 0x56, 0x89, 0x0b, 0x52, 0xeb, 0x57, 0x73, 0x4f, 0x1b, 0x67, 0x24,
-//         0xcb, 0xb8, 0x6a, 0x10, 0x69, 0xd6, 0xfb, 0x52, 0x40, 0xff, 0x20, 0xa5, 0xf3, 0x72, 0xe1,
-//         0x3d, 0xa4, 0x8c, 0x81, 0x66, 0x16, 0x0d, 0x5d, 0xad, 0xa8, 0x50, 0x25, 0x78, 0x31, 0x77,
-//         0x0c, 0x57, 0xe4, 0xe9, 0x15, 0x2d, 0xdb, 0x07, 0x87, 0xc8, 0xb0, 0x43, 0xde, 0xfc, 0xfe,
-//         0xa9, 0xeb, 0xf5, 0xb0, 0xd3, 0x7b, 0xe9, 0x1f, 0x6e, 0xca, 0xe4, 0x03, 0x95, 0xc5, 0xd1,
-//         0x59, 0x72, 0x63, 0xf0, 0x86, 0x54, 0xe8, 0x16, 0x62, 0x0b, 0x35, 0x29, 0xc2, 0x68, 0xd0,
-//         0xd6, 0x3e, 0x90, 0x60, 0x57, 0x1d, 0xc9, 0xed, 0x3f, 0xed, 0xb0, 0x2f, 0x7e, 0x97, 0x02,
-//         0x51, 0xec, 0xee, 0x6f, 0x82, 0x74, 0x76, 0x7f, 0xfb, 0xd6, 0xc4, 0xc3, 0xdd, 0xe8, 0xb1,
-//         0x60, 0xfc, 0xc6, 0xb9, 0x0d, 0x6a, 0x33, 0x78, 0xc6, 0xc1, 0xbf, 0x86, 0x2c, 0x50, 0xcc,
-//         0x9a, 0x70, 0x8e, 0x7b, 0xec, 0xab, 0x95, 0xac, 0x53, 0xa0, 0x4b, 0x07, 0x88, 0xaf, 0x42,
-//         0xed, 0x19, 0x8d, 0xf6, 0x32, 0x17, 0x48, 0x47, 0x1d, 0x41, 0x6f, 0xfe, 0x2e, 0xa7, 0x8f,
-//         0x4b, 0xa0, 0x51, 0xf3, 0xbf, 0x02, 0x0a, 0x48, 0x58, 0xf7, 0xa1, 0x6d, 0xea, 0xa5, 0x13,
-//         0x5a, 0x5b, 0xea, 0x0c, 0x9e, 0x52, 0x4f, 0x9e, 0xb9, 0x71, 0x7f, 0x23, 0x83, 0xda, 0x1b,
-//         0x86, 0x9a, 0x41, 0x29, 0xda, 0x70, 0xe7, 0x64, 0xa1, 0x7b, 0xd5, 0x0a, 0x22, 0x0d, 0x5c,
-//         0x40, 0xc4, 0x81, 0x07, 0x25, 0x35, 0x4a, 0x1c, 0x10, 0xdb, 0x45, 0x0a, 0xff, 0x36, 0xd4,
-//         0xe0, 0xeb, 0x5f, 0x68, 0xd6, 0x67, 0xc6, 0xd0, 0x8b, 0x76, 0x1a, 0x7d, 0x59, 0x42, 0xa1,
-//         0xcb, 0x96, 0x4d, 0x84, 0x09, 0x9a, 0x3d, 0xe0, 0x52, 0x85, 0x6e, 0x48, 0x90, 0x85, 0x2a,
-//         0x63, 0xb2, 0x69, 0xd2, 0x00, 0x43, 0x31, 0x37, 0xb3, 0x52, 0xaf, 0x62, 0xfa, 0xc1, 0xe0,
-//         0x03, 0xfb, 0x62, 0xaa, 0x88, 0xc9, 0xb2, 0x2c, 0xd5, 0xa8, 0xf5, 0xa5, 0x4c, 0x12, 0x59,
-//         0x4e, 0x06, 0x5e, 0x9b, 0x15, 0x66, 0x11, 0xb2, 0x27, 0x92, 0xdc, 0x98, 0x59, 0xde, 0xdf,
-//         0xfa, 0x9a, 0x32, 0x2e, 0xc0, 0x5d, 0x3c, 0x33, 0x41, 0x6d, 0xaf, 0xb2, 0x25, 0x23, 0x14,
-//         0xa5, 0x7b, 0xc7, 0x9b, 0x68, 0xf3, 0xda, 0xeb, 0xe3, 0xa9, 0xe2, 0x6f, 0x0e, 0x1d, 0x1c,
-//         0xba, 0x55, 0xb6, 0x34, 0x6a, 0x93, 0x1f, 0x1f, 0xb8, 0x34, 0xc8, 0x84, 0x08, 0xb1, 0x6b,
-//         0x6a, 0x28, 0x74, 0x74, 0xe5, 0xeb, 0x75, 0xe9, 0x7c, 0xd8, 0xba, 0xd8, 0x42, 0xa5, 0xee,
-//         0x1f, 0x80, 0xd9, 0x96, 0xb2, 0x2e, 0xe7, 0xbf, 0xba, 0xeb, 0xd1, 0x69, 0xbb, 0x8f, 0xfd,
-//         0x5a, 0x63, 0x8f, 0x39, 0x7f, 0xdf, 0x1d, 0x37, 0xd2, 0x18, 0x35, 0x9d, 0xb6, 0xcc, 0xe4,
-//         0x27, 0x81, 0x89, 0x38, 0x38, 0x68, 0x33, 0xe7, 0x78, 0xd8, 0x76, 0xf5, 0xee, 0xd0, 0x4a,
-//         0x07, 0x69, 0x19, 0x7a, 0xad, 0x18, 0xb1, 0x94, 0x61, 0x45, 0x53, 0xa2, 0x48, 0xda, 0x96,
-//         0x4a, 0xf9, 0xee, 0x94, 0x2a, 0x1f, 0x6e, 0x18, 0x3c, 0x92, 0x46, 0xd1, 0x1a, 0x28, 0x18,
-//         0x32, 0x1f, 0x3a, 0x45, 0xbe, 0x04, 0x35, 0x92, 0xe5, 0xa3, 0xcb, 0xb5, 0x2e, 0x32, 0x43,
-//         0xac, 0x65, 0x17, 0x89, 0x99, 0x15, 0x03, 0x9e, 0xb1, 0x23, 0x2f, 0xed, 0x76, 0x4d, 0xd8,
-//         0xac, 0x21, 0x40, 0xc4, 0x99, 0x4e, 0x65, 0x71, 0x2c, 0xb3, 0x45, 0xab, 0xfb, 0xe7, 0x72,
-//         0x39, 0x56, 0x30, 0x6d, 0xfb, 0x74, 0xeb, 0x99, 0xf3, 0xcd, 0x57, 0x5c, 0x78, 0x75, 0xe9,
-//         0x8d, 0xc3, 0xa2, 0xfb, 0x5d, 0xe0, 0x90, 0xc5, 0x55, 0xad, 0x91, 0x53, 0x4e, 0x9e, 0xbd,
-//         0x8c, 0x49, 0xa4, 0xa4, 0x69, 0x10, 0x0c, 0xc5, 0x76, 0xe9, 0x25, 0x86, 0x8d, 0x66, 0x23,
-//         0xa8, 0xdb, 0x5c, 0xe8, 0xd9, 0x30, 0xe1, 0x15, 0x7b, 0xc0, 0x99, 0x0f, 0x03, 0xec, 0xaa,
-//         0x12, 0xef, 0xce, 0xd4, 0xea, 0x55, 0x5c, 0x08, 0x86, 0xf4, 0xf4, 0xb0, 0x83, 0x42, 0x95,
-//         0x37, 0xb6, 0x38, 0xe0, 0x2b, 0x54, 0x89, 0xbd, 0x4e, 0x20, 0x9d, 0x3f, 0xc3, 0x4b, 0xb7,
-//         0xec, 0xfa, 0x5a, 0x14, 0x03, 0xcb, 0x64, 0xc8, 0x34, 0x4a, 0x4b, 0x6e, 0xf8, 0x6e, 0x56,
-//         0xf6, 0xdd, 0x5f, 0xa1, 0x24, 0xe2, 0xd4, 0xd0, 0x82, 0x64, 0x1f, 0x8e, 0x9b, 0xfa, 0xb4,
-//         0xcb, 0xdb, 0x0a, 0xe8, 0x15, 0xfc, 0x15, 0xab, 0x4b, 0x18, 0xbf, 0xd4, 0x42, 0x14, 0x48,
-//         0x82, 0x85, 0xdd, 0xeb, 0x49, 0x1b, 0x0b, 0x0b, 0x05, 0xe9, 0xb4, 0xa1, 0x33, 0x0a, 0x5d,
-//         0x0e, 0x6c, 0x4b, 0xc0, 0xd6, 0x6c, 0x7c, 0xfb, 0x69, 0x0b, 0x53, 0x19, 0xe4, 0xf3, 0x35,
-//         0xfc, 0xbe, 0xa1, 0x34, 0x02, 0x09, 0x4f, 0x74, 0x86, 0x92, 0xcd, 0x5d, 0x1a, 0xc1, 0x27,
-//         0x0c, 0xf2, 0xc5, 0xcf, 0xdd, 0x23, 0x93, 0x02, 0xbd, 0x41, 0x5e, 0x42, 0xf0, 0xa0, 0x9d,
-//         0x0c, 0x72, 0xc8, 0xec, 0x32, 0x0a, 0x8a, 0xfd, 0x3d, 0x5a, 0x41, 0x27, 0x0c, 0x88, 0x59,
-//         0xad, 0x94, 0x2e, 0xef, 0x5d, 0x8f, 0xc7, 0xdf, 0x66, 0xe4, 0xdd, 0x56, 0x6c, 0x7b, 0xca,
-//         0x55, 0x81, 0xae, 0xae, 0x5c, 0x1b, 0x1a, 0xab, 0xae, 0x99, 0x8d, 0xcc, 0x42, 0x97, 0x59,
-//         0xf4, 0x14, 0x3f, 0x75, 0xc6, 0xd1, 0x88, 0xba, 0xaa, 0x84, 0x4a, 0xd0, 0x34, 0x08, 0x3b,
-//         0x7d, 0xdb, 0x15, 0x06, 0xb0, 0x5c, 0xbd, 0x40, 0xf5, 0xa8, 0xec, 0xae, 0x36, 0x40, 0xdd,
-//         0x90, 0x1c, 0x3e, 0x0d, 0x7e, 0x73, 0xc7, 0xc2, 0xc5, 0x6a, 0xff, 0x52, 0x05, 0x7f, 0xbe,
-//         0xd0, 0x92, 0xfd, 0xb3, 0x6f, 0xff, 0x5d, 0xb7, 0x97, 0x64, 0x73, 0x7b, 0xca, 0xd1, 0x98,
-//         0x24, 0x6b, 0x0b, 0x01, 0x68, 0xdd, 0x27, 0x85, 0x85, 0xb5, 0x83, 0xc1, 0xe0, 0x50, 0x64,
-//         0xc7, 0xaf, 0xf1, 0xc6, 0x4d, 0xb1, 0xef, 0xc9, 0xb4, 0x0a, 0x6d, 0x65, 0xf3, 0x47, 0xcc,
-//         0xa3, 0x02, 0x21, 0x0c, 0xbe, 0x22, 0x29, 0x05, 0xcf, 0x5f, 0xe8, 0x94, 0x6c, 0xe5, 0xdc,
-//         0xc4, 0xdf, 0xbe, 0x3e, 0xa8, 0xb4, 0x18, 0xb0, 0x99, 0xb8, 0x6f, 0xff, 0x5d, 0xb9, 0xfd,
-//         0x3b, 0x5d, 0x16, 0xbf, 0x3e, 0xd8, 0xb3, 0xd8, 0x08, 0x34, 0xf6, 0x47, 0x35, 0x5b, 0x72,
-//         0x1a, 0x33, 0xad, 0x52, 0x5d, 0xb8, 0xd0, 0x77, 0xc6, 0xab, 0xba, 0x55, 0x09, 0x5f, 0x02,
-//         0xf8, 0xd4, 0x5f, 0x53, 0x06, 0x91, 0xcd, 0x74, 0x42, 0xae, 0x54, 0x91, 0x81, 0x62, 0x13,
-//         0x6f, 0xd8, 0xa9, 0x77, 0xc3, 0x6c, 0xcb, 0xf1, 0x29, 0x5a, 0xcc, 0xda, 0x35, 0xbd, 0x52,
-//         0x23, 0xbe, 0x59, 0xeb, 0x12, 0x6d, 0xb7, 0x53, 0xee, 0xfc, 0xb4, 0x1b, 0x13, 0x5e, 0xba,
-//         0x16, 0x7c, 0xc5, 0xf3, 0xe3, 0x6d, 0x07, 0x78, 0xf5, 0x2b, 0x21, 0x05, 0x88, 0x4c, 0xc0,
-//         0xa1, 0xe3, 0x36, 0x10, 0xf8, 0x1b, 0xd8, 0x17, 0xfb, 0x6a, 0x4e, 0xd8, 0xb3, 0x47, 0x2d,
-//         0x99, 0xbd, 0xbb, 0x5d, 0x37, 0x7d, 0xba, 0xf1, 0xe1, 0x7c, 0xc0, 0xc5, 0x54, 0x62, 0x7f,
-//         0xcf, 0x5a, 0x4a, 0x93, 0xcc, 0xf1, 0x1b, 0x34, 0xc8, 0xa6, 0x05, 0x4c, 0x55, 0x8b, 0x54,
-//         0x84, 0xd5, 0x77, 0xeb, 0xc0, 0x6d, 0x3a, 0x29, 0xbd, 0x75, 0x61, 0x09, 0x9a, 0x2c, 0xbb,
-//         0xf7, 0x18, 0x79, 0x34, 0x90, 0x24, 0xa5, 0x81, 0x70, 0x87, 0xc5, 0x02, 0x7c, 0xba, 0xd4,
-//         0x5e, 0x14, 0x8e, 0xe4, 0xed, 0xa2, 0x61, 0x6a, 0xb9, 0x6e, 0xb5, 0x4a, 0xb9, 0x01, 0x46,
-//         0xf4, 0xcf, 0xbc, 0x09, 0x2f, 0x27, 0x4b, 0xbd, 0x86, 0x7a, 0x10, 0xe1, 0xd4, 0xc8, 0xd9,
-//         0x20, 0x8d, 0x8a, 0x63, 0x00, 0x63, 0x44, 0xeb, 0x54, 0x0b, 0x75, 0x49, 0x10, 0xa2, 0xa7,
-//         0xad, 0xb9, 0xd1, 0x01, 0x80, 0x63, 0x25, 0xc8, 0x12, 0xa6, 0xce, 0x1e, 0xbe, 0xfe, 0x7e,
-//         0x5f, 0x3c, 0xdb, 0x34, 0xea, 0x37, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x8c, 0x9a, 0xb6,
-//         0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x1b, 0xb4, 0xea, 0x56,
-//         0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xd6, 0x2e, 0xde, 0x1f, 0x9d,
-//         0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x66, 0x4e, 0x1e, 0x9f, 0x9d, 0xb8, 0xf2, 0x47,
-//         0x0c, 0x9a, 0xb6, 0xee, 0x3f, 0xfc, 0x7a, 0x57, 0x0d, 0x79, 0x70, 0x62, 0x27, 0xad, 0xb9,
-//         0xd1, 0x01, 0x61, 0x40, 0x02, 0x67, 0x2d, 0xd8, 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xd7, 0x2c,
-//         0xbb, 0xf4, 0x4b, 0xf5, 0x49, 0xf1, 0x60, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x01,
-//         0x80, 0x63, 0x25, 0xa9, 0xb1, 0xe0, 0x42, 0xe7, 0x4c, 0x1a, 0x97, 0xac, 0xbb, 0xf4, 0x6a,
-//         0x37, 0xcd, 0x18, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0xa8, 0xd2, 0x07, 0x6d, 0x58, 0x32,
-//         0xe6, 0x4e, 0x1e, 0x9f, 0xbc, 0xfa, 0x57, 0x0d, 0x79, 0x51, 0x20, 0xc2, 0x06, 0x6f, 0x5c,
-//         0x1b, 0x95, 0xa8, 0xb3, 0xc5, 0xe9, 0x31, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93,
-//         0x85, 0x69, 0x31, 0xc1, 0xe1, 0x21, 0xc0, 0xe3, 0x44, 0x0a, 0x77, 0x6c, 0x5a, 0x17, 0x8d,
-//         0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x17, 0xac, 0xbb, 0xf4, 0x4b, 0x14,
-//         0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xb3, 0xc5, 0xe9, 0x31, 0xc1, 0x00, 0x82, 0x67, 0x4c,
-//         0xfb, 0x55, 0x28, 0xd2, 0x26, 0xaf, 0xbd, 0xd9, 0x11, 0x81, 0x61, 0x21, 0xa1, 0xa1, 0xc0,
-//         0x02, 0x86, 0x6f, 0x5c, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xdd,
-//         0x19, 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x7c, 0x5b, 0x15, 0x89, 0x90, 0x83, 0x84, 0x6b, 0x54,
-//         0x0b, 0x75, 0x68, 0x52, 0x07, 0x6d, 0x58, 0x32, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0xed, 0x58,
-//         0x32, 0xe6, 0x4e, 0xff, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xdd, 0x38, 0xd3, 0x05, 0x88, 0x92,
-//         0xa6, 0xaf, 0xdc, 0x1b, 0xb4, 0xcb, 0xf5, 0x68, 0x52, 0x07, 0x8c, 0x7b, 0x55, 0x09, 0x90,
-//         0x83, 0x84, 0x6b, 0x54, 0x2a, 0xb7, 0xec, 0x3b, 0xd5, 0x09, 0x90, 0xa2, 0xc6, 0x0e, 0x7f,
-//         0x7c, 0x7a, 0x57, 0x0d, 0x98, 0xb2, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0x0c, 0x7b, 0x74, 0x4b,
-//         0x14, 0x8b, 0x94, 0xaa, 0xb7, 0xcd, 0x18, 0x93, 0xa4, 0xca, 0x16, 0xae, 0xbf, 0xdd, 0x19,
-//         0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x63, 0x44, 0xeb, 0x35, 0xc9,
-//         0x10, 0x83, 0x65, 0x48, 0x12, 0xa6, 0xce, 0x1e, 0x9f, 0xbc, 0xdb, 0x15, 0x89, 0x71, 0x60,
-//         0x23, 0xc4, 0xeb, 0x54, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xcf, 0x81, 0x10, 0xac, 0x74,
-//     ];
-// }
+const RATIO: u32 = 5;
diff --git a/examples/rtic_bare7.rs b/examples/rtic_bare7.rs
index 6813067ce97a217b57b40abacb02701f4408c10c..0f2dea18411d7e7c80325ad9cff46836177451f1 100644
--- a/examples/rtic_bare7.rs
+++ b/examples/rtic_bare7.rs
@@ -1,15 +1,25 @@
 //! rtic_bare7.rs
 //!
-//! Clocking
+//! HAL OutputPin abstractions
 //!
 //! What it covers:
 //! - using embedded hal, and the OutputPin abstraction
 
+#![no_main]
+#![no_std]
+
 use panic_rtt_target as _;
 use rtic::cyccnt::{Instant, U32Ext as _};
 use rtt_target::{rprintln, rtt_init_print};
 use stm32f4xx_hal::stm32;
 
+use stm32f4xx_hal::{
+    gpio::{gpioa::PA5, Output, PushPull},
+    prelude::*,
+};
+;
+use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin};
+
 const OFFSET: u32 = 8_000_000;
 
 #[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)]
@@ -17,6 +27,7 @@ const APP: () = {
     struct Resources {
         // late resources
         GPIOA: stm32::GPIOA,
+        // led: PA5<Output<PushPull>>,
     }
     #[init(schedule = [toggle])]
     fn init(cx: init::Context) -> init::LateResources {
@@ -76,23 +87,38 @@ const APP: () = {
     }
 };
 
+fn _toggle_generic<E>(led: &mut dyn OutputPin<Error = E>, toggle: &mut bool) {
+    if *toggle {
+        led.set_high().ok();
+    } else {
+        led.set_low().ok();
+    }
+
+    *toggle = !*toggle;
+}
+
+fn _toggleable_generic<E>(led: &mut dyn ToggleableOutputPin<Error = E>) {
+    led.toggle().ok();
+}
+
 // 1. In this example you will use RTT.
 //
 //    > cargo run --example rtic_bare7
 //
-//    Now look at the documentation for `embedded_hal::digital::v2::OutputPin`.
+//    Look in the generated documentation for `set_high`/`set_low`.
 //    (You created documentation for your dependencies in previous exercise
 //    so you can just search (press `S`) for `OutputPin`).
+//    You will find that these methods are implemented for `Output` pins.
 //
-//    You see that the OutputPin trait defines `set_low`/`set_high` functions.
-//    Your task is to alter the code to use the `set_low`/`set_high` API.
+//    Now change your code to use these functions instead of the low-level GPIO API.
 //
 //    HINTS:
 //    - A GPIOx peripheral can be `split` into individual PINs Px0..Px15).
 //    - A Pxy, can be turned into an `Output` by `into_push_pull_output`.
 //    - You may optionally set other pin properties as well (such as `speed`).
 //    - An `Output` pin provides `set_low`/`set_high`
-//      (and implements the `OutputPin` trait in embedded-hal).
+//    - Instead of passing `GPIO` resource to the `toggle` task pass the
+//      `led: PA5<Output<PushPull>>` resource instead.
 //
 //    Comment your code to explain the steps taken.
 //
@@ -101,29 +127,115 @@ const APP: () = {
 //
 //    Commit your code (bare7_1)
 //
-// 2. Optional
+// 2. Further generalizations:
+//
+//    Now look at the documentation for `embedded_hal::digital::v2::OutputPin`.
+//
+//    You see that the OutputPin trait defines `set_low`/`set_high` functions.
+//    Your task is to alter the code to use the `set_low`/`set_high` API.
+//
+//    The function `_toggle_generic` is generic to any object that
+//    implements the `OutputPin<Error = E>` trait.
+//
+//    Digging deeper we find the type parameter `E`, which in this case
+//    is left generic (unbound).
+//
+//    It will be instantiated with a concrete type argument when called.
+//
+//    Our `PA5<Output<PushPull>>` implements `OutputPin` trait, thus
+//    we can pass the `led` resource to `_toggle_generic`.
+//    
+//    The error type is given by the stm32f4xx-hal implementation:
+//    where `core::convert::Infallible` is used to indicate
+//    there are no errors to be expected (hence infallible).
+//
+//    Additionally, `_toggle_generic` takes a mutable reference
+//    `toggle: &mut bool`, so you need to pass your `TOGGLE` variable.
+//
+//    As you see, `TOGGLE` holds the "state", switching between
+//    `true` and `false` (to make your led blink).
+//
+//    Change your code into using the `_toggle_generic` function.
+//    (You may rename it to `toggle_generic` if wished.)
+//
+//    Confirm that your implementation correctly toggles the LED as in
+//    previous exercise.
+//
+//    Commit your code (bare7_2)
+//
+// 3. What about the state?
+//
+//    In your code `TOGGLE` holds the "state". However, the underlying
+//    hardware ALSO holds the state (if the corresponding bit is set/cleared).
+//
+//    What if we can leverage that, and guess what we can!!!!
+//
+//    Look at the documentation for `embedded_hal::digital::v2::ToggleableOutputPin`,
+//    and the implementation of:
+//
+//    fn _toggleable_generic(led: &mut dyn ToggleableOutputPin<Error = Infallible>) {
+//      led.toggle().ok();
+//    }
+//
+//    The latter does not take any state variable, instead it directly `toggle()`
+//    the `ToggleableOutputPin`.
+//
+//    Now alter your code to leverage on the `_toggleable_generic` function.
+//    (You should be able to remove the `TOGGLE` state variable altogether.)
+//
+//    Confirm that your implementation correctly toggles the LED as in
+//    previous exercise.
+//
+//    Commit your code (bare7_3)
+//
+// 4. Discussion:
+//
+//    In this exercise you have gone from a very hardware specific implementation,
+//    to leveraging abstractions (batteries included).
+//
+//    Your final code amounts to "configuration" rather than "coding".
 //
-//    Use the `toggle` function instead to further simply your code.
+//    This reduces the risk of errors (as you let the libraries do the heavy lifting).
 //
-//    Notice:
-//    The `ToggleableOutputPin` abstraction requires `embedded-hal`
-//    to compiled with the `unproven` feature.
+//    This also improves code-re use. E.g., if you were to do something less
+//    trivial then merely toggling you can do that in a generic manner,
+//    breaking out functionality into "components" re-usable in other applications.
 //
-//    The `embedded-hal` traits is mostly used to write drivers
-//    that is hardware agnostic (and thus cross platform).
+//    Of course the example is trivial, you don't gain much here, but the principle
+//    is the same behind drivers for USART communication, USB, PMW3389 etc.
 //
-//    However:
-//    In our case we can use `toggle` directly as implemented by the `stm32f4xx-hal`.
+// 5. More details:
+//    
+//    Looking closer at the implementation:
+//    `led: &mut dyn OutputPin<Error = E>`
 //
-//    Confirm that your implementation correctly toggles the LED.
+//    You may ask what kind of mumbo jumbo is at play here.
 //
-//    Which one do you prefer and why (what problem does it solve)?
+//    This is the way to express that we expect a mutable reference to a trait object 
+//    that implements the `OutputPin`. Since we will change the underlying object
+//    (in this case an GPIOA pin 5) the reference needs to be mutable.
+// 
+//    Trait objects are further explained in the Rust book.
+//    The `dyn` keyword indicates dynamic dispatch (through a VTABLE).
+//    https://doc.rust-lang.org/std/keyword.dyn.html
 //
-//    ** your answer here **
+//    Notice: the Rust compiler (rustc + LLVM) is really smart. In many cases
+//    it can analyse the call chain, and conclude the exact trait object type at hand.
+//    In such cases the dynamic dispatch is turned into a static dispatch
+//    and the VTABLE is gone, and we have a zero-cost abstraction.
 //
-//    Commit your answer (bare7_2)
+//    If the trait object is stored for e.g., in an array along with other
+//    trait objects (of different concrete type), there is usually no telling
+//    the concrete type of each element, and we will have dynamic dispatch.
+//    Arguably, this is also a zero-cost abstraction, as there is no (obvious)
+//    way to implement it more efficiently. Remember, zero-cost is not without cost
+//    just that it is as good as it possibly gets (you can't make it better by hand).
 //
-// 3. Discussion
+//    You can also force the compiler to deduce the type at compile time, by using
+//    `impl` instead of `dyn`, if you are sure you don't want the compiler to
+//    "fallback" to dynamic dispatch.
 //
-//    In this exercise you have learned more on navigating the generated documentation
-//    and to use abstractions to simplify and generalize your code.
+//    You might find Rust to have long compile times. Yes you are right,
+//    and this type of deep analysis done in release mode is part of the story.
+//    On the other hand, the aggressive optimization allows us to code 
+//    in a generic high level fashion and still have excellent performing binaries.
\ No newline at end of file
diff --git a/examples/rtic_bare8.rs b/examples/rtic_bare8.rs
new file mode 100644
index 0000000000000000000000000000000000000000..b4b18ee4a72d728359e36c70467f4de9ba8643a0
--- /dev/null
+++ b/examples/rtic_bare8.rs
@@ -0,0 +1,185 @@
+//! bare8.rs
+//!
+//! Serial
+//!
+//! What it covers:
+//! - serial communication
+//! - bad design
+
+#![no_main]
+#![no_std]
+
+use panic_rtt_target as _;
+
+use nb::block;
+
+use stm32f4xx_hal::{
+    gpio::{gpioa::PA, Output, PushPull},
+    prelude::*,
+    serial::{config::Config, Rx, Serial, Tx},
+    stm32::USART2,
+};
+
+use rtic::app;
+use rtt_target::{rprintln, rtt_init_print};
+
+#[app(device = stm32f4xx_hal::stm32, peripherals = true)]
+const APP: () = {
+    struct Resources {
+        // Late resources
+        TX: Tx<USART2>,
+        RX: Rx<USART2>,
+    }
+
+    // init runs in an interrupt free section
+    #[init]
+    fn init(cx: init::Context) -> init::LateResources {
+        rtt_init_print!();
+        rprintln!("init");
+
+        let device = cx.device;
+
+        let rcc = device.RCC.constrain();
+
+        // 16 MHz (default, all clocks)
+        let clocks = rcc.cfgr.freeze();
+
+        let gpioa = device.GPIOA.split();
+
+        let tx = gpioa.pa2.into_alternate_af7();
+        let rx = gpioa.pa3.into_alternate_af7();
+
+        let serial = Serial::usart2(
+            device.USART2,
+            (tx, rx),
+            Config::default().baudrate(115_200.bps()),
+            clocks,
+        )
+        .unwrap();
+
+        // Separate out the sender and receiver of the serial port
+        let (tx, rx) = serial.split();
+
+        // Late resources
+        init::LateResources { TX: tx, RX: rx }
+    }
+
+    // idle may be interrupted by other interrupts/tasks in the system
+    #[idle(resources = [RX, TX])]
+    fn idle(cx: idle::Context) -> ! {
+        let rx = cx.resources.RX;
+        let tx = cx.resources.TX;
+
+        loop {
+            match block!(rx.read()) {
+                Ok(byte) => {
+                    rprintln!("Ok {:?}", byte);
+                    tx.write(byte).unwrap();
+                }
+                Err(err) => {
+                    rprintln!("Error {:?}", err);
+                }
+            }
+        }
+    }
+};
+
+// 0. Background
+//
+//    The Nucleo st-link programmer provides a Virtual Com Port (VCP).
+//    It is connected to the PA2(TX)/PA3(RX) pins of the stm32f401/411.
+//    On the host, the VCP is presented under `/dev/ttyACMx`, where
+//    `x` is an enumerated number (ff 0 is busy it will pick 1, etc.)
+//
+// 1. In this example we use RTT.
+//
+//    > cargo run --example rtic_bare8
+//
+//    Start a terminal program, e.g., `moserial`.
+//    Connect to the port
+//
+//    Device       /dev/ttyACM0
+//    Baude Rate   115200
+//    Data Bits    8
+//    Stop Bits    1
+//    Parity       None
+//
+//    This setting is typically abbreviated as 115200 8N1.
+//
+//    Send a single character (byte), (set the option `No end` in `moserial`).
+//    Verify that sent bytes are echoed back, and that RTT tracing is working.
+//
+//    Try sending "a", don't send the quotation marks, just a.
+//
+//    What do you receive in `moserial`?
+//
+//    ** your answer here **
+//
+//    What do you receive in the RTT terminal?
+//
+//    ** your answer here **
+//
+//    Try sending: "abcd" as a single sequence, don't send the quotation marks, just abcd.
+//
+//    What did you receive in `moserial`?
+//
+//    ** your answer here **
+//
+//    What do you receive in the RTT terminal?
+//
+//    ** your answer here **
+//
+//    What do you believe to be the problem?
+//
+//    Hint: Look at the code in `idle` what does it do?
+//
+//    ** your answer here **
+//
+//    Experiment a bit, what is the max length sequence you can receive without errors?
+//
+//    ** your answer here **
+//
+//    Commit your answers (bare8_1)
+//
+// 2. Add a local variable `received` that counts the number of bytes received.
+//    Add a local variable `errors` that counts the number of errors.
+//
+//    Adjust the RTT trace to print the added information inside the loop.
+//
+//    Compile/run reconnect, and verify that it works as intended.
+//
+//    Commit your development (bare8_2)
+//
+// 3. Experiment a bit, what is the max length sequence you can receive without errors?
+//
+//    ** your answer here **
+//
+//    How did the added tracing/instrumentation affect the behavior?
+//
+//    ** your answer here **
+//
+//    Commit your answer (bare8_3)
+//
+// 4. Now try compile and run the same experiment 3 but in --release mode.
+//
+//    > cargo run --example rtic_bare8 --release
+//
+//    Reconnect your `moserial` terminal.
+//
+//    Experiment a bit, what is the max length sequence you can receive without errors?
+//
+//    ** your answer here **
+//
+//    Commit your answer (bare8_4)
+//
+// 5. Discussion
+//
+//    (If you ever used Arduino, you might feel at home with the `loop` and poll design.)
+//
+//    Typically, this is what you can expect from a polling approach, if you
+//    are not very careful what you are doing. This exemplifies a bad design.
+//
+//    Loss of data might be Ok for some applications but this typically NOT what we want.
+//
+//    (With that said, Arduino gets away with some simple examples as their drivers do
+//    internal magic - buffering data etc.)
diff --git a/examples/rtic_bare9.rs b/examples/rtic_bare9.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a1fc61c6b3a97855fc50f1fb85419a0bfe7c27ce
--- /dev/null
+++ b/examples/rtic_bare9.rs
@@ -0,0 +1,222 @@
+//! bare8.rs
+//!
+//! Serial
+//!
+//! What it covers:
+
+#![no_main]
+#![no_std]
+
+use panic_rtt_target as _;
+
+use stm32f4xx_hal::{
+    prelude::*,
+    serial::{config::Config, Event, Rx, Serial, Tx},
+    stm32::USART2,
+};
+
+use rtic::app;
+use rtt_target::{rprintln, rtt_init_print};
+
+#[app(device = stm32f4xx_hal::stm32, peripherals = true)]
+const APP: () = {
+    struct Resources {
+        // Late resources
+        TX: Tx<USART2>,
+        RX: Rx<USART2>,
+    }
+
+    // init runs in an interrupt free section
+    #[init]
+    fn init(cx: init::Context) -> init::LateResources {
+        rtt_init_print!();
+        rprintln!("init");
+
+        let device = cx.device;
+
+        let rcc = device.RCC.constrain();
+
+        // 16 MHz (default, all clocks)
+        let clocks = rcc.cfgr.freeze();
+
+        let gpioa = device.GPIOA.split();
+
+        let tx = gpioa.pa2.into_alternate_af7();
+        let rx = gpioa.pa3.into_alternate_af7();
+
+        let mut serial = Serial::usart2(
+            device.USART2,
+            (tx, rx),
+            Config::default().baudrate(115_200.bps()),
+            clocks,
+        )
+        .unwrap();
+
+        // generate interrupt on Rxne
+        serial.listen(Event::Rxne);
+
+        // Separate out the sender and receiver of the serial port
+        let (tx, rx) = serial.split();
+
+        // Late resources
+        init::LateResources { TX: tx, RX: rx }
+    }
+
+    // idle may be interrupted by other interrupts/tasks in the system
+    #[idle()]
+    fn idle(_cx: idle::Context) -> ! {
+        loop {
+            continue;
+        }
+    }
+
+    // capacity sets the size of the input buffer (# outstanding messages)
+    #[task(resources = [TX], priority = 1, capacity = 128)]
+    fn rx(cx: rx::Context, data: u8) {
+        let tx = cx.resources.TX;
+        tx.write(data).unwrap();
+        rprintln!("data {}", data);
+    }
+
+    // Task bound to the USART2 interrupt.
+    #[task(binds = USART2,  priority = 2, resources = [RX], spawn = [rx])]
+    fn usart2(cx: usart2::Context) {
+        let rx = cx.resources.RX;
+        let data = rx.read().unwrap();
+        cx.spawn.rx(data).unwrap();
+    }
+
+    extern "C" {
+        fn EXTI0();
+    }
+};
+
+// 0. Background
+//
+//    As seen in the prior example, you may loose data unless polling frequently enough.
+//    Let's try an interrupt driven approach instead.
+//
+//    In init we just add:
+//
+//    // generate interrupt on Rxne
+//    serial.listen(Event::Rxne);
+//
+//    This causes the USART hardware to generate an interrupt when data is available.
+//
+//    // Task bound to the USART2 interrupt.
+//    #[task(binds = USART2,  priority = 2, resources = [RX], spawn = [rx])]
+//    fn usart2(cx: usart2::Context) {
+//      let rx = cx.resources.RX;
+//      let data = rx.read().unwrap();
+//      cx.spawn.rx(data).unwrap();
+//    }
+//
+//    The `usart2` task will be triggered, and we read one byte from the internal
+//    buffer in the USART2 hardware. (panic if something goes bad)
+//
+//    We send the read byte to the `rx` task (by `cx.spawn.rx(data).unwrap();`)
+//    (We panic if the capacity of the message queue is reached)
+//
+//    // capacity sets the size of the input buffer (# outstanding messages)
+//    #[task(resources = [TX], priority = 1, capacity = 128)]
+//    fn rx(cx: rx::Context, data: u8) {
+//        let tx = cx.resources.TX;
+//        tx.write(data).unwrap();
+//        rprintln!("data {}", data);
+//    }
+//
+//    Here we echo the data back, `tx.write(data).unwrap();` (panic if usart is busy)
+//    We then trace the received data `rprintln!("data {}", data);`
+//
+//    The `priority = 2` gives the `usart2` task the highest priority
+//    (to ensure that we don't miss data).
+//
+//    The `priority = 1` gives the `rx` task a lower priority.
+//    Here we can take our time and process the data.
+//
+//    `idle` runs at priority 0, lowest priority in the system.
+//    Here we can do some background job, when nothing urgent is happening.
+//
+//    This is an example of a good design!
+//
+// 1. In this example we use RTT.
+//
+//    > cargo run --example rtic_bare9
+//
+//    Try breaking it!!!!
+//    Throw any data at it, and see if you could make it panic!
+//
+//    Were you able to crash it?
+//
+//    ** your answer here **
+//
+//    Notice, the input tracing in `moserial` seems broken, and may loose data.
+//    So don't be alarmed if data is missing, its a GUI tool after all.
+//
+//    If you want to sniff the `ttyACM0`, install e.g., `interceptty` and run
+//    > interceptty /dev/ttyACM0
+//
+//    In another terminal, you can do:
+//    > cat examples/rtic_bare9.rs > /dev/ttyACM0
+//
+//    Incoming data will be intercepted/displayed by `interceptty`.
+//    (In the RTT trace you will see that data is indeed arriving to the target.)
+//
+//    Commit your answer (bare9_1)
+//
+// 2. Now, re-implement the received and error counters from previous exercise.
+//
+//    Good design:
+//    - Defer any tracing to lower priority task/tasks
+//      (you may introduce an error task at low priority).
+//
+//    - State variables can be introduced either locally (static mut), or
+//      by using a resource.
+//
+//      If a resource is shared among tasks of different priorities:
+//      The highest priority task will have direct access to the data,
+//      the lower priority task(s) will need to lock the resource first.
+//
+//    Check the RTIC book, https://rtic.rs/0.5/book/en/by-example
+//    regarding resources, software tasks, error handling etc.
+//
+//    Test that your implementation works and traces number of
+//    bytes received and errors encountered.
+//
+//    If implemented correctly, it should be very hard (or impossible)
+//    to get an error.
+//
+//    You can force an error by doing some "stupid delay" (faking workload),
+//    e.g., burning clock cycles using `cortex_m::asm::delay` in the
+//    `rx` task. Still you need to saturate the capacity (128 bytes).
+//
+//    To make errors easier to produce, reduce the capacity.
+//
+//    Once finished, comment your code.
+//
+//    Commit your code (bare9_2)
+//
+// 3. Discussion
+//
+//    Here you have used RTIC to implement a highly efficient and good design.
+//
+//    Tasks in RTIC are run-to-end, with non-blocking access to resources.
+//    (Even `lock` is non-blocking, isn't that sweet?)
+//
+//    Tasks in RTIC are scheduled according to priorities.
+//    (A higher priority task `H` always preempts lower priority task `L` running,
+//    unless `L` holds a resource with higher or equal ceiling as `H`.)
+//
+//    Tasks in RTIC can spawn other tasks.
+//    (`capacity` sets the message queue size.)
+//
+//    By design RTIC guarantees race- and deadlock-free execution.
+//
+//    It also comes with theoretical underpinning for static analysis.
+//    - task response time
+//    - overall schedulability
+//    - stack memory analysis
+//    - etc.
+//
+//    RTIC leverages on the zero-cost abstractions in Rust,
+//    and the implementation offers best in class performance.
diff --git a/src/pmw3389.rs b/src/pmw3389.rs
index fd9e8112a79164f0d0d67758899055363fad28b6..a978c32dfeece778559228503d94d6cf1242b5cf 100644
--- a/src/pmw3389.rs
+++ b/src/pmw3389.rs
@@ -166,38 +166,6 @@ where
         let srom_id = pmw3389.read_register(Register::SROMId)?;
         rprintln!("srom_id {}, 0x{:x}", srom_id, srom_id);
 
-        // loop {
-        //     pmw3389.write_register(Register::Motion, 0x01)?;
-
-        //     let motion = pmw3389.read_register(Register::Motion)?;
-        //     let xl = pmw3389.read_register(Register::DeltaXL)?;
-        //     let xh = pmw3389.read_register(Register::DeltaXH)?;
-        //     let yl = pmw3389.read_register(Register::DeltaYL)?;
-        //     let yh = pmw3389.read_register(Register::DeltaYH)?;
-
-        //     let x = (xl as u16 + (xh as u16) << 8) as i16;
-        //     let y = (yl as u16 + (yh as u16) << 8) as i16;
-
-        //     let surface = motion & 0x08;
-        //     let motion_detect = motion & 0x80;
-
-        //     rprintln!(
-        //         "motion {}, surface {}, (x, y) {:?}",
-        //         motion_detect,
-        //         surface,
-        //         (x, y),
-        //     );
-        //     pmw3389.delay.delay_ms(200);
-        // }
-
-        // self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
-        // self.delay.delay_ms(35); // waits for tSRAD
-
-        // loop {
-        //     pmw3389.read_status(itm)?;
-        //     pmw3389.delay.delay_ms(10);
-        // }
-
         Ok(pmw3389)
     }
 
@@ -208,8 +176,7 @@ where
         self.spi.transfer(&mut buffer)?;
 
         // tSRAD
-        self.delay.delay_us(100);
-        self.delay.delay_us(120);
+        self.delay.delay_us(35);
 
         let mut buffer = [0];
         self.spi.transfer(&mut buffer)?;
@@ -221,7 +188,6 @@ where
 
         // tSRW/tSRR (=20us) minus tSCLK-NCS
         self.delay.delay_us(19);
-        self.delay.delay_us(120);
 
         Ok(buffer[0])
     }
@@ -254,13 +220,10 @@ where
     }
 
     /// Read status
-    pub fn read_status(&mut self) -> Result<(), E> {
+    pub fn read_status(&mut self) -> Result<((i16, i16)), E> {
         self.com_begin();
 
-        // self.write_register(Register::Motion, 0x01)?;
-
         self.spi.transfer(&mut [Register::MotionBurst.addr()])?;
-        // self.write_register(Register::MotionBurst, 0x00);
 
         self.delay.delay_us(35); // waits for tSRAD
 
@@ -269,16 +232,10 @@ where
         self.spi.transfer(&mut buf)?;
 
         // tSCLK-NCS for read operation is 120ns
-        self.delay.delay_us(120);
+        // self.delay.delay_us(120);
 
         self.com_end();
 
-        rprint!("burst [");
-        for j in buf.iter() {
-            rprint!("0x{:02x}, ", j);
-        }
-        rprintln!("]");
-
         //     SPI.endTransaction(); // Per:Not sure what it does
         //     /*
         //     BYTE[00] = Motion    = if the 7th bit is 1, a motion is detected.
@@ -299,24 +256,16 @@ where
         //     BYTE[11] = Shutter_Lower     = Shutter MSB, Shutter = shutter is adjusted to keep the average raw data values within normal operating ranges
         //     */
         //     int motion = (burstBuffer[0] & 0x80) > 0;
-        let motion = buf[0] & 0x80;
-        let surface = buf[0] & 0x08;
+        let _motion = buf[0] & 0x80;
+        let _surface = buf[0] & 0x08;
         // 0 if on surface / 1 if off surface
 
-        let x = buf[2] as u16 + (buf[3] as u16) << 8;
-        let y = buf[4] as u16 + (buf[5] as u16) << 8;
-
-        let squal = buf[6];
+        let x: i16 = (((buf[3] as u16) << 8) | buf[2] as u16) as i16;
+        let y: i16 = (((buf[5] as u16) << 8) | buf[4] as u16) as i16;
 
-        rprintln!(
-            "motion {}, surface {}, (x, y) {:?}, squal {}",
-            motion,
-            surface,
-            (x, y),
-            squal
-        );
+        let _squal = buf[6];
 
-        Ok(())
+        Ok((x, y))
     }
 
     // Upload the firmware
@@ -369,9 +318,8 @@ where
 
         for i in Self::FIRMWARE.iter() {
             let mut buff = [*i];
-            // iprintln!(stim, "0x{:x}", buff[0]);
             self.spi.transfer(&mut buff)?;
-            self.delay.delay_us(15); // 15
+            self.delay.delay_us(15); // 15us delay between transfers
         }
 
         // // Per: added this, seems adequate
@@ -387,18 +335,17 @@ where
 
         // //Write 0x00 to Config2 register for wired mouse or 0x20 for wireless mouse design.
         // // adns_write_reg(Config2, 0x00);
-        self.write_register(Register::Config2, 0x20)?;
+        self.write_register(Register::Config2, 0x00)?;
 
         // // set initial CPI resolution
         // // adns_write_reg(Config1, 0x15);
 
-        //            self.write_register(Register::ResolutionL, 0x15)?;
-        self.write_register(Register::ResolutionL, 0x5)?;
-        // self.write_register(Register::ResolutionH, 0x15)?;
-        self.write_register(Register::ResolutionH, 0x00)?;
+        let cpi: u16 = 16000;
+        self.write_register(Register::ResolutionL, cpi as u8)?;
+        self.write_register(Register::ResolutionH, (cpi >> 8) as u8)?;
 
         // adns_com_end(); // why the CS is already high
-        self.com_end();
+        // self.com_end();
         Ok(())
     }