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 = [
"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"
......
......@@ -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"] }
......
// 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 {
// 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, 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)
0x29, 0x05, // USAGE_MAXIMUM (Button 5)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x03, // REPORT_COUNT (3)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x05, // REPORT_SIZE (5)
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)
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, 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();
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();
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,15 +378,20 @@ 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;
// Calc movement
......@@ -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();
......
// > 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();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment