Mouse sensor testing
This commit is contained in:
parent
2de4c0638e
commit
273dbaa630
5 changed files with 225 additions and 49 deletions
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
|
@ -5,4 +5,7 @@
|
||||||
"titleBar.activeForeground": "#FCFCFE"
|
"titleBar.activeForeground": "#FCFCFE"
|
||||||
},
|
},
|
||||||
"rust-analyzer.check.allTargets": false,
|
"rust-analyzer.check.allTargets": false,
|
||||||
|
"rust-analyzer.cargo.features": [
|
||||||
|
"serial"
|
||||||
|
],
|
||||||
}
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
use crate::{serial::Serial, MouseInfoSender};
|
use crate::{
|
||||||
|
serial::{Commands, Serial},
|
||||||
|
MouseInfoSender,
|
||||||
|
};
|
||||||
|
|
||||||
use rp_pico as bsp;
|
use rp_pico as bsp;
|
||||||
|
|
||||||
|
@ -7,6 +10,7 @@ use bsp::{
|
||||||
clocks::ClocksManager,
|
clocks::ClocksManager,
|
||||||
pac,
|
pac,
|
||||||
pac::{interrupt, Interrupt},
|
pac::{interrupt, Interrupt},
|
||||||
|
rom_data::reset_to_usb_boot,
|
||||||
usb::UsbBus,
|
usb::UsbBus,
|
||||||
},
|
},
|
||||||
pac::{RESETS, USBCTRL_DPRAM, USBCTRL_REGS},
|
pac::{RESETS, USBCTRL_DPRAM, USBCTRL_REGS},
|
||||||
|
@ -19,12 +23,15 @@ static mut USB_BUS: Option<UsbBusAllocator<UsbBus>> = None;
|
||||||
static mut USB_SERIAL: Option<Serial> = None;
|
static mut USB_SERIAL: Option<Serial> = None;
|
||||||
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
|
static mut USB_DEVICE: Option<UsbDevice<UsbBus>> = None;
|
||||||
|
|
||||||
pub struct CustomHID<'a> {
|
pub fn serial() -> &'static mut Serial<'static> {
|
||||||
out_ep: EndpointOut<'a, UsbBus>,
|
unsafe { USB_SERIAL.as_mut().unwrap() }
|
||||||
in_ep: EndpointIn<'a, UsbBus>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CustomHID<'a> {
|
pub struct CustomHID {
|
||||||
|
c: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CustomHID {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
usbctrl_reg: USBCTRL_REGS,
|
usbctrl_reg: USBCTRL_REGS,
|
||||||
usbctrl_dpram: USBCTRL_DPRAM,
|
usbctrl_dpram: USBCTRL_DPRAM,
|
||||||
|
@ -58,20 +65,25 @@ impl<'a> CustomHID<'a> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (in_ep, out_ep) = unsafe {
|
unsafe {
|
||||||
pac::NVIC::unmask(Interrupt::USBCTRL_IRQ);
|
pac::NVIC::unmask(Interrupt::USBCTRL_IRQ);
|
||||||
|
pac::NVIC::unmask(Interrupt::SW0_IRQ);
|
||||||
(
|
|
||||||
USB_BUS.as_ref().unwrap().interrupt(64, poll_ms),
|
|
||||||
USB_BUS.as_ref().unwrap().interrupt(64, poll_ms),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Self { in_ep, out_ep }
|
Self { c: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serial<F>(&mut self, mut f: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&mut Serial),
|
||||||
|
{
|
||||||
|
critical_section::with(|_| {
|
||||||
|
f(serial());
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> MouseInfoSender for CustomHID<'a> {
|
impl MouseInfoSender for CustomHID {
|
||||||
fn send(&mut self, x: i8, y: i8, buttons: u8, wheel: i8, pan: i8) {
|
fn send(&mut self, x: i8, y: i8, buttons: u8, wheel: i8, pan: i8) {
|
||||||
push_mouse_movement(MouseReport {
|
push_mouse_movement(MouseReport {
|
||||||
x,
|
x,
|
||||||
|
@ -81,12 +93,24 @@ impl<'a> MouseInfoSender for CustomHID<'a> {
|
||||||
pan,
|
pan,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn heart_beat(&mut self) {
|
||||||
|
self.c += 1;
|
||||||
|
|
||||||
|
if self.c == 1_000_000 {
|
||||||
|
self.c = 0;
|
||||||
|
|
||||||
|
if !(pac::NVIC::is_pending(Interrupt::SW0_IRQ)) {
|
||||||
|
pac::NVIC::pend(Interrupt::SW0_IRQ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// with interrupts disabled, to avoid a race hazard with the USB IRQ.
|
/// with interrupts disabled, to avoid a race hazard with the USB IRQ.
|
||||||
fn push_mouse_movement(report: MouseReport) {
|
fn push_mouse_movement(report: MouseReport) {
|
||||||
critical_section::with(|_| unsafe {
|
critical_section::with(|_| {
|
||||||
let serial = USB_SERIAL.as_mut().unwrap();
|
let serial = serial();
|
||||||
|
|
||||||
serial.send_text("x");
|
serial.send_text("x");
|
||||||
serial.send_number(report.x, 10);
|
serial.send_number(report.x, 10);
|
||||||
|
@ -101,6 +125,19 @@ fn push_mouse_movement(report: MouseReport) {
|
||||||
unsafe fn USBCTRL_IRQ() {
|
unsafe fn USBCTRL_IRQ() {
|
||||||
// Handle USB request
|
// Handle USB request
|
||||||
let usb_dev = USB_DEVICE.as_mut().unwrap();
|
let usb_dev = USB_DEVICE.as_mut().unwrap();
|
||||||
let usb_hid = USB_SERIAL.as_mut().unwrap();
|
let usb_hid = serial();
|
||||||
usb_dev.poll(&mut [usb_hid]);
|
|
||||||
|
if usb_dev.poll(&mut [usb_hid]) {
|
||||||
|
if let Some(command) = usb_hid.read() {
|
||||||
|
match command {
|
||||||
|
Commands::Reset => reset_to_usb_boot(0, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
#[interrupt]
|
||||||
|
unsafe fn SW0_IRQ() {
|
||||||
|
serial().send_text("heartbeat (IRQ)");
|
||||||
}
|
}
|
||||||
|
|
74
src/main.rs
74
src/main.rs
|
@ -1,24 +1,28 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
#[cfg(features = "serial")]
|
#[cfg(feature = "serial")]
|
||||||
mod custom_hid;
|
mod custom_hid;
|
||||||
|
|
||||||
#[cfg(not(features = "serial"))]
|
#[cfg(not(feature = "serial"))]
|
||||||
mod mouse_hid;
|
mod mouse_hid;
|
||||||
|
|
||||||
mod mouse_sensor;
|
mod mouse_sensor;
|
||||||
mod serial;
|
mod serial;
|
||||||
|
|
||||||
#[cfg(features = "serial")]
|
use core::panic::PanicInfo;
|
||||||
|
|
||||||
|
use cortex_m::delay::Delay;
|
||||||
|
#[cfg(feature = "serial")]
|
||||||
use custom_hid::CustomHID;
|
use custom_hid::CustomHID;
|
||||||
|
|
||||||
#[cfg(not(features = "serial"))]
|
#[cfg(not(feature = "serial"))]
|
||||||
use mouse_hid::MouseHID;
|
use mouse_hid::MouseHID;
|
||||||
|
|
||||||
// Ensure we halt the program on panic (if we don't mention this crate it won't
|
#[panic_handler]
|
||||||
// be linked)
|
fn panic(_info: &PanicInfo) -> ! {
|
||||||
use panic_halt as _;
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
use rp_pico as bsp;
|
use rp_pico as bsp;
|
||||||
|
|
||||||
|
@ -32,6 +36,7 @@ use crate::mouse_sensor::MouseSensor;
|
||||||
|
|
||||||
pub trait MouseInfoSender {
|
pub trait MouseInfoSender {
|
||||||
fn send(&mut self, x: i8, y: i8, buttons: u8, wheel: i8, pan: i8);
|
fn send(&mut self, x: i8, y: i8, buttons: u8, wheel: i8, pan: i8);
|
||||||
|
fn heart_beat(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
|
@ -57,8 +62,9 @@ fn main() -> ! {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let peripheral_clock = clocks.peripheral_clock.freq();
|
let peripheral_clock = clocks.peripheral_clock.freq();
|
||||||
|
let delay = Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
|
||||||
|
|
||||||
#[cfg(features = "serial")]
|
#[cfg(feature = "serial")]
|
||||||
let mut hid = CustomHID::new(
|
let mut hid = CustomHID::new(
|
||||||
pac.USBCTRL_REGS,
|
pac.USBCTRL_REGS,
|
||||||
pac.USBCTRL_DPRAM,
|
pac.USBCTRL_DPRAM,
|
||||||
|
@ -67,7 +73,7 @@ fn main() -> ! {
|
||||||
10,
|
10,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(not(features = "serial"))]
|
#[cfg(not(feature = "serial"))]
|
||||||
let mut hid = MouseHID::new(
|
let mut hid = MouseHID::new(
|
||||||
pac.USBCTRL_REGS,
|
pac.USBCTRL_REGS,
|
||||||
pac.USBCTRL_DPRAM,
|
pac.USBCTRL_DPRAM,
|
||||||
|
@ -87,11 +93,53 @@ fn main() -> ! {
|
||||||
&mut pac.RESETS,
|
&mut pac.RESETS,
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut mouse_sensor = MouseSensor::new(pins, &mut pac.RESETS, pac.SPI0, peripheral_clock);
|
let mut mouse_sensor = MouseSensor::new(
|
||||||
|
pins,
|
||||||
|
&mut pac.RESETS,
|
||||||
|
pac.SPI0,
|
||||||
|
peripheral_clock,
|
||||||
|
delay,
|
||||||
|
|msg| {
|
||||||
|
#[cfg(feature = "serial")]
|
||||||
|
critical_section::with(|_| {
|
||||||
|
custom_hid::serial().send_text(msg);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// #[cfg(feature = "serial")]
|
||||||
|
// {
|
||||||
|
// hid.serial(|serial| {
|
||||||
|
// serial.send_number(mouse_sensor.product_id_1(), 10);
|
||||||
|
// serial.send_number(mouse_sensor.product_id_2(), 10);
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
|
let mut c = 0;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if let Some((x, y)) = mouse_sensor.read_movement() {
|
// if let Some((x, y)) = mouse_sensor.read_movement() {
|
||||||
hid.send(x, y, 0, 0, 0);
|
// hid.send(x, y, 0, 0, 0);
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
c += 1;
|
||||||
|
|
||||||
|
if c == 10_000_000 {
|
||||||
|
c = 0;
|
||||||
|
|
||||||
|
#[cfg(feature = "serial")]
|
||||||
|
critical_section::with(|_| {
|
||||||
|
let serial = custom_hid::serial();
|
||||||
|
|
||||||
|
serial.send_text("---");
|
||||||
|
serial.send_number(mouse_sensor.operation_mode(), 10);
|
||||||
|
serial.send_text(" - ");
|
||||||
|
serial.send_number(0xB8, 10);
|
||||||
|
|
||||||
|
// custom_hid::serial().send_number(mouse_sensor.product_id_2(), 10);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// hid.heart_beat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,8 +78,6 @@ impl MouseHID {
|
||||||
pac::NVIC::unmask(Interrupt::USBCTRL_IRQ);
|
pac::NVIC::unmask(Interrupt::USBCTRL_IRQ);
|
||||||
}
|
}
|
||||||
|
|
||||||
let delay = Delay::new(core.SYST, clocks.system_clock.freq().to_Hz());
|
|
||||||
|
|
||||||
Self { delay }
|
Self { delay }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,6 +93,10 @@ impl MouseInfoSender for MouseHID {
|
||||||
})
|
})
|
||||||
.unwrap_or(0);
|
.unwrap_or(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn heart_beat(&mut self) {
|
||||||
|
// mouse hid does everything by itself
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// with interrupts disabled, to avoid a race hazard with the USB IRQ.
|
/// with interrupts disabled, to avoid a race hazard with the USB IRQ.
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
use core::mem;
|
use core::mem;
|
||||||
|
|
||||||
use cortex_m::prelude::_embedded_hal_spi_FullDuplex;
|
use cortex_m::{delay::Delay, prelude::_embedded_hal_spi_FullDuplex};
|
||||||
use embedded_hal::digital::v2::OutputPin;
|
use embedded_hal::digital::v2::OutputPin;
|
||||||
use fugit::HertzU32;
|
use fugit::{HertzU32, MegahertzU32};
|
||||||
use rp_pico::{
|
use rp_pico::{
|
||||||
hal::{
|
hal::{
|
||||||
gpio::{
|
gpio::{
|
||||||
self,
|
self,
|
||||||
bank0::{Gpio2, Gpio3, Gpio4, Gpio5},
|
bank0::{Gpio2, Gpio25, Gpio3, Gpio4, Gpio5},
|
||||||
Function, Output, Pin, PushPull, Spi,
|
Function, Output, Pin, PushPull, PushPullOutput, Spi,
|
||||||
},
|
},
|
||||||
spi::{self, Enabled, Spi as SpiDevice},
|
spi::{self, Enabled, Spi as SpiDevice},
|
||||||
},
|
},
|
||||||
|
@ -16,18 +16,29 @@ use rp_pico::{
|
||||||
Pins,
|
Pins,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct MouseSensor {
|
pub struct MouseSensor<L>
|
||||||
|
where
|
||||||
|
L: FnMut(&str),
|
||||||
|
{
|
||||||
_sclk: Pin<Gpio2, Function<Spi>>,
|
_sclk: Pin<Gpio2, Function<Spi>>,
|
||||||
_mosi: Pin<Gpio3, Function<Spi>>,
|
_mosi: Pin<Gpio3, Function<Spi>>,
|
||||||
_miso: Pin<Gpio4, Function<Spi>>,
|
_miso: Pin<Gpio4, Function<Spi>>,
|
||||||
cs: Pin<Gpio5, Output<PushPull>>,
|
cs: Pin<Gpio5, Output<PushPull>>,
|
||||||
|
|
||||||
|
led: Pin<Gpio25, PushPullOutput>,
|
||||||
|
|
||||||
spi: SpiDevice<Enabled, SPI0, 8>,
|
spi: SpiDevice<Enabled, SPI0, 8>,
|
||||||
|
delay: Delay,
|
||||||
|
|
||||||
|
log: L,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MouseSensor {
|
impl<L> MouseSensor<L>
|
||||||
const READ: u8 = 0x7F;
|
where
|
||||||
const WRITE: u8 = 0x80;
|
L: FnMut(&str),
|
||||||
|
{
|
||||||
|
const READ: u8 = 0b0111_1111;
|
||||||
|
const WRITE: u8 = 0b1000_0000;
|
||||||
|
|
||||||
const REG_PRODUCT_ID1: u8 = 0x00;
|
const REG_PRODUCT_ID1: u8 = 0x00;
|
||||||
const REG_PRODUCT_ID2: u8 = 0x01;
|
const REG_PRODUCT_ID2: u8 = 0x01;
|
||||||
|
@ -54,6 +65,8 @@ impl MouseSensor {
|
||||||
resets: &mut RESETS,
|
resets: &mut RESETS,
|
||||||
spio: SPI0,
|
spio: SPI0,
|
||||||
peripheral_clock: impl Into<HertzU32>,
|
peripheral_clock: impl Into<HertzU32>,
|
||||||
|
mut delay: Delay,
|
||||||
|
mut log: L,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// These are implicitly used by the spi driver if they are in the correct mode
|
// These are implicitly used by the spi driver if they are in the correct mode
|
||||||
let _sclk = pins.gpio2.into_mode::<gpio::FunctionSpi>();
|
let _sclk = pins.gpio2.into_mode::<gpio::FunctionSpi>();
|
||||||
|
@ -68,46 +81,95 @@ impl MouseSensor {
|
||||||
let spi = spi.init(
|
let spi = spi.init(
|
||||||
resets,
|
resets,
|
||||||
peripheral_clock,
|
peripheral_clock,
|
||||||
HertzU32::from_raw(16_000_000u32),
|
MegahertzU32::from_raw(1).convert(),
|
||||||
&embedded_hal::spi::MODE_0,
|
&embedded_hal::spi::MODE_2,
|
||||||
);
|
);
|
||||||
|
|
||||||
cs.set_high().unwrap();
|
if let Err(_err) = cs.set_low() {
|
||||||
|
log("cs high failed");
|
||||||
|
}
|
||||||
|
|
||||||
Self {
|
delay.delay_ms(2);
|
||||||
|
|
||||||
|
if let Err(_err) = cs.set_high() {
|
||||||
|
log("cs high failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut me = Self {
|
||||||
_sclk,
|
_sclk,
|
||||||
_mosi,
|
_mosi,
|
||||||
_miso,
|
_miso,
|
||||||
cs,
|
cs,
|
||||||
|
|
||||||
|
led: pins.led.into_push_pull_output(),
|
||||||
|
|
||||||
spi,
|
spi,
|
||||||
|
delay,
|
||||||
|
|
||||||
|
log,
|
||||||
|
};
|
||||||
|
|
||||||
|
if me.led.set_low().is_err() {
|
||||||
|
(me.log)("led low failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !me.verify_product_id_1() || !me.verify_product_id_2() {
|
||||||
|
if me.led.set_high().is_err() {
|
||||||
|
(me.log)("led high failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
me
|
||||||
}
|
}
|
||||||
|
|
||||||
fn access<F, T>(&mut self, f: F) -> T
|
fn access<F, T>(&mut self, f: F) -> T
|
||||||
where
|
where
|
||||||
F: Fn(&mut Self) -> T,
|
F: Fn(&mut Self) -> T,
|
||||||
{
|
{
|
||||||
self.cs.set_low().unwrap();
|
if self.cs.set_low().is_err() {
|
||||||
|
(self.log)("cs low failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.delay.delay_us(1);
|
||||||
|
|
||||||
let res = f(self);
|
let res = f(self);
|
||||||
|
|
||||||
self.cs.set_high().unwrap();
|
if self.cs.set_high().is_err() {
|
||||||
|
(self.log)("cs low failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.delay.delay_us(2);
|
||||||
|
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read(&mut self, address: u8) -> u8 {
|
pub fn read(&mut self, address: u8) -> u8 {
|
||||||
self.access(|me| {
|
self.access(|me| {
|
||||||
me.spi.send(address & Self::READ).unwrap();
|
if me.spi.send(address & Self::READ).is_err() {
|
||||||
me.spi.read().unwrap()
|
(me.log)("send address (read) failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
me.delay.delay_us(50);
|
||||||
|
|
||||||
|
match me.spi.read() {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(_) => {
|
||||||
|
(me.log)("read failed");
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&mut self, address: u8, value: u8) {
|
pub fn write(&mut self, address: u8, value: u8) {
|
||||||
self.access(|me| {
|
self.access(|me| {
|
||||||
me.spi.send(address | Self::WRITE).unwrap();
|
if me.spi.send(address | Self::WRITE).is_err() {
|
||||||
me.spi.send(value).unwrap();
|
(me.log)("send address (write) failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
if me.spi.send(value).is_err() {
|
||||||
|
(me.log)("send value (write) failed");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,4 +207,28 @@ impl MouseSensor {
|
||||||
|
|
||||||
(motion, x_overflow, y_overflow)
|
(motion, x_overflow, y_overflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn product_id_1(&mut self) -> u8 {
|
||||||
|
self.read(Self::REG_PRODUCT_ID1)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn product_id_2(&mut self) -> u8 {
|
||||||
|
self.read(Self::REG_PRODUCT_ID2)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn operation_mode(&mut self) -> u8 {
|
||||||
|
self.read(Self::REG_OPERATION_MODE)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_product_id_1(&mut self) -> bool {
|
||||||
|
const DEFAULT_VALUE: u8 = 0x30;
|
||||||
|
|
||||||
|
DEFAULT_VALUE == self.product_id_1()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_product_id_2(&mut self) -> bool {
|
||||||
|
const DEFAULT_VALUE: u8 = 0x02;
|
||||||
|
|
||||||
|
DEFAULT_VALUE == self.product_id_2()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue