TinyGPU
Loading...
Searching...
No Matches
TouchDriverCommon.h
Go to the documentation of this file.
1#pragma once
2/**
3 * @file TouchDriver.h
4 * @brief Platform-independent touch driver interface: the Point/
5 * CalibrationData/Rotation types, the TouchDriver base class (calibration
6 * storage, raw-to-logical coordinate mapping) and nothing else - this file
7 * has no dependency on Arduino.h or any bus library, so including it (e.g.
8 * transitively via TinyGPU.h) never requires linking against an Arduino
9 * core.
10 *
11 * Concrete controller drivers (XPT2046, FT6236/FT6206, CST816S, GT911),
12 * which do need Arduino.h/SPI.h/Wire.h, live in the separate
13 * TouchDriverArduino.h - include that explicitly to use one of them.
14 */
15
16#include <stdint.h>
17
18namespace tinygpu {
19
20/**
21 * @brief Logical display rotation.
22 */
23enum class Rotation : uint8_t { Deg0 = 0, Deg90 = 1, Deg180 = 2, Deg270 = 3 };
24
25/**
26 * @brief Touch point.
27 *
28 * pressure semantics:
29 * - XPT2046: estimated Z/pressure-related value, 0..4095
30 * - Capacitive controllers: 255 while touched
31 */
32struct Point {
33 int16_t x = 0;
34 int16_t y = 0;
35 uint16_t pressure = 0;
36
37 bool operator==(const Point& other) const {
38 return x == other.x && y == other.y;
39 }
40
41 bool operator!=(const Point& other) const { return !(*this == other); }
42};
43
44/**
45 * @brief Touch calibration configuration.
46 *
47 * rawXMin/rawXMax and rawYMin/rawYMax describe the raw controller
48 * coordinate ranges.
49 *
50 * screenWidth/screenHeight describe the unrotated display dimensions.
51 *
52 * swapXY is applied AFTER raw X/Y calibration. This is important when
53 * the X and Y calibration ranges differ.
54 */
56 int16_t rawXMin = 300;
57 int16_t rawXMax = 3800;
58 int16_t rawYMin = 300;
59 int16_t rawYMax = 3800;
60
61 uint16_t screenWidth = 240;
62 uint16_t screenHeight = 320;
63
64 bool invertX = false;
65 bool invertY = false;
66 bool swapXY = false;
67};
68
69/**
70 * @brief Base class for touch controllers.
71 */
73 public:
74 virtual ~TouchDriver() = default;
75
76 /**
77 * @brief Initialize the controller.
78 *
79 * The driver does NOT initialize the SPI/I2C bus itself.
80 * The application is responsible for calling Wire.begin(), SPI.begin(),
81 * and configuring any board-specific bus pins.
82 */
83 virtual bool begin() = 0;
84
85 /**
86 * @brief Return whether the panel currently appears touched.
87 *
88 * For controllers without an IRQ pin this may perform a controller read.
89 */
90 virtual bool isTouched() = 0;
91
92 /**
93 * @brief Read the current touch point.
94 *
95 * @return true if a valid touch point was obtained.
96 */
97 virtual bool getPoint(Point& outPoint) = 0;
98
99 /**
100 * @brief Read a second, simultaneous touch point, for multi-touch
101 * gestures (pinch/rotate).
102 *
103 * Returns false by default. Only override this if the underlying
104 * controller can genuinely report two simultaneous touches - none of
105 * the drivers built into this library can (XPT2046 is a resistive,
106 * inherently single-touch controller; CST816S/FT6236 are single-touch
107 * capacitive parts), so pinch/rotate gestures built on top of this will
108 * not fire against them.
109 */
110 virtual bool getSecondPoint(Point& outPoint) { return false; }
111
112 void setRotation(Rotation rotation) { rotation_ = rotation; }
113
114 Rotation getRotation() const { return rotation_; }
115
116 /**
117 * @brief Set and validate calibration.
118 *
119 * @return true if the calibration is valid.
120 */
122 if (!validateCalibration(cal)) {
123 return false;
124 }
125
126 calibration_ = cal;
127 hasCalibration_ = true;
128 return true;
129 }
130
131 const CalibrationData& getCalibration() const { return calibration_; }
132
133 bool hasCalibration() const { return hasCalibration_; }
134
135 protected:
138 bool hasCalibration_ = false;
139
140 static bool validateCalibration(const CalibrationData& cal) {
141 if (cal.rawXMin >= cal.rawXMax) {
142 return false;
143 }
144
145 if (cal.rawYMin >= cal.rawYMax) {
146 return false;
147 }
148
149 if (cal.screenWidth == 0 || cal.screenHeight == 0) {
150 return false;
151 }
152
153 return true;
154 }
155
156 /**
157 * @brief Clamp an integer to an inclusive range.
158 */
159 static int32_t clamp32(int32_t value, int32_t minimum, int32_t maximum) {
160 if (value < minimum) {
161 return minimum;
162 }
163
164 if (value > maximum) {
165 return maximum;
166 }
167
168 return value;
169 }
170
171 /**
172 * @brief Map an integer from one range to another.
173 *
174 * Unlike Arduino's map(), this function:
175 * - uses 64-bit intermediate arithmetic
176 * - explicitly handles invalid ranges
177 * - avoids accidental overflow for normal touch-controller ranges
178 */
179 static int32_t mapRange(int32_t value, int32_t inMin, int32_t inMax,
180 int32_t outMin, int32_t outMax) {
181 if (inMin == inMax) {
182 return outMin;
183 }
184
185 const int64_t numerator = static_cast<int64_t>(value - inMin) *
186 static_cast<int64_t>(outMax - outMin);
187
188 const int64_t denominator = static_cast<int64_t>(inMax - inMin);
189
190 return static_cast<int32_t>(outMin + numerator / denominator);
191 }
192
193 /**
194 * @brief Convert raw controller coordinates into logical display space.
195 *
196 * Processing order:
197 *
198 * raw coordinates
199 * -> inversion
200 * -> independent X/Y calibration
201 * -> swap XY
202 * -> display rotation
203 *
204 * This order is important. In particular, swapping raw X/Y before
205 * calibration would incorrectly apply the X calibration range to Y
206 * and vice versa.
207 */
208 Point mapCoordinates(int16_t rawX, int16_t rawY,
209 uint16_t pressure = 255) const {
210 if (!hasCalibration_) {
211 return applyRotation(rawX, rawY, pressure, false);
212 }
213
214 int32_t x = rawX;
215 int32_t y = rawY;
216
217 /*
218 * Inversion is performed in raw/controller space.
219 *
220 * Clamp first so a slightly out-of-range controller reading cannot
221 * produce surprising inverted values.
222 */
224
226
229 }
230
233 }
234
235 /*
236 * IMPORTANT:
237 *
238 * Map X against X calibration and Y against Y calibration BEFORE
239 * swapping axes.
240 */
241 int32_t mappedX =
243 static_cast<int32_t>(calibration_.screenWidth) - 1);
244
245 int32_t mappedY =
247 static_cast<int32_t>(calibration_.screenHeight) - 1);
248
249 mappedX =
250 clamp32(mappedX, 0, static_cast<int32_t>(calibration_.screenWidth) - 1);
251
252 mappedY = clamp32(mappedY, 0,
253 static_cast<int32_t>(calibration_.screenHeight) - 1);
254
255 /*
256 * Swap logical axes after calibration.
257 */
259 const int32_t tmp = mappedX;
260 mappedX = mappedY;
261 mappedY = tmp;
262 }
263
264 return applyRotation(mappedX, mappedY, pressure, true);
265 }
266
267 private:
268 Point applyRotation(int32_t x, int32_t y, uint16_t pressure,
269 bool calibrated) const {
270 if (!calibrated) {
271 return {static_cast<int16_t>(x), static_cast<int16_t>(y), pressure};
272 }
273
274 const int32_t width = static_cast<int32_t>(calibration_.screenWidth);
275
276 const int32_t height = static_cast<int32_t>(calibration_.screenHeight);
277
278 int32_t finalX = x;
279 int32_t finalY = y;
280
281 switch (rotation_) {
282 case Rotation::Deg0:
283 break;
284
285 case Rotation::Deg90:
286 /*
287 * Unrotated:
288 * X = [0, width-1]
289 * Y = [0, height-1]
290 *
291 * Rotated:
292 * X = [0, height-1]
293 * Y = [0, width-1]
294 */
295 finalX = height - 1 - y;
296 finalY = x;
297 break;
298
299 case Rotation::Deg180:
300 finalX = width - 1 - x;
301 finalY = height - 1 - y;
302 break;
303
304 case Rotation::Deg270:
305 finalX = y;
306 finalY = width - 1 - x;
307 break;
308 }
309
310 return {static_cast<int16_t>(finalX), static_cast<int16_t>(finalY),
311 pressure};
312 }
313};
314
315} // namespace tinygpu
Base class for touch controllers.
Definition: TouchDriverCommon.h:72
static bool validateCalibration(const CalibrationData &cal)
Definition: TouchDriverCommon.h:140
CalibrationData calibration_
Definition: TouchDriverCommon.h:137
virtual bool isTouched()=0
Return whether the panel currently appears touched.
static int32_t mapRange(int32_t value, int32_t inMin, int32_t inMax, int32_t outMin, int32_t outMax)
Map an integer from one range to another.
Definition: TouchDriverCommon.h:179
bool setCalibration(const CalibrationData &cal)
Set and validate calibration.
Definition: TouchDriverCommon.h:121
Point mapCoordinates(int16_t rawX, int16_t rawY, uint16_t pressure=255) const
Convert raw controller coordinates into logical display space.
Definition: TouchDriverCommon.h:208
bool hasCalibration_
Definition: TouchDriverCommon.h:138
virtual bool getPoint(Point &outPoint)=0
Read the current touch point.
Rotation getRotation() const
Definition: TouchDriverCommon.h:114
const CalibrationData & getCalibration() const
Definition: TouchDriverCommon.h:131
static int32_t clamp32(int32_t value, int32_t minimum, int32_t maximum)
Clamp an integer to an inclusive range.
Definition: TouchDriverCommon.h:159
virtual bool getSecondPoint(Point &outPoint)
Read a second, simultaneous touch point, for multi-touch gestures (pinch/rotate).
Definition: TouchDriverCommon.h:110
void setRotation(Rotation rotation)
Definition: TouchDriverCommon.h:112
virtual ~TouchDriver()=default
bool hasCalibration() const
Definition: TouchDriverCommon.h:133
virtual bool begin()=0
Initialize the controller.
Rotation rotation_
Definition: TouchDriverCommon.h:136
Definition: DSIBusESP32.h:19
Rotation
Logical display rotation.
Definition: TouchDriverCommon.h:23
Touch calibration configuration.
Definition: TouchDriverCommon.h:55
int16_t rawXMax
Definition: TouchDriverCommon.h:57
bool swapXY
Definition: TouchDriverCommon.h:66
bool invertY
Definition: TouchDriverCommon.h:65
int16_t rawYMin
Definition: TouchDriverCommon.h:58
uint16_t screenWidth
Definition: TouchDriverCommon.h:61
uint16_t screenHeight
Definition: TouchDriverCommon.h:62
int16_t rawYMax
Definition: TouchDriverCommon.h:59
int16_t rawXMin
Definition: TouchDriverCommon.h:56
bool invertX
Definition: TouchDriverCommon.h:64
Touch point.
Definition: TouchDriverCommon.h:32
bool operator!=(const Point &other) const
Definition: TouchDriverCommon.h:41
uint16_t pressure
Definition: TouchDriverCommon.h:35
int16_t x
Definition: TouchDriverCommon.h:33
bool operator==(const Point &other) const
Definition: TouchDriverCommon.h:37
int16_t y
Definition: TouchDriverCommon.h:34