Skip to content
Snippets Groups Projects
Commit 07a35396 authored by Carl Österberg's avatar Carl Österberg
Browse files

working mouse

parent 1ffa7767
No related branches found
No related tags found
No related merge requests found
...@@ -18,7 +18,10 @@ dependencies = [ ...@@ -18,7 +18,10 @@ dependencies = [
"cortex-m-rtic", "cortex-m-rtic",
"cortex-m-semihosting", "cortex-m-semihosting",
"embedded-hal", "embedded-hal",
"panic-halt",
"panic-itm",
"panic-rtt-target", "panic-rtt-target",
"panic-semihosting",
"rtt-target 0.3.0", "rtt-target 0.3.0",
"stm32f4 0.13.0", "stm32f4 0.13.0",
"stm32f4xx-hal", "stm32f4xx-hal",
...@@ -251,6 +254,21 @@ version = "1.0.0" ...@@ -251,6 +254,21 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" 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]] [[package]]
name = "panic-rtt-target" name = "panic-rtt-target"
version = "0.1.1" version = "0.1.1"
...@@ -261,6 +279,16 @@ dependencies = [ ...@@ -261,6 +279,16 @@ dependencies = [
"rtt-target 0.2.2", "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]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.24" version = "1.0.24"
......
...@@ -15,16 +15,16 @@ usb-device = "0.2.7" ...@@ -15,16 +15,16 @@ usb-device = "0.2.7"
usbd-hid = "0.5.0" usbd-hid = "0.5.0"
# Panic handlers, comment all but one to generate doc! # 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. # Uncomment for the itm panic examples.
#panic-itm = "0.4.2" panic-itm = "0.4.2"
# Uncomment for the rtt-timing examples. # Uncomment for the rtt-timing examples.
panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] } panic-rtt-target = { version = "0.1.1", features = ["cortex-m"] }
# Uncomment for the semihosting examples. # Uncomment for the semihosting examples.
#panic-semihosting = "0.5.6" panic-semihosting = "0.5.6"
# Tracing # Tracing
rtt-target = { version = "0.3.0", features = ["cortex-m"] } rtt-target = { version = "0.3.0", features = ["cortex-m"] }
......
// 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;
}
}
...@@ -57,32 +57,36 @@ pub mod hid { ...@@ -57,32 +57,36 @@ pub mod hid {
// https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/mouse-collection-report-descriptor // https://docs.microsoft.com/en-us/windows-hardware/design/component-guidelines/mouse-collection-report-descriptor
const REPORT_DESCR: &[u8] = &[ const REPORT_DESCR: &[u8] = &[
0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x05, 0x01, // USAGE_PAGE Generic Desktop
0x09, 0x02, // USAGE (Mouse) 0x09, 0x02, // USAGE Mouse
0xa1, 0x01, // COLLECTION (Application) 0xa1, 0x01, // COLLECTION Application
0x09, 0x01, // USAGE (Pointer) 0x09, 0x01, // USAGE Pointer
0xa1, 0x00, // COLLECTION (Physical) 0xa1, 0x00, // COLLECTION Physical
0x05, 0x09, // USAGE_PAGE (Button) 0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1) 0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x03, // USAGE_MAXIMUM (Button 3) 0x29, 0x05, // USAGE_MAXIMUM (Button 5)
0x15, 0x00, // LOGICAL_MINIMUM (0) 0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x03, // REPORT_COUNT (3) 0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1) 0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs) 0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1) 0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x05, // REPORT_SIZE (5) 0x75, 0x03, // REPORT_SIZE (3)
0x81, 0x03, // INPUT (Cnst,Var,Abs) 0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x30, // USAGE (X) 0x05, 0x01, // USAGE_PAGE Generic Desktop
0x09, 0x31, // USAGE (Y) 0x09, 0x30, // USAGE X
0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x09, 0x31, // USAGE Y
0x25, 0x7f, // LOGICAL_MAXIMUM (127) 0x09, 0x38, // USAGE Wheel
0x75, 0x08, // REPORT_SIZE (8) 0x15, 0x81, // LOGICAL_MINIMUM -127
0x95, 0x02, // REPORT_COUNT (2) 0x25, 0x7f, // LOGICAL_MAXIMUM 127
0x81, 0x06, // INPUT (Data,Var,Rel) 0x75, 0x08, // REPORT_SIZE 8
0xc0, // END_COLLECTION 0x95, 0x03, // REPORT_COUNT 3
0xc0, // END_COLLECTION 0x81, 0x06, // INPUT Data,Var,Rel
0xc0, // END COLLECTION
0xc0, // END COLLECTION
]; ];
pub fn report(b: u8,x: i8, y: i8) -> [u8; 3] { pub fn report(b: u8,x: i8, y: i8) -> [u8; 3] {
...@@ -306,9 +310,11 @@ const APP: () = { ...@@ -306,9 +310,11 @@ const APP: () = {
// set in burst mode // set in burst mode
pmw3389.write_register(Register::MotionBurst, 0x00); pmw3389.write_register(Register::MotionBurst, 0x00).unwrap();
pmw3389.write_register(Register::ResolutionH, 0 as u8).unwrap();
// Pull the D+ pin down to send a RESET condition to the USB bus. // 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(); let mut usb_dp = gpioa.pa12.into_push_pull_output();
usb_dp.set_low().ok(); usb_dp.set_low().ok();
delay(clocks.sysclk().0 / 100); delay(clocks.sysclk().0 / 100);
...@@ -358,7 +364,7 @@ const APP: () = { ...@@ -358,7 +364,7 @@ const APP: () = {
} }
#[task(resources = [pmw3389, POS_X, POS_Y], schedule = [poll])] #[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_x = cx.resources.POS_X;
let pos_y = cx.resources.POS_Y; let pos_y = cx.resources.POS_Y;
...@@ -372,15 +378,20 @@ const APP: () = { ...@@ -372,15 +378,20 @@ const APP: () = {
.unwrap(); .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) { fn tick(mut cx: tick::Context) {
cx.schedule.tick(cx.scheduled + (84_000).cycles()).unwrap(); cx.schedule.tick(cx.scheduled + (84_000).cycles()).unwrap();
let res = cx.resources;
let pos_x = cx.resources.POS_X; let pos_x = cx.resources.POS_X;
let pos_y = cx.resources.POS_Y; let pos_y = cx.resources.POS_Y;
let old_pos_x = cx.resources.OLD_POS_X; let old_pos_x = cx.resources.OLD_POS_X;
let old_pos_y = cx.resources.OLD_POS_Y; 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; let hid = &mut cx.resources.hid;
// Calc movement // Calc movement
...@@ -390,12 +401,14 @@ const APP: () = { ...@@ -390,12 +401,14 @@ const APP: () = {
let report = MouseReport { let report = MouseReport {
x: diff_x as i8, x: diff_x as i8,
y: diff_y 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, wheel: 0,
}; };
rprintln!("Report: x:{}, y:{}", *pos_x, *pos_y);
// push the report // push the report
hid.push_input(&report).ok(); hid.push_input(&report).ok();
......
// > cargo run usb-mouse // > cargo run
// or // or
// > cargo run usb-mouse --release // > cargo run --release
#![no_main] #![no_main]
#![no_std] #![no_std]
use cortex_m::{asm::delay, peripheral::DWT}; use cortex_m::{asm::delay, peripheral::DWT};
use cortex_m_semihosting::hprintln;
use embedded_hal::digital::v2::OutputPin; use embedded_hal::digital::v2::OutputPin;
use embedded_hal::spi::MODE_3; use embedded_hal::spi::MODE_3;
use rtic::cyccnt::{Instant, U32Ext as _}; use rtic::cyccnt::{Instant, U32Ext as _};
...@@ -32,10 +33,39 @@ use usbd_hid::{ ...@@ -32,10 +33,39 @@ use usbd_hid::{
}; };
use panic_rtt_target as _; use panic_rtt_target as _;
use rtt_target::{rprintln, rtt_init_print}; use rtt_target::{rprint, rprintln, rtt_init_print};
// PMW3389 // PMW3389
use app::{DwtDelay, pmw3389::{self, Register}, pmw3389e}; 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< type PMW3389T = pmw3389::Pmw3389<
Spi< Spi<
...@@ -62,6 +92,8 @@ const APP: () = { ...@@ -62,6 +92,8 @@ const APP: () = {
OLD_POS_X: i64, OLD_POS_X: i64,
OLD_POS_Y: i64, OLD_POS_Y: i64,
DPI_SCALAR: i8,
MB2: gpioc::PC6<Input<PullUp>>, MB2: gpioc::PC6<Input<PullUp>>,
MB1: gpioc::PC7<Input<PullUp>>, MB1: gpioc::PC7<Input<PullUp>>,
DPIB1: gpiob::PB13<Input<PullUp>>, DPIB1: gpiob::PB13<Input<PullUp>>,
...@@ -70,7 +102,7 @@ const APP: () = { ...@@ -70,7 +102,7 @@ const APP: () = {
MB4: gpiob::PB14<Input<PullUp>>, MB4: gpiob::PB14<Input<PullUp>>,
} }
#[init(schedule = [poll])] #[init(schedule = [poll, dpi_buttons])]
fn init(mut cx: init::Context) -> init::LateResources { fn init(mut cx: init::Context) -> init::LateResources {
static mut EP_MEMORY: [u32; 1024] = [0; 1024]; static mut EP_MEMORY: [u32; 1024] = [0; 1024];
static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None; static mut USB_BUS: Option<UsbBusAllocator<UsbBusType>> = None;
...@@ -126,9 +158,9 @@ const APP: () = { ...@@ -126,9 +158,9 @@ const APP: () = {
let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay_dwt).unwrap(); let mut pmw3389 = pmw3389::Pmw3389::new(spi, cs, delay_dwt).unwrap();
// set in burst mode // 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::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 { let usb = USB {
usb_global: device.OTG_FS_GLOBAL, usb_global: device.OTG_FS_GLOBAL,
...@@ -138,10 +170,11 @@ const APP: () = { ...@@ -138,10 +170,11 @@ const APP: () = {
pin_dp: gpioa.pa12.into_alternate_af10(), pin_dp: gpioa.pa12.into_alternate_af10(),
}; };
let mut scalar:i8 = 1;
USB_BUS.replace(UsbBus::new(usb, EP_MEMORY)); 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)) let usb_dev = UsbDeviceBuilder::new(USB_BUS.as_ref().unwrap(), UsbVidPid(0xc410, 0x0000))
.manufacturer("") .manufacturer("")
.product("Vibora Rapido Muerta") .product("Vibora Rapido Muerta")
...@@ -150,19 +183,20 @@ const APP: () = { ...@@ -150,19 +183,20 @@ const APP: () = {
.build(); .build();
cx.schedule.poll(cx.start + (48_000).cycles()).ok(); cx.schedule.poll(cx.start + (48_000).cycles()).ok();
cx.schedule.dpi_buttons(cx.start + (50_000).cycles()).ok();
init::LateResources { init::LateResources {
usb_dev, usb_dev,
hid, hid,
MB1:mb1, MB2:mb2, MB4:mb4, MB5:mb5, DPIB1:dpib1, DPIB2:dpib2, MB1:mb1, MB2:mb2, MB4:mb4, MB5:mb5, DPIB1:dpib1, DPIB2:dpib2,
pmw3389, 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)] #[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_x = cx.resources.POS_X;
let pos_y = cx.resources.POS_Y; let pos_y = cx.resources.POS_Y;
...@@ -176,7 +210,41 @@ const APP: () = { ...@@ -176,7 +210,41 @@ const APP: () = {
.unwrap(); .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) { fn on_usb(cx: on_usb::Context) {
// destruct the context // destruct the context
let ( let (
...@@ -184,28 +252,36 @@ const APP: () = { ...@@ -184,28 +252,36 @@ const APP: () = {
hid, hid,
mb1, mb1,
mb2, mb2,
mb4,
mb5,
pos_x, pos_x,
pos_y, pos_y,
scalar,
) = ( ) = (
cx.resources.usb_dev, cx.resources.usb_dev,
cx.resources.hid, cx.resources.hid,
cx.resources.MB1, cx.resources.MB1,
cx.resources.MB2, cx.resources.MB2,
cx.resources.MB4,
cx.resources.MB5,
cx.resources.POS_X, cx.resources.POS_X,
cx.resources.POS_Y, cx.resources.POS_Y,
cx.resources.DPI_SCALAR,
); );
let report = MouseReport {
x: *pos_x, let report = NuttaliReport {
y: *pos_y, x: *pos_x * (*scalar),
buttons: (( y: *pos_y * (*scalar),
mb2.is_low().unwrap() as u8) << 1 buttons: (
| mb1.is_low().unwrap() as u8), // buttons = 1 byte. MB1 = bit 1, MB2 = bit 2, etc etc (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, wheel: 0,
}; };
rprintln!("Report: x:{}, y:{}", *pos_x, *pos_y);
// push the report // push the report
hid.push_input(&report).ok(); hid.push_input(&report).ok();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment