1#![no_std]
2
3use core::convert::Infallible;
6
7use embedded_hal::blocking::delay::DelayUs;
8use embedded_hal::blocking::i2c::{Write, WriteRead};
9use embedded_hal::digital::v2::InputPin;
10use embedded_time::duration::Microseconds;
11use embedded_time::{Clock, TimeError};
12use private::Sealed;
13
14pub struct I2CInterface<I2C> {
16 i2c: I2C,
17 addr: u8,
18}
19
20impl<I> I2CInterface<I>
21where
22 I: Write,
23{
24 pub fn new(i2c: I) -> Self {
26 Self::new_custom_address(i2c, 0x0A)
27 }
28
29 pub fn new_alternate_address(i2c: I) -> Self {
31 Self::new_custom_address(i2c, 0x0B)
32 }
33
34 pub fn new_custom_address(i2c: I, addr: u8) -> Self {
36 Self { i2c, addr }
37 }
38
39 pub fn release(self) -> I {
42 self.i2c
43 }
44}
45
46const SWITCH_STATE_MASK: u8 = 0b1000_0000;
47
48impl<I2C> I2CInterface<I2C>
49where
50 I2C: Write<Error = <I2C as WriteRead>::Error> + WriteRead,
51{
52 fn chip_id(&mut self) -> Result<u16, <I2C as Write>::Error> {
53 let mut bytes = [0u8; 2];
54 self.i2c.write_read(self.addr, &[CHIP_ID_L], &mut bytes)?;
55 let chip_id: u16 = u16::from_ne_bytes(bytes);
56 Ok(chip_id)
60 }
61
62 fn set_red(&mut self, val: u8) -> Result<(), <I2C as Write>::Error> {
63 self.i2c.write(self.addr, &[RED_REGISTER, val])
64 }
65
66 fn set_green(&mut self, val: u8) -> Result<(), <I2C as Write>::Error> {
67 self.i2c.write(self.addr, &[GREEN_REGISTER, val])
68 }
69
70 fn set_blue(&mut self, val: u8) -> Result<(), <I2C as Write>::Error> {
71 self.i2c.write(self.addr, &[BLUE_REGISTER, val])
72 }
73
74 fn set_white(&mut self, val: u8) -> Result<(), <I2C as Write>::Error> {
75 self.i2c.write(self.addr, &[WHITE_REGISTER, val])
76 }
77
78 fn get_interrupt(&mut self) -> Result<bool, <I2C as Write>::Error> {
79 let mut val = 0;
80 self.i2c.write_read(
81 self.addr,
82 &[WHITE_REGISTER],
83 core::slice::from_mut(&mut val),
84 )?;
85 Ok((val & INTERRUPT_TRIGGERED_MASK) > 0)
86 }
87}
88
89impl<I2C> I2CInterface<I2C>
90where
91 I2C: WriteRead,
92{
93 fn read(&mut self) -> Result<TrackballData, I2C::Error> {
94 let mut left = 0;
95 let mut right = 0;
96 let mut up = 0;
97 let mut down = 0;
98 let mut switch_state = 0;
99 self.i2c
100 .write_read(self.addr, &[LEFT], core::slice::from_mut(&mut left))?;
101 self.i2c
102 .write_read(self.addr, &[RIGHT], core::slice::from_mut(&mut right))?;
103 self.i2c
104 .write_read(self.addr, &[UP], core::slice::from_mut(&mut up))?;
105 self.i2c
106 .write_read(self.addr, &[DOWN], core::slice::from_mut(&mut down))?;
107 self.i2c.write_read(
108 self.addr,
109 &[SWITCH],
110 core::slice::from_mut(&mut switch_state),
111 )?;
112 let switch_changed = (switch_state & !SWITCH_STATE_MASK) > 0;
113 let switch_pressed = (switch_state & SWITCH_STATE_MASK) > 0;
114
115 Ok(TrackballData {
116 left,
117 right,
118 up,
119 down,
120 switch_changed,
121 switch_pressed,
122 })
123 }
124}
125
126const CHIP_ID: u16 = 0xBA11;
127#[allow(dead_code)]
128const VERSION: u8 = 1;
129const DEFAULT_TIMEOUT_US: u32 = 5;
130
131#[derive(Copy, Clone, Debug)]
133pub struct TrackballData {
134 pub left: u8,
136 pub right: u8,
138 pub up: u8,
140 pub down: u8,
142 pub switch_changed: bool,
144 pub switch_pressed: bool,
146}
147
148const RED_REGISTER: u8 = 0x00;
149const GREEN_REGISTER: u8 = 0x01;
150const BLUE_REGISTER: u8 = 0x02;
151const WHITE_REGISTER: u8 = 0x03;
152
153const LEFT: u8 = 0x04;
154const RIGHT: u8 = 0x05;
155const UP: u8 = 0x06;
156const DOWN: u8 = 0x07;
157const SWITCH: u8 = 0x08;
158
159#[allow(dead_code)]
160const USER_FLASH: u8 = 0xD0;
161#[allow(dead_code)]
162const FLASH_PAGE: u8 = 0xF0;
163const INTERRUPT: u8 = 0xF9;
164
165const CHIP_ID_L: u8 = 0xFA;
166#[allow(dead_code)]
167const CHIP_ID_H: u8 = 0xFB;
168#[allow(dead_code)]
169const VERSION_REG: u8 = 0xFC;
170const I2C_ADDR: u8 = 0xFD;
171#[allow(dead_code)]
172const CTRL: u8 = 0xFE;
173
174const INTERRUPT_OUT_ENABLE_MASK: u8 = 0b0000_0010;
175const INTERRUPT_TRIGGERED_MASK: u8 = 0b0000_0001;
176
177pub enum TrackballError<I, P> {
179 I2C(I),
181 Pin(P),
183 TimeError(TimeError),
185 ChipId,
187 Timeout,
189}
190
191impl<I, P> From<TimeError> for TrackballError<I, P> {
192 fn from(t: TimeError) -> Self {
193 Self::TimeError(t)
194 }
195}
196
197pub type TrackballResult<T, I, P = NoneT> =
199 Result<T, TrackballError<<I as Write>::Error, <P as OptionalPin>::Error>>;
200
201pub trait OptionalPin: Sealed {
203 type Error;
204}
205
206impl<T> Sealed for T where T: InputPin {}
208impl Sealed for NoneT {}
209
210impl<T> OptionalPin for T
212where
213 T: InputPin,
214{
215 type Error = <T as InputPin>::Error;
216}
217
218impl OptionalPin for NoneT {
220 type Error = Infallible;
221}
222
223mod private {
224 pub trait Sealed {}
226}
227
228pub struct NoneT;
231
232pub trait Interrupt: Sealed {
233 type I: Write;
234 type P: OptionalPin;
235
236 fn get_interrupt(&mut self) -> TrackballResult<bool, Self::I, Self::P>;
238
239 #[doc(hidden)]
240 fn setup_interrupt_mask(&mut self, value: &mut u8);
241
242 #[doc(hidden)]
243 fn process_enable_func<F>(&mut self, func: F)
244 where
245 F: for<'a> FnOnce(&'a mut Self::P);
246}
247
248pub struct TrackballBuilder<I, P = NoneT> {
250 i2c: I2CInterface<I>,
251 interrupt_pin: Option<P>,
252 timeout: u32,
253}
254
255impl<I> TrackballBuilder<I> {
256 pub fn new(i2c: I2CInterface<I>) -> Self {
258 Self {
259 i2c,
260 interrupt_pin: Some(NoneT),
261 timeout: DEFAULT_TIMEOUT_US,
262 }
263 }
264}
265
266impl<I, P> TrackballBuilder<I, P>
267where
268 P: InputPin,
269{
270 pub fn new(i2c: I2CInterface<I>) -> Self {
272 Self {
273 i2c,
274 interrupt_pin: None,
275 timeout: DEFAULT_TIMEOUT_US,
276 }
277 }
278
279 pub fn interrupt_pin(mut self, pin: P) -> Self {
281 self.interrupt_pin = Some(pin);
282 self
283 }
284}
285
286impl<I, P> TrackballBuilder<I, P> {
287 pub fn timeout(mut self, timeout: u32) -> Self {
290 self.timeout = timeout;
291 self
292 }
293
294 pub fn build(self) -> Trackball<I, P> {
296 Trackball {
297 i2c: self.i2c,
298 interrupt_pin: self.interrupt_pin.unwrap(),
299 timeout: self.timeout,
300 }
301 }
302}
303
304pub struct Trackball<I, P = NoneT> {
306 i2c: I2CInterface<I>,
307 interrupt_pin: P,
308 timeout: u32,
309}
310
311impl<I, P> Trackball<I, P>
312where
313 P: OptionalPin,
314 I: Write<Error = <I as WriteRead>::Error> + WriteRead,
315 Self: Interrupt<I = I, P = P>,
316{
317 pub fn init(
322 &mut self,
323 interrupt_enable_func: impl FnOnce(&mut P),
324 ) -> TrackballResult<(), I, P> {
325 let chip_id = self.i2c.chip_id().map_err(TrackballError::I2C)?;
326 if chip_id == CHIP_ID {
327 self.enable_interrupt(interrupt_enable_func)?;
328 Ok(())
329 } else {
330 Err(TrackballError::ChipId)
331 }
332 }
333
334 pub fn i2c(&mut self) -> &mut I {
336 &mut self.i2c.i2c
337 }
338
339 fn enable_interrupt(
340 &mut self,
341 interrupt_enable_func: impl for<'a> FnOnce(&'a mut P),
342 ) -> TrackballResult<(), I, P> {
343 let mut value = 0u8;
344 self.i2c
345 .i2c
346 .write_read(
347 self.i2c.addr,
348 &[INTERRUPT],
349 core::slice::from_mut(&mut value),
350 )
351 .map_err(TrackballError::I2C)?;
352 self.setup_interrupt_mask(&mut value);
353
354 let res = self
355 .i2c
356 .i2c
357 .write(self.i2c.addr, &[INTERRUPT, value])
358 .map_err(TrackballError::I2C);
359
360 self.process_enable_func(interrupt_enable_func);
361 res
362 }
363
364 pub fn set_rgbw(&mut self, r: u8, g: u8, b: u8, w: u8) -> Result<(), <I as Write>::Error> {
366 self.i2c.set_red(r)?;
367 self.i2c.set_green(g)?;
368 self.i2c.set_blue(b)?;
369 self.i2c.set_white(w)?;
370 Ok(())
371 }
372
373 #[inline]
375 pub fn set_red(&mut self, val: u8) -> Result<(), <I as Write>::Error> {
376 self.i2c.set_red(val)
377 }
378
379 #[inline]
381 pub fn set_green(&mut self, val: u8) -> Result<(), <I as Write>::Error> {
382 self.i2c.set_green(val)
383 }
384
385 #[inline]
387 pub fn set_blue(&mut self, val: u8) -> Result<(), <I as Write>::Error> {
388 self.i2c.set_blue(val)
389 }
390
391 #[inline]
393 pub fn set_white(&mut self, val: u8) -> Result<(), <I as Write>::Error> {
394 self.i2c.set_white(val)
395 }
396
397 #[inline]
399 pub fn read(&mut self) -> Result<TrackballData, <I as Write>::Error> {
400 self.i2c.read()
401 }
402
403 pub fn change_address<C, De>(
409 &mut self,
410 new_address: u8,
411 clock: &mut C,
412 delay: &mut De,
413 ) -> TrackballResult<(), I, P>
414 where
415 C: Clock,
416 De: DelayUs<u8>,
417 <C as Clock>::T: From<u32>,
418 {
419 self.i2c
420 .i2c
421 .write(self.i2c.addr, &[I2C_ADDR, new_address])
422 .map_err(TrackballError::I2C)?;
423 self.wait_for_flash(clock, delay)?;
424 Ok(())
425 }
426
427 fn wait_for_flash<C, De>(&mut self, clock: &mut C, delay: &mut De) -> TrackballResult<(), I, P>
428 where
429 C: Clock,
430 De: DelayUs<u8>,
431 <C as Clock>::T: From<u32>,
432 {
433 let timer = clock.new_timer(Microseconds(self.timeout));
434 let timer = timer.start()?;
435 while self.get_interrupt()? {
436 if timer.is_expired()? {
437 return Err(TrackballError::Timeout);
438 }
439 delay.delay_us(1u8);
440 }
441
442 let timer = clock.new_timer(Microseconds(self.timeout));
443 let timer = timer.start()?;
444 while !self.get_interrupt()? {
445 if timer.is_expired()? {
446 return Err(TrackballError::Timeout);
447 }
448 delay.delay_us(1u8);
449 }
450 Ok(())
451 }
452}
453
454impl<I, P> Sealed for Trackball<I, P> {}
455
456impl<I, P> Interrupt for Trackball<I, P>
457where
458 P: InputPin,
459 I: Write<Error = <I as WriteRead>::Error> + WriteRead,
460{
461 type I = I;
462 type P = P;
463
464 fn get_interrupt(&mut self) -> TrackballResult<bool, I, P> {
465 self.interrupt_pin.is_low().map_err(TrackballError::Pin)
466 }
467
468 #[inline]
469 fn setup_interrupt_mask(&mut self, value: &mut u8) {
470 *value |= INTERRUPT_OUT_ENABLE_MASK;
471 }
472
473 #[inline]
474 fn process_enable_func<F>(&mut self, interrupt_enable_func: F)
475 where
476 F: for<'a> FnOnce(&'a mut Self::P),
477 {
478 (interrupt_enable_func)(&mut self.interrupt_pin)
479 }
480}
481impl<I, P> Trackball<I, P>
482where
483 P: InputPin,
484 I: Write<Error = <I as WriteRead>::Error> + WriteRead,
485{
486 pub fn interrupt(&mut self) -> &mut P {
488 &mut self.interrupt_pin
489 }
490}
491
492impl<I> Interrupt for Trackball<I>
493where
494 I: Write<Error = <I as WriteRead>::Error> + WriteRead,
495{
496 type I = I;
497 type P = NoneT;
498
499 fn get_interrupt(&mut self) -> TrackballResult<bool, I> {
501 self.i2c.get_interrupt().map_err(TrackballError::I2C)
502 }
503
504 #[inline]
505 fn setup_interrupt_mask(&mut self, value: &mut u8) {
506 *value &= !INTERRUPT_OUT_ENABLE_MASK;
507 }
508
509 #[inline]
510 fn process_enable_func<F>(&mut self, _: F)
511 where
512 F: for<'a> FnOnce(&'a mut Self::P),
513 {
514 }
516}