mirror of
https://github.com/pelgraine/Meck.git
synced 2026-06-27 05:11:13 +02:00
332 lines
9.4 KiB
C++
332 lines
9.4 KiB
C++
#if defined(LilyGo_TDeck_Pro_Max)
|
|
// Meck: MAX-only build guard. Board include TDeckMaxBoard.h -> HynTouchBoard.h.
|
|
#include "HynTouch.h"
|
|
|
|
#include <driver/gpio.h>
|
|
#include <esp_err.h>
|
|
#include <esp_log.h>
|
|
|
|
#include <cstring>
|
|
|
|
#include "HynTouchBoard.h"
|
|
|
|
#include "hyn_core.h"
|
|
|
|
#ifndef HYN_TOUCH_RUNTIME_LOG
|
|
#define HYN_TOUCH_RUNTIME_LOG 0
|
|
#endif
|
|
|
|
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
|
|
|
namespace {
|
|
|
|
constexpr const char *kTag = "HynTouch";
|
|
|
|
struct HynTouchRuntime {
|
|
HynTouchConfig config = {};
|
|
struct hyn_ts_data *data = nullptr;
|
|
volatile bool press_flag = false;
|
|
bool ready = false;
|
|
bool isr_attached = false;
|
|
int attached_irq = -1;
|
|
bool key_pressed[3] = {false, false, false};
|
|
bool key_seen[3] = {false, false, false};
|
|
HynTouchKeyCallback key_callback = nullptr;
|
|
void *key_callback_user_data = nullptr;
|
|
};
|
|
|
|
HynTouchRuntime g_touch;
|
|
|
|
void clear_key_state()
|
|
{
|
|
memset(g_touch.key_pressed, 0, sizeof(g_touch.key_pressed));
|
|
memset(g_touch.key_seen, 0, sizeof(g_touch.key_seen));
|
|
}
|
|
|
|
void apply_axis_transform(uint8_t point_count)
|
|
{
|
|
if (!g_touch.data) {
|
|
return;
|
|
}
|
|
|
|
for (u8 i = 0; i < point_count; ++i) {
|
|
if (g_touch.data->plat_data.swap_xy) {
|
|
u16 tmp = g_touch.data->rp_buf.pos_info[i].pos_x;
|
|
g_touch.data->rp_buf.pos_info[i].pos_x = g_touch.data->rp_buf.pos_info[i].pos_y;
|
|
g_touch.data->rp_buf.pos_info[i].pos_y = tmp;
|
|
}
|
|
if (g_touch.data->plat_data.reverse_x) {
|
|
g_touch.data->rp_buf.pos_info[i].pos_x =
|
|
g_touch.data->plat_data.x_resolution - g_touch.data->rp_buf.pos_info[i].pos_x;
|
|
}
|
|
if (g_touch.data->plat_data.reverse_y) {
|
|
g_touch.data->rp_buf.pos_info[i].pos_y =
|
|
g_touch.data->plat_data.y_resolution - g_touch.data->rp_buf.pos_info[i].pos_y;
|
|
}
|
|
}
|
|
}
|
|
|
|
void handle_key_report()
|
|
{
|
|
if (!g_touch.data || (g_touch.data->rp_buf.report_need & REPORT_KEY) == 0) {
|
|
return;
|
|
}
|
|
|
|
const int key_id = g_touch.data->rp_buf.key_id;
|
|
if (key_id < 0 || key_id >= 3) {
|
|
return;
|
|
}
|
|
|
|
const bool pressed = g_touch.data->rp_buf.key_state == 1;
|
|
if (pressed) {
|
|
g_touch.key_seen[key_id] = true;
|
|
}
|
|
|
|
if (g_touch.key_pressed[key_id] == pressed) {
|
|
return;
|
|
}
|
|
|
|
g_touch.key_pressed[key_id] = pressed;
|
|
if (g_touch.key_callback) {
|
|
g_touch.key_callback((uint8_t)key_id, pressed, g_touch.key_callback_user_data);
|
|
}
|
|
}
|
|
|
|
void IRAM_ATTR gpio_isr_handler(void *arg)
|
|
{
|
|
(void)arg;
|
|
g_touch.press_flag = true;
|
|
}
|
|
|
|
bool configure_irq_gpio(int irq_pin)
|
|
{
|
|
if (irq_pin < 0) {
|
|
ESP_LOGE(kTag, "Invalid touch IRQ pin: %d", irq_pin);
|
|
return false;
|
|
}
|
|
|
|
gpio_config_t io_conf = {};
|
|
io_conf.intr_type = GPIO_INTR_NEGEDGE;
|
|
io_conf.pin_bit_mask = (1ULL << irq_pin);
|
|
io_conf.mode = GPIO_MODE_INPUT;
|
|
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
|
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
|
if (gpio_config(&io_conf) != ESP_OK) {
|
|
ESP_LOGE(kTag, "Failed to configure touch IRQ pin %d", irq_pin);
|
|
return false;
|
|
}
|
|
|
|
esp_err_t isr_ret = gpio_install_isr_service(0);
|
|
if (isr_ret != ESP_OK && isr_ret != ESP_ERR_INVALID_STATE) {
|
|
ESP_LOGE(kTag, "gpio_install_isr_service failed: %s", esp_err_to_name(isr_ret));
|
|
return false;
|
|
}
|
|
|
|
if (g_touch.isr_attached && g_touch.attached_irq >= 0) {
|
|
gpio_isr_handler_remove((gpio_num_t)g_touch.attached_irq);
|
|
}
|
|
|
|
esp_err_t handler_ret = gpio_isr_handler_add((gpio_num_t)irq_pin, gpio_isr_handler, nullptr);
|
|
if (handler_ret != ESP_OK) {
|
|
ESP_LOGE(kTag, "gpio_isr_handler_add failed: %s", esp_err_to_name(handler_ret));
|
|
return false;
|
|
}
|
|
|
|
g_touch.isr_attached = true;
|
|
g_touch.attached_irq = irq_pin;
|
|
return true;
|
|
}
|
|
|
|
bool initialize_touch_core(const HynTouchConfig &config)
|
|
{
|
|
int ret = 0;
|
|
static struct hyn_ts_data ts_data;
|
|
memset(&ts_data, 0, sizeof(ts_data));
|
|
|
|
g_touch.config = config;
|
|
g_touch.data = &ts_data;
|
|
g_touch.ready = false;
|
|
g_touch.press_flag = false;
|
|
clear_key_state();
|
|
|
|
ESP_LOGI(kTag, HYN_DRIVER_VERSION);
|
|
|
|
struct hyn_ts_fuc *support_touch_list[] = {
|
|
(struct hyn_ts_fuc *)&cst66xx_fuc,
|
|
(struct hyn_ts_fuc *)&cst3xx_fuc,
|
|
(struct hyn_ts_fuc *)&cst226se_fuc,
|
|
};
|
|
|
|
g_touch.data->hyn_fuc_used = &cst66xx_fuc;
|
|
g_touch.data->plat_data.max_touch_num = config.max_touch_points ? config.max_touch_points : MAX_POINTS_REPORT;
|
|
g_touch.data->plat_data.irq_gpio = config.irq_pin;
|
|
g_touch.data->plat_data.reset_gpio = config.reset_pin;
|
|
g_touch.data->plat_data.x_resolution = config.x_resolution;
|
|
g_touch.data->plat_data.y_resolution = config.y_resolution;
|
|
g_touch.data->plat_data.swap_xy = config.swap_xy ? 1 : 0;
|
|
g_touch.data->plat_data.reverse_x = config.reverse_x ? 1 : 0;
|
|
g_touch.data->plat_data.reverse_y = config.reverse_y ? 1 : 0;
|
|
|
|
if (g_touch.data->plat_data.reset_gpio >= 0 && !XL9555_GPIO_IS(g_touch.data->plat_data.reset_gpio)) {
|
|
gpio_config_t io_conf = {};
|
|
io_conf.intr_type = GPIO_INTR_DISABLE;
|
|
io_conf.mode = GPIO_MODE_OUTPUT;
|
|
io_conf.pin_bit_mask = (1ULL << g_touch.data->plat_data.reset_gpio);
|
|
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
|
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
|
if (gpio_config(&io_conf) != ESP_OK) {
|
|
ESP_LOGE(kTag, "Failed to configure touch reset pin %d", g_touch.data->plat_data.reset_gpio);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
esp_err_t i2c_ret = hyn_i2c_init((u8)config.sda_pin, (u8)config.scl_pin);
|
|
if (i2c_ret != ESP_OK) {
|
|
ESP_LOGE(kTag, "I2C init failed: %s", esp_err_to_name(i2c_ret));
|
|
return false;
|
|
}
|
|
|
|
for (size_t i = 0; i < ARRAY_SIZE(support_touch_list); ++i) {
|
|
g_touch.data->hyn_fuc_used = support_touch_list[i];
|
|
ret = g_touch.data->hyn_fuc_used->tp_chip_init(g_touch.data);
|
|
if (ret == 0) {
|
|
ESP_LOGI(kTag, "Touch init SUCCEED");
|
|
ESP_LOGI(kTag, "IC_info fw_project_id:%lx", g_touch.data->hw_info.fw_project_id);
|
|
ESP_LOGI(kTag, "ictype:[%lx]", g_touch.data->hw_info.fw_chip_type);
|
|
ESP_LOGI(kTag, "fw_ver:%lx", g_touch.data->hw_info.fw_ver);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ret != 0) {
|
|
ESP_LOGE(kTag, "Touch probe failed");
|
|
return false;
|
|
}
|
|
|
|
if (!configure_irq_gpio(config.irq_pin)) {
|
|
return false;
|
|
}
|
|
|
|
g_touch.ready = true;
|
|
return true;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
HynTouchConfig hyn_touch_default_config()
|
|
{
|
|
HynTouchConfig config = {};
|
|
config.sda_pin = BOARD_TOUCH_SDA;
|
|
config.scl_pin = BOARD_TOUCH_SCL;
|
|
config.reset_pin = BOARD_TOUCH_RST;
|
|
config.irq_pin = BOARD_TOUCH_INT;
|
|
config.max_touch_points = MAX_POINTS_REPORT;
|
|
config.x_resolution = LCD_HOR_SIZE;
|
|
config.y_resolution = LCD_VER_SIZE;
|
|
config.swap_xy = false;
|
|
config.reverse_x = false;
|
|
config.reverse_y = false;
|
|
return config;
|
|
}
|
|
|
|
bool hyn_touch_init()
|
|
{
|
|
const HynTouchConfig config = hyn_touch_default_config();
|
|
return hyn_touch_init_with_config(&config);
|
|
}
|
|
|
|
bool hyn_touch_init_with_config(const HynTouchConfig *config)
|
|
{
|
|
if (config == nullptr) {
|
|
return false;
|
|
}
|
|
|
|
return initialize_touch_core(*config);
|
|
}
|
|
|
|
bool hyn_touch_is_ready()
|
|
{
|
|
return g_touch.ready;
|
|
}
|
|
|
|
uint8_t hyn_touch_get_point(int16_t *x_array, int16_t *y_array, uint8_t get_point)
|
|
{
|
|
if (!g_touch.ready || !g_touch.data || x_array == nullptr || y_array == nullptr || get_point == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (!g_touch.press_flag) {
|
|
return 0;
|
|
}
|
|
g_touch.press_flag = false;
|
|
|
|
uint8_t point_count = 0;
|
|
g_touch.data->hyn_irq_flg = 1;
|
|
if (g_touch.data->work_mode < DIFF_MODE) {
|
|
const int ret = g_touch.data->hyn_fuc_used->tp_report();
|
|
point_count = (g_touch.data->rp_buf.report_need & REPORT_POS) ? g_touch.data->rp_buf.rep_num : 0;
|
|
apply_axis_transform(point_count);
|
|
|
|
for (uint8_t i = 0; i < point_count && i < get_point; ++i) {
|
|
x_array[i] = g_touch.data->rp_buf.pos_info[i].pos_x;
|
|
y_array[i] = g_touch.data->rp_buf.pos_info[i].pos_y;
|
|
}
|
|
|
|
#if HYN_TOUCH_RUNTIME_LOG
|
|
printf("ret:%d num:%d xy:", ret, point_count);
|
|
for (uint8_t i = 0; i < point_count; ++i) {
|
|
printf("(%d,%d) ", g_touch.data->rp_buf.pos_info[i].pos_x, g_touch.data->rp_buf.pos_info[i].pos_y);
|
|
}
|
|
printf("key_id:%d, key_st:%d\n", g_touch.data->rp_buf.key_id, g_touch.data->rp_buf.key_state);
|
|
#else
|
|
(void)ret;
|
|
#endif
|
|
}
|
|
|
|
handle_key_report();
|
|
g_touch.data->rp_buf.report_need = REPORT_NONE;
|
|
return point_count;
|
|
}
|
|
|
|
bool hyn_touch_get_key_state(uint8_t key_id)
|
|
{
|
|
if (key_id >= 3) {
|
|
return false;
|
|
}
|
|
return g_touch.key_pressed[key_id];
|
|
}
|
|
|
|
bool hyn_touch_get_key_seen(uint8_t key_id)
|
|
{
|
|
if (key_id >= 3) {
|
|
return false;
|
|
}
|
|
return g_touch.key_seen[key_id];
|
|
}
|
|
|
|
void hyn_touch_clear_key_seen()
|
|
{
|
|
memset(g_touch.key_seen, 0, sizeof(g_touch.key_seen));
|
|
}
|
|
|
|
void hyn_touch_set_key_callback(HynTouchKeyCallback callback, void *user_data)
|
|
{
|
|
g_touch.key_callback = callback;
|
|
g_touch.key_callback_user_data = user_data;
|
|
}
|
|
|
|
void hyn_sleep()
|
|
{
|
|
if (!g_touch.ready || !g_touch.data || !g_touch.data->hyn_fuc_used || !g_touch.data->hyn_fuc_used->tp_supend) {
|
|
return;
|
|
}
|
|
|
|
#if HYN_TOUCH_RUNTIME_LOG
|
|
printf("hyn_sleep = %p\n", g_touch.data->hyn_fuc_used->tp_supend);
|
|
#endif
|
|
g_touch.data->hyn_fuc_used->tp_supend();
|
|
delay(100);
|
|
}
|
|
|
|
#endif // LilyGo_TDeck_Pro_Max
|