use core::marker::PhantomData;
use embedded_hal::i2c;
use heapless::Vec;
use crate::{chip::*, reg};
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Debug)]
pub enum Error<I2cE> {
I2C(I2cE),
InvalidData,
InvalidChip,
InvalidProductId,
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Gt9x<'a, C, I2C>
where
C: Chip,
I2C: i2c::I2c,
{
chip: PhantomData<C>,
i2c: I2C,
i2c_addr: u8,
buf: &'a mut [u8],
}
impl<'a, C, I2C> Gt9x<'a, C, I2C>
where
C: Chip,
I2C: i2c::I2c,
{
pub fn new(i2c: I2C, buf: &'a mut [u8]) -> Self {
let required_len = (C::MAX_POINTS as usize * 8).max(4);
assert!(buf.len() >= required_len, "Buffer too small");
Gt9x {
chip: PhantomData,
i2c,
i2c_addr: 0x5D,
buf,
}
}
pub fn set_i2c_addr(&mut self, addr: u8) {
self.i2c_addr = addr;
}
pub fn write(&mut self, write: &[u8]) -> Result<(), Error<I2C::Error>> {
self.i2c.write(self.i2c_addr, write).map_err(Error::I2C)
}
pub fn write_read(&mut self, write: &[u8], len: usize) -> Result<(), Error<I2C::Error>> {
self.i2c
.write_read(self.i2c_addr, write, &mut self.buf[..len])
.map_err(Error::I2C)?;
Ok(())
}
pub fn init(&mut self) -> Result<(), Error<I2C::Error>> {
self.write(reg::CMD::ModeRead.as_bytes())?;
self.write_read(reg::ID_ADDR, 4)?;
match core::str::from_utf8(&self.buf[..4]) {
Ok(product_id) => {
#[cfg(feature = "defmt")]
defmt::trace!("Product ID: {}", product_id);
if product_id == C::ID {
self.write(reg::CLEAR_STATUS)?;
Ok(())
} else {
#[cfg(feature = "defmt")]
defmt::error!("Expected: {}, found: {}", C::ID, product_id);
Err(Error::InvalidProductId)
}
}
Err(_) => {
#[cfg(feature = "defmt")]
defmt::error!("InvalidData: {}", self.buf[..4]);
Err(Error::InvalidData)
}
}
}
pub fn get_touches(
&mut self,
) -> Result<Vec<Point, { C::MAX_POINTS as usize }>, Error<I2C::Error>>
where
[(); C::MAX_POINTS as usize]:,
{
self.write_read(reg::STATUS_ADDR, 1)?;
let status = reg::Status::from_bits(self.buf[0]);
if status.num_points() == 0 || !status.buffer_status() {
self.write(reg::CLEAR_STATUS)?;
return Ok(Vec::new());
}
self.write_read(®::POINT_BASE, status.num_points() as usize * 8)?;
let mut points = Vec::new();
for i in 0..status.num_points().min(C::MAX_POINTS) {
let base = (i as usize) * 8;
let point = Point {
id: self.buf[base] & 0x0F,
x: u16::from_le_bytes([self.buf[base + 1], self.buf[base + 2]]),
y: u16::from_le_bytes([self.buf[base + 3], self.buf[base + 4]]),
area: u16::from_le_bytes([self.buf[base + 5], self.buf[base + 6]]),
};
points.push(point).map_err(|_| Error::InvalidData)?;
}
self.write(reg::CLEAR_STATUS)?;
Ok(points)
}
}