#![no_std]
use embedded_hal::delay::DelayNs;
use embedded_hal::i2c::I2c;
use heapless::Vec;
pub const CST226_DEVICE_ADDRESS: u8 = 0x5A;
const CST226_REG_STATUS: u8 = 0x00;
const CST226_BUFFER_SIZE: usize = 28;
const MAX_TOUCH_POINTS: usize = 5;
const SWIPE_MIN_DISTANCE: i32 = 50;
#[derive(Clone, Copy, Debug)]
pub enum PowerMode {
Active,
Sleep,
}
#[derive(Debug, Default, Clone, Copy)]
pub struct TouchPoint {
pub x: u16,
pub y: u16,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Gesture {
None,
SwipeUp,
SwipeDown,
SwipeLeft,
SwipeRight,
}
#[derive(Default)]
struct GestureState {
is_touching: bool,
start_point: TouchPoint,
last_point: TouchPoint,
}
pub trait ResetInterface {
type Error;
fn reset(&mut self) -> Result<(), Self::Error>;
}
#[derive(Debug)]
pub enum DriverError<ResetError, I2cError> {
I2cError(I2cError),
ResetError(ResetError),
}
pub struct Cst226Driver<I2C, D, RST> {
i2c: I2C,
device_address: u8,
delay: D,
reset: RST,
gesture_state: GestureState,
}
impl<I2C, D, RST> Cst226Driver<I2C, D, RST>
where
I2C: I2c,
D: DelayNs,
RST: ResetInterface,
{
pub fn new(i2c: I2C, device_address: u8, reset: RST, delay: D) -> Self {
Cst226Driver {
i2c,
device_address,
delay,
reset,
gesture_state: GestureState::default(),
}
}
pub fn initialize(&mut self) -> Result<(), DriverError<RST::Error, I2C::Error>> {
self.reset.reset().map_err(DriverError::ResetError)?;
self.delay.delay_ms(10);
self.gesture_state = GestureState::default();
Ok(())
}
pub fn set_power_mode(&mut self, mode: PowerMode) -> Result<(), I2C::Error> {
match mode {
PowerMode::Sleep => self.i2c.write(self.device_address, &[0xD1, 0x05]),
PowerMode::Active => {
Ok(())
}
}
}
pub fn get_touches(&mut self) -> Result<Vec<TouchPoint, MAX_TOUCH_POINTS>, I2C::Error> {
let mut buffer = [0u8; CST226_BUFFER_SIZE];
self.i2c
.write_read(self.device_address, &[CST226_REG_STATUS], &mut buffer)?;
if buffer[6] != 0xAB || buffer[0] == 0xAB || buffer[5] == 0x80 {
return Ok(Vec::new());
}
let num_touches = (buffer[5] & 0x7F) as usize;
if num_touches == 0 {
return Ok(Vec::new());
}
if num_touches > MAX_TOUCH_POINTS {
self.i2c.write(self.device_address, &[0x00, 0xAB])?;
return Ok(Vec::new());
}
let mut touches = Vec::new();
let mut index: usize = 0;
for i in 0..num_touches {
if index + 4 >= CST226_BUFFER_SIZE {
break; }
let x = ((buffer[index + 1] as u16) << 4) | (((buffer[index + 3] >> 4) & 0x0F) as u16);
let y = ((buffer[index + 2] as u16) << 4) | ((buffer[index + 3] & 0x0F) as u16);
if touches.push(TouchPoint { x, y }).is_err() {
break; }
index += if i == 0 { 7 } else { 5 };
}
Ok(touches)
}
pub fn get_gesture(&mut self) -> Result<Gesture, I2C::Error> {
let touches = self.get_touches()?;
let state = &mut self.gesture_state;
if touches.len() > 1 {
state.is_touching = false;
return Ok(Gesture::None);
}
if touches.is_empty() {
if state.is_touching {
state.is_touching = false;
let dx = state.last_point.x as i32 - state.start_point.x as i32;
let dy = state.last_point.y as i32 - state.start_point.y as i32;
if dx.abs() > dy.abs() && dx.abs() > SWIPE_MIN_DISTANCE {
return Ok(if dx > 0 {
Gesture::SwipeRight
} else {
Gesture::SwipeLeft
});
} else if dy.abs() > dx.abs() && dy.abs() > SWIPE_MIN_DISTANCE {
return Ok(if dy > 0 {
Gesture::SwipeDown
} else {
Gesture::SwipeUp
});
}
}
return Ok(Gesture::None);
} else {
let point = touches[0];
if !state.is_touching {
state.is_touching = true;
state.start_point = point;
state.last_point = point;
} else {
state.last_point = point;
}
return Ok(Gesture::None);
}
}
}