diff --git a/code/Cargo.lock b/code/Cargo.lock
index c3316ff5cbfc94e452634d6bb43ced38de8148ed..2c823d4a690a81dd38aa88f67a5852abd3ede048 100644
--- a/code/Cargo.lock
+++ b/code/Cargo.lock
@@ -18,7 +18,10 @@ dependencies = [
  "cortex-m-rtic",
  "cortex-m-semihosting",
  "embedded-hal",
+ "panic-halt",
+ "panic-itm",
  "panic-rtt-target",
+ "panic-semihosting",
  "rtt-target 0.3.0",
  "stm32f4 0.13.0",
  "stm32f4xx-hal",
@@ -251,6 +254,21 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae"
 
+[[package]]
+name = "panic-halt"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
+
+[[package]]
+name = "panic-itm"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d577d97d1b31268087b6dddf2470e6794ef5eee87d9dca7fcd0481695391a4c"
+dependencies = [
+ "cortex-m 0.7.2",
+]
+
 [[package]]
 name = "panic-rtt-target"
 version = "0.1.1"
@@ -261,6 +279,16 @@ dependencies = [
  "rtt-target 0.2.2",
 ]
 
+[[package]]
+name = "panic-semihosting"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3d55dedd501dfd02514646e0af4d7016ce36bc12ae177ef52056989966a1eec"
+dependencies = [
+ "cortex-m 0.7.2",
+ "cortex-m-semihosting",
+]
+
 [[package]]
 name = "proc-macro2"
 version = "1.0.24"
diff --git a/code/Cargo.toml b/code/Cargo.toml
index af9967acdf8dd4f70aefcd40a79cdde7e17d8e02..a6326e76914c31ddb9aeb4e7bd3ffb79726ba5fa 100644
--- a/code/Cargo.toml
+++ b/code/Cargo.toml
@@ -15,16 +15,16 @@ usb-device = "0.2.7"
 usbd-hid = "0.5.0"
 
 # Panic handlers, comment all but one to generate doc!
-#panic-halt = "0.2.0"
+panic-halt = "0.2.0"
 
 # Uncomment for the itm panic examples.
-#panic-itm = "0.4.2"
+panic-itm = "0.4.2"
 
 # Uncomment for the rtt-timing examples.
 panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] }
 
 # Uncomment for the semihosting examples.
-#panic-semihosting = "0.5.6"
+panic-semihosting = "0.5.6"
 
 # Tracing
 rtt-target = { version = "0.3.0", features = ["cortex-m"] }
