1#![allow(non_camel_case_types)]
26
27use core::cell::Cell;
28use enum_primitive::cast::FromPrimitive;
29use enum_primitive::enum_from_primitive;
30use kernel::hil::gpio;
31use kernel::hil::i2c;
32use kernel::hil::touch::{self, GestureEvent, TouchEvent, TouchStatus};
33use kernel::utilities::cells::{OptionalCell, TakeCell};
34use kernel::ErrorCode;
35
36pub static NO_TOUCH: TouchEvent = TouchEvent {
37 id: 0,
38 x: 0,
39 y: 0,
40 status: TouchStatus::Released,
41 size: None,
42 pressure: None,
43};
44
45enum_from_primitive! {
46 enum Registers {
47 REG_GEST_ID = 0x01,
48 REG_TD_STATUS = 0x02,
49 REG_CHIPID = 0xA3,
50 }
51}
52
53pub struct Ft6x06<'a, I: i2c::I2CDevice> {
54 i2c: &'a I,
55 interrupt_pin: &'a dyn gpio::InterruptPin<'a>,
56 touch_client: OptionalCell<&'a dyn touch::TouchClient>,
57 gesture_client: OptionalCell<&'a dyn touch::GestureClient>,
58 multi_touch_client: OptionalCell<&'a dyn touch::MultiTouchClient>,
59 num_touches: Cell<usize>,
60 buffer: TakeCell<'static, [u8]>,
61 events: TakeCell<'static, [TouchEvent]>,
62}
63
64impl<'a, I: i2c::I2CDevice> Ft6x06<'a, I> {
65 pub fn new(
66 i2c: &'a I,
67 interrupt_pin: &'a dyn gpio::InterruptPin<'a>,
68 buffer: &'static mut [u8],
69 events: &'static mut [TouchEvent],
70 ) -> Ft6x06<'a, I> {
71 interrupt_pin.enable_interrupts(gpio::InterruptEdge::FallingEdge);
73 Ft6x06 {
74 i2c,
75 interrupt_pin,
76 touch_client: OptionalCell::empty(),
77 gesture_client: OptionalCell::empty(),
78 multi_touch_client: OptionalCell::empty(),
79 num_touches: Cell::new(0),
80 buffer: TakeCell::new(buffer),
81 events: TakeCell::new(events),
82 }
83 }
84}
85
86impl<I: i2c::I2CDevice> i2c::I2CClient for Ft6x06<'_, I> {
87 fn command_complete(&self, buffer: &'static mut [u8], _status: Result<(), i2c::Error>) {
88 self.num_touches.set((buffer[1] & 0x0F) as usize);
89 self.touch_client.map(|client| {
90 if self.num_touches.get() <= 2 {
91 let status = match buffer[2] >> 6 {
92 0x00 => Some(TouchStatus::Pressed),
93 0x01 => Some(TouchStatus::Released),
94 0x02 => Some(TouchStatus::Moved),
95 _ => None,
96 };
97 if let Some(status) = status {
98 let x = (((buffer[2] & 0x0F) as u16) << 8) + (buffer[3] as u16);
99 let y = (((buffer[4] & 0x0F) as u16) << 8) + (buffer[5] as u16);
100 let pressure = Some(buffer[6] as u16);
101 let size = Some(buffer[7] as u16);
102 client.touch_event(TouchEvent {
103 status,
104 x,
105 y,
106 id: 0,
107 pressure,
108 size,
109 });
110 }
111 }
112 });
113 self.gesture_client.map(|client| {
114 if self.num_touches.get() <= 2 {
115 let gesture_event = match buffer[0] {
116 0x10 => Some(GestureEvent::SwipeUp),
117 0x14 => Some(GestureEvent::SwipeRight),
118 0x18 => Some(GestureEvent::SwipeDown),
119 0x1C => Some(GestureEvent::SwipeLeft),
120 0x48 => Some(GestureEvent::ZoomIn),
121 0x49 => Some(GestureEvent::ZoomOut),
122 _ => None,
123 };
124 if let Some(gesture) = gesture_event {
125 client.gesture_event(gesture);
126 }
127 }
128 });
129 self.multi_touch_client.map(|client| {
130 if self.num_touches.get() <= 2 {
131 let mut num_touches = 0;
132 for touch_event in 0..2 {
133 let status = match buffer[touch_event * 6 + 2] >> 6 {
134 0x00 => Some(TouchStatus::Pressed),
135 0x01 => Some(TouchStatus::Released),
136 0x02 => Some(TouchStatus::Moved),
137 _ => None,
138 };
139 if let Some(status) = status {
140 let x = (((buffer[touch_event * 6 + 2] & 0x0F) as u16) << 8)
141 + (buffer[touch_event * 6 + 3] as u16);
142 let y = (((buffer[touch_event * 6 + 4] & 0x0F) as u16) << 8)
143 + (buffer[touch_event * 6 + 5] as u16);
144 let pressure = Some(buffer[touch_event * 6 + 6] as u16);
145 let size = Some(buffer[touch_event * 6 + 7] as u16);
146 let id = (buffer[touch_event * 6 + 4] >> 4) as usize;
147 self.events.map(|buffer| {
148 buffer[num_touches] = TouchEvent {
149 status,
150 x,
151 y,
152 id,
153 size,
154 pressure,
155 };
156 });
157 num_touches += 1;
158 }
159 }
160 self.events.map(|buffer| {
161 client.touch_events(buffer, num_touches);
162 });
163 }
164 });
165 self.buffer.replace(buffer);
166 self.interrupt_pin
167 .enable_interrupts(gpio::InterruptEdge::FallingEdge);
168 }
169}
170
171impl<I: i2c::I2CDevice> gpio::Client for Ft6x06<'_, I> {
172 fn fired(&self) {
173 self.buffer.take().map(|buffer| {
174 self.interrupt_pin.disable_interrupts();
175
176 buffer[0] = Registers::REG_GEST_ID as u8;
177
178 match self.i2c.write_read(buffer, 1, 15) {
179 Ok(()) => {}
180 Err((_err, buffer)) => {
181 self.buffer.replace(buffer);
182 self.interrupt_pin
183 .enable_interrupts(gpio::InterruptEdge::FallingEdge);
184 }
185 }
186 });
187 }
188}
189
190impl<'a, I: i2c::I2CDevice> touch::Touch<'a> for Ft6x06<'a, I> {
191 fn enable(&self) -> Result<(), ErrorCode> {
192 Ok(())
193 }
194
195 fn disable(&self) -> Result<(), ErrorCode> {
196 Ok(())
197 }
198
199 fn set_client(&self, client: &'a dyn touch::TouchClient) {
200 self.touch_client.replace(client);
201 }
202}
203
204impl<'a, I: i2c::I2CDevice> touch::Gesture<'a> for Ft6x06<'a, I> {
205 fn set_client(&self, client: &'a dyn touch::GestureClient) {
206 self.gesture_client.replace(client);
207 }
208}
209
210impl<'a, I: i2c::I2CDevice> touch::MultiTouch<'a> for Ft6x06<'a, I> {
211 fn enable(&self) -> Result<(), ErrorCode> {
212 Ok(())
213 }
214
215 fn disable(&self) -> Result<(), ErrorCode> {
216 Ok(())
217 }
218
219 fn get_num_touches(&self) -> usize {
220 2
221 }
222
223 fn get_touch(&self, index: usize) -> Option<TouchEvent> {
224 self.buffer.map_or(None, |buffer| {
225 if index <= self.num_touches.get() {
226 let offset = index * 7;
228 let status = match buffer[offset + 1] >> 6 {
229 0x00 => TouchStatus::Pressed,
230 0x01 => TouchStatus::Released,
231 0x02 => TouchStatus::Moved,
232 _ => TouchStatus::Released,
233 };
234 let x = (((buffer[offset + 2] & 0x0F) as u16) << 8) + (buffer[offset + 3] as u16);
235 let y = (((buffer[offset + 4] & 0x0F) as u16) << 8) + (buffer[offset + 5] as u16);
236 let pressure = Some(buffer[offset + 6] as u16);
237 let size = Some(buffer[offset + 7] as u16);
238 Some(TouchEvent {
239 status,
240 x,
241 y,
242 id: 0,
243 pressure,
244 size,
245 })
246 } else {
247 None
248 }
249 })
250 }
251
252 fn set_client(&self, client: &'a dyn touch::MultiTouchClient) {
253 self.multi_touch_client.replace(client);
254 }
255}