Skip to main content

cirque_pinnacle/
mode.rs

1use crate::*;
2use embedded_hal::spi::SpiDevice;
3
4#[expect(clippy::struct_excessive_bools)]
5pub struct Relative {
6    /// Set to false to disable X.
7    ///
8    /// Disabling the X-axis will not allow regular tracking and is not recommended
9    /// for typical applications.
10    pub x: bool,
11
12    /// Set to false to disable Y.
13    ///
14    /// Disabling the Y-axis will not allow regular tracking and is not recommended
15    /// for typical applications.
16    pub y: bool,
17
18    /// Set to false to disable filter.
19    ///
20    /// The Filter disable bit controls whether the filtering algorithm is applied
21    /// to generated data. By default the hardware filters are enabled.
22    /// Cirque does not recommend disabling hardware filtering.
23    pub filter: bool,
24
25    /// Swap X & Y
26    pub swap_x_y: bool,
27
28    /// Enable GlideExtend®.
29    ///
30    /// GlideExtend is Cirque's patented motion extender technology that allows
31    /// the user to continue the drag function when an edge is reached, by lifting
32    /// and repositioning the finger.
33    pub glide_extend: bool,
34
35    /// Enable scroll.
36    pub scroll: bool,
37
38    /// Enable secondary tap.
39    ///
40    /// Secondary Taps allows a tap in the upper right corner (standard orientation)
41    /// to simulate an activation of the secondary button.
42    pub secondary_tap: bool,
43
44    /// If false, disables all taps.
45    ///
46    /// Disabling all taps disables secondary taps, even if secondary tap
47    /// is explicitly enabled.
48    pub taps: bool,
49
50    /// Enable Intellimouse.
51    ///
52    /// Intellimouse enabled will change Pinnacle's relative data packet to four bytes
53    /// rather than three. The fourth byte (PacketByte_3) will report scroll data
54    /// (referred to as wheel count).
55    pub intellimouse: bool,
56}
57
58impl Default for Relative {
59    fn default() -> Self {
60        Self {
61            x: true,
62            y: true,
63            filter: true,
64            swap_x_y: false,
65            glide_extend: false,
66            scroll: false,
67            secondary_tap: false,
68            taps: true,
69            intellimouse: false,
70        }
71    }
72}
73
74impl Relative {
75    pub fn init<S: SpiDevice<u8>>(&self, spi: S) -> Result<Touchpad<S, Self>, S::Error> {
76        let config1 =
77            1 | u8::from(!self.y) << 4 | u8::from(!self.x) << 3 | u8::from(!self.filter) << 2;
78        let config2 = u8::from(self.swap_x_y) << 7
79            | u8::from(!self.glide_extend) << 4
80            | u8::from(!self.scroll) << 3
81            | u8::from(!self.secondary_tap) << 2
82            | u8::from(!self.taps) << 1
83            | u8::from(self.intellimouse);
84        init(spi, config1, config2)
85    }
86}
87
88#[expect(clippy::struct_excessive_bools)]
89pub struct Absolute {
90    /// Set to false to disable X.
91    ///
92    /// Disabling the X-axis will not allow regular tracking and is not recommended
93    /// for typical applications.
94    pub x: bool,
95
96    /// Set to false to disable Y.
97    ///
98    /// Disabling the Y-axis will not allow regular tracking and is not recommended
99    /// for typical applications.
100    pub y: bool,
101
102    /// Set to false to disable filter.
103    ///
104    /// The Filter disable bit controls whether the filtering algorithm is applied
105    /// to generated data. By default the hardware filters are enabled.
106    /// Cirque does not recommend disabling hardware filtering.
107    pub filter: bool,
108
109    /// X data Invert.
110    ///
111    /// Y and X data count invert is only available when in absolute mode.
112    invert_x: bool,
113
114    /// Y data Invert.
115    ///
116    /// Y and X data count invert is only available when in absolute mode.
117    invert_y: bool,
118}
119
120impl Default for Absolute {
121    fn default() -> Self {
122        Self {
123            x: true,
124            y: true,
125            filter: true,
126            invert_x: false,
127            invert_y: false,
128        }
129    }
130}
131
132impl Absolute {
133    pub fn init<S: SpiDevice<u8>>(&self, spi: S) -> Result<Touchpad<S, Self>, S::Error> {
134        let config1 = 1
135            | u8::from(self.invert_y) << 7
136            | u8::from(self.invert_x) << 6
137            | u8::from(!self.y) << 4
138            | u8::from(!self.x) << 3
139            | u8::from(!self.filter) << 2
140            | 1 << 1;
141        let config2 = 0b11111; // disable all relative mode features;
142        init(spi, config1, config2)
143    }
144}
145
146pub trait Mode {}
147impl Mode for Relative {}
148impl Mode for Absolute {}
149
150fn init<M, S>(spi: S, config1: u8, config2: u8) -> Result<Touchpad<S, M>, S::Error>
151where
152    S: SpiDevice<u8>,
153    M: Mode,
154{
155    let mut pinnacle = Touchpad::new(spi);
156    pinnacle.clear_flags()?;
157    pinnacle.set_power_mode(PowerMode::Active)?;
158    pinnacle.write(FEED_CONFIG2_ADDR, config2)?;
159    pinnacle.write(FEED_CONFIG1_ADDR, config1)?;
160    Ok(pinnacle)
161}
162
163#[derive(Copy, Clone, Debug)]
164pub struct AbsoluteData {
165    pub x: u16,
166    pub y: u16,
167    pub z: u8,
168    pub button_flags: u8,
169}
170
171impl AbsoluteData {
172    pub const X_MIN: u16 = 0;
173    pub const Y_MIN: u16 = 0;
174    pub const X_MAX: u16 = 2047;
175    pub const Y_MAX: u16 = 1535;
176
177    #[must_use]
178    pub const fn touched(&self) -> bool {
179        self.z != 0
180    }
181
182    /// Represent X as f32 on the range from -1.0 to +1.0.
183    #[must_use]
184    pub fn x_f32(&self) -> f32 {
185        f32::from(self.x * 2) / f32::from(Self::X_MAX) - 1.0
186    }
187
188    /// Represent Y as f32 on the range from -1.0 to +1.0.
189    #[must_use]
190    pub fn y_f32(&self) -> f32 {
191        f32::from(self.y * 2) / f32::from(Self::Y_MAX) - 1.0
192    }
193}
194
195#[derive(Copy, Clone, Debug)]
196pub struct RelativeData {
197    pub x: i16,
198    pub y: i16,
199    pub wheel: i8,
200    pub buttons: Buttons,
201}
202
203#[derive(Copy, Clone, Debug)]
204pub struct Buttons {
205    /// BTN Primary (or tap).
206    pub primary: bool,
207    /// BTN Secondary (or top right corner tap).
208    pub secondary: bool,
209    /// BTN Auxiliary.
210    pub auxiliary: bool,
211}