diff --git a/Cargo.toml b/Cargo.toml index 029b5e29f0190a0087ac6000f236967954724316..e1504415b039d1995b43af67660cd0fe384af1a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,8 @@ cortex-m-rtic = "0.5.5" # embedded-hal = { version = "0.2.4", features = ["unproven"] } embedded-hal = "0.2.4" usb-device = "0.2.7" +serde = { version = "1.0", default-features = false } +ssmarshal = { version = "1.0", default-features = false} # Panic handlers, comment all but one to generate doc! panic-halt = "0.2.0" @@ -68,17 +70,7 @@ codegen-units = 1 # better optimizations debug = true # symbols are nice and they don't increase the size on Flash lto = true # better optimizations -<<<<<<< HEAD -======= - - # [features] # nightly = ["cortex-m/inline-asm"] -# # this lets you use `cargo fix`! -# [[bin]] -# name = "app" -# test = false -# bench = false ->>>>>>> 5e5504062ee4477abe60461125dac9cfae10ea99 diff --git a/examples/buttons.rs b/examples/buttons.rs index 7fe324fbac4ecb95629091259c7821aa20b4ad67..38628859cf3313cac3171cd50b7bd2a706dc5964 100644 --- a/examples/buttons.rs +++ b/examples/buttons.rs @@ -14,7 +14,7 @@ use core::convert::TryInto; use panic_rtt_target as _; -use rtic::cyccnt::{Instant, U32Ext as _}; +use rtic::cyccnt::{Instant, Duration, U32Ext as _}; use rtt_target::{rprint, rprintln, rtt_init_print}; use stm32f4xx_hal::{gpio::{AlternateOD, PullUp}, stm32}; @@ -95,18 +95,20 @@ const APP: () = { device.GPIOA.moder.modify(|_, w| w.moder2().bits(1)); device.GPIOA.moder.modify(|_, w| w.moder1().bits(1)); - device.GPIOC.moder.modify(|_, w| w.moder5().bits(1)); + //device.GPIOC.moder.modify(|_, w| w.moder5().bits(1)); //left_button_read = device.GPIOCEN_R; let gpioa = device.GPIOA.split(); let gpiob = device.GPIOB.split(); let gpioc = device.GPIOC.split(); + // pass on late resources init::LateResources { //GPIOA: device.GPIOA, led_red: gpioa.pa3.into_push_pull_output(), led_green: gpioa.pa2.into_push_pull_output(), led_blue: gpioa.pa1.into_push_pull_output(), + turbo_button: gpioa.pa4.into_pull_down_input(), left_button: gpioc.pc5.into_pull_down_input(), right_button: gpioa.pa5.into_pull_down_input(), @@ -118,6 +120,8 @@ const APP: () = { forward_button: gpiob.pb14.into_pull_down_input(), backward_button: gpiob.pb15.into_pull_down_input(), } + + } #[idle] @@ -131,18 +135,23 @@ const APP: () = { #[task(resources = [left_button, right_button, scroll_button, turbo_button, forward_button, backward_button, scroll_forward, scroll_back, led_red], schedule = [is_button_pressed])] fn is_button_pressed(cx: is_button_pressed::Context) { + let mut is_pressed: bool = false; + let mut counter: i32 = 0; //[left,right,mouse,turbo,forward,backward] let mut buttons: [bool;8] = [false,false,false,false,false,false,false,false]; let mut buttons_prev : [bool;8] = [false,false,false,false,false,false,false, false]; loop { + //cx.resources.left_button.set_high().ok(); - if cx.resources.left_button.is_high().unwrap() { + if cx.resources.left_button.is_high().unwrap(){ buttons[0] = false; //rprintln!("left button is set high"); } else { buttons[0] = true; + //is_pressed = true; + //let start = Instant::now(); //rprintln!("left button is set low"); } @@ -199,77 +208,26 @@ const APP: () = { } if buttons != buttons_prev{ - - rprintln!("Buttons -- Right: {}, Left: {}, Middle: {}, DPI: {}, Fram: {}, Bak: {}, scroll forward: {}, scroll back: {}", buttons[0], buttons[1], buttons[2], buttons[3], + buttons_prev = buttons; + rprintln!("Buttons -- Left: {}, Right: {}, Middle: {}, DPI: {}, Fram: {}, Bak: {}, scroll forward: {}, scroll back: {}", buttons[0], buttons[1], buttons[2], buttons[3], buttons[4],buttons[5], buttons[6], buttons[7]); - //rprintln!(print); - buttons_prev = buttons; + loop { + counter = counter + 1; + if counter > 1000 { + counter = 0; + break; + } + } + } + } } - #[task(resources = [led_green,led_blue,led_red], schedule = [toggle])] - fn toggle(cx: toggle::Context, mut no_toggled: i32) { - static mut TOGGLE: bool = false; - //rprintln!("toggle @ {:?}", Instant::now()); - //rprintln!("times I have toggled {:?}", no_toggled); - no_toggled +=1; - - /*if no_toggled % 8 == 0{ - rprintln!("White"); - cx.resources.led_red.set_high().ok(); - cx.resources.led_green.set_high().ok(); - cx.resources.led_blue.set_high().ok(); - } else if no_toggled % 8 == 1{ - rprintln!("Green-yellow"); //Needs more oomph to be real yellow. - cx.resources.led_red.set_high().ok(); - cx.resources.led_blue.set_low().ok(); - cx.resources.led_green.set_high().ok(); - } else if no_toggled % 8 == 2{ - rprintln!("Purple"); - cx.resources.led_red.set_high().ok(); - cx.resources.led_blue.set_high().ok(); - cx.resources.led_green.set_low().ok(); - } else if no_toggled % 8 == 3{ - rprintln!("Light blue"); - cx.resources.led_red.set_low().ok(); - cx.resources.led_blue.set_high().ok(); - cx.resources.led_green.set_high().ok(); - } else if no_toggled % 8 == 4{ - rprintln!("Red"); - cx.resources.led_red.set_high().ok(); - cx.resources.led_blue.set_low().ok(); - cx.resources.led_green.set_low().ok(); - } else if no_toggled % 8 == 5{ - rprintln!("Green"); - cx.resources.led_red.set_low().ok(); - cx.resources.led_blue.set_low().ok(); - cx.resources.led_green.set_high().ok(); - } else if no_toggled % 8 == 6{ - rprintln!("Blue"); - cx.resources.led_red.set_low().ok(); - cx.resources.led_blue.set_high().ok(); - cx.resources.led_green.set_low().ok(); - } else { - rprintln!("Off"); - cx.resources.led_red.set_low().ok(); - cx.resources.led_blue.set_low().ok(); - cx.resources.led_green.set_low().ok(); - }*/ - rprintln!("printing"); - rprintln!("White"); - cx.resources.led_red.set_high().ok(); - cx.resources.led_green.set_high().ok(); - cx.resources.led_blue.set_high().ok(); - - //*TOGGLE = !*TOGGLE; - //cx.schedule.toggle(cx.scheduled + OFFSET.cycles(),no_toggled).unwrap(); - } - extern "C" { fn EXTI0(); fn USART1(); diff --git a/examples/main.rs b/examples/main.rs new file mode 100644 index 0000000000000000000000000000000000000000..0e4b3233c228849327641a254204a74f30a5dfe2 --- /dev/null +++ b/examples/main.rs @@ -0,0 +1,304 @@ +//Work made by J, Jacobsson, T. Andersson and S. Gradén. +//Tested and valideted on: +//Windows - Lenovo Yoga 7 series +//Mac - Apple MacBook Pro Model A2141 EMC 3347 +//TODO: +//Forward and back buttons should work as normal buttons. +//RGB should be able to be configured in the computer. + +#![no_main] +#![no_std] + +use stm32f4xx_hal::{ + //dwt::Dwt, + gpio::Speed, + gpio::{gpioa::{PA1, PA2, PA3, PA4, PA5, PA6, PA7}, + gpiob::{PB10, PB12, PB14,PB15}, + gpioc::{PC2, PC3, PC4, PC5}, + Alternate, Output, PushPull, Input, PullDown,// PullUp, + }, + //rcc::Clocks, + spi::Spi, + //stm32, + otg_fs::{UsbBus, UsbBusType, USB}, //USB + prelude::*, +}; +use usb_device::{bus::UsbBusAllocator, prelude::*}; +use usbd_hid::{ + descriptor::{generator_prelude::*, MouseReport}, + hid_class::HIDClass, +}; + +use embedded_hal::spi::MODE_3; +use rtic::cyccnt::{Instant, U32Ext as _}; +use panic_rtt_target as _; +use rtt_target::{rprintln, rtt_init_print}; + +use app::{ + pmw3389::{self, Register}, + DwtDelay, +}; + +//Some settings for the sensor. +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>>, + ), + >, + PB12<Output<PushPull>>, +>; + +#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)] +const APP: () = { + struct Resources { + // late resources + // Leds + // led_blue: PA1<Output<PushPull>>, + // led_red: PA3<Output<PushPull>>, + // led_green: PA2<Output<PushPull>>, + + // Buttons + // turbo_button: PA4<Input<PullDown>>, + right_button: PA5<Input<PullDown>>, + scroll_button: PA6<Input<PullDown>>, + forward_button: PB14<Input<PullDown>>, + // backward_button: PB15<Input<PullDown>>, + left_button: PC5<Input<PullDown>>, + + // Scroll + scroll_b: PC4<Input<PullDown>>, + scroll_a: PA7<Input<PullDown>>, + + // USB + hid: HIDClass<'static, UsbBusType>, + usb_dev: UsbDevice<'static, UsbBus<USB>>, + + //Sensor + pmw3389: PMW3389T, + } + + #[init] + fn init(mut ctx: init::Context) -> init::LateResources { + static mut EP_MEMORY: [u32; 1024] = [0; 1024]; + static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None; + + rtt_init_print!(); + rprintln!("init"); + + // Set up the system clock. + let rcc = ctx.device.RCC.constrain(); + let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze(); + + // Initialize (enable) the monotonic timer (CYCCNT) + ctx.core.DCB.enable_trace(); + ctx.core.DWT.enable_cycle_counter(); + + // Buttons + // |||||||||| + // \/\/\/\/\/ + + let gpioa = ctx.device.GPIOA.split(); + let gpiob = ctx.device.GPIOB.split(); + let gpioc = ctx.device.GPIOC.split(); + let left_button = gpioc.pc5.into_pull_down_input(); + let right_button = gpioa.pa5.into_pull_down_input(); + let scroll_button = gpioa.pa6.into_pull_down_input(); + let forward_button = gpiob.pb14.into_pull_down_input(); + // /\/\/\/\/\ + // |||||||||| + // Buttons + + //Scroll + let scroll_a = gpioa.pa7.into_pull_down_input(); + let scroll_b = gpioc.pc4.into_pull_down_input(); + + // Sensor Init + // |||||||||| + // \/\/\/\/\/ + let mut core = ctx.core; + + // Initialize (enable) the monotonic timer (CYCCNT) + core.DCB.enable_trace(); + core.DWT.enable_cycle_counter(); + + // setup clocks Duplicate code + //let rcc = ctx.device.RCC.constrain(); + //let clocks = rcc.cfgr.freeze(); + rprintln!("clocks:"); + rprintln!("hclk {}", _clocks.hclk().0); + + // Configure SPI + let sck = gpiob.pb10.into_alternate_af5(); + let miso = gpioc.pc2.into_alternate_af5(); + let mosi = gpioc.pc3.into_alternate_af5(); + let cs = gpiob.pb12.into_push_pull_output().set_speed(Speed::High); + + let spi = Spi::spi2( + ctx.device.SPI2, + (sck, miso, mosi), + MODE_3, + stm32f4xx_hal::time::KiloHertz(2000).into(), + _clocks, + ); + + let delay = DwtDelay::new(&mut core.DWT, _clocks); + let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap(); + + // set in burst mode + pmw3389.write_register(Register::MotionBurst, 0x00); + // /\/\/\/\/\ + // |||||||||| + // Sensor Init + + // USB + // |||||||||| + // \/\/\/\/\/ + let usb = USB { + usb_global: ctx.device.OTG_FS_GLOBAL, + usb_device: ctx.device.OTG_FS_DEVICE, + usb_pwrclk: ctx.device.OTG_FS_PWRCLK, + pin_dm: gpioa.pa11.into_alternate_af10(), + pin_dp: gpioa.pa12.into_alternate_af10(), + }; + USB_BUS.replace(UsbBus::new(usb, EP_MEMORY)); + + let hid = HIDClass::new(USB_BUS.as_ref().unwrap(), MouseReport::desc(), 1); + let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0xc410, 0x0000)) + .manufacturer("Nuttali") + .product("Mouse") + .serial_number("1.0") + .device_class(0) + .build(); + + // /\/\/\/\/\ + // |||||||||| + // USB + + init::LateResources{ left_button,right_button,scroll_button,forward_button, hid, usb_dev, pmw3389, scroll_b, scroll_a} + } + + #[task(binds=OTG_FS, resources = [left_button, right_button,scroll_button,forward_button, hid, usb_dev, pmw3389, scroll_a, scroll_b])] + fn on_usb(ctx: on_usb::Context) { + static mut WHEEL_COUNT: i8 = 0; + static mut A_PREV :bool = false; + static mut B_PREV :bool = false; + + // destruct the context + let (left_button, right_button, scroll_button, forward_button, + usb_dev, hid, pmw3389, scroll_a, scroll_b) + = (ctx.resources.left_button, ctx.resources.right_button, + ctx.resources.scroll_button, + ctx.resources.forward_button, ctx.resources.usb_dev, + ctx.resources.hid, ctx.resources.pmw3389, ctx.resources.scroll_a, + ctx.resources.scroll_b); + + let a:bool = scroll_a.is_high().unwrap(); + let b:bool = scroll_b.is_high().unwrap(); + *WHEEL_COUNT = check_scroll(a,b,*A_PREV,*B_PREV); + *A_PREV = a; + *B_PREV = b; + + // Read from sensor + let (x_sensor, y_sensor) = pmw3389.read_status().unwrap(); + + let left:u8; + if left_button.is_low().unwrap(){ + left = 1; + }else{ + left = 0; + } + let right:u8; + if right_button.is_low().unwrap(){ + right = 2; + }else{ + right = 0; + } + let scroll:u8; + if scroll_button.is_high().unwrap(){ + //rprintln!("scroll"); + scroll = 4; + }else{ + scroll = 0; + } + + //This dose not work yet. + let forward:u8; + if forward_button.is_high().unwrap(){ + //rprintln!("forward"); + forward = 8; + }else{ + forward = 0; + } + + + + + //https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ + let report = MouseReport { + x: (x_sensor as i8)>> 1, // need to convert form i16 to i8. Shifts to get smother movement + y: (y_sensor as i8)>> 1, // need to convert form i16 to i8. Shifts to get smother movement + buttons: left+right+scroll+forward, // (into takes a bool into an integer) + wheel: *WHEEL_COUNT, + }; + + // push the report + hid.push_input(&report).ok(); + + // update the usb device state + if usb_dev.poll(&mut [hid]) { + return; + } + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + rprintln!("idle"); + loop { + continue; + } + } +}; + +fn check_scroll(scroll_a:bool, scroll_b:bool, scroll_a_prev:bool, scroll_b_prev:bool) -> i8{ + let mut wheel_count: i8 = 0; + + if scroll_a != scroll_a_prev || scroll_b != scroll_b_prev{ + + //Sequence for up: + //A:Low B:Low + //A:High B:Low + //B:High B:High + //A:Low B:High + //A:Low B:Low + + //Sequence for down: + //A:Low B:Low + //A:Low B:High + //A:High B:High + //A:High B:Low + //A:Low B:Low + + if scroll_a_prev==scroll_b_prev{ + if scroll_b==scroll_b_prev{ + wheel_count +=1; + //rprintln!("Up count:{}", WHEEL_COUNT) + }else{ + wheel_count -=1; + //rprintln!("Down count:{}", WHEEL_COUNT) + } + }else{ + if scroll_a==scroll_a_prev{ + wheel_count +=1; + //rprintln!("Up count:{}", WHEEL_COUNT) + }else{ + wheel_count -=1; + //rprintln!("Down count:{}", WHEEL_COUNT) + } + } + } + return wheel_count; +} diff --git a/examples/nuttali_scroll.rs b/examples/nuttali_scroll.rs new file mode 100644 index 0000000000000000000000000000000000000000..887db65f347a671adb29218cd0c59e5c085dc515 --- /dev/null +++ b/examples/nuttali_scroll.rs @@ -0,0 +1,257 @@ +//! nuttali_scroll +//! +//! HAL OutputPin abstractions +//! +//! What it covers: +//! - using embedded hal, and the OutputPin abstraction + +#![no_main] +#![no_std] + + +//use core::intrinsics::rotate_left; + +use core::convert::TryInto; + +use panic_rtt_target as _; +use rtic::cyccnt::{Instant, U32Ext as _}; +use rtt_target::{rprint, rprintln, rtt_init_print}; +use stm32f4xx_hal::{gpio::{AlternateOD, PullUp}, stm32}; + +use stm32f4xx_hal::{ + gpio::{ + gpioa::{ + PA1, PA2, PA3, PA4, PA5, PA6, PA7}, + gpiob::{ + PB14,PB15}, + gpioc::{ + PC4, PC5}, + Input, Output, PushPull, PullDown, Alternate}, + prelude::*, +}; + +use embedded_hal::digital::v2::{OutputPin, ToggleableOutputPin, InputPin}; + +const OFFSET: u32 = 50_000_000; + +#[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)] +const APP: () = { + struct Resources { + // late resources + //GPIOA: stm32::GPIOA, + led_blue: PA1<Output<PushPull>>, + led_red: PA3<Output<PushPull>>, + led_green: PA2<Output<PushPull>>, + + turbo_button: PA4<Input<PullDown>>, + right_button: PA5<Input<PullDown>>, + scroll_button: PA6<Input<PullDown>>, + + scroll_B: PC4<Input<PullDown>>, + scroll_A: PA7<Input<PullDown>>, + + forward_button: PB14<Input<PullDown>>, + backward_button: PB15<Input<PullDown>>, + + left_button: PC5<Input<PullDown>>, + + + } + //#[init(schedule = [toggle])] + #[init(schedule = [is_button_pressed])] + fn init(cx: init::Context) -> init::LateResources { + rtt_init_print!(); + rprintln!("init"); + + + let mut core = cx.core; + let device = cx.device; + + + // Initialize (enable) the monotonic timer (CYCCNT) + core.DCB.enable_trace(); + core.DWT.enable_cycle_counter(); + + // 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 + + // Schedule `toggle` to run 8e6 cycles (clock cycles) in the future + //let number_of_toggles = 0; + //cx.schedule.toggle(now + OFFSET.cycles(),number_of_toggles).unwrap(); + + cx.schedule.is_button_pressed(now + OFFSET.cycles()).unwrap(); + + + //let left_button = gpioc.pc5.into_pull_up_input(); + //let left_button_timer = dp.TIM2; + + // power on GPIOA, RM0368 6.3.11 + //device.RCC.ahb1enr.modify(|_, w| w.gpioaen().set_bit()); + + //device.RCC.ahb1enr.modify(|_, w| w.gpiocen().set_bit()); + //configure PA3 as output, RM0368 8.4.1 + device.GPIOA.moder.modify(|_, w| w.moder3().bits(1)); + device.GPIOA.moder.modify(|_, w| w.moder2().bits(1)); + device.GPIOA.moder.modify(|_, w| w.moder1().bits(1)); + + device.GPIOC.moder.modify(|_, w| w.moder5().bits(1)); + //left_button_read = device.GPIOCEN_R; + let gpioa = device.GPIOA.split(); + let gpiob = device.GPIOB.split(); + let gpioc = device.GPIOC.split(); + + // pass on late resources + init::LateResources { + //GPIOA: device.GPIOA, + led_red: gpioa.pa3.into_push_pull_output(), + led_green: gpioa.pa2.into_push_pull_output(), + led_blue: gpioa.pa1.into_push_pull_output(), + turbo_button: gpioa.pa4.into_pull_down_input(), + left_button: gpioc.pc5.into_pull_down_input(), + right_button: gpioa.pa5.into_pull_down_input(), + + scroll_B: gpioc.pc4.into_pull_down_input(), + scroll_button: gpioa.pa6.into_pull_down_input(), + scroll_A: gpioa.pa7.into_pull_down_input(), + + forward_button: gpiob.pb14.into_pull_down_input(), + backward_button: gpiob.pb15.into_pull_down_input(), + } + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + rprintln!("idle"); + loop { + continue; + } + } + + #[task(resources = [scroll_A, scroll_B], schedule = [is_button_pressed])] + fn is_button_pressed(cx: is_button_pressed::Context) { + //[left,right,mouse,turbo,forward,backward] + let mut counter: i32 = 0; + let mut scroll: [bool;2] = [false,false]; + + let mut scroll_prev : [bool;2] = [false,false]; + loop { + + if cx.resources.scroll_A.is_high().unwrap(){ + scroll[0] = true + } else { + scroll[0] = false; + } + + if cx.resources.scroll_B.is_high().unwrap(){ + scroll[1] = true + } else { + scroll[1] = false; + } + + if scroll != scroll_prev{ + + //Sequence for up: + //A:Low B:Low + //A:High B:Low + //B:High B:High + //A:Low B:High + //A:Low B:Low + + //Sequence for down: + //A:Low B:Low + //A:Low B:High + //A:High B:High + //A:High B:Low + //A:Low B:Low + + if scroll_prev[0]==scroll_prev[1]{ + if scroll[1]==scroll_prev[1]{ + counter +=1; + rprintln!("Up count:{}",counter) + }else{ + counter -=1; + rprintln!("Down count:{}",counter) + } + }else{ + if scroll[0]==scroll_prev[0]{ + counter +=1; + rprintln!("Up count:{}",counter) + }else{ + counter -=1; + rprintln!("Down count:{}",counter) + } + } + + //rprintln!(print); + scroll_prev = scroll; + } + + + } + } + + + #[task(resources = [led_green,led_blue,led_red], schedule = [toggle])] + fn toggle(cx: toggle::Context, mut no_toggled: i32) { + static mut TOGGLE: bool = false; + //rprintln!("toggle @ {:?}", Instant::now()); + //rprintln!("times I have toggled {:?}", no_toggled); + no_toggled +=1; + + /*if no_toggled % 8 == 0{ + rprintln!("White"); + cx.resources.led_red.set_high().ok(); + cx.resources.led_green.set_high().ok(); + cx.resources.led_blue.set_high().ok(); + } else if no_toggled % 8 == 1{ + rprintln!("Green-yellow"); //Needs more oomph to be real yellow. + cx.resources.led_red.set_high().ok(); + cx.resources.led_blue.set_low().ok(); + cx.resources.led_green.set_high().ok(); + } else if no_toggled % 8 == 2{ + rprintln!("Purple"); + cx.resources.led_red.set_high().ok(); + cx.resources.led_blue.set_high().ok(); + cx.resources.led_green.set_low().ok(); + } else if no_toggled % 8 == 3{ + rprintln!("Light blue"); + cx.resources.led_red.set_low().ok(); + cx.resources.led_blue.set_high().ok(); + cx.resources.led_green.set_high().ok(); + } else if no_toggled % 8 == 4{ + rprintln!("Red"); + cx.resources.led_red.set_high().ok(); + cx.resources.led_blue.set_low().ok(); + cx.resources.led_green.set_low().ok(); + } else if no_toggled % 8 == 5{ + rprintln!("Green"); + cx.resources.led_red.set_low().ok(); + cx.resources.led_blue.set_low().ok(); + cx.resources.led_green.set_high().ok(); + } else if no_toggled % 8 == 6{ + rprintln!("Blue"); + cx.resources.led_red.set_low().ok(); + cx.resources.led_blue.set_high().ok(); + cx.resources.led_green.set_low().ok(); + } else { + rprintln!("Off"); + cx.resources.led_red.set_low().ok(); + cx.resources.led_blue.set_low().ok(); + cx.resources.led_green.set_low().ok(); + }*/ + rprintln!("printing"); + rprintln!("White"); + cx.resources.led_red.set_high().ok(); + cx.resources.led_green.set_high().ok(); + cx.resources.led_blue.set_high().ok(); + + //*TOGGLE = !*TOGGLE; + //cx.schedule.toggle(cx.scheduled + OFFSET.cycles(),no_toggled).unwrap(); + } + + extern "C" { + fn EXTI0(); + fn USART1(); + } +}; diff --git a/examples/pmw3389.rs b/examples/pmw3389.rs index 0d3cc8edf424f1806c21d2a97ea8a51e128ff5ee..cd4d763a09697b4e59710c6a284313cb52dc120c 100644 --- a/examples/pmw3389.rs +++ b/examples/pmw3389.rs @@ -11,11 +11,7 @@ use stm32f4xx_hal::{ dwt::Dwt, gpio::Speed, gpio::{ -<<<<<<< HEAD gpiob::{PB10, PB12}, -======= - gpiob::{PB10, PB4}, ->>>>>>> 5e5504062ee4477abe60461125dac9cfae10ea99 gpioc::{PC2, PC3}, Alternate, Output, PushPull, }, @@ -40,11 +36,7 @@ type PMW3389T = pmw3389::Pmw3389< PC3<Alternate<stm32f4xx_hal::gpio::AF5>>, ), >, -<<<<<<< HEAD PB12<Output<PushPull>>, -======= - PB4<Output<PushPull>>, ->>>>>>> 5e5504062ee4477abe60461125dac9cfae10ea99 >; #[rtic::app(device = stm32f4xx_hal::stm32, monotonic = rtic::cyccnt::CYCCNT, peripherals = true)] @@ -76,7 +68,7 @@ const APP: () = { // sck - pb10, (yellow) // miso - pc2, (red) // mosi - pc3, (orange) - // ncs - pb4, (long yellow) + // ncs - pb12, (long yellow) // motion - (brown) // // +5, (white) @@ -88,11 +80,7 @@ const APP: () = { let sck = gpiob.pb10.into_alternate_af5(); let miso = gpioc.pc2.into_alternate_af5(); let mosi = gpioc.pc3.into_alternate_af5(); -<<<<<<< HEAD let cs = gpiob.pb12.into_push_pull_output().set_speed(Speed::High); -======= - let cs = gpiob.pb4.into_push_pull_output().set_speed(Speed::High); ->>>>>>> 5e5504062ee4477abe60461125dac9cfae10ea99 let spi = Spi::spi2( device.SPI2, @@ -122,15 +110,17 @@ const APP: () = { 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).unwrap(); + cx.spawn.trace(*POS_X,*POS_Y).unwrap(); *COUNTER = 0; } - let (x, _y) = cx.resources.pmw3389.read_status().unwrap(); + 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 @@ -139,15 +129,19 @@ const APP: () = { } #[task(priority = 1)] - fn trace(_cx: trace::Context, pos: i64) { - static mut OLD_POS: i64 = 0; + fn trace(_cx: trace::Context, pos_x: i64, pos_y: i64) { + static mut OLD_POS_X: i64 = 0; + static mut OLD_POS_Y: i64 = 0; rprintln!( - "pos_x {:010}, diff {:010} @{:?}", - pos, - pos - *OLD_POS, + "pos_x {:010}, diff_x {:010}, pos_y {:010}, diff_y {:010} @{:?}", + pos_x, + pos_x - *OLD_POS_X, + pos_y, + pos_y - *OLD_POS_Y, Instant::now() ); - *OLD_POS = pos; + *OLD_POS_X = pos_x; + *OLD_POS_Y = pos_y; } #[idle] diff --git a/examples/rtt_rtic_usb_mouse.rs b/examples/rtt_rtic_usb_mouse.rs index 7bb3347a607f48c70bc23c468a133d1776c0fcb2..441a2fe212cb9e2550c797407466e0cb4191e9f3 100644 --- a/examples/rtt_rtic_usb_mouse.rs +++ b/examples/rtt_rtic_usb_mouse.rs @@ -71,7 +71,7 @@ pub mod hid { pub fn report(x: i8, y: i8) -> [u8; 3] { [ - 0x00, // button: none + 0x09, // button: none x as u8, // x-axis y as u8, // y-axis ] @@ -257,7 +257,7 @@ const APP: () = { let hid = HIDClass::new(USB_BUS.as_ref().unwrap()); let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0xc410, 0x0000)) - .manufacturer("Fake company") + .manufacturer("Nuttali") .product("mouse") .serial_number("TEST") .device_class(0) @@ -296,10 +296,10 @@ const APP: () = { // move mouse cursor horizontally (x-axis) while blinking LED if *counter < P / 2 { led.set_high().ok(); - hid.write(&hid::report(10, 0)); + hid.write(&hid::report(10, 10)); } else { led.set_low().ok(); - hid.write(&hid::report(-10, 0)); + hid.write(&hid::report(-10, -10)); } } diff --git a/examples/usb_mouse.rs b/examples/usb_mouse.rs new file mode 100644 index 0000000000000000000000000000000000000000..355dfba8f97c41f73374806c827b8c1cd1b6dceb --- /dev/null +++ b/examples/usb_mouse.rs @@ -0,0 +1,377 @@ +// > cargo run usb-mouse +// or +// > cargo run usb-mouse --release + +#![no_main] +#![no_std] + +use stm32f4xx_hal::{ + dwt::Dwt, + gpio::Speed, + gpio::{gpioa::{PA1, PA2, PA3, PA4, PA5, PA6, PA7}, + gpiob::{PB10, PB12, PB14,PB15}, + gpioc::{PC2, PC3, PC4, PC5}, + Alternate, Output, PushPull, Input, PullDown,// PullUp, + }, + rcc::Clocks, + spi::Spi, + stm32, + otg_fs::{UsbBus, UsbBusType, USB}, //USB + prelude::*, +}; +use usb_device::{bus::UsbBusAllocator, prelude::*}; +use usbd_hid::{ + descriptor::{generator_prelude::*, MouseReport}, + hid_class::HIDClass, +}; + +use embedded_hal::spi::MODE_3; +use rtic::cyccnt::{Instant, U32Ext as _}; +use panic_rtt_target as _; +use rtt_target::{rprintln, rtt_init_print}; + +use app::{ + pmw3389::{self, Register}, + DwtDelay, +}; + +//Some settings for the sensor. +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>>, + ), + >, + PB12<Output<PushPull>>, +>; + +#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)] +const APP: () = { + struct Resources { + // late resources + // Leds + led_blue: PA1<Output<PushPull>>, + led_red: PA3<Output<PushPull>>, + led_green: PA2<Output<PushPull>>, + + // Buttons + dpi_button: PA4<Input<PullDown>>, + right_button: PA5<Input<PullDown>>, + scroll_button: PA6<Input<PullDown>>, + forward_button: PB14<Input<PullDown>>, + backward_button: PB15<Input<PullDown>>, + left_button: PC5<Input<PullDown>>, + + // Scroll + scroll_B: PC4<Input<PullDown>>, + scroll_A: PA7<Input<PullDown>>, + + // USB + hid: HIDClass<'static, UsbBusType>, + usb_dev: UsbDevice<'static, UsbBus<USB>>, + + //Sensor + pmw3389: PMW3389T, + + + } + + #[init] + fn init(mut ctx: init::Context) -> init::LateResources { + static mut EP_MEMORY: [u32; 1024] = [0; 1024]; + static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None; + static mut dpi_button_prev: bool = false; + + rtt_init_print!(); + + rprintln!("init"); + + // Set up the system clock. + let rcc = ctx.device.RCC.constrain(); + let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze(); + + // Initialize (enable) the monotonic timer (CYCCNT) + ctx.core.DCB.enable_trace(); + ctx.core.DWT.enable_cycle_counter(); + // Leds + + + + // Buttons + // |||||||||| + // \/\/\/\/\/ + + let gpioa = ctx.device.GPIOA.split(); + let gpiob = ctx.device.GPIOB.split(); + let gpioc = ctx.device.GPIOC.split(); + + let led_red = gpioa.pa3.into_push_pull_output(); + let led_green = gpioa.pa2.into_push_pull_output(); + let led_blue = gpioa.pa1.into_push_pull_output(); + + + let left_button = gpioc.pc5.into_pull_down_input(); + let right_button = gpioa.pa5.into_pull_down_input(); + let scroll_button = gpioa.pa6.into_pull_down_input(); + + let dpi_button = gpioa.pa4.into_pull_down_input(); + + let forward_button = gpiob.pb14.into_pull_down_input(); + let backward_button = gpiob.pb15.into_pull_down_input(); + + + // /\/\/\/\/\ + // |||||||||| + // Buttons + + //Scroll + let scroll_A = gpioa.pa7.into_pull_down_input(); + let scroll_B = gpioc.pc4.into_pull_down_input(); + + // Sensor Init + // |||||||||| + // \/\/\/\/\/ + let mut core = ctx.core; + + // Initialize (enable) the monotonic timer (CYCCNT) + core.DCB.enable_trace(); + core.DWT.enable_cycle_counter(); + + // setup clocks Duplicate code + //let rcc = ctx.device.RCC.constrain(); + //let clocks = rcc.cfgr.freeze(); + rprintln!("clocks:"); + rprintln!("hclk {}", _clocks.hclk().0); + + // Configure SPI + let sck = gpiob.pb10.into_alternate_af5(); + let miso = gpioc.pc2.into_alternate_af5(); + let mosi = gpioc.pc3.into_alternate_af5(); + let cs = gpiob.pb12.into_push_pull_output().set_speed(Speed::High); + + let spi = Spi::spi2( + ctx.device.SPI2, + (sck, miso, mosi), + MODE_3, + stm32f4xx_hal::time::KiloHertz(2000).into(), + _clocks, + ); + + let mut delay = DwtDelay::new(&mut core.DWT, _clocks); + let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay).unwrap(); + + // set in burst mode + pmw3389.write_register(Register::MotionBurst, 0x00); + // /\/\/\/\/\ + // |||||||||| + // Sensor Init + + // USB + // |||||||||| + // \/\/\/\/\/ + let usb = USB { + usb_global: ctx.device.OTG_FS_GLOBAL, + usb_device: ctx.device.OTG_FS_DEVICE, + usb_pwrclk: ctx.device.OTG_FS_PWRCLK, + pin_dm: gpioa.pa11.into_alternate_af10(), + pin_dp: gpioa.pa12.into_alternate_af10(), + }; + USB_BUS.replace(UsbBus::new(usb, EP_MEMORY)); + + let hid = HIDClass::new(USB_BUS.as_ref().unwrap(), MouseReport::desc(), 1); + let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0xc410, 0x0000)) + .manufacturer("Nuttali") + .product("Mouse") + .serial_number("1.0") + .device_class(0) + .build(); + + // /\/\/\/\/\ + // |||||||||| + // USB + + init::LateResources{ left_button,right_button, scroll_button, hid, usb_dev, pmw3389, scroll_B, scroll_A, + dpi_button, forward_button,backward_button,led_red,led_blue,led_green} + } + + #[task(binds=OTG_FS, resources = [left_button, right_button, scroll_button, hid, usb_dev, pmw3389, scroll_A, + scroll_B, dpi_button,forward_button, backward_button, led_red, led_blue, led_green])] + fn on_usb(ctx: on_usb::Context) { + static mut wheel_count: i8 = 0; + static mut a_prev :bool = false; + static mut b_prev :bool = false; + + static mut dpi_toggle_prev :bool = false; + static mut dpi_toggle: i8 = 0; + static mut dpi_settings: [i8; 2] = [2, 8]; + static mut dpi_button_prev: bool = false; + + static mut forward_button_pressed: bool = false; + static mut backward_button_pressed: bool = false; + static mut wrapping_led_counter:u8 = 0; + + // destruct the context + let (left_button, right_button,scroll_button, usb_dev, hid, pmw3389, scroll_A, scroll_B, dpi_button, + forward_button, backward_button, led_red, led_blue, led_green) + = (ctx.resources.left_button, ctx.resources.right_button,ctx.resources.scroll_button, + ctx.resources.usb_dev, + ctx.resources.hid, ctx.resources.pmw3389, ctx.resources.scroll_A, + ctx.resources.scroll_B, ctx.resources.dpi_button, ctx.resources.forward_button, + ctx.resources.backward_button, ctx.resources.led_red, ctx.resources.led_blue, ctx.resources.led_green); + + let mut a:bool = scroll_A.is_high().unwrap(); + let mut b:bool = scroll_B.is_high().unwrap(); + *wheel_count = check_scroll(a,b,*a_prev,*b_prev); + *a_prev = a; + *b_prev = b; + + // Read from sensor + let (x_sensor, y_sensor) = pmw3389.read_status().unwrap(); + + let left:u8; + if left_button.is_low().unwrap(){ + left = 1; + }else{ + left = 0; + } + let right:u8; + if right_button.is_low().unwrap(){ + right = 2; + }else{ + right = 0; + } + //This dose not work yet. + let scroll:u8; + if scroll_button.is_low().unwrap(){ + scroll = 4; + }else{ + scroll = 0; + } + + + if forward_button.is_high().unwrap() && *forward_button_pressed == false{ + *wrapping_led_counter = *wrapping_led_counter + 1; + rprintln!("{}", wrapping_led_counter); + } + if backward_button.is_high().unwrap() && *backward_button_pressed == false{ + *wrapping_led_counter = *wrapping_led_counter - 1; + rprintln!("{}", wrapping_led_counter); + } + + + + if *wrapping_led_counter & 1 !=0{ + led_blue.set_high().ok(); + }else{ + led_blue.set_low().ok(); + + } + + if *wrapping_led_counter & 2 !=0{ + led_green.set_high().ok(); + }else{ + led_green.set_low().ok(); + + } + + + if *wrapping_led_counter & 4 !=0{ + led_red.set_high().ok(); + }else{ + led_red.set_low().ok(); + + } + + + *forward_button_pressed = forward_button.is_high().unwrap(); + *backward_button_pressed = backward_button.is_high().unwrap(); + + //rprintln!("{}",dpi_button.is_low().unwrap()); + let dpi:i8; + let mut length:i8 = dpi_settings.len() as i8; + //rprintln!("lenght: {}, Index: {}, DPI: {}",length,*dpi_toggle, dpi_settings[*dpi_toggle as usize]); + //let temp_dpi: bool = dpi_button_prev; + if dpi_button.is_high().unwrap() && *dpi_button_prev == false{ + + if *dpi_toggle +1 < length { + *dpi_toggle = *dpi_toggle +1; + //rprintln!("{}",dpi_settings[*dpi_toggle as usize]); + + } else { + *dpi_toggle = 0; + } + + + } + + *dpi_button_prev = dpi_button.is_high().unwrap(); + + let mut index:usize = *dpi_toggle as usize; + //https://eleccelerator.com/tutorial-about-usb-hid-report-descriptors/ + let report = MouseReport { + x: (x_sensor as i8)/dpi_settings[*dpi_toggle as usize], // need to convert form i16 to i8 + y: (y_sensor as i8)/dpi_settings[*dpi_toggle as usize], // need to convert form i16 to i8 + buttons: left+right, // (into takes a bool into an integer) + wheel: *wheel_count, + }; + + // push the report + hid.push_input(&report).ok(); + + // update the usb device state + if usb_dev.poll(&mut [hid]) { + return; + } + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + rprintln!("idle"); + loop { + continue; + } + } +}; + +fn check_scroll(scroll_A:bool, scroll_B:bool, scroll_A_prev:bool, scroll_B_prev:bool) -> i8{ + let mut wheel_count: i8 = 0; + + if scroll_A != scroll_A_prev || scroll_B != scroll_B_prev{ + + //Sequence for up: + //A:Low B:Low + //A:High B:Low + //B:High B:High + //A:Low B:High + //A:Low B:Low + + //Sequence for down: + //A:Low B:Low + //A:Low B:High + //A:High B:High + //A:High B:Low + //A:Low B:Low + + if scroll_A_prev==scroll_B_prev{ + if scroll_B==scroll_B_prev{ + wheel_count +=1; + rprintln!("Up count:{}", wheel_count) + }else{ + wheel_count -=1; + rprintln!("Down count:{}", wheel_count) + } + }else{ + if scroll_A==scroll_A_prev{ + wheel_count +=1; + rprintln!("Up count:{}", wheel_count) + }else{ + wheel_count -=1; + rprintln!("Down count:{}", wheel_count) + } + } + } + return wheel_count; +} diff --git a/src/main.rs b/src/main.rs index 792259654a49249056b0368a6cc45d2f3959069e..1d4474b3e58a67f33189883fea05072d9708d169 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,418 @@ -#![no_std] +//Work made by J, Jacobsson, T. Andersson and S. Gradén. +//Tested and valideted on: +//Windows - Lenovo Yoga 7 series +//Mac - Apple MacBook Pro Model A2141 EMC 3347 +//TODO: +//Forward and back buttons should work as normal buttons. +//RGB should be able to be configured in the computer. + #![no_main] +#![no_std] + +//Needed to create custom made hid reports +use usbd_hid::hid_class::HIDClass; +use usbd_hid::descriptor::SerializedDescriptor; +use serde::ser::{Serialize, Serializer, SerializeTuple}; +use usbd_hid::descriptor::AsInputReport; +use usbd_hid::descriptor::gen_hid_descriptor; + +//Cortex things from per +//use cortex_m::{asm::delay, peripheral::DWT}; +use stm32f4xx_hal::{ + //dwt::Dwt, + gpio::Speed, + //Look at resources to see what pin belongs to what. + gpio::{gpioa::{PA1, PA2, PA3, PA4, PA5, PA6, PA7}, + gpiob::{PB10, PB12, PB14,PB15}, + gpioc::{PC2, PC3, PC4, PC5}, + Alternate, Output, PushPull, Input, PullDown,// PullUp, + }, + //rcc::Clocks, + spi::Spi, + //stm32, + otg_fs::{UsbBus, UsbBusType, USB}, //USB + prelude::*, +}; +use usb_device::{bus::UsbBusAllocator, prelude::*}; + +use embedded_hal::spi::MODE_3; +//use rtic::cyccnt::{Instant, U32Ext as _}; +use panic_rtt_target as _; +use rtt_target::{rprintln, rtt_init_print}; + +use app::{ + pmw3389::{self, Register}, + DwtDelay, +}; + +//Some settings for the sensor. +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>>, + ), + >, + PB12<Output<PushPull>>, +>; + +//Report for USB. +#[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 +} + +#[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)] +const APP: () = { + struct Resources { + // late resources + // Leds + led_blue: PA1<Output<PushPull>>, + led_red: PA3<Output<PushPull>>, + led_green: PA2<Output<PushPull>>, + + // Buttons + dpi_button: PA4<Input<PullDown>>, + right_button: PA5<Input<PullDown>>, + scroll_button: PA6<Input<PullDown>>, + backward_button: PB15<Input<PullDown>>, + forward_button: PB14<Input<PullDown>>, + left_button: PC5<Input<PullDown>>, + + // Scroll + scroll_B: PC4<Input<PullDown>>, + scroll_A: PA7<Input<PullDown>>, + + // USB + hid: HIDClass<'static, UsbBusType>, + usb_dev: UsbDevice<'static, UsbBus<USB>>, + + //Sensor + pmw3389: PMW3389T, + } + + #[init] + fn init(mut ctx: init::Context) -> init::LateResources { + static mut EP_MEMORY: [u32; 1024] = [0; 1024]; + static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None; + + rtt_init_print!(); + rprintln!("init"); + + //Split all needed gpioa so that we can access every single pin. + let gpioa = ctx.device.GPIOA.split(); + let gpiob = ctx.device.GPIOB.split(); + let gpioc = ctx.device.GPIOC.split(); + + // Set up the system clock. + let rcc = ctx.device.RCC.constrain(); + let _clocks = rcc.cfgr.sysclk(48.mhz()).require_pll48clk().freeze(); + + // Initialize (enable) the monotonic timer (CYCCNT) + ctx.core.DCB.enable_trace(); + ctx.core.DWT.enable_cycle_counter(); + + // Leds + let led_red = gpioa.pa3.into_push_pull_output(); + let led_green = gpioa.pa2.into_push_pull_output(); + let led_blue = gpioa.pa1.into_push_pull_output(); + + // Buttons + let left_button = gpioc.pc5.into_pull_down_input(); + let right_button = gpioa.pa5.into_pull_down_input(); + let scroll_button = gpioa.pa6.into_pull_down_input(); + let backward_button = gpiob.pb15.into_pull_down_input(); + let forward_button = gpiob.pb14.into_pull_down_input(); + let dpi_button = gpioa.pa4.into_pull_down_input(); + + //Scroll + let scroll_A = gpioa.pa7.into_pull_down_input(); + let scroll_B = gpioc.pc4.into_pull_down_input(); + + // Sensor Init + // |||||||||| + // \/\/\/\/\/ + let mut core = ctx.core; + + // Initialize (enable) the monotonic timer (CYCCNT) + core.DCB.enable_trace(); + core.DWT.enable_cycle_counter(); + + // setup clocks Duplicate code + //let rcc = ctx.device.RCC.constrain(); + //let clocks = rcc.cfgr.freeze(); + rprintln!("clocks:"); + rprintln!("hclk {}", _clocks.hclk().0); + + // Configure SPI + let sck = gpiob.pb10.into_alternate_af5(); + let miso = gpioc.pc2.into_alternate_af5(); + let mosi = gpioc.pc3.into_alternate_af5(); + let cs = gpiob.pb12.into_push_pull_output().set_speed(Speed::High); + + let spi = Spi::spi2( + ctx.device.SPI2, + (sck, miso, mosi), + MODE_3, + stm32f4xx_hal::time::KiloHertz(2000).into(), + _clocks, + ); -// pick a panicking behavior -use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics -// use panic_abort as _; // requires nightly -// use panic_itm as _; // logs messages over ITM; requires ITM support -// use panic_semihosting as _; // logs messages to the host stderr; requires a debugger + let delay_or_something = DwtDelay::new(&mut core.DWT, _clocks); + let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay_or_something).unwrap(); -use cortex_m::asm; -use cortex_m_rt::entry; + // set in burst mode + let _burst = pmw3389.write_register(Register::MotionBurst, 0x00); + // /\/\/\/\/\ + // |||||||||| + // Sensor Init + + // USB + // |||||||||| + // \/\/\/\/\/ + + // Pull the D+ pin down to send a RESET condition to the USB bus. + // Dose not work yet. + //let mut usb_dp = gpioa.pa12.into_alternate_af10(); + //usb_dp= false; + //delay(_clocks.sysclk().0 / 100); + + let usb = USB { + usb_global: ctx.device.OTG_FS_GLOBAL, + usb_device: ctx.device.OTG_FS_DEVICE, + usb_pwrclk: ctx.device.OTG_FS_PWRCLK, + pin_dm: gpioa.pa11.into_alternate_af10(), + pin_dp: gpioa.pa12.into_alternate_af10(), + }; + + USB_BUS.replace(UsbBus::new(usb, EP_MEMORY)); + + 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("Nuttali") + .product("Mouse") + .serial_number("1.0") + .device_class(0) + .build(); + + // /\/\/\/\/\ + // |||||||||| + // USB + + init::LateResources{led_blue, led_red, led_green, dpi_button, left_button, right_button, scroll_button, backward_button, forward_button, hid, usb_dev, pmw3389, scroll_B, scroll_A} + } + + #[task(binds=OTG_FS, resources = [led_blue, led_red, led_green, dpi_button, left_button, right_button, scroll_button, backward_button, forward_button, hid, usb_dev, pmw3389, scroll_A, scroll_B])] + fn on_usb(ctx: on_usb::Context) { + //The scroll wheel need to know the last position or dose not work. + static mut A_PREV :bool = false; + static mut B_PREV :bool = false; + + + static mut DPI_BUTTON_PREV: bool = false; + + static mut WRAPPING_LED_COUNTER:i32 = 0; + + // destruct the context + let (led_blue, led_red, led_green, dpi_button, + left_button, right_button, scroll_button, backward_button, + forward_button, usb_dev, hid, pmw3389, scroll_A, scroll_B) + = (ctx.resources.led_blue,ctx.resources.led_red, + ctx.resources.led_green,ctx.resources.dpi_button, + ctx.resources.left_button, ctx.resources.right_button, + ctx.resources.scroll_button, ctx.resources.backward_button, + ctx.resources.forward_button, ctx.resources.usb_dev, + ctx.resources.hid, ctx.resources.pmw3389, ctx.resources.scroll_A, + ctx.resources.scroll_B); + let a:bool = scroll_A.is_high().unwrap(); + let b:bool = scroll_B.is_high().unwrap(); + let wheel_count = check_scroll(a,b,*A_PREV,*B_PREV); + *A_PREV = a; + *B_PREV = b; + + // Read from sensor + let (x_sensor, y_sensor) = pmw3389.read_status().unwrap(); + + let left:bool = left_button.is_low().unwrap(); + let right:bool = right_button.is_low().unwrap(); + let scroll:bool = scroll_button.is_high().unwrap(); + let backward:bool = backward_button.is_high().unwrap(); + let forward:bool = forward_button.is_high().unwrap(); + + let report = NuttaliReport { + x: (x_sensor as i8)>> 1, // need to convert form i16 to i8. Shifts to get smother movement + y: (y_sensor as i8)>> 1, // need to convert form i16 to i8. Shifts to get smother movement + buttons: check_buttons(left, right, scroll, backward, forward), // (into takes a bool into an integer) + wheel: wheel_count, + }; + + + if dpi_button.is_high().unwrap() && *DPI_BUTTON_PREV == false{ + *WRAPPING_LED_COUNTER = *WRAPPING_LED_COUNTER + 1; + let (red,blue,green) = change_led(*WRAPPING_LED_COUNTER); + if red{ + led_red.set_high().ok(); + }else{ + led_red.set_low().ok(); + } + if blue{ + led_blue.set_high().ok(); + }else{ + led_blue.set_low().ok(); + } + if green{ + led_green.set_high().ok(); + }else{ + led_green.set_low().ok(); + } + } + *DPI_BUTTON_PREV = dpi_button.is_high().unwrap(); + + // push the report + hid.push_input(&report).ok(); + + // update the usb device state + if usb_dev.poll(&mut [hid]) { + return; + } + } + + #[idle] + fn idle(_cx: idle::Context) -> ! { + rprintln!("idle"); + loop { + continue; + } + } +}; + +fn check_scroll(scroll_a:bool, scroll_b:bool, scroll_a_prev:bool, scroll_b_prev:bool) -> i8{ + let mut wheel_count: i8 = 0; + + if scroll_a != scroll_a_prev || scroll_b != scroll_b_prev{ + + //Sequence for up: + //A:Low B:Low + //A:High B:Low + //B:High B:High + //A:Low B:High + //A:Low B:Low + + //Sequence for down: + //A:Low B:Low + //A:Low B:High + //A:High B:High + //A:High B:Low + //A:Low B:Low + + if scroll_a_prev==scroll_b_prev{ + if scroll_b==scroll_b_prev{ + wheel_count +=1; + rprintln!("Up count:{}", wheel_count) + }else{ + wheel_count -=1; + rprintln!("Down count:{}", wheel_count) + } + }else{ + if scroll_a==scroll_a_prev{ + wheel_count +=1; + rprintln!("Up count:{}", wheel_count) + }else{ + wheel_count -=1; + rprintln!("Down count:{}", wheel_count) + } + } + } + return wheel_count; +} + +//Dose not check dpi +// Left button : bit no 0 +// Right button : bit no 1 +// Scroll/Middle button : bit no 2 +// Backward button : bit no 3 +// Forward button : bit no 4 +fn check_buttons(left:bool,right:bool,scroll:bool,backward:bool,forward:bool) -> u8{ + let mut result:u8 = 0; + if left{ + result += 1; + } + if right{ + result += 2; + } + if scroll{ + result += 4; + } + if backward{ + result += 8; + } + if forward{ + result += 16; + } + return result; +} -#[entry] -fn main() -> ! { - asm::nop(); // To not have main optimize to abort in release mode, remove when you add code +fn change_led(no_toggled: i32) -> (bool,bool,bool) { + let led_red:bool; + let led_blue:bool; + let led_green:bool; - loop { - // your code goes here + if no_toggled % 8 == 0{ + led_red= true; + led_green= true; + led_blue= true; + } else if no_toggled % 8 == 1{ + led_red= true; + led_blue= false; + led_green= true; + } else if no_toggled % 8 == 2{ + led_red= true; + led_blue= true; + led_green= false; + } else if no_toggled % 8 == 3{ + led_red= false; + led_blue= true; + led_green= true; + } else if no_toggled % 8 == 4{ + led_red= true; + led_blue= false; + led_green= false; + } else if no_toggled % 8 == 5{ + led_red= false; + led_blue= false; + led_green= true; + } else if no_toggled % 8 == 6{ + led_red= false; + led_blue= true; + led_green= false; + } else { + led_red= false; + led_blue= false; + led_green= false; } + return (led_red,led_blue,led_green); }