diff --git a/code/examples/din_mama.rs b/code/examples/din_mama.rs
new file mode 100644
index 0000000000000000000000000000000000000000..935d009cb314287ca231b5240a1faa3bdbb3c910
--- /dev/null
+++ b/code/examples/din_mama.rs
@@ -0,0 +1,413 @@
+// cargo run --example rtt_rtic_usb_mouse --release
+//
+// Notice, release build required
+
+#![no_std]
+#![no_main]
+
+use core::{convert::TryInto, i8};
+
+use panic_halt as _;
+
+use cortex_m::{asm::delay, peripheral::DWT};
+use embedded_hal::digital::v2::OutputPin;
+use embedded_hal::spi::MODE_3;
+use rtic::cyccnt::{Instant, U32Ext as _};
+use stm32f4xx_hal::{
+    dwt::Dwt,
+    gpio::{
+        Speed, Alternate, Input, Output, PullUp, PushPull,
+        gpioa::{PA15},
+        gpiob::{self,PB12, PB13, PB14, PB15},
+        gpioc::{self,PC6, PC7, PC10, PC11, PC12},
+    },
+    prelude::*,
+    rcc::Clocks,
+    spi::Spi,
+    stm32,
+    otg_fs::{UsbBus, UsbBusType, USB},
+    prelude::*,
+};
+use usb_device::bus;
+use usb_device::prelude::*;
+
+#[allow(unused)]
+pub mod hid {
+    use usb_device::class_prelude::*;
+    use usb_device::Result;
+
+    pub const USB_CLASS_HID: u8 = 0x03;
+
+    const USB_SUBCLASS_NONE: u8 = 0x00;
+    const USB_SUBCLASS_BOOT: u8 = 0x01;
+
+    const USB_INTERFACE_NONE: u8 = 0x00;
+    const USB_INTERFACE_KEYBOARD: u8 = 0x01;
+    const USB_INTERFACE_MOUSE: u8 = 0x02;
+
+    const REQ_GET_REPORT: u8 = 0x01;
+    const REQ_GET_IDLE: u8 = 0x02;
+    const REQ_GET_PROTOCOL: u8 = 0x03;
+    const REQ_SET_REPORT: u8 = 0x09;
+    const REQ_SET_IDLE: u8 = 0x0a;
+    const REQ_SET_PROTOCOL: u8 = 0x0b;
+
+    // https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/mouse-collection-report-descriptor
+    const REPORT_DESCR: &[u8] = &[
+        0x05, 0x01, // USAGE_PAGE (Generic Desktop)
+        0x09, 0x02, // USAGE (Mouse)
+        0xa1, 0x01, // COLLECTION (Application)
+        0x09, 0x01, //   USAGE (Pointer)
+        0xa1, 0x00, //   COLLECTION (Physical)
+        0x05, 0x09, //     USAGE_PAGE (Button)
+        0x19, 0x01, //     USAGE_MINIMUM (Button 1)
+        0x29, 0x03, //     USAGE_MAXIMUM (Button 3)
+        0x15, 0x00, //     LOGICAL_MINIMUM (0)
+        0x25, 0x01, //     LOGICAL_MAXIMUM (1)
+        0x95, 0x03, //     REPORT_COUNT (3)
+        0x75, 0x01, //     REPORT_SIZE (1)
+        0x81, 0x02, //     INPUT (Data,Var,Abs)
+        0x95, 0x01, //     REPORT_COUNT (1)
+        0x75, 0x05, //     REPORT_SIZE (5)
+        0x81, 0x03, //     INPUT (Cnst,Var,Abs)
+        0x05, 0x01, //     USAGE_PAGE (Generic Desktop)
+        0x09, 0x30, //     USAGE (X)
+        0x09, 0x31, //     USAGE (Y)
+        0x15, 0x81, //     LOGICAL_MINIMUM (-127)
+        0x25, 0x7f, //     LOGICAL_MAXIMUM (127)
+        0x75, 0x08, //     REPORT_SIZE (8)
+        0x95, 0x02, //     REPORT_COUNT (2)
+        0x81, 0x06, //     INPUT (Data,Var,Rel)
+        0xc0, //   END_COLLECTION
+        0xc0, // END_COLLECTION
+    ];
+
+    pub fn report(x: i8, y: i8) -> [u8; 3] {
+        [
+            0x00,    // button: none
+            x as u8, // x-axis
+            y as u8, // y-axis
+        ]
+    }
+
+    pub struct HIDClass<'a, B: UsbBus> {
+        report_if: InterfaceNumber,
+        report_ep: EndpointIn<'a, B>,
+    }
+
+    impl<B: UsbBus> HIDClass<'_, B> {
+        /// Creates a new HIDClass with the provided UsbBus and max_packet_size in bytes. For
+        /// full-speed devices, max_packet_size has to be one of 8, 16, 32 or 64.
+        pub fn new(alloc: &UsbBusAllocator<B>) -> HIDClass<'_, B> {
+            HIDClass {
+                report_if: alloc.interface(),
+                report_ep: alloc.interrupt(8, 10),
+            }
+        }
+
+        pub fn write(&mut self, data: &[u8]) {
+            self.report_ep.write(data).ok();
+        }
+    }
+
+    impl<B: UsbBus> UsbClass<B> for HIDClass<'_, B> {
+        fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> {
+            writer.interface(
+                self.report_if,
+                USB_CLASS_HID,
+                USB_SUBCLASS_NONE,
+                USB_INTERFACE_MOUSE,
+            )?;
+
+            let descr_len: u16 = REPORT_DESCR.len() as u16;
+            writer.write(
+                0x21,
+                &[
+                    0x01,                   // bcdHID
+                    0x01,                   // bcdHID
+                    0x00,                   // bCountryCode
+                    0x01,                   // bNumDescriptors
+                    0x22,                   // bDescriptorType
+                    descr_len as u8,        // wDescriptorLength
+                    (descr_len >> 8) as u8, // wDescriptorLength
+                ],
+            )?;
+
+            writer.endpoint(&self.report_ep)?;
+
+            Ok(())
+        }
+
+        fn control_in(&mut self, xfer: ControlIn<B>) {
+            let req = xfer.request();
+
+            if req.request_type == control::RequestType::Standard {
+                match (req.recipient, req.request) {
+                    (control::Recipient::Interface, control::Request::GET_DESCRIPTOR) => {
+                        let (dtype, _index) = req.descriptor_type_index();
+                        if dtype == 0x21 {
+                            // HID descriptor
+                            cortex_m::asm::bkpt();
+                            let descr_len: u16 = REPORT_DESCR.len() as u16;
+
+                            // HID descriptor
+                            let descr = &[
+                                0x09,                   // length
+                                0x21,                   // descriptor type
+                                0x01,                   // bcdHID
+                                0x01,                   // bcdHID
+                                0x00,                   // bCountryCode
+                                0x01,                   // bNumDescriptors
+                                0x22,                   // bDescriptorType
+                                descr_len as u8,        // wDescriptorLength
+                                (descr_len >> 8) as u8, // wDescriptorLength
+                            ];
+
+                            xfer.accept_with(descr).ok();
+                            return;
+                        } else if dtype == 0x22 {
+                            // Report descriptor
+                            xfer.accept_with(REPORT_DESCR).ok();
+                            return;
+                        }
+                    }
+                    _ => {
+                        return;
+                    }
+                };
+            }
+
+            if !(req.request_type == control::RequestType::Class
+                && req.recipient == control::Recipient::Interface
+                && req.index == u8::from(self.report_if) as u16)
+            {
+                return;
+            }
+
+            match req.request {
+                REQ_GET_REPORT => {
+                    // USB host requests for report
+                    // I'm not sure what should we do here, so just send empty report
+                    xfer.accept_with(&report(0, 0)).ok();
+                }
+                _ => {
+                    xfer.reject().ok();
+                }
+            }
+        }
+
+        fn control_out(&mut self, xfer: ControlOut<B>) {
+            let req = xfer.request();
+
+            if !(req.request_type == control::RequestType::Class
+                && req.recipient == control::Recipient::Interface
+                && req.index == u8::from(self.report_if) as u16)
+            {
+                return;
+            }
+
+            xfer.reject().ok();
+        }
+    }
+}
+
+use hid::HIDClass;
+
+// PMW3389
+use app::{
+    pmw3389::{self, Register},
+    DwtDelay,
+};
+use rtt_target::{rprint, rprintln, rtt_init_print};
+
+type PMW3389T = pmw3389::Pmw3389<
+    Spi<
+        stm32f4xx_hal::stm32::SPI3,
+        (
+            PC10<Alternate<stm32f4xx_hal::gpio::AF6>>,
+            PC11<Alternate<stm32f4xx_hal::gpio::AF6>>,
+            PC12<Alternate<stm32f4xx_hal::gpio::AF6>>,
+        ),
+    >,
+    PA15<Output<PushPull>>,
+>;
+
+const PERIOD: u32 = 10000;
+const RATIO: u32 = 1;
+
+#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)]
+const APP: () = {
+    struct Resources {
+        //counter: u8,
+        usb_dev: UsbDevice<'static, UsbBusType>,
+        hid: HIDClass<'static, UsbBusType>,
+        pmw3389: PMW3389T,
+        MB2: gpioc::PC6<Input<PullUp>>,
+        MB1: gpioc::PC7<Input<PullUp>>,
+        DPIB1: gpiob::PB13<Input<PullUp>>,
+        DPIB2: gpiob::PB12<Input<PullUp>>,
+        MB5: gpiob::PB15<Input<PullUp>>,
+        MB4: gpiob::PB14<Input<PullUp>>,
+    }
+
+    #[init(schedule = [poll])]
+    fn init(mut cx: init::Context) -> init::LateResources {
+        static mut USB_BUS: Option<bus::UsbBusAllocator<UsbBusType>> = None;
+        static mut EP_MEMORY: [u32; 1024] = [0; 1024];
+        cx.core.DCB.enable_trace();
+        DWT::unlock();
+        cx.core.DWT.enable_cycle_counter();
+
+        let mut core = cx.core;
+
+        let rcc = cx.device.RCC.constrain();
+
+        let clocks = rcc
+            .cfgr
+            // .use_hse(8.mhz())
+            .sysclk(48.mhz())
+            .pclk1(24.mhz())
+            .freeze();
+
+        // assert!(clocks.usbclk_valid());
+
+        let gpioa = cx.device.GPIOA.split();
+        let gpioc = cx.device.GPIOC.split();
+        let gpiob = cx.device.GPIOB.split();
+
+        // Buttons
+        let mb2 = gpioc.pc6.into_pull_up_input();
+        let mb1 = gpioc.pc7.into_pull_up_input();
+        let mb5 = gpiob.pb15.into_pull_up_input();
+        let mb4 = gpiob.pb14.into_pull_up_input();
+        let dpib1 = gpiob.pb13.into_pull_up_input();
+        let dpib2 = gpiob.pb12.into_pull_up_input();
+
+        // Sensor communcation
+        let sck = gpioc.pc10.into_alternate_af6();
+        let miso = gpioc.pc11.into_alternate_af6();
+        let mosi = gpioc.pc12.into_alternate_af6();
+        let cs = gpioa.pa15.into_push_pull_output().set_speed(Speed::High);
+
+        let spi = Spi::spi3(
+            cx.device.SPI3,
+            (sck, miso, mosi),
+            MODE_3,
+            stm32f4xx_hal::time::KiloHertz(2000).into(),
+            clocks,
+        );
+
+
+        let mut delay_dwt = DwtDelay::new(&mut core.DWT, clocks);
+        let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay_dwt).unwrap();
+
+        // set in burst mode
+        pmw3389.write_register(Register::MotionBurst, 0x00);
+
+        // Pull the D+ pin down to send a RESET condition to the USB bus.
+        let mut usb_dp = gpioa.pa12.into_push_pull_output();
+        usb_dp.set_low().ok();
+        delay(clocks.sysclk().0 / 100);
+        let usb_dp = usb_dp.into_floating_input();
+
+        let usb_dm = gpioa.pa11;
+
+        let usb = USB {
+            usb_global: cx.device.OTG_FS_GLOBAL,
+            usb_device: cx.device.OTG_FS_DEVICE,
+            usb_pwrclk: cx.device.OTG_FS_PWRCLK,
+            pin_dm: usb_dm.into_alternate_af10(),
+            pin_dp: usb_dp.into_alternate_af10(),
+        };
+
+        *USB_BUS = Some(UsbBus::new(usb, EP_MEMORY));
+
+        let hid = HIDClass::new(USB_BUS.as_ref().unwrap());
+
+        let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0xc410, 0x0000))
+            .manufacturer("Albatraoz")
+            .product("VRM")
+            .serial_number("TEST")
+            .device_class(0)
+            .build();
+
+        cx.schedule.poll(cx.start + 16_000.cycles()).unwrap();
+
+        init::LateResources {
+            //counter: 0,
+            usb_dev,
+            hid,
+            MB1:mb1, MB2:mb2, MB4:mb4, MB5:mb5, DPIB1:dpib1, DPIB2:dpib2,
+            pmw3389,
+
+        }
+    }
+
+    #[idle]
+    fn idle(_cx: idle::Context) -> ! {
+        // rprintln!("idle");
+        loop {
+            continue;
+        }
+    }
+
+    #[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;
+        static mut POS_Y: i64 = 0;
+
+        *COUNTER += 1;
+        if *COUNTER == 1000 / RATIO {
+            cx.spawn.trace(*POS_X, *POS_Y).unwrap();
+            *COUNTER = 0;
+        }
+
+        let (x, y) = cx.resources.pmw3389.read_status().unwrap();
+        *POS_X += x as i64;
+        *POS_Y += y as i64;
+
+        // task should run each second N ms (16_000 cycles at 16MHz)
+        cx.schedule
+            .poll(cx.scheduled + (RATIO * 16_000).cycles())
+            .unwrap();
+    }
+
+    #[task(priority = 1, resources = [hid])]
+    fn trace(mut cx: trace::Context, x: i64, y:i64) {
+        static mut OLD_POS_X: i64 = 0;
+        static mut OLD_POS_Y: i64 = 0;
+        let hid = &mut cx.resources.hid;
+        hid.write(&hid::report(
+            (x - *OLD_POS_X) as i8,
+            (y - *OLD_POS_Y) as i8  
+        ));
+        *OLD_POS_X = x;
+        *OLD_POS_Y = y;
+    }
+    
+
+    #[task(binds=OTG_FS, resources = [usb_dev, hid])]
+    fn usb_fs(mut cx: usb_fs::Context) {
+        usb_poll(
+            //&mut cx.resources.counter,
+            &mut cx.resources.usb_dev,
+            &mut cx.resources.hid,
+        );
+    }
+
+    extern "C" {
+        fn EXTI0();
+        fn EXTI1();
+    }
+};
+
+fn usb_poll<B: bus::UsbBus>(
+    //_counter: &mut u8,
+    usb_dev: &mut UsbDevice<'static, B>,
+    hid: &mut HIDClass<'static, B>,
+) {
+    if !usb_dev.poll(&mut [hid]) {
+        return;
+    }
+}
diff --git a/code/examples/rtt_rtic_usb_mouse.rs b/code/examples/rtt_rtic_usb_mouse.rs
index 7d425ae907f94310e7276026d1985a753074dca0..2cc82b6af72d473fec8f53d75248f7b68dd93547 100644
--- a/code/examples/rtt_rtic_usb_mouse.rs
+++ b/code/examples/rtt_rtic_usb_mouse.rs
@@ -57,32 +57,36 @@ pub mod hid {
 
     // https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/mouse-collection-report-descriptor
     const REPORT_DESCR: &[u8] = &[
-        0x05, 0x01, // USAGE_PAGE (Generic Desktop)
-        0x09, 0x02, // USAGE (Mouse)
-        0xa1, 0x01, // COLLECTION (Application)
-        0x09, 0x01, //   USAGE (Pointer)
-        0xa1, 0x00, //   COLLECTION (Physical)
-        0x05, 0x09, //     USAGE_PAGE (Button)
-        0x19, 0x01, //     USAGE_MINIMUM (Button 1)
-        0x29, 0x03, //     USAGE_MAXIMUM (Button 3)
-        0x15, 0x00, //     LOGICAL_MINIMUM (0)
-        0x25, 0x01, //     LOGICAL_MAXIMUM (1)
-        0x95, 0x03, //     REPORT_COUNT (3)
-        0x75, 0x01, //     REPORT_SIZE (1)
-        0x81, 0x02, //     INPUT (Data,Var,Abs)
-        0x95, 0x01, //     REPORT_COUNT (1)
-        0x75, 0x05, //     REPORT_SIZE (5)
-        0x81, 0x03, //     INPUT (Cnst,Var,Abs)
-        0x05, 0x01, //     USAGE_PAGE (Generic Desktop)
-        0x09, 0x30, //     USAGE (X)
-        0x09, 0x31, //     USAGE (Y)
-        0x15, 0x81, //     LOGICAL_MINIMUM (-127)
-        0x25, 0x7f, //     LOGICAL_MAXIMUM (127)
-        0x75, 0x08, //     REPORT_SIZE (8)
-        0x95, 0x02, //     REPORT_COUNT (2)
-        0x81, 0x06, //     INPUT (Data,Var,Rel)
-        0xc0, //   END_COLLECTION
-        0xc0, // END_COLLECTION
+        0x05, 0x01,     // USAGE_PAGE Generic Desktop
+        0x09, 0x02,     // USAGE Mouse
+        0xa1, 0x01,     // COLLECTION Application
+            0x09, 0x01,     // USAGE Pointer
+            0xa1, 0x00,     // COLLECTION Physical
+
+                0x05, 0x09, //     USAGE_PAGE (Button)
+                0x19, 0x01, //     USAGE_MINIMUM (Button 1)
+                0x29, 0x05, //     USAGE_MAXIMUM (Button 5)
+                0x15, 0x00, //     LOGICAL_MINIMUM (0)
+                0x25, 0x01, //     LOGICAL_MAXIMUM (1)
+                0x95, 0x05, //     REPORT_COUNT (5)
+                0x75, 0x01, //     REPORT_SIZE (1)
+                0x81, 0x02, //     INPUT (Data,Var,Abs)
+                0x95, 0x01, //     REPORT_COUNT (1)
+                0x75, 0x03, //     REPORT_SIZE (3)
+                0x81, 0x03, //     INPUT (Cnst,Var,Abs)
+
+                0x05, 0x01,     // USAGE_PAGE Generic Desktop
+                0x09, 0x30,     // USAGE X
+                0x09, 0x31,     // USAGE Y
+                0x09, 0x38,     // USAGE Wheel
+                0x15, 0x81,     // LOGICAL_MINIMUM -127
+                0x25, 0x7f,     // LOGICAL_MAXIMUM 127
+                0x75, 0x08,     // REPORT_SIZE 8
+                0x95, 0x03,     // REPORT_COUNT 3
+                0x81, 0x06,     // INPUT Data,Var,Rel
+
+            0xc0,           // END COLLECTION
+        0xc0,           // END COLLECTION
     ];
 
     pub fn report(b: u8,x: i8, y: i8) -> [u8; 3] {
@@ -306,9 +310,11 @@ const APP: () = {
 
 
         // set in burst mode
-        pmw3389.write_register(Register::MotionBurst, 0x00);
+        pmw3389.write_register(Register::MotionBurst, 0x00).unwrap();
 
-        // Pull the D+ pin down to send a RESET condition to the USB bus.
+        pmw3389.write_register(Register::ResolutionH, 0 as u8).unwrap();
+
+        // Pull the D+ pin down to send a RESET chttps://www.usbmadesimple.co.uk/ums_5.htmondition to the USB bus.
         let mut usb_dp = gpioa.pa12.into_push_pull_output();
         usb_dp.set_low().ok();
         delay(clocks.sysclk().0 / 100);
@@ -358,7 +364,7 @@ const APP: () = {
     }
 
     #[task(resources = [pmw3389, POS_X, POS_Y], schedule = [poll])]
-    fn poll(mut cx: poll::Context) {
+    fn poll(cx: poll::Context) {
         let pos_x = cx.resources.POS_X;
         let pos_y = cx.resources.POS_Y;
 
@@ -372,14 +378,19 @@ const APP: () = {
             .unwrap();
     }
 
-    #[task(resources = [hid, POS_X, POS_Y, OLD_POS_X, OLD_POS_Y, MB1, MB2], schedule = [tick])]
+    #[task(resources = [hid, POS_X, POS_Y, OLD_POS_X, OLD_POS_Y, MB1, MB2, MB4, MB5], schedule = [tick])]
     fn tick(mut cx: tick::Context) {
         cx.schedule.tick(cx.scheduled + (84_000).cycles()).unwrap();
-        let res = cx.resources;
         let pos_x = cx.resources.POS_X;
         let pos_y = cx.resources.POS_Y;
         let old_pos_x = cx.resources.OLD_POS_X;
         let old_pos_y = cx.resources.OLD_POS_Y;
+
+        let mb1 = cx.resources.MB1;
+        let mb2 = cx.resources.MB2;
+
+        let mb4 = cx.resources.MB4;
+        let mb5 = cx.resources.MB5;
         
         let hid = &mut cx.resources.hid;
         
@@ -390,12 +401,14 @@ const APP: () = {
         let report = MouseReport {
             x: diff_x as i8,
             y: diff_y as i8,
-            buttons: res.MB1.is_low().unwrap().into(), // (into takes a bool into an integer)
+            buttons: (
+                (mb5.is_low().unwrap() as u8) << 4
+                | (mb4.is_low().unwrap() as u8) << 3
+                | (mb2.is_low().unwrap() as u8) << 1 
+                | (mb1.is_low().unwrap() as u8)), // (into takes a bool into an integer)
             wheel: 0,
         };
 
-        rprintln!("Report: x:{}, y:{}", *pos_x, *pos_y);
-
         // push the report
         hid.push_input(&report).ok();
 
diff --git a/code/src/main.rs b/code/src/main.rs
index e75c8637851bb721629ef5f975a0edd29367d5ba..9a9c6237548677b17b2e46c1695ddbcf22dee917 100644
--- a/code/src/main.rs
+++ b/code/src/main.rs
@@ -1,12 +1,13 @@
-// > cargo run usb-mouse
+// > cargo run
 // or
-// > cargo run usb-mouse --release
+// > cargo run --release
 
 #![no_main]
 #![no_std]
 
 
 use cortex_m::{asm::delay, peripheral::DWT};
+use cortex_m_semihosting::hprintln;
 use embedded_hal::digital::v2::OutputPin;
 use embedded_hal::spi::MODE_3;
 use rtic::cyccnt::{Instant, U32Ext as _};
@@ -32,10 +33,39 @@ use usbd_hid::{
 };
 
 use panic_rtt_target as _;
-use rtt_target::{rprintln, rtt_init_print};
+use rtt_target::{rprint, rprintln, rtt_init_print};
 
 // PMW3389
 use app::{DwtDelay, pmw3389::{self, Register}, pmw3389e};
+use usbd_hid::descriptor::SerializedDescriptor;
+use usbd_hid::descriptor::AsInputReport;
+use usbd_hid::descriptor::gen_hid_descriptor;
+#[gen_hid_descriptor(
+    (collection = APPLICATION, usage_page = GENERIC_DESKTOP, usage = MOUSE) = {
+        (collection = PHYSICAL, usage = POINTER) = {
+            (usage_page = BUTTON, usage_min = 0x01, usage_max = 0x05) = {
+                #[packed_bits 5] #[item_settings data,variable,absolute] buttons=input;
+            };
+            (usage_page = GENERIC_DESKTOP,) = {
+                (usage = X,) = {
+                    #[item_settings data,variable,relative] x=input;
+                };
+                (usage = Y,) = {
+                    #[item_settings data,variable,relative] y=input;
+                };
+                (usage = WHEEL,) = {
+                    #[item_settings data,variable,relative] wheel=input;
+                };
+            };
+        };
+    }
+)]
+pub struct NuttaliReport {
+    pub buttons: u8,
+    pub x: i8,
+    pub y: i8,
+    pub wheel: i8, // Scroll down (negative) or up (positive) this many units
+}
 
 type PMW3389T = pmw3389::Pmw3389<
     Spi<
@@ -62,6 +92,8 @@ const APP: () = {
         OLD_POS_X: i64,
         OLD_POS_Y: i64,
 
+        DPI_SCALAR: i8,
+
         MB2: gpioc::PC6<Input<PullUp>>,
         MB1: gpioc::PC7<Input<PullUp>>,
         DPIB1: gpiob::PB13<Input<PullUp>>,
@@ -70,7 +102,7 @@ const APP: () = {
         MB4: gpiob::PB14<Input<PullUp>>,
     }
 
-    #[init(schedule = [poll])]
+    #[init(schedule = [poll, dpi_buttons])]
     fn init(mut cx: init::Context) -> init::LateResources {
         static mut EP_MEMORY: [u32; 1024] = [0; 1024];
         static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None;
@@ -126,9 +158,9 @@ const APP: () = {
         let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay_dwt).unwrap();
 
         // set in burst mode
-        pmw3389.write_register(Register::MotionBurst, 0x00);
+        pmw3389.write_register(Register::MotionBurst, 0x00).unwrap();
         //pmw3389.write_register(Register::ResolutionL, 255 as u8);
-        pmw3389.write_register(Register::ResolutionH, 0 as u8); // sets CPI 0 is lowest, don't know the number tho
+        pmw3389.write_register(Register::ResolutionH, 0 as u8).unwrap(); // sets CPI 0 is lowest, don't know the number tho
 
         let usb = USB {
             usb_global: device.OTG_FS_GLOBAL,
@@ -138,10 +170,11 @@ const APP: () = {
             pin_dp: gpioa.pa12.into_alternate_af10(),
         };
 
+        let mut scalar:i8 = 1;
 
         USB_BUS.replace(UsbBus::new(usb, EP_MEMORY));
 
-        let hid = HIDClass::new(USB_BUS.as_ref().unwrap(), MouseReport::desc(), 1);
+        let hid = HIDClass::new(USB_BUS.as_ref().unwrap(), NuttaliReport::desc(), 1);
         let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0xc410, 0x0000))
             .manufacturer("")
             .product("Vibora Rapido Muerta")
@@ -150,19 +183,20 @@ const APP: () = {
             .build();
         
         cx.schedule.poll(cx.start + (48_000).cycles()).ok();
+        cx.schedule.dpi_buttons(cx.start + (50_000).cycles()).ok();
 
         init::LateResources {
             usb_dev,
             hid,
             MB1:mb1, MB2:mb2, MB4:mb4, MB5:mb5, DPIB1:dpib1, DPIB2:dpib2,
             pmw3389,
-            POS_X: 0, POS_Y: 0, OLD_POS_X: 0, OLD_POS_Y: 0,
+            POS_X: 0, POS_Y: 0, OLD_POS_X: 0, OLD_POS_Y: 0, DPI_SCALAR: scalar,
 
         }
     }
 
     #[task(resources = [pmw3389, POS_X, POS_Y], schedule = [poll], priority = 2)]
-    fn poll(mut cx: poll::Context) {
+    fn poll(cx: poll::Context) {
         let pos_x = cx.resources.POS_X;
         let pos_y = cx.resources.POS_Y;
 
@@ -176,7 +210,41 @@ const APP: () = {
             .unwrap();
     }
 
-    #[task(binds=OTG_FS, resources = [hid, usb_dev, POS_X, POS_Y, OLD_POS_X, OLD_POS_Y, MB1, MB2], priority = 2)]
+    #[task(resources = [DPIB1, DPIB2, DPI_SCALAR], schedule = [dpi_buttons], priority = 2)]
+    fn dpi_buttons(cx: dpi_buttons::Context) {
+        static mut LEFT_CLICKED: bool = false;
+        static mut RIGHT_CLICKED: bool = false;
+
+        let dpib1 = cx.resources.DPIB1;
+        let dpib2 = cx.resources.DPIB2;
+        let scalar = cx.resources.DPI_SCALAR;
+
+        if dpib1.is_low().unwrap() && !*LEFT_CLICKED {
+            if *scalar < 5 {
+                *scalar += 1;
+            }
+            *LEFT_CLICKED = true;
+        }
+        else if !dpib1.is_low().unwrap() {
+            *LEFT_CLICKED = false;
+        }
+
+        if dpib2.is_low().unwrap() && !*RIGHT_CLICKED {
+            if *scalar > 1 {
+                *scalar -= 1;
+            }
+            *RIGHT_CLICKED = true;
+        }
+        else if !dpib2.is_low().unwrap() {
+            *RIGHT_CLICKED = false;
+        }
+
+        cx.schedule
+            .dpi_buttons(cx.scheduled + (100_000_0).cycles())
+            .unwrap();
+    }
+
+    #[task(binds=OTG_FS, resources = [hid, usb_dev, POS_X, POS_Y, OLD_POS_X, OLD_POS_Y, MB1, MB2, MB4, MB5, DPI_SCALAR], priority = 2)]
     fn on_usb(cx: on_usb::Context) {
         // destruct the context
         let (
@@ -184,28 +252,36 @@ const APP: () = {
                 hid,
                 mb1,
                 mb2,
+                mb4,
+                mb5,
                 pos_x,
                 pos_y,
+                scalar,
             ) = (
                 cx.resources.usb_dev, 
                 cx.resources.hid, 
                 cx.resources.MB1, 
                 cx.resources.MB2,
+                cx.resources.MB4,
+                cx.resources.MB5,
                 cx.resources.POS_X,
                 cx.resources.POS_Y,
+                cx.resources.DPI_SCALAR,
             );
 
+        
 
-        let report = MouseReport {
-            x: *pos_x,
-            y: *pos_y,
-            buttons: ((
-                        mb2.is_low().unwrap() as u8) << 1 
-                        | mb1.is_low().unwrap() as u8), // buttons = 1 byte. MB1 = bit 1, MB2 = bit 2, etc etc
+        let report = NuttaliReport {
+            x: *pos_x * (*scalar),
+            y: *pos_y * (*scalar),
+            buttons: (
+                (mb5.is_low().unwrap() as u8) << 3
+                | (mb4.is_low().unwrap() as u8) << 4
+                | (mb2.is_low().unwrap() as u8) << 1 
+                | (mb1.is_low().unwrap() as u8)), // buttons = 1 byte. MB1 = bit 1, MB2 = bit 2, etc etc
             wheel: 0,
         };
 
-        rprintln!("Report: x:{}, y:{}", *pos_x, *pos_y);
 
         // push the report
         hid.push_input(&report).ok();