1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
#include "touch.h"
#include <stdint.h>
#include "driver/i2c_master.h"
#include "esp_check.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "display.h"
#include "local_screens.h"
#include "nvs_config.h"
#include "state_machine.h"
#include "viewport_state.h"
static const char *TAG = "touch";
#define FT5426_ADDR 0x38
#define FT5426_I2C_FREQ_HZ 400000
#define FT_REG_DEV_MODE 0x00
#define FT_REG_TD_STATUS 0x02
#define FT_REG_P1_XH 0x03
#define POLL_PERIOD_MS 30
#define TAP_MAX_MS 500 // < this on release = short tap (toggle)
#define LONG_PRESS_MS 1500 // ≥ this while held = identity overlay
#define FACTORY_RESET_MS 5000 // ≥ this while held = factory reset
#define OVERLAY_MS 15000
#define TAP_DEBOUNCE_MS 150
static i2c_master_dev_handle_t s_dev;
static TaskHandle_t s_task;
static esp_err_t ft_read(uint8_t reg, uint8_t *buf, size_t n)
{
return i2c_master_transmit_receive(s_dev, ®, 1, buf, n, 50);
}
static void on_short_tap(void)
{
if (local_screens_overlay_active()) local_screens_overlay_dismiss();
viewport_run_state_t target =
(state_machine_current() == VIEWPORT_STATE_AWAKE)
? VIEWPORT_STATE_ASLEEP
: VIEWPORT_STATE_AWAKE;
ESP_LOGI(TAG, "tap -> %s", target == VIEWPORT_STATE_AWAKE ? "wake" : "sleep");
state_machine_set_local(target);
}
static void on_long_press(void)
{
ESP_LOGI(TAG, "long-press → identity overlay for %dms", OVERLAY_MS);
if (display_is_up()) local_screens_overlay(OVERLAY_MS);
}
static void on_factory_reset(void)
{
ESP_LOGW(TAG, "very-long-press %dms → factory reset", FACTORY_RESET_MS);
nvs_config_reset();
vTaskDelay(pdMS_TO_TICKS(200));
esp_restart();
}
static void touch_task(void *arg)
{
bool was_down = false;
uint64_t down_us = 0;
bool long_fired = false;
bool reset_fired = false;
uint64_t last_tap_us = 0;
uint8_t buf[7];
for (;;) {
vTaskDelay(pdMS_TO_TICKS(POLL_PERIOD_MS));
if (ft_read(FT_REG_DEV_MODE, buf, sizeof(buf)) != ESP_OK) continue;
uint8_t touches = buf[FT_REG_TD_STATUS] & 0x0F;
uint64_t now = (uint64_t)esp_timer_get_time();
if (touches > 0) {
if (!was_down) {
was_down = true;
down_us = now;
long_fired = false;
reset_fired = false;
} else {
uint64_t held_ms = (now - down_us) / 1000ULL;
if (!long_fired && held_ms >= LONG_PRESS_MS) {
long_fired = true;
on_long_press();
}
if (!reset_fired && held_ms >= FACTORY_RESET_MS) {
reset_fired = true;
on_factory_reset(); // does not return
}
}
} else if (was_down) {
was_down = false;
uint64_t held_ms = (now - down_us) / 1000ULL;
if (now - last_tap_us < (uint64_t)TAP_DEBOUNCE_MS * 1000ULL) continue;
// Short tap only fires on release; long-press already fired
// while the finger was still down.
if (!long_fired && held_ms > 0 && held_ms <= TAP_MAX_MS) {
last_tap_us = now;
on_short_tap();
}
}
}
}
esp_err_t touch_init(void)
{
i2c_master_bus_handle_t bus = display_i2c_bus();
if (!bus) {
ESP_LOGW(TAG, "I2C bus unavailable — display didn't come up; skipping touch");
return ESP_ERR_INVALID_STATE;
}
i2c_device_config_t cfg = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = FT5426_ADDR,
.scl_speed_hz = FT5426_I2C_FREQ_HZ,
};
ESP_RETURN_ON_ERROR(i2c_master_bus_add_device(bus, &cfg, &s_dev),
TAG, "i2c add FT5426");
uint8_t dev_mode = 0;
esp_err_t err = ft_read(FT_REG_DEV_MODE, &dev_mode, 1);
if (err != ESP_OK) {
ESP_LOGE(TAG, "FT5426 @0x38 unreachable (%s)", esp_err_to_name(err));
return err;
}
ESP_LOGI(TAG, "FT5426 ack'd (dev_mode=0x%02x); "
"tap=toggle, %dms hold=ID overlay, %dms hold=factory reset",
dev_mode, LONG_PRESS_MS, FACTORY_RESET_MS);
BaseType_t ok = xTaskCreate(touch_task, "touch", 3072, NULL, 4, &s_task);
return (ok == pdPASS) ? ESP_OK : ESP_FAIL;
}
|