cryptnox-pos 1.0.0
Standalone USDC payment terminal firmware (ESP32 + Cryptnox smart card)
Loading...
Searching...
No Matches
touch_cal.h
Go to the documentation of this file.
1/*
2 * SPDX-License-Identifier: LGPL-3.0-or-later
3 * Copyright (c) 2026 Cryptnox SA
4 */
5
21
22#ifndef TOUCH_CAL_H
23#define TOUCH_CAL_H
24
25#include <stdbool.h>
26#include <stdint.h>
27
28#ifdef __cplusplus
29extern "C" {
30#endif
31
33typedef struct {
34 uint16_t x_min;
35 uint16_t x_max;
36 uint16_t y_min;
37 uint16_t y_max;
39
59#define TOUCH_CAL_MIN_SPAN 500
61#define TOUCH_CAL_RAW_MAX 4095
62
63/* Extrapolating past a target that was tapped near the edge of the converter's
64 * range lands outside it. Clamped rather than rejected: the tap itself was
65 * fine, and a raw count the hardware can never report is simply an edge the
66 * finger can never reach. Unsigned underflow is the reason this exists at all —
67 * a -261 stored as 65275 inverts the axis. */
68static inline uint16_t touch_cal_clamp(int32_t v)
69{
70 if (v < 0) { return 0U; }
71 if (v > TOUCH_CAL_RAW_MAX) { return (uint16_t)TOUCH_CAL_RAW_MAX; }
72 return (uint16_t)v;
73}
74
75static inline bool touch_cal_from_corners(int16_t r0x, int16_t r0y,
76 int16_t r1x, int16_t r1y,
77 int16_t inset, int16_t w, int16_t h,
78 touch_cal_t *out)
79{
80 const int32_t span_x = (int32_t)(w - 1 - inset) - (int32_t)inset;
81 const int32_t span_y = (int32_t)(h - 1 - inset) - (int32_t)inset;
82 const int32_t dx = (int32_t)r1x - (int32_t)r0x;
83 const int32_t dy = (int32_t)r1y - (int32_t)r0y;
84
85 if ((out == NULL) || (span_x <= 0) || (span_y <= 0)) { return false; }
86 if ((dx < TOUCH_CAL_MIN_SPAN) || (dy < TOUCH_CAL_MIN_SPAN)) { return false; }
87
88 out->x_min = touch_cal_clamp((int32_t)r0x - ((dx * inset) / span_x));
89 out->x_max = touch_cal_clamp((int32_t)r1x + ((dx * inset) / span_x));
90 out->y_min = touch_cal_clamp((int32_t)r0y - ((dy * inset) / span_y));
91 out->y_max = touch_cal_clamp((int32_t)r1y + ((dy * inset) / span_y));
92 return true;
93}
94
135#define TOUCH_JUMP_MAX_PX 25
136
137/* How far z must rise above the lightest press of this touch to count as a
138 * second contact. A knob, deliberately: z is contact area and force as much as
139 * finger count, it differs between panels, and the only honest way to set it is
140 * to watch the "second contact:" line ui.cpp logs under a real thumb. Too low
141 * freezes hard taps, which costs nothing; too high lets the thumb through, which
142 * is the bug. Err low.
143 *
144 * 30 because the bench said so: on the CYD this was written against, z idles
145 * around 1900-2000 under one finger and a second contact stepped it 43% — which
146 * the 50 this started at sat just above, and missed. */
147#define TOUCH_Z_STEP_PCT 30
148
150typedef struct {
151 int16_t x;
152 int16_t y;
153 int16_t z_min;
154 bool have;
156
157static inline bool touch_jump_second_contact(const touch_jump_t *st,
158 int16_t z, int16_t x, int16_t y)
159{
160 const int32_t dx = (int32_t)x - (int32_t)st->x;
161 const int32_t dy = (int32_t)y - (int32_t)st->y;
162
163 if ((z > 0) && (st->z_min > 0)) {
164 const int32_t step = (int32_t)st->z_min +
165 (((int32_t)st->z_min * TOUCH_Z_STEP_PCT) / 100);
166 if ((int32_t)z > step) { return true; }
167 }
168 return ((dx * dx) + (dy * dy)) >
169 ((int32_t)TOUCH_JUMP_MAX_PX * (int32_t)TOUCH_JUMP_MAX_PX);
170}
171
172static inline void touch_jump_filter(touch_jump_t *st, bool pressed,
173 int16_t z, int16_t *x, int16_t *y)
174{
175 if (!pressed) { st->have = false; return; }
176
177 if (st->have) {
178 if (touch_jump_second_contact(st, z, *x, *y)) {
179 *x = st->x; /* hold the first finger's point */
180 *y = st->y;
181 return;
182 }
183 /* Track the lightest press, not the first: an operator who lands heavy
184 * and eases off would otherwise set a bar their own thumb fits under. */
185 if ((z > 0) && (z < st->z_min)) { st->z_min = z; }
186 } else {
187 st->z_min = z;
188 }
189
190 st->x = *x;
191 st->y = *y;
192 st->have = true;
193}
194
195#ifdef __cplusplus
196}
197#endif
198
199#endif /* TOUCH_CAL_H */
uint16_t y_max
Definition touch_cal.h:37
uint16_t x_min
Definition touch_cal.h:34
uint16_t x_max
Definition touch_cal.h:35
uint16_t y_min
Definition touch_cal.h:36
int16_t y
Definition touch_cal.h:152
int16_t z_min
Definition touch_cal.h:153
int16_t x
Definition touch_cal.h:151
static uint16_t touch_cal_clamp(int32_t v)
Definition touch_cal.h:68
#define TOUCH_CAL_MIN_SPAN
Solve the edge-to-edge raw range from two corner taps.
Definition touch_cal.h:59
#define TOUCH_CAL_RAW_MAX
Definition touch_cal.h:61
static void touch_jump_filter(touch_jump_t *st, bool pressed, int16_t z, int16_t *x, int16_t *y)
Definition touch_cal.h:172
#define TOUCH_JUMP_MAX_PX
Second-contact guard: hold the first finger's point while two are down.
Definition touch_cal.h:135
static bool touch_cal_from_corners(int16_t r0x, int16_t r0y, int16_t r1x, int16_t r1y, int16_t inset, int16_t w, int16_t h, touch_cal_t *out)
Definition touch_cal.h:75
#define TOUCH_Z_STEP_PCT
Definition touch_cal.h:147
static bool touch_jump_second_contact(const touch_jump_t *st, int16_t z, int16_t x, int16_t y)
Definition touch_cal.h:157