use crate::timer::Timer;
use crate::usb::control::{
get_configuration_descriptor, set_configuration, set_idle, set_protocol,
};
use crate::usb::descriptor::ConfigurationDescriptor;
use crate::usb::dwc2::{Channel, ControlEndpoint, TransferError};
use crate::usb::hid::{is_boot_interface, HidInterface, BOOT_PROTOCOL};
use crate::usb::Device;
const PROTOCOL_MOUSE: u8 = 2;
const BUTTON_COUNT: u8 = 3;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Button {
Left,
Right,
Middle,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Buttons(
pub u8,
);
impl Buttons {
pub fn left(&self) -> bool {
self.0 & (1 << 0) != 0
}
pub fn right(&self) -> bool {
self.0 & (1 << 1) != 0
}
pub fn middle(&self) -> bool {
self.0 & (1 << 2) != 0
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MouseReport {
pub buttons: Buttons,
pub x: i8,
pub y: i8,
pub wheel: i8,
}
impl MouseReport {
pub fn parse(report: &[u8]) -> Option<Self> {
if report.len() < 3 {
return None;
}
Some(Self {
buttons: Buttons(report[0]),
x: report[1] as i8,
y: report[2] as i8,
wheel: if report.len() >= 4 {
report[3] as i8
} else {
0
},
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ButtonEvent {
Pressed(Button),
Released(Button),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct MouseUpdate {
previous_buttons: Buttons,
report: MouseReport,
}
impl MouseUpdate {
pub fn report(&self) -> &MouseReport {
&self.report
}
pub fn button_events(&self) -> ButtonEventIter<'_> {
ButtonEventIter {
update: self,
index: 0,
}
}
}
pub struct ButtonEventIter<'a> {
update: &'a MouseUpdate,
index: u8,
}
impl Iterator for ButtonEventIter<'_> {
type Item = ButtonEvent;
fn next(&mut self) -> Option<ButtonEvent> {
while self.index < BUTTON_COUNT {
let button = match self.index {
0 => Button::Left,
1 => Button::Right,
_ => Button::Middle,
};
let mask = 1 << self.index;
self.index += 1;
let was_held = self.update.previous_buttons.0 & mask != 0;
let is_held = self.update.report.buttons.0 & mask != 0;
if is_held && !was_held {
return Some(ButtonEvent::Pressed(button));
}
if was_held && !is_held {
return Some(ButtonEvent::Released(button));
}
}
None
}
}
pub struct Mouse {
endpoint: ControlEndpoint,
interface: u8,
report_endpoint: u8,
toggle: bool,
previous_buttons: Buttons,
}
impl Mouse {
pub fn from_device(
channel: &mut Channel,
timer: &Timer,
device: Device,
) -> Result<Option<Mouse>, TransferError> {
let mut config = [0u8; 64];
let len = get_configuration_descriptor(channel, timer, device.endpoint, 0, &mut config)?;
let Some(interface) = HidInterface::find(&config[..len], |iface| {
is_boot_interface(iface, PROTOCOL_MOUSE)
}) else {
return Ok(None);
};
let Some(config_value) = ConfigurationDescriptor::parse(&config[..len]).map(|c| c.value())
else {
return Ok(None);
};
set_configuration(channel, timer, device.endpoint, config_value)?;
set_protocol(
channel,
timer,
device.endpoint,
interface.interface,
BOOT_PROTOCOL,
)?;
let _ = set_idle(channel, timer, device.endpoint, interface.interface, 0);
Ok(Some(Mouse {
endpoint: ControlEndpoint {
max_packet_size: interface.max_packet_size,
..device.endpoint
},
interface: interface.interface,
report_endpoint: interface.endpoint,
toggle: false,
previous_buttons: Buttons(0),
}))
}
pub fn interface(&self) -> u8 {
self.interface
}
pub fn report_endpoint(&self) -> u8 {
self.report_endpoint
}
pub fn max_packet_size(&self) -> u16 {
self.endpoint.max_packet_size
}
pub fn poll(
&mut self,
channel: &mut Channel,
timer: &Timer,
) -> Result<Option<MouseUpdate>, TransferError> {
let mut buffer = [0u8; 8];
let received = match channel.interrupt_in(
self.endpoint,
self.report_endpoint,
&mut self.toggle,
&mut buffer,
timer,
) {
Ok(received) => received,
Err(TransferError::Nak) => return Ok(None),
Err(error) => return Err(error),
};
let Some(report) = MouseReport::parse(&buffer[..received]) else {
return Ok(None);
};
let previous_buttons = self.previous_buttons;
self.previous_buttons = report.buttons;
Ok(Some(MouseUpdate {
previous_buttons,
report,
}))
}
}