#![no_std]
use core::{fmt::Debug, marker::PhantomData};
use config::{Bitfield, Mask};
use embedded_hal::{
digital::{self, InputPin},
i2c::I2c,
};
use crate::register::{Bank0, Register};
pub use crate::{
config::{
Address, FeedMode, FilterMode, GlideExtendMode, IntelliMouseMode, PositionMode, PowerMode,
ScrollMode, TapMode, XYEnable, XYInverted, XYSwapped,
},
error::Error,
};
mod config;
mod error;
mod register;
mod private {
pub trait Sealed {}
}
const PINNACLE_X_LOWER: u16 = 128;
const PINNACLE_Y_LOWER: u16 = 64;
const PINNACLE_X_UPPER: u16 = 1920;
const PINNACLE_Y_UPPER: u16 = 1472;
#[derive(Debug, Clone, Copy)]
pub struct RelativeData {
pub primary_pressed: bool,
pub secondary_pressed: bool,
pub aux_pressed: bool,
pub x_delta: i16,
pub y_delta: i16,
}
#[derive(Debug, Clone, Copy)]
pub struct AbsoluteData {
pub button_state: u8,
pub x_pos: u16,
pub y_pos: u16,
pub z_level: u8,
}
pub trait FeedState: private::Sealed {}
pub struct FeedEnabled;
pub struct NoFeed;
impl FeedState for FeedEnabled {}
impl private::Sealed for FeedEnabled {}
impl FeedState for NoFeed {}
impl private::Sealed for NoFeed {}
pub trait PositionReportingMode: private::Sealed {}
pub struct Relative;
pub struct Absolute;
impl PositionReportingMode for Relative {}
impl private::Sealed for Relative {}
impl PositionReportingMode for Absolute {}
impl private::Sealed for Absolute {}
pub struct Tm040040<'a, I2C, PositionMode: PositionReportingMode, Feed: FeedState, E> {
i2c: I2C,
address: Address,
hardware_data_ready: &'a mut dyn InputPin<Error = E>,
_pos_state: PhantomData<PositionMode>,
_feed_state: PhantomData<Feed>,
}
impl<I2C, E, PosMode, Feed, PinError> Tm040040<'_, I2C, PosMode, Feed, PinError>
where
I2C: I2c<Error = E>,
E: Debug,
PosMode: PositionReportingMode,
Feed: FeedState,
PinError: digital::Error,
{
pub fn free(self) -> I2C {
self.i2c
}
pub fn device_id(&mut self) -> Result<u8, Error<E, PinError>> {
self.read_reg(&Bank0::FIRMWARE_ID)
}
pub fn power_mode(&mut self) -> Result<PowerMode, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::SYS_CONFIG1)? >> 1;
let mode = PowerMode::try_from(bits)?;
Ok(mode)
}
pub fn set_power_mode(&mut self, power_mode: PowerMode) -> Result<(), Error<E, PinError>> {
self.update_reg(power_mode)
}
pub fn feed_mode(&mut self) -> Result<FeedMode, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & FeedMode::BITMASK;
let mode = FeedMode::try_from(bits)?;
Ok(mode)
}
fn set_feed_mode(&mut self, fd: FeedMode) -> Result<(), Error<E, PinError>> {
self.update_reg(fd)
}
pub fn position_mode(&mut self) -> Result<PositionMode, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & PositionMode::BITMASK;
let mode = PositionMode::try_from(bits)?;
Ok(mode)
}
fn set_position_mode(&mut self, pos: PositionMode) -> Result<(), Error<E, PinError>> {
self.update_reg(pos)
}
pub fn filter_mode(&mut self) -> Result<FilterMode, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & FilterMode::BITMASK;
let mode = FilterMode::try_from(bits)?;
Ok(mode)
}
pub fn set_filter_mode(&mut self, filter: FilterMode) -> Result<(), Error<E, PinError>> {
self.update_reg(filter)
}
pub fn xy_enable(&mut self) -> Result<XYEnable, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & XYEnable::BITMASK;
let mode = XYEnable::try_from(bits)?;
Ok(mode)
}
pub fn set_xy_enable(&mut self, yx: XYEnable) -> Result<(), Error<E, PinError>> {
self.update_reg(yx)
}
pub fn xy_inverted(&mut self) -> Result<XYInverted, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & XYInverted::BITMASK;
let mode = XYInverted::try_from(bits)?;
Ok(mode)
}
pub fn set_xy_inverted(&mut self, yx: XYInverted) -> Result<(), Error<E, PinError>> {
self.update_reg(yx)
}
fn read_reg<R: Register>(&mut self, reg: &R) -> Result<u8, Error<E, PinError>> {
let mut buffer = [0u8];
self.i2c
.write_read(
self.address as u8,
&[reg.addr() | Mask::Read as u8],
&mut buffer,
)
.map_err(|e| Error::BusError(e))?;
Ok(buffer[0])
}
fn write_reg<R: Register>(&mut self, reg: &R, value: u8) -> Result<(), Error<E, PinError>> {
if reg.read_only() {
Err(Error::SensorError(error::SensorError::WriteToReadOnly))
} else {
self.i2c
.write(self.address as u8, &[reg.addr() | Mask::Write as u8, value])
.map_err(|e| Error::BusError(e))
}
}
fn update_reg<BF: Bitfield>(&mut self, value: BF) -> Result<(), Error<E, PinError>> {
if BF::REGISTER.read_only() {
Err(Error::SensorError(error::SensorError::WriteToReadOnly))
} else {
let current = self.read_reg(&BF::REGISTER)?;
let value = (current & !BF::BITMASK) | (value.bits() & BF::BITMASK);
self.write_reg(&BF::REGISTER, value)
}
}
fn clear_flags(&mut self) -> Result<(), Error<E, PinError>> {
self.write_reg(&Bank0::STATUS1, 0x00)
}
}
impl<'a, I2C, E, PinError> Tm040040<'a, I2C, Relative, NoFeed, PinError>
where
I2C: I2c<Error = E>,
E: Debug,
PinError: digital::Error,
{
pub fn new(
i2c: I2C,
address: Address,
hardware_data_ready: &'a mut impl InputPin<Error = PinError>,
) -> Tm040040<'a, I2C, Relative, NoFeed, PinError> {
Tm040040::<'a, I2C, Relative, NoFeed, PinError> {
i2c,
address,
hardware_data_ready,
_pos_state: PhantomData,
_feed_state: PhantomData,
}
}
}
impl<'a, I2C, E, PinError> Tm040040<'a, I2C, Relative, FeedEnabled, PinError>
where
I2C: I2c<Error = E>,
E: Debug,
PinError: digital::Error,
{
pub fn relative_data(&mut self) -> Result<Option<RelativeData>, Error<E, PinError>> {
let hw_dr = self.hardware_data_ready.is_high()?;
if !hw_dr {
return Ok(None);
}
let sw_dr = self.read_reg(&Bank0::STATUS1)? & 0b0000_0100;
if sw_dr == 0 {
return Ok(None);
}
let pb0 = self.read_reg(&Bank0::PACKET_BYTE0)?;
let pb1 = self.read_reg(&Bank0::PACKET_BYTE1)?;
let pb2 = self.read_reg(&Bank0::PACKET_BYTE2)?;
self.clear_flags()?;
let primary_pressed = (pb0 & 0x1) != 0;
let secondary_pressed = (pb0 & 0x2) != 0;
let aux_pressed = (pb0 & 0x4) != 0;
let x_sign = pb0 & 0b0001_0000;
let y_sign = pb0 & 0b0010_0000;
let x_delta = if x_sign == 0 {
pb1 as i16
} else {
(pb1 as i16) - 256
};
let y_delta = if y_sign == 0 {
pb2 as i16
} else {
(pb2 as i16) - 256
};
Ok(Some(RelativeData {
primary_pressed,
secondary_pressed,
aux_pressed,
x_delta,
y_delta,
}))
}
pub fn absolute(
mut self,
) -> Result<Tm040040<'a, I2C, Absolute, FeedEnabled, PinError>, Error<E, PinError>> {
self.set_position_mode(PositionMode::Absolute)?;
Ok(Tm040040 {
i2c: self.i2c,
address: self.address,
hardware_data_ready: self.hardware_data_ready,
_pos_state: PhantomData,
_feed_state: PhantomData,
})
}
}
impl<I2C, E, Feed, PinError> Tm040040<'_, I2C, Relative, Feed, PinError>
where
I2C: I2c<Error = E>,
E: Debug,
Feed: FeedState,
PinError: digital::Error,
{
pub fn xy_swapped(&mut self) -> Result<XYSwapped, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & XYSwapped::BITMASK;
let mode = XYSwapped::try_from(bits)?;
Ok(mode)
}
pub fn set_xy_swapped(&mut self, yx: XYSwapped) -> Result<(), Error<E, PinError>> {
self.update_reg(yx)
}
pub fn intelli_mouse(&mut self) -> Result<IntelliMouseMode, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & IntelliMouseMode::BITMASK;
let mode = IntelliMouseMode::try_from(bits)?;
Ok(mode)
}
pub fn set_intelli_mouse(&mut self, im: IntelliMouseMode) -> Result<(), Error<E, PinError>> {
self.update_reg(im)
}
pub fn tap_mode(&mut self) -> Result<TapMode, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & TapMode::BITMASK;
let mode = TapMode::try_from(bits)?;
Ok(mode)
}
pub fn set_tap_mode(&mut self, tm: TapMode) -> Result<(), Error<E, PinError>> {
self.update_reg(tm)
}
pub fn scroll_mode(&mut self) -> Result<ScrollMode, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & ScrollMode::BITMASK;
let mode = ScrollMode::try_from(bits)?;
Ok(mode)
}
pub fn set_scroll_mode(&mut self, sm: ScrollMode) -> Result<(), Error<E, PinError>> {
self.update_reg(sm)
}
pub fn glide_extend_mode(&mut self) -> Result<GlideExtendMode, Error<E, PinError>> {
let bits = self.read_reg(&Bank0::FEED_CONFIG1)? & GlideExtendMode::BITMASK;
let mode = GlideExtendMode::try_from(bits)?;
Ok(mode)
}
pub fn set_glide_extend_mode(
&mut self,
gem: GlideExtendMode,
) -> Result<(), Error<E, PinError>> {
self.update_reg(gem)
}
}
impl<'a, I2C, E, PinError> Tm040040<'a, I2C, Absolute, FeedEnabled, PinError>
where
I2C: I2c<Error = E>,
E: Debug,
PinError: digital::Error,
{
pub fn absolute_data(&mut self) -> Result<Option<AbsoluteData>, Error<E, PinError>> {
let hw_dr = self.hardware_data_ready.is_high()?;
if !hw_dr {
return Ok(None);
}
let button_state = self.read_reg(&Bank0::PACKET_BYTE0)? & 0x3F;
let x_low = self.read_reg(&Bank0::PACKET_BYTE2)?;
let y_low = self.read_reg(&Bank0::PACKET_BYTE3)?;
let x_y_high = self.read_reg(&Bank0::PACKET_BYTE4)?;
let z_level = self.read_reg(&Bank0::PACKET_BYTE5)? & 0x3F;
let x_pos = x_low as u16 | (((x_y_high & 0x0F) as u16) << 8);
let y_pos = y_low as u16 | (((x_y_high & 0xF0) as u16) << 4);
self.clear_flags()?;
Ok(Some(AbsoluteData {
button_state,
x_pos: x_pos.max(PINNACLE_X_UPPER).min(PINNACLE_X_LOWER),
y_pos: y_pos.max(PINNACLE_Y_UPPER).min(PINNACLE_Y_LOWER),
z_level,
}))
}
pub fn relative(
mut self,
) -> Result<Tm040040<'a, I2C, Relative, FeedEnabled, PinError>, Error<E, PinError>> {
self.set_position_mode(PositionMode::Relative)?;
Ok(Tm040040 {
i2c: self.i2c,
address: self.address,
hardware_data_ready: self.hardware_data_ready,
_pos_state: PhantomData,
_feed_state: PhantomData,
})
}
}
impl<'a, I2C, E, PosMode, PinError> Tm040040<'a, I2C, PosMode, FeedEnabled, PinError>
where
I2C: I2c<Error = E>,
E: Debug,
PosMode: PositionReportingMode,
PinError: digital::Error,
{
pub fn disable(
mut self,
) -> Result<Tm040040<'a, I2C, PosMode, NoFeed, PinError>, Error<E, PinError>> {
self.set_feed_mode(FeedMode::NoFeed)?;
Ok(Tm040040 {
i2c: self.i2c,
address: self.address,
hardware_data_ready: self.hardware_data_ready,
_pos_state: PhantomData,
_feed_state: PhantomData,
})
}
}
impl<'a, I2C, E, PosMode, PinError> Tm040040<'a, I2C, PosMode, NoFeed, PinError>
where
I2C: I2c<Error = E>,
E: Debug,
PosMode: PositionReportingMode,
PinError: digital::Error,
{
pub fn enable(
mut self,
) -> Result<Tm040040<'a, I2C, PosMode, FeedEnabled, PinError>, Error<E, PinError>> {
self.set_feed_mode(FeedMode::Enabled)?;
self.clear_flags()?;
Ok(Tm040040 {
i2c: self.i2c,
address: self.address,
hardware_data_ready: self.hardware_data_ready,
_pos_state: PhantomData,
_feed_state: PhantomData,
})
}
}