From 3127a9c44fcf2b90b8130441dbefacd7d97dce5c Mon Sep 17 00:00:00 2001 From: sukuwc Date: Wed, 11 Mar 2026 12:48:12 +0100 Subject: [PATCH 1/9] SUKU address scan works --- .../grid_esp32_module_octv/CMakeLists.txt | 2 +- .../grid_esp32_module_octv.c | 18 ++++ .../grid_esp32_touch/CMakeLists.txt | 8 ++ .../grid_esp32_touch/grid_esp32_touch.c | 90 +++++++++++++++++++ .../grid_esp32_touch/grid_esp32_touch.h | 41 +++++++++ 5 files changed, 158 insertions(+), 1 deletion(-) create mode 100644 grid_esp/components/grid_esp32_touch/CMakeLists.txt create mode 100644 grid_esp/components/grid_esp32_touch/grid_esp32_touch.c create mode 100644 grid_esp/components/grid_esp32_touch/grid_esp32_touch.h diff --git a/grid_esp/components/grid_esp32_module_octv/CMakeLists.txt b/grid_esp/components/grid_esp32_module_octv/CMakeLists.txt index 1ebaf3ab..42756ee5 100644 --- a/grid_esp/components/grid_esp32_module_octv/CMakeLists.txt +++ b/grid_esp/components/grid_esp32_module_octv/CMakeLists.txt @@ -4,5 +4,5 @@ idf_component_register( INCLUDE_DIRS "." REQUIRES - "grid_esp32_adc" "grid_esp32_encoder" "grid_common" + "grid_esp32_adc" "grid_esp32_encoder" "grid_common" "grid_esp32_touch" ) diff --git a/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c b/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c index e39a0d21..f1b17c9c 100644 --- a/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c +++ b/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c @@ -22,9 +22,20 @@ #include "grid_esp32_adc.h" #include "grid_esp32_encoder.h" +#include "grid_esp32_touch.h" + +#include "rom/ets_sys.h" // static const char* TAG = "module_octv"; +#define OCTV_I2C_PORT I2C_NUM_0 +#define OCTV_I2C_SCL_GPIO 40 +#define OCTV_I2C_SDA_GPIO 41 +#define OCTV_I2C_FREQ_HZ 100000 + +#define OCTV_SENSOR_RESET_GPIO 39 +#define OCTV_SENSOR_INT_GPIO 42 + #define GRID_MODULE_OCTV_ENC_NUM 8 static struct grid_ui_model* DRAM_ATTR ui_ptr = NULL; @@ -36,6 +47,10 @@ static DRAM_ATTR const uint8_t mux_element_lookup[2][8] = { }; #undef X +static void IRAM_ATTR octv_process_touch(void) { + ets_printf("OCTV sensor INT fired\r\n"); +} + void IRAM_ATTR octv_process_analog(struct grid_adc_result* result) { assert(result); @@ -68,6 +83,9 @@ void IRAM_ATTR octv_process_encoder(struct grid_encoder_result* result) { void grid_esp32_module_octv_init(struct grid_sys_model* sys, struct grid_ui_model* ui, struct grid_esp32_adc_model* adc, struct grid_esp32_encoder_model* enc, struct grid_config_model* conf, struct grid_cal_model* cal) { + grid_esp32_touch_init(&grid_esp32_touch_state, OCTV_I2C_PORT, OCTV_I2C_SCL_GPIO, OCTV_I2C_SDA_GPIO, OCTV_SENSOR_RESET_GPIO, OCTV_SENSOR_INT_GPIO, OCTV_I2C_FREQ_HZ, octv_process_touch); + grid_esp32_touch_scan(&grid_esp32_touch_state); + ui_ptr = ui; uint8_t detent = grid_hwcfg_module_encoder_is_detent(sys); diff --git a/grid_esp/components/grid_esp32_touch/CMakeLists.txt b/grid_esp/components/grid_esp32_touch/CMakeLists.txt new file mode 100644 index 00000000..38533ec6 --- /dev/null +++ b/grid_esp/components/grid_esp32_touch/CMakeLists.txt @@ -0,0 +1,8 @@ +idf_component_register( + SRCS + "grid_esp32_touch.c" + INCLUDE_DIRS + "." + REQUIRES + "driver" "freertos" +) diff --git a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.c b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.c new file mode 100644 index 00000000..279908b0 --- /dev/null +++ b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.c @@ -0,0 +1,90 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "grid_esp32_touch.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "rom/ets_sys.h" + +DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; + +static struct grid_esp32_touch_model* touch_ptr = NULL; + +static void IRAM_ATTR grid_esp32_touch_int_handler(void* arg) { + struct grid_esp32_touch_model* touch = (struct grid_esp32_touch_model*)arg; + ets_printf("OCTV touch INT\r\n"); + if (touch->process_touch) { + touch->process_touch(); + } +} + +void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, + grid_process_touch_t process_touch) { + + touch_ptr = touch; + touch->i2c_port = i2c_port; + touch->scl_gpio = scl_gpio; + touch->sda_gpio = sda_gpio; + touch->reset_gpio = reset_gpio; + touch->int_gpio = int_gpio; + touch->i2c_freq_hz = i2c_freq_hz; + touch->process_touch = process_touch; + + // RESET: drive high before gpio_reset_pin to avoid floating the pin + gpio_set_direction(touch->reset_gpio, GPIO_MODE_OUTPUT); + gpio_set_level(touch->reset_gpio, 1); + gpio_reset_pin(touch->reset_gpio); + gpio_set_direction(touch->reset_gpio, GPIO_MODE_OUTPUT); + gpio_set_level(touch->reset_gpio, 1); + + vTaskDelay(pdMS_TO_TICKS(150)); + + // INT: input with pull-up, falling edge interrupt (active low) + gpio_reset_pin(touch->int_gpio); + gpio_set_direction(touch->int_gpio, GPIO_MODE_INPUT); + gpio_set_pull_mode(touch->int_gpio, GPIO_PULLUP_ONLY); + gpio_set_intr_type(touch->int_gpio, GPIO_INTR_NEGEDGE); + gpio_install_isr_service(0); + gpio_isr_handler_add(touch->int_gpio, grid_esp32_touch_int_handler, touch); + gpio_intr_enable(touch->int_gpio); + + // I2C master + gpio_reset_pin(touch->scl_gpio); + gpio_reset_pin(touch->sda_gpio); + i2c_config_t conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = touch->sda_gpio, + .scl_io_num = touch->scl_gpio, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = touch->i2c_freq_hz, + }; + i2c_param_config(touch->i2c_port, &conf); + i2c_driver_install(touch->i2c_port, I2C_MODE_MASTER, 0, 0, 0); +} + +void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch) { + + ets_printf("I2C scan (SCL=GPIO%d SDA=GPIO%d):\r\n", touch->scl_gpio, touch->sda_gpio); + int found = 0; + for (uint8_t addr = 0x08; addr < 0x78; addr++) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(touch->i2c_port, cmd, pdMS_TO_TICKS(10)); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + ets_printf(" found device at 0x%02X\r\n", addr); + found++; + } + } + if (found == 0) { + ets_printf(" no devices found\r\n"); + } +} diff --git a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h new file mode 100644 index 00000000..0fc6e405 --- /dev/null +++ b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +#include "driver/i2c.h" +#include "driver/gpio.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*grid_process_touch_t)(void); + +struct grid_esp32_touch_model { + i2c_port_t i2c_port; + gpio_num_t scl_gpio; + gpio_num_t sda_gpio; + gpio_num_t reset_gpio; + gpio_num_t int_gpio; + uint32_t i2c_freq_hz; + grid_process_touch_t process_touch; +}; + +extern DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; + +void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, + grid_process_touch_t process_touch); + +void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch); + +#ifdef __cplusplus +} +#endif From 8be5f7ec5f5dc95b8937f706b9fc4ee671c9c6f0 Mon Sep 17 00:00:00 2001 From: sukuwc Date: Mon, 16 Mar 2026 12:47:54 +0100 Subject: [PATCH 2/9] SUKU support pin --- .../grid_esp32_module_octv.c | 29 +- .../grid_esp32_module_octv.h | 1 + .../grid_esp32_touch/CMakeLists.txt | 3 +- .../grid_esp32_touch/bb_captouch.cpp | 353 ++++++++++++++++++ .../components/grid_esp32_touch/bb_captouch.h | 66 ++++ ...rid_esp32_touch.c => grid_esp32_touch.cpp} | 63 ++-- .../grid_esp32_touch/grid_esp32_touch.h | 18 +- grid_esp/main/grid_fw.c | 5 + 8 files changed, 500 insertions(+), 38 deletions(-) create mode 100644 grid_esp/components/grid_esp32_touch/bb_captouch.cpp create mode 100644 grid_esp/components/grid_esp32_touch/bb_captouch.h rename grid_esp/components/grid_esp32_touch/{grid_esp32_touch.c => grid_esp32_touch.cpp} (62%) diff --git a/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c b/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c index f1b17c9c..c256952d 100644 --- a/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c +++ b/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c @@ -28,13 +28,13 @@ // static const char* TAG = "module_octv"; -#define OCTV_I2C_PORT I2C_NUM_0 -#define OCTV_I2C_SCL_GPIO 40 -#define OCTV_I2C_SDA_GPIO 41 -#define OCTV_I2C_FREQ_HZ 100000 +#define OCTV_I2C_PORT I2C_NUM_0 +#define OCTV_I2C_SCL_GPIO 40 +#define OCTV_I2C_SDA_GPIO 41 +#define OCTV_I2C_FREQ_HZ 100000 -#define OCTV_SENSOR_RESET_GPIO 39 -#define OCTV_SENSOR_INT_GPIO 42 +#define OCTV_SENSOR_RESET_GPIO 39 +#define OCTV_SENSOR_INT_GPIO 42 #define GRID_MODULE_OCTV_ENC_NUM 8 @@ -47,8 +47,19 @@ static DRAM_ATTR const uint8_t mux_element_lookup[2][8] = { }; #undef X -static void IRAM_ATTR octv_process_touch(void) { - ets_printf("OCTV sensor INT fired\r\n"); +void grid_esp32_module_octv_poll_touch(void) { + TOUCHINFO ti = {}; + if (grid_esp32_touch_get_samples(&grid_esp32_touch_state, &ti) && ti.count > 0) { + for (int i = 0; i < ti.count; i++) { + ets_printf("touch[%d] x=%d y=%d area=%d\r\n", i, ti.x[i], ti.y[i], ti.area[i]); + } + } + + static uint32_t diag_counter = 0; + if (++diag_counter >= 500) { + diag_counter = 0; + grid_esp32_touch_diagnostic(&grid_esp32_touch_state); + } } void IRAM_ATTR octv_process_analog(struct grid_adc_result* result) { @@ -83,7 +94,7 @@ void IRAM_ATTR octv_process_encoder(struct grid_encoder_result* result) { void grid_esp32_module_octv_init(struct grid_sys_model* sys, struct grid_ui_model* ui, struct grid_esp32_adc_model* adc, struct grid_esp32_encoder_model* enc, struct grid_config_model* conf, struct grid_cal_model* cal) { - grid_esp32_touch_init(&grid_esp32_touch_state, OCTV_I2C_PORT, OCTV_I2C_SCL_GPIO, OCTV_I2C_SDA_GPIO, OCTV_SENSOR_RESET_GPIO, OCTV_SENSOR_INT_GPIO, OCTV_I2C_FREQ_HZ, octv_process_touch); + grid_esp32_touch_init(&grid_esp32_touch_state, OCTV_I2C_PORT, OCTV_I2C_SCL_GPIO, OCTV_I2C_SDA_GPIO, OCTV_SENSOR_RESET_GPIO, OCTV_SENSOR_INT_GPIO, OCTV_I2C_FREQ_HZ, NULL); grid_esp32_touch_scan(&grid_esp32_touch_state); ui_ptr = ui; diff --git a/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.h b/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.h index e9df2b40..5eb23547 100644 --- a/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.h +++ b/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.h @@ -19,6 +19,7 @@ extern "C" { void grid_esp32_module_octv_init(struct grid_sys_model* sys, struct grid_ui_model* ui, struct grid_esp32_adc_model* adc, struct grid_esp32_encoder_model* enc, struct grid_config_model* conf, struct grid_cal_model* cal); +void grid_esp32_module_octv_poll_touch(void); #ifdef __cplusplus } diff --git a/grid_esp/components/grid_esp32_touch/CMakeLists.txt b/grid_esp/components/grid_esp32_touch/CMakeLists.txt index 38533ec6..86342a9e 100644 --- a/grid_esp/components/grid_esp32_touch/CMakeLists.txt +++ b/grid_esp/components/grid_esp32_touch/CMakeLists.txt @@ -1,6 +1,7 @@ idf_component_register( SRCS - "grid_esp32_touch.c" + "grid_esp32_touch.cpp" + "bb_captouch.cpp" INCLUDE_DIRS "." REQUIRES diff --git a/grid_esp/components/grid_esp32_touch/bb_captouch.cpp b/grid_esp/components/grid_esp32_touch/bb_captouch.cpp new file mode 100644 index 00000000..cf3dd8ed --- /dev/null +++ b/grid_esp/components/grid_esp32_touch/bb_captouch.cpp @@ -0,0 +1,353 @@ +// BitBank Capacitive Touch Sensor Library +// Stripped to MXT144 only, non-Arduino ESP-IDF port +// +// Copyright 2023 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 + +#include "bb_captouch.h" + +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +// +// Initialize the MXT144 +// +int BBCapTouch::initMXT(void) { + uint8_t ucTemp[32]; + int i, iObjCount, iReportID; + uint16_t u16, u16Offset; + + I2CReadRegister16(_iAddr, 0, ucTemp, 7); + iObjCount = ucTemp[6]; + _mxtdata.matrix_x_size = ucTemp[4]; + _mxtdata.matrix_y_size = ucTemp[5]; + ets_printf("mxt initMXT: family=0x%02X variant=0x%02X fw=%d.%d obj_count=%d matrix=%dx%d\r\n", + ucTemp[0], ucTemp[1], ucTemp[2], ucTemp[3], iObjCount, + _mxtdata.matrix_x_size, _mxtdata.matrix_y_size); + if (iObjCount < 1 || iObjCount > 64) { + return CT_ERROR; + } + u16Offset = 7; + iReportID = 1; + for (i = 0; i < iObjCount; i++) { + I2CReadRegister16(_iAddr, u16Offset, ucTemp, 6); + u16 = ucTemp[1] | (ucTemp[2] << 8); + ets_printf(" obj[%d] type=%d addr=0x%04X size=%d instances=%d rids=%d\r\n", + i, ucTemp[0], u16, ucTemp[3], ucTemp[4], ucTemp[5]); + switch (ucTemp[0]) { + case 2: _mxtdata.t2_encryption_status_address = u16; break; + case 5: + _mxtdata.t5_message_processor_address = u16; + _mxtdata.t5_max_message_size = ucTemp[3] + 1; // actual size = size_field + 1 + break; + case 6: _mxtdata.t6_command_processor_address = u16; break; + case 7: _mxtdata.t7_powerconfig_address = u16; break; + case 8: _mxtdata.t8_acquisitionconfig_address = u16; break; + case 15: + _mxtdata.t15_key_array_address = u16; + _mxtdata.t15_first_report_id = iReportID + 1; // +1: sensor allocates one status slot before key data + break; + case 37: _mxtdata.t37_diagnostic_address = u16; break; + case 44: _mxtdata.t44_message_count_address = u16; break; + case 46: _mxtdata.t46_cte_config_address = u16; break; + case 56: _mxtdata.t56_shieldless_address = u16; break; + case 100: + _mxtdata.t100_multiple_touch_touchscreen_address = u16; + _mxtdata.t100_first_report_id = iReportID; + break; + default: break; + } + u16Offset += 6; + // Type 166 appears in the object table with rids=12/instances=12 but does NOT + // allocate user-visible report IDs on this chip variant — skip its contribution. + if (ucTemp[0] != 166) { + iReportID += ucTemp[5] * (ucTemp[4] + 1); + } + } + return CT_SUCCESS; +} + +// +// Initialize the library — reset and I2C are already configured by grid_esp32_touch_init(). +// This re-applies I2C config, detects the MXT144 and reads its object table. +// +int BBCapTouch::init(int iSDA, int iSCL, uint32_t u32Speed) { + i2c_config_t conf = {}; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = iSDA; + conf.scl_io_num = iSCL; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = u32Speed; + i2c_param_config(I2C_NUM_0, &conf); + i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0); + + if (!I2CTest(MXT144_ADDR)) { + return CT_ERROR; + } + int rc = initMXT(); + if (rc == CT_SUCCESS) { + // T7: acquisition timing (free-run at 16ms intervals). + { + uint8_t t7wr[2 + 4] = {}; + t7wr[0] = (uint8_t)(_mxtdata.t7_powerconfig_address); + t7wr[1] = (uint8_t)(_mxtdata.t7_powerconfig_address >> 8); + t7wr[2] = 16; // IDLEACQINT: 16ms + t7wr[3] = 16; // ACTVACQINT: 16ms + I2CWrite(_iAddr, t7wr, 2 + 4); + } + + // T8: charge time and measurement parameters (reference: Table 11-1). + { + uint8_t t8wr[2 + 14] = {}; + t8wr[0] = (uint8_t)(_mxtdata.t8_acquisitionconfig_address); + t8wr[1] = (uint8_t)(_mxtdata.t8_acquisitionconfig_address >> 8); + t8wr[2 + 0] = 26; // CHRGTIME + t8wr[2 + 10] = 11; // MEASALLOW + t8wr[2 + 11] = 8; // MEASIDLEDEF + t8wr[2 + 12] = 2; // MEASACTVDEF + I2CWrite(_iAddr, t8wr, 2 + 14); + } + + // T46: CTE (charge transfer engine), reference: IDLESYNCSPERX=16, ACTSYNCSPERX=16. + { + uint8_t t46wr[2 + 11] = {}; + t46wr[0] = (uint8_t)(_mxtdata.t46_cte_config_address); + t46wr[1] = (uint8_t)(_mxtdata.t46_cte_config_address >> 8); + t46wr[2 + 0] = 0x01; // CTRL: ENABLE + t46wr[2 + 2] = 16; // IDLESYNCSPERX + t46wr[2 + 3] = 16; // ACTIVESYNCSPERX + t46wr[2 + 4] = 4; // ADCSPERSYNC + t46wr[2 + 5] = 1; // PULSESPERADC + I2CWrite(_iAddr, t46wr, 2 + 11); + } + + // T7 must be written BEFORE T6 CALIBRATE so the scanner restarts with the correct interval. + // (Blank NVM leaves IDLEACQINT=0 which stops the scanner after one measurement.) + { + uint8_t rb[4] = {}; + I2CReadRegister16(_iAddr, _mxtdata.t7_powerconfig_address, rb, 4); + ets_printf("mxt T7 readback: IDLEACQINT=%d ACTVACQINT=%d ACTV2IDLETO=%d\r\n", rb[0], rb[1], rb[2]); + I2CReadRegister16(_iAddr, _mxtdata.t46_cte_config_address, rb, 4); + ets_printf("mxt T46 readback: CTRL=0x%02X MODE=%d IDLESYNCSPERX=%d ACTSYNCSPERX=%d\r\n", rb[0], rb[1], rb[2], rb[3]); + } + + // T56 Shieldless: reference config (Table 11-1) enables T56 with INTTIME=26. + // Write only the first 2 fields (CTRL + INTTIME) to avoid overwriting adjacent objects. + if (_mxtdata.t56_shieldless_address) { + uint8_t t56wr[2 + 2] = {}; + t56wr[0] = (uint8_t)(_mxtdata.t56_shieldless_address); + t56wr[1] = (uint8_t)(_mxtdata.t56_shieldless_address >> 8); + t56wr[2 + 0] = 0x01; // CTRL: ENABLE + t56wr[2 + 1] = 26; // INTTIME + I2CWrite(_iAddr, t56wr, 2 + 2); + } + + // T100: multitouch touchscreen. XSIZE/YSIZE must match the sensor matrix. + // Object table size field is (actual-1), so actual T100 size = 68 bytes (offsets 0-67). + // TCHEVENTCFG offset is uncertain across MXT variants (offset 4 vs 5) — set both. + // T100 layout: [0]=CTRL [4/5]=TCHEVENTCFG [7]=NUMTCH + // [10]=XSIZE [14-15]=XRANGE [21]=YSIZE [25-26]=YRANGE [33]=TCHTHR [34]=TCHHYST + { + uint8_t t100wr[2 + 68] = {}; + t100wr[0] = (uint8_t)(_mxtdata.t100_multiple_touch_touchscreen_address); + t100wr[1] = (uint8_t)(_mxtdata.t100_multiple_touch_touchscreen_address >> 8); + t100wr[2 + 0] = 0x07; // CTRL: ENABLE | RPTEN | SCANEN + t100wr[2 + 4] = 0xFF; // TCHEVENTCFG (offset 4, all events) + t100wr[2 + 5] = 0xFF; // TCHEVENTCFG (offset 5, all events — covers both placements) + t100wr[2 + 7] = 5; // NUMTCH + t100wr[2 + 10] = _mxtdata.matrix_x_size; // XSIZE + t100wr[2 + 14] = 0xFF; // XRANGE lo + t100wr[2 + 15] = 0x0F; // XRANGE hi + t100wr[2 + 21] = _mxtdata.matrix_y_size; // YSIZE + t100wr[2 + 25] = 0xFF; // YRANGE lo + t100wr[2 + 26] = 0x0F; // YRANGE hi + t100wr[2 + 33] = 5; // TCHTHR + t100wr[2 + 34] = 2; // TCHHYST + I2CWrite(_iAddr, t100wr, 2 + 68); + + } + // BACKUP (T6[1] = 0x55): save RAM config → NVM to clear CFGERR. + // Per datasheet §9.3, chip auto-resets after BACKUP — must read the RESET + // message from T5 before issuing any further commands. + { + uint8_t t5_size = _mxtdata.t5_max_message_size; + uint8_t msg[16] = {}; + + uint16_t backup_reg = _mxtdata.t6_command_processor_address + 1; + uint8_t backup_cmd[3] = {(uint8_t)backup_reg, (uint8_t)(backup_reg >> 8), 0x55}; + I2CWrite(_iAddr, backup_cmd, 3); + ets_printf("mxt: BACKUP issued, waiting for auto-reset...\r\n"); + + bool reset_seen = false; + for (int ms = 0; ms < 2000 && !reset_seen; ms += 10) { + vTaskDelay(pdMS_TO_TICKS(10)); + uint8_t count = 0; + I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, &count, 1); + for (int m = 0; m < count; m++) { + memset(msg, 0, sizeof(msg)); + I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, msg, t5_size); + ets_printf("mxt: BACKUP msg @%dms rid=%d status=0x%02X\r\n", ms, msg[0], msg[1]); + if (msg[1] & 0x80) { // RESET bit — BACKUP complete + reset_seen = true; + } + } + } + if (!reset_seen) { + ets_printf("mxt: BACKUP timed out — no RESET message received\r\n"); + } + } + + // CALIBRATE (T6[2] = 0x01): establish fresh baseline after BACKUP. + // Poll T5 messages to confirm CAL completes (CAL bit set then cleared). + { + uint8_t t5_size = _mxtdata.t5_max_message_size; + uint8_t msg[16] = {}; + + uint16_t cal_reg = _mxtdata.t6_command_processor_address + 2; + uint8_t cal_cmd[3] = {(uint8_t)cal_reg, (uint8_t)(cal_reg >> 8), 0x01}; + I2CWrite(_iAddr, cal_cmd, 3); + ets_printf("mxt: CALIBRATE issued\r\n"); + + bool cal_done = false; + for (int ms = 0; ms < 2000 && !cal_done; ms += 10) { + vTaskDelay(pdMS_TO_TICKS(10)); + uint8_t count = 0; + I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, &count, 1); + for (int m = 0; m < count; m++) { + memset(msg, 0, sizeof(msg)); + I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, msg, t5_size); + ets_printf("mxt: CAL msg @%dms rid=%d status=0x%02X\r\n", ms, msg[0], msg[1]); + // CAL complete: T6 message (rid=1) with CAL bit (0x10) clear + if (msg[0] == 1 && !(msg[1] & 0x10) && !(msg[1] & 0x80)) { + ets_printf("mxt: CALIBRATE complete, STATUS=0x%02X\r\n", msg[1]); + cal_done = true; + } + } + } + if (!cal_done) { + ets_printf("mxt: CALIBRATE timed out\r\n"); + } + } + } + return rc; +} + +// +// Read touch samples from the MXT144 +// +int BBCapTouch::getSamples(TOUCHINFO *pTI) { + uint8_t ucTemp[32]; + int i, j; + + if (!pTI) return 0; + pTI->count = 0; + + if (!_mxtdata.t44_message_count_address) { + ets_printf("mxt: no t44 addr\r\n"); + return 0; + } + I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, ucTemp, 1); + j = ucTemp[0]; + if (j > 0) ets_printf("mxt: msg_count=%d t100_frid=%d\r\n", j, _mxtdata.t100_first_report_id); + uint8_t t5_size = (_mxtdata.t5_max_message_size && _mxtdata.t5_max_message_size <= 32) + ? _mxtdata.t5_max_message_size : MXT_MESSAGE_SIZE; + for (i = 0; i < j; i++) { + I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, ucTemp, t5_size); + ets_printf("mxt: rid=%d b1=0x%02X x=%d y=%d\r\n", ucTemp[0], ucTemp[1], + ucTemp[2]|(ucTemp[3]<<8), ucTemp[4]|(ucTemp[5]<<8)); + // T100: RID+0 = screen status, RID+1..+N = finger 0..N-1 + if (ucTemp[0] >= _mxtdata.t100_first_report_id + 1 && + ucTemp[0] < _mxtdata.t100_first_report_id + 1 + 5) { + uint8_t finger_idx = ucTemp[0] - _mxtdata.t100_first_report_id - 1; + uint8_t event = ucTemp[1] & 0xf; + if (finger_idx + 1 > (uint8_t)pTI->count) pTI->count = finger_idx + 1; + pTI->x[finger_idx] = ucTemp[2] + (ucTemp[3] << 8); + pTI->y[finger_idx] = ucTemp[4] + (ucTemp[5] << 8); + if (event == 1 || event == 4) { // press / move + pTI->area[finger_idx] = 50; + } else if (event == 5) { // release + pTI->area[finger_idx] = 0; + } + } + } + return (pTI->count > 0); +} + +// +// Read the T37 diagnostic object and print a raw delta matrix. +// Command 0x10 = DELTA_DATA: shows capacitance change vs baseline. +// Values change when a finger is present; all-zero means the sensor is not sensing. +// +void BBCapTouch::dumpDiagnostic(void) { + if (!_mxtdata.t37_diagnostic_address || !_mxtdata.t6_command_processor_address) { + ets_printf("mxt diag: T37 or T6 address not found in object table\r\n"); + return; + } + int cols = _mxtdata.matrix_x_size ? _mxtdata.matrix_x_size : 12; + int rows = _mxtdata.matrix_y_size ? _mxtdata.matrix_y_size : 12; + + uint16_t diag_reg = _mxtdata.t6_command_processor_address + 5; + uint8_t cmd[3]; + cmd[0] = (uint8_t)diag_reg; + cmd[1] = (uint8_t)(diag_reg >> 8); + uint8_t buf[2 + 128] = {}; + + // --- Reference data (0x11): uint16 per node, 2 bytes each. + // Page 0 = 64 nodes. Non-zero here means CTE is running and has a baseline. + cmd[2] = 0x11; + I2CWrite(_iAddr, cmd, 3); + vTaskDelay(pdMS_TO_TICKS(20)); + I2CReadRegister16(_iAddr, _mxtdata.t37_diagnostic_address, buf, 2 + 128); + ets_printf("mxt T37 mode=0x%02X page=%d (reference, uint16, first %d nodes):\r\n", + buf[0], buf[1], 64); + for (int i = 0; i < 64; i++) { + uint16_t ref = buf[2 + i * 2] | (buf[2 + i * 2 + 1] << 8); + ets_printf("%6u", ref); + if ((i + 1) % cols == 0) ets_printf("\r\n"); + } + + // --- Delta data (0x10): int8 per node. + // Page 0 = 128 nodes. Non-zero here means a finger is changing capacitance. + cmd[2] = 0x10; + I2CWrite(_iAddr, cmd, 3); + vTaskDelay(pdMS_TO_TICKS(20)); + memset(buf, 0, sizeof(buf)); + I2CReadRegister16(_iAddr, _mxtdata.t37_diagnostic_address, buf, 2 + 128); + ets_printf("mxt T37 mode=0x%02X page=%d (delta, int8, first %d nodes):\r\n", + buf[0], buf[1], rows * cols < 128 ? rows * cols : 128); + for (int r = 0; r < rows; r++) { + for (int c = 0; c < cols; c++) { + int idx = r * cols + c; + if (idx >= 128) break; + ets_printf("%4d", (int8_t)buf[2 + idx]); + } + ets_printf("\r\n"); + } +} + +bool BBCapTouch::I2CTest(uint8_t u8Addr) { + uint8_t c; + return (i2c_master_read_from_device(I2C_NUM_0, u8Addr, &c, 1, pdMS_TO_TICKS(10)) == ESP_OK); +} + +int BBCapTouch::I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen) { + return (i2c_master_write_to_device(I2C_NUM_0, u8Addr, pData, iLen, pdMS_TO_TICKS(100)) == ESP_OK); +} + +int BBCapTouch::I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen) { + uint8_t ucTemp[2]; + ucTemp[0] = (uint8_t)u16Register; // low byte (MXT144 is little-endian) + ucTemp[1] = (uint8_t)(u16Register >> 8); // high byte + i2c_master_write_read_device(I2C_NUM_0, u8Addr, ucTemp, 2, pData, iLen, pdMS_TO_TICKS(100)); + return iLen; +} + +int BBCapTouch::I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen) { + int rc = i2c_master_read_from_device(I2C_NUM_0, u8Addr, pData, iLen, pdMS_TO_TICKS(100)); + return (rc == ESP_OK) ? iLen : 0; +} diff --git a/grid_esp/components/grid_esp32_touch/bb_captouch.h b/grid_esp/components/grid_esp32_touch/bb_captouch.h new file mode 100644 index 00000000..12419b0f --- /dev/null +++ b/grid_esp/components/grid_esp32_touch/bb_captouch.h @@ -0,0 +1,66 @@ +// BitBank Capacitive Touch Sensor Library +// Stripped to MXT144 only, non-Arduino ESP-IDF port +// +// Copyright 2023 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 + +#pragma once + +#include +#include "driver/i2c.h" + +#define CT_SUCCESS 0 +#define CT_ERROR -1 + +#define MXT144_ADDR 0x4A + +typedef struct mxt_data_tag { + uint16_t t2_encryption_status_address; + uint16_t t5_message_processor_address; + uint16_t t5_max_message_size; + uint16_t t6_command_processor_address; + uint16_t t7_powerconfig_address; + uint16_t t8_acquisitionconfig_address; + uint16_t t37_diagnostic_address; + uint16_t t44_message_count_address; + uint16_t t46_cte_config_address; + uint16_t t56_shieldless_address; + uint16_t t15_key_array_address; + uint16_t t15_first_report_id; + uint16_t t100_multiple_touch_touchscreen_address; + uint16_t t100_first_report_id; + uint8_t matrix_x_size; + uint8_t matrix_y_size; +} MXTDATA; + +#define MXT_MESSAGE_SIZE 6 + +#ifndef __TOUCHINFO_STRUCT__ +#define __TOUCHINFO_STRUCT__ +typedef struct _fttouchinfo { + int count; + uint32_t key_state; + uint16_t x[5], y[5]; + uint8_t pressure[5], area[5]; +} TOUCHINFO; +#endif + +class BBCapTouch { +public: + BBCapTouch() {} + int init(int iSDA, int iSCL, uint32_t u32Speed = 400000); + int getSamples(TOUCHINFO *pTI); + void dumpDiagnostic(void); + +private: + int _iAddr = MXT144_ADDR; + MXTDATA _mxtdata = {}; + int initMXT(void); + bool I2CTest(uint8_t u8Addr); + int I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen); + int I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen); + int I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen); +}; diff --git a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.c b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp similarity index 62% rename from grid_esp/components/grid_esp32_touch/grid_esp32_touch.c rename to grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp index 279908b0..1c220682 100644 --- a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.c +++ b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp @@ -5,6 +5,7 @@ */ #include "grid_esp32_touch.h" +#include "bb_captouch.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -14,13 +15,12 @@ DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; static struct grid_esp32_touch_model* touch_ptr = NULL; +static BBCapTouch bbc; static void IRAM_ATTR grid_esp32_touch_int_handler(void* arg) { struct grid_esp32_touch_model* touch = (struct grid_esp32_touch_model*)arg; - ets_printf("OCTV touch INT\r\n"); - if (touch->process_touch) { - touch->process_touch(); - } + touch->int_pending = true; + ets_printf("INT\r\n"); } void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, @@ -35,37 +35,38 @@ void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_ touch->i2c_freq_hz = i2c_freq_hz; touch->process_touch = process_touch; - // RESET: drive high before gpio_reset_pin to avoid floating the pin - gpio_set_direction(touch->reset_gpio, GPIO_MODE_OUTPUT); - gpio_set_level(touch->reset_gpio, 1); + // Apply pull-ups to all sensor pins before reset — no external resistors on this board. + // Must happen before the reset pulse so SDA/SCL are not floating during sensor boot. + gpio_reset_pin(touch->scl_gpio); + gpio_pullup_en(touch->scl_gpio); + gpio_reset_pin(touch->sda_gpio); + gpio_pullup_en(touch->sda_gpio); + gpio_reset_pin(touch->int_gpio); + gpio_pullup_en(touch->int_gpio); + + // RESET: active-low reset pulse gpio_reset_pin(touch->reset_gpio); gpio_set_direction(touch->reset_gpio, GPIO_MODE_OUTPUT); - gpio_set_level(touch->reset_gpio, 1); + gpio_set_level(touch->reset_gpio, 0); // assert reset + vTaskDelay(pdMS_TO_TICKS(10)); + gpio_set_level(touch->reset_gpio, 1); // deassert reset + vTaskDelay(pdMS_TO_TICKS(250)); // wait for sensor boot - vTaskDelay(pdMS_TO_TICKS(150)); - - // INT: input with pull-up, falling edge interrupt (active low) - gpio_reset_pin(touch->int_gpio); + // INT: falling edge interrupt (pull-up already set above) gpio_set_direction(touch->int_gpio, GPIO_MODE_INPUT); - gpio_set_pull_mode(touch->int_gpio, GPIO_PULLUP_ONLY); gpio_set_intr_type(touch->int_gpio, GPIO_INTR_NEGEDGE); gpio_install_isr_service(0); gpio_isr_handler_add(touch->int_gpio, grid_esp32_touch_int_handler, touch); gpio_intr_enable(touch->int_gpio); - // I2C master - gpio_reset_pin(touch->scl_gpio); - gpio_reset_pin(touch->sda_gpio); - i2c_config_t conf = { - .mode = I2C_MODE_MASTER, - .sda_io_num = touch->sda_gpio, - .scl_io_num = touch->scl_gpio, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master.clk_speed = touch->i2c_freq_hz, - }; - i2c_param_config(touch->i2c_port, &conf); - i2c_driver_install(touch->i2c_port, I2C_MODE_MASTER, 0, 0, 0); + // I2C + MXT144 init — i2c_param_config will reconfigure SCL/SDA with pull-ups enabled + int rc = bbc.init(touch->sda_gpio, touch->scl_gpio, touch->i2c_freq_hz); + if (rc == CT_SUCCESS) { + ets_printf("MXT144 init OK\r\n"); + touch->int_pending = true; // drain any messages queued during init + } else { + ets_printf("MXT144 init FAILED\r\n"); + } } void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch) { @@ -88,3 +89,13 @@ void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch) { ets_printf(" no devices found\r\n"); } } + +int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI) { + (void)touch; + return bbc.getSamples(pTI); +} + +void grid_esp32_touch_diagnostic(struct grid_esp32_touch_model* touch) { + (void)touch; + bbc.dumpDiagnostic(); +} diff --git a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h index 0fc6e405..302d7e31 100644 --- a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h +++ b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h @@ -10,13 +10,23 @@ #include "freertos/FreeRTOS.h" #include "freertos/semphr.h" -#include "driver/i2c.h" #include "driver/gpio.h" +#include "driver/i2c.h" #ifdef __cplusplus extern "C" { #endif +#ifndef __TOUCHINFO_STRUCT__ +#define __TOUCHINFO_STRUCT__ +typedef struct _fttouchinfo { + int count; // number of pressed keys + uint32_t key_state; // T15 key bitmap (1 bit per key, up to 32 keys) + uint16_t x[5], y[5]; + uint8_t pressure[5], area[5]; +} TOUCHINFO; +#endif + typedef void (*grid_process_touch_t)(void); struct grid_esp32_touch_model { @@ -27,15 +37,19 @@ struct grid_esp32_touch_model { gpio_num_t int_gpio; uint32_t i2c_freq_hz; grid_process_touch_t process_touch; + volatile bool int_pending; }; -extern DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; +extern struct grid_esp32_touch_model grid_esp32_touch_state; void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, grid_process_touch_t process_touch); void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch); +int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI); +void grid_esp32_touch_diagnostic(struct grid_esp32_touch_model* touch); + #ifdef __cplusplus } #endif diff --git a/grid_esp/main/grid_fw.c b/grid_esp/main/grid_fw.c index 313ded2b..7bdf03d3 100644 --- a/grid_esp/main/grid_fw.c +++ b/grid_esp/main/grid_fw.c @@ -619,6 +619,11 @@ void app_main(void) { vmp_flushed = true; } + // Poll touch sensor if OCTV module + if (grid_hwcfg_module_is_octv(&grid_sys_state)) { + grid_esp32_module_octv_poll_touch(); + } + // Run microtasks grid_esp32_utask_led(&timer_led); From c1781230eec06f5577b8ce21b7af1dd481c0d032 Mon Sep 17 00:00:00 2001 From: sukuwc Date: Mon, 16 Mar 2026 15:25:41 +0100 Subject: [PATCH 3/9] SUKU random stash --- bb_captouch-1.3.1/LICENSE | 204 +++ bb_captouch-1.3.1/README.md | 28 + .../examples/named_device/named_device.ino | 33 + .../examples/touch_demo/touch_demo.ino | 144 +++ bb_captouch-1.3.1/library.properties | 11 + bb_captouch-1.3.1/src/bb_captouch.cpp | 878 +++++++++++++ bb_captouch-1.3.1/src/bb_captouch.h | 255 ++++ .../grid_esp32_module_octv.c | 15 +- .../grid_esp32_port/grid_esp32_port.c | 23 +- .../grid_esp32_touch/bb_captouch.cpp | 1151 ++++++++++++----- .../components/grid_esp32_touch/bb_captouch.h | 248 +++- .../grid_esp32_touch/grid_esp32_touch.cpp | 39 +- .../grid_esp32_touch/grid_esp32_touch.h | 2 - maxtouch.c | 654 ++++++++++ mxt144.pdf | Bin 0 -> 477936 bytes 15 files changed, 3288 insertions(+), 397 deletions(-) create mode 100644 bb_captouch-1.3.1/LICENSE create mode 100644 bb_captouch-1.3.1/README.md create mode 100644 bb_captouch-1.3.1/examples/named_device/named_device.ino create mode 100644 bb_captouch-1.3.1/examples/touch_demo/touch_demo.ino create mode 100644 bb_captouch-1.3.1/library.properties create mode 100644 bb_captouch-1.3.1/src/bb_captouch.cpp create mode 100644 bb_captouch-1.3.1/src/bb_captouch.h create mode 100644 maxtouch.c create mode 100644 mxt144.pdf diff --git a/bb_captouch-1.3.1/LICENSE b/bb_captouch-1.3.1/LICENSE new file mode 100644 index 00000000..716f427d --- /dev/null +++ b/bb_captouch-1.3.1/LICENSE @@ -0,0 +1,204 @@ +Copyright 2020 BitBank Software, Inc. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/bb_captouch-1.3.1/README.md b/bb_captouch-1.3.1/README.md new file mode 100644 index 00000000..297e1770 --- /dev/null +++ b/bb_captouch-1.3.1/README.md @@ -0,0 +1,28 @@ +BitBank Capacitive Touch Sensor Library
+--------------------------------------- +Copyright (c) 2023-2024 BitBank Software, Inc.
+Written by Larry Bank
+email: bitbank@pobox.com
+
+There are a growing list of development boards which include LCDs with capacitive touch plates on them. These are overwhelmingly controlled by different versions of the ESP32 MCU. The boards normally only utilize GOODiX and FocalTech capacitive touch controllers and this library supports the MXT144, CST820, GT911 and FT6x36 in a generic way. Each has different capabilities and usually come pre-programmed for the specific pixel width and height of the target application. A feature supported by this library that may not be present in the device you're using is the touch area and pressure values. Some of their controllers also have built-in gesture detection. The common features of the controllers is that they will generate an interrupt signal when a touch event is occurring. This library allows you to request the latest touch information and it returns the number of active touch points (0-5) along with the coordinates (and pressure/area of each if available). The sensor type and address is auto-detected when calling the init() method. The only info that must be correctly supplied to the library are the GPIO pins used for the SDA/SCL/INT/RESET signals. Once initialized, repeatedly call getSamples() to test for and read any touch samples available.
+ +There are only 4 methods exposed by the class:
+int init() - detects if a supported CT controller is available and initializes it
+int setOrientation(int iOrientation, int iWidth, int iHeight) - allows you to rotate the coordinates to match the LCD orientation
+int getSamples() - returns touch points if available
+int sensorType() - returns an enumerated value of the sensor detected<> +Here is the TOUCHINFO structure filled by the getSamples() method:
+``` +typedef struct _fttouchinfo +{ + int count; + uint16_t x[5], y[5]; + uint8_t pressure[5], area[5]; +} TOUCHINFO; +``` + +If you find this code useful, please consider becoming a sponsor or sending a donation. + +[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SR4F44J2UR8S4) + + diff --git a/bb_captouch-1.3.1/examples/named_device/named_device.ino b/bb_captouch-1.3.1/examples/named_device/named_device.ino new file mode 100644 index 00000000..e0f1e21c --- /dev/null +++ b/bb_captouch-1.3.1/examples/named_device/named_device.ino @@ -0,0 +1,33 @@ +// +// This example shows how to use a pre-configured device name +// The names contain the GPIO pin numbers of a specific device +// +#include +BBCapTouch bbct; + +void setup() +{ + int rc; + Serial.begin(115200); + delay(3000); // allow time for CDC-Serial to start + +// The full list of device names can be found in bb_captouch.h + rc = bbct.init(TOUCH_WS_AMOLED_18); + if (rc == CT_SUCCESS) { + Serial.printf("bb_captouch init success, type = %d\n", bbct.sensorType()); + } else { + Serial.println("Error initializing bb_captouch"); + while (1) {}; + } +} + +void loop() +{ + TOUCHINFO ti; + while (1) { + bbct.getSamples(&ti); + if (ti.count > 0) { + Serial.printf("x,y = %d,%d\n", ti.x[0], ti.y[0]); + } + } +} diff --git a/bb_captouch-1.3.1/examples/touch_demo/touch_demo.ino b/bb_captouch-1.3.1/examples/touch_demo/touch_demo.ino new file mode 100644 index 00000000..40b204d8 --- /dev/null +++ b/bb_captouch-1.3.1/examples/touch_demo/touch_demo.ino @@ -0,0 +1,144 @@ +#include +//#include +#include +#include + +//#define CYD_128C +//#define LILYGO_S3_PRO +//#define LILYGO_S3_LONG +#define CYD_543 + + +#ifdef CYD_543 +#define LCD DISPLAY_CYD_543 +#define TOUCH_SDA 8 +#define TOUCH_SCL 4 +#define TOUCH_INT 3 +#define TOUCH_RST 38 +#endif + +#ifdef LILYGO_S3_LONG +#define TOUCH_SDA 15 +#define TOUCH_SCL 10 +#define TOUCH_INT 11 +// reset is 16, but it's shared with the LCD +#define TOUCH_RST -1 +#define LCD DISPLAY_T_DISPLAY_S3_LONG +#endif + +#ifdef LILYGO_S3_PRO +#define TOUCH_SDA 5 +#define TOUCH_SCL 6 +#define TOUCH_INT 7 +#define TOUCH_RST 13 +#define LCD DISPLAY_T_DISPLAY_S3_PRO +#endif + +#ifdef CYD_28C +// These defines are for a low cost 2.8" ESP32 LCD board with the GT911 touch controller +#define TOUCH_SDA 33 +#define TOUCH_SCL 32 +#define TOUCH_INT 21 +#define TOUCH_RST 25 +#define LCD DISPLAY_CYD +#endif + +#ifdef CYD_128C +// These defines are for a low cost 1.28" ESP32-C3 round LCD board with the CST816D touch controller +#define TOUCH_SDA 4 +#define TOUCH_SCL 5 +#define TOUCH_INT 0 +#define TOUCH_RST 1 +#define QWIIC_SDA 21 +#define QWIIC_SCL 20 +#define LCD DISPLAY_CYD_128 +#endif + +#ifdef ARDUINO_M5STACK_CORES3 +#define TOUCH_SDA 12 +#define TOUCH_SCL 11 +#define TOUCH_INT -1 +#define TOUCH_RST -1 +#define LCD DISPLAY_M5STACK_CORES3 +#endif // CORES3 + +BBCapTouch bbct; +BB_SPI_LCD lcd; +int iWidth, iHeight; + +const char *szNames[] = {"Unknown", "FT6x36", "GT911", "CST820", "CST226", "MXT144", "AXS15231"}; +void setup() { + + Serial.begin(115200); + while (!Serial) {}; + lcd.begin(LCD); + Serial.println("Starting..."); +// obd.setI2CPins(QWIIC_SDA, QWIIC_SCL); +// obd.setBitBang(true); +// obd.I2Cbegin(OLED_128x64); +// obd.fillScreen(OBD_WHITE); +// obd.setFont(FONT_12x16); +// obd.println("QWIIC OLED"); + iWidth = lcd.width(); + iHeight = lcd.height(); + Serial.printf("LCD size = %dx%d\n", iWidth, iHeight); + lcd.fillScreen(TFT_BLACK); + lcd.setTextColor(TFT_GREEN, TFT_BLACK); + lcd.setFont(FONT_8x8); + lcd.setCursor(0, 0); + lcd.println("CYD Touch Test"); + delay(1000); + Wire.end(); + //Wire1.end(); + bbct.init(TOUCH_SDA, TOUCH_SCL, TOUCH_RST, TOUCH_INT); + int iType = bbct.sensorType(); + Serial.printf("Sensor type = %s\n", szNames[iType]); +#ifdef OLD_STUFF +if (co2.init(QWIIC_SDA, QWIIC_SCL, 1, 100000) == SCD41_SUCCESS) { +// Serial.println("Found SCD41 sensor!"); + co2.start(); // start sampling mode + lcd.println("SCD41 found!"); + } else { // can't find the sensor, stop + lcd.println("SCD41 sensor not found"); + lcd.println("Check your connections"); + lcd.println("\nstopping..."); + while (1) {}; + } // no sensor connected or some error +#endif +} /* setup() */ + +void loop() { +#ifndef OLD_STUFF + int i; + TOUCHINFO ti; + +while (1) { + if (bbct.getSamples(&ti)) { + for (int i=0; i64) { // invalid number of items + return CT_ERROR; + } + u16Offset = 7; // starting offset of first object + // Read the objects one by one to get the memory offests to the info we will need + iReportID = 1; + // Serial.printf("object count = %d\n", iObjCount); + for (i=0; ibegin(iSDA, iSCL); // this is specific to ESP32 MCUs + myWire->setClock(u32Speed); + myWire->setTimeout(1000); +#else + i2c_config_t conf = { + .mode = I2C_MODE_MASTER, + .sda_io_num = iSDA, + .scl_io_num = iSCL, + .sda_pullup_en = GPIO_PULLUP_ENABLE, + .scl_pullup_en = GPIO_PULLUP_ENABLE, + .master.clk_speed = u32Speed, + }; + i2c_driver_delete(I2C_NUM_0); // remove driver (if installed) + i2c_param_config(I2C_NUM_0, &conf); // configure I2C device 0 + i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0); // configure with no send or receive buffers +#endif + _iType = CT_TYPE_UNKNOWN; + + if (iRST != -1) { + reset(iRST); + } + +#ifdef FUTURE + if (I2CTest(AXS15231_ADDR)) { + _iType = CT_TYPE_AXS15231; + _iAddr = AXS15231_ADDR; + if (iRST != -1) { + reset(iRST); + } + return CT_SUCCESS; + } // AXS15231 +#endif + + if (I2CTest(SPD2010_ADDR)) { + _iType = CT_TYPE_SPD2010; + _iAddr = SPD2010_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT_PULLUP); + } + return CT_SUCCESS; + } + if (I2CTest(TMA445_ADDR)) { + _iType = CT_TYPE_TMA445; + _iAddr = TMA445_ADDR; +// if (iINT != -1) { +// pinMode(iINT, INPUT_PULLUP); +// } + // send soft reset + ucTemp[0] = 0; + ucTemp[1] = 1; + I2CWrite(_iAddr, ucTemp, 2); + delay(50); + // send security key + I2CWrite(_iAddr, tma445_key, sizeof(tma445_key)); + delay(88); + + uint8_t tries = 0; + cyttsp_bootloader_data bl_data = {}; + do { + delay(20); + I2CRead(_iAddr, (uint8_t *)&bl_data, sizeof(bl_data)); + } while (bl_data.bl_status & 0x10 && tries++ < 10); // while bootloader mode + if (tries >= 10) Serial.println("bootloader mode timed out"); + // set OP mode + ucTemp[0] = 0; + ucTemp[1] = 0; // start op mode + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + if (I2CTest(MXT144_ADDR)) { + _iType = CT_TYPE_MXT144; + _iAddr = MXT144_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT); + } + if (iRST != -1) { + reset(iRST); + } + return initMXT(); + } + if (I2CTest(CHSC6540_ADDR)) { + _iType = CT_TYPE_CHSC6540; + _iAddr = CHSC6540_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT); + } + ucTemp[0] = ucTemp[1] = 0x5a; // set interrupt mode + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + if (I2CTest(CST226_ADDR)) { + _iType = CT_TYPE_CST226; + _iAddr = CST226_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT); + } + return CT_SUCCESS; + } + if (I2CTest(GT911_ADDR1) || I2CTest(GT911_ADDR2)) { + _iType = CT_TYPE_GT911; + } + if (_iType == CT_TYPE_GT911) { // reset the sensor to start it + pinMode(iRST, OUTPUT); + pinMode(iINT, OUTPUT); + digitalWrite(iINT, LOW); + digitalWrite(iRST, LOW); + delay(5); + digitalWrite(iINT, LOW); // set I2C addr to ADDR1 + delay(1); + digitalWrite(iRST, HIGH); // when it comes out of reset, it samples INT + delay(10); + digitalWrite(iINT, LOW); + delay(50); + pinMode(iINT, INPUT); + // double check the I2C addr in case it changed + if (I2CTest(GT911_ADDR1)) { + _iAddr = GT911_ADDR1; + } else if (I2CTest(GT911_ADDR2)) { + _iAddr = GT911_ADDR2; + } + } else if (I2CTest(FT6X36_ADDR1)) { + _iType = CT_TYPE_FT6X36; + _iAddr = FT6X36_ADDR1; + } else if (I2CTest(FT6X36_ADDR2)) { + _iType = CT_TYPE_FT6X36; + _iAddr = FT6X36_ADDR2; + } else if (I2CTest(CST820_ADDR)) { + _iType = CT_TYPE_CST820; + _iAddr = CST820_ADDR; + if (iRST != -1) { + reset(iRST); + } + } else { +#ifdef ARDUINO + myWire->end(); +#else + i2c_driver_delete(I2C_NUM_0); +#endif + return CT_ERROR; // no device found + } + return CT_SUCCESS; +} /* init() */ + +// Initialize the touch controller from a pre-defined configuration name +int BBCapTouch::init(int iConfigName) +{ +const BBCT_CONFIG *pC = &_configs[iConfigName]; + + if (iConfigName < 0 || iConfigName >= TOUCH_COUNT) { + return CT_ERROR; + } + + if (iConfigName == TOUCH_WS_AMOLED_241) { // touch is rotated + _iOrientation = 270; + _iWidth = 450; + _iHeight = 600; + + } + if (iConfigName == TOUCH_WS_AMOLED_18 || iConfigName == TOUCH_WS_ROUND_146) { + // need to release the RESET line which is controlled by an + // I/O expander (TCA9554) + uint8_t ucEXIO; + if (iConfigName == TOUCH_WS_AMOLED_18) ucEXIO = 6; // touch reset (AMOLED 1.8) + else ucEXIO = 1; // touch reset (1.46" round) + Wire.end(); + Wire.begin(pC->i8SDA, pC->i8SCL); + Wire.beginTransmission(0x20); + Wire.write(1); // output port register + Wire.write(~ucEXIO); // set touch controller reset low + Wire.write(0); // polarity inversion all disabled + Wire.write(~7); // enable P0+P1+P2 as an output (connected to RESET) + Wire.endTransmission(); + delay(50); + Wire.beginTransmission(0x20); + Wire.write(1); // output port register + Wire.write(0xff); // set all outputs high (disable resets) + Wire.endTransmission(); + delay(50); + if (iConfigName == TOUCH_WS_AMOLED_18) { + Wire.beginTransmission(0x38); + Wire.write(0xa5); // power mode + Wire.write(0); // active + Wire.endTransmission(); + } + Wire.end(); + } + return init(pC->i8SDA, pC->i8SCL, pC->i8RST, pC->i8IRQ, +#ifdef ARDUINO + 400000, &Wire); +#else + 400000); +#endif +} /* init() */ +// +// Test if an I2C device is monitoring an address +// return true if it responds, false if no response +// +bool BBCapTouch::I2CTest(uint8_t u8Addr) +{ + // Check if a device acknowledges the address. +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + return(myWire->endTransmission(true) == 0); +#else // allow 100ms for device to respond + uint8_t c = 0; + return (i2c_master_write_to_device(I2C_NUM_0, u8Addr, &c, 1, 10) == ESP_OK); +#endif +} /* I2CTest() */ +// +// Write I2C data +// quits if a NACK is received and returns 0 +// otherwise returns the number of bytes written +// +int BBCapTouch::I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen) +{ + int rc = 0; + +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + myWire->write(pData, (uint8_t)iLen); + rc = !myWire->endTransmission(); +#else + rc = (i2c_master_write_to_device(I2C_NUM_0, u8Addr, pData, iLen, 100) == ESP_OK); +#endif + return rc; +} /* I2CWrite() */ +// +// Read N bytes starting at a specific 16-bit I2C register +// +int BBCapTouch::I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen) +{ + int i = 0; + +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + if (_iType == CT_TYPE_MXT144) { // little endian + myWire->write((uint8_t)u16Register); // low byte + myWire->write((uint8_t)(u16Register>>8)); // high byte + } else { // big endian address + myWire->write((uint8_t)(u16Register>>8)); // high byte + myWire->write((uint8_t)u16Register); // low byte + } + myWire->endTransmission(); + myWire->requestFrom(u8Addr, (uint8_t)iLen); + while (i < iLen) + { + pData[i++] = myWire->read(); + } +#else + uint8_t ucTemp[4]; + int rc; + if (_iType == CT_TYPE_MXT144) { // little endian + ucTemp[1] = (uint8_t)(u16Register>>8); // high byte + ucTemp[0] = (uint8_t)u16Register; // low byte + } else { + ucTemp[0] = (uint8_t)(u16Register>>8); // high byte + ucTemp[1] = (uint8_t)u16Register; // low byte + } + i2c_master_write_read_device(I2C_NUM_0, u8Addr, ucTemp, 2, pData, iLen, 100); + if (rc == ESP_OK) { + i = iLen; + } +#endif + return i; + +} /* I2CReadRegister16() */ +// +// Read N bytes starting at a specific I2C internal register +// returns 1 for success, 0 for error +// +int BBCapTouch::I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen) +{ + int rc; + int i = 0; + +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + myWire->write(u8Register); + myWire->endTransmission(); + myWire->requestFrom(u8Addr, (uint8_t)iLen); + // i = myWire->readBytes(pData, iLen); + while (myWire->available() && i < iLen) + { + pData[i++] = myWire->read(); + } +#else + rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, &u8Register, 1, pData, iLen, 100); + i = (rc == ESP_OK); +#endif + return i; +} /* I2CReadRegister() */ +// +// Read N bytes +// +int BBCapTouch::I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen) +{ + int i = 0; + +#ifdef ARDUINO + myWire->requestFrom(u8Addr, (uint8_t)iLen); + while (i < iLen) + { + pData[i++] = myWire->read(); + } +#else + int rc; + rc = i2c_master_read_from_device(I2C_NUM_0, u8Addr, pData, iLen, 100); + i = (rc == ESP_OK) ? iLen : 0; +#endif + return i; +} /* I2CRead() */ +// +// Private function to rotate touch samples if the user +// specified a new display orientation +// +void BBCapTouch::fixSamples(TOUCHINFO *pTI) +{ +int i, x, y; + + for (i=0; icount; i++) { + switch (_iOrientation) { + case 90: + x = pTI->y[i]; + y = _iWidth - 1 - pTI->x[i]; + pTI->x[i] = x; + pTI->y[i] = y; + break; + case 180: + pTI->x[i] = _iWidth - 1 - pTI->x[i]; + pTI->y[i] = _iHeight - 1 - pTI->y[i]; + break; + case 270: + x = _iHeight - 1 - pTI->y[i]; + y = pTI->x[i]; + pTI->x[i] = x; + pTI->y[i] = y; + break; + default: // do nothing + break; + } + } +} /* fixSamples() */ +void BBCapTouch::SPD2010ClearInt(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 2; + ucTemp[1] = 0; + ucTemp[2] = 1; + ucTemp[3] = 0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010ClearInt() */ + +void BBCapTouch::SPD2010CPUStart(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 4; + ucTemp[1] = 0; + ucTemp[2] = 1; + ucTemp[3] = 0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010CPUStart() */ + +uint8_t BBCapTouch::SPD2010Status(int *iNextLen) +{ + uint8_t ucTemp[8]; + I2CReadRegister16(_iAddr, 0xfc02, ucTemp, 8); + *iNextLen = (ucTemp[3] << 8) | ucTemp[2]; + return ucTemp[5]; +} /* SPD2010Status() */ + +void BBCapTouch::SPD2010TouchStart(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 0x46; + ucTemp[1] = 0x0; + ucTemp[2] = 0x0; + ucTemp[3] = 0x0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010TouchStart() */ + +void BBCapTouch::SPD2010PointMode(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 0x50; + ucTemp[1] = 0x0; + ucTemp[2] = 0x0; + ucTemp[3] = 0x0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010PointMode() */ + +// +// Read the touch points +// returns 0 (none), 1 if touch points are available +// The point count and info is returned in the TOUCHINFO structure +// +int BBCapTouch::getSamples(TOUCHINFO *pTI) +{ +uint8_t c, *s, ucTemp[32]; +int i, j, rc = 0; + + if (!pTI) + return 0; + pTI->count = 0; + if (_iType == CT_TYPE_UNKNOWN) return 0; // library not initialized? + + if (_iType == CT_TYPE_SPD2010) { + static int iNextLen = 0; + int iReadLen; + uint8_t ucStatus; + // first read the status + I2CReadRegister16(_iAddr, 0x2000, ucTemp, 4); + // Byte 0 has a bit field with the following info: + // 0 = point exists + // 1 = gesture + // 3 = aux, cytang + // Byte 1 + // 3 = cpu run + // 4 = tint low + // 5 = tic in cpu + // 6 = tic in bios + // 7 = tic busy + iReadLen = (ucTemp[3]<<8) + ucTemp[2]; + // Serial.printf("status byte 0: 0x%02x, 0x%02x, read len = %d\n", ucTemp[0], ucTemp[1], iReadLen); + if (ucTemp[1] & 0x40) { // tic in bios + SPD2010ClearInt(); // Write Clear TINT Command + SPD2010CPUStart(); // Write CPU Start Command + } else if (ucTemp[1] & 0x20) { // tic in cpu + SPD2010PointMode(); // Write Touch Change Command + SPD2010TouchStart(); // Write Touch Start Command + SPD2010ClearInt(); + } else if ((ucTemp[1] & 8) && iReadLen == 0) { // cpu run + SPD2010ClearInt(); + } else if (ucTemp[0] & 1 || ucTemp[0] & 2) { // point or gesture + uint8_t ucData[64]; // 4-byte header plus up to 10 fingers of 6 bytes each + I2CReadRegister16(_iAddr, 0x0003, ucData, iReadLen); + // Serial.printf("readlen: %d, data[4]: 0x%02x\n", iReadLen, ucData[4]); + if (ucData[4] <= 0xa && ucTemp[0] & 1) { // check_id < 10 && point exists + rc = 1; // touch event + pTI->count = (iReadLen - 4)/6; // number of touch points + for (int i=0; icount; i++) { + int iOffset = i*6; + pTI->x[i] = ((ucData[7+iOffset] & 0xf0) << 4) | ucData[5+iOffset]; + pTI->y[i] = ((ucData[7+iOffset] & 0x0f) << 8) | ucData[6+iOffset]; + pTI->area[i] = ucData[8+iOffset]; + } + } + // gestures... + hdp_done_check: + /* Read HDP Status */ + ucStatus = SPD2010Status(&iNextLen); +// Serial.printf("status: 0x%02\n", ucStatus); + if (ucStatus == 0x82) { + SPD2010ClearInt(); + } else if (ucStatus == 0x00) { // Read HDP Remain Data + // Read_HDP_REMAIN_DATA(&tp_hdp_status); + goto hdp_done_check; + } + } else if (ucTemp[1] & 8 && ucTemp[0] & 8) { // cpu run && aux + SPD2010ClearInt(); + } + return rc; + } + if (_iType == CT_TYPE_TMA445) { + uint8_t hst_mode; + I2CReadRegister(_iAddr, 0, ucTemp, 14); // read up to 2 touch points + pTI->count = ucTemp[2]; // touch point count + if (pTI->count > 0) { + pTI->y[0] = (ucTemp[5]*256) + ucTemp[6]; + pTI->x[0] = (ucTemp[3]*256) + ucTemp[4]; + pTI->area[0] = ucTemp[7]; + if (pTI->count == 2) { // get second touch point + pTI->y[1] = (ucTemp[11]*256) + ucTemp[12]; + pTI->x[1] = (ucTemp[9]*256) + ucTemp[10]; + pTI->area[1] = ucTemp[13]; + } + // do handshake + I2CReadRegister(_iAddr, 0, &hst_mode, 1); + hst_mode ^= CY_HNDSHK_BIT; // toggle handshake bit + ucTemp[0] = 0; + ucTemp[1] = hst_mode; // send it back + I2CWrite(_iAddr, ucTemp, 2); + return 1; + } + return 0; + } + if (_iType == CT_TYPE_MXT144) { + if (!_mxtdata.t44_message_count_address) { + return 0; // No message offset, so we can't read anything :( + } + I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, ucTemp, 1); + j = ucTemp[0]; // object count + // As each message is read from the sensor, the internal count + // is decremented. It appears that it can hold 6 messages maximum + // before you must read them to receive more. + for (i = 0; i < j; i++) { // read the messages + I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, ucTemp, MXT_MESSAGE_SIZE); // each message is 6 bytes + // check report_id + if (ucTemp[0] >= _mxtdata.t100_first_report_id + 2 && + ucTemp[0] < _mxtdata.t100_first_report_id + 2 + 5) { + uint8_t finger_idx = ucTemp[0] - _mxtdata.t100_first_report_id - 2; + uint8_t event = ucTemp[1] & 0xf; + if (finger_idx+1 > pTI->count) pTI->count = finger_idx+1; + pTI->x[finger_idx] = ucTemp[2] + (ucTemp[3] << 8); + pTI->y[finger_idx] = ucTemp[4] + (ucTemp[5] << 8); + if (event == 1 || event == 4) { // move/press event + pTI->area[finger_idx] = 50; + } else if (event == 5) { // release + pTI->area[finger_idx] = 0; + } + } // if touch report + } // for each report + return (pTI->count > 0); + } // MXT144 + + if (_iType == CT_TYPE_AXS15231) { + uint8_t ucReadCMD[8] = {0xb5,0xab,0xa5,0x5a,0,0,0,0x8}; + I2CWrite(_iAddr, (uint8_t *)ucReadCMD, 8); + I2CRead(_iAddr, ucTemp, 14); // read up to 2 touch points + c = ucTemp[1]; // number of touch points + if (c == 0 || c > 2 || ucTemp[0] != 0) return 0; + pTI->count = c; + j = 0; // buffer offset + for (i=0; ix[i] = ((ucTemp[j+2] & 0xf) << 8) + ucTemp[j+3]; + pTI->y[i] = ((ucTemp[j+4] & 0xf) << 8) + ucTemp[j+5]; + pTI->area[i] = 1; + j += 6; + } + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } // AXS15231 + + if (_iType == CT_TYPE_CST226) { + i = I2CReadRegister(_iAddr, 0, ucTemp, 28); // read the whole block of regs +// Serial.printf("I2CReadRegister returned %d\n", i); +#ifdef FUTURE + if (ucTemp[0] == 0x83 && ucTemp[1] == 0x17 && ucTemp[5] == 0x80) { + // home button pressed + return 0; + } + if (ucTemp[6] != 0xab) return 0; + if (ucTemp[0] == 0xab) return 0; + if (ucTemp[5] == 0x80) return 0; + c = ucTemp[5] & 0x7f; + if (c > 5 || c == 0) { // invalid point count + ucTemp[0] = 0; + ucTemp[1] = 0xab; + I2CWrite(_iAddr, ucTemp, 2); // reset + return 0; + } +#endif + c = 1; // debug + pTI->count = c; + // Serial.printf("count = %d\n", c); + j = 0; + for (i=0; ix[i] = (uint16_t)((ucTemp[j+1] << 4) | ((ucTemp[j+3] >> 4) & 0xf)); + pTI->y[i] = (uint16_t)((ucTemp[j+2] << 4) | (ucTemp[j+3] & 0xf)); + pTI->pressure[i] = ucTemp[j+4]; + j = (i == 0) ? (j+7) : (j+5); + } + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } + + if (_iType == CT_TYPE_CHSC6540) { + if (digitalRead(_iINT) == LOW) { + I2CReadRegister(_iAddr, 2, ucTemp, 13); // read touch points + if (ucTemp[2] == 1 || ucTemp[2] == 2) { + pTI->count = ucTemp[2]; + pTI->x[0] = ((ucTemp[3] & 0xf) << 8) | ucTemp[4]; + pTI->y[0] = ((ucTemp[5] & 0xf) << 8) | ucTemp[6]; + if (ucTemp[0] == 2) { // second touch point + pTI->x[0] = ((ucTemp[9] & 0xf) << 8) | ucTemp[10]; + pTI->y[0] = ((ucTemp[11] & 0xf) << 8) | ucTemp[12]; + } + return 1; + } + } + return 0; + } + if (_iType == CT_TYPE_CST820) { + I2CReadRegister(_iAddr, CST820_TOUCH_REGS+1, ucTemp, 1); // read touch count + if (ucTemp[0] < 1 || ucTemp[0] > 5) { // something went wrong + return 0; + } + if (ucTemp[0] >= 1) { // touch data available, read it + pTI->count = ucTemp[0]; + I2CReadRegister(_iAddr, CST820_TOUCH_REGS+2, ucTemp, pTI->count * 6); + s = ucTemp; + for (i=0; icount; i++) { + pTI->x[i] = ((s[0] & 0xf) << 8) | s[1]; + pTI->y[i] = ((s[2] & 0xf) << 8) | s[3]; + pTI->area[i] = 1; // no data available + s += 6; + } + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } + } + if (_iType == CT_TYPE_FT6X36) { + rc = I2CReadRegister(_iAddr, TOUCH_REG_STATUS, ucTemp, 1); // read touch status + if (rc == 0) { // something went wrong + return 0; + } + i = ucTemp[0]; // number of touch points available + if (i >= 1 && i <= 5) { // get data + rc = I2CReadRegister(_iAddr, TOUCH_REG_XH, ucTemp, 6*i); // read X+Y position(s) + if ((ucTemp[0] & 0x40) == 0 && (ucTemp[2] & 0xf0) != 0xf0) { // finger is down + pTI->x[0] = ((ucTemp[0] & 0xf) << 8) | ucTemp[1]; + pTI->y[0] = ((ucTemp[2] & 0xf) << 8) | ucTemp[3]; + // get touch pressure and area + pTI->pressure[0] = ucTemp[4]; + pTI->area[0] = ucTemp[5]; + pTI->count++; + } + if (i > 1) { // get second point + if ((ucTemp[6] & 0x40) == 0 && (ucTemp[8] & 0xf0) != 0xf0) { // finger is down + pTI->x[1] = ((ucTemp[6] & 0xf) << 8) | ucTemp[7]; + pTI->y[1] = ((ucTemp[8] & 0xf) << 8) | ucTemp[9]; + // get touch pressure and area + pTI->pressure[1] = ucTemp[10]; + pTI->area[1] = ucTemp[11]; + pTI->count++; + } + } + } // if touch points available + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } else { // GT911 + I2CReadRegister16(_iAddr, GT911_POINT_INFO, ucTemp, 1); // get number of touch points + i = ucTemp[0] & 0xf; // number of touches + if (i <= 5 && ucTemp[0] & 0x80) { // if buffer status is good + >= 1 touch points + ucTemp[0] = (uint8_t)(GT911_POINT_INFO >> 8); + ucTemp[1] = (uint8_t)GT911_POINT_INFO; + ucTemp[2] = 0; // clear touch info for next time + I2CWrite(_iAddr, ucTemp, 3); + + pTI->count = i; + for (int j=0; jx[j] = ucTemp[1] + (ucTemp[2] << 8); + pTI->y[j] = ucTemp[3] + (ucTemp[4] << 8); + pTI->area[j] = ucTemp[5] + (ucTemp[6] << 8); + pTI->pressure[j] = 0; + } + if (i && _iOrientation != 0) fixSamples(pTI); + return (i > 0); + } + } // GT911 + return 0; +} /* getSamples() */ + +int BBCapTouch::setOrientation(int iOrientation, int iWidth, int iHeight) +{ + if (iOrientation != 0 && iOrientation != 90 && iOrientation != 180 && iOrientation != 270) { + return CT_ERROR; + } + _iOrientation = iOrientation; + _iWidth = iWidth; + _iHeight = iHeight; + return CT_SUCCESS; +} /* setOrientation() */ + +int BBCapTouch::sensorType(void) +{ + return _iType; +} /* type() */ + +int BBCapTouch::sleep(void) +{ +uint8_t ucTemp[8]; + + if (_iType == CT_TYPE_AXS15231) { + ucTemp[0] = 0x90; // enter deep sleep + ucTemp[1] = 0xa5; + ucTemp[2] = 0x5a; + ucTemp[3] = 0x15; + ucTemp[4] = 0x23; + I2CWrite(_iAddr, ucTemp, 5); + return CT_SUCCESS; + } + if (_iType == CT_TYPE_GT911 && _iINT != -1) { + pinMode(_iINT, OUTPUT); + digitalWrite(_iINT, 0); // setting interrupt pin low to prepare sleep mode + ucTemp[0] = (uint8_t)(GT911_ENTER_SLEEP >> 8); + ucTemp[1] = (uint8_t)GT911_ENTER_SLEEP; + ucTemp[2] = 0x05; //?? + I2CWrite(_iAddr, ucTemp, 3); // enter sleep mode + return CT_SUCCESS; + } + if (_iType == CT_TYPE_CST226) { + ucTemp[0] = 0xd1; + ucTemp[1] = 0x05; + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + return CT_ERROR; +} /* sleep() */ + +int BBCapTouch::wake(void) +{ +uint8_t ucTemp[4]; + + if (_iType == CT_TYPE_AXS15231) { + digitalWrite(_iRST, 0); + delay(50); + digitalWrite(_iRST, 1); + return CT_SUCCESS; + } + if (_iType == CT_TYPE_GT911 && _iINT != -1) { + digitalWrite(_iINT, 1); // wake up the controller + delay(5); // allow it time to wake + pinMode(_iINT, INPUT); // change pin mode back to floating + } + if (_iType == CT_TYPE_CST226) { + ucTemp[0] = 0xd1; + ucTemp[1] = 0x06; + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + return CT_ERROR; +} /* wake() */ + + diff --git a/bb_captouch-1.3.1/src/bb_captouch.h b/bb_captouch-1.3.1/src/bb_captouch.h new file mode 100644 index 00000000..a8d4ccdb --- /dev/null +++ b/bb_captouch-1.3.1/src/bb_captouch.h @@ -0,0 +1,255 @@ +// +// BitBank Capacitive Touch Sensor Library +// written by Larry Bank +// +// Copyright 2023 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== + +// +// Written for the many variants of ESP32 + Capacitive touch LCDs on the market +// +#ifdef ARDUINO +#include +#include +#else +#define INPUT 0 +#define OUTPUT 1 +#include "driver/gpio.h" +#include "driver/i2c.h" +#endif // ARDUINO + +#ifndef __BB_CAPTOUCH__ +#define __BB_CAPTOUCH__ + +#define CT_SUCCESS 0 +#define CT_ERROR -1 +// +// Pre-configured device names +// Don't change the order of this list! +// the structure values follow it. Always +// add new values to the end +// +enum { + TOUCH_T_QT_C6=0, + TOUCH_CYD_550, + TOUCH_T_DISPLAY_S3_PRO, + TOUCH_T_DISPLAY_S3_LONG, + TOUCH_CYD_22C, + TOUCH_CYD_24C, + TOUCH_CYD_128, + TOUCH_CYD_35C, + TOUCH_CYD_518, + TOUCH_CYD_543, + TOUCH_M5_CORE2, + TOUCH_M5_CORES3, + TOUCH_M5_PAPER, + TOUCH_WT32_SC01_PLUS, + TOUCH_MAKERFABS_480x480, + TOUCH_MAKERFABS_320x480, + TOUCH_T_DISPLAY_S3_AMOLED, + TOUCH_WS_AMOLED_18, + TOUCH_M5_PAPERS3, + TOUCH_WS_ROUND_146, + TOUCH_WS_AMOLED_241, + TOUCH_WS_LCD_169, + TOUCH_VIEWE_2432, + TOUCH_T_DISPLAY_S3_AMOLED_164, + TOUCH_COUNT +}; +// structure holding the configurations +typedef struct bbct_config_tag { + int8_t i8SDA, i8SCL, i8IRQ, i8RST; +} BBCT_CONFIG; + +enum { + CT_TYPE_UNKNOWN = 0, + CT_TYPE_FT6X36, + CT_TYPE_GT911, + CT_TYPE_CST820, + CT_TYPE_CST226, + CT_TYPE_MXT144, + CT_TYPE_AXS15231, + CT_TYPE_TMA445, + CT_TYPE_SPD2010, + CT_TYPE_CHSC6540, + CT_TYPE_COUNT +}; + +#define SPD2010_ADDR 0x53 +#define GT911_ADDR1 0x5D +#define GT911_ADDR2 0x14 +#define FT6X36_ADDR1 0x38 +#define FT6X36_ADDR2 0x48 +#define CST820_ADDR 0x15 +#define CST226_ADDR 0x5A +#define CHSC6540_ADDR 0x2E +#define MXT144_ADDR 0x4A +#define TMA445_ADDR 0x24 +#define AXS15231_ADDR 0x3B + +// CST8xx gestures +enum { + GESTURE_NONE = 0, + GESTURE_SWIPE_UP, + GESTURE_SWIPE_DOWN, + GESTURE_SWIPE_LEFT, + GESTURE_SWIPE_RIGHT, + GESTURE_SINGLE_CLICK, + GESTURE_DOUBLE_CLICK = 0x0B, + GESTURE_LONG_PRESS = 0x0C +}; + +// TMA445 Security KEY +static uint8_t tma445_key[] = {0x00, 0x00, 0xFF, 0xA5, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + +/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */ +typedef struct cyttsp_xydata_tag { + uint8_t hst_mode; + uint8_t tt_mode; + uint8_t tt_stat; + uint16_t x1 __attribute__ ((packed)); + uint16_t y1 __attribute__ ((packed)); + uint8_t z1; + uint8_t touch12_id; + uint16_t x2 __attribute__ ((packed)); + uint16_t y2 __attribute__ ((packed)); + uint8_t z2; +} cyttsp_xydata; +#define CY_HNDSHK_BIT 0x80 +typedef struct cyttsp_bootloader_data_tag { + uint8_t bl_file; + uint8_t bl_status; + uint8_t bl_error; + uint8_t blver_hi; + uint8_t blver_lo; + uint8_t bld_blver_hi; + uint8_t bld_blver_lo; + uint8_t ttspver_hi; + uint8_t ttspver_lo; + uint8_t appid_hi; + uint8_t appid_lo; + uint8_t appver_hi; + uint8_t appver_lo; + uint8_t cid_0; + uint8_t cid_1; + uint8_t cid_2; +} cyttsp_bootloader_data; + + +typedef struct mxt_data_tag { + uint16_t t2_encryption_status_address; + uint16_t t5_message_processor_address; + uint16_t t5_max_message_size; + uint16_t t6_command_processor_address; + uint16_t t7_powerconfig_address; + uint16_t t8_acquisitionconfig_address; + uint16_t t44_message_count_address; + uint16_t t46_cte_config_address; + uint16_t t100_multiple_touch_touchscreen_address; + uint16_t t100_first_report_id; +} MXTDATA; + +typedef struct mxt_object_tag { + uint8_t type; + uint16_t position; + uint8_t size_minus_one; + uint8_t instances_minus_one; + uint8_t report_ids_per_instance; +} MXTOBJECT; + +#define MXT_MESSAGE_SIZE 6 + +// CST820 registers +#define CST820_TOUCH_REGS 1 + +// GT911 registers +#define GT911_POINT_INFO 0x814E +#define GT911_POINT_1 0x814F +#define GT911_CONFIG_FRESH 0x8100 +#define GT911_CONFIG_SIZE 0xb9 +#define GT911_CONFIG_START 0x8047 +#define GT911_ENTER_SLEEP 0x8040 + +// FT6x36 registers +#define TOUCH_REG_STATUS 0x02 +#define TOUCH_REG_XH 0x03 +#define TOUCH_REG_XL 0x04 +#define TOUCH_REG_YH 0x05 +#define TOUCH_REG_YL 0x06 +#define TOUCH_REG_WEIGHT 0x07 +#define TOUCH_REG_AREA 0x08 +// register offset to info for the second touch point +#define PT2_OFFSET 6 + +#ifndef __TOUCHINFO_STRUCT__ +#define __TOUCHINFO_STRUCT__ + +typedef struct _fttouchinfo +{ + int count; + uint16_t x[5], y[5]; + uint8_t pressure[5], area[5]; +} TOUCHINFO; +#endif + +//extern TwoWire* myWire; + +class BBCapTouch +{ +public: + BBCapTouch() { _iOrientation = 0; _iType = CT_TYPE_UNKNOWN;} +// ~BBCapTouch() { Wire.end(); } + ~BBCapTouch() { myWire->end(); } + +#ifdef ARDUINO + int init(int iConfigName); + int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000, TwoWire* _myWire=&Wire); +#else + int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000); +#endif + int getSamples(TOUCHINFO *pTI); + uint8_t interruptPin(void) {return (uint8_t)_iINT;} + int sensorType(void); + int setOrientation(int iOrientation, int iWidth, int iHeight); + int sleep(void); + int wake(void); + +protected: + void reset(int iResetPin); + +private: + int _iAddr; + int _iType; + int _iOrientation, _iWidth, _iHeight; + MXTDATA _mxtdata; + int _iINT; // interrupt GPIO pin needed for sleep/wake of GT911 + int _iRST; // reset GPIO needed for AXS15206 to wake from deep sleep +#ifdef ARDUINO + TwoWire* myWire; +#else + void pinMode(uint8_t u8Pin, uint8_t u8Mode); + void digitalWrite(uint8_t u8Pin, uint8_t u8State); +#endif + int initMXT(void); + void fixSamples(TOUCHINFO *pTI); + bool I2CTest(uint8_t u8Addr); + int I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen); + int I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen); + int I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen); + int I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen); + void SPD2010ClearInt(void); + void SPD2010CPUStart(void); + uint8_t SPD2010Status(int *iNextLen); + void SPD2010TouchStart(void); + void SPD2010PointMode(void); +}; // class BBCapTouch +#endif // __BB_CAPTOUCH__ diff --git a/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c b/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c index c256952d..89889e69 100644 --- a/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c +++ b/grid_esp/components/grid_esp32_module_octv/grid_esp32_module_octv.c @@ -49,16 +49,10 @@ static DRAM_ATTR const uint8_t mux_element_lookup[2][8] = { void grid_esp32_module_octv_poll_touch(void) { TOUCHINFO ti = {}; - if (grid_esp32_touch_get_samples(&grid_esp32_touch_state, &ti) && ti.count > 0) { - for (int i = 0; i < ti.count; i++) { - ets_printf("touch[%d] x=%d y=%d area=%d\r\n", i, ti.x[i], ti.y[i], ti.area[i]); - } - } - - static uint32_t diag_counter = 0; - if (++diag_counter >= 500) { - diag_counter = 0; - grid_esp32_touch_diagnostic(&grid_esp32_touch_state); + int rc = grid_esp32_touch_get_samples(&grid_esp32_touch_state, &ti); + ets_printf("touch rc=%d count=%d\r\n", rc, ti.count); + for (int i = 0; i < ti.count; i++) { + ets_printf(" [%d] x=%d y=%d area=%d\r\n", i, ti.x[i], ti.y[i], ti.area[i]); } } @@ -95,7 +89,6 @@ void grid_esp32_module_octv_init(struct grid_sys_model* sys, struct grid_ui_mode struct grid_cal_model* cal) { grid_esp32_touch_init(&grid_esp32_touch_state, OCTV_I2C_PORT, OCTV_I2C_SCL_GPIO, OCTV_I2C_SDA_GPIO, OCTV_SENSOR_RESET_GPIO, OCTV_SENSOR_INT_GPIO, OCTV_I2C_FREQ_HZ, NULL); - grid_esp32_touch_scan(&grid_esp32_touch_state); ui_ptr = ui; diff --git a/grid_esp/components/grid_esp32_port/grid_esp32_port.c b/grid_esp/components/grid_esp32_port/grid_esp32_port.c index 56a75794..243ca052 100644 --- a/grid_esp/components/grid_esp32_port/grid_esp32_port.c +++ b/grid_esp/components/grid_esp32_port/grid_esp32_port.c @@ -414,6 +414,7 @@ void grid_esp32_port_task(void* arg) { // Watchdog-style tracking for the rolling ID uint8_t watchdog_rollid_last_recv = rollid.last_recv; + uint8_t watchdog_rollid_last_errors = rollid.errors; uint64_t watchdog_rollid_last_time = grid_platform_rtc_get_micros(); // Allocate custom SPI transaction queue @@ -453,25 +454,25 @@ void grid_esp32_port_task(void* arg) { while (1) { - // When the rolling ID changes, reset watchdog + // When the rolling ID changes without error, reset watchdog if (rollid.last_recv != watchdog_rollid_last_recv) { watchdog_rollid_last_time = grid_platform_rtc_get_micros(); - watchdog_rollid_last_recv = rollid.last_recv; - rp2040_active = true; - } + // Only mark RP2040 active if the byte was the expected next value (no new error) + if (rollid.errors == watchdog_rollid_last_errors) { + rp2040_active = true; + } - // Rolling ID watchdog expiration - if (grid_platform_rtc_get_elapsed_time(watchdog_rollid_last_time) > 100000) { + watchdog_rollid_last_recv = rollid.last_recv; + watchdog_rollid_last_errors = rollid.errors; + } - grid_platform_printf("ERROR: SPI frozen\n"); + // Rolling ID watchdog expiration (only if RP2040 was ever seen) + if (rp2040_active && + grid_platform_rtc_get_elapsed_time(watchdog_rollid_last_time) > 100000) { watchdog_rollid_last_time = grid_platform_rtc_get_micros(); - - grid_alert_all_set(&grid_led_state, GRID_LED_COLOR_PURPLE, 50); - grid_alert_all_set_frequency(&grid_led_state, -4); - grid_alert_all_set_phase(&grid_led_state, 100); } // Check if USB is connected and start animation diff --git a/grid_esp/components/grid_esp32_touch/bb_captouch.cpp b/grid_esp/components/grid_esp32_touch/bb_captouch.cpp index cf3dd8ed..1294d1b9 100644 --- a/grid_esp/components/grid_esp32_touch/bb_captouch.cpp +++ b/grid_esp/components/grid_esp32_touch/bb_captouch.cpp @@ -1,353 +1,882 @@ -// BitBank Capacitive Touch Sensor Library -// Stripped to MXT144 only, non-Arduino ESP-IDF port +// +// BitBank Capactive Touch Sensor Library +// Written by Larry Bank // // Copyright 2023 BitBank Software, Inc. All Rights Reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 - +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== #include "bb_captouch.h" +#ifndef ARDUINO +#include "rom/ets_sys.h" +#endif + +static const BBCT_CONFIG _configs[] = { + // sda, scl, irq, rst + {21, 22, 7, 23}, // TOUCH_T_QT_C6 + {19, 20, -1, 38}, // TOUCH_CYD_550 + {5, 6, 7, 13}, // T-Display S3 Pro + {15, 20, 11, 16}, // T-Display-S3-Long + {21, 22, -1, -1}, // CYD_22C + {33, 32, 21, 25}, // CYD_24C + {4, 5, 0, 1}, // CYD_128 + {33, 32, 21, 25}, // CYD_35C + {7, 8, 41, 40}, // CYD_518 + {8, 4, 3, -1}, // CYD_543 + {21, 22, 39, -1}, // M5_CORE2 + {12, 11, -1, -1}, // M5_CORES3 + {21, 22, 36, -1}, // M5_PAPER + {6, 5 ,7, -1}, // WT32_SC01_PLUS + {17, 18, -1, 38}, // MakerFabs 4" 480x480 + {38,39,40,-1}, // MakerFabs 3.5" 320x480 + {7, 6, 9, 8}, // TOUCH_T_DISPLAY_S3_AMOLED (1.64") + {15, 14, 21, -1}, // TOUCH_WS_AMOLED_18 (Waveshare 1.8" 368x448 AMOLED) + {41, 42, 48, -1}, // TOUCH_M5_PAPERS3 + {11, 10, 4, -1}, // TOUCH_WS_ROUND_146 + {47,48,-1,3}, // TOUCH_WS_AMOLED_241 + {11,10,14,13}, // TOUCH_WS_LCD_169 + {1,3,4,2}, // TOUCH_VIEWE_2432 + {7, 6, 9, 8}, // TOUCH_T_DISPLAY_S3_AMOLED_164 + {0,0,0,0} + }; -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" +#ifndef ARDUINO +void BBCapTouch::pinMode(uint8_t u8Pin, uint8_t u8Mode) +{ + gpio_config_t io_conf = {}; + + io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt + //bit mask of the pins that you want to set,e.g.GPIO18/19 + io_conf.pin_bit_mask = (1 << u8Pin); + io_conf.pull_down_en = (gpio_pulldown_t)0; //disable pull-down mode + io_conf.pull_up_en = (gpio_pullup_t)0; //disable pull-up mode + if (u8Mode == INPUT) { + io_conf.mode = GPIO_MODE_INPUT; + } else { // must be output + io_conf.mode = GPIO_MODE_OUTPUT; + } + gpio_config(&io_conf); //configure GPIO with the given settings +} /* pinMode() */ +void BBCapTouch::digitalWrite(uint8_t u8Pin, uint8_t u8State) +{ + gpio_set_level((gpio_num_t)u8Pin, u8State); +} /* digitalWrite() */ +#endif // !ARDUINO +void BBCapTouch::reset(int iRST) +{ + pinMode(iRST, OUTPUT); + digitalWrite(iRST, LOW); + delay(100); + digitalWrite(iRST, HIGH); + delay(250); +} /* reset() */ // -// Initialize the MXT144 +// Initalize the MXT144 - an overly complicated mess of a touch sensor // -int BBCapTouch::initMXT(void) { - uint8_t ucTemp[32]; - int i, iObjCount, iReportID; - uint16_t u16, u16Offset; - - I2CReadRegister16(_iAddr, 0, ucTemp, 7); - iObjCount = ucTemp[6]; - _mxtdata.matrix_x_size = ucTemp[4]; - _mxtdata.matrix_y_size = ucTemp[5]; - ets_printf("mxt initMXT: family=0x%02X variant=0x%02X fw=%d.%d obj_count=%d matrix=%dx%d\r\n", - ucTemp[0], ucTemp[1], ucTemp[2], ucTemp[3], iObjCount, - _mxtdata.matrix_x_size, _mxtdata.matrix_y_size); - if (iObjCount < 1 || iObjCount > 64) { - return CT_ERROR; - } - u16Offset = 7; - iReportID = 1; - for (i = 0; i < iObjCount; i++) { - I2CReadRegister16(_iAddr, u16Offset, ucTemp, 6); - u16 = ucTemp[1] | (ucTemp[2] << 8); - ets_printf(" obj[%d] type=%d addr=0x%04X size=%d instances=%d rids=%d\r\n", - i, ucTemp[0], u16, ucTemp[3], ucTemp[4], ucTemp[5]); - switch (ucTemp[0]) { - case 2: _mxtdata.t2_encryption_status_address = u16; break; - case 5: - _mxtdata.t5_message_processor_address = u16; - _mxtdata.t5_max_message_size = ucTemp[3] + 1; // actual size = size_field + 1 - break; - case 6: _mxtdata.t6_command_processor_address = u16; break; - case 7: _mxtdata.t7_powerconfig_address = u16; break; - case 8: _mxtdata.t8_acquisitionconfig_address = u16; break; - case 15: - _mxtdata.t15_key_array_address = u16; - _mxtdata.t15_first_report_id = iReportID + 1; // +1: sensor allocates one status slot before key data - break; - case 37: _mxtdata.t37_diagnostic_address = u16; break; - case 44: _mxtdata.t44_message_count_address = u16; break; - case 46: _mxtdata.t46_cte_config_address = u16; break; - case 56: _mxtdata.t56_shieldless_address = u16; break; - case 100: - _mxtdata.t100_multiple_touch_touchscreen_address = u16; - _mxtdata.t100_first_report_id = iReportID; - break; - default: break; - } - u16Offset += 6; - // Type 166 appears in the object table with rids=12/instances=12 but does NOT - // allocate user-visible report IDs on this chip variant — skip its contribution. - if (ucTemp[0] != 166) { - iReportID += ucTemp[5] * (ucTemp[4] + 1); - } - } - return CT_SUCCESS; -} +int BBCapTouch::initMXT(void) +{ +uint8_t ucTemp[32]; +int i, iObjCount, iReportID; +uint16_t u16, u16Offset; + +// Read information block (first 7 bytes of address space) + I2CReadRegister16(_iAddr, 0, ucTemp, 7); + iObjCount = ucTemp[6]; + if (iObjCount < 1 || iObjCount >64) { // invalid number of items + return CT_ERROR; + } + u16Offset = 7; // starting offset of first object + // Read the objects one by one to get the memory offests to the info we will need + iReportID = 1; + // Serial.printf("object count = %d\n", iObjCount); + for (i=0; ibegin(iSDA, iSCL); // this is specific to ESP32 MCUs + myWire->setClock(u32Speed); + myWire->setTimeout(1000); +#else i2c_config_t conf = {}; - conf.mode = I2C_MODE_MASTER; - conf.sda_io_num = iSDA; - conf.scl_io_num = iSCL; - conf.sda_pullup_en = GPIO_PULLUP_ENABLE; - conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = iSDA; + conf.scl_io_num = iSCL; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; conf.master.clk_speed = u32Speed; - i2c_param_config(I2C_NUM_0, &conf); - i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0); + i2c_driver_delete(I2C_NUM_0); // remove driver (if installed) + i2c_param_config(I2C_NUM_0, &conf); // configure I2C device 0 + i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0); // configure with no send or receive buffers +#endif + _iType = CT_TYPE_UNKNOWN; - if (!I2CTest(MXT144_ADDR)) { - return CT_ERROR; + if (iRST != -1) { + reset(iRST); } - int rc = initMXT(); - if (rc == CT_SUCCESS) { - // T7: acquisition timing (free-run at 16ms intervals). - { - uint8_t t7wr[2 + 4] = {}; - t7wr[0] = (uint8_t)(_mxtdata.t7_powerconfig_address); - t7wr[1] = (uint8_t)(_mxtdata.t7_powerconfig_address >> 8); - t7wr[2] = 16; // IDLEACQINT: 16ms - t7wr[3] = 16; // ACTVACQINT: 16ms - I2CWrite(_iAddr, t7wr, 2 + 4); - } - // T8: charge time and measurement parameters (reference: Table 11-1). - { - uint8_t t8wr[2 + 14] = {}; - t8wr[0] = (uint8_t)(_mxtdata.t8_acquisitionconfig_address); - t8wr[1] = (uint8_t)(_mxtdata.t8_acquisitionconfig_address >> 8); - t8wr[2 + 0] = 26; // CHRGTIME - t8wr[2 + 10] = 11; // MEASALLOW - t8wr[2 + 11] = 8; // MEASIDLEDEF - t8wr[2 + 12] = 2; // MEASACTVDEF - I2CWrite(_iAddr, t8wr, 2 + 14); - } +#ifdef FUTURE + if (I2CTest(AXS15231_ADDR)) { + _iType = CT_TYPE_AXS15231; + _iAddr = AXS15231_ADDR; + if (iRST != -1) { + reset(iRST); + } + return CT_SUCCESS; + } // AXS15231 +#endif - // T46: CTE (charge transfer engine), reference: IDLESYNCSPERX=16, ACTSYNCSPERX=16. - { - uint8_t t46wr[2 + 11] = {}; - t46wr[0] = (uint8_t)(_mxtdata.t46_cte_config_address); - t46wr[1] = (uint8_t)(_mxtdata.t46_cte_config_address >> 8); - t46wr[2 + 0] = 0x01; // CTRL: ENABLE - t46wr[2 + 2] = 16; // IDLESYNCSPERX - t46wr[2 + 3] = 16; // ACTIVESYNCSPERX - t46wr[2 + 4] = 4; // ADCSPERSYNC - t46wr[2 + 5] = 1; // PULSESPERADC - I2CWrite(_iAddr, t46wr, 2 + 11); + if (I2CTest(SPD2010_ADDR)) { + _iType = CT_TYPE_SPD2010; + _iAddr = SPD2010_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT_PULLUP); } + return CT_SUCCESS; + } + if (I2CTest(TMA445_ADDR)) { + _iType = CT_TYPE_TMA445; + _iAddr = TMA445_ADDR; +// if (iINT != -1) { +// pinMode(iINT, INPUT_PULLUP); +// } + // send soft reset + ucTemp[0] = 0; + ucTemp[1] = 1; + I2CWrite(_iAddr, ucTemp, 2); + delay(50); + // send security key + I2CWrite(_iAddr, tma445_key, sizeof(tma445_key)); + delay(88); - // T7 must be written BEFORE T6 CALIBRATE so the scanner restarts with the correct interval. - // (Blank NVM leaves IDLEACQINT=0 which stops the scanner after one measurement.) - { - uint8_t rb[4] = {}; - I2CReadRegister16(_iAddr, _mxtdata.t7_powerconfig_address, rb, 4); - ets_printf("mxt T7 readback: IDLEACQINT=%d ACTVACQINT=%d ACTV2IDLETO=%d\r\n", rb[0], rb[1], rb[2]); - I2CReadRegister16(_iAddr, _mxtdata.t46_cte_config_address, rb, 4); - ets_printf("mxt T46 readback: CTRL=0x%02X MODE=%d IDLESYNCSPERX=%d ACTSYNCSPERX=%d\r\n", rb[0], rb[1], rb[2], rb[3]); - } + uint8_t tries = 0; + cyttsp_bootloader_data bl_data = {}; + do { + delay(20); + I2CRead(_iAddr, (uint8_t *)&bl_data, sizeof(bl_data)); + } while (bl_data.bl_status & 0x10 && tries++ < 10); // while bootloader mode + if (tries >= 10) ets_printf("bootloader mode timed out\r\n"); + // set OP mode + ucTemp[0] = 0; + ucTemp[1] = 0; // start op mode + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + if (I2CTest(MXT144_ADDR)) { + _iType = CT_TYPE_MXT144; + _iAddr = MXT144_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT); + } + if (iRST != -1) { + reset(iRST); + } + return initMXT(); + } + if (I2CTest(CHSC6540_ADDR)) { + _iType = CT_TYPE_CHSC6540; + _iAddr = CHSC6540_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT); + } + ucTemp[0] = ucTemp[1] = 0x5a; // set interrupt mode + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + if (I2CTest(CST226_ADDR)) { + _iType = CT_TYPE_CST226; + _iAddr = CST226_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT); + } + return CT_SUCCESS; + } + if (I2CTest(GT911_ADDR1) || I2CTest(GT911_ADDR2)) { + _iType = CT_TYPE_GT911; + } + if (_iType == CT_TYPE_GT911) { // reset the sensor to start it + pinMode(iRST, OUTPUT); + pinMode(iINT, OUTPUT); + digitalWrite(iINT, LOW); + digitalWrite(iRST, LOW); + delay(5); + digitalWrite(iINT, LOW); // set I2C addr to ADDR1 + delay(1); + digitalWrite(iRST, HIGH); // when it comes out of reset, it samples INT + delay(10); + digitalWrite(iINT, LOW); + delay(50); + pinMode(iINT, INPUT); + // double check the I2C addr in case it changed + if (I2CTest(GT911_ADDR1)) { + _iAddr = GT911_ADDR1; + } else if (I2CTest(GT911_ADDR2)) { + _iAddr = GT911_ADDR2; + } + } else if (I2CTest(FT6X36_ADDR1)) { + _iType = CT_TYPE_FT6X36; + _iAddr = FT6X36_ADDR1; + } else if (I2CTest(FT6X36_ADDR2)) { + _iType = CT_TYPE_FT6X36; + _iAddr = FT6X36_ADDR2; + } else if (I2CTest(CST820_ADDR)) { + _iType = CT_TYPE_CST820; + _iAddr = CST820_ADDR; + if (iRST != -1) { + reset(iRST); + } + } else { +#ifdef ARDUINO + myWire->end(); +#else + i2c_driver_delete(I2C_NUM_0); +#endif + return CT_ERROR; // no device found + } + return CT_SUCCESS; +} /* init() */ - // T56 Shieldless: reference config (Table 11-1) enables T56 with INTTIME=26. - // Write only the first 2 fields (CTRL + INTTIME) to avoid overwriting adjacent objects. - if (_mxtdata.t56_shieldless_address) { - uint8_t t56wr[2 + 2] = {}; - t56wr[0] = (uint8_t)(_mxtdata.t56_shieldless_address); - t56wr[1] = (uint8_t)(_mxtdata.t56_shieldless_address >> 8); - t56wr[2 + 0] = 0x01; // CTRL: ENABLE - t56wr[2 + 1] = 26; // INTTIME - I2CWrite(_iAddr, t56wr, 2 + 2); - } +// Initialize the touch controller from a pre-defined configuration name +#ifdef ARDUINO +int BBCapTouch::init(int iConfigName) +{ +const BBCT_CONFIG *pC = &_configs[iConfigName]; - // T100: multitouch touchscreen. XSIZE/YSIZE must match the sensor matrix. - // Object table size field is (actual-1), so actual T100 size = 68 bytes (offsets 0-67). - // TCHEVENTCFG offset is uncertain across MXT variants (offset 4 vs 5) — set both. - // T100 layout: [0]=CTRL [4/5]=TCHEVENTCFG [7]=NUMTCH - // [10]=XSIZE [14-15]=XRANGE [21]=YSIZE [25-26]=YRANGE [33]=TCHTHR [34]=TCHHYST - { - uint8_t t100wr[2 + 68] = {}; - t100wr[0] = (uint8_t)(_mxtdata.t100_multiple_touch_touchscreen_address); - t100wr[1] = (uint8_t)(_mxtdata.t100_multiple_touch_touchscreen_address >> 8); - t100wr[2 + 0] = 0x07; // CTRL: ENABLE | RPTEN | SCANEN - t100wr[2 + 4] = 0xFF; // TCHEVENTCFG (offset 4, all events) - t100wr[2 + 5] = 0xFF; // TCHEVENTCFG (offset 5, all events — covers both placements) - t100wr[2 + 7] = 5; // NUMTCH - t100wr[2 + 10] = _mxtdata.matrix_x_size; // XSIZE - t100wr[2 + 14] = 0xFF; // XRANGE lo - t100wr[2 + 15] = 0x0F; // XRANGE hi - t100wr[2 + 21] = _mxtdata.matrix_y_size; // YSIZE - t100wr[2 + 25] = 0xFF; // YRANGE lo - t100wr[2 + 26] = 0x0F; // YRANGE hi - t100wr[2 + 33] = 5; // TCHTHR - t100wr[2 + 34] = 2; // TCHHYST - I2CWrite(_iAddr, t100wr, 2 + 68); + if (iConfigName < 0 || iConfigName >= TOUCH_COUNT) { + return CT_ERROR; + } - } - // BACKUP (T6[1] = 0x55): save RAM config → NVM to clear CFGERR. - // Per datasheet §9.3, chip auto-resets after BACKUP — must read the RESET - // message from T5 before issuing any further commands. - { - uint8_t t5_size = _mxtdata.t5_max_message_size; - uint8_t msg[16] = {}; - - uint16_t backup_reg = _mxtdata.t6_command_processor_address + 1; - uint8_t backup_cmd[3] = {(uint8_t)backup_reg, (uint8_t)(backup_reg >> 8), 0x55}; - I2CWrite(_iAddr, backup_cmd, 3); - ets_printf("mxt: BACKUP issued, waiting for auto-reset...\r\n"); - - bool reset_seen = false; - for (int ms = 0; ms < 2000 && !reset_seen; ms += 10) { - vTaskDelay(pdMS_TO_TICKS(10)); - uint8_t count = 0; - I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, &count, 1); - for (int m = 0; m < count; m++) { - memset(msg, 0, sizeof(msg)); - I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, msg, t5_size); - ets_printf("mxt: BACKUP msg @%dms rid=%d status=0x%02X\r\n", ms, msg[0], msg[1]); - if (msg[1] & 0x80) { // RESET bit — BACKUP complete - reset_seen = true; - } - } - } - if (!reset_seen) { - ets_printf("mxt: BACKUP timed out — no RESET message received\r\n"); - } - } + if (iConfigName == TOUCH_WS_AMOLED_241) { // touch is rotated + _iOrientation = 270; + _iWidth = 450; + _iHeight = 600; - // CALIBRATE (T6[2] = 0x01): establish fresh baseline after BACKUP. - // Poll T5 messages to confirm CAL completes (CAL bit set then cleared). - { - uint8_t t5_size = _mxtdata.t5_max_message_size; - uint8_t msg[16] = {}; - - uint16_t cal_reg = _mxtdata.t6_command_processor_address + 2; - uint8_t cal_cmd[3] = {(uint8_t)cal_reg, (uint8_t)(cal_reg >> 8), 0x01}; - I2CWrite(_iAddr, cal_cmd, 3); - ets_printf("mxt: CALIBRATE issued\r\n"); - - bool cal_done = false; - for (int ms = 0; ms < 2000 && !cal_done; ms += 10) { - vTaskDelay(pdMS_TO_TICKS(10)); - uint8_t count = 0; - I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, &count, 1); - for (int m = 0; m < count; m++) { - memset(msg, 0, sizeof(msg)); - I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, msg, t5_size); - ets_printf("mxt: CAL msg @%dms rid=%d status=0x%02X\r\n", ms, msg[0], msg[1]); - // CAL complete: T6 message (rid=1) with CAL bit (0x10) clear - if (msg[0] == 1 && !(msg[1] & 0x10) && !(msg[1] & 0x80)) { - ets_printf("mxt: CALIBRATE complete, STATUS=0x%02X\r\n", msg[1]); - cal_done = true; - } - } - } - if (!cal_done) { - ets_printf("mxt: CALIBRATE timed out\r\n"); - } - } - } + } + if (iConfigName == TOUCH_WS_AMOLED_18 || iConfigName == TOUCH_WS_ROUND_146) { + // need to release the RESET line which is controlled by an + // I/O expander (TCA9554) + uint8_t ucEXIO; + if (iConfigName == TOUCH_WS_AMOLED_18) ucEXIO = 6; // touch reset (AMOLED 1.8) + else ucEXIO = 1; // touch reset (1.46" round) + Wire.end(); + Wire.begin(pC->i8SDA, pC->i8SCL); + Wire.beginTransmission(0x20); + Wire.write(1); // output port register + Wire.write(~ucEXIO); // set touch controller reset low + Wire.write(0); // polarity inversion all disabled + Wire.write(~7); // enable P0+P1+P2 as an output (connected to RESET) + Wire.endTransmission(); + delay(50); + Wire.beginTransmission(0x20); + Wire.write(1); // output port register + Wire.write(0xff); // set all outputs high (disable resets) + Wire.endTransmission(); + delay(50); + if (iConfigName == TOUCH_WS_AMOLED_18) { + Wire.beginTransmission(0x38); + Wire.write(0xa5); // power mode + Wire.write(0); // active + Wire.endTransmission(); + } + Wire.end(); + } + return init(pC->i8SDA, pC->i8SCL, pC->i8RST, pC->i8IRQ, +#ifdef ARDUINO + 400000, &Wire); +#else + 400000); +#endif +} /* init() */ +#endif // ARDUINO +// +// Test if an I2C device is monitoring an address +// return true if it responds, false if no response +// +bool BBCapTouch::I2CTest(uint8_t u8Addr) +{ + // Check if a device acknowledges the address. +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + return(myWire->endTransmission(true) == 0); +#else // allow 100ms for device to respond + uint8_t c = 0; + return (i2c_master_write_to_device(I2C_NUM_0, u8Addr, &c, 1, 10) == ESP_OK); +#endif +} /* I2CTest() */ +// +// Write I2C data +// quits if a NACK is received and returns 0 +// otherwise returns the number of bytes written +// +int BBCapTouch::I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen) +{ + int rc = 0; + +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + myWire->write(pData, (uint8_t)iLen); + rc = !myWire->endTransmission(); +#else + rc = (i2c_master_write_to_device(I2C_NUM_0, u8Addr, pData, iLen, 100) == ESP_OK); +#endif return rc; -} +} /* I2CWrite() */ +// +// Read N bytes starting at a specific 16-bit I2C register +// +int BBCapTouch::I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen) +{ + int i = 0; + +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + if (_iType == CT_TYPE_MXT144) { // little endian + myWire->write((uint8_t)u16Register); // low byte + myWire->write((uint8_t)(u16Register>>8)); // high byte + } else { // big endian address + myWire->write((uint8_t)(u16Register>>8)); // high byte + myWire->write((uint8_t)u16Register); // low byte + } + myWire->endTransmission(); + myWire->requestFrom(u8Addr, (uint8_t)iLen); + while (i < iLen) + { + pData[i++] = myWire->read(); + } +#else + uint8_t ucTemp[4]; + int rc; + if (_iType == CT_TYPE_MXT144) { // little endian + ucTemp[1] = (uint8_t)(u16Register>>8); // high byte + ucTemp[0] = (uint8_t)u16Register; // low byte + } else { + ucTemp[0] = (uint8_t)(u16Register>>8); // high byte + ucTemp[1] = (uint8_t)u16Register; // low byte + } + rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, ucTemp, 2, pData, iLen, 100); + if (rc == ESP_OK) { + i = iLen; + } +#endif + return i; +} /* I2CReadRegister16() */ // -// Read touch samples from the MXT144 +// Read N bytes starting at a specific I2C internal register +// returns 1 for success, 0 for error // -int BBCapTouch::getSamples(TOUCHINFO *pTI) { - uint8_t ucTemp[32]; - int i, j; +int BBCapTouch::I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen) +{ + int rc; + int i = 0; - if (!pTI) return 0; +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + myWire->write(u8Register); + myWire->endTransmission(); + myWire->requestFrom(u8Addr, (uint8_t)iLen); + // i = myWire->readBytes(pData, iLen); + while (myWire->available() && i < iLen) + { + pData[i++] = myWire->read(); + } +#else + rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, &u8Register, 1, pData, iLen, 100); + i = (rc == ESP_OK); +#endif + return i; +} /* I2CReadRegister() */ +// +// Read N bytes +// +int BBCapTouch::I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen) +{ + int i = 0; + +#ifdef ARDUINO + myWire->requestFrom(u8Addr, (uint8_t)iLen); + while (i < iLen) + { + pData[i++] = myWire->read(); + } +#else + int rc; + rc = i2c_master_read_from_device(I2C_NUM_0, u8Addr, pData, iLen, 100); + i = (rc == ESP_OK) ? iLen : 0; +#endif + return i; +} /* I2CRead() */ +// +// Private function to rotate touch samples if the user +// specified a new display orientation +// +void BBCapTouch::fixSamples(TOUCHINFO *pTI) +{ +int i, x, y; + + for (i=0; icount; i++) { + switch (_iOrientation) { + case 90: + x = pTI->y[i]; + y = _iWidth - 1 - pTI->x[i]; + pTI->x[i] = x; + pTI->y[i] = y; + break; + case 180: + pTI->x[i] = _iWidth - 1 - pTI->x[i]; + pTI->y[i] = _iHeight - 1 - pTI->y[i]; + break; + case 270: + x = _iHeight - 1 - pTI->y[i]; + y = pTI->x[i]; + pTI->x[i] = x; + pTI->y[i] = y; + break; + default: // do nothing + break; + } + } +} /* fixSamples() */ +void BBCapTouch::SPD2010ClearInt(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 2; + ucTemp[1] = 0; + ucTemp[2] = 1; + ucTemp[3] = 0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010ClearInt() */ + +void BBCapTouch::SPD2010CPUStart(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 4; + ucTemp[1] = 0; + ucTemp[2] = 1; + ucTemp[3] = 0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010CPUStart() */ + +uint8_t BBCapTouch::SPD2010Status(int *iNextLen) +{ + uint8_t ucTemp[8]; + I2CReadRegister16(_iAddr, 0xfc02, ucTemp, 8); + *iNextLen = (ucTemp[3] << 8) | ucTemp[2]; + return ucTemp[5]; +} /* SPD2010Status() */ + +void BBCapTouch::SPD2010TouchStart(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 0x46; + ucTemp[1] = 0x0; + ucTemp[2] = 0x0; + ucTemp[3] = 0x0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010TouchStart() */ + +void BBCapTouch::SPD2010PointMode(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 0x50; + ucTemp[1] = 0x0; + ucTemp[2] = 0x0; + ucTemp[3] = 0x0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010PointMode() */ + +// +// Read the touch points +// returns 0 (none), 1 if touch points are available +// The point count and info is returned in the TOUCHINFO structure +// +int BBCapTouch::getSamples(TOUCHINFO *pTI) +{ +uint8_t c, *s, ucTemp[32]; +int i, j, rc = 0; + + if (!pTI) + return 0; pTI->count = 0; + if (_iType == CT_TYPE_UNKNOWN) return 0; // library not initialized? - if (!_mxtdata.t44_message_count_address) { - ets_printf("mxt: no t44 addr\r\n"); - return 0; + if (_iType == CT_TYPE_SPD2010) { + static int iNextLen = 0; + int iReadLen; + uint8_t ucStatus; + // first read the status + I2CReadRegister16(_iAddr, 0x2000, ucTemp, 4); + // Byte 0 has a bit field with the following info: + // 0 = point exists + // 1 = gesture + // 3 = aux, cytang + // Byte 1 + // 3 = cpu run + // 4 = tint low + // 5 = tic in cpu + // 6 = tic in bios + // 7 = tic busy + iReadLen = (ucTemp[3]<<8) + ucTemp[2]; + // Serial.printf("status byte 0: 0x%02x, 0x%02x, read len = %d\n", ucTemp[0], ucTemp[1], iReadLen); + if (ucTemp[1] & 0x40) { // tic in bios + SPD2010ClearInt(); // Write Clear TINT Command + SPD2010CPUStart(); // Write CPU Start Command + } else if (ucTemp[1] & 0x20) { // tic in cpu + SPD2010PointMode(); // Write Touch Change Command + SPD2010TouchStart(); // Write Touch Start Command + SPD2010ClearInt(); + } else if ((ucTemp[1] & 8) && iReadLen == 0) { // cpu run + SPD2010ClearInt(); + } else if (ucTemp[0] & 1 || ucTemp[0] & 2) { // point or gesture + uint8_t ucData[64]; // 4-byte header plus up to 10 fingers of 6 bytes each + I2CReadRegister16(_iAddr, 0x0003, ucData, iReadLen); + // Serial.printf("readlen: %d, data[4]: 0x%02x\n", iReadLen, ucData[4]); + if (ucData[4] <= 0xa && ucTemp[0] & 1) { // check_id < 10 && point exists + rc = 1; // touch event + pTI->count = (iReadLen - 4)/6; // number of touch points + for (int i=0; icount; i++) { + int iOffset = i*6; + pTI->x[i] = ((ucData[7+iOffset] & 0xf0) << 4) | ucData[5+iOffset]; + pTI->y[i] = ((ucData[7+iOffset] & 0x0f) << 8) | ucData[6+iOffset]; + pTI->area[i] = ucData[8+iOffset]; + } + } + // gestures... + hdp_done_check: + /* Read HDP Status */ + ucStatus = SPD2010Status(&iNextLen); +// Serial.printf("status: 0x%02\n", ucStatus); + if (ucStatus == 0x82) { + SPD2010ClearInt(); + } else if (ucStatus == 0x00) { // Read HDP Remain Data + // Read_HDP_REMAIN_DATA(&tp_hdp_status); + goto hdp_done_check; + } + } else if (ucTemp[1] & 8 && ucTemp[0] & 8) { // cpu run && aux + SPD2010ClearInt(); + } + return rc; } - I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, ucTemp, 1); - j = ucTemp[0]; - if (j > 0) ets_printf("mxt: msg_count=%d t100_frid=%d\r\n", j, _mxtdata.t100_first_report_id); - uint8_t t5_size = (_mxtdata.t5_max_message_size && _mxtdata.t5_max_message_size <= 32) - ? _mxtdata.t5_max_message_size : MXT_MESSAGE_SIZE; - for (i = 0; i < j; i++) { - I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, ucTemp, t5_size); - ets_printf("mxt: rid=%d b1=0x%02X x=%d y=%d\r\n", ucTemp[0], ucTemp[1], - ucTemp[2]|(ucTemp[3]<<8), ucTemp[4]|(ucTemp[5]<<8)); - // T100: RID+0 = screen status, RID+1..+N = finger 0..N-1 - if (ucTemp[0] >= _mxtdata.t100_first_report_id + 1 && - ucTemp[0] < _mxtdata.t100_first_report_id + 1 + 5) { - uint8_t finger_idx = ucTemp[0] - _mxtdata.t100_first_report_id - 1; - uint8_t event = ucTemp[1] & 0xf; - if (finger_idx + 1 > (uint8_t)pTI->count) pTI->count = finger_idx + 1; - pTI->x[finger_idx] = ucTemp[2] + (ucTemp[3] << 8); - pTI->y[finger_idx] = ucTemp[4] + (ucTemp[5] << 8); - if (event == 1 || event == 4) { // press / move - pTI->area[finger_idx] = 50; - } else if (event == 5) { // release - pTI->area[finger_idx] = 0; + if (_iType == CT_TYPE_TMA445) { + uint8_t hst_mode; + I2CReadRegister(_iAddr, 0, ucTemp, 14); // read up to 2 touch points + pTI->count = ucTemp[2]; // touch point count + if (pTI->count > 0) { + pTI->y[0] = (ucTemp[5]*256) + ucTemp[6]; + pTI->x[0] = (ucTemp[3]*256) + ucTemp[4]; + pTI->area[0] = ucTemp[7]; + if (pTI->count == 2) { // get second touch point + pTI->y[1] = (ucTemp[11]*256) + ucTemp[12]; + pTI->x[1] = (ucTemp[9]*256) + ucTemp[10]; + pTI->area[1] = ucTemp[13]; } + // do handshake + I2CReadRegister(_iAddr, 0, &hst_mode, 1); + hst_mode ^= CY_HNDSHK_BIT; // toggle handshake bit + ucTemp[0] = 0; + ucTemp[1] = hst_mode; // send it back + I2CWrite(_iAddr, ucTemp, 2); + return 1; } + return 0; } - return (pTI->count > 0); -} + if (_iType == CT_TYPE_MXT144) { + if (!_mxtdata.t44_message_count_address) { + return 0; // No message offset, so we can't read anything :( + } + I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, ucTemp, 1); + j = ucTemp[0]; // object count + // As each message is read from the sensor, the internal count + // is decremented. It appears that it can hold 6 messages maximum + // before you must read them to receive more. + for (i = 0; i < j; i++) { // read the messages + I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, ucTemp, MXT_MESSAGE_SIZE); // each message is 6 bytes + // check report_id + if (ucTemp[0] >= _mxtdata.t100_first_report_id + 2 && + ucTemp[0] < _mxtdata.t100_first_report_id + 2 + 5) { + uint8_t finger_idx = ucTemp[0] - _mxtdata.t100_first_report_id - 2; + uint8_t event = ucTemp[1] & 0xf; + if (finger_idx+1 > pTI->count) pTI->count = finger_idx+1; + pTI->x[finger_idx] = ucTemp[2] + (ucTemp[3] << 8); + pTI->y[finger_idx] = ucTemp[4] + (ucTemp[5] << 8); + if (event == 1 || event == 4) { // move/press event + pTI->area[finger_idx] = 50; + } else if (event == 5) { // release + pTI->area[finger_idx] = 0; + } + } // if touch report + } // for each report + return (pTI->count > 0); + } // MXT144 -// -// Read the T37 diagnostic object and print a raw delta matrix. -// Command 0x10 = DELTA_DATA: shows capacitance change vs baseline. -// Values change when a finger is present; all-zero means the sensor is not sensing. -// -void BBCapTouch::dumpDiagnostic(void) { - if (!_mxtdata.t37_diagnostic_address || !_mxtdata.t6_command_processor_address) { - ets_printf("mxt diag: T37 or T6 address not found in object table\r\n"); - return; + if (_iType == CT_TYPE_AXS15231) { + uint8_t ucReadCMD[8] = {0xb5,0xab,0xa5,0x5a,0,0,0,0x8}; + I2CWrite(_iAddr, (uint8_t *)ucReadCMD, 8); + I2CRead(_iAddr, ucTemp, 14); // read up to 2 touch points + c = ucTemp[1]; // number of touch points + if (c == 0 || c > 2 || ucTemp[0] != 0) return 0; + pTI->count = c; + j = 0; // buffer offset + for (i=0; ix[i] = ((ucTemp[j+2] & 0xf) << 8) + ucTemp[j+3]; + pTI->y[i] = ((ucTemp[j+4] & 0xf) << 8) + ucTemp[j+5]; + pTI->area[i] = 1; + j += 6; + } + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } // AXS15231 + + if (_iType == CT_TYPE_CST226) { + i = I2CReadRegister(_iAddr, 0, ucTemp, 28); // read the whole block of regs +// Serial.printf("I2CReadRegister returned %d\n", i); +#ifdef FUTURE + if (ucTemp[0] == 0x83 && ucTemp[1] == 0x17 && ucTemp[5] == 0x80) { + // home button pressed + return 0; + } + if (ucTemp[6] != 0xab) return 0; + if (ucTemp[0] == 0xab) return 0; + if (ucTemp[5] == 0x80) return 0; + c = ucTemp[5] & 0x7f; + if (c > 5 || c == 0) { // invalid point count + ucTemp[0] = 0; + ucTemp[1] = 0xab; + I2CWrite(_iAddr, ucTemp, 2); // reset + return 0; + } +#endif + c = 1; // debug + pTI->count = c; + // Serial.printf("count = %d\n", c); + j = 0; + for (i=0; ix[i] = (uint16_t)((ucTemp[j+1] << 4) | ((ucTemp[j+3] >> 4) & 0xf)); + pTI->y[i] = (uint16_t)((ucTemp[j+2] << 4) | (ucTemp[j+3] & 0xf)); + pTI->pressure[i] = ucTemp[j+4]; + j = (i == 0) ? (j+7) : (j+5); + } + if (_iOrientation != 0) fixSamples(pTI); + return 1; } - int cols = _mxtdata.matrix_x_size ? _mxtdata.matrix_x_size : 12; - int rows = _mxtdata.matrix_y_size ? _mxtdata.matrix_y_size : 12; - - uint16_t diag_reg = _mxtdata.t6_command_processor_address + 5; - uint8_t cmd[3]; - cmd[0] = (uint8_t)diag_reg; - cmd[1] = (uint8_t)(diag_reg >> 8); - uint8_t buf[2 + 128] = {}; - - // --- Reference data (0x11): uint16 per node, 2 bytes each. - // Page 0 = 64 nodes. Non-zero here means CTE is running and has a baseline. - cmd[2] = 0x11; - I2CWrite(_iAddr, cmd, 3); - vTaskDelay(pdMS_TO_TICKS(20)); - I2CReadRegister16(_iAddr, _mxtdata.t37_diagnostic_address, buf, 2 + 128); - ets_printf("mxt T37 mode=0x%02X page=%d (reference, uint16, first %d nodes):\r\n", - buf[0], buf[1], 64); - for (int i = 0; i < 64; i++) { - uint16_t ref = buf[2 + i * 2] | (buf[2 + i * 2 + 1] << 8); - ets_printf("%6u", ref); - if ((i + 1) % cols == 0) ets_printf("\r\n"); + + if (_iType == CT_TYPE_CHSC6540) { + if (digitalRead(_iINT) == LOW) { + I2CReadRegister(_iAddr, 2, ucTemp, 13); // read touch points + if (ucTemp[2] == 1 || ucTemp[2] == 2) { + pTI->count = ucTemp[2]; + pTI->x[0] = ((ucTemp[3] & 0xf) << 8) | ucTemp[4]; + pTI->y[0] = ((ucTemp[5] & 0xf) << 8) | ucTemp[6]; + if (ucTemp[0] == 2) { // second touch point + pTI->x[0] = ((ucTemp[9] & 0xf) << 8) | ucTemp[10]; + pTI->y[0] = ((ucTemp[11] & 0xf) << 8) | ucTemp[12]; + } + return 1; + } + } + return 0; + } + if (_iType == CT_TYPE_CST820) { + I2CReadRegister(_iAddr, CST820_TOUCH_REGS+1, ucTemp, 1); // read touch count + if (ucTemp[0] < 1 || ucTemp[0] > 5) { // something went wrong + return 0; + } + if (ucTemp[0] >= 1) { // touch data available, read it + pTI->count = ucTemp[0]; + I2CReadRegister(_iAddr, CST820_TOUCH_REGS+2, ucTemp, pTI->count * 6); + s = ucTemp; + for (i=0; icount; i++) { + pTI->x[i] = ((s[0] & 0xf) << 8) | s[1]; + pTI->y[i] = ((s[2] & 0xf) << 8) | s[3]; + pTI->area[i] = 1; // no data available + s += 6; + } + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } } + if (_iType == CT_TYPE_FT6X36) { + rc = I2CReadRegister(_iAddr, TOUCH_REG_STATUS, ucTemp, 1); // read touch status + if (rc == 0) { // something went wrong + return 0; + } + i = ucTemp[0]; // number of touch points available + if (i >= 1 && i <= 5) { // get data + rc = I2CReadRegister(_iAddr, TOUCH_REG_XH, ucTemp, 6*i); // read X+Y position(s) + if ((ucTemp[0] & 0x40) == 0 && (ucTemp[2] & 0xf0) != 0xf0) { // finger is down + pTI->x[0] = ((ucTemp[0] & 0xf) << 8) | ucTemp[1]; + pTI->y[0] = ((ucTemp[2] & 0xf) << 8) | ucTemp[3]; + // get touch pressure and area + pTI->pressure[0] = ucTemp[4]; + pTI->area[0] = ucTemp[5]; + pTI->count++; + } + if (i > 1) { // get second point + if ((ucTemp[6] & 0x40) == 0 && (ucTemp[8] & 0xf0) != 0xf0) { // finger is down + pTI->x[1] = ((ucTemp[6] & 0xf) << 8) | ucTemp[7]; + pTI->y[1] = ((ucTemp[8] & 0xf) << 8) | ucTemp[9]; + // get touch pressure and area + pTI->pressure[1] = ucTemp[10]; + pTI->area[1] = ucTemp[11]; + pTI->count++; + } + } + } // if touch points available + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } else { // GT911 + I2CReadRegister16(_iAddr, GT911_POINT_INFO, ucTemp, 1); // get number of touch points + i = ucTemp[0] & 0xf; // number of touches + if (i <= 5 && ucTemp[0] & 0x80) { // if buffer status is good + >= 1 touch points + ucTemp[0] = (uint8_t)(GT911_POINT_INFO >> 8); + ucTemp[1] = (uint8_t)GT911_POINT_INFO; + ucTemp[2] = 0; // clear touch info for next time + I2CWrite(_iAddr, ucTemp, 3); - // --- Delta data (0x10): int8 per node. - // Page 0 = 128 nodes. Non-zero here means a finger is changing capacitance. - cmd[2] = 0x10; - I2CWrite(_iAddr, cmd, 3); - vTaskDelay(pdMS_TO_TICKS(20)); - memset(buf, 0, sizeof(buf)); - I2CReadRegister16(_iAddr, _mxtdata.t37_diagnostic_address, buf, 2 + 128); - ets_printf("mxt T37 mode=0x%02X page=%d (delta, int8, first %d nodes):\r\n", - buf[0], buf[1], rows * cols < 128 ? rows * cols : 128); - for (int r = 0; r < rows; r++) { - for (int c = 0; c < cols; c++) { - int idx = r * cols + c; - if (idx >= 128) break; - ets_printf("%4d", (int8_t)buf[2 + idx]); - } - ets_printf("\r\n"); + pTI->count = i; + for (int j=0; jx[j] = ucTemp[1] + (ucTemp[2] << 8); + pTI->y[j] = ucTemp[3] + (ucTemp[4] << 8); + pTI->area[j] = ucTemp[5] + (ucTemp[6] << 8); + pTI->pressure[j] = 0; + } + if (i && _iOrientation != 0) fixSamples(pTI); + return (i > 0); + } + } // GT911 + return 0; +} /* getSamples() */ + +int BBCapTouch::setOrientation(int iOrientation, int iWidth, int iHeight) +{ + if (iOrientation != 0 && iOrientation != 90 && iOrientation != 180 && iOrientation != 270) { + return CT_ERROR; } -} - -bool BBCapTouch::I2CTest(uint8_t u8Addr) { - uint8_t c; - return (i2c_master_read_from_device(I2C_NUM_0, u8Addr, &c, 1, pdMS_TO_TICKS(10)) == ESP_OK); -} - -int BBCapTouch::I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen) { - return (i2c_master_write_to_device(I2C_NUM_0, u8Addr, pData, iLen, pdMS_TO_TICKS(100)) == ESP_OK); -} - -int BBCapTouch::I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen) { - uint8_t ucTemp[2]; - ucTemp[0] = (uint8_t)u16Register; // low byte (MXT144 is little-endian) - ucTemp[1] = (uint8_t)(u16Register >> 8); // high byte - i2c_master_write_read_device(I2C_NUM_0, u8Addr, ucTemp, 2, pData, iLen, pdMS_TO_TICKS(100)); - return iLen; -} - -int BBCapTouch::I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen) { - int rc = i2c_master_read_from_device(I2C_NUM_0, u8Addr, pData, iLen, pdMS_TO_TICKS(100)); - return (rc == ESP_OK) ? iLen : 0; -} + _iOrientation = iOrientation; + _iWidth = iWidth; + _iHeight = iHeight; + return CT_SUCCESS; +} /* setOrientation() */ + +int BBCapTouch::sensorType(void) +{ + return _iType; +} /* type() */ + +int BBCapTouch::sleep(void) +{ +uint8_t ucTemp[8]; + + if (_iType == CT_TYPE_AXS15231) { + ucTemp[0] = 0x90; // enter deep sleep + ucTemp[1] = 0xa5; + ucTemp[2] = 0x5a; + ucTemp[3] = 0x15; + ucTemp[4] = 0x23; + I2CWrite(_iAddr, ucTemp, 5); + return CT_SUCCESS; + } + if (_iType == CT_TYPE_GT911 && _iINT != -1) { + pinMode(_iINT, OUTPUT); + digitalWrite(_iINT, 0); // setting interrupt pin low to prepare sleep mode + ucTemp[0] = (uint8_t)(GT911_ENTER_SLEEP >> 8); + ucTemp[1] = (uint8_t)GT911_ENTER_SLEEP; + ucTemp[2] = 0x05; //?? + I2CWrite(_iAddr, ucTemp, 3); // enter sleep mode + return CT_SUCCESS; + } + if (_iType == CT_TYPE_CST226) { + ucTemp[0] = 0xd1; + ucTemp[1] = 0x05; + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + return CT_ERROR; +} /* sleep() */ + +int BBCapTouch::wake(void) +{ +uint8_t ucTemp[4]; + + if (_iType == CT_TYPE_AXS15231) { + digitalWrite(_iRST, 0); + delay(50); + digitalWrite(_iRST, 1); + return CT_SUCCESS; + } + if (_iType == CT_TYPE_GT911 && _iINT != -1) { + digitalWrite(_iINT, 1); // wake up the controller + delay(5); // allow it time to wake + pinMode(_iINT, INPUT); // change pin mode back to floating + } + if (_iType == CT_TYPE_CST226) { + ucTemp[0] = 0xd1; + ucTemp[1] = 0x06; + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + return CT_ERROR; +} /* wake() */ + + diff --git a/grid_esp/components/grid_esp32_touch/bb_captouch.h b/grid_esp/components/grid_esp32_touch/bb_captouch.h index 12419b0f..8fa6c0bc 100644 --- a/grid_esp/components/grid_esp32_touch/bb_captouch.h +++ b/grid_esp/components/grid_esp32_touch/bb_captouch.h @@ -1,21 +1,156 @@ +// // BitBank Capacitive Touch Sensor Library -// Stripped to MXT144 only, non-Arduino ESP-IDF port +// written by Larry Bank // // Copyright 2023 BitBank Software, Inc. All Rights Reserved. // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== -#pragma once - -#include +// +// Written for the many variants of ESP32 + Capacitive touch LCDs on the market +// +#ifdef ARDUINO +#include +#include +#else +#define INPUT 0 +#define OUTPUT 1 +#define INPUT_PULLUP 2 +#define LOW 0 +#define HIGH 1 +#include "driver/gpio.h" #include "driver/i2c.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +static inline void delay(uint32_t ms) { vTaskDelay(pdMS_TO_TICKS(ms)); } +static inline int digitalRead(uint8_t pin) { return (int)gpio_get_level((gpio_num_t)pin); } +#endif // ARDUINO -#define CT_SUCCESS 0 -#define CT_ERROR -1 +#ifndef __BB_CAPTOUCH__ +#define __BB_CAPTOUCH__ +#define CT_SUCCESS 0 +#define CT_ERROR -1 +// +// Pre-configured device names +// Don't change the order of this list! +// the structure values follow it. Always +// add new values to the end +// +enum { + TOUCH_T_QT_C6=0, + TOUCH_CYD_550, + TOUCH_T_DISPLAY_S3_PRO, + TOUCH_T_DISPLAY_S3_LONG, + TOUCH_CYD_22C, + TOUCH_CYD_24C, + TOUCH_CYD_128, + TOUCH_CYD_35C, + TOUCH_CYD_518, + TOUCH_CYD_543, + TOUCH_M5_CORE2, + TOUCH_M5_CORES3, + TOUCH_M5_PAPER, + TOUCH_WT32_SC01_PLUS, + TOUCH_MAKERFABS_480x480, + TOUCH_MAKERFABS_320x480, + TOUCH_T_DISPLAY_S3_AMOLED, + TOUCH_WS_AMOLED_18, + TOUCH_M5_PAPERS3, + TOUCH_WS_ROUND_146, + TOUCH_WS_AMOLED_241, + TOUCH_WS_LCD_169, + TOUCH_VIEWE_2432, + TOUCH_T_DISPLAY_S3_AMOLED_164, + TOUCH_COUNT +}; +// structure holding the configurations +typedef struct bbct_config_tag { + int8_t i8SDA, i8SCL, i8IRQ, i8RST; +} BBCT_CONFIG; + +enum { + CT_TYPE_UNKNOWN = 0, + CT_TYPE_FT6X36, + CT_TYPE_GT911, + CT_TYPE_CST820, + CT_TYPE_CST226, + CT_TYPE_MXT144, + CT_TYPE_AXS15231, + CT_TYPE_TMA445, + CT_TYPE_SPD2010, + CT_TYPE_CHSC6540, + CT_TYPE_COUNT +}; + +#define SPD2010_ADDR 0x53 +#define GT911_ADDR1 0x5D +#define GT911_ADDR2 0x14 +#define FT6X36_ADDR1 0x38 +#define FT6X36_ADDR2 0x48 +#define CST820_ADDR 0x15 +#define CST226_ADDR 0x5A +#define CHSC6540_ADDR 0x2E #define MXT144_ADDR 0x4A +#define TMA445_ADDR 0x24 +#define AXS15231_ADDR 0x3B + +// CST8xx gestures +enum { + GESTURE_NONE = 0, + GESTURE_SWIPE_UP, + GESTURE_SWIPE_DOWN, + GESTURE_SWIPE_LEFT, + GESTURE_SWIPE_RIGHT, + GESTURE_SINGLE_CLICK, + GESTURE_DOUBLE_CLICK = 0x0B, + GESTURE_LONG_PRESS = 0x0C +}; + +// TMA445 Security KEY +static uint8_t tma445_key[] = {0x00, 0x00, 0xFF, 0xA5, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + +/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */ +typedef struct cyttsp_xydata_tag { + uint8_t hst_mode; + uint8_t tt_mode; + uint8_t tt_stat; + uint16_t x1 __attribute__ ((packed)); + uint16_t y1 __attribute__ ((packed)); + uint8_t z1; + uint8_t touch12_id; + uint16_t x2 __attribute__ ((packed)); + uint16_t y2 __attribute__ ((packed)); + uint8_t z2; +} cyttsp_xydata; +#define CY_HNDSHK_BIT 0x80 +typedef struct cyttsp_bootloader_data_tag { + uint8_t bl_file; + uint8_t bl_status; + uint8_t bl_error; + uint8_t blver_hi; + uint8_t blver_lo; + uint8_t bld_blver_hi; + uint8_t bld_blver_lo; + uint8_t ttspver_hi; + uint8_t ttspver_lo; + uint8_t appid_hi; + uint8_t appid_lo; + uint8_t appver_hi; + uint8_t appver_lo; + uint8_t cid_0; + uint8_t cid_1; + uint8_t cid_2; +} cyttsp_bootloader_data; + typedef struct mxt_data_tag { uint16_t t2_encryption_status_address; @@ -24,43 +159,108 @@ typedef struct mxt_data_tag { uint16_t t6_command_processor_address; uint16_t t7_powerconfig_address; uint16_t t8_acquisitionconfig_address; - uint16_t t37_diagnostic_address; uint16_t t44_message_count_address; uint16_t t46_cte_config_address; - uint16_t t56_shieldless_address; - uint16_t t15_key_array_address; - uint16_t t15_first_report_id; uint16_t t100_multiple_touch_touchscreen_address; uint16_t t100_first_report_id; - uint8_t matrix_x_size; - uint8_t matrix_y_size; } MXTDATA; +typedef struct mxt_object_tag { + uint8_t type; + uint16_t position; + uint8_t size_minus_one; + uint8_t instances_minus_one; + uint8_t report_ids_per_instance; +} MXTOBJECT; + #define MXT_MESSAGE_SIZE 6 +// CST820 registers +#define CST820_TOUCH_REGS 1 + +// GT911 registers +#define GT911_POINT_INFO 0x814E +#define GT911_POINT_1 0x814F +#define GT911_CONFIG_FRESH 0x8100 +#define GT911_CONFIG_SIZE 0xb9 +#define GT911_CONFIG_START 0x8047 +#define GT911_ENTER_SLEEP 0x8040 + +// FT6x36 registers +#define TOUCH_REG_STATUS 0x02 +#define TOUCH_REG_XH 0x03 +#define TOUCH_REG_XL 0x04 +#define TOUCH_REG_YH 0x05 +#define TOUCH_REG_YL 0x06 +#define TOUCH_REG_WEIGHT 0x07 +#define TOUCH_REG_AREA 0x08 +// register offset to info for the second touch point +#define PT2_OFFSET 6 + #ifndef __TOUCHINFO_STRUCT__ #define __TOUCHINFO_STRUCT__ -typedef struct _fttouchinfo { - int count; - uint32_t key_state; - uint16_t x[5], y[5]; - uint8_t pressure[5], area[5]; + +typedef struct _fttouchinfo +{ + int count; + uint16_t x[5], y[5]; + uint8_t pressure[5], area[5]; } TOUCHINFO; #endif -class BBCapTouch { +//extern TwoWire* myWire; + +class BBCapTouch +{ public: - BBCapTouch() {} - int init(int iSDA, int iSCL, uint32_t u32Speed = 400000); + BBCapTouch() { _iOrientation = 0; _iType = CT_TYPE_UNKNOWN;} +// ~BBCapTouch() { Wire.end(); } +#ifdef ARDUINO + ~BBCapTouch() { myWire->end(); } +#else + ~BBCapTouch() {} +#endif + +#ifdef ARDUINO + int init(int iConfigName); + int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000, TwoWire* _myWire=&Wire); +#else + int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000); +#endif int getSamples(TOUCHINFO *pTI); - void dumpDiagnostic(void); + uint8_t interruptPin(void) {return (uint8_t)_iINT;} + int sensorType(void); + int setOrientation(int iOrientation, int iWidth, int iHeight); + int sleep(void); + int wake(void); +protected: + void reset(int iResetPin); + private: - int _iAddr = MXT144_ADDR; - MXTDATA _mxtdata = {}; + int _iAddr; + int _iType; + int _iOrientation, _iWidth, _iHeight; + MXTDATA _mxtdata; + int _iINT; // interrupt GPIO pin needed for sleep/wake of GT911 + int _iRST; // reset GPIO needed for AXS15206 to wake from deep sleep +#ifdef ARDUINO + TwoWire* myWire; +#else + void pinMode(uint8_t u8Pin, uint8_t u8Mode); + void digitalWrite(uint8_t u8Pin, uint8_t u8State); +#endif int initMXT(void); + void fixSamples(TOUCHINFO *pTI); bool I2CTest(uint8_t u8Addr); int I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen); + int I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen); int I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen); int I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen); -}; + void SPD2010ClearInt(void); + void SPD2010CPUStart(void); + uint8_t SPD2010Status(int *iNextLen); + void SPD2010TouchStart(void); + void SPD2010PointMode(void); +}; // class BBCapTouch +#endif // __BB_CAPTOUCH__ diff --git a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp index 1c220682..8cdf76af 100644 --- a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp +++ b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp @@ -17,12 +17,6 @@ DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; static struct grid_esp32_touch_model* touch_ptr = NULL; static BBCapTouch bbc; -static void IRAM_ATTR grid_esp32_touch_int_handler(void* arg) { - struct grid_esp32_touch_model* touch = (struct grid_esp32_touch_model*)arg; - touch->int_pending = true; - ets_printf("INT\r\n"); -} - void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, grid_process_touch_t process_touch) { @@ -35,35 +29,9 @@ void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_ touch->i2c_freq_hz = i2c_freq_hz; touch->process_touch = process_touch; - // Apply pull-ups to all sensor pins before reset — no external resistors on this board. - // Must happen before the reset pulse so SDA/SCL are not floating during sensor boot. - gpio_reset_pin(touch->scl_gpio); - gpio_pullup_en(touch->scl_gpio); - gpio_reset_pin(touch->sda_gpio); - gpio_pullup_en(touch->sda_gpio); - gpio_reset_pin(touch->int_gpio); - gpio_pullup_en(touch->int_gpio); - - // RESET: active-low reset pulse - gpio_reset_pin(touch->reset_gpio); - gpio_set_direction(touch->reset_gpio, GPIO_MODE_OUTPUT); - gpio_set_level(touch->reset_gpio, 0); // assert reset - vTaskDelay(pdMS_TO_TICKS(10)); - gpio_set_level(touch->reset_gpio, 1); // deassert reset - vTaskDelay(pdMS_TO_TICKS(250)); // wait for sensor boot - - // INT: falling edge interrupt (pull-up already set above) - gpio_set_direction(touch->int_gpio, GPIO_MODE_INPUT); - gpio_set_intr_type(touch->int_gpio, GPIO_INTR_NEGEDGE); - gpio_install_isr_service(0); - gpio_isr_handler_add(touch->int_gpio, grid_esp32_touch_int_handler, touch); - gpio_intr_enable(touch->int_gpio); - - // I2C + MXT144 init — i2c_param_config will reconfigure SCL/SDA with pull-ups enabled - int rc = bbc.init(touch->sda_gpio, touch->scl_gpio, touch->i2c_freq_hz); + int rc = bbc.init(touch->sda_gpio, touch->scl_gpio, touch->reset_gpio, touch->int_gpio, touch->i2c_freq_hz); if (rc == CT_SUCCESS) { ets_printf("MXT144 init OK\r\n"); - touch->int_pending = true; // drain any messages queued during init } else { ets_printf("MXT144 init FAILED\r\n"); } @@ -94,8 +62,3 @@ int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO (void)touch; return bbc.getSamples(pTI); } - -void grid_esp32_touch_diagnostic(struct grid_esp32_touch_model* touch) { - (void)touch; - bbc.dumpDiagnostic(); -} diff --git a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h index 302d7e31..7da47412 100644 --- a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h +++ b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h @@ -37,7 +37,6 @@ struct grid_esp32_touch_model { gpio_num_t int_gpio; uint32_t i2c_freq_hz; grid_process_touch_t process_touch; - volatile bool int_pending; }; extern struct grid_esp32_touch_model grid_esp32_touch_state; @@ -48,7 +47,6 @@ void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_ void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch); int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI); -void grid_esp32_touch_diagnostic(struct grid_esp32_touch_model* touch); #ifdef __cplusplus } diff --git a/maxtouch.c b/maxtouch.c new file mode 100644 index 00000000..367dbca7 --- /dev/null +++ b/maxtouch.c @@ -0,0 +1,654 @@ + // Copyright 2024 George Norton (@george-norton) +// SPDX-License-Identifier: GPL-2.0-or-later + +#include QMK_KEYBOARD_H +#include "i2c_master.h" +#include "maxtouch.h" + +#include "digitizer.h" +#include "digitizer_driver.h" + +#ifdef MAXTOUCH_DEBUG +# include "raw_hid.h" +#endif + +#define SWAP_BYTES(a) (((a << 8) & 0xff00) | ((a >> 8) & 0xff)) + +// Mandatory configuration. These are hardware specific. +#ifndef MXT_SENSOR_WIDTH_MM +# error "You must define the MXT_SENSOR_WIDTH_MM" +#endif + +#ifndef MXT_SENSOR_HEIGHT_MM +# error "You must define the MXT_SENSOR_HEIGHT_MM" +#endif + +// By default we assume all available X and Y pins are in use, but a designer +// may decide to leave some pins unconnected, so the size can be overridden here. +#ifndef MXT_MATRIX_X_SIZE +# define MXT_MATRIX_X_SIZE information.matrix_x_size +#endif + +#ifndef MXT_MATRIX_Y_SIZE +# define MXT_MATRIX_Y_SIZE information.matrix_y_size +#endif + +#ifndef MXT_SCROLL_DIVISOR +# define MXT_SCROLL_DIVISOR 4 +#endif + +// We detect a tap gesture if an UP event occurs within MXT_TAP_TIME +// milliseconds of the DOWN event. +#ifndef MXT_TAP_TIME +# define MXT_TAP_TIME 100 +#endif + +// We detect a tap and hold gesture if a finger does not move +// further than MXT_TAP_AND_HOLD_DISTANCE within MXT_TAP_AND_HOLD_TIME +// milliseconds of being put down on the sensor. +#ifndef MXT_TAP_AND_HOLD_TIME +# define MXT_TAP_AND_HOLD_TIME 200 +#endif +#ifndef MXT_TAP_AND_HOLD_DISTANCE +# define MXT_TAP_AND_HOLD_DISTANCE 5 +#endif + +#ifndef MXT_RECALIBRATE_AFTER +// Steps of 200ms, 25 = 5 seconds +# define MXT_RECALIBRATE_AFTER 50 +#endif + +#ifndef MXT_TOUCH_THRESHOLD +# define MXT_TOUCH_THRESHOLD 18 +#endif + +#ifndef MXT_GAIN +# define MXT_GAIN 4 +#endif + +#ifndef MXT_TOUCH_HYST +# define MXT_TOUCH_HYST 0 +#endif + +#ifndef MXT_INTERNAL_TOUCH_HYST +# define MXT_INTERNAL_TOUCH_HYST 0 +#endif + +#ifndef MXT_INTERNAL_TOUCH_THRESHOLD +# define MXT_INTERNAL_TOUCH_THRESHOLD 0 +#endif + +#ifndef MXT_DX_GAIN +# define MXT_DX_GAIN 0 +#endif + +#ifndef MXT_X_PITCH +# define MXT_X_PITCH (MXT_SENSOR_WIDTH_MM * 10 / MXT_MATRIX_X_SIZE) +#endif + +#ifndef MXT_Y_PITCH +# define MXT_Y_PITCH (MXT_SENSOR_HEIGHT_MM * 10 / MXT_MATRIX_Y_SIZE) +#endif + +#ifndef MXT_MESALLOW +# define MXT_MESALLOW 3 +#endif + +#ifndef MXT_IDLE_SYNCS_PER_X +# define MXT_IDLE_SYNCS_PER_X 0 +#endif + +#ifndef MXT_ACTIVE_SYNCS_PER_X +# define MXT_ACTIVE_SYNCS_PER_X 0 +#endif + +#ifndef MXT_IDLE_ACQUISITION_INTERVAL +# define MXT_IDLE_ACQUISITION_INTERVAL 32 +#endif + +#ifndef MXT_ACTIVE_ACQUISITION_INTERVAL +# define MXT_ACTIVE_ACQUISITION_INTERVAL 10 +#endif + +#ifndef MXT_RETRANSMISSION_COMPENSATION_ENABLE +# define MXT_RETRANSMISSION_COMPENSATION_ENABLE 1 +#endif + +#ifndef MXT_MOVE_HYSTERESIS_INITIAL +# define MXT_MOVE_HYSTERESIS_INITIAL 10 +#endif + +#ifndef MXT_MOVE_HYSTERESIS_NEXT +# define MXT_MOVE_HYSTERESIS_NEXT 4 +#endif + +#ifndef MXT_LOW_PASS_FILTER_COEFFICIENT +# define MXT_LOW_PASS_FILTER_COEFFICIENT 0 +#endif + +#ifndef MXT_CHARGE_TIME +# define MXT_CHARGE_TIME 1 +#endif + +// Any stylus event smaller than this, is treated as a hover rather than a press. +#ifndef MXT_STYLUS_HOVER_THRESHOLD +# define MXT_STYLUS_HOVER_THRESHOLD 6 +#endif + +#ifndef MXT_CONFTHR +# define MXT_CONFTHR 2 +#endif + +// Data from the object table. Registers are not at fixed addresses, they may vary between firmware +// versions. Instead must read the addresses from the object table. +static uint16_t t2_encryption_status_address = 0; +static uint16_t t5_message_processor_address = 0; +static uint16_t t5_max_message_size = 0; +static uint16_t t6_command_processor_address = 0; +static uint16_t t6_command_processor_report_id = 0; +static uint16_t t7_powerconfig_address = 0; +static uint16_t t8_acquisitionconfig_address = 0; +static uint16_t t25_self_test_address = 0; +static uint16_t t37_diagnostic_debug_address = 0; +static uint16_t t42_proci_touchsupression_address = 0; +static uint16_t t44_message_count_address = 0; +static uint16_t t46_cte_config_address = 0; +static uint16_t t47_proci_stylus_address = 0; +static uint16_t t56_proci_shieldless_address = 0; +static uint16_t t65_proci_lensbending_address = 0; +static uint16_t t80_proci_retransmissioncompensation_address = 0; +static uint16_t t100_multiple_touch_touchscreen_address = 0; + +// The object table also contains report_ids. These are used to identify which object generated a +// message. Again we must lookup these values rather than using hard coded values. +// Most messages are ignored, we basically just want the messages from the t100 object for now. +static uint16_t t25_self_test_report_id = 0; +static uint16_t t100_first_report_id = 0; +static uint16_t t100_second_report_id = 0; +static uint16_t t100_subsequent_report_ids[DIGITIZER_CONTACT_COUNT] = {}; +static uint16_t t100_num_reports = 0; +static mxt_information_block information = {0}; + +void maxtouch_print_info(void) { + // Pavonis: Found MXT 164:75, fw 16.170 with 32 objects. Matrix size 41x26 + uprintf("Found MXT %d:%d, fw %d.%d with %d objects. Matrix size %dx%d\n", information.family_id, information.variant_id, information.version, information.build, information.num_objects, information.matrix_x_size, information.matrix_y_size); +} + +void maxtouch_init(void) { +#ifdef MXT_I2CMODE_PIN + gpio_set_pin_output(MXT_I2CMODE_PIN); + gpio_write_pin_high(MXT_I2CMODE_PIN); +#endif +#ifdef MXT_RESET_PIN + gpio_set_pin_output(MXT_RESET_PIN); + gpio_write_pin_low(MXT_RESET_PIN); + wait_ms(500); + gpio_write_pin_high(MXT_RESET_PIN); + wait_ms(300); +#endif + i2c_init(); + i2c_status_t status = i2c_readReg16(MXT336UD_ADDRESS, MXT_REG_INFORMATION_BLOCK, (uint8_t *)&information, sizeof(mxt_information_block), MXT_I2C_TIMEOUT_MS); + + // First read the object table to lookup addresses and report_ids of the various objects + if (status == I2C_STATUS_SUCCESS) { + // I2C found device family: 166 with 34 objects + dprintf("Found MXT %d:%d, fw %d.%d with %d objects. Matrix size %dx%d\n", information.family_id, information.variant_id, information.version, information.build, information.num_objects, information.matrix_x_size, information.matrix_y_size); + int report_id = 1; + uint16_t object_table_element_address = sizeof(mxt_information_block); + for (int i = 0; i < information.num_objects; i++) { + mxt_object_table_element object = {}; + i2c_status_t status = i2c_readReg16(MXT336UD_ADDRESS, SWAP_BYTES(object_table_element_address), (uint8_t *)&object, sizeof(mxt_object_table_element), MXT_I2C_TIMEOUT_MS); + if (status == I2C_STATUS_SUCCESS) { + // Store addresses in network byte order + const uint16_t address = object.position_ms_byte | (object.position_ls_byte << 8); + switch (object.type) { + case 2: + t2_encryption_status_address = address; + break; + case 5: + t5_message_processor_address = address; + t5_max_message_size = object.size_minus_one - 1; + break; + case 6: + t6_command_processor_address = address; + t6_command_processor_report_id = report_id; + break; + case 7: + t7_powerconfig_address = address; + break; + case 8: + t8_acquisitionconfig_address = address; + break; + case 25: + t25_self_test_address = address; + t25_self_test_report_id = report_id; + break; + case 37: + t37_diagnostic_debug_address = address; + break; + case 42: + t42_proci_touchsupression_address = address; + break; + case 44: + t44_message_count_address = address; + break; + case 46: + t46_cte_config_address = address; + break; + case 47: + t47_proci_stylus_address = address; + break; + case 56: + t56_proci_shieldless_address = address; + break; + case 65: + t65_proci_lensbending_address = address; + break; + case 80: + t80_proci_retransmissioncompensation_address = address; + break; + case 100: + t100_multiple_touch_touchscreen_address = address; + t100_first_report_id = report_id; + t100_second_report_id = report_id + 1; + for (t100_num_reports = 0; t100_num_reports < DIGITIZER_CONTACT_COUNT && t100_num_reports < object.report_ids_per_instance; t100_num_reports++) { + t100_subsequent_report_ids[t100_num_reports] = report_id + 2 + t100_num_reports; + } + break; + } + object_table_element_address += sizeof(mxt_object_table_element); + report_id += object.report_ids_per_instance * (object.instances_minus_one + 1); + } else { + dprintf("Failed to read object table element. Status: %d\n", status); + } + } + } else { + dprintf("Failed to read object table. Status: %d\n", status); + } + + // TODO Remove? Maybe not interesting unless for whatever reason encryption is enabled and we need to turn it off + if (t2_encryption_status_address) { + mxt_gen_encryptionstatus_t2 t2 = {}; + i2c_status_t status = i2c_readReg16(MXT336UD_ADDRESS, t2_encryption_status_address, (uint8_t *)&t2, sizeof(mxt_gen_encryptionstatus_t2), MXT_I2C_TIMEOUT_MS); + if (status != I2C_STATUS_SUCCESS) { + dprintf("Failed to read T2. Status: %02x %d\n", t2.status, t2.error); + } + } + + // Configure power saving features + if (t7_powerconfig_address) { + mxt_gen_powerconfig_t7 t7 = {}; + t7.idleacqint = MXT_IDLE_ACQUISITION_INTERVAL; // The acquisition interval while in idle mode. 255 is free-running (as fast as possible). + t7.actacqint = MXT_ACTIVE_ACQUISITION_INTERVAL; // The acquisition interval while in active mode. 255 is free-running (as fast as possible). + t7.actv2idelto = 50; // The timeout for transitioning from active to idle mode + t7.cfg = T7_CFG_ACTVPIPEEN | T7_CFG_IDLEPIPEEN; // Enable pipelining in both active and idle mode + + i2c_writeReg16(MXT336UD_ADDRESS, t7_powerconfig_address, (uint8_t *)&t7, sizeof(mxt_gen_powerconfig_t7), MXT_I2C_TIMEOUT_MS); + } + + // Configure capacitive acquision, currently we use all the default values but it feels like some of this stuff might be important. + if (t8_acquisitionconfig_address) { + mxt_gen_acquisitionconfig_t8 t8 = {}; + t8.chrgtime = MXT_CHARGE_TIME; + t8.tchautocal = MXT_RECALIBRATE_AFTER; + t8.atchcalst = 0; + + // Antitouch detection - reject palms etc.. + t8.atchcalsthr = 50; + t8.atchfrccalthr = 50; + t8.atchfrccalratio = 25; + t8.measallow = MXT_MESALLOW; + + i2c_writeReg16(MXT336UD_ADDRESS, t8_acquisitionconfig_address, (uint8_t *)&t8, sizeof(mxt_gen_acquisitionconfig_t8), MXT_I2C_TIMEOUT_MS); + } + +#ifdef DIGITIZER_HAS_STYLUS + if (t42_proci_touchsupression_address) { + mxt_proci_touchsupression_t42 t42 = {}; + + t42.ctrl = T42_CTRL_ENABLE | T42_CTRL_SHAPEEN; + t42.maxapprarea = 0; // Default (0): suppress any touch that approaches >40 channels. + t42.maxtcharea = 0; // Default (0): suppress any touch that covers >35 channels. + t42.maxnumtchs = 6; // Suppress all touches if >6 are detected. + t42.supdist = 0; // Default (0): Suppress all touches within 5 nodes of a suppressed large object detection. + t42.disthyst = 0; + t42.supstrength = 0; // Default (0): suppression strength of 128. + t42.supextto = 0; // Timeout to save power; set to 0 to disable. + t42.shapestrength = 0; // Default (0): shape suppression strength of 10, range [0, 31]. + t42.maxscrnarea = 0; + t42.edgesupstrength = 0; + t42.cfg = 1; + i2c_writeReg16(MXT336UD_ADDRESS, t42_proci_touchsupression_address, (uint8_t *)&t42, sizeof(mxt_proci_touchsupression_t42), MXT_I2C_TIMEOUT_MS); + } +#endif + + // Mutural Capacitive Touch Engine (CTE) configuration, currently we use all the default values but it feels like some of this stuff might be important. + if (t46_cte_config_address) { + mxt_spt_cteconfig_t46 t46 = {}; + t46.idlesyncsperx = MXT_IDLE_SYNCS_PER_X; // ADC samples per X. + t46.activesyncsperx = MXT_ACTIVE_SYNCS_PER_X; // ADC samples per X. + t46.inrushcfg = 0; // Set Y-line inrush limit resistors. + + i2c_writeReg16(MXT336UD_ADDRESS, t46_cte_config_address, (uint8_t *)&t46, sizeof(mxt_spt_cteconfig_t46), MXT_I2C_TIMEOUT_MS); + } + +#ifdef DIGITIZER_HAS_STYLUS + if (t47_proci_stylus_address) { + mxt_proci_stylus_t47 t47 = {}; + t47.ctrl = 1; // Enable stylus detection + t47.cfg = T47_CFG_SUPSTY; // Supress stylus detections when normal touches are present. + t47.contmax = 80; // The maximum contact diameter of the stylus in 0.1mm increments + t47.maxtcharea = 100; // Maximum touch area a contact can have an still be considered a stylus + t47.stability = 30; // Higher values prevent the stylus from dropping out when it gets small + t47.confthr = 6; // Higher values increase the chances of correctly detecting as stylus, but introduce a delay + t47.amplthr = 60; // Any touches smaller than this are classified as stylus touches + t47.supstyto = 5; // Continue to suppress stylus touches until supstyto x 200ms after the last touch is removed. + t47.hoversup = 200; // 255 Disables hover supression + t47.maxnumsty = 1; // Only report a single stylus + i2c_writeReg16(MXT336UD_ADDRESS, t47_proci_stylus_address, (uint8_t *)&t47, sizeof(mxt_proci_stylus_t47), MXT_I2C_TIMEOUT_MS); + } +#endif + + if (t80_proci_retransmissioncompensation_address) { + mxt_proci_retransmissioncompensation_t80 t80 = {}; + t80.ctrl = MXT_RETRANSMISSION_COMPENSATION_ENABLE; + t80.compgain = 5; + t80.targetdelta = 125; + t80.compthr = 60; + i2c_writeReg16(MXT336UD_ADDRESS, t80_proci_retransmissioncompensation_address, (uint8_t *)&t80, sizeof(mxt_proci_retransmissioncompensation_t80), MXT_I2C_TIMEOUT_MS); + } + + // Multiple touch touchscreen confguration - defines an area of the sensor to use as a trackpad/touchscreen. This object generates all our interesting report messages. + if (t100_multiple_touch_touchscreen_address) { + mxt_touch_multiscreen_t100 cfg = {}; + + cfg.ctrl = T100_CTRL_RPTEN | T100_CTRL_ENABLE | T100_CTRL_SCANEN; // Enable the t100 object, and enable message reporting for the t100 object.1. Also enable close scanning mode. + // TODO: Generic handling of rotation/inversion for absolute mode? + uint8_t rotation = 0; +#ifdef MXT_INVERT_X + rotation |= T100_CFG_INVERTX; +#endif +#ifdef MXT_INVERT_Y + rotation |= T100_CFG_INVERTY; +#endif +#ifdef MXT_SWITCH_XY + rotation |= T100_CFG_SWITCHXY; +#endif + cfg.cfg1 = rotation; + cfg.scraux = 0x7; // AUX data: Report the number of touch events, touch area, anti touch area + cfg.tchaux = 0x2; // report amplitude + cfg.tcheventcfg = 24; // Disable reporting suppressed events + cfg.numtch = DIGITIZER_CONTACT_COUNT; // The number of touch reports we want to receive (upto 10) + cfg.xsize = MXT_MATRIX_X_SIZE; // Make configurable as this depends on the sensor design. + cfg.ysize = MXT_MATRIX_Y_SIZE; // Make configurable as this depends on the sensor design. + cfg.xpitch = MXT_X_PITCH; // Pitch between X-Lines in 0.1mm increments. + cfg.ypitch = MXT_Y_PITCH; // Pitch between Y-Lines in 0.1mm increments. + cfg.xedgecfg = 9; + cfg.xedgedist = 10; + cfg.yedgecfg = 9; + cfg.yedgedist = 10; + cfg.gain = MXT_GAIN; // Single transmit gain for mutual capacitance measurements + cfg.dxgain = MXT_DX_GAIN; // Dual transmit gain for mutual capacitance measurements (255 = auto calibrate) + cfg.tchthr = MXT_TOUCH_THRESHOLD; // Touch threshold + cfg.tchhyst = MXT_TOUCH_HYST; + cfg.intthr = MXT_INTERNAL_TOUCH_THRESHOLD; + cfg.intthryst = MXT_INTERNAL_TOUCH_HYST; + cfg.mrgthr = 5; // Merge threshold + cfg.mrghyst = 10; // Merge threshold hysteresis + cfg.mrgthradjstr = 20; + cfg.movsmooth = 0; // The amount of smoothing applied to movements, this tails off at higher speeds + cfg.movfilter = 0; // The lower 4 bits are the speed response value, higher values reduce lag, but also smoothing + // These two fields implement a simple filter for reducing jitter, but large values cause the pointer to stick in place before moving. + cfg.movhysti = MXT_MOVE_HYSTERESIS_INITIAL; // Initial movement hysteresis + cfg.movhystn = MXT_MOVE_HYSTERESIS_NEXT; // Next movement hysteresis + + cfg.tchdiup = 4; // MXT_UP touch detection integration - the number of cycles before the sensor decides an MXT_UP event has occurred + cfg.tchdidown = 2; // MXT_DOWN touch detection integration - the number of cycles before the sensor decides an MXT_DOWN event has occurred + cfg.nexttchdi = 2; + cfg.calcfg = 0; +#ifdef MXT_SWITCH_XY + cfg.xrange = DIGITIZER_RESOLUTION_Y - 1; // The logical and physical resolution is reported in our USB descriptor + cfg.yrange = DIGITIZER_RESOLUTION_X - 1; // the host uses this to set the speed of the pointer. +#else + cfg.xrange = DIGITIZER_RESOLUTION_X - 1; // The logical and physical resolution is reported in our USB descriptor + cfg.yrange = DIGITIZER_RESOLUTION_Y - 1; // the host uses this to set the speed of the pointer. +#endif + cfg.cfg2 = MXT_CONFTHR; // Touch debounce + + i2c_status_t status = i2c_writeReg16(MXT336UD_ADDRESS, t100_multiple_touch_touchscreen_address, (uint8_t *)&cfg, sizeof(mxt_touch_multiscreen_t100), MXT_I2C_TIMEOUT_MS); + if (status != I2C_STATUS_SUCCESS) { + dprintf("T100 Configuration failed: %d\n", status); + } + } + + // Configure shieldless and lensbending objects to provide some additional resistance + // against bad behaviour. +#ifdef MXT_T56_SHIELDLESS_ENABLE + if (t56_proci_shieldless_address) { + mxt_proci_shieldless_t56 t56 = {}; + t56.ctrl = T56_CTRL_ENABLE; + t56.optint = 1; + t56.inttime = 10; + i2c_writeReg16(MXT336UD_ADDRESS, t56_proci_shieldless_address, (uint8_t *)&t56, sizeof(mxt_proci_shieldless_t56), MXT_I2C_TIMEOUT_MS); + } +#endif +#ifdef MXT_T65_LENS_BENDING_ENABLE + if (t65_proci_lensbending_address) { + mxt_proci_lensbending_t65 t65 = {}; + t65.ctrl = T65_CTRL_ENABLE; + t65.lpfiltcoef = MXT_LOW_PASS_FILTER_COEFFICIENT; // default (0): 5, range 1 to 15. + i2c_writeReg16(MXT336UD_ADDRESS, t65_proci_lensbending_address, (uint8_t *)&t65, sizeof(mxt_proci_lensbending_t65), MXT_I2C_TIMEOUT_MS); + } +#endif +} + +// Store state different from report so we can report MXT_DOWNUP as MXT_DOWN, but remember we are MXT_UP +digitizer_t maxtouch_get_report(digitizer_t digitizer_report) { + if (t44_message_count_address) { + mxt_message_count message_count = {}; + + i2c_status_t status = i2c_readReg16(MXT336UD_ADDRESS, t44_message_count_address, (uint8_t *)&message_count, sizeof(mxt_message_count), MXT_I2C_TIMEOUT_MS); + if (status == I2C_STATUS_SUCCESS) { + for (int i = 0; i < message_count.count; i++) { + mxt_message message = {}; + status = i2c_readReg16(MXT336UD_ADDRESS, t5_message_processor_address, (uint8_t *)&message, sizeof(mxt_message), MXT_I2C_TIMEOUT_MS); + + if (message.report_id == t100_first_report_id) { + const uint8_t fingers = message.data[1]; +#ifdef MAXTOUCH_BOOTLOADER_GESTURE + // Debug feature - reboot to bootloader if 5 fingers are MXT_DOWN + // TODO: A better gesture. + if (fingers == 5) reset_keyboard(); +#endif + if (fingers == 0) { + // Belt and braces, make sure we dont have any stuck contacts + for (int j = 0; j < DIGITIZER_CONTACT_COUNT; j++) { + digitizer_report.contacts[j].type = UNKNOWN; + digitizer_report.contacts[j].tip = false; + digitizer_report.contacts[j].in_range = false; + digitizer_report.contacts[j].confidence = false; + } + } + } else if (message.report_id == t25_self_test_report_id) { + const uint8_t result = message.data[0]; + switch (result) { + case T25_TEST_PASSED: + uprintf("Self Tests passed\n"); + break; + case T25_TEST_INVALID: + uprintf("Invalid self test command\n"); + break; + case T25_TEST_POWER: + uprintf("Power fault detected\n"); + break; + case T25_TEST_PIN_FAULT: + uprintf("Pin fault detected. Seq %d, pin %dx%d\n", message.data[2], message.data[3], message.data[4]); + break; + case T25_TEST_SIGNAL_LIMIT: + uprintf("Signal limit fault detected\n"); + break; + } + } else if ((message.report_id >= t100_subsequent_report_ids[0]) && (message.report_id <= t100_subsequent_report_ids[t100_num_reports - 1])) { + const uint8_t contact_id = message.report_id - t100_subsequent_report_ids[0]; + const int event = (message.data[0] & 0xf); + const int type = (message.data[0] >> 4) & 0x7; + const uint16_t x = message.data[1] | (message.data[2] << 8); + const uint16_t y = message.data[3] | (message.data[4] << 8); + const uint8_t ampl = message.data[5]; + // uprintf("EVT[%u] %d %d %ux%u %u\n", contact_id, event, type, x, y, ampl); + + switch (type) { + case MXT_FINGER: + digitizer_report.contacts[contact_id].type = FINGER; + break; + case MXT_PASSIVE_STYLUS: + digitizer_report.contacts[contact_id].type = STYLUS; + break; + default: + digitizer_report.contacts[contact_id].type = UNKNOWN; + break; + } + + digitizer_report.contacts[contact_id].in_range = true; + + if (type == MXT_FINGER) { + if (event == MXT_DOWN || event == MXT_MOVE) { + digitizer_report.contacts[contact_id].tip = true; + } + } + else if (type == MXT_PASSIVE_STYLUS) { + digitizer_report.contacts[contact_id].tip = ampl > MXT_STYLUS_HOVER_THRESHOLD; + } + + if (event == MXT_UP || event == MXT_UNSUPSUP) { + digitizer_report.contacts[contact_id].tip = false; + } + + if (event == MXT_MOVE || event == MXT_DOWN || event == MXT_DOWNSUP || event == MXT_UP || event == MXT_UNSUPUP || event == MXT_UNSUP) { + digitizer_report.contacts[contact_id].x = x; + digitizer_report.contacts[contact_id].y = y; + } + if (event == MXT_SUP || event == MXT_UNSUPSUP || event == MXT_DOWNSUP) { + digitizer_report.contacts[contact_id].confidence = 0; + } else { + digitizer_report.contacts[contact_id].confidence = 1; + } + } else if (message.report_id == t6_command_processor_report_id) { + const uint8_t status = message.data[0]; + uprintf("T6 status: RESET: %d, OFL: %d. SIGERR: %d, CAL: %d, CFGERR: %d. COMSERR: %d\n", status & (1 << 7) ? 1 : 0, status & (1 << 6) ? 1 : 0, status & (1 << 5) ? 1 : 0, status & (1 << 4) ? 1 : 0, status & (1 << 3) ? 1 : 0, status & (1 << 2) ? 1 : 0); + // Run all self tests after a reset + if (t25_self_test_address && status & (1 << 7)) { + mxt_spt_selftest_t25 t25 = {}; + t25.ctrl = 0x3; + t25.cmd = T25_TEST_ALL; + + // Min/Max values from the 1066u datasheet + t25.losiglim_msb = 0x44; // 17500 + t25.losiglim_lsb = 0x5c; + t25.upsiglim_msb = 0x79; // 31000 + t25.upsiglim_lsb = 0x18; + + // Observed reference signal is approx 6000, and we get + // a 700 delta when touching. So create a range of 7000. + t25.sigrangelim_lsb = 0x58; + t25.sigrangelim_msb = 0x1B; + + t25.sesiglimits[1] = MXT_GAIN; + t25.sesiglimits[2] = MXT_DX_GAIN; + + i2c_writeReg16(MXT336UD_ADDRESS, t25_self_test_address, (uint8_t *)&t25, sizeof(mxt_spt_selftest_t25), MXT_I2C_TIMEOUT_MS); + } + } else { + uprintf("Unhandled event %d (%02x %02x %02x %02x %02x %02x) %d\n", message.report_id, message.data[0], message.data[1], message.data[2], message.data[3], message.data[4], message.data[5], t25_self_test_report_id); + } + } + } + } + return digitizer_report; +} + +#ifdef MAXTOUCH_DEBUG +# define MAXTOUCH_DEBUG_MAGIC 0x9A4D +# define MAXTOUCH_DEBUG_VERSION 0x0001 + +typedef enum { + MAXTOUCH_DEBUG_CHECK_VERSION, + MAXTOUCH_DEBUG_COMMAND, + MAXTOUCH_DEBUG_READ, + MAXTOUCH_DEBUG_WRITE, +} maxtouch_debug_command; + +typedef enum { MAXTOUCH_DEBUG_REBOOT_BOOTLOADER, MAXTOUCH_DEBUG_SET_MOUSE_MODE, MAXTOUCH_DEBUG_GET_MOUSE_MODE } maxtouch_debug_command_type; + +typedef enum { MAXTOUCH_DEBUG_OK, MAXTOUCH_DEBUG_INVALID_VERSION, MAXTOUCH_DEBUG_INVALID_CMD, MAXTOUCH_DEBUG_INVALID_LENGTH, MAXTOUCH_DEBUG_I2C_ERR } maxtouch_debug_status; + +void raw_hid_receive(uint8_t *data, uint8_t length) { + maxtouch_debug_status status = MAXTOUCH_DEBUG_OK; + maxtouch_debug_command cmd = (maxtouch_debug_command)data[0]; + + switch (cmd) { + case MAXTOUCH_DEBUG_CHECK_VERSION: { + const uint16_t magic = (data[1] << 8) | data[2]; + const uint16_t version = (data[3] << 8) | data[4]; + if (magic != MAXTOUCH_DEBUG_MAGIC || version != MAXTOUCH_DEBUG_VERSION) { + status = MAXTOUCH_DEBUG_INVALID_VERSION; + } + break; + } + case MAXTOUCH_DEBUG_COMMAND: { + const maxtouch_debug_command_type cmd_type = data[1]; + switch (cmd_type) { + case MAXTOUCH_DEBUG_REBOOT_BOOTLOADER: + reset_keyboard(); + break; +#if defined(POINTING_DEVICE_DRIVER_digitizer) + case MAXTOUCH_DEBUG_SET_MOUSE_MODE: { + extern bool digitizer_send_mouse_reports; + digitizer_send_mouse_reports = (bool)data[2]; + break; + } + case MAXTOUCH_DEBUG_GET_MOUSE_MODE: { + extern bool digitizer_send_mouse_reports; + data[1] = digitizer_send_mouse_reports; + break; + } +#endif + default: + status = MAXTOUCH_DEBUG_INVALID_CMD; + break; + } + break; + } + case MAXTOUCH_DEBUG_READ: { + const uint16_t read_address = (data[1] << 8) | data[2]; + const uint16_t read_length = data[3]; + if (read_length > 0x1c) { + status = MAXTOUCH_DEBUG_INVALID_LENGTH; + } else { + if (i2c_readReg16(MXT336UD_ADDRESS, read_address, (uint8_t *)&data[4], read_length, MXT_I2C_TIMEOUT_MS) != I2C_STATUS_SUCCESS) { + status = MAXTOUCH_DEBUG_I2C_ERR; + } + } + break; + } + case MAXTOUCH_DEBUG_WRITE: { + const uint16_t write_address = (data[1] << 8) | data[2]; + const uint16_t write_length = data[3]; + if (write_length > 0x1c) { + status = MAXTOUCH_DEBUG_INVALID_LENGTH; + } else { + if (i2c_writeReg16(MXT336UD_ADDRESS, write_address, (uint8_t *)&data[4], write_length, MXT_I2C_TIMEOUT_MS) != I2C_STATUS_SUCCESS) { + status = MAXTOUCH_DEBUG_I2C_ERR; + } + } + break; + } + default: { + status = MAXTOUCH_DEBUG_INVALID_CMD; + } + } + + data[0] = (uint8_t)status; + raw_hid_send(data, length); +} +#endif diff --git a/mxt144.pdf b/mxt144.pdf new file mode 100644 index 0000000000000000000000000000000000000000..6d3d5c90fa50d4dd55595945ce370dfaf91b9b9a GIT binary patch literal 477936 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%0A-k85(8rlI|gIM4iB5p+p z;~B74&u|>xTBlxf!qR<-j$Mo2(wqHQLnl~71sDubgz@#2k(PSNIPi)f<7@y|MhVqY zo~t}3#bPmM?xQFFXWaTfF|PQ3(`&~6?E}U5pD}BTp~Bddsa`Frqp6g|g<#3dHb?Sw zSE#2wxTC3r((3V*YYmcF@v6k!Gl6->&>cjdno;Ryo90wVSPPl~?1sW1PVH#b_*_e@ zV4>dZwxtb}M>;l~!WnmH9c2*t`W*n(h2`T5<-P!?=_^0eyzKbx=tlg=0Bd2*+qsRpUutXN9;i< z#+`GI6&rj@qq{GHSZ2c!yR8KuhI_wmRAbAU8Gk~}Gp$$>wETsoDo*N5e*-eY3*6TM zmtcs?z9r399H2^gmaMNBPl4C;P~3&qV)9=G5s>E^P~SB2C^I7XJTG5pFutH&Hb{%` zh_`n8#ZremFl*fX?-}|jRg&~Rq3F&f2zGfX6If3T8`DDD@LQK+qW%GCP`CPT06-7r z;K5&w;mS=d^A<HrEAo30vC&|CafS$=vsmGVQ zQrkoA)5z6>OR8=2ttfUA(Co2R)HlaL)SrfTt zdfBk9CIZ{dGzk+SrD1mzwk-5zDd^du3=*x~YPKh&JHga-GsjgD4#mZQi3WBzC7Xmh zEZHleq;IFSnrnc-4zD8NW-Y@zzOS zDCb}9fvM19^AJ2o$f0#Rm+}aId?xYNG22bBDr@d<8m(eETb9j9L?J4yTq4M{Ej==T>`!1BWG9rb)nYHZd9F8CQ(L*g4#5n>7t2(K-;^cSc4$)(W$T?xz>1ULrd;uO4MD-0?C65e7;=Vv`Wn5*sV39`*J<5p z?c={Iwiv;vBwIkA6G-!H+UXj_J=&^t>nlBhqSRvM(-5Zt>KiXa-p9JtNS@>CbTp`V zB9h2Y!)I)U=Y{>Bv9RH>^CU@oVe!F0lw{~u{OFdvk>y7)?5Gvcd zzszC7xBa&cV}YTi@uvYsg;}o~*?3VBQ`;5@gQ9A@B)Ev?hHhv&&9Re9OA;J5Is&b~ z8_hR4D-`@4m2`%^dRYOCnS>VXLl)~o)a&vgh<$X~Xnt`8VVOTu2m8`>syAZBxO2Ct zf;BZvL{1N)^NM0v##qD|s2q)sSAC-VbTUp~?3_Q=aUqmQqzE<3y0C0YiNEdy@hsk9 zqk@L}SF39|`wrkSjiuScmMVI~W!E>~xCjfZSiXVxc7bw49YlycFne$xd8_p1B*Ef> z$pEFS1y_BRkqToDTaa|!0 z>(|iS@VwZj9{Tcv%Ox(GTuukd4!z>b=xFSDh&8dit_@{ba9x&@v?^6pn4*8$3gh7_^%^*dj)3K=>Pky(zUnpIf(kzt>& z86E8T6jf(;&L-7v!%SZa22zfb)l$}rqVqt{SC>sTO%VVMb3o)+Xt=VChFpHD(y*y| zb?CXXmLCM_EJ@&Di8!j_srXC;P0iJCK^V)HlvT{cPPZk1r_p)^jwH_#_1ls#q{9Dh9`#*W?t*TRWyzO-WXsi4vh^^1ACCXVf%lR^_$zKx?fuAyhE2D?}GfTwH8hg*^WOFIr?*x*iqo1nqw6c!qaz2^wm(5ENExHqn| z$yBMfq-IXml^Ps_vtcc2(Bw3UmaE8E>BX7+3KXLJxiRtT#3;J+Km81+=7^xGL<7~( zoWYgVuQBq!LC&o0B+*(=eBdGTN@Sv?{Fb9jM;H<-7=~57L_LQe3jWs_Q!$E^khYa6 zWi|%kC|(^Fy8oOo9MSt+0Bq@c#VcYEJSX~e$f1}l&t z-)mbQq8QMFyaUy;pYM%gu)=zEG6=?E{dW6O)O{WIUh9#IJk>H9_lUuW**70v(tY9R zk^2(8d2<_IPWTonIcroOP_{PLP2uIJT!^TAd;CnZlY=mFuS;bhDLjD37xgzQoeCwq zYf3jzdWOb|LnZFbX_cym!&kYQ1~Q?E4X!!F`T7vMI*xh+*>Hv%NEdSk=y_MT;!iN_ z(P`Jn<~p~i#0d9HsgUNEk>-s|e!VFasunzo_14Jkdi{3LZ5&sY$EoU{9K{P3kW+q) z4TD1?5GTr|ShbW?AFplvE|E$8dN>M$$oP5gQU|oS@V7KPzuUuK5rE^N2k($*SbvuV zl)ba>L%|5KvNDcn7?c)7d*M@wSVozEZ35WsPl1ipBeifS6njfNH`OjR$q{iXWXX$q zxfU`Tu8-BsHwxm8VGRNkD9tqQb#0czj~dC%Jd00=P?KImN5PK2h>vG|U=LCB6%N7K z-nnsN!DyU9b$HOxK!>aLI28s3WSMjEgyiM%G*AfxrUl9CLJ2CS%TMa~duu#KL59=~ z7%qXJOWY;r$*{w`OJX?V)Lfo+U=Y164IO3eYGa__9UiavvVSRmXXCMl6V+>EE_cA4 zN3~z#Al3(Z=32(h*@Vl)$^E(_Auq*)$xn*MC4tW$pS}7-QHP5Gs3x=%=MTI};^-m^ z!nDaOLymL_cUqz4P8qkFb~-vExq3leSjwli7@3}5Dq27oQOF}devIjH$@wUwyeq-) z@hA~E;Ab_#PwU?m&76+)(4TYa+Ew3I$|YKPM%&GQ4nr*dLsk3liSqwb)tHz#{(n^s z8LC}f{8x_14?{8gKKF}`V93peoP;e)MFoeyp4!?TQMj&D+7-?XqF3yxJt|u5V-cjA zlaabpK@0llvqwcC&gLJ>Ho|NO(|^PZ(Kah$}iuc~ER^*Rlz zxJY18p;xIwG&)=P;&9B4d!}x$Au&d%8Y}N4qW_& zEUegS@>CB@--+cU_6_4*wA{(l&b}(?AEm90T8bhpl|YsRmGGDI@e?lVK$&o7p;Fg# zUj&S=1#F9j!oWOE3D@dIh`VU!fW+t1p3EH$k`mg2R`_fqPp)tnVTUYtgzWDz)i_8s z>WCotU1O-ru1&#KE1HiKAj0`WaDDW~>RVQ{x~Gjiwg{MB!_ky~N=drqJ@qj@3P|Qe zw9$&3$`G=P^xm+4dTLMv@8*sWrzxA^r!zusox?l()2oddomeb7)r2iFd1NX}06?M2 zKg}XHq*qfOhz{@w8(|jBd2_Pc+iv!+ckphNtR!?{gP)N#ZqKFLs>>7O_sh>X+5*CF zZl&ui9lXU3JQpYwTh4)xUj&2iInI}m2W&iOIm?ECL| zIe>rTn3T$kZRwxazpQ7*BBCyzD%V1J$x@?g$;{<@y(%e92gj!1Dt<FO9Q};@jl#aY}35 zurYi8!U~H7w z3`0d*Em3PWbc!2&I?nOuh39ibLTcJW9r*+2wxIf)Zsp+1$=Ua|9!x_e!xB|}fp1LF z?~kC4j_@r~`?-1|EhS%C+Vz7c3&$rh{BxAOHRrW1kWVCVW(+}9uS)tyfJFYjBQEG% z2cb!C9ofB}XI+*CX&%TIxpUv;6a1l@N(@f`@=bbgb0098B)kgAykjqE(eL|!hqH?| zca~LtL!aRHjLTP%m`+nNl(o^dwR4X!ZO$ljeJD-7yOScR1gv6G!FaxT(Q006LNVO2 zwhzSc>kAtoV4*maZ6S1aMYNb>?@d@@jyLXEPbj2vQho)REa~563aDRUCSBl-E*enI zU;t+ADaCJ(S2yci))9wbIUv4D_renp&I33TQ0thCFIK}#GDx7FPS-pI)=j1fl#@zn zFs6p)ohn~ot*K?}PByo8pI<4kwHQ+WgV&%&p!3?1Fsk;RH?L$GSd$|EuUYvgt?!0J zz*Bf-B9oGr!-MA7VFhe!0)YXI-&b)U`TiEIvuy1KVREP=lr>uxNM8S0CpBI+GMjT3 z>Hd6|(owSQtWj3%$M0>PP!+yp`!RdGB$$1@AfZ=ScMI3|-Q_YTDX#S~t%rnzeJ#am z&+%I-pI5*DT%NQpt`nCVOfRdby9|W#mPt85m%vikOP{@C*l#NJoia|3#fy%-C#AZ9 zAo-gRyV`6LCv2B{qgjmpv}c6y>>L?a2Uvgl*qrj^dv`d+H4=gbTO(NMS3JeJ_#MP9 z3rN(Fh4kfG1dS~>l>yaymhPsAP-`QACmTY*CHr^nh+TJZP9l8Cdx?_az4z2^^Wyx5I1Ix4eMZ`f!@GYih2k&nev*+*{YX*n5od0?4=xNR z&!sOyG}&z}AQ+NbvfZW0Znv64Z0t*{XO?+%(jmW2J0Yxkw>_+l(m{pR%`^*fnon$5 z;*T#On0)C~V}_q-ITaareQL`pgby6asJ{v_1g9h$EwRTr*SA(pu!Lp^_i$6IT5q*p z(WnA}O<&)|RUL14$W-<~qsCCgp3qK?c-u#_6+^@Z-e|hsvdBMEt|~_;)^eow-@&3) zK~V=%f_V5K6y_33)~yeQI%n2dr06})buswJ)DfxlGBj_^%Hgh#^xy-8<-?<+eln7Q z96XVdbyq1InTz^qr=aTO@N&Qd{}d5mDGWKQKVHqXVB4a@r4$jUbEFF8 zn7h*cPTDV$b}@YmItp-GYv|x_zk~omj~+fEwUgQP5%pIZiGaeSRFQJ+K>t3gAY~y7 z^^)LTa^u~@Zn@1p-4PKVm=1~YBxpn~HqRyWJ7&do#XyLd%g+iX19qZCB3QNxDl1^z zkO0l4fM(e1123wB&5J{MoIF{(X?K!?Le`k9j)RZb$!jn3LmL=wiE=HZf#o~V zb5?^ZDdBVYo8-bZc;ml}+_K%(3Br;4@tLq(rHC>1F7@CoO)L_Z+XnYN5i%eyC0NGK z56R5&sL(b6v%1k)><%P>;R#h_ki^|Y_Bs$1^-F@Uwjr_7{eI**{1Q<&sd4Fw5Fes{ zf&K^7^xxC8{|7a(FtPsESCG;;5!vS!n~$oGoJm& z9Aq4f3v_qhhnG0hzf2Ne0!pMJ&-iMdsWPoZIL#s?-fMl|FEXNbj7yj2phJQ>49?>I@W$(}$TT zXoh2%e0Hw^@nz2Y;B|uT@|wL+QxYiD(c{ej@Y?^qvCRL)$jprF|MlEwGT?1TLE1-r zLanV4yU_mBzdkC$U-O@iGjJi0bSgQln>3DV;;Zwv;t4G}fT0*H~nT&}Ar( z2Clcyew$jzbdgu^{1munu+b~j+^;jW7r(l7P2P;XEG_(N$MDP4lTJU2Uc90 zaG9f+FAS$SEkXhXYNN`mb4^Ps-nJ!l{nblrkC%-E`aw}98CR->16FbXAa+Cq~6K}F(W4yUwEZl(=b z91Qk4yq%3rCe_75feUzR3jCP1PtkBMdS^l=2}%Rl#T71_M)NyTXA$W+(poys5OAo)v*m0Af|J>DKM@;ol+{(J#cFJ;#_ z9cmp~5K-CQT$nND9c)$$w)4It~H2g*&y@JyeN%kw6RMfYQ+F+@oH8SvavB6UBp#^EFa1$7|sQIY*JxW zC6}s3GWBFiJMy5aBHTJ znCXgruC~1664g3LzIy?_8UCkYUT!XgbYY$PHMOUVT~A_=dmLCCiac#=X%LSgU8$2E9%xgaX?k^EF7F$_6f8`@=S^w5j%8YU$qNJjEXqoMrlE6Zl^wKEGq8C`b4IsoH8nUSw zwVj$n@SDM%S1o2o`FhQV1lpSC9=1Ph#c5B>=G}bJ=U+#)*)ZVaK{#Kj=TUNSQHYZ1 zmCjGa*)07nLuiWK@I+1ecmEvYwL&p9M?&h`c#KyN>WwUt7#qvy%k*%nRvm_V(RB+V zebWTWC2APE@tw-XH#D>@hziM$jYE>eDkp@OG1f6W>o~Gve&Ib&yGR1QqJVVj=&=Bq zny7t%q(Suyfn);y(51h;V0rT#4|dVcNHwI-vG>jb%_tKsq4ERwP8M)?u-D3Xbz{Sxh;RT_mrjvU z8}hPyzBU>*L%@0FC`IoXK|+DRu3%27h&aOA=Bne{J&U#fq#tU)*YR1$9?`?Va4)m5 zJ+;yqahb$!lGcHtD3lN;CFuo$w3KJ$J!59rNlkM!1GL}Jv?+>67ngaR(H+r*0PVjD zD6Hnv*!!ms5}@2g^2g*jai&Vtt2dR6P?MTzr8EnoMtGsXt_K7aiD>SdQ1Qo4Fg^G7 zTjx@#SkRO824u?7O2@84m|l)j5)kZ~ofv)2?T?#6!e9xBLJE0csAcUi1eaMGX?fDz zkpWY?uE0Ik@Zgt>M}!crgWp?5Nr6Lew!mZkOX}%<%^O!cYqah0=iBhlYZgp#0O9G; zO$KzAct4Hok9-adB3(clB)qS}e-Luj*ELlL2b?B`(1?l9vvZs^5>0X-w!!)2m{=7IP zY!j4OPUN6UvhT7C*Y@PpqidgV$OrD!XF>E)$FAXJ>GHMBt-G*B%B?H3`@-z|%~>nWD2frXWh(*MKh zgJP>?=fTK~VO=ee`+y`#dE?rl?Cw9HLJgm_SA=#}Zi)~rRj-@JGvuIMM&V#G64R4R zF+mI?s9xq$fY#j$;hI+UJchgj?55YxGwC|D6}gn>YW(9c=*)Ls*NG`4 zKA<>K?bJ)r3Me&dX2F%gN(#Ei-6qdZ;DF+%lJ3O&OiHa)ev&sxERDb8dk+fMprtj> zdauQizUMa}D3>D{iBi)x2wbZy=l#oYOxgiO6F%14+}5=Ii6_kv>T*JyP+84xaA%Z7 zCtqXNNK|NJlKs--aGtb>>4$iNY#}`$rM69;tGn#dpUhtU_(KH)1r}laVaxZD&^5&iQZFY&^!AG$r%DoGw|7m~lP!%X0Y(L**AgoOO|xfm=0^ zRY$Y73d$KbH(kYHA0{1el@)59fLQ+lQZfFIrYW54EdK?mn6Ao~^DPs;ql?ucO1yfZ6^3S1A_D5fQ+H~9QtP%`1-F9Y&87ll%1haJD#C1eQd9dthLKeh@<)+|4>pOIgSvMXG_>IZLvd(5`E>R z4LKWkAEQwn*j*M2*PD2!W_%?&2NF%;B5%tDF=H4;KIH~h_lgN9VRf<)g44}{YS1xlO{6K_xK9g+hTEw^sPD=hcn-eo*N6RKU*%a@n1T888Nc2Li zjYF-3`;6%~BnEirDauFOsU7348_I~xQLg^R-lhe7emC5^=rfIBafNMW=JoxbYQq0$7Qx8E#`IrBL2>Nh))81Fk)0Hh?%hCJ zLbygug!HOsm-q(D1Wj=hSV~|v!zv<=NtB3yDqAsSju!c< zu_@g(cjZ54C>v(WMcgRPXf`pI;;_ucX>*c?idJHU2r;-@G5sNcxW93_oMZ9IAR{19 zJ*2WF>rwcdzu#5YI6Q11JzF_(Cw;k|dK_xHX$<4{pRi1(MuE|!IzaCA9QNkkVoqez zNEiM49+s4^Vg~3(FDUsKsM{$vxG>q|y($4}At|k%Ybl2(wFcFZGYJSM(>JPpJ zTc7YN-lMSF>Mm>~lRf)H$lRvz`I8GmcrX_CRP3L!SLPr%KNEiMf$>G97B9*Ex1iW_ z#4|Qv_L^wF%U=yTlkgEhvDCty53(G%+OD4FuZ-#333uHDxww_KXh1E9!wuE!;-1?~ zB8NvtbgL9>_(u2{q&6q4?LWZw66wV-kQdrwkEbc|0SJSfl1q_YDKm*mzt?0#kOGY( zl^@amIWN;4+TDaocVThIq-vu)NfHo%Ztc8_fk`SaeWYz;5>bp3gau!r3k&tKaQ zR||N4jwY^F{m#RYTeod^aMZMD6Ccs;7N%f6913d>@kFkE9#;K_5|+5cyd*QU_;n$k zx8McAvnO5%EbAdXS2-8h(OM46LD^3!-LD%^V$DVuGU0W0J6}g+nssWhVLW1O<(14I zGDu~39#1bu5+5(w1Y|5^eGluH2hhESLbH>du3y?7kXqQCXu2(Nd8q~{%; zKv0mir|Jf_f|<#D?lpW`C^%QsZ3L^Lp->h(*&wbyDql@F5>Rw(I`jR~UbF2iQlWgt zJEH6++Zs;#!XqJJFVu*(YtlMte;#cMRKI9jM>d})&Pt#@7p^UHZ*EtlX$@$d3&FMh z)>bcgNNSt*DeAg=NcnzvX{h$?v3-^P;inQweX;Dc(N+yB?sxifV|7lKYrQAjpG+R; z2Y$UweFR}16~5Eu&$ z02AKRyqJ_e_5GysbMf}}HI2|-lTOvqJ;EA^ID+2V<3DA{82|Utg8znWoGkx?sm@AE z-6e}eRima?2z^+#fBO2&SOs%(s-HmyZzar{gN0$bX&0HYBM|PcMY(wtzv6?)Tn`5i-u1Gw&spW+P@wlW7C83*)>80;+2+0O2M*IGq?W$?LDyy)Jrl>`w zNwUV6s^f1dLe60~@Ye`XSi5h?%XzW_yC`KdSk3?()%YpRq0dB_+BpNw;U~jScJYF; zKYA=aJXg(7A>~1GJwOi`E>-((dh-)2a;Zgmnj=|i8;x4ya||zmS4klQu}FLF_$~Fq z|Jl7dT29?8OW?r$;DcW5Zw;2&bfTM~*<#fANxsne2%KPHd30pvTbcX7l zM+3SaIcBnGZ9Sp6f$4m3npSEF$^`R$TaiSE4t*Os{=mXAyZ? z^k3JY+VzO4QMX0dU0{y>$g}~Q!9u}^8~}+n4)g?}x!l=S1=(lX*7T2qAk~%#xS+N2 zi2MV22$99caS|u_xA70?HzO6T!>v#C`SMmoKT@ufgI_lq^aVb4w-{q``O;s>)WIp0 zMYKeRnbpVbk0BBO=g#I^EnFr$slJw_l=JgCmc$pZ- zt*y|_KllAcVLEO_<*cXgLvhwkP_AS#c35ZGcN%x1ptG7uxJw;=YX4H?=wBdU25mH9E#6t!T+&naR@wW)O)g}4r-lQV(S)HI(>hC8(0kFM>Sy-T=G1HD z2WAeu6Yg?LVLYT|D%dMSYnH-7Dx2)8v%OPGVKQW&=E_SEfyl@0_oMG#R@6UfGtCdo zC6WqVD40cJa*!t&j2L#VI2|!sU%nTAGoQaOr+i(b6%yU*{_6Iy#MM}hBsh3lDx}!4 zK1tRBO>@5SraZx2@f`BiYZUPAdeY{%c#SH+BX6W+_2jnWA-CFm0Q2edpaZe} z(yv`qy+!qd7S*PT%r-*ci-2N&%^QP6YL_?x;8H1}h~p40CcU3=$&Wp1R#A-Ci4=MC zB?mkl;rV->J;4hN`HOZARo0$r{Nz2MOjc`>RT}5bNP?DqIEQS+Tz(eF?vVAA8O1Z2 ziS$*&-W0YmjK2b|UP{8Z?xhjIDulu4Qom&_DV=)B=)1I7)oZupy-_hKZbTYk0Z0 z;iOgOYHnVwt2xlX8UKX*E}!4Xj6K}*oHlCa&-oS%CAgoVG6tNKr_5vVKTw;dci1BE z0Z^J}?y4l%?{jfxF{+W>4Y*BRLq2N^PQSB^Ow(V8O~&*1(~Qo`WJTgTkq-6l{md)+ zkv5Ry0<9;H-fy)_xN4|QA0+{xo+S_Oa1hp{>Kg{Q>ZCnrKD zB${R5XmBG2;A-ZEs5s%Ts$UW>0+wfWE8u6sX3IXd7Ij#E)zXFPSko7eLR|;*b>J}V zmipaAD9Q91d;yGbKDQu4bx z&;@~tAtPw)6Jf=a{^~x$qG+H(&6Q?}WYnNbAXAmOnzKf?l|FOFvlrsnLS@hpSE@mj!Qtt*kLTct zFHcC?Tq)`@7|d+YbRwcdt=G?e>YekF2}HC`GPiWq<2h3R)5;}4FEeTsI_cbfr~Gh$;gvOEamh&;rBE48<_N8I)rUls|

%3P5&TSv3 zEmPm4(*Vth^BwMbXUh1zUBuqq=pvyPt%oFthU?i?^)gtYJ;`b!~G$y>H) zEpqDm=O_93yu*^f$&y)*M8o4&IS&Op8u3;R^)^67a-l}yiYM$(B9{932ay}dV{y;U zistsr0Glli4W3Q+Su7byJ4;mCGz>5=EA?#;IBcvv(fmxSBLKJT)T&>Cu7u$gmZz9u z;J*o6q?nI5WCJa}tlRPh8_eRDW%(fEIVu7%BG#RniBFOB~F7C(Pur1um2H zpu~sfbzwd1FFAo6WQSX(N3q3kdJS`{v5@;~KJs+^?J4rzE>AG8*ks@HWp^ZHR>g(t z2wzd7orjzW1rD2@g~jHANT_%{!MpItxJ~d@tBgMSgI@vcmv%B+Q+1-bU%j58O6p?t4-8#YWwRwe^vlP zgiRux`LRh6TPQ0`+ z2aIwL=`MNAvSVk#YV<9Fq?oBrWwP*CCL9##y4wVN4UA0gcx8@^-Rq)p?!_U!b3JP8 zp;ybVJAffA!9+N6JOvGH|2+JAMiF~<&Twy{4pV|)$r7jB@gf}QP zKw?6rbj1B?FCbJVDy30)KwZ8QQd(~^2Mxb6eNLLZ?AG>HdABqDm_@#L8pVp(2 zVB0uQHl7~*7d1a7a=z!(pMol6`6Zl|{H8?N`^%=T**0>M3-7-@uwJ(nCzPThGK+~$_LR2Q^%dLwNwrF}G z80D zkwnu*PcCMk{X8=-Uw?vES(J`9zEAC&0r-5`TwVid{sY8e`rn&)|L-5q%EtOXAkOn4 z8hxBg^1~LJyOKVIkN<5WQQi)*bo+%2NHh7%OJ{ z;l3v8lf+V`!=&URPgRh{x-iNgQ(?X=D!W0JuY=#?vPw{rTnN?0{fqz2X3UrsII190cm z`6D9m_~a0x+%OHqQ%o8jcHI?Edn>@y-UWAvi&N=wx6oEi^=Ys2Vx(7_>y6r%7~YIF zB+-+5hbx1r;5!&|hRp+>I#b?Jej;aBZ>q9rDImPv%MpxyGNJ!8pBjs*ftor~xg93_ zew#@I%jBBuEM^x%6Y$M>u-d`niQbqW&88Ibz>V<(c7PWz6YA%}K`v*K&e{>`( zW#rFYE{7TT4MTHZIaohf%vK=M5pj1THxcSHOfW`4>YiBAa7*o6_RBM32?9ONpy}&X zwjgm-i7FjY`;COAn#qmH)>zlVANZEOh*c*H6@(r9k`SVj^`7dZefLLA`2vl2q-}=F|PvzeWS{^sB!hQt#zBV>&ZyIxFkZH z{rrJ6UBuZlcxNPbmF-EJ{-Ky8(4WSgT3BhN^}FHG<>(PkrAsl|WJ2bwY~Soa|#=oe5~((dzLr(vwq zkLIyt@5!i7wEdC&RLj$5Vn=nx;h`I9s^kYDODH5M_RC$bhSGF3uV_OY7!|#J27U3o z^A9mgG<=+|PtoUp|C{QdWQ+HD=HVmMnaTz#Kq(co5El=$+8ZP`-)Jz8S38R+HQ=yz zkVlZ1$U#d^5Pnz=czpEE>E(xzJO4$Pr$v8C18dL+fU^t+VN$j?X}Xee5dh2fH=Dow zagtQAE5e(0KRnX&;E)ZRfxFe!+PoFwf07u#hN@~8ky99887)qb&v@5jk zCzhdm?@!DAoVP=k?c$}9iljRL#N~k5hs#poU<3DnAH<=wy0PiOFr84OSYghVg7Jm6 zGmVvWR9m~8*uw)}is*UI(rv%|nVPt%Tmr_xf?$JLIp)q^CoBU65B5h_h5Kc<=U4ZG zIB-m!CY98uoySZ{E(kSH=J@TsmT_(lM|)Cqj0eLGq#TkL7CXKGY!^FZIhpe}<479> zUZpHXUH{^8b7huJGwRQ3Wq3MUH`lh52(7m%CFsfQU2GeAOdm192)III8T!7`yu_Ah zK8X_)p!{T4?bnN}FHhHl-|OJ6_=_-#V^7h6f{m!6jcq$JYeq{n6(4skC9)4IWFRn{ zF-%{H{O=Q4l^M*1klaORoE0+O+K?D|U&xCS$%&_p1JwhKDxS!6jkJ9)fJ z_yI`xkGYw+Q^_4dO&n<00_1_@nL-~MFrhw2jq=gor**dnyt=mGho_r_zukzTBu&XU zOPSooPzVCRfFu+^Z^;K3d8Wx&js_xk($AY&url$aT(8_+LgMo#=fp?th*qO>P5R5W z^g!bIYYztcxY0@1pS;Z<)YeoIiTjhVC555YW zc-kte+*AST`Os>S8i0L;Oh8Y0cRF$Al7~2a{&>H#T=Jer!D_2^WA@yws9=Rtd@;L$ z(%s0xS_}z8kD3!|o+{_O?jQ0&HWN6{11k8>_cWMoqlamgTvez`hzhf7Rj-k|iuNiN zMD>?ghyDU|S*2OFFKxq{-j%DPOrL4+)L!a>+n#E}RuYJGY~w(Z)fY@eFe5$h4|T|r ztvfu=Ami=LZ5ZL+ah$HMW04Yc;VTu%6#a>{H!ARc3%#vC`O4;F#rrPVU)f=&&to#m zi81T|8cOjck)C)oKIysg3W(EAVNUkz*|)x&D=VG#p|lm0y-YOp)qT5kP?V3$e{o>! zxeLR&!06+|X~08X!F=cM?7W=xOt|G}*t;kRn*FUn#`XkWcGE98<&nOJTzMQZM z)Qt$b(==OXY(|L%F%PWs41F+i!059BfR$sarhcRVTqruuv#KAkRX_vnL8#Z>g(b-P z0hltOHGV>%NVM$70^NXZ<18C0Ve>S>@Hwxxl9rN4dD zsZY`4yhbuHKUPO&INes=3ncJ!uh{;f{-kJh`O-e%C<(EXmF=Hyaa)S0(UkM>0eX|3 zqm7$bzJnh9}I1nxETDznB$3=zhUJ&I6@*uIB zKadfJe`XVRgnUON5Ep((N@E-~tH?j&;Va2j*KBCUHNz zE^xB0aNyp?Gsc!3?rXE(18DVfiYDlxJlVZWn4dp+uFE}82|RORJ5Xm3n*c`L{4;Fe zStFWPiPNu;f`-!O3pnSe@Va{Ks8Q=MXF=~*D8I-dh_v^7IdtK243y2}7V}_Q_0a&r z*JkPb6~?d91`S}#_HA)MUa&DZ83#nWdC0@kolKMW5cPY99*^aHeMO zt*JlKGSI*+m`4;6p0sv|&Hz;TPD1otC8gRD#D0M~4?>q;knDLASY^lHeSY;=$p|L# z5QSm7bjwnHADC$O9@T1R6HLUox5R4XHE24HnCTZ-p^EXiBBZz2;Y~`}Dr%sCq>zJe z<_)1`Jpd$wI%UKrH23z7Un+#wL$9Dts99N$JP27VtGr#I2}lP`kR8q84L$GmFTclt zHPQtP4FZ0l8+r>;f%L2aKGj`qa0Y%zR}{{h;dL&|Elrj(cFV2ZzI38N;j7Zx->>;-X|6*zt7T;e6=cI~{fQqWO5j~=$fkPpFTMY*HQ<{Nk zDo(h%d|Nt(CZza&=Tv=kK%b7Rmn?%?fJTsrT#6gp0rdx>b8XK;VYUFsisv7pG>k21 zRE5pPMFZatR+Bh1M1W*Vj0}y>CfxLsH2v#}A}a6?7fba#th7Al_`s?=Ig@I}7zI*0fOs!AAc*leOMl;j z;9N?B{8vu)--7PxH>CpV{P^%Rb>U~K#)T9~N@3;ap)2vtr`5N#0Yw3)7x%q6fd7c$ zZE2&RX=JwIfs`?V=?r9U0CKQDT$13Gd^Hsvt~bd%XF-L=2->KZb)3sMjMfsc<+rw$ zlIRBmgSGb~MTBZ|c+y_m!0#Tdqf~zY=Kakjfi$p^(QdTL{^_Q|QV!S4ZkWEnql9KNhL zPNnCw`xej^4%)l-VnA~TMJ3V^I=09*6STB|2gIiTwpF*s!zv zK`p$n+bXB)IcEYnJtLSS+ZF$G+)Oh5K3QcY*A2RkyPdX%Ed*Hz+o7V$MB#n4PXAL2Rm6_ln~nr_m8UVxXxOCjUI^P2v%E=6)b}*u6EU z%%c~fVa3E_XzPYW;hKDRG{0lB$IHJY3_Wn}+4E>N^2m<~Y+uC@LmFs52~}rPIr5@{ zN3qU)^jD(=EMK=wO8=!NKCVF+*-+o)M%MhfHS1=b=m$kYULEC+&BVq%?nO(z{D2K%?plmLUS>$ z(L`{Iml$yw{N zI#&uxCApnhx@Zx|`RTF{v21`N*(ZE0Y2qLnxTz(qPd$N?2P=mij4^w91d=Jsg!+%y zaHyeQX11i$(;MF>+?TD(m$3KPd=dF!T(*&$w-p9Flc9gzD(6}!%v8hY??>l=DAtk> zI}cPY$J01c*}l|K-MT##ajn0Km$@Ef6;;Tx&gw-&Qi&z#3!}dk@fTxYloP)i*@wna zAW}YNBlfA-cld;8QQ>J%(KOjIX^1)(>jWEue8}6j6J@9OLiZsaw z>O(H*X=9J8_n?k0dXH+3|2d!HNfbfDC%W*R2>fJ~v3JPOsHvhoNbR#e@zD;d_F>%_ zc$G<=jT~ALxumzP^2u2l-*r+A7;#RExh*6yDcc&krQf`hQ-K~&2z$d&i*pfy%#Lk- zXcz}OrWk_txAV^9={N+;bziK)MJLs~Ipg$-W6qR}>U## zYmF0kq)ouA@5cjV*6)2=GxD=rb9ar{g($;FkmEXe&ZsTF67&Kl`t8x0pSo*BO+!P!Z8K zO*WiCVvb>2UcYO|zvxXZk_VF-$B)nU$bqi!kw!ErlTIzocfZmryn}#?kt^~XiWWPH zeQKL&2pBtVQsC#A?`VJ=?5CTj|0v!nw^2|I04_ky{9zOT?#cMH5URHw)B_<}$^J{ShP!#SC>@NtdpCGEh`Mh2shz(n>y28P^?7lc(A`Jf6r+@&RSugI*NR&Nv?|(we|9i>sf1_nqrvG6Y zj^2@u$bE<~32%gZ%(N!c;?8d+XR5*j&yxkm?@~mb4FAHbb3$AspVY$w+O>{0I)6wO zuvoRb`vD#>au~MP8AvP#j~dG%4^1T~8;T*HW>FA90&{9jmbHmQsyg`H0)yHgVec=^ zQKMh+LJ;O6d5)$9pO-#mxHlcDh?hzbIzIia-X-CQ1RBn;F)<51gP48@>?FA(y&w@3F%%jv*{6xvN1iZ^aR;xlXjzm@%m`AQf(ykOqsM;esGLTcnPZ$PBl1D>f4FVeY5EdME=$+1esS~eV2rql5`IQ(} zEd5`pIQY`m11*Y#(13E6%O!hVAvmtIHhQ`n{t>ss;;|Ng^G8 zs1`>RUWEPmYP0jGZ0_Q?65WC<^O>ClO-~lf7=DgR3~XBiDP5#GXOiI#Z!HC7 z8&5K44F#@uAywHOG97WcfY$aG$#GQTvh%09MJBC^EoWK5q%VsTlYuz9R(xkA;sASx z>~K0toH&gT=!iFU>0dAD4Fp7cR8)L!U9u`-Vq+*4I~8YQ_*#WIu9R0&<5K|`gznHG z#Z;ihQw-=jh}Slfs+>0k5>`*68bY?Keq37(0JPc%)vT)}ZcP?&ik_>^cB>&fsqF-y zeZE8~F!h7GyQEif>k>rhbLS#O+3mRclTAIi5dWfIBb3?=G}fcCR&J%p40!!NbC%2f z6wWj$wv&%C8L@84OE;t8eciCSOzz~7RXwblCDdEgT29KfiWQ9J;cGs#IQITlu0j>0 zwqls%Bw$7e4$V>`ms5?`pm3R?61}=#wRO!bF-K+)zBq|@(~K(|qSPmVg~6*KUE%Au z?#D(FKf(orEmOg}lBaH+&tx3#!=Yc{qw~FzBY@T)?>_wVQN3#(9G{S$J80!xpP=e*@SK>tQz872#Riq_0z<@{@-rWk@c%*GO;Jl~j z=<4QZIq+!~t@750yOr@X3ZTud#VY5nZdy2Fk0Kxw8fX3Us=83@Ri0`>9%rN*n1RY1 zB4j<~gn{M-XstbA$wlA6GLc#r7E3j(H<}bzWZQX(#q@b#EGwHvT zhQ&uCtV^4CABS<&&3f76eRG?b^deH+J@r~;i@=?aK2zz|PvIqVnb9~OQ;?ZmDZti! z(3S|4L(Xw20bu>OGP4i?$3V7lo4nLq1CCs)GKHX#zp|BtYapQ@PT1;)d@@NSYv5^% z51IqAOd6pJjEEf|@k?{QmL#?&OZKvmhCkX9{f=y-KX+i92c-romRdZH&?xV8pY3a9 z44_aDE*AW!!trkwQ_YDDO^D^p-xzBjL>iiS`ty*}%qs4qccGW?zd8%6$Pn)V)M2W% zaovq6p5K1iIua$ng&)fbR=ZdvKey+#Qu9dZlYwa^*(#4IQO}{EPk`k31jn}SooW(u zRdL=C01pvWxt}}Gg0PV|7!)2u-RCAs|M0>L8A5{q6nzC{s;RlDojWVCZ@?O(A3E?j z@`$tJNmanbJ`!~#Q-=onl`P46+#8^Y6Tx=OyM`7RnOgHj+RT))L$ z(9hEU>JCZNt?K!u6bbgGWxOY*-|qn>cGvMuQjE(C-v6>vft)VR>p${}>@(^k3R{ZG zvx3cpTs1#x{TOAvHIrnOxW2{OHn7_uwfLc&+dBGH8eOPnx+krjDx6n_Lnr-_H~{`U zdKfw40Zd><`;aLtN$=**m!Yn#2NyM!GZ7_*X1J-7(CQBxiW@NE6#nl{|;;TPmC zv!$zoq7qkqyC6~5ea;;%*RWgzMM^0A>z`6V!~Q$bj@$D%UhY?4hv*nbxzAsyPCmHV zH7+AiVSf}`lt+s%iS8eGU%|?dM~1*z!7Jeh#{Tj5v2MA?!DUjH;-Y2fAQTx)Q?98X_1DD2%EYmwB(XX!D9X*R3q0&*aRgCC!12nh22 z;VoD}k{s^?wE$zK8CjP_A{#@wDe8}TWO}n3@-v!wrmbx7`Kdejg_y4yF2qarn5R6D zl$1P64vMrS$8V>23aW2Y31bzF_7mETxevSV&J5Zx+zDPFA=+AFhf74NFBQ$6tf$D=U56i4jOQKbah_}9kMy=y>}MN zk1&4h%|gQW-2~(oIuXJ!%Ho{Zr!^ku+1o#M9k?iQ?&M~Llv2yv7#AzH;MIR)D(_j! zrcvx#ccy_n)GwKJmvPFYZ|mGx%Ie6cVI5LX@J@)R1p=BfxgE0hK{qKq4s0npVdQ`u;lL7#Szm-qITD;tng!{d#DI{(y`=4XDcH%Z7iO@y???)i;J3b^i zJi(AaJztnjD&^m(5D2^bB8vuqWU0dU3}gyu8=Jy?Rp^6rV|X_E&M4`Y3g&M0wub@k zV6>XCw9@&|C@)u#jcDoM3yGnhYjRMV2Z&ZgLM)KE*<5)VPYGQEK)7HD$pX9&-p&{M zM=P``b>6FW{D+FfNVirUMOIkJlT3VSF;65BvgC}9oVME%n zlBNZtQLYKdKJX5hEn)ur!C`q7w={&Bz!3W7vW=9rivDo~b8ZR*UW8Nh>I<6p%nbf; z^^Yn^-k@pws|;7-|Iwy~S1d8gCESe5F*JL>(|;JsBP$dE4wwYTQMBo<6+=*)?aG@8 z7(*G+o-iwo8-#Xqk6%i^M+S)xecX_!BJ8BJ~BC5(^=AmukMbrx>)a* zh}nON>hhdYh7dx2nY13grm~ZN(Nj9pntqFR>%&3NDuh629fpi#m@bUfDCRaxduVE| zJsKrLS@2h7OQ+&aSf{Q}x5tRD6HTI}Lyqa;5=n4BTymSv4l(>RS^7~y*5r&g5=Uq5 zx?#w9ntRtg--Pe4>PNqfjMS9hFg^GfnVjtuko2F-TJQ}SiGuX*nr$G}NsQzb80Y$0 zx9y@8VJvifbuLRn5BOT~+I(e0E)P3$GO0pd7luS8O`oimCkv~aQIYZK zIuaR#afhuOE)+psn$A;={j?LZ#-`mZnXVK9w2oEJlR51IJdizjFxJH&L_c8Z>CQTh z*~gQ8Y`;XP&#@J`~` zv8B}stPIlj_MbswWaLBkyNg|a6I`VbWTlJUtmn z`&g9frgh9zvf{7&yS;zYfsoBddzX*X35lC3IBX~?1X$RqYNOVq(hu!P^(y%PhHY;j z3qxUVAQ5lb#h_k>U-ZB2D@wTLIy;j5-4{UcAK}h6f9TTOQqbv`#f1~+PeiaTTx%`4 zw@s3$AC1`9-z}9u#>69NMhzkHsYUy?H|y2T66|7Up(FPC*Y>6#(A1Jn`I6Wb7gxGl zI!P8d!(86cXGDgQL0ZOFlO034T#j+5P`dJQJA9-Ruka*(CejHyu?~QqT@}uEG#hJW z#bCc3j=wm%C#T_g-(7>om6}&Uv+oUw7RV}}8~vVjQ%u8e*80o=4vxyM{jg6*6}J49 z$NMQoOGY5BOyn8m3n-mi;UV-pjt2DvnVi2aih$ZZ)Vvw9Ez-~aD8vb;e})&!66^Cd zQ?#@)4-~?~jX~c`*R$ZOhH+vmFN2saY07)~^>G2mnFGe+uA~ zU4yjj!BF1Mk9RZ*y^HHJLxiJf|nVzshb6)JhV=emkdk=OH5$a!^ zGrSN(++4Rek<^CcbuY&gaNVS<>41BIUJY6Y9r=BEy!N$}H6neR;JFyXK(G&Fojru- z+C+%lIzBs|o5%R^)w?4_iv=Cct)5f+~4(yt2+L9Y7*7d_v zTR^%$gFO!jocU9Jvf<{yXeZ;E#^

>PljeXX|O_b`bet2#Ub6IHL;)&iKgM3iBTk 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 z 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

0-G^ax{aGYB-&;u{(=Q3a*32DAv5P=>p3xrKve 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�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

-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 sUvFKwy^p6ZT_xjRo@Nr+(U Date: Mon, 4 May 2026 16:06:01 +0200 Subject: [PATCH 4/9] SUKU xy module driver created --- common/src/c/grid_module.c | 13 + common/src/c/grid_module.h | 1 + common/src/c/grid_protocol.h | 2 + common/src/c/grid_sys.c | 10 + common/src/c/grid_sys.h | 1 + .../grid_esp32_module_octv/CMakeLists.txt | 2 +- .../grid_esp32_module_octv.c | 21 - .../grid_esp32_module_octv.h | 1 - .../grid_esp32_module_xy/CMakeLists.txt | 8 + .../grid_esp32_module_xy.c | 41 + .../grid_esp32_module_xy.h | 20 + .../grid_esp32_port/grid_esp32_port.c | 3 +- .../grid_esp32_touch/CMakeLists.txt | 9 + .../grid_esp32_touch/bb_captouch.cpp | 882 ++++++++++++++++++ .../components/grid_esp32_touch/bb_captouch.h | 266 ++++++ .../grid_esp32_touch/grid_esp32_touch.cpp | 64 ++ .../grid_esp32_touch/grid_esp32_touch.h | 53 ++ esp32s3/main/grid_esp32s3.c | 10 +- 18 files changed, 1379 insertions(+), 28 deletions(-) create mode 100644 esp32s3/components/grid_esp32_module_xy/CMakeLists.txt create mode 100644 esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c create mode 100644 esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h create mode 100644 esp32s3/components/grid_esp32_touch/CMakeLists.txt create mode 100644 esp32s3/components/grid_esp32_touch/bb_captouch.cpp create mode 100644 esp32s3/components/grid_esp32_touch/bb_captouch.h create mode 100644 esp32s3/components/grid_esp32_touch/grid_esp32_touch.cpp create mode 100644 esp32s3/components/grid_esp32_touch/grid_esp32_touch.h diff --git a/common/src/c/grid_module.c b/common/src/c/grid_module.c index fe4fc03d..d5c22eb5 100644 --- a/common/src/c/grid_module.c +++ b/common/src/c/grid_module.c @@ -255,3 +255,16 @@ void grid_module_octv_ui_init(struct grid_ain_model* ain, struct grid_led_model* ui->lua_ui_init_callback = grid_lua_ui_init; } + +void grid_module_xy_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui) { + + grid_led_init(led, 25); + grid_led_lookup_alloc_identity(led, 0, 25); + + grid_ui_model_init(ui, 1); + + struct grid_ui_element* ele = grid_ui_element_model_init(ui, 0); + grid_ui_element_system_init(ele); + + ui->lua_ui_init_callback = grid_lua_ui_init; +} diff --git a/common/src/c/grid_module.h b/common/src/c/grid_module.h index 10c9fe1b..584ed128 100644 --- a/common/src/c/grid_module.h +++ b/common/src/c/grid_module.h @@ -13,5 +13,6 @@ void grid_module_pbf4_ui_init(struct grid_ain_model* ain, struct grid_led_model* void grid_module_en16_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui); void grid_module_ef44_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui); void grid_module_octv_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui); +void grid_module_xy_ui_init(struct grid_ain_model* ain, struct grid_led_model* led, struct grid_ui_model* ui); #endif /* GRID_MODULE_H */ diff --git a/common/src/c/grid_protocol.h b/common/src/c/grid_protocol.h index 9de1e3df..c31dfecb 100644 --- a/common/src/c/grid_protocol.h +++ b/common/src/c/grid_protocol.h @@ -84,6 +84,8 @@ #define GRID_MODULE_OCTV_RevH 211 #define GRID_MODULE_OCTV_ND_RevH 219 +#define GRID_MODULE_XY_RevH 161 + #define GRID_MODULE_TEK1_RevA 225 #define GRID_MODULE_TEK2_RevA 17 diff --git a/common/src/c/grid_sys.c b/common/src/c/grid_sys.c index 768318ec..86a2f837 100644 --- a/common/src/c/grid_sys.c +++ b/common/src/c/grid_sys.c @@ -240,6 +240,16 @@ int grid_hwcfg_module_is_octv(struct grid_sys_model* sys) { } } +int grid_hwcfg_module_is_xy(struct grid_sys_model* sys) { + + switch (grid_sys_get_hwcfg(sys)) { + case GRID_MODULE_XY_RevH: + return 1; + default: + return 0; + } +} + int grid_hwcfg_module_is_pbf4(struct grid_sys_model* sys) { switch (grid_sys_get_hwcfg(sys)) { diff --git a/common/src/c/grid_sys.h b/common/src/c/grid_sys.h index ee0c35c9..a49c02e4 100644 --- a/common/src/c/grid_sys.h +++ b/common/src/c/grid_sys.h @@ -99,6 +99,7 @@ int grid_hwcfg_module_is_bu16(struct grid_sys_model* sys); int grid_hwcfg_module_is_ef44(struct grid_sys_model* sys); int grid_hwcfg_module_is_en16(struct grid_sys_model* sys); int grid_hwcfg_module_is_octv(struct grid_sys_model* sys); +int grid_hwcfg_module_is_xy(struct grid_sys_model* sys); int grid_hwcfg_module_is_pbf4(struct grid_sys_model* sys); int grid_hwcfg_module_is_po16(struct grid_sys_model* sys); int grid_hwcfg_module_is_tek2(struct grid_sys_model* sys); diff --git a/esp32s3/components/grid_esp32_module_octv/CMakeLists.txt b/esp32s3/components/grid_esp32_module_octv/CMakeLists.txt index 42756ee5..1ebaf3ab 100644 --- a/esp32s3/components/grid_esp32_module_octv/CMakeLists.txt +++ b/esp32s3/components/grid_esp32_module_octv/CMakeLists.txt @@ -4,5 +4,5 @@ idf_component_register( INCLUDE_DIRS "." REQUIRES - "grid_esp32_adc" "grid_esp32_encoder" "grid_common" "grid_esp32_touch" + "grid_esp32_adc" "grid_esp32_encoder" "grid_common" ) diff --git a/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.c b/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.c index e8f6a455..86421010 100644 --- a/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.c +++ b/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.c @@ -22,20 +22,10 @@ #include "grid_esp32_adc.h" #include "grid_esp32_encoder.h" -#include "grid_esp32_touch.h" - #include "rom/ets_sys.h" // static const char* TAG = "module_octv"; -#define OCTV_I2C_PORT I2C_NUM_0 -#define OCTV_I2C_SCL_GPIO 40 -#define OCTV_I2C_SDA_GPIO 41 -#define OCTV_I2C_FREQ_HZ 100000 - -#define OCTV_SENSOR_RESET_GPIO 39 -#define OCTV_SENSOR_INT_GPIO 42 - #define GRID_MODULE_OCTV_ENC_NUM 8 static struct grid_ui_model* DRAM_ATTR ui_ptr = NULL; @@ -47,15 +37,6 @@ static DRAM_ATTR const uint8_t mux_element_lookup[2][8] = { }; #undef X -void grid_esp32_module_octv_poll_touch(void) { - TOUCHINFO ti = {}; - int rc = grid_esp32_touch_get_samples(&grid_esp32_touch_state, &ti); - ets_printf("touch rc=%d count=%d\r\n", rc, ti.count); - for (int i = 0; i < ti.count; i++) { - ets_printf(" [%d] x=%d y=%d area=%d\r\n", i, ti.x[i], ti.y[i], ti.area[i]); - } -} - void IRAM_ATTR octv_process_analog(struct grid_adc_result* result) { assert(result); @@ -88,8 +69,6 @@ void IRAM_ATTR octv_process_encoder(struct grid_encoder_result* result) { void grid_esp32_module_octv_init(struct grid_sys_model* sys, struct grid_ui_model* ui, struct grid_esp32_adc_model* adc, struct grid_esp32_encoder_model* enc, struct grid_config_model* conf, struct grid_cal_model* cal) { - grid_esp32_touch_init(&grid_esp32_touch_state, OCTV_I2C_PORT, OCTV_I2C_SCL_GPIO, OCTV_I2C_SDA_GPIO, OCTV_SENSOR_RESET_GPIO, OCTV_SENSOR_INT_GPIO, OCTV_I2C_FREQ_HZ, NULL); - ui_ptr = ui; uint8_t detent = grid_hwcfg_module_encoder_is_detent(sys); diff --git a/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.h b/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.h index 5eb23547..e9df2b40 100644 --- a/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.h +++ b/esp32s3/components/grid_esp32_module_octv/grid_esp32_module_octv.h @@ -19,7 +19,6 @@ extern "C" { void grid_esp32_module_octv_init(struct grid_sys_model* sys, struct grid_ui_model* ui, struct grid_esp32_adc_model* adc, struct grid_esp32_encoder_model* enc, struct grid_config_model* conf, struct grid_cal_model* cal); -void grid_esp32_module_octv_poll_touch(void); #ifdef __cplusplus } diff --git a/esp32s3/components/grid_esp32_module_xy/CMakeLists.txt b/esp32s3/components/grid_esp32_module_xy/CMakeLists.txt new file mode 100644 index 00000000..990e7e28 --- /dev/null +++ b/esp32s3/components/grid_esp32_module_xy/CMakeLists.txt @@ -0,0 +1,8 @@ +idf_component_register( + SRCS + "grid_esp32_module_xy.c" + INCLUDE_DIRS + "." + REQUIRES + "grid_common" "grid_esp32_touch" +) diff --git a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c new file mode 100644 index 00000000..84b42a52 --- /dev/null +++ b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c @@ -0,0 +1,41 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "grid_esp32_module_xy.h" + +#include + +#include "grid_sys.h" +#include "grid_ui.h" + +#include "grid_esp32_touch.h" + +#include "rom/ets_sys.h" + +#define XY_I2C_PORT I2C_NUM_0 +#define XY_I2C_SCL_GPIO 40 +#define XY_I2C_SDA_GPIO 41 +#define XY_I2C_FREQ_HZ 100000 + +#define XY_SENSOR_RESET_GPIO 39 +#define XY_SENSOR_INT_GPIO 42 + +void grid_esp32_module_xy_poll_touch(void) { + TOUCHINFO ti = {}; + int rc = grid_esp32_touch_get_samples(&grid_esp32_touch_state, &ti); + ets_printf("touch rc=%d count=%d\r\n", rc, ti.count); + for (int i = 0; i < ti.count; i++) { + ets_printf(" [%d] x=%d y=%d area=%d\r\n", i, ti.x[i], ti.y[i], ti.area[i]); + } +} + +void grid_esp32_module_xy_init(struct grid_sys_model* sys, struct grid_ui_model* ui) { + + grid_esp32_touch_init(&grid_esp32_touch_state, XY_I2C_PORT, XY_I2C_SCL_GPIO, XY_I2C_SDA_GPIO, XY_SENSOR_RESET_GPIO, XY_SENSOR_INT_GPIO, XY_I2C_FREQ_HZ, NULL); + + grid_ui_bulk_start_with_state(ui, grid_ui_bulk_conf_read, 0, 0, NULL); + grid_ui_bulk_flush(ui); +} diff --git a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h new file mode 100644 index 00000000..798355d9 --- /dev/null +++ b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "grid_sys.h" +#include "grid_ui.h" + +void grid_esp32_module_xy_init(struct grid_sys_model* sys, struct grid_ui_model* ui); +void grid_esp32_module_xy_poll_touch(void); + +#ifdef __cplusplus +} +#endif diff --git a/esp32s3/components/grid_esp32_port/grid_esp32_port.c b/esp32s3/components/grid_esp32_port/grid_esp32_port.c index eadd956a..c776eaf6 100644 --- a/esp32s3/components/grid_esp32_port/grid_esp32_port.c +++ b/esp32s3/components/grid_esp32_port/grid_esp32_port.c @@ -462,8 +462,7 @@ void grid_esp32_port_task(void* arg) { } // Rolling ID watchdog expiration (only if RP2040 was ever seen) - if (rp2040_active && - grid_platform_rtc_get_elapsed_time(watchdog_rollid_last_time) > 100000) { + if (rp2040_active && grid_platform_rtc_get_elapsed_time(watchdog_rollid_last_time) > 100000) { watchdog_rollid_last_time = grid_platform_rtc_get_micros(); } diff --git a/esp32s3/components/grid_esp32_touch/CMakeLists.txt b/esp32s3/components/grid_esp32_touch/CMakeLists.txt new file mode 100644 index 00000000..885c0547 --- /dev/null +++ b/esp32s3/components/grid_esp32_touch/CMakeLists.txt @@ -0,0 +1,9 @@ +idf_component_register( + SRCS + "grid_esp32_touch.cpp" + "bb_captouch.cpp" + INCLUDE_DIRS + "." + REQUIRES + "driver" "esp_driver_gpio" "freertos" +) diff --git a/esp32s3/components/grid_esp32_touch/bb_captouch.cpp b/esp32s3/components/grid_esp32_touch/bb_captouch.cpp new file mode 100644 index 00000000..7267b429 --- /dev/null +++ b/esp32s3/components/grid_esp32_touch/bb_captouch.cpp @@ -0,0 +1,882 @@ +// +// BitBank Capactive Touch Sensor Library +// Written by Larry Bank +// +// Copyright 2023 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== +#include "bb_captouch.h" +#ifndef ARDUINO +#include "rom/ets_sys.h" +#endif + +static const BBCT_CONFIG _configs[] = { + // sda, scl, irq, rst + {21, 22, 7, 23}, // TOUCH_T_QT_C6 + {19, 20, -1, 38}, // TOUCH_CYD_550 + {5, 6, 7, 13}, // T-Display S3 Pro + {15, 20, 11, 16}, // T-Display-S3-Long + {21, 22, -1, -1}, // CYD_22C + {33, 32, 21, 25}, // CYD_24C + {4, 5, 0, 1}, // CYD_128 + {33, 32, 21, 25}, // CYD_35C + {7, 8, 41, 40}, // CYD_518 + {8, 4, 3, -1}, // CYD_543 + {21, 22, 39, -1}, // M5_CORE2 + {12, 11, -1, -1}, // M5_CORES3 + {21, 22, 36, -1}, // M5_PAPER + {6, 5 ,7, -1}, // WT32_SC01_PLUS + {17, 18, -1, 38}, // MakerFabs 4" 480x480 + {38,39,40,-1}, // MakerFabs 3.5" 320x480 + {7, 6, 9, 8}, // TOUCH_T_DISPLAY_S3_AMOLED (1.64") + {15, 14, 21, -1}, // TOUCH_WS_AMOLED_18 (Waveshare 1.8" 368x448 AMOLED) + {41, 42, 48, -1}, // TOUCH_M5_PAPERS3 + {11, 10, 4, -1}, // TOUCH_WS_ROUND_146 + {47,48,-1,3}, // TOUCH_WS_AMOLED_241 + {11,10,14,13}, // TOUCH_WS_LCD_169 + {1,3,4,2}, // TOUCH_VIEWE_2432 + {7, 6, 9, 8}, // TOUCH_T_DISPLAY_S3_AMOLED_164 + {0,0,0,0} + }; + +#ifndef ARDUINO +void BBCapTouch::pinMode(uint8_t u8Pin, uint8_t u8Mode) +{ + gpio_config_t io_conf = {}; + + io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt + //bit mask of the pins that you want to set,e.g.GPIO18/19 + io_conf.pin_bit_mask = (1 << u8Pin); + io_conf.pull_down_en = (gpio_pulldown_t)0; //disable pull-down mode + io_conf.pull_up_en = (gpio_pullup_t)0; //disable pull-up mode + if (u8Mode == INPUT) { + io_conf.mode = GPIO_MODE_INPUT; + } else { // must be output + io_conf.mode = GPIO_MODE_OUTPUT; + } + gpio_config(&io_conf); //configure GPIO with the given settings +} /* pinMode() */ +void BBCapTouch::digitalWrite(uint8_t u8Pin, uint8_t u8State) +{ + gpio_set_level((gpio_num_t)u8Pin, u8State); +} /* digitalWrite() */ +#endif // !ARDUINO +void BBCapTouch::reset(int iRST) +{ + pinMode(iRST, OUTPUT); + digitalWrite(iRST, LOW); + delay(100); + digitalWrite(iRST, HIGH); + delay(250); +} /* reset() */ + +// +// Initalize the MXT144 - an overly complicated mess of a touch sensor +// +int BBCapTouch::initMXT(void) +{ +uint8_t ucTemp[32]; +int i, iObjCount, iReportID; +uint16_t u16, u16Offset; + +// Read information block (first 7 bytes of address space) + I2CReadRegister16(_iAddr, 0, ucTemp, 7); + iObjCount = ucTemp[6]; + if (iObjCount < 1 || iObjCount >64) { // invalid number of items + return CT_ERROR; + } + u16Offset = 7; // starting offset of first object + // Read the objects one by one to get the memory offests to the info we will need + iReportID = 1; + // Serial.printf("object count = %d\n", iObjCount); + for (i=0; ibegin(iSDA, iSCL); // this is specific to ESP32 MCUs + myWire->setClock(u32Speed); + myWire->setTimeout(1000); +#else + i2c_config_t conf = {}; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = (gpio_num_t)iSDA; + conf.scl_io_num = (gpio_num_t)iSCL; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = u32Speed; + i2c_driver_delete(I2C_NUM_0); // remove driver (if installed) + i2c_param_config(I2C_NUM_0, &conf); // configure I2C device 0 + i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0); // configure with no send or receive buffers +#endif + _iType = CT_TYPE_UNKNOWN; + + if (iRST != -1) { + reset(iRST); + } + +#ifdef FUTURE + if (I2CTest(AXS15231_ADDR)) { + _iType = CT_TYPE_AXS15231; + _iAddr = AXS15231_ADDR; + if (iRST != -1) { + reset(iRST); + } + return CT_SUCCESS; + } // AXS15231 +#endif + + if (I2CTest(SPD2010_ADDR)) { + _iType = CT_TYPE_SPD2010; + _iAddr = SPD2010_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT_PULLUP); + } + return CT_SUCCESS; + } + if (I2CTest(TMA445_ADDR)) { + _iType = CT_TYPE_TMA445; + _iAddr = TMA445_ADDR; +// if (iINT != -1) { +// pinMode(iINT, INPUT_PULLUP); +// } + // send soft reset + ucTemp[0] = 0; + ucTemp[1] = 1; + I2CWrite(_iAddr, ucTemp, 2); + delay(50); + // send security key + I2CWrite(_iAddr, tma445_key, sizeof(tma445_key)); + delay(88); + + uint8_t tries = 0; + cyttsp_bootloader_data bl_data = {}; + do { + delay(20); + I2CRead(_iAddr, (uint8_t *)&bl_data, sizeof(bl_data)); + } while (bl_data.bl_status & 0x10 && tries++ < 10); // while bootloader mode + if (tries >= 10) ets_printf("bootloader mode timed out\r\n"); + // set OP mode + ucTemp[0] = 0; + ucTemp[1] = 0; // start op mode + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + if (I2CTest(MXT144_ADDR)) { + _iType = CT_TYPE_MXT144; + _iAddr = MXT144_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT); + } + if (iRST != -1) { + reset(iRST); + } + return initMXT(); + } + if (I2CTest(CHSC6540_ADDR)) { + _iType = CT_TYPE_CHSC6540; + _iAddr = CHSC6540_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT); + } + ucTemp[0] = ucTemp[1] = 0x5a; // set interrupt mode + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + if (I2CTest(CST226_ADDR)) { + _iType = CT_TYPE_CST226; + _iAddr = CST226_ADDR; + if (iINT != -1) { + pinMode(iINT, INPUT); + } + return CT_SUCCESS; + } + if (I2CTest(GT911_ADDR1) || I2CTest(GT911_ADDR2)) { + _iType = CT_TYPE_GT911; + } + if (_iType == CT_TYPE_GT911) { // reset the sensor to start it + pinMode(iRST, OUTPUT); + pinMode(iINT, OUTPUT); + digitalWrite(iINT, LOW); + digitalWrite(iRST, LOW); + delay(5); + digitalWrite(iINT, LOW); // set I2C addr to ADDR1 + delay(1); + digitalWrite(iRST, HIGH); // when it comes out of reset, it samples INT + delay(10); + digitalWrite(iINT, LOW); + delay(50); + pinMode(iINT, INPUT); + // double check the I2C addr in case it changed + if (I2CTest(GT911_ADDR1)) { + _iAddr = GT911_ADDR1; + } else if (I2CTest(GT911_ADDR2)) { + _iAddr = GT911_ADDR2; + } + } else if (I2CTest(FT6X36_ADDR1)) { + _iType = CT_TYPE_FT6X36; + _iAddr = FT6X36_ADDR1; + } else if (I2CTest(FT6X36_ADDR2)) { + _iType = CT_TYPE_FT6X36; + _iAddr = FT6X36_ADDR2; + } else if (I2CTest(CST820_ADDR)) { + _iType = CT_TYPE_CST820; + _iAddr = CST820_ADDR; + if (iRST != -1) { + reset(iRST); + } + } else { +#ifdef ARDUINO + myWire->end(); +#else + i2c_driver_delete(I2C_NUM_0); +#endif + return CT_ERROR; // no device found + } + return CT_SUCCESS; +} /* init() */ + +// Initialize the touch controller from a pre-defined configuration name +#ifdef ARDUINO +int BBCapTouch::init(int iConfigName) +{ +const BBCT_CONFIG *pC = &_configs[iConfigName]; + + if (iConfigName < 0 || iConfigName >= TOUCH_COUNT) { + return CT_ERROR; + } + + if (iConfigName == TOUCH_WS_AMOLED_241) { // touch is rotated + _iOrientation = 270; + _iWidth = 450; + _iHeight = 600; + + } + if (iConfigName == TOUCH_WS_AMOLED_18 || iConfigName == TOUCH_WS_ROUND_146) { + // need to release the RESET line which is controlled by an + // I/O expander (TCA9554) + uint8_t ucEXIO; + if (iConfigName == TOUCH_WS_AMOLED_18) ucEXIO = 6; // touch reset (AMOLED 1.8) + else ucEXIO = 1; // touch reset (1.46" round) + Wire.end(); + Wire.begin(pC->i8SDA, pC->i8SCL); + Wire.beginTransmission(0x20); + Wire.write(1); // output port register + Wire.write(~ucEXIO); // set touch controller reset low + Wire.write(0); // polarity inversion all disabled + Wire.write(~7); // enable P0+P1+P2 as an output (connected to RESET) + Wire.endTransmission(); + delay(50); + Wire.beginTransmission(0x20); + Wire.write(1); // output port register + Wire.write(0xff); // set all outputs high (disable resets) + Wire.endTransmission(); + delay(50); + if (iConfigName == TOUCH_WS_AMOLED_18) { + Wire.beginTransmission(0x38); + Wire.write(0xa5); // power mode + Wire.write(0); // active + Wire.endTransmission(); + } + Wire.end(); + } + return init(pC->i8SDA, pC->i8SCL, pC->i8RST, pC->i8IRQ, +#ifdef ARDUINO + 400000, &Wire); +#else + 400000); +#endif +} /* init() */ +#endif // ARDUINO +// +// Test if an I2C device is monitoring an address +// return true if it responds, false if no response +// +bool BBCapTouch::I2CTest(uint8_t u8Addr) +{ + // Check if a device acknowledges the address. +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + return(myWire->endTransmission(true) == 0); +#else // allow 100ms for device to respond + uint8_t c = 0; + return (i2c_master_write_to_device(I2C_NUM_0, u8Addr, &c, 1, 10) == ESP_OK); +#endif +} /* I2CTest() */ +// +// Write I2C data +// quits if a NACK is received and returns 0 +// otherwise returns the number of bytes written +// +int BBCapTouch::I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen) +{ + int rc = 0; + +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + myWire->write(pData, (uint8_t)iLen); + rc = !myWire->endTransmission(); +#else + rc = (i2c_master_write_to_device(I2C_NUM_0, u8Addr, pData, iLen, 100) == ESP_OK); +#endif + return rc; +} /* I2CWrite() */ +// +// Read N bytes starting at a specific 16-bit I2C register +// +int BBCapTouch::I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen) +{ + int i = 0; + +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + if (_iType == CT_TYPE_MXT144) { // little endian + myWire->write((uint8_t)u16Register); // low byte + myWire->write((uint8_t)(u16Register>>8)); // high byte + } else { // big endian address + myWire->write((uint8_t)(u16Register>>8)); // high byte + myWire->write((uint8_t)u16Register); // low byte + } + myWire->endTransmission(); + myWire->requestFrom(u8Addr, (uint8_t)iLen); + while (i < iLen) + { + pData[i++] = myWire->read(); + } +#else + uint8_t ucTemp[4]; + int rc; + if (_iType == CT_TYPE_MXT144) { // little endian + ucTemp[1] = (uint8_t)(u16Register>>8); // high byte + ucTemp[0] = (uint8_t)u16Register; // low byte + } else { + ucTemp[0] = (uint8_t)(u16Register>>8); // high byte + ucTemp[1] = (uint8_t)u16Register; // low byte + } + rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, ucTemp, 2, pData, iLen, 100); + if (rc == ESP_OK) { + i = iLen; + } +#endif + return i; + +} /* I2CReadRegister16() */ +// +// Read N bytes starting at a specific I2C internal register +// returns 1 for success, 0 for error +// +int BBCapTouch::I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen) +{ + int rc; + int i = 0; + +#ifdef ARDUINO + myWire->beginTransmission(u8Addr); + myWire->write(u8Register); + myWire->endTransmission(); + myWire->requestFrom(u8Addr, (uint8_t)iLen); + // i = myWire->readBytes(pData, iLen); + while (myWire->available() && i < iLen) + { + pData[i++] = myWire->read(); + } +#else + rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, &u8Register, 1, pData, iLen, 100); + i = (rc == ESP_OK); +#endif + return i; +} /* I2CReadRegister() */ +// +// Read N bytes +// +int BBCapTouch::I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen) +{ + int i = 0; + +#ifdef ARDUINO + myWire->requestFrom(u8Addr, (uint8_t)iLen); + while (i < iLen) + { + pData[i++] = myWire->read(); + } +#else + int rc; + rc = i2c_master_read_from_device(I2C_NUM_0, u8Addr, pData, iLen, 100); + i = (rc == ESP_OK) ? iLen : 0; +#endif + return i; +} /* I2CRead() */ +// +// Private function to rotate touch samples if the user +// specified a new display orientation +// +void BBCapTouch::fixSamples(TOUCHINFO *pTI) +{ +int i, x, y; + + for (i=0; icount; i++) { + switch (_iOrientation) { + case 90: + x = pTI->y[i]; + y = _iWidth - 1 - pTI->x[i]; + pTI->x[i] = x; + pTI->y[i] = y; + break; + case 180: + pTI->x[i] = _iWidth - 1 - pTI->x[i]; + pTI->y[i] = _iHeight - 1 - pTI->y[i]; + break; + case 270: + x = _iHeight - 1 - pTI->y[i]; + y = pTI->x[i]; + pTI->x[i] = x; + pTI->y[i] = y; + break; + default: // do nothing + break; + } + } +} /* fixSamples() */ +void BBCapTouch::SPD2010ClearInt(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 2; + ucTemp[1] = 0; + ucTemp[2] = 1; + ucTemp[3] = 0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010ClearInt() */ + +void BBCapTouch::SPD2010CPUStart(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 4; + ucTemp[1] = 0; + ucTemp[2] = 1; + ucTemp[3] = 0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010CPUStart() */ + +uint8_t BBCapTouch::SPD2010Status(int *iNextLen) +{ + uint8_t ucTemp[8]; + I2CReadRegister16(_iAddr, 0xfc02, ucTemp, 8); + *iNextLen = (ucTemp[3] << 8) | ucTemp[2]; + return ucTemp[5]; +} /* SPD2010Status() */ + +void BBCapTouch::SPD2010TouchStart(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 0x46; + ucTemp[1] = 0x0; + ucTemp[2] = 0x0; + ucTemp[3] = 0x0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010TouchStart() */ + +void BBCapTouch::SPD2010PointMode(void) +{ + uint8_t ucTemp[4]; + ucTemp[0] = 0x50; + ucTemp[1] = 0x0; + ucTemp[2] = 0x0; + ucTemp[3] = 0x0; + I2CWrite(_iAddr, ucTemp, 4); +} /* SPD2010PointMode() */ + +// +// Read the touch points +// returns 0 (none), 1 if touch points are available +// The point count and info is returned in the TOUCHINFO structure +// +int BBCapTouch::getSamples(TOUCHINFO *pTI) +{ +uint8_t c, *s, ucTemp[32]; +int i, j, rc = 0; + + if (!pTI) + return 0; + pTI->count = 0; + if (_iType == CT_TYPE_UNKNOWN) return 0; // library not initialized? + + if (_iType == CT_TYPE_SPD2010) { + static int iNextLen = 0; + int iReadLen; + uint8_t ucStatus; + // first read the status + I2CReadRegister16(_iAddr, 0x2000, ucTemp, 4); + // Byte 0 has a bit field with the following info: + // 0 = point exists + // 1 = gesture + // 3 = aux, cytang + // Byte 1 + // 3 = cpu run + // 4 = tint low + // 5 = tic in cpu + // 6 = tic in bios + // 7 = tic busy + iReadLen = (ucTemp[3]<<8) + ucTemp[2]; + // Serial.printf("status byte 0: 0x%02x, 0x%02x, read len = %d\n", ucTemp[0], ucTemp[1], iReadLen); + if (ucTemp[1] & 0x40) { // tic in bios + SPD2010ClearInt(); // Write Clear TINT Command + SPD2010CPUStart(); // Write CPU Start Command + } else if (ucTemp[1] & 0x20) { // tic in cpu + SPD2010PointMode(); // Write Touch Change Command + SPD2010TouchStart(); // Write Touch Start Command + SPD2010ClearInt(); + } else if ((ucTemp[1] & 8) && iReadLen == 0) { // cpu run + SPD2010ClearInt(); + } else if (ucTemp[0] & 1 || ucTemp[0] & 2) { // point or gesture + uint8_t ucData[64]; // 4-byte header plus up to 10 fingers of 6 bytes each + I2CReadRegister16(_iAddr, 0x0003, ucData, iReadLen); + // Serial.printf("readlen: %d, data[4]: 0x%02x\n", iReadLen, ucData[4]); + if (ucData[4] <= 0xa && ucTemp[0] & 1) { // check_id < 10 && point exists + rc = 1; // touch event + pTI->count = (iReadLen - 4)/6; // number of touch points + for (int i=0; icount; i++) { + int iOffset = i*6; + pTI->x[i] = ((ucData[7+iOffset] & 0xf0) << 4) | ucData[5+iOffset]; + pTI->y[i] = ((ucData[7+iOffset] & 0x0f) << 8) | ucData[6+iOffset]; + pTI->area[i] = ucData[8+iOffset]; + } + } + // gestures... + hdp_done_check: + /* Read HDP Status */ + ucStatus = SPD2010Status(&iNextLen); +// Serial.printf("status: 0x%02\n", ucStatus); + if (ucStatus == 0x82) { + SPD2010ClearInt(); + } else if (ucStatus == 0x00) { // Read HDP Remain Data + // Read_HDP_REMAIN_DATA(&tp_hdp_status); + goto hdp_done_check; + } + } else if (ucTemp[1] & 8 && ucTemp[0] & 8) { // cpu run && aux + SPD2010ClearInt(); + } + return rc; + } + if (_iType == CT_TYPE_TMA445) { + uint8_t hst_mode; + I2CReadRegister(_iAddr, 0, ucTemp, 14); // read up to 2 touch points + pTI->count = ucTemp[2]; // touch point count + if (pTI->count > 0) { + pTI->y[0] = (ucTemp[5]*256) + ucTemp[6]; + pTI->x[0] = (ucTemp[3]*256) + ucTemp[4]; + pTI->area[0] = ucTemp[7]; + if (pTI->count == 2) { // get second touch point + pTI->y[1] = (ucTemp[11]*256) + ucTemp[12]; + pTI->x[1] = (ucTemp[9]*256) + ucTemp[10]; + pTI->area[1] = ucTemp[13]; + } + // do handshake + I2CReadRegister(_iAddr, 0, &hst_mode, 1); + hst_mode ^= CY_HNDSHK_BIT; // toggle handshake bit + ucTemp[0] = 0; + ucTemp[1] = hst_mode; // send it back + I2CWrite(_iAddr, ucTemp, 2); + return 1; + } + return 0; + } + if (_iType == CT_TYPE_MXT144) { + if (!_mxtdata.t44_message_count_address) { + return 0; // No message offset, so we can't read anything :( + } + I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, ucTemp, 1); + j = ucTemp[0]; // object count + // As each message is read from the sensor, the internal count + // is decremented. It appears that it can hold 6 messages maximum + // before you must read them to receive more. + for (i = 0; i < j; i++) { // read the messages + I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, ucTemp, MXT_MESSAGE_SIZE); // each message is 6 bytes + // check report_id + if (ucTemp[0] >= _mxtdata.t100_first_report_id + 2 && + ucTemp[0] < _mxtdata.t100_first_report_id + 2 + 5) { + uint8_t finger_idx = ucTemp[0] - _mxtdata.t100_first_report_id - 2; + uint8_t event = ucTemp[1] & 0xf; + if (finger_idx+1 > pTI->count) pTI->count = finger_idx+1; + pTI->x[finger_idx] = ucTemp[2] + (ucTemp[3] << 8); + pTI->y[finger_idx] = ucTemp[4] + (ucTemp[5] << 8); + if (event == 1 || event == 4) { // move/press event + pTI->area[finger_idx] = 50; + } else if (event == 5) { // release + pTI->area[finger_idx] = 0; + } + } // if touch report + } // for each report + return (pTI->count > 0); + } // MXT144 + + if (_iType == CT_TYPE_AXS15231) { + uint8_t ucReadCMD[8] = {0xb5,0xab,0xa5,0x5a,0,0,0,0x8}; + I2CWrite(_iAddr, (uint8_t *)ucReadCMD, 8); + I2CRead(_iAddr, ucTemp, 14); // read up to 2 touch points + c = ucTemp[1]; // number of touch points + if (c == 0 || c > 2 || ucTemp[0] != 0) return 0; + pTI->count = c; + j = 0; // buffer offset + for (i=0; ix[i] = ((ucTemp[j+2] & 0xf) << 8) + ucTemp[j+3]; + pTI->y[i] = ((ucTemp[j+4] & 0xf) << 8) + ucTemp[j+5]; + pTI->area[i] = 1; + j += 6; + } + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } // AXS15231 + + if (_iType == CT_TYPE_CST226) { + i = I2CReadRegister(_iAddr, 0, ucTemp, 28); // read the whole block of regs +// Serial.printf("I2CReadRegister returned %d\n", i); +#ifdef FUTURE + if (ucTemp[0] == 0x83 && ucTemp[1] == 0x17 && ucTemp[5] == 0x80) { + // home button pressed + return 0; + } + if (ucTemp[6] != 0xab) return 0; + if (ucTemp[0] == 0xab) return 0; + if (ucTemp[5] == 0x80) return 0; + c = ucTemp[5] & 0x7f; + if (c > 5 || c == 0) { // invalid point count + ucTemp[0] = 0; + ucTemp[1] = 0xab; + I2CWrite(_iAddr, ucTemp, 2); // reset + return 0; + } +#endif + c = 1; // debug + pTI->count = c; + // Serial.printf("count = %d\n", c); + j = 0; + for (i=0; ix[i] = (uint16_t)((ucTemp[j+1] << 4) | ((ucTemp[j+3] >> 4) & 0xf)); + pTI->y[i] = (uint16_t)((ucTemp[j+2] << 4) | (ucTemp[j+3] & 0xf)); + pTI->pressure[i] = ucTemp[j+4]; + j = (i == 0) ? (j+7) : (j+5); + } + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } + + if (_iType == CT_TYPE_CHSC6540) { + if (digitalRead(_iINT) == LOW) { + I2CReadRegister(_iAddr, 2, ucTemp, 13); // read touch points + if (ucTemp[2] == 1 || ucTemp[2] == 2) { + pTI->count = ucTemp[2]; + pTI->x[0] = ((ucTemp[3] & 0xf) << 8) | ucTemp[4]; + pTI->y[0] = ((ucTemp[5] & 0xf) << 8) | ucTemp[6]; + if (ucTemp[0] == 2) { // second touch point + pTI->x[0] = ((ucTemp[9] & 0xf) << 8) | ucTemp[10]; + pTI->y[0] = ((ucTemp[11] & 0xf) << 8) | ucTemp[12]; + } + return 1; + } + } + return 0; + } + if (_iType == CT_TYPE_CST820) { + I2CReadRegister(_iAddr, CST820_TOUCH_REGS+1, ucTemp, 1); // read touch count + if (ucTemp[0] < 1 || ucTemp[0] > 5) { // something went wrong + return 0; + } + if (ucTemp[0] >= 1) { // touch data available, read it + pTI->count = ucTemp[0]; + I2CReadRegister(_iAddr, CST820_TOUCH_REGS+2, ucTemp, pTI->count * 6); + s = ucTemp; + for (i=0; icount; i++) { + pTI->x[i] = ((s[0] & 0xf) << 8) | s[1]; + pTI->y[i] = ((s[2] & 0xf) << 8) | s[3]; + pTI->area[i] = 1; // no data available + s += 6; + } + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } + } + if (_iType == CT_TYPE_FT6X36) { + rc = I2CReadRegister(_iAddr, TOUCH_REG_STATUS, ucTemp, 1); // read touch status + if (rc == 0) { // something went wrong + return 0; + } + i = ucTemp[0]; // number of touch points available + if (i >= 1 && i <= 5) { // get data + rc = I2CReadRegister(_iAddr, TOUCH_REG_XH, ucTemp, 6*i); // read X+Y position(s) + if ((ucTemp[0] & 0x40) == 0 && (ucTemp[2] & 0xf0) != 0xf0) { // finger is down + pTI->x[0] = ((ucTemp[0] & 0xf) << 8) | ucTemp[1]; + pTI->y[0] = ((ucTemp[2] & 0xf) << 8) | ucTemp[3]; + // get touch pressure and area + pTI->pressure[0] = ucTemp[4]; + pTI->area[0] = ucTemp[5]; + pTI->count++; + } + if (i > 1) { // get second point + if ((ucTemp[6] & 0x40) == 0 && (ucTemp[8] & 0xf0) != 0xf0) { // finger is down + pTI->x[1] = ((ucTemp[6] & 0xf) << 8) | ucTemp[7]; + pTI->y[1] = ((ucTemp[8] & 0xf) << 8) | ucTemp[9]; + // get touch pressure and area + pTI->pressure[1] = ucTemp[10]; + pTI->area[1] = ucTemp[11]; + pTI->count++; + } + } + } // if touch points available + if (_iOrientation != 0) fixSamples(pTI); + return 1; + } else { // GT911 + I2CReadRegister16(_iAddr, GT911_POINT_INFO, ucTemp, 1); // get number of touch points + i = ucTemp[0] & 0xf; // number of touches + if (i <= 5 && ucTemp[0] & 0x80) { // if buffer status is good + >= 1 touch points + ucTemp[0] = (uint8_t)(GT911_POINT_INFO >> 8); + ucTemp[1] = (uint8_t)GT911_POINT_INFO; + ucTemp[2] = 0; // clear touch info for next time + I2CWrite(_iAddr, ucTemp, 3); + + pTI->count = i; + for (int j=0; jx[j] = ucTemp[1] + (ucTemp[2] << 8); + pTI->y[j] = ucTemp[3] + (ucTemp[4] << 8); + pTI->area[j] = ucTemp[5] + (ucTemp[6] << 8); + pTI->pressure[j] = 0; + } + if (i && _iOrientation != 0) fixSamples(pTI); + return (i > 0); + } + } // GT911 + return 0; +} /* getSamples() */ + +int BBCapTouch::setOrientation(int iOrientation, int iWidth, int iHeight) +{ + if (iOrientation != 0 && iOrientation != 90 && iOrientation != 180 && iOrientation != 270) { + return CT_ERROR; + } + _iOrientation = iOrientation; + _iWidth = iWidth; + _iHeight = iHeight; + return CT_SUCCESS; +} /* setOrientation() */ + +int BBCapTouch::sensorType(void) +{ + return _iType; +} /* type() */ + +int BBCapTouch::sleep(void) +{ +uint8_t ucTemp[8]; + + if (_iType == CT_TYPE_AXS15231) { + ucTemp[0] = 0x90; // enter deep sleep + ucTemp[1] = 0xa5; + ucTemp[2] = 0x5a; + ucTemp[3] = 0x15; + ucTemp[4] = 0x23; + I2CWrite(_iAddr, ucTemp, 5); + return CT_SUCCESS; + } + if (_iType == CT_TYPE_GT911 && _iINT != -1) { + pinMode(_iINT, OUTPUT); + digitalWrite(_iINT, 0); // setting interrupt pin low to prepare sleep mode + ucTemp[0] = (uint8_t)(GT911_ENTER_SLEEP >> 8); + ucTemp[1] = (uint8_t)GT911_ENTER_SLEEP; + ucTemp[2] = 0x05; //?? + I2CWrite(_iAddr, ucTemp, 3); // enter sleep mode + return CT_SUCCESS; + } + if (_iType == CT_TYPE_CST226) { + ucTemp[0] = 0xd1; + ucTemp[1] = 0x05; + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + return CT_ERROR; +} /* sleep() */ + +int BBCapTouch::wake(void) +{ +uint8_t ucTemp[4]; + + if (_iType == CT_TYPE_AXS15231) { + digitalWrite(_iRST, 0); + delay(50); + digitalWrite(_iRST, 1); + return CT_SUCCESS; + } + if (_iType == CT_TYPE_GT911 && _iINT != -1) { + digitalWrite(_iINT, 1); // wake up the controller + delay(5); // allow it time to wake + pinMode(_iINT, INPUT); // change pin mode back to floating + } + if (_iType == CT_TYPE_CST226) { + ucTemp[0] = 0xd1; + ucTemp[1] = 0x06; + I2CWrite(_iAddr, ucTemp, 2); + return CT_SUCCESS; + } + return CT_ERROR; +} /* wake() */ + + diff --git a/esp32s3/components/grid_esp32_touch/bb_captouch.h b/esp32s3/components/grid_esp32_touch/bb_captouch.h new file mode 100644 index 00000000..8fa6c0bc --- /dev/null +++ b/esp32s3/components/grid_esp32_touch/bb_captouch.h @@ -0,0 +1,266 @@ +// +// BitBank Capacitive Touch Sensor Library +// written by Larry Bank +// +// Copyright 2023 BitBank Software, Inc. All Rights Reserved. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//=========================================================================== + +// +// Written for the many variants of ESP32 + Capacitive touch LCDs on the market +// +#ifdef ARDUINO +#include +#include +#else +#define INPUT 0 +#define OUTPUT 1 +#define INPUT_PULLUP 2 +#define LOW 0 +#define HIGH 1 +#include "driver/gpio.h" +#include "driver/i2c.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +static inline void delay(uint32_t ms) { vTaskDelay(pdMS_TO_TICKS(ms)); } +static inline int digitalRead(uint8_t pin) { return (int)gpio_get_level((gpio_num_t)pin); } +#endif // ARDUINO + +#ifndef __BB_CAPTOUCH__ +#define __BB_CAPTOUCH__ + +#define CT_SUCCESS 0 +#define CT_ERROR -1 +// +// Pre-configured device names +// Don't change the order of this list! +// the structure values follow it. Always +// add new values to the end +// +enum { + TOUCH_T_QT_C6=0, + TOUCH_CYD_550, + TOUCH_T_DISPLAY_S3_PRO, + TOUCH_T_DISPLAY_S3_LONG, + TOUCH_CYD_22C, + TOUCH_CYD_24C, + TOUCH_CYD_128, + TOUCH_CYD_35C, + TOUCH_CYD_518, + TOUCH_CYD_543, + TOUCH_M5_CORE2, + TOUCH_M5_CORES3, + TOUCH_M5_PAPER, + TOUCH_WT32_SC01_PLUS, + TOUCH_MAKERFABS_480x480, + TOUCH_MAKERFABS_320x480, + TOUCH_T_DISPLAY_S3_AMOLED, + TOUCH_WS_AMOLED_18, + TOUCH_M5_PAPERS3, + TOUCH_WS_ROUND_146, + TOUCH_WS_AMOLED_241, + TOUCH_WS_LCD_169, + TOUCH_VIEWE_2432, + TOUCH_T_DISPLAY_S3_AMOLED_164, + TOUCH_COUNT +}; +// structure holding the configurations +typedef struct bbct_config_tag { + int8_t i8SDA, i8SCL, i8IRQ, i8RST; +} BBCT_CONFIG; + +enum { + CT_TYPE_UNKNOWN = 0, + CT_TYPE_FT6X36, + CT_TYPE_GT911, + CT_TYPE_CST820, + CT_TYPE_CST226, + CT_TYPE_MXT144, + CT_TYPE_AXS15231, + CT_TYPE_TMA445, + CT_TYPE_SPD2010, + CT_TYPE_CHSC6540, + CT_TYPE_COUNT +}; + +#define SPD2010_ADDR 0x53 +#define GT911_ADDR1 0x5D +#define GT911_ADDR2 0x14 +#define FT6X36_ADDR1 0x38 +#define FT6X36_ADDR2 0x48 +#define CST820_ADDR 0x15 +#define CST226_ADDR 0x5A +#define CHSC6540_ADDR 0x2E +#define MXT144_ADDR 0x4A +#define TMA445_ADDR 0x24 +#define AXS15231_ADDR 0x3B + +// CST8xx gestures +enum { + GESTURE_NONE = 0, + GESTURE_SWIPE_UP, + GESTURE_SWIPE_DOWN, + GESTURE_SWIPE_LEFT, + GESTURE_SWIPE_RIGHT, + GESTURE_SINGLE_CLICK, + GESTURE_DOUBLE_CLICK = 0x0B, + GESTURE_LONG_PRESS = 0x0C +}; + +// TMA445 Security KEY +static uint8_t tma445_key[] = {0x00, 0x00, 0xFF, 0xA5, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; + +/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */ +typedef struct cyttsp_xydata_tag { + uint8_t hst_mode; + uint8_t tt_mode; + uint8_t tt_stat; + uint16_t x1 __attribute__ ((packed)); + uint16_t y1 __attribute__ ((packed)); + uint8_t z1; + uint8_t touch12_id; + uint16_t x2 __attribute__ ((packed)); + uint16_t y2 __attribute__ ((packed)); + uint8_t z2; +} cyttsp_xydata; +#define CY_HNDSHK_BIT 0x80 +typedef struct cyttsp_bootloader_data_tag { + uint8_t bl_file; + uint8_t bl_status; + uint8_t bl_error; + uint8_t blver_hi; + uint8_t blver_lo; + uint8_t bld_blver_hi; + uint8_t bld_blver_lo; + uint8_t ttspver_hi; + uint8_t ttspver_lo; + uint8_t appid_hi; + uint8_t appid_lo; + uint8_t appver_hi; + uint8_t appver_lo; + uint8_t cid_0; + uint8_t cid_1; + uint8_t cid_2; +} cyttsp_bootloader_data; + + +typedef struct mxt_data_tag { + uint16_t t2_encryption_status_address; + uint16_t t5_message_processor_address; + uint16_t t5_max_message_size; + uint16_t t6_command_processor_address; + uint16_t t7_powerconfig_address; + uint16_t t8_acquisitionconfig_address; + uint16_t t44_message_count_address; + uint16_t t46_cte_config_address; + uint16_t t100_multiple_touch_touchscreen_address; + uint16_t t100_first_report_id; +} MXTDATA; + +typedef struct mxt_object_tag { + uint8_t type; + uint16_t position; + uint8_t size_minus_one; + uint8_t instances_minus_one; + uint8_t report_ids_per_instance; +} MXTOBJECT; + +#define MXT_MESSAGE_SIZE 6 + +// CST820 registers +#define CST820_TOUCH_REGS 1 + +// GT911 registers +#define GT911_POINT_INFO 0x814E +#define GT911_POINT_1 0x814F +#define GT911_CONFIG_FRESH 0x8100 +#define GT911_CONFIG_SIZE 0xb9 +#define GT911_CONFIG_START 0x8047 +#define GT911_ENTER_SLEEP 0x8040 + +// FT6x36 registers +#define TOUCH_REG_STATUS 0x02 +#define TOUCH_REG_XH 0x03 +#define TOUCH_REG_XL 0x04 +#define TOUCH_REG_YH 0x05 +#define TOUCH_REG_YL 0x06 +#define TOUCH_REG_WEIGHT 0x07 +#define TOUCH_REG_AREA 0x08 +// register offset to info for the second touch point +#define PT2_OFFSET 6 + +#ifndef __TOUCHINFO_STRUCT__ +#define __TOUCHINFO_STRUCT__ + +typedef struct _fttouchinfo +{ + int count; + uint16_t x[5], y[5]; + uint8_t pressure[5], area[5]; +} TOUCHINFO; +#endif + +//extern TwoWire* myWire; + +class BBCapTouch +{ +public: + BBCapTouch() { _iOrientation = 0; _iType = CT_TYPE_UNKNOWN;} +// ~BBCapTouch() { Wire.end(); } +#ifdef ARDUINO + ~BBCapTouch() { myWire->end(); } +#else + ~BBCapTouch() {} +#endif + +#ifdef ARDUINO + int init(int iConfigName); + int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000, TwoWire* _myWire=&Wire); +#else + int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000); +#endif + int getSamples(TOUCHINFO *pTI); + uint8_t interruptPin(void) {return (uint8_t)_iINT;} + int sensorType(void); + int setOrientation(int iOrientation, int iWidth, int iHeight); + int sleep(void); + int wake(void); + +protected: + void reset(int iResetPin); + +private: + int _iAddr; + int _iType; + int _iOrientation, _iWidth, _iHeight; + MXTDATA _mxtdata; + int _iINT; // interrupt GPIO pin needed for sleep/wake of GT911 + int _iRST; // reset GPIO needed for AXS15206 to wake from deep sleep +#ifdef ARDUINO + TwoWire* myWire; +#else + void pinMode(uint8_t u8Pin, uint8_t u8Mode); + void digitalWrite(uint8_t u8Pin, uint8_t u8State); +#endif + int initMXT(void); + void fixSamples(TOUCHINFO *pTI); + bool I2CTest(uint8_t u8Addr); + int I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen); + int I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen); + int I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen); + int I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen); + void SPD2010ClearInt(void); + void SPD2010CPUStart(void); + uint8_t SPD2010Status(int *iNextLen); + void SPD2010TouchStart(void); + void SPD2010PointMode(void); +}; // class BBCapTouch +#endif // __BB_CAPTOUCH__ diff --git a/esp32s3/components/grid_esp32_touch/grid_esp32_touch.cpp b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.cpp new file mode 100644 index 00000000..8cdf76af --- /dev/null +++ b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.cpp @@ -0,0 +1,64 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "grid_esp32_touch.h" +#include "bb_captouch.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" + +#include "rom/ets_sys.h" + +DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; + +static struct grid_esp32_touch_model* touch_ptr = NULL; +static BBCapTouch bbc; + +void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, + grid_process_touch_t process_touch) { + + touch_ptr = touch; + touch->i2c_port = i2c_port; + touch->scl_gpio = scl_gpio; + touch->sda_gpio = sda_gpio; + touch->reset_gpio = reset_gpio; + touch->int_gpio = int_gpio; + touch->i2c_freq_hz = i2c_freq_hz; + touch->process_touch = process_touch; + + int rc = bbc.init(touch->sda_gpio, touch->scl_gpio, touch->reset_gpio, touch->int_gpio, touch->i2c_freq_hz); + if (rc == CT_SUCCESS) { + ets_printf("MXT144 init OK\r\n"); + } else { + ets_printf("MXT144 init FAILED\r\n"); + } +} + +void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch) { + + ets_printf("I2C scan (SCL=GPIO%d SDA=GPIO%d):\r\n", touch->scl_gpio, touch->sda_gpio); + int found = 0; + for (uint8_t addr = 0x08; addr < 0x78; addr++) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(touch->i2c_port, cmd, pdMS_TO_TICKS(10)); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + ets_printf(" found device at 0x%02X\r\n", addr); + found++; + } + } + if (found == 0) { + ets_printf(" no devices found\r\n"); + } +} + +int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI) { + (void)touch; + return bbc.getSamples(pTI); +} diff --git a/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h new file mode 100644 index 00000000..7da47412 --- /dev/null +++ b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h @@ -0,0 +1,53 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ +#pragma once + +#include + +#include "freertos/FreeRTOS.h" +#include "freertos/semphr.h" + +#include "driver/gpio.h" +#include "driver/i2c.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __TOUCHINFO_STRUCT__ +#define __TOUCHINFO_STRUCT__ +typedef struct _fttouchinfo { + int count; // number of pressed keys + uint32_t key_state; // T15 key bitmap (1 bit per key, up to 32 keys) + uint16_t x[5], y[5]; + uint8_t pressure[5], area[5]; +} TOUCHINFO; +#endif + +typedef void (*grid_process_touch_t)(void); + +struct grid_esp32_touch_model { + i2c_port_t i2c_port; + gpio_num_t scl_gpio; + gpio_num_t sda_gpio; + gpio_num_t reset_gpio; + gpio_num_t int_gpio; + uint32_t i2c_freq_hz; + grid_process_touch_t process_touch; +}; + +extern struct grid_esp32_touch_model grid_esp32_touch_state; + +void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, + grid_process_touch_t process_touch); + +void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch); + +int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI); + +#ifdef __cplusplus +} +#endif diff --git a/esp32s3/main/grid_esp32s3.c b/esp32s3/main/grid_esp32s3.c index 8171c28e..397a8778 100644 --- a/esp32s3/main/grid_esp32s3.c +++ b/esp32s3/main/grid_esp32s3.c @@ -48,6 +48,7 @@ #include "grid_esp32_module_pbf4.h" #include "grid_esp32_module_po16.h" #include "grid_esp32_module_vsnx.h" +#include "grid_esp32_module_xy.h" #include "pico_firmware.h" #include "grid_esp32_trace.h" @@ -445,6 +446,8 @@ void app_main(void) { grid_module_ef44_ui_init(&grid_ain_state, &grid_led_state, &grid_ui_state); } else if (grid_hwcfg_module_is_octv(&grid_sys_state)) { grid_module_octv_ui_init(&grid_ain_state, &grid_led_state, &grid_ui_state); + } else if (grid_hwcfg_module_is_xy(&grid_sys_state)) { + grid_module_xy_ui_init(&grid_ain_state, &grid_led_state, &grid_ui_state); } else if (grid_hwcfg_module_is_tek2(&grid_sys_state) || grid_hwcfg_module_is_vsnx(&grid_sys_state)) { grid_module_vsnx_ui_init(&grid_ain_state, &grid_led_state, &grid_ui_state, &grid_sys_state); } else { @@ -558,6 +561,8 @@ void app_main(void) { grid_esp32_module_ef44_init(&grid_sys_state, &grid_ui_state, &grid_esp32_adc_state, &grid_esp32_encoder_state, &grid_config_state, &grid_cal_state); } else if (grid_hwcfg_module_is_octv(&grid_sys_state)) { grid_esp32_module_octv_init(&grid_sys_state, &grid_ui_state, &grid_esp32_adc_state, &grid_esp32_encoder_state, &grid_config_state, &grid_cal_state); + } else if (grid_hwcfg_module_is_xy(&grid_sys_state)) { + grid_esp32_module_xy_init(&grid_sys_state, &grid_ui_state); } else if (grid_hwcfg_module_is_tek2(&grid_sys_state) || grid_hwcfg_module_is_vsnx(&grid_sys_state)) { grid_esp32_module_vsnx_init(&grid_sys_state, &grid_ui_state, &grid_esp32_adc_state, &grid_config_state, &grid_cal_state, grid_esp32_lcd_states); } else { @@ -619,9 +624,8 @@ void app_main(void) { vmp_flushed = true; } - // Poll touch sensor if OCTV module - if (grid_hwcfg_module_is_octv(&grid_sys_state)) { - grid_esp32_module_octv_poll_touch(); + if (grid_hwcfg_module_is_xy(&grid_sys_state)) { + grid_esp32_module_xy_poll_touch(); } // Run microtasks From 8dc9d49e0c6a28b0149dc485050ae358e1618cb8 Mon Sep 17 00:00:00 2001 From: sukuwc Date: Tue, 5 May 2026 10:57:17 +0200 Subject: [PATCH 5/9] XY module: replace bb_captouch with native MXT object-protocol driver Replaces the FocalTech-protocol bb_captouch library with a native Microchip MXT object-table driver (T5/T44/T100). Touch reading is interrupt-driven via a volatile pending flag set in the CHG ISR and serviced in the main loop. OCTV no longer owns the touch component. Co-Authored-By: Claude Sonnet 4.6 --- .../grid_esp32_module_xy.c | 10 +- .../grid_esp32_module_xy.h | 2 +- .../grid_esp32_touch/CMakeLists.txt | 3 +- .../grid_esp32_touch/bb_captouch.cpp | 882 ------------------ .../components/grid_esp32_touch/bb_captouch.h | 266 ------ .../grid_esp32_touch/grid_esp32_touch.c | 250 +++++ .../grid_esp32_touch/grid_esp32_touch.cpp | 64 -- .../grid_esp32_touch/grid_esp32_touch.h | 8 + esp32s3/main/grid_esp32s3.c | 5 +- 9 files changed, 269 insertions(+), 1221 deletions(-) delete mode 100644 esp32s3/components/grid_esp32_touch/bb_captouch.cpp delete mode 100644 esp32s3/components/grid_esp32_touch/bb_captouch.h create mode 100644 esp32s3/components/grid_esp32_touch/grid_esp32_touch.c delete mode 100644 esp32s3/components/grid_esp32_touch/grid_esp32_touch.cpp diff --git a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c index 84b42a52..582e8d7d 100644 --- a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c +++ b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c @@ -23,12 +23,14 @@ #define XY_SENSOR_RESET_GPIO 39 #define XY_SENSOR_INT_GPIO 42 -void grid_esp32_module_xy_poll_touch(void) { +void grid_esp32_module_xy_handle_touch(void) { TOUCHINFO ti = {}; int rc = grid_esp32_touch_get_samples(&grid_esp32_touch_state, &ti); - ets_printf("touch rc=%d count=%d\r\n", rc, ti.count); - for (int i = 0; i < ti.count; i++) { - ets_printf(" [%d] x=%d y=%d area=%d\r\n", i, ti.x[i], ti.y[i], ti.area[i]); + if (rc) { + ets_printf("touch count=%d\r\n", ti.count); + for (int i = 0; i < ti.count; i++) { + ets_printf(" [%d] x=%d y=%d area=%d\r\n", i, ti.x[i], ti.y[i], ti.area[i]); + } } } diff --git a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h index 798355d9..6fc056ed 100644 --- a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h +++ b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.h @@ -13,7 +13,7 @@ extern "C" { #include "grid_ui.h" void grid_esp32_module_xy_init(struct grid_sys_model* sys, struct grid_ui_model* ui); -void grid_esp32_module_xy_poll_touch(void); +void grid_esp32_module_xy_handle_touch(void); #ifdef __cplusplus } diff --git a/esp32s3/components/grid_esp32_touch/CMakeLists.txt b/esp32s3/components/grid_esp32_touch/CMakeLists.txt index 885c0547..8d7aa5aa 100644 --- a/esp32s3/components/grid_esp32_touch/CMakeLists.txt +++ b/esp32s3/components/grid_esp32_touch/CMakeLists.txt @@ -1,7 +1,6 @@ idf_component_register( SRCS - "grid_esp32_touch.cpp" - "bb_captouch.cpp" + "grid_esp32_touch.c" INCLUDE_DIRS "." REQUIRES diff --git a/esp32s3/components/grid_esp32_touch/bb_captouch.cpp b/esp32s3/components/grid_esp32_touch/bb_captouch.cpp deleted file mode 100644 index 7267b429..00000000 --- a/esp32s3/components/grid_esp32_touch/bb_captouch.cpp +++ /dev/null @@ -1,882 +0,0 @@ -// -// BitBank Capactive Touch Sensor Library -// Written by Larry Bank -// -// Copyright 2023 BitBank Software, Inc. All Rights Reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//=========================================================================== -#include "bb_captouch.h" -#ifndef ARDUINO -#include "rom/ets_sys.h" -#endif - -static const BBCT_CONFIG _configs[] = { - // sda, scl, irq, rst - {21, 22, 7, 23}, // TOUCH_T_QT_C6 - {19, 20, -1, 38}, // TOUCH_CYD_550 - {5, 6, 7, 13}, // T-Display S3 Pro - {15, 20, 11, 16}, // T-Display-S3-Long - {21, 22, -1, -1}, // CYD_22C - {33, 32, 21, 25}, // CYD_24C - {4, 5, 0, 1}, // CYD_128 - {33, 32, 21, 25}, // CYD_35C - {7, 8, 41, 40}, // CYD_518 - {8, 4, 3, -1}, // CYD_543 - {21, 22, 39, -1}, // M5_CORE2 - {12, 11, -1, -1}, // M5_CORES3 - {21, 22, 36, -1}, // M5_PAPER - {6, 5 ,7, -1}, // WT32_SC01_PLUS - {17, 18, -1, 38}, // MakerFabs 4" 480x480 - {38,39,40,-1}, // MakerFabs 3.5" 320x480 - {7, 6, 9, 8}, // TOUCH_T_DISPLAY_S3_AMOLED (1.64") - {15, 14, 21, -1}, // TOUCH_WS_AMOLED_18 (Waveshare 1.8" 368x448 AMOLED) - {41, 42, 48, -1}, // TOUCH_M5_PAPERS3 - {11, 10, 4, -1}, // TOUCH_WS_ROUND_146 - {47,48,-1,3}, // TOUCH_WS_AMOLED_241 - {11,10,14,13}, // TOUCH_WS_LCD_169 - {1,3,4,2}, // TOUCH_VIEWE_2432 - {7, 6, 9, 8}, // TOUCH_T_DISPLAY_S3_AMOLED_164 - {0,0,0,0} - }; - -#ifndef ARDUINO -void BBCapTouch::pinMode(uint8_t u8Pin, uint8_t u8Mode) -{ - gpio_config_t io_conf = {}; - - io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt - //bit mask of the pins that you want to set,e.g.GPIO18/19 - io_conf.pin_bit_mask = (1 << u8Pin); - io_conf.pull_down_en = (gpio_pulldown_t)0; //disable pull-down mode - io_conf.pull_up_en = (gpio_pullup_t)0; //disable pull-up mode - if (u8Mode == INPUT) { - io_conf.mode = GPIO_MODE_INPUT; - } else { // must be output - io_conf.mode = GPIO_MODE_OUTPUT; - } - gpio_config(&io_conf); //configure GPIO with the given settings -} /* pinMode() */ -void BBCapTouch::digitalWrite(uint8_t u8Pin, uint8_t u8State) -{ - gpio_set_level((gpio_num_t)u8Pin, u8State); -} /* digitalWrite() */ -#endif // !ARDUINO -void BBCapTouch::reset(int iRST) -{ - pinMode(iRST, OUTPUT); - digitalWrite(iRST, LOW); - delay(100); - digitalWrite(iRST, HIGH); - delay(250); -} /* reset() */ - -// -// Initalize the MXT144 - an overly complicated mess of a touch sensor -// -int BBCapTouch::initMXT(void) -{ -uint8_t ucTemp[32]; -int i, iObjCount, iReportID; -uint16_t u16, u16Offset; - -// Read information block (first 7 bytes of address space) - I2CReadRegister16(_iAddr, 0, ucTemp, 7); - iObjCount = ucTemp[6]; - if (iObjCount < 1 || iObjCount >64) { // invalid number of items - return CT_ERROR; - } - u16Offset = 7; // starting offset of first object - // Read the objects one by one to get the memory offests to the info we will need - iReportID = 1; - // Serial.printf("object count = %d\n", iObjCount); - for (i=0; ibegin(iSDA, iSCL); // this is specific to ESP32 MCUs - myWire->setClock(u32Speed); - myWire->setTimeout(1000); -#else - i2c_config_t conf = {}; - conf.mode = I2C_MODE_MASTER; - conf.sda_io_num = (gpio_num_t)iSDA; - conf.scl_io_num = (gpio_num_t)iSCL; - conf.sda_pullup_en = GPIO_PULLUP_ENABLE; - conf.scl_pullup_en = GPIO_PULLUP_ENABLE; - conf.master.clk_speed = u32Speed; - i2c_driver_delete(I2C_NUM_0); // remove driver (if installed) - i2c_param_config(I2C_NUM_0, &conf); // configure I2C device 0 - i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0); // configure with no send or receive buffers -#endif - _iType = CT_TYPE_UNKNOWN; - - if (iRST != -1) { - reset(iRST); - } - -#ifdef FUTURE - if (I2CTest(AXS15231_ADDR)) { - _iType = CT_TYPE_AXS15231; - _iAddr = AXS15231_ADDR; - if (iRST != -1) { - reset(iRST); - } - return CT_SUCCESS; - } // AXS15231 -#endif - - if (I2CTest(SPD2010_ADDR)) { - _iType = CT_TYPE_SPD2010; - _iAddr = SPD2010_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT_PULLUP); - } - return CT_SUCCESS; - } - if (I2CTest(TMA445_ADDR)) { - _iType = CT_TYPE_TMA445; - _iAddr = TMA445_ADDR; -// if (iINT != -1) { -// pinMode(iINT, INPUT_PULLUP); -// } - // send soft reset - ucTemp[0] = 0; - ucTemp[1] = 1; - I2CWrite(_iAddr, ucTemp, 2); - delay(50); - // send security key - I2CWrite(_iAddr, tma445_key, sizeof(tma445_key)); - delay(88); - - uint8_t tries = 0; - cyttsp_bootloader_data bl_data = {}; - do { - delay(20); - I2CRead(_iAddr, (uint8_t *)&bl_data, sizeof(bl_data)); - } while (bl_data.bl_status & 0x10 && tries++ < 10); // while bootloader mode - if (tries >= 10) ets_printf("bootloader mode timed out\r\n"); - // set OP mode - ucTemp[0] = 0; - ucTemp[1] = 0; // start op mode - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - if (I2CTest(MXT144_ADDR)) { - _iType = CT_TYPE_MXT144; - _iAddr = MXT144_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT); - } - if (iRST != -1) { - reset(iRST); - } - return initMXT(); - } - if (I2CTest(CHSC6540_ADDR)) { - _iType = CT_TYPE_CHSC6540; - _iAddr = CHSC6540_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT); - } - ucTemp[0] = ucTemp[1] = 0x5a; // set interrupt mode - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - if (I2CTest(CST226_ADDR)) { - _iType = CT_TYPE_CST226; - _iAddr = CST226_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT); - } - return CT_SUCCESS; - } - if (I2CTest(GT911_ADDR1) || I2CTest(GT911_ADDR2)) { - _iType = CT_TYPE_GT911; - } - if (_iType == CT_TYPE_GT911) { // reset the sensor to start it - pinMode(iRST, OUTPUT); - pinMode(iINT, OUTPUT); - digitalWrite(iINT, LOW); - digitalWrite(iRST, LOW); - delay(5); - digitalWrite(iINT, LOW); // set I2C addr to ADDR1 - delay(1); - digitalWrite(iRST, HIGH); // when it comes out of reset, it samples INT - delay(10); - digitalWrite(iINT, LOW); - delay(50); - pinMode(iINT, INPUT); - // double check the I2C addr in case it changed - if (I2CTest(GT911_ADDR1)) { - _iAddr = GT911_ADDR1; - } else if (I2CTest(GT911_ADDR2)) { - _iAddr = GT911_ADDR2; - } - } else if (I2CTest(FT6X36_ADDR1)) { - _iType = CT_TYPE_FT6X36; - _iAddr = FT6X36_ADDR1; - } else if (I2CTest(FT6X36_ADDR2)) { - _iType = CT_TYPE_FT6X36; - _iAddr = FT6X36_ADDR2; - } else if (I2CTest(CST820_ADDR)) { - _iType = CT_TYPE_CST820; - _iAddr = CST820_ADDR; - if (iRST != -1) { - reset(iRST); - } - } else { -#ifdef ARDUINO - myWire->end(); -#else - i2c_driver_delete(I2C_NUM_0); -#endif - return CT_ERROR; // no device found - } - return CT_SUCCESS; -} /* init() */ - -// Initialize the touch controller from a pre-defined configuration name -#ifdef ARDUINO -int BBCapTouch::init(int iConfigName) -{ -const BBCT_CONFIG *pC = &_configs[iConfigName]; - - if (iConfigName < 0 || iConfigName >= TOUCH_COUNT) { - return CT_ERROR; - } - - if (iConfigName == TOUCH_WS_AMOLED_241) { // touch is rotated - _iOrientation = 270; - _iWidth = 450; - _iHeight = 600; - - } - if (iConfigName == TOUCH_WS_AMOLED_18 || iConfigName == TOUCH_WS_ROUND_146) { - // need to release the RESET line which is controlled by an - // I/O expander (TCA9554) - uint8_t ucEXIO; - if (iConfigName == TOUCH_WS_AMOLED_18) ucEXIO = 6; // touch reset (AMOLED 1.8) - else ucEXIO = 1; // touch reset (1.46" round) - Wire.end(); - Wire.begin(pC->i8SDA, pC->i8SCL); - Wire.beginTransmission(0x20); - Wire.write(1); // output port register - Wire.write(~ucEXIO); // set touch controller reset low - Wire.write(0); // polarity inversion all disabled - Wire.write(~7); // enable P0+P1+P2 as an output (connected to RESET) - Wire.endTransmission(); - delay(50); - Wire.beginTransmission(0x20); - Wire.write(1); // output port register - Wire.write(0xff); // set all outputs high (disable resets) - Wire.endTransmission(); - delay(50); - if (iConfigName == TOUCH_WS_AMOLED_18) { - Wire.beginTransmission(0x38); - Wire.write(0xa5); // power mode - Wire.write(0); // active - Wire.endTransmission(); - } - Wire.end(); - } - return init(pC->i8SDA, pC->i8SCL, pC->i8RST, pC->i8IRQ, -#ifdef ARDUINO - 400000, &Wire); -#else - 400000); -#endif -} /* init() */ -#endif // ARDUINO -// -// Test if an I2C device is monitoring an address -// return true if it responds, false if no response -// -bool BBCapTouch::I2CTest(uint8_t u8Addr) -{ - // Check if a device acknowledges the address. -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - return(myWire->endTransmission(true) == 0); -#else // allow 100ms for device to respond - uint8_t c = 0; - return (i2c_master_write_to_device(I2C_NUM_0, u8Addr, &c, 1, 10) == ESP_OK); -#endif -} /* I2CTest() */ -// -// Write I2C data -// quits if a NACK is received and returns 0 -// otherwise returns the number of bytes written -// -int BBCapTouch::I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen) -{ - int rc = 0; - -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - myWire->write(pData, (uint8_t)iLen); - rc = !myWire->endTransmission(); -#else - rc = (i2c_master_write_to_device(I2C_NUM_0, u8Addr, pData, iLen, 100) == ESP_OK); -#endif - return rc; -} /* I2CWrite() */ -// -// Read N bytes starting at a specific 16-bit I2C register -// -int BBCapTouch::I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen) -{ - int i = 0; - -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - if (_iType == CT_TYPE_MXT144) { // little endian - myWire->write((uint8_t)u16Register); // low byte - myWire->write((uint8_t)(u16Register>>8)); // high byte - } else { // big endian address - myWire->write((uint8_t)(u16Register>>8)); // high byte - myWire->write((uint8_t)u16Register); // low byte - } - myWire->endTransmission(); - myWire->requestFrom(u8Addr, (uint8_t)iLen); - while (i < iLen) - { - pData[i++] = myWire->read(); - } -#else - uint8_t ucTemp[4]; - int rc; - if (_iType == CT_TYPE_MXT144) { // little endian - ucTemp[1] = (uint8_t)(u16Register>>8); // high byte - ucTemp[0] = (uint8_t)u16Register; // low byte - } else { - ucTemp[0] = (uint8_t)(u16Register>>8); // high byte - ucTemp[1] = (uint8_t)u16Register; // low byte - } - rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, ucTemp, 2, pData, iLen, 100); - if (rc == ESP_OK) { - i = iLen; - } -#endif - return i; - -} /* I2CReadRegister16() */ -// -// Read N bytes starting at a specific I2C internal register -// returns 1 for success, 0 for error -// -int BBCapTouch::I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen) -{ - int rc; - int i = 0; - -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - myWire->write(u8Register); - myWire->endTransmission(); - myWire->requestFrom(u8Addr, (uint8_t)iLen); - // i = myWire->readBytes(pData, iLen); - while (myWire->available() && i < iLen) - { - pData[i++] = myWire->read(); - } -#else - rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, &u8Register, 1, pData, iLen, 100); - i = (rc == ESP_OK); -#endif - return i; -} /* I2CReadRegister() */ -// -// Read N bytes -// -int BBCapTouch::I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen) -{ - int i = 0; - -#ifdef ARDUINO - myWire->requestFrom(u8Addr, (uint8_t)iLen); - while (i < iLen) - { - pData[i++] = myWire->read(); - } -#else - int rc; - rc = i2c_master_read_from_device(I2C_NUM_0, u8Addr, pData, iLen, 100); - i = (rc == ESP_OK) ? iLen : 0; -#endif - return i; -} /* I2CRead() */ -// -// Private function to rotate touch samples if the user -// specified a new display orientation -// -void BBCapTouch::fixSamples(TOUCHINFO *pTI) -{ -int i, x, y; - - for (i=0; icount; i++) { - switch (_iOrientation) { - case 90: - x = pTI->y[i]; - y = _iWidth - 1 - pTI->x[i]; - pTI->x[i] = x; - pTI->y[i] = y; - break; - case 180: - pTI->x[i] = _iWidth - 1 - pTI->x[i]; - pTI->y[i] = _iHeight - 1 - pTI->y[i]; - break; - case 270: - x = _iHeight - 1 - pTI->y[i]; - y = pTI->x[i]; - pTI->x[i] = x; - pTI->y[i] = y; - break; - default: // do nothing - break; - } - } -} /* fixSamples() */ -void BBCapTouch::SPD2010ClearInt(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 2; - ucTemp[1] = 0; - ucTemp[2] = 1; - ucTemp[3] = 0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010ClearInt() */ - -void BBCapTouch::SPD2010CPUStart(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 4; - ucTemp[1] = 0; - ucTemp[2] = 1; - ucTemp[3] = 0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010CPUStart() */ - -uint8_t BBCapTouch::SPD2010Status(int *iNextLen) -{ - uint8_t ucTemp[8]; - I2CReadRegister16(_iAddr, 0xfc02, ucTemp, 8); - *iNextLen = (ucTemp[3] << 8) | ucTemp[2]; - return ucTemp[5]; -} /* SPD2010Status() */ - -void BBCapTouch::SPD2010TouchStart(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 0x46; - ucTemp[1] = 0x0; - ucTemp[2] = 0x0; - ucTemp[3] = 0x0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010TouchStart() */ - -void BBCapTouch::SPD2010PointMode(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 0x50; - ucTemp[1] = 0x0; - ucTemp[2] = 0x0; - ucTemp[3] = 0x0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010PointMode() */ - -// -// Read the touch points -// returns 0 (none), 1 if touch points are available -// The point count and info is returned in the TOUCHINFO structure -// -int BBCapTouch::getSamples(TOUCHINFO *pTI) -{ -uint8_t c, *s, ucTemp[32]; -int i, j, rc = 0; - - if (!pTI) - return 0; - pTI->count = 0; - if (_iType == CT_TYPE_UNKNOWN) return 0; // library not initialized? - - if (_iType == CT_TYPE_SPD2010) { - static int iNextLen = 0; - int iReadLen; - uint8_t ucStatus; - // first read the status - I2CReadRegister16(_iAddr, 0x2000, ucTemp, 4); - // Byte 0 has a bit field with the following info: - // 0 = point exists - // 1 = gesture - // 3 = aux, cytang - // Byte 1 - // 3 = cpu run - // 4 = tint low - // 5 = tic in cpu - // 6 = tic in bios - // 7 = tic busy - iReadLen = (ucTemp[3]<<8) + ucTemp[2]; - // Serial.printf("status byte 0: 0x%02x, 0x%02x, read len = %d\n", ucTemp[0], ucTemp[1], iReadLen); - if (ucTemp[1] & 0x40) { // tic in bios - SPD2010ClearInt(); // Write Clear TINT Command - SPD2010CPUStart(); // Write CPU Start Command - } else if (ucTemp[1] & 0x20) { // tic in cpu - SPD2010PointMode(); // Write Touch Change Command - SPD2010TouchStart(); // Write Touch Start Command - SPD2010ClearInt(); - } else if ((ucTemp[1] & 8) && iReadLen == 0) { // cpu run - SPD2010ClearInt(); - } else if (ucTemp[0] & 1 || ucTemp[0] & 2) { // point or gesture - uint8_t ucData[64]; // 4-byte header plus up to 10 fingers of 6 bytes each - I2CReadRegister16(_iAddr, 0x0003, ucData, iReadLen); - // Serial.printf("readlen: %d, data[4]: 0x%02x\n", iReadLen, ucData[4]); - if (ucData[4] <= 0xa && ucTemp[0] & 1) { // check_id < 10 && point exists - rc = 1; // touch event - pTI->count = (iReadLen - 4)/6; // number of touch points - for (int i=0; icount; i++) { - int iOffset = i*6; - pTI->x[i] = ((ucData[7+iOffset] & 0xf0) << 4) | ucData[5+iOffset]; - pTI->y[i] = ((ucData[7+iOffset] & 0x0f) << 8) | ucData[6+iOffset]; - pTI->area[i] = ucData[8+iOffset]; - } - } - // gestures... - hdp_done_check: - /* Read HDP Status */ - ucStatus = SPD2010Status(&iNextLen); -// Serial.printf("status: 0x%02\n", ucStatus); - if (ucStatus == 0x82) { - SPD2010ClearInt(); - } else if (ucStatus == 0x00) { // Read HDP Remain Data - // Read_HDP_REMAIN_DATA(&tp_hdp_status); - goto hdp_done_check; - } - } else if (ucTemp[1] & 8 && ucTemp[0] & 8) { // cpu run && aux - SPD2010ClearInt(); - } - return rc; - } - if (_iType == CT_TYPE_TMA445) { - uint8_t hst_mode; - I2CReadRegister(_iAddr, 0, ucTemp, 14); // read up to 2 touch points - pTI->count = ucTemp[2]; // touch point count - if (pTI->count > 0) { - pTI->y[0] = (ucTemp[5]*256) + ucTemp[6]; - pTI->x[0] = (ucTemp[3]*256) + ucTemp[4]; - pTI->area[0] = ucTemp[7]; - if (pTI->count == 2) { // get second touch point - pTI->y[1] = (ucTemp[11]*256) + ucTemp[12]; - pTI->x[1] = (ucTemp[9]*256) + ucTemp[10]; - pTI->area[1] = ucTemp[13]; - } - // do handshake - I2CReadRegister(_iAddr, 0, &hst_mode, 1); - hst_mode ^= CY_HNDSHK_BIT; // toggle handshake bit - ucTemp[0] = 0; - ucTemp[1] = hst_mode; // send it back - I2CWrite(_iAddr, ucTemp, 2); - return 1; - } - return 0; - } - if (_iType == CT_TYPE_MXT144) { - if (!_mxtdata.t44_message_count_address) { - return 0; // No message offset, so we can't read anything :( - } - I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, ucTemp, 1); - j = ucTemp[0]; // object count - // As each message is read from the sensor, the internal count - // is decremented. It appears that it can hold 6 messages maximum - // before you must read them to receive more. - for (i = 0; i < j; i++) { // read the messages - I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, ucTemp, MXT_MESSAGE_SIZE); // each message is 6 bytes - // check report_id - if (ucTemp[0] >= _mxtdata.t100_first_report_id + 2 && - ucTemp[0] < _mxtdata.t100_first_report_id + 2 + 5) { - uint8_t finger_idx = ucTemp[0] - _mxtdata.t100_first_report_id - 2; - uint8_t event = ucTemp[1] & 0xf; - if (finger_idx+1 > pTI->count) pTI->count = finger_idx+1; - pTI->x[finger_idx] = ucTemp[2] + (ucTemp[3] << 8); - pTI->y[finger_idx] = ucTemp[4] + (ucTemp[5] << 8); - if (event == 1 || event == 4) { // move/press event - pTI->area[finger_idx] = 50; - } else if (event == 5) { // release - pTI->area[finger_idx] = 0; - } - } // if touch report - } // for each report - return (pTI->count > 0); - } // MXT144 - - if (_iType == CT_TYPE_AXS15231) { - uint8_t ucReadCMD[8] = {0xb5,0xab,0xa5,0x5a,0,0,0,0x8}; - I2CWrite(_iAddr, (uint8_t *)ucReadCMD, 8); - I2CRead(_iAddr, ucTemp, 14); // read up to 2 touch points - c = ucTemp[1]; // number of touch points - if (c == 0 || c > 2 || ucTemp[0] != 0) return 0; - pTI->count = c; - j = 0; // buffer offset - for (i=0; ix[i] = ((ucTemp[j+2] & 0xf) << 8) + ucTemp[j+3]; - pTI->y[i] = ((ucTemp[j+4] & 0xf) << 8) + ucTemp[j+5]; - pTI->area[i] = 1; - j += 6; - } - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } // AXS15231 - - if (_iType == CT_TYPE_CST226) { - i = I2CReadRegister(_iAddr, 0, ucTemp, 28); // read the whole block of regs -// Serial.printf("I2CReadRegister returned %d\n", i); -#ifdef FUTURE - if (ucTemp[0] == 0x83 && ucTemp[1] == 0x17 && ucTemp[5] == 0x80) { - // home button pressed - return 0; - } - if (ucTemp[6] != 0xab) return 0; - if (ucTemp[0] == 0xab) return 0; - if (ucTemp[5] == 0x80) return 0; - c = ucTemp[5] & 0x7f; - if (c > 5 || c == 0) { // invalid point count - ucTemp[0] = 0; - ucTemp[1] = 0xab; - I2CWrite(_iAddr, ucTemp, 2); // reset - return 0; - } -#endif - c = 1; // debug - pTI->count = c; - // Serial.printf("count = %d\n", c); - j = 0; - for (i=0; ix[i] = (uint16_t)((ucTemp[j+1] << 4) | ((ucTemp[j+3] >> 4) & 0xf)); - pTI->y[i] = (uint16_t)((ucTemp[j+2] << 4) | (ucTemp[j+3] & 0xf)); - pTI->pressure[i] = ucTemp[j+4]; - j = (i == 0) ? (j+7) : (j+5); - } - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } - - if (_iType == CT_TYPE_CHSC6540) { - if (digitalRead(_iINT) == LOW) { - I2CReadRegister(_iAddr, 2, ucTemp, 13); // read touch points - if (ucTemp[2] == 1 || ucTemp[2] == 2) { - pTI->count = ucTemp[2]; - pTI->x[0] = ((ucTemp[3] & 0xf) << 8) | ucTemp[4]; - pTI->y[0] = ((ucTemp[5] & 0xf) << 8) | ucTemp[6]; - if (ucTemp[0] == 2) { // second touch point - pTI->x[0] = ((ucTemp[9] & 0xf) << 8) | ucTemp[10]; - pTI->y[0] = ((ucTemp[11] & 0xf) << 8) | ucTemp[12]; - } - return 1; - } - } - return 0; - } - if (_iType == CT_TYPE_CST820) { - I2CReadRegister(_iAddr, CST820_TOUCH_REGS+1, ucTemp, 1); // read touch count - if (ucTemp[0] < 1 || ucTemp[0] > 5) { // something went wrong - return 0; - } - if (ucTemp[0] >= 1) { // touch data available, read it - pTI->count = ucTemp[0]; - I2CReadRegister(_iAddr, CST820_TOUCH_REGS+2, ucTemp, pTI->count * 6); - s = ucTemp; - for (i=0; icount; i++) { - pTI->x[i] = ((s[0] & 0xf) << 8) | s[1]; - pTI->y[i] = ((s[2] & 0xf) << 8) | s[3]; - pTI->area[i] = 1; // no data available - s += 6; - } - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } - } - if (_iType == CT_TYPE_FT6X36) { - rc = I2CReadRegister(_iAddr, TOUCH_REG_STATUS, ucTemp, 1); // read touch status - if (rc == 0) { // something went wrong - return 0; - } - i = ucTemp[0]; // number of touch points available - if (i >= 1 && i <= 5) { // get data - rc = I2CReadRegister(_iAddr, TOUCH_REG_XH, ucTemp, 6*i); // read X+Y position(s) - if ((ucTemp[0] & 0x40) == 0 && (ucTemp[2] & 0xf0) != 0xf0) { // finger is down - pTI->x[0] = ((ucTemp[0] & 0xf) << 8) | ucTemp[1]; - pTI->y[0] = ((ucTemp[2] & 0xf) << 8) | ucTemp[3]; - // get touch pressure and area - pTI->pressure[0] = ucTemp[4]; - pTI->area[0] = ucTemp[5]; - pTI->count++; - } - if (i > 1) { // get second point - if ((ucTemp[6] & 0x40) == 0 && (ucTemp[8] & 0xf0) != 0xf0) { // finger is down - pTI->x[1] = ((ucTemp[6] & 0xf) << 8) | ucTemp[7]; - pTI->y[1] = ((ucTemp[8] & 0xf) << 8) | ucTemp[9]; - // get touch pressure and area - pTI->pressure[1] = ucTemp[10]; - pTI->area[1] = ucTemp[11]; - pTI->count++; - } - } - } // if touch points available - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } else { // GT911 - I2CReadRegister16(_iAddr, GT911_POINT_INFO, ucTemp, 1); // get number of touch points - i = ucTemp[0] & 0xf; // number of touches - if (i <= 5 && ucTemp[0] & 0x80) { // if buffer status is good + >= 1 touch points - ucTemp[0] = (uint8_t)(GT911_POINT_INFO >> 8); - ucTemp[1] = (uint8_t)GT911_POINT_INFO; - ucTemp[2] = 0; // clear touch info for next time - I2CWrite(_iAddr, ucTemp, 3); - - pTI->count = i; - for (int j=0; jx[j] = ucTemp[1] + (ucTemp[2] << 8); - pTI->y[j] = ucTemp[3] + (ucTemp[4] << 8); - pTI->area[j] = ucTemp[5] + (ucTemp[6] << 8); - pTI->pressure[j] = 0; - } - if (i && _iOrientation != 0) fixSamples(pTI); - return (i > 0); - } - } // GT911 - return 0; -} /* getSamples() */ - -int BBCapTouch::setOrientation(int iOrientation, int iWidth, int iHeight) -{ - if (iOrientation != 0 && iOrientation != 90 && iOrientation != 180 && iOrientation != 270) { - return CT_ERROR; - } - _iOrientation = iOrientation; - _iWidth = iWidth; - _iHeight = iHeight; - return CT_SUCCESS; -} /* setOrientation() */ - -int BBCapTouch::sensorType(void) -{ - return _iType; -} /* type() */ - -int BBCapTouch::sleep(void) -{ -uint8_t ucTemp[8]; - - if (_iType == CT_TYPE_AXS15231) { - ucTemp[0] = 0x90; // enter deep sleep - ucTemp[1] = 0xa5; - ucTemp[2] = 0x5a; - ucTemp[3] = 0x15; - ucTemp[4] = 0x23; - I2CWrite(_iAddr, ucTemp, 5); - return CT_SUCCESS; - } - if (_iType == CT_TYPE_GT911 && _iINT != -1) { - pinMode(_iINT, OUTPUT); - digitalWrite(_iINT, 0); // setting interrupt pin low to prepare sleep mode - ucTemp[0] = (uint8_t)(GT911_ENTER_SLEEP >> 8); - ucTemp[1] = (uint8_t)GT911_ENTER_SLEEP; - ucTemp[2] = 0x05; //?? - I2CWrite(_iAddr, ucTemp, 3); // enter sleep mode - return CT_SUCCESS; - } - if (_iType == CT_TYPE_CST226) { - ucTemp[0] = 0xd1; - ucTemp[1] = 0x05; - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - return CT_ERROR; -} /* sleep() */ - -int BBCapTouch::wake(void) -{ -uint8_t ucTemp[4]; - - if (_iType == CT_TYPE_AXS15231) { - digitalWrite(_iRST, 0); - delay(50); - digitalWrite(_iRST, 1); - return CT_SUCCESS; - } - if (_iType == CT_TYPE_GT911 && _iINT != -1) { - digitalWrite(_iINT, 1); // wake up the controller - delay(5); // allow it time to wake - pinMode(_iINT, INPUT); // change pin mode back to floating - } - if (_iType == CT_TYPE_CST226) { - ucTemp[0] = 0xd1; - ucTemp[1] = 0x06; - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - return CT_ERROR; -} /* wake() */ - - diff --git a/esp32s3/components/grid_esp32_touch/bb_captouch.h b/esp32s3/components/grid_esp32_touch/bb_captouch.h deleted file mode 100644 index 8fa6c0bc..00000000 --- a/esp32s3/components/grid_esp32_touch/bb_captouch.h +++ /dev/null @@ -1,266 +0,0 @@ -// -// BitBank Capacitive Touch Sensor Library -// written by Larry Bank -// -// Copyright 2023 BitBank Software, Inc. All Rights Reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//=========================================================================== - -// -// Written for the many variants of ESP32 + Capacitive touch LCDs on the market -// -#ifdef ARDUINO -#include -#include -#else -#define INPUT 0 -#define OUTPUT 1 -#define INPUT_PULLUP 2 -#define LOW 0 -#define HIGH 1 -#include "driver/gpio.h" -#include "driver/i2c.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -static inline void delay(uint32_t ms) { vTaskDelay(pdMS_TO_TICKS(ms)); } -static inline int digitalRead(uint8_t pin) { return (int)gpio_get_level((gpio_num_t)pin); } -#endif // ARDUINO - -#ifndef __BB_CAPTOUCH__ -#define __BB_CAPTOUCH__ - -#define CT_SUCCESS 0 -#define CT_ERROR -1 -// -// Pre-configured device names -// Don't change the order of this list! -// the structure values follow it. Always -// add new values to the end -// -enum { - TOUCH_T_QT_C6=0, - TOUCH_CYD_550, - TOUCH_T_DISPLAY_S3_PRO, - TOUCH_T_DISPLAY_S3_LONG, - TOUCH_CYD_22C, - TOUCH_CYD_24C, - TOUCH_CYD_128, - TOUCH_CYD_35C, - TOUCH_CYD_518, - TOUCH_CYD_543, - TOUCH_M5_CORE2, - TOUCH_M5_CORES3, - TOUCH_M5_PAPER, - TOUCH_WT32_SC01_PLUS, - TOUCH_MAKERFABS_480x480, - TOUCH_MAKERFABS_320x480, - TOUCH_T_DISPLAY_S3_AMOLED, - TOUCH_WS_AMOLED_18, - TOUCH_M5_PAPERS3, - TOUCH_WS_ROUND_146, - TOUCH_WS_AMOLED_241, - TOUCH_WS_LCD_169, - TOUCH_VIEWE_2432, - TOUCH_T_DISPLAY_S3_AMOLED_164, - TOUCH_COUNT -}; -// structure holding the configurations -typedef struct bbct_config_tag { - int8_t i8SDA, i8SCL, i8IRQ, i8RST; -} BBCT_CONFIG; - -enum { - CT_TYPE_UNKNOWN = 0, - CT_TYPE_FT6X36, - CT_TYPE_GT911, - CT_TYPE_CST820, - CT_TYPE_CST226, - CT_TYPE_MXT144, - CT_TYPE_AXS15231, - CT_TYPE_TMA445, - CT_TYPE_SPD2010, - CT_TYPE_CHSC6540, - CT_TYPE_COUNT -}; - -#define SPD2010_ADDR 0x53 -#define GT911_ADDR1 0x5D -#define GT911_ADDR2 0x14 -#define FT6X36_ADDR1 0x38 -#define FT6X36_ADDR2 0x48 -#define CST820_ADDR 0x15 -#define CST226_ADDR 0x5A -#define CHSC6540_ADDR 0x2E -#define MXT144_ADDR 0x4A -#define TMA445_ADDR 0x24 -#define AXS15231_ADDR 0x3B - -// CST8xx gestures -enum { - GESTURE_NONE = 0, - GESTURE_SWIPE_UP, - GESTURE_SWIPE_DOWN, - GESTURE_SWIPE_LEFT, - GESTURE_SWIPE_RIGHT, - GESTURE_SINGLE_CLICK, - GESTURE_DOUBLE_CLICK = 0x0B, - GESTURE_LONG_PRESS = 0x0C -}; - -// TMA445 Security KEY -static uint8_t tma445_key[] = {0x00, 0x00, 0xFF, 0xA5, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; - -/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */ -typedef struct cyttsp_xydata_tag { - uint8_t hst_mode; - uint8_t tt_mode; - uint8_t tt_stat; - uint16_t x1 __attribute__ ((packed)); - uint16_t y1 __attribute__ ((packed)); - uint8_t z1; - uint8_t touch12_id; - uint16_t x2 __attribute__ ((packed)); - uint16_t y2 __attribute__ ((packed)); - uint8_t z2; -} cyttsp_xydata; -#define CY_HNDSHK_BIT 0x80 -typedef struct cyttsp_bootloader_data_tag { - uint8_t bl_file; - uint8_t bl_status; - uint8_t bl_error; - uint8_t blver_hi; - uint8_t blver_lo; - uint8_t bld_blver_hi; - uint8_t bld_blver_lo; - uint8_t ttspver_hi; - uint8_t ttspver_lo; - uint8_t appid_hi; - uint8_t appid_lo; - uint8_t appver_hi; - uint8_t appver_lo; - uint8_t cid_0; - uint8_t cid_1; - uint8_t cid_2; -} cyttsp_bootloader_data; - - -typedef struct mxt_data_tag { - uint16_t t2_encryption_status_address; - uint16_t t5_message_processor_address; - uint16_t t5_max_message_size; - uint16_t t6_command_processor_address; - uint16_t t7_powerconfig_address; - uint16_t t8_acquisitionconfig_address; - uint16_t t44_message_count_address; - uint16_t t46_cte_config_address; - uint16_t t100_multiple_touch_touchscreen_address; - uint16_t t100_first_report_id; -} MXTDATA; - -typedef struct mxt_object_tag { - uint8_t type; - uint16_t position; - uint8_t size_minus_one; - uint8_t instances_minus_one; - uint8_t report_ids_per_instance; -} MXTOBJECT; - -#define MXT_MESSAGE_SIZE 6 - -// CST820 registers -#define CST820_TOUCH_REGS 1 - -// GT911 registers -#define GT911_POINT_INFO 0x814E -#define GT911_POINT_1 0x814F -#define GT911_CONFIG_FRESH 0x8100 -#define GT911_CONFIG_SIZE 0xb9 -#define GT911_CONFIG_START 0x8047 -#define GT911_ENTER_SLEEP 0x8040 - -// FT6x36 registers -#define TOUCH_REG_STATUS 0x02 -#define TOUCH_REG_XH 0x03 -#define TOUCH_REG_XL 0x04 -#define TOUCH_REG_YH 0x05 -#define TOUCH_REG_YL 0x06 -#define TOUCH_REG_WEIGHT 0x07 -#define TOUCH_REG_AREA 0x08 -// register offset to info for the second touch point -#define PT2_OFFSET 6 - -#ifndef __TOUCHINFO_STRUCT__ -#define __TOUCHINFO_STRUCT__ - -typedef struct _fttouchinfo -{ - int count; - uint16_t x[5], y[5]; - uint8_t pressure[5], area[5]; -} TOUCHINFO; -#endif - -//extern TwoWire* myWire; - -class BBCapTouch -{ -public: - BBCapTouch() { _iOrientation = 0; _iType = CT_TYPE_UNKNOWN;} -// ~BBCapTouch() { Wire.end(); } -#ifdef ARDUINO - ~BBCapTouch() { myWire->end(); } -#else - ~BBCapTouch() {} -#endif - -#ifdef ARDUINO - int init(int iConfigName); - int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000, TwoWire* _myWire=&Wire); -#else - int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000); -#endif - int getSamples(TOUCHINFO *pTI); - uint8_t interruptPin(void) {return (uint8_t)_iINT;} - int sensorType(void); - int setOrientation(int iOrientation, int iWidth, int iHeight); - int sleep(void); - int wake(void); - -protected: - void reset(int iResetPin); - -private: - int _iAddr; - int _iType; - int _iOrientation, _iWidth, _iHeight; - MXTDATA _mxtdata; - int _iINT; // interrupt GPIO pin needed for sleep/wake of GT911 - int _iRST; // reset GPIO needed for AXS15206 to wake from deep sleep -#ifdef ARDUINO - TwoWire* myWire; -#else - void pinMode(uint8_t u8Pin, uint8_t u8Mode); - void digitalWrite(uint8_t u8Pin, uint8_t u8State); -#endif - int initMXT(void); - void fixSamples(TOUCHINFO *pTI); - bool I2CTest(uint8_t u8Addr); - int I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen); - int I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen); - int I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen); - int I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen); - void SPD2010ClearInt(void); - void SPD2010CPUStart(void); - uint8_t SPD2010Status(int *iNextLen); - void SPD2010TouchStart(void); - void SPD2010PointMode(void); -}; // class BBCapTouch -#endif // __BB_CAPTOUCH__ diff --git a/esp32s3/components/grid_esp32_touch/grid_esp32_touch.c b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.c new file mode 100644 index 00000000..5497adee --- /dev/null +++ b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.c @@ -0,0 +1,250 @@ +/* + * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "grid_esp32_touch.h" + +#include "driver/gpio.h" +#include "driver/i2c.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "rom/ets_sys.h" + +#define MXT_I2C_ADDR 0x4A + +#define MXT_ID_BLOCK_SIZE 7 +#define MXT_OBJ_ENTRY_SIZE 6 + +#define MXT_OBJ_T5 5 +#define MXT_OBJ_T44 44 +#define MXT_OBJ_T100 100 + +DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; + +static struct grid_esp32_touch_model* s_touch_ptr = NULL; + +static void IRAM_ATTR mxt_chg_isr(void* arg) { s_touch_ptr->pending = true; } + +static esp_err_t mxt_write_addr(i2c_port_t port, uint16_t addr) { + uint8_t buf[2] = {(uint8_t)(addr & 0xFF), (uint8_t)(addr >> 8)}; + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (MXT_I2C_ADDR << 1) | I2C_MASTER_WRITE, true); + i2c_master_write(cmd, buf, 2, true); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(port, cmd, pdMS_TO_TICKS(100)); + i2c_cmd_link_delete(cmd); + return ret; +} + +static esp_err_t mxt_read_block(i2c_port_t port, uint16_t addr, uint8_t* dest, size_t len) { + esp_err_t ret = mxt_write_addr(port, addr); + if (ret != ESP_OK) + return ret; + + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (MXT_I2C_ADDR << 1) | I2C_MASTER_READ, true); + if (len > 1) { + i2c_master_read(cmd, dest, len - 1, I2C_MASTER_ACK); + } + i2c_master_read_byte(cmd, dest + len - 1, I2C_MASTER_NACK); + i2c_master_stop(cmd); + ret = i2c_master_cmd_begin(port, cmd, pdMS_TO_TICKS(100)); + i2c_cmd_link_delete(cmd); + return ret; +} + +void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, + grid_process_touch_t process_touch) { + + touch->i2c_port = i2c_port; + touch->scl_gpio = scl_gpio; + touch->sda_gpio = sda_gpio; + touch->reset_gpio = reset_gpio; + touch->int_gpio = int_gpio; + touch->i2c_freq_hz = i2c_freq_hz; + touch->process_touch = process_touch; + touch->t5_addr = 0; + touch->t5_size = 0; + touch->t44_addr = 0; + touch->t100_first_report_id = 0; + + // I2C master + i2c_config_t conf = {0}; + conf.mode = I2C_MODE_MASTER; + conf.sda_io_num = sda_gpio; + conf.scl_io_num = scl_gpio; + conf.sda_pullup_en = GPIO_PULLUP_ENABLE; + conf.scl_pullup_en = GPIO_PULLUP_ENABLE; + conf.master.clk_speed = i2c_freq_hz; + i2c_param_config(i2c_port, &conf); + esp_err_t ret = i2c_driver_install(i2c_port, I2C_MODE_MASTER, 0, 0, 0); + if (ret != ESP_OK && ret != ESP_ERR_INVALID_STATE) { + ets_printf("MXT i2c_driver_install failed: %d\r\n", ret); + return; + } + + // RST as output, INT/CHG as input with pull-up + gpio_config_t io_conf = {0}; + io_conf.pin_bit_mask = (1ULL << reset_gpio); + io_conf.mode = GPIO_MODE_OUTPUT; + io_conf.pull_up_en = GPIO_PULLUP_DISABLE; + io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE; + io_conf.intr_type = GPIO_INTR_DISABLE; + gpio_config(&io_conf); + + io_conf.pin_bit_mask = (1ULL << int_gpio); + io_conf.mode = GPIO_MODE_INPUT; + io_conf.pull_up_en = GPIO_PULLUP_ENABLE; + gpio_config(&io_conf); + + // Reset sequence — hold RST low 100ms, then wait 300ms for chip to initialise + gpio_set_level(reset_gpio, 0); + vTaskDelay(pdMS_TO_TICKS(100)); + gpio_set_level(reset_gpio, 1); + vTaskDelay(pdMS_TO_TICKS(300)); + + // Check CHG state as a diagnostic (not a hard gate) + ets_printf("MXT CHG after reset: %s\r\n", gpio_get_level(int_gpio) == 0 ? "LOW (ready)" : "HIGH"); + + // Scan I2C bus to confirm device is visible + grid_esp32_touch_scan(touch); + + // Read ID block at address 0 + uint8_t id[MXT_ID_BLOCK_SIZE]; + ret = mxt_read_block(i2c_port, 0, id, MXT_ID_BLOCK_SIZE); + if (ret != ESP_OK) { + ets_printf("MXT ID block read failed: %d\r\n", ret); + return; + } + ets_printf("MXT family=0x%02X variant=0x%02X fw=%d.%d.%02X matrix=%dx%d objects=%d\r\n", id[0], id[1], id[2] >> 4, id[2] & 0x0F, id[3], id[4], id[5], id[6]); + + // Parse object table to find T5, T44, T100 + uint8_t num_objects = id[6]; + uint16_t table_ptr = MXT_ID_BLOCK_SIZE; + uint8_t report_id = 1; + + for (uint8_t i = 0; i < num_objects; i++) { + uint8_t entry[MXT_OBJ_ENTRY_SIZE]; + ret = mxt_read_block(i2c_port, table_ptr, entry, MXT_OBJ_ENTRY_SIZE); + if (ret != ESP_OK) { + ets_printf("MXT object table read failed at entry %d\r\n", i); + return; + } + table_ptr += MXT_OBJ_ENTRY_SIZE; + + uint8_t obj_type = entry[0]; + uint16_t obj_addr = entry[1] | ((uint16_t)entry[2] << 8); + uint8_t num_inst = entry[4]; // stored as instances-1 + uint8_t num_rids = entry[5]; + + if (obj_type == MXT_OBJ_T5) { + touch->t5_addr = obj_addr; + touch->t5_size = entry[3]; // read size-1 bytes, skipping trailing checksum + } else if (obj_type == MXT_OBJ_T44) { + touch->t44_addr = obj_addr; + } else if (obj_type == MXT_OBJ_T100) { + touch->t100_first_report_id = report_id; + } + + if (num_rids > 0) { + report_id += (num_inst + 1) * num_rids; + } + } + + if (touch->t5_addr && touch->t44_addr && touch->t100_first_report_id) { + ets_printf("MXT init OK: T5@0x%04X(sz=%d) T44@0x%04X T100 first_rid=%d\r\n", touch->t5_addr, touch->t5_size, touch->t44_addr, touch->t100_first_report_id); + + } else { + ets_printf("MXT init FAILED: T5=0x%04X T44=0x%04X T100_rid=%d\r\n", touch->t5_addr, touch->t44_addr, touch->t100_first_report_id); + return; + } + + // Interrupt on falling edge of CHG — sets pending flag, serviced in main loop + s_touch_ptr = touch; + esp_err_t isr_ret; + isr_ret = gpio_install_isr_service(0); + ets_printf("MXT gpio_install_isr_service: %d\r\n", isr_ret); + isr_ret = gpio_set_intr_type(int_gpio, GPIO_INTR_NEGEDGE); + ets_printf("MXT gpio_set_intr_type: %d\r\n", isr_ret); + isr_ret = gpio_isr_handler_add(int_gpio, mxt_chg_isr, NULL); + ets_printf("MXT gpio_isr_handler_add: %d\r\n", isr_ret); + isr_ret = gpio_intr_enable(int_gpio); + ets_printf("MXT gpio_intr_enable: %d\r\n", isr_ret); + touch->pending = true; +} + +void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch) { + + ets_printf("I2C scan (SCL=GPIO%d SDA=GPIO%d):\r\n", touch->scl_gpio, touch->sda_gpio); + int found = 0; + for (uint8_t addr = 0x08; addr < 0x78; addr++) { + i2c_cmd_handle_t cmd = i2c_cmd_link_create(); + i2c_master_start(cmd); + i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true); + i2c_master_stop(cmd); + esp_err_t ret = i2c_master_cmd_begin(touch->i2c_port, cmd, pdMS_TO_TICKS(10)); + i2c_cmd_link_delete(cmd); + if (ret == ESP_OK) { + ets_printf(" found device at 0x%02X\r\n", addr); + found++; + } + } + if (found == 0) { + ets_printf(" no devices found\r\n"); + } +} + +int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI) { + if (!pTI) + return 0; + pTI->count = 0; + + if (!touch->t44_addr || !touch->t5_addr || !touch->t100_first_report_id) { + return 0; + } + + if (!touch->pending) { + return 0; + } + touch->pending = false; + + uint8_t msg_count = 0; + esp_err_t ret = mxt_read_block(touch->i2c_port, touch->t44_addr, &msg_count, 1); + if (ret != ESP_OK || msg_count == 0) { + return 0; + } + + uint8_t msg[10]; + uint8_t finger_start = touch->t100_first_report_id + 2; + + for (uint8_t i = 0; i < msg_count; i++) { + ret = mxt_read_block(touch->i2c_port, touch->t5_addr, msg, touch->t5_size); + if (ret != ESP_OK) + break; + + uint8_t report_id = msg[0]; + + if (report_id >= finger_start && report_id < finger_start + 5) { + uint8_t finger_idx = report_id - finger_start; + uint8_t event = msg[1] & 0x0F; + + if (finger_idx + 1 > pTI->count) { + pTI->count = finger_idx + 1; + } + pTI->x[finger_idx] = msg[2] | ((uint16_t)msg[3] << 8); + pTI->y[finger_idx] = msg[4] | ((uint16_t)msg[5] << 8); + + if (event == 4 || event == 1) { // touch down or move + pTI->area[finger_idx] = 50; + } else if (event == 5) { // touch up + pTI->area[finger_idx] = 0; + } + } + } + + return (pTI->count > 0); +} diff --git a/esp32s3/components/grid_esp32_touch/grid_esp32_touch.cpp b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.cpp deleted file mode 100644 index 8cdf76af..00000000 --- a/esp32s3/components/grid_esp32_touch/grid_esp32_touch.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "grid_esp32_touch.h" -#include "bb_captouch.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "rom/ets_sys.h" - -DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; - -static struct grid_esp32_touch_model* touch_ptr = NULL; -static BBCapTouch bbc; - -void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, - grid_process_touch_t process_touch) { - - touch_ptr = touch; - touch->i2c_port = i2c_port; - touch->scl_gpio = scl_gpio; - touch->sda_gpio = sda_gpio; - touch->reset_gpio = reset_gpio; - touch->int_gpio = int_gpio; - touch->i2c_freq_hz = i2c_freq_hz; - touch->process_touch = process_touch; - - int rc = bbc.init(touch->sda_gpio, touch->scl_gpio, touch->reset_gpio, touch->int_gpio, touch->i2c_freq_hz); - if (rc == CT_SUCCESS) { - ets_printf("MXT144 init OK\r\n"); - } else { - ets_printf("MXT144 init FAILED\r\n"); - } -} - -void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch) { - - ets_printf("I2C scan (SCL=GPIO%d SDA=GPIO%d):\r\n", touch->scl_gpio, touch->sda_gpio); - int found = 0; - for (uint8_t addr = 0x08; addr < 0x78; addr++) { - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true); - i2c_master_stop(cmd); - esp_err_t ret = i2c_master_cmd_begin(touch->i2c_port, cmd, pdMS_TO_TICKS(10)); - i2c_cmd_link_delete(cmd); - if (ret == ESP_OK) { - ets_printf(" found device at 0x%02X\r\n", addr); - found++; - } - } - if (found == 0) { - ets_printf(" no devices found\r\n"); - } -} - -int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI) { - (void)touch; - return bbc.getSamples(pTI); -} diff --git a/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h index 7da47412..70bed729 100644 --- a/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h +++ b/esp32s3/components/grid_esp32_touch/grid_esp32_touch.h @@ -5,6 +5,7 @@ */ #pragma once +#include #include #include "freertos/FreeRTOS.h" @@ -37,6 +38,13 @@ struct grid_esp32_touch_model { gpio_num_t int_gpio; uint32_t i2c_freq_hz; grid_process_touch_t process_touch; + + uint16_t t5_addr; + uint8_t t5_size; + uint16_t t44_addr; + uint8_t t100_first_report_id; + + volatile bool pending; }; extern struct grid_esp32_touch_model grid_esp32_touch_state; diff --git a/esp32s3/main/grid_esp32s3.c b/esp32s3/main/grid_esp32s3.c index 397a8778..c5bc7341 100644 --- a/esp32s3/main/grid_esp32s3.c +++ b/esp32s3/main/grid_esp32s3.c @@ -49,6 +49,7 @@ #include "grid_esp32_module_po16.h" #include "grid_esp32_module_vsnx.h" #include "grid_esp32_module_xy.h" +#include "grid_esp32_touch.h" #include "pico_firmware.h" #include "grid_esp32_trace.h" @@ -624,8 +625,8 @@ void app_main(void) { vmp_flushed = true; } - if (grid_hwcfg_module_is_xy(&grid_sys_state)) { - grid_esp32_module_xy_poll_touch(); + if (grid_hwcfg_module_is_xy(&grid_sys_state) && grid_esp32_touch_state.pending) { + grid_esp32_module_xy_handle_touch(); } // Run microtasks From e99c3dfd431e04971acb2c5faf25524769b24fc3 Mon Sep 17 00:00:00 2001 From: sukuwc Date: Tue, 5 May 2026 10:58:25 +0200 Subject: [PATCH 6/9] Remove bb_captouch library, stale grid_esp dir, and maxtouch.c scratch file These were used during development and prototyping of the MXT touch driver; all superseded by the native driver in grid_esp32_touch. Co-Authored-By: Claude Sonnet 4.6 --- bb_captouch-1.3.1/LICENSE | 204 ---- bb_captouch-1.3.1/README.md | 28 - .../examples/named_device/named_device.ino | 33 - .../examples/touch_demo/touch_demo.ino | 144 --- bb_captouch-1.3.1/library.properties | 11 - bb_captouch-1.3.1/src/bb_captouch.cpp | 878 ----------------- bb_captouch-1.3.1/src/bb_captouch.h | 255 ----- .../grid_esp32_touch/CMakeLists.txt | 9 - .../grid_esp32_touch/bb_captouch.cpp | 882 ------------------ .../components/grid_esp32_touch/bb_captouch.h | 266 ------ .../grid_esp32_touch/grid_esp32_touch.cpp | 64 -- .../grid_esp32_touch/grid_esp32_touch.h | 53 -- maxtouch.c | 654 ------------- 13 files changed, 3481 deletions(-) delete mode 100644 bb_captouch-1.3.1/LICENSE delete mode 100644 bb_captouch-1.3.1/README.md delete mode 100644 bb_captouch-1.3.1/examples/named_device/named_device.ino delete mode 100644 bb_captouch-1.3.1/examples/touch_demo/touch_demo.ino delete mode 100644 bb_captouch-1.3.1/library.properties delete mode 100644 bb_captouch-1.3.1/src/bb_captouch.cpp delete mode 100644 bb_captouch-1.3.1/src/bb_captouch.h delete mode 100644 grid_esp/components/grid_esp32_touch/CMakeLists.txt delete mode 100644 grid_esp/components/grid_esp32_touch/bb_captouch.cpp delete mode 100644 grid_esp/components/grid_esp32_touch/bb_captouch.h delete mode 100644 grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp delete mode 100644 grid_esp/components/grid_esp32_touch/grid_esp32_touch.h delete mode 100644 maxtouch.c diff --git a/bb_captouch-1.3.1/LICENSE b/bb_captouch-1.3.1/LICENSE deleted file mode 100644 index 716f427d..00000000 --- a/bb_captouch-1.3.1/LICENSE +++ /dev/null @@ -1,204 +0,0 @@ -Copyright 2020 BitBank Software, Inc. All rights reserved. - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/bb_captouch-1.3.1/README.md b/bb_captouch-1.3.1/README.md deleted file mode 100644 index 297e1770..00000000 --- a/bb_captouch-1.3.1/README.md +++ /dev/null @@ -1,28 +0,0 @@ -BitBank Capacitive Touch Sensor Library
---------------------------------------- -Copyright (c) 2023-2024 BitBank Software, Inc.
-Written by Larry Bank
-email: bitbank@pobox.com
-
-There are a growing list of development boards which include LCDs with capacitive touch plates on them. These are overwhelmingly controlled by different versions of the ESP32 MCU. The boards normally only utilize GOODiX and FocalTech capacitive touch controllers and this library supports the MXT144, CST820, GT911 and FT6x36 in a generic way. Each has different capabilities and usually come pre-programmed for the specific pixel width and height of the target application. A feature supported by this library that may not be present in the device you're using is the touch area and pressure values. Some of their controllers also have built-in gesture detection. The common features of the controllers is that they will generate an interrupt signal when a touch event is occurring. This library allows you to request the latest touch information and it returns the number of active touch points (0-5) along with the coordinates (and pressure/area of each if available). The sensor type and address is auto-detected when calling the init() method. The only info that must be correctly supplied to the library are the GPIO pins used for the SDA/SCL/INT/RESET signals. Once initialized, repeatedly call getSamples() to test for and read any touch samples available.
- -There are only 4 methods exposed by the class:
-int init() - detects if a supported CT controller is available and initializes it
-int setOrientation(int iOrientation, int iWidth, int iHeight) - allows you to rotate the coordinates to match the LCD orientation
-int getSamples() - returns touch points if available
-int sensorType() - returns an enumerated value of the sensor detected<> -Here is the TOUCHINFO structure filled by the getSamples() method:
-``` -typedef struct _fttouchinfo -{ - int count; - uint16_t x[5], y[5]; - uint8_t pressure[5], area[5]; -} TOUCHINFO; -``` - -If you find this code useful, please consider becoming a sponsor or sending a donation. - -[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=SR4F44J2UR8S4) - - diff --git a/bb_captouch-1.3.1/examples/named_device/named_device.ino b/bb_captouch-1.3.1/examples/named_device/named_device.ino deleted file mode 100644 index e0f1e21c..00000000 --- a/bb_captouch-1.3.1/examples/named_device/named_device.ino +++ /dev/null @@ -1,33 +0,0 @@ -// -// This example shows how to use a pre-configured device name -// The names contain the GPIO pin numbers of a specific device -// -#include -BBCapTouch bbct; - -void setup() -{ - int rc; - Serial.begin(115200); - delay(3000); // allow time for CDC-Serial to start - -// The full list of device names can be found in bb_captouch.h - rc = bbct.init(TOUCH_WS_AMOLED_18); - if (rc == CT_SUCCESS) { - Serial.printf("bb_captouch init success, type = %d\n", bbct.sensorType()); - } else { - Serial.println("Error initializing bb_captouch"); - while (1) {}; - } -} - -void loop() -{ - TOUCHINFO ti; - while (1) { - bbct.getSamples(&ti); - if (ti.count > 0) { - Serial.printf("x,y = %d,%d\n", ti.x[0], ti.y[0]); - } - } -} diff --git a/bb_captouch-1.3.1/examples/touch_demo/touch_demo.ino b/bb_captouch-1.3.1/examples/touch_demo/touch_demo.ino deleted file mode 100644 index 40b204d8..00000000 --- a/bb_captouch-1.3.1/examples/touch_demo/touch_demo.ino +++ /dev/null @@ -1,144 +0,0 @@ -#include -//#include -#include -#include - -//#define CYD_128C -//#define LILYGO_S3_PRO -//#define LILYGO_S3_LONG -#define CYD_543 - - -#ifdef CYD_543 -#define LCD DISPLAY_CYD_543 -#define TOUCH_SDA 8 -#define TOUCH_SCL 4 -#define TOUCH_INT 3 -#define TOUCH_RST 38 -#endif - -#ifdef LILYGO_S3_LONG -#define TOUCH_SDA 15 -#define TOUCH_SCL 10 -#define TOUCH_INT 11 -// reset is 16, but it's shared with the LCD -#define TOUCH_RST -1 -#define LCD DISPLAY_T_DISPLAY_S3_LONG -#endif - -#ifdef LILYGO_S3_PRO -#define TOUCH_SDA 5 -#define TOUCH_SCL 6 -#define TOUCH_INT 7 -#define TOUCH_RST 13 -#define LCD DISPLAY_T_DISPLAY_S3_PRO -#endif - -#ifdef CYD_28C -// These defines are for a low cost 2.8" ESP32 LCD board with the GT911 touch controller -#define TOUCH_SDA 33 -#define TOUCH_SCL 32 -#define TOUCH_INT 21 -#define TOUCH_RST 25 -#define LCD DISPLAY_CYD -#endif - -#ifdef CYD_128C -// These defines are for a low cost 1.28" ESP32-C3 round LCD board with the CST816D touch controller -#define TOUCH_SDA 4 -#define TOUCH_SCL 5 -#define TOUCH_INT 0 -#define TOUCH_RST 1 -#define QWIIC_SDA 21 -#define QWIIC_SCL 20 -#define LCD DISPLAY_CYD_128 -#endif - -#ifdef ARDUINO_M5STACK_CORES3 -#define TOUCH_SDA 12 -#define TOUCH_SCL 11 -#define TOUCH_INT -1 -#define TOUCH_RST -1 -#define LCD DISPLAY_M5STACK_CORES3 -#endif // CORES3 - -BBCapTouch bbct; -BB_SPI_LCD lcd; -int iWidth, iHeight; - -const char *szNames[] = {"Unknown", "FT6x36", "GT911", "CST820", "CST226", "MXT144", "AXS15231"}; -void setup() { - - Serial.begin(115200); - while (!Serial) {}; - lcd.begin(LCD); - Serial.println("Starting..."); -// obd.setI2CPins(QWIIC_SDA, QWIIC_SCL); -// obd.setBitBang(true); -// obd.I2Cbegin(OLED_128x64); -// obd.fillScreen(OBD_WHITE); -// obd.setFont(FONT_12x16); -// obd.println("QWIIC OLED"); - iWidth = lcd.width(); - iHeight = lcd.height(); - Serial.printf("LCD size = %dx%d\n", iWidth, iHeight); - lcd.fillScreen(TFT_BLACK); - lcd.setTextColor(TFT_GREEN, TFT_BLACK); - lcd.setFont(FONT_8x8); - lcd.setCursor(0, 0); - lcd.println("CYD Touch Test"); - delay(1000); - Wire.end(); - //Wire1.end(); - bbct.init(TOUCH_SDA, TOUCH_SCL, TOUCH_RST, TOUCH_INT); - int iType = bbct.sensorType(); - Serial.printf("Sensor type = %s\n", szNames[iType]); -#ifdef OLD_STUFF -if (co2.init(QWIIC_SDA, QWIIC_SCL, 1, 100000) == SCD41_SUCCESS) { -// Serial.println("Found SCD41 sensor!"); - co2.start(); // start sampling mode - lcd.println("SCD41 found!"); - } else { // can't find the sensor, stop - lcd.println("SCD41 sensor not found"); - lcd.println("Check your connections"); - lcd.println("\nstopping..."); - while (1) {}; - } // no sensor connected or some error -#endif -} /* setup() */ - -void loop() { -#ifndef OLD_STUFF - int i; - TOUCHINFO ti; - -while (1) { - if (bbct.getSamples(&ti)) { - for (int i=0; i64) { // invalid number of items - return CT_ERROR; - } - u16Offset = 7; // starting offset of first object - // Read the objects one by one to get the memory offests to the info we will need - iReportID = 1; - // Serial.printf("object count = %d\n", iObjCount); - for (i=0; ibegin(iSDA, iSCL); // this is specific to ESP32 MCUs - myWire->setClock(u32Speed); - myWire->setTimeout(1000); -#else - i2c_config_t conf = { - .mode = I2C_MODE_MASTER, - .sda_io_num = iSDA, - .scl_io_num = iSCL, - .sda_pullup_en = GPIO_PULLUP_ENABLE, - .scl_pullup_en = GPIO_PULLUP_ENABLE, - .master.clk_speed = u32Speed, - }; - i2c_driver_delete(I2C_NUM_0); // remove driver (if installed) - i2c_param_config(I2C_NUM_0, &conf); // configure I2C device 0 - i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0); // configure with no send or receive buffers -#endif - _iType = CT_TYPE_UNKNOWN; - - if (iRST != -1) { - reset(iRST); - } - -#ifdef FUTURE - if (I2CTest(AXS15231_ADDR)) { - _iType = CT_TYPE_AXS15231; - _iAddr = AXS15231_ADDR; - if (iRST != -1) { - reset(iRST); - } - return CT_SUCCESS; - } // AXS15231 -#endif - - if (I2CTest(SPD2010_ADDR)) { - _iType = CT_TYPE_SPD2010; - _iAddr = SPD2010_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT_PULLUP); - } - return CT_SUCCESS; - } - if (I2CTest(TMA445_ADDR)) { - _iType = CT_TYPE_TMA445; - _iAddr = TMA445_ADDR; -// if (iINT != -1) { -// pinMode(iINT, INPUT_PULLUP); -// } - // send soft reset - ucTemp[0] = 0; - ucTemp[1] = 1; - I2CWrite(_iAddr, ucTemp, 2); - delay(50); - // send security key - I2CWrite(_iAddr, tma445_key, sizeof(tma445_key)); - delay(88); - - uint8_t tries = 0; - cyttsp_bootloader_data bl_data = {}; - do { - delay(20); - I2CRead(_iAddr, (uint8_t *)&bl_data, sizeof(bl_data)); - } while (bl_data.bl_status & 0x10 && tries++ < 10); // while bootloader mode - if (tries >= 10) Serial.println("bootloader mode timed out"); - // set OP mode - ucTemp[0] = 0; - ucTemp[1] = 0; // start op mode - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - if (I2CTest(MXT144_ADDR)) { - _iType = CT_TYPE_MXT144; - _iAddr = MXT144_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT); - } - if (iRST != -1) { - reset(iRST); - } - return initMXT(); - } - if (I2CTest(CHSC6540_ADDR)) { - _iType = CT_TYPE_CHSC6540; - _iAddr = CHSC6540_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT); - } - ucTemp[0] = ucTemp[1] = 0x5a; // set interrupt mode - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - if (I2CTest(CST226_ADDR)) { - _iType = CT_TYPE_CST226; - _iAddr = CST226_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT); - } - return CT_SUCCESS; - } - if (I2CTest(GT911_ADDR1) || I2CTest(GT911_ADDR2)) { - _iType = CT_TYPE_GT911; - } - if (_iType == CT_TYPE_GT911) { // reset the sensor to start it - pinMode(iRST, OUTPUT); - pinMode(iINT, OUTPUT); - digitalWrite(iINT, LOW); - digitalWrite(iRST, LOW); - delay(5); - digitalWrite(iINT, LOW); // set I2C addr to ADDR1 - delay(1); - digitalWrite(iRST, HIGH); // when it comes out of reset, it samples INT - delay(10); - digitalWrite(iINT, LOW); - delay(50); - pinMode(iINT, INPUT); - // double check the I2C addr in case it changed - if (I2CTest(GT911_ADDR1)) { - _iAddr = GT911_ADDR1; - } else if (I2CTest(GT911_ADDR2)) { - _iAddr = GT911_ADDR2; - } - } else if (I2CTest(FT6X36_ADDR1)) { - _iType = CT_TYPE_FT6X36; - _iAddr = FT6X36_ADDR1; - } else if (I2CTest(FT6X36_ADDR2)) { - _iType = CT_TYPE_FT6X36; - _iAddr = FT6X36_ADDR2; - } else if (I2CTest(CST820_ADDR)) { - _iType = CT_TYPE_CST820; - _iAddr = CST820_ADDR; - if (iRST != -1) { - reset(iRST); - } - } else { -#ifdef ARDUINO - myWire->end(); -#else - i2c_driver_delete(I2C_NUM_0); -#endif - return CT_ERROR; // no device found - } - return CT_SUCCESS; -} /* init() */ - -// Initialize the touch controller from a pre-defined configuration name -int BBCapTouch::init(int iConfigName) -{ -const BBCT_CONFIG *pC = &_configs[iConfigName]; - - if (iConfigName < 0 || iConfigName >= TOUCH_COUNT) { - return CT_ERROR; - } - - if (iConfigName == TOUCH_WS_AMOLED_241) { // touch is rotated - _iOrientation = 270; - _iWidth = 450; - _iHeight = 600; - - } - if (iConfigName == TOUCH_WS_AMOLED_18 || iConfigName == TOUCH_WS_ROUND_146) { - // need to release the RESET line which is controlled by an - // I/O expander (TCA9554) - uint8_t ucEXIO; - if (iConfigName == TOUCH_WS_AMOLED_18) ucEXIO = 6; // touch reset (AMOLED 1.8) - else ucEXIO = 1; // touch reset (1.46" round) - Wire.end(); - Wire.begin(pC->i8SDA, pC->i8SCL); - Wire.beginTransmission(0x20); - Wire.write(1); // output port register - Wire.write(~ucEXIO); // set touch controller reset low - Wire.write(0); // polarity inversion all disabled - Wire.write(~7); // enable P0+P1+P2 as an output (connected to RESET) - Wire.endTransmission(); - delay(50); - Wire.beginTransmission(0x20); - Wire.write(1); // output port register - Wire.write(0xff); // set all outputs high (disable resets) - Wire.endTransmission(); - delay(50); - if (iConfigName == TOUCH_WS_AMOLED_18) { - Wire.beginTransmission(0x38); - Wire.write(0xa5); // power mode - Wire.write(0); // active - Wire.endTransmission(); - } - Wire.end(); - } - return init(pC->i8SDA, pC->i8SCL, pC->i8RST, pC->i8IRQ, -#ifdef ARDUINO - 400000, &Wire); -#else - 400000); -#endif -} /* init() */ -// -// Test if an I2C device is monitoring an address -// return true if it responds, false if no response -// -bool BBCapTouch::I2CTest(uint8_t u8Addr) -{ - // Check if a device acknowledges the address. -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - return(myWire->endTransmission(true) == 0); -#else // allow 100ms for device to respond - uint8_t c = 0; - return (i2c_master_write_to_device(I2C_NUM_0, u8Addr, &c, 1, 10) == ESP_OK); -#endif -} /* I2CTest() */ -// -// Write I2C data -// quits if a NACK is received and returns 0 -// otherwise returns the number of bytes written -// -int BBCapTouch::I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen) -{ - int rc = 0; - -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - myWire->write(pData, (uint8_t)iLen); - rc = !myWire->endTransmission(); -#else - rc = (i2c_master_write_to_device(I2C_NUM_0, u8Addr, pData, iLen, 100) == ESP_OK); -#endif - return rc; -} /* I2CWrite() */ -// -// Read N bytes starting at a specific 16-bit I2C register -// -int BBCapTouch::I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen) -{ - int i = 0; - -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - if (_iType == CT_TYPE_MXT144) { // little endian - myWire->write((uint8_t)u16Register); // low byte - myWire->write((uint8_t)(u16Register>>8)); // high byte - } else { // big endian address - myWire->write((uint8_t)(u16Register>>8)); // high byte - myWire->write((uint8_t)u16Register); // low byte - } - myWire->endTransmission(); - myWire->requestFrom(u8Addr, (uint8_t)iLen); - while (i < iLen) - { - pData[i++] = myWire->read(); - } -#else - uint8_t ucTemp[4]; - int rc; - if (_iType == CT_TYPE_MXT144) { // little endian - ucTemp[1] = (uint8_t)(u16Register>>8); // high byte - ucTemp[0] = (uint8_t)u16Register; // low byte - } else { - ucTemp[0] = (uint8_t)(u16Register>>8); // high byte - ucTemp[1] = (uint8_t)u16Register; // low byte - } - i2c_master_write_read_device(I2C_NUM_0, u8Addr, ucTemp, 2, pData, iLen, 100); - if (rc == ESP_OK) { - i = iLen; - } -#endif - return i; - -} /* I2CReadRegister16() */ -// -// Read N bytes starting at a specific I2C internal register -// returns 1 for success, 0 for error -// -int BBCapTouch::I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen) -{ - int rc; - int i = 0; - -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - myWire->write(u8Register); - myWire->endTransmission(); - myWire->requestFrom(u8Addr, (uint8_t)iLen); - // i = myWire->readBytes(pData, iLen); - while (myWire->available() && i < iLen) - { - pData[i++] = myWire->read(); - } -#else - rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, &u8Register, 1, pData, iLen, 100); - i = (rc == ESP_OK); -#endif - return i; -} /* I2CReadRegister() */ -// -// Read N bytes -// -int BBCapTouch::I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen) -{ - int i = 0; - -#ifdef ARDUINO - myWire->requestFrom(u8Addr, (uint8_t)iLen); - while (i < iLen) - { - pData[i++] = myWire->read(); - } -#else - int rc; - rc = i2c_master_read_from_device(I2C_NUM_0, u8Addr, pData, iLen, 100); - i = (rc == ESP_OK) ? iLen : 0; -#endif - return i; -} /* I2CRead() */ -// -// Private function to rotate touch samples if the user -// specified a new display orientation -// -void BBCapTouch::fixSamples(TOUCHINFO *pTI) -{ -int i, x, y; - - for (i=0; icount; i++) { - switch (_iOrientation) { - case 90: - x = pTI->y[i]; - y = _iWidth - 1 - pTI->x[i]; - pTI->x[i] = x; - pTI->y[i] = y; - break; - case 180: - pTI->x[i] = _iWidth - 1 - pTI->x[i]; - pTI->y[i] = _iHeight - 1 - pTI->y[i]; - break; - case 270: - x = _iHeight - 1 - pTI->y[i]; - y = pTI->x[i]; - pTI->x[i] = x; - pTI->y[i] = y; - break; - default: // do nothing - break; - } - } -} /* fixSamples() */ -void BBCapTouch::SPD2010ClearInt(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 2; - ucTemp[1] = 0; - ucTemp[2] = 1; - ucTemp[3] = 0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010ClearInt() */ - -void BBCapTouch::SPD2010CPUStart(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 4; - ucTemp[1] = 0; - ucTemp[2] = 1; - ucTemp[3] = 0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010CPUStart() */ - -uint8_t BBCapTouch::SPD2010Status(int *iNextLen) -{ - uint8_t ucTemp[8]; - I2CReadRegister16(_iAddr, 0xfc02, ucTemp, 8); - *iNextLen = (ucTemp[3] << 8) | ucTemp[2]; - return ucTemp[5]; -} /* SPD2010Status() */ - -void BBCapTouch::SPD2010TouchStart(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 0x46; - ucTemp[1] = 0x0; - ucTemp[2] = 0x0; - ucTemp[3] = 0x0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010TouchStart() */ - -void BBCapTouch::SPD2010PointMode(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 0x50; - ucTemp[1] = 0x0; - ucTemp[2] = 0x0; - ucTemp[3] = 0x0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010PointMode() */ - -// -// Read the touch points -// returns 0 (none), 1 if touch points are available -// The point count and info is returned in the TOUCHINFO structure -// -int BBCapTouch::getSamples(TOUCHINFO *pTI) -{ -uint8_t c, *s, ucTemp[32]; -int i, j, rc = 0; - - if (!pTI) - return 0; - pTI->count = 0; - if (_iType == CT_TYPE_UNKNOWN) return 0; // library not initialized? - - if (_iType == CT_TYPE_SPD2010) { - static int iNextLen = 0; - int iReadLen; - uint8_t ucStatus; - // first read the status - I2CReadRegister16(_iAddr, 0x2000, ucTemp, 4); - // Byte 0 has a bit field with the following info: - // 0 = point exists - // 1 = gesture - // 3 = aux, cytang - // Byte 1 - // 3 = cpu run - // 4 = tint low - // 5 = tic in cpu - // 6 = tic in bios - // 7 = tic busy - iReadLen = (ucTemp[3]<<8) + ucTemp[2]; - // Serial.printf("status byte 0: 0x%02x, 0x%02x, read len = %d\n", ucTemp[0], ucTemp[1], iReadLen); - if (ucTemp[1] & 0x40) { // tic in bios - SPD2010ClearInt(); // Write Clear TINT Command - SPD2010CPUStart(); // Write CPU Start Command - } else if (ucTemp[1] & 0x20) { // tic in cpu - SPD2010PointMode(); // Write Touch Change Command - SPD2010TouchStart(); // Write Touch Start Command - SPD2010ClearInt(); - } else if ((ucTemp[1] & 8) && iReadLen == 0) { // cpu run - SPD2010ClearInt(); - } else if (ucTemp[0] & 1 || ucTemp[0] & 2) { // point or gesture - uint8_t ucData[64]; // 4-byte header plus up to 10 fingers of 6 bytes each - I2CReadRegister16(_iAddr, 0x0003, ucData, iReadLen); - // Serial.printf("readlen: %d, data[4]: 0x%02x\n", iReadLen, ucData[4]); - if (ucData[4] <= 0xa && ucTemp[0] & 1) { // check_id < 10 && point exists - rc = 1; // touch event - pTI->count = (iReadLen - 4)/6; // number of touch points - for (int i=0; icount; i++) { - int iOffset = i*6; - pTI->x[i] = ((ucData[7+iOffset] & 0xf0) << 4) | ucData[5+iOffset]; - pTI->y[i] = ((ucData[7+iOffset] & 0x0f) << 8) | ucData[6+iOffset]; - pTI->area[i] = ucData[8+iOffset]; - } - } - // gestures... - hdp_done_check: - /* Read HDP Status */ - ucStatus = SPD2010Status(&iNextLen); -// Serial.printf("status: 0x%02\n", ucStatus); - if (ucStatus == 0x82) { - SPD2010ClearInt(); - } else if (ucStatus == 0x00) { // Read HDP Remain Data - // Read_HDP_REMAIN_DATA(&tp_hdp_status); - goto hdp_done_check; - } - } else if (ucTemp[1] & 8 && ucTemp[0] & 8) { // cpu run && aux - SPD2010ClearInt(); - } - return rc; - } - if (_iType == CT_TYPE_TMA445) { - uint8_t hst_mode; - I2CReadRegister(_iAddr, 0, ucTemp, 14); // read up to 2 touch points - pTI->count = ucTemp[2]; // touch point count - if (pTI->count > 0) { - pTI->y[0] = (ucTemp[5]*256) + ucTemp[6]; - pTI->x[0] = (ucTemp[3]*256) + ucTemp[4]; - pTI->area[0] = ucTemp[7]; - if (pTI->count == 2) { // get second touch point - pTI->y[1] = (ucTemp[11]*256) + ucTemp[12]; - pTI->x[1] = (ucTemp[9]*256) + ucTemp[10]; - pTI->area[1] = ucTemp[13]; - } - // do handshake - I2CReadRegister(_iAddr, 0, &hst_mode, 1); - hst_mode ^= CY_HNDSHK_BIT; // toggle handshake bit - ucTemp[0] = 0; - ucTemp[1] = hst_mode; // send it back - I2CWrite(_iAddr, ucTemp, 2); - return 1; - } - return 0; - } - if (_iType == CT_TYPE_MXT144) { - if (!_mxtdata.t44_message_count_address) { - return 0; // No message offset, so we can't read anything :( - } - I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, ucTemp, 1); - j = ucTemp[0]; // object count - // As each message is read from the sensor, the internal count - // is decremented. It appears that it can hold 6 messages maximum - // before you must read them to receive more. - for (i = 0; i < j; i++) { // read the messages - I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, ucTemp, MXT_MESSAGE_SIZE); // each message is 6 bytes - // check report_id - if (ucTemp[0] >= _mxtdata.t100_first_report_id + 2 && - ucTemp[0] < _mxtdata.t100_first_report_id + 2 + 5) { - uint8_t finger_idx = ucTemp[0] - _mxtdata.t100_first_report_id - 2; - uint8_t event = ucTemp[1] & 0xf; - if (finger_idx+1 > pTI->count) pTI->count = finger_idx+1; - pTI->x[finger_idx] = ucTemp[2] + (ucTemp[3] << 8); - pTI->y[finger_idx] = ucTemp[4] + (ucTemp[5] << 8); - if (event == 1 || event == 4) { // move/press event - pTI->area[finger_idx] = 50; - } else if (event == 5) { // release - pTI->area[finger_idx] = 0; - } - } // if touch report - } // for each report - return (pTI->count > 0); - } // MXT144 - - if (_iType == CT_TYPE_AXS15231) { - uint8_t ucReadCMD[8] = {0xb5,0xab,0xa5,0x5a,0,0,0,0x8}; - I2CWrite(_iAddr, (uint8_t *)ucReadCMD, 8); - I2CRead(_iAddr, ucTemp, 14); // read up to 2 touch points - c = ucTemp[1]; // number of touch points - if (c == 0 || c > 2 || ucTemp[0] != 0) return 0; - pTI->count = c; - j = 0; // buffer offset - for (i=0; ix[i] = ((ucTemp[j+2] & 0xf) << 8) + ucTemp[j+3]; - pTI->y[i] = ((ucTemp[j+4] & 0xf) << 8) + ucTemp[j+5]; - pTI->area[i] = 1; - j += 6; - } - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } // AXS15231 - - if (_iType == CT_TYPE_CST226) { - i = I2CReadRegister(_iAddr, 0, ucTemp, 28); // read the whole block of regs -// Serial.printf("I2CReadRegister returned %d\n", i); -#ifdef FUTURE - if (ucTemp[0] == 0x83 && ucTemp[1] == 0x17 && ucTemp[5] == 0x80) { - // home button pressed - return 0; - } - if (ucTemp[6] != 0xab) return 0; - if (ucTemp[0] == 0xab) return 0; - if (ucTemp[5] == 0x80) return 0; - c = ucTemp[5] & 0x7f; - if (c > 5 || c == 0) { // invalid point count - ucTemp[0] = 0; - ucTemp[1] = 0xab; - I2CWrite(_iAddr, ucTemp, 2); // reset - return 0; - } -#endif - c = 1; // debug - pTI->count = c; - // Serial.printf("count = %d\n", c); - j = 0; - for (i=0; ix[i] = (uint16_t)((ucTemp[j+1] << 4) | ((ucTemp[j+3] >> 4) & 0xf)); - pTI->y[i] = (uint16_t)((ucTemp[j+2] << 4) | (ucTemp[j+3] & 0xf)); - pTI->pressure[i] = ucTemp[j+4]; - j = (i == 0) ? (j+7) : (j+5); - } - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } - - if (_iType == CT_TYPE_CHSC6540) { - if (digitalRead(_iINT) == LOW) { - I2CReadRegister(_iAddr, 2, ucTemp, 13); // read touch points - if (ucTemp[2] == 1 || ucTemp[2] == 2) { - pTI->count = ucTemp[2]; - pTI->x[0] = ((ucTemp[3] & 0xf) << 8) | ucTemp[4]; - pTI->y[0] = ((ucTemp[5] & 0xf) << 8) | ucTemp[6]; - if (ucTemp[0] == 2) { // second touch point - pTI->x[0] = ((ucTemp[9] & 0xf) << 8) | ucTemp[10]; - pTI->y[0] = ((ucTemp[11] & 0xf) << 8) | ucTemp[12]; - } - return 1; - } - } - return 0; - } - if (_iType == CT_TYPE_CST820) { - I2CReadRegister(_iAddr, CST820_TOUCH_REGS+1, ucTemp, 1); // read touch count - if (ucTemp[0] < 1 || ucTemp[0] > 5) { // something went wrong - return 0; - } - if (ucTemp[0] >= 1) { // touch data available, read it - pTI->count = ucTemp[0]; - I2CReadRegister(_iAddr, CST820_TOUCH_REGS+2, ucTemp, pTI->count * 6); - s = ucTemp; - for (i=0; icount; i++) { - pTI->x[i] = ((s[0] & 0xf) << 8) | s[1]; - pTI->y[i] = ((s[2] & 0xf) << 8) | s[3]; - pTI->area[i] = 1; // no data available - s += 6; - } - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } - } - if (_iType == CT_TYPE_FT6X36) { - rc = I2CReadRegister(_iAddr, TOUCH_REG_STATUS, ucTemp, 1); // read touch status - if (rc == 0) { // something went wrong - return 0; - } - i = ucTemp[0]; // number of touch points available - if (i >= 1 && i <= 5) { // get data - rc = I2CReadRegister(_iAddr, TOUCH_REG_XH, ucTemp, 6*i); // read X+Y position(s) - if ((ucTemp[0] & 0x40) == 0 && (ucTemp[2] & 0xf0) != 0xf0) { // finger is down - pTI->x[0] = ((ucTemp[0] & 0xf) << 8) | ucTemp[1]; - pTI->y[0] = ((ucTemp[2] & 0xf) << 8) | ucTemp[3]; - // get touch pressure and area - pTI->pressure[0] = ucTemp[4]; - pTI->area[0] = ucTemp[5]; - pTI->count++; - } - if (i > 1) { // get second point - if ((ucTemp[6] & 0x40) == 0 && (ucTemp[8] & 0xf0) != 0xf0) { // finger is down - pTI->x[1] = ((ucTemp[6] & 0xf) << 8) | ucTemp[7]; - pTI->y[1] = ((ucTemp[8] & 0xf) << 8) | ucTemp[9]; - // get touch pressure and area - pTI->pressure[1] = ucTemp[10]; - pTI->area[1] = ucTemp[11]; - pTI->count++; - } - } - } // if touch points available - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } else { // GT911 - I2CReadRegister16(_iAddr, GT911_POINT_INFO, ucTemp, 1); // get number of touch points - i = ucTemp[0] & 0xf; // number of touches - if (i <= 5 && ucTemp[0] & 0x80) { // if buffer status is good + >= 1 touch points - ucTemp[0] = (uint8_t)(GT911_POINT_INFO >> 8); - ucTemp[1] = (uint8_t)GT911_POINT_INFO; - ucTemp[2] = 0; // clear touch info for next time - I2CWrite(_iAddr, ucTemp, 3); - - pTI->count = i; - for (int j=0; jx[j] = ucTemp[1] + (ucTemp[2] << 8); - pTI->y[j] = ucTemp[3] + (ucTemp[4] << 8); - pTI->area[j] = ucTemp[5] + (ucTemp[6] << 8); - pTI->pressure[j] = 0; - } - if (i && _iOrientation != 0) fixSamples(pTI); - return (i > 0); - } - } // GT911 - return 0; -} /* getSamples() */ - -int BBCapTouch::setOrientation(int iOrientation, int iWidth, int iHeight) -{ - if (iOrientation != 0 && iOrientation != 90 && iOrientation != 180 && iOrientation != 270) { - return CT_ERROR; - } - _iOrientation = iOrientation; - _iWidth = iWidth; - _iHeight = iHeight; - return CT_SUCCESS; -} /* setOrientation() */ - -int BBCapTouch::sensorType(void) -{ - return _iType; -} /* type() */ - -int BBCapTouch::sleep(void) -{ -uint8_t ucTemp[8]; - - if (_iType == CT_TYPE_AXS15231) { - ucTemp[0] = 0x90; // enter deep sleep - ucTemp[1] = 0xa5; - ucTemp[2] = 0x5a; - ucTemp[3] = 0x15; - ucTemp[4] = 0x23; - I2CWrite(_iAddr, ucTemp, 5); - return CT_SUCCESS; - } - if (_iType == CT_TYPE_GT911 && _iINT != -1) { - pinMode(_iINT, OUTPUT); - digitalWrite(_iINT, 0); // setting interrupt pin low to prepare sleep mode - ucTemp[0] = (uint8_t)(GT911_ENTER_SLEEP >> 8); - ucTemp[1] = (uint8_t)GT911_ENTER_SLEEP; - ucTemp[2] = 0x05; //?? - I2CWrite(_iAddr, ucTemp, 3); // enter sleep mode - return CT_SUCCESS; - } - if (_iType == CT_TYPE_CST226) { - ucTemp[0] = 0xd1; - ucTemp[1] = 0x05; - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - return CT_ERROR; -} /* sleep() */ - -int BBCapTouch::wake(void) -{ -uint8_t ucTemp[4]; - - if (_iType == CT_TYPE_AXS15231) { - digitalWrite(_iRST, 0); - delay(50); - digitalWrite(_iRST, 1); - return CT_SUCCESS; - } - if (_iType == CT_TYPE_GT911 && _iINT != -1) { - digitalWrite(_iINT, 1); // wake up the controller - delay(5); // allow it time to wake - pinMode(_iINT, INPUT); // change pin mode back to floating - } - if (_iType == CT_TYPE_CST226) { - ucTemp[0] = 0xd1; - ucTemp[1] = 0x06; - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - return CT_ERROR; -} /* wake() */ - - diff --git a/bb_captouch-1.3.1/src/bb_captouch.h b/bb_captouch-1.3.1/src/bb_captouch.h deleted file mode 100644 index a8d4ccdb..00000000 --- a/bb_captouch-1.3.1/src/bb_captouch.h +++ /dev/null @@ -1,255 +0,0 @@ -// -// BitBank Capacitive Touch Sensor Library -// written by Larry Bank -// -// Copyright 2023 BitBank Software, Inc. All Rights Reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//=========================================================================== - -// -// Written for the many variants of ESP32 + Capacitive touch LCDs on the market -// -#ifdef ARDUINO -#include -#include -#else -#define INPUT 0 -#define OUTPUT 1 -#include "driver/gpio.h" -#include "driver/i2c.h" -#endif // ARDUINO - -#ifndef __BB_CAPTOUCH__ -#define __BB_CAPTOUCH__ - -#define CT_SUCCESS 0 -#define CT_ERROR -1 -// -// Pre-configured device names -// Don't change the order of this list! -// the structure values follow it. Always -// add new values to the end -// -enum { - TOUCH_T_QT_C6=0, - TOUCH_CYD_550, - TOUCH_T_DISPLAY_S3_PRO, - TOUCH_T_DISPLAY_S3_LONG, - TOUCH_CYD_22C, - TOUCH_CYD_24C, - TOUCH_CYD_128, - TOUCH_CYD_35C, - TOUCH_CYD_518, - TOUCH_CYD_543, - TOUCH_M5_CORE2, - TOUCH_M5_CORES3, - TOUCH_M5_PAPER, - TOUCH_WT32_SC01_PLUS, - TOUCH_MAKERFABS_480x480, - TOUCH_MAKERFABS_320x480, - TOUCH_T_DISPLAY_S3_AMOLED, - TOUCH_WS_AMOLED_18, - TOUCH_M5_PAPERS3, - TOUCH_WS_ROUND_146, - TOUCH_WS_AMOLED_241, - TOUCH_WS_LCD_169, - TOUCH_VIEWE_2432, - TOUCH_T_DISPLAY_S3_AMOLED_164, - TOUCH_COUNT -}; -// structure holding the configurations -typedef struct bbct_config_tag { - int8_t i8SDA, i8SCL, i8IRQ, i8RST; -} BBCT_CONFIG; - -enum { - CT_TYPE_UNKNOWN = 0, - CT_TYPE_FT6X36, - CT_TYPE_GT911, - CT_TYPE_CST820, - CT_TYPE_CST226, - CT_TYPE_MXT144, - CT_TYPE_AXS15231, - CT_TYPE_TMA445, - CT_TYPE_SPD2010, - CT_TYPE_CHSC6540, - CT_TYPE_COUNT -}; - -#define SPD2010_ADDR 0x53 -#define GT911_ADDR1 0x5D -#define GT911_ADDR2 0x14 -#define FT6X36_ADDR1 0x38 -#define FT6X36_ADDR2 0x48 -#define CST820_ADDR 0x15 -#define CST226_ADDR 0x5A -#define CHSC6540_ADDR 0x2E -#define MXT144_ADDR 0x4A -#define TMA445_ADDR 0x24 -#define AXS15231_ADDR 0x3B - -// CST8xx gestures -enum { - GESTURE_NONE = 0, - GESTURE_SWIPE_UP, - GESTURE_SWIPE_DOWN, - GESTURE_SWIPE_LEFT, - GESTURE_SWIPE_RIGHT, - GESTURE_SINGLE_CLICK, - GESTURE_DOUBLE_CLICK = 0x0B, - GESTURE_LONG_PRESS = 0x0C -}; - -// TMA445 Security KEY -static uint8_t tma445_key[] = {0x00, 0x00, 0xFF, 0xA5, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; - -/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */ -typedef struct cyttsp_xydata_tag { - uint8_t hst_mode; - uint8_t tt_mode; - uint8_t tt_stat; - uint16_t x1 __attribute__ ((packed)); - uint16_t y1 __attribute__ ((packed)); - uint8_t z1; - uint8_t touch12_id; - uint16_t x2 __attribute__ ((packed)); - uint16_t y2 __attribute__ ((packed)); - uint8_t z2; -} cyttsp_xydata; -#define CY_HNDSHK_BIT 0x80 -typedef struct cyttsp_bootloader_data_tag { - uint8_t bl_file; - uint8_t bl_status; - uint8_t bl_error; - uint8_t blver_hi; - uint8_t blver_lo; - uint8_t bld_blver_hi; - uint8_t bld_blver_lo; - uint8_t ttspver_hi; - uint8_t ttspver_lo; - uint8_t appid_hi; - uint8_t appid_lo; - uint8_t appver_hi; - uint8_t appver_lo; - uint8_t cid_0; - uint8_t cid_1; - uint8_t cid_2; -} cyttsp_bootloader_data; - - -typedef struct mxt_data_tag { - uint16_t t2_encryption_status_address; - uint16_t t5_message_processor_address; - uint16_t t5_max_message_size; - uint16_t t6_command_processor_address; - uint16_t t7_powerconfig_address; - uint16_t t8_acquisitionconfig_address; - uint16_t t44_message_count_address; - uint16_t t46_cte_config_address; - uint16_t t100_multiple_touch_touchscreen_address; - uint16_t t100_first_report_id; -} MXTDATA; - -typedef struct mxt_object_tag { - uint8_t type; - uint16_t position; - uint8_t size_minus_one; - uint8_t instances_minus_one; - uint8_t report_ids_per_instance; -} MXTOBJECT; - -#define MXT_MESSAGE_SIZE 6 - -// CST820 registers -#define CST820_TOUCH_REGS 1 - -// GT911 registers -#define GT911_POINT_INFO 0x814E -#define GT911_POINT_1 0x814F -#define GT911_CONFIG_FRESH 0x8100 -#define GT911_CONFIG_SIZE 0xb9 -#define GT911_CONFIG_START 0x8047 -#define GT911_ENTER_SLEEP 0x8040 - -// FT6x36 registers -#define TOUCH_REG_STATUS 0x02 -#define TOUCH_REG_XH 0x03 -#define TOUCH_REG_XL 0x04 -#define TOUCH_REG_YH 0x05 -#define TOUCH_REG_YL 0x06 -#define TOUCH_REG_WEIGHT 0x07 -#define TOUCH_REG_AREA 0x08 -// register offset to info for the second touch point -#define PT2_OFFSET 6 - -#ifndef __TOUCHINFO_STRUCT__ -#define __TOUCHINFO_STRUCT__ - -typedef struct _fttouchinfo -{ - int count; - uint16_t x[5], y[5]; - uint8_t pressure[5], area[5]; -} TOUCHINFO; -#endif - -//extern TwoWire* myWire; - -class BBCapTouch -{ -public: - BBCapTouch() { _iOrientation = 0; _iType = CT_TYPE_UNKNOWN;} -// ~BBCapTouch() { Wire.end(); } - ~BBCapTouch() { myWire->end(); } - -#ifdef ARDUINO - int init(int iConfigName); - int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000, TwoWire* _myWire=&Wire); -#else - int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000); -#endif - int getSamples(TOUCHINFO *pTI); - uint8_t interruptPin(void) {return (uint8_t)_iINT;} - int sensorType(void); - int setOrientation(int iOrientation, int iWidth, int iHeight); - int sleep(void); - int wake(void); - -protected: - void reset(int iResetPin); - -private: - int _iAddr; - int _iType; - int _iOrientation, _iWidth, _iHeight; - MXTDATA _mxtdata; - int _iINT; // interrupt GPIO pin needed for sleep/wake of GT911 - int _iRST; // reset GPIO needed for AXS15206 to wake from deep sleep -#ifdef ARDUINO - TwoWire* myWire; -#else - void pinMode(uint8_t u8Pin, uint8_t u8Mode); - void digitalWrite(uint8_t u8Pin, uint8_t u8State); -#endif - int initMXT(void); - void fixSamples(TOUCHINFO *pTI); - bool I2CTest(uint8_t u8Addr); - int I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen); - int I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen); - int I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen); - int I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen); - void SPD2010ClearInt(void); - void SPD2010CPUStart(void); - uint8_t SPD2010Status(int *iNextLen); - void SPD2010TouchStart(void); - void SPD2010PointMode(void); -}; // class BBCapTouch -#endif // __BB_CAPTOUCH__ diff --git a/grid_esp/components/grid_esp32_touch/CMakeLists.txt b/grid_esp/components/grid_esp32_touch/CMakeLists.txt deleted file mode 100644 index 86342a9e..00000000 --- a/grid_esp/components/grid_esp32_touch/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -idf_component_register( - SRCS - "grid_esp32_touch.cpp" - "bb_captouch.cpp" - INCLUDE_DIRS - "." - REQUIRES - "driver" "freertos" -) diff --git a/grid_esp/components/grid_esp32_touch/bb_captouch.cpp b/grid_esp/components/grid_esp32_touch/bb_captouch.cpp deleted file mode 100644 index 1294d1b9..00000000 --- a/grid_esp/components/grid_esp32_touch/bb_captouch.cpp +++ /dev/null @@ -1,882 +0,0 @@ -// -// BitBank Capactive Touch Sensor Library -// Written by Larry Bank -// -// Copyright 2023 BitBank Software, Inc. All Rights Reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//=========================================================================== -#include "bb_captouch.h" -#ifndef ARDUINO -#include "rom/ets_sys.h" -#endif - -static const BBCT_CONFIG _configs[] = { - // sda, scl, irq, rst - {21, 22, 7, 23}, // TOUCH_T_QT_C6 - {19, 20, -1, 38}, // TOUCH_CYD_550 - {5, 6, 7, 13}, // T-Display S3 Pro - {15, 20, 11, 16}, // T-Display-S3-Long - {21, 22, -1, -1}, // CYD_22C - {33, 32, 21, 25}, // CYD_24C - {4, 5, 0, 1}, // CYD_128 - {33, 32, 21, 25}, // CYD_35C - {7, 8, 41, 40}, // CYD_518 - {8, 4, 3, -1}, // CYD_543 - {21, 22, 39, -1}, // M5_CORE2 - {12, 11, -1, -1}, // M5_CORES3 - {21, 22, 36, -1}, // M5_PAPER - {6, 5 ,7, -1}, // WT32_SC01_PLUS - {17, 18, -1, 38}, // MakerFabs 4" 480x480 - {38,39,40,-1}, // MakerFabs 3.5" 320x480 - {7, 6, 9, 8}, // TOUCH_T_DISPLAY_S3_AMOLED (1.64") - {15, 14, 21, -1}, // TOUCH_WS_AMOLED_18 (Waveshare 1.8" 368x448 AMOLED) - {41, 42, 48, -1}, // TOUCH_M5_PAPERS3 - {11, 10, 4, -1}, // TOUCH_WS_ROUND_146 - {47,48,-1,3}, // TOUCH_WS_AMOLED_241 - {11,10,14,13}, // TOUCH_WS_LCD_169 - {1,3,4,2}, // TOUCH_VIEWE_2432 - {7, 6, 9, 8}, // TOUCH_T_DISPLAY_S3_AMOLED_164 - {0,0,0,0} - }; - -#ifndef ARDUINO -void BBCapTouch::pinMode(uint8_t u8Pin, uint8_t u8Mode) -{ - gpio_config_t io_conf = {}; - - io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt - //bit mask of the pins that you want to set,e.g.GPIO18/19 - io_conf.pin_bit_mask = (1 << u8Pin); - io_conf.pull_down_en = (gpio_pulldown_t)0; //disable pull-down mode - io_conf.pull_up_en = (gpio_pullup_t)0; //disable pull-up mode - if (u8Mode == INPUT) { - io_conf.mode = GPIO_MODE_INPUT; - } else { // must be output - io_conf.mode = GPIO_MODE_OUTPUT; - } - gpio_config(&io_conf); //configure GPIO with the given settings -} /* pinMode() */ -void BBCapTouch::digitalWrite(uint8_t u8Pin, uint8_t u8State) -{ - gpio_set_level((gpio_num_t)u8Pin, u8State); -} /* digitalWrite() */ -#endif // !ARDUINO -void BBCapTouch::reset(int iRST) -{ - pinMode(iRST, OUTPUT); - digitalWrite(iRST, LOW); - delay(100); - digitalWrite(iRST, HIGH); - delay(250); -} /* reset() */ - -// -// Initalize the MXT144 - an overly complicated mess of a touch sensor -// -int BBCapTouch::initMXT(void) -{ -uint8_t ucTemp[32]; -int i, iObjCount, iReportID; -uint16_t u16, u16Offset; - -// Read information block (first 7 bytes of address space) - I2CReadRegister16(_iAddr, 0, ucTemp, 7); - iObjCount = ucTemp[6]; - if (iObjCount < 1 || iObjCount >64) { // invalid number of items - return CT_ERROR; - } - u16Offset = 7; // starting offset of first object - // Read the objects one by one to get the memory offests to the info we will need - iReportID = 1; - // Serial.printf("object count = %d\n", iObjCount); - for (i=0; ibegin(iSDA, iSCL); // this is specific to ESP32 MCUs - myWire->setClock(u32Speed); - myWire->setTimeout(1000); -#else - i2c_config_t conf = {}; - conf.mode = I2C_MODE_MASTER; - conf.sda_io_num = iSDA; - conf.scl_io_num = iSCL; - conf.sda_pullup_en = GPIO_PULLUP_ENABLE; - conf.scl_pullup_en = GPIO_PULLUP_ENABLE; - conf.master.clk_speed = u32Speed; - i2c_driver_delete(I2C_NUM_0); // remove driver (if installed) - i2c_param_config(I2C_NUM_0, &conf); // configure I2C device 0 - i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0); // configure with no send or receive buffers -#endif - _iType = CT_TYPE_UNKNOWN; - - if (iRST != -1) { - reset(iRST); - } - -#ifdef FUTURE - if (I2CTest(AXS15231_ADDR)) { - _iType = CT_TYPE_AXS15231; - _iAddr = AXS15231_ADDR; - if (iRST != -1) { - reset(iRST); - } - return CT_SUCCESS; - } // AXS15231 -#endif - - if (I2CTest(SPD2010_ADDR)) { - _iType = CT_TYPE_SPD2010; - _iAddr = SPD2010_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT_PULLUP); - } - return CT_SUCCESS; - } - if (I2CTest(TMA445_ADDR)) { - _iType = CT_TYPE_TMA445; - _iAddr = TMA445_ADDR; -// if (iINT != -1) { -// pinMode(iINT, INPUT_PULLUP); -// } - // send soft reset - ucTemp[0] = 0; - ucTemp[1] = 1; - I2CWrite(_iAddr, ucTemp, 2); - delay(50); - // send security key - I2CWrite(_iAddr, tma445_key, sizeof(tma445_key)); - delay(88); - - uint8_t tries = 0; - cyttsp_bootloader_data bl_data = {}; - do { - delay(20); - I2CRead(_iAddr, (uint8_t *)&bl_data, sizeof(bl_data)); - } while (bl_data.bl_status & 0x10 && tries++ < 10); // while bootloader mode - if (tries >= 10) ets_printf("bootloader mode timed out\r\n"); - // set OP mode - ucTemp[0] = 0; - ucTemp[1] = 0; // start op mode - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - if (I2CTest(MXT144_ADDR)) { - _iType = CT_TYPE_MXT144; - _iAddr = MXT144_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT); - } - if (iRST != -1) { - reset(iRST); - } - return initMXT(); - } - if (I2CTest(CHSC6540_ADDR)) { - _iType = CT_TYPE_CHSC6540; - _iAddr = CHSC6540_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT); - } - ucTemp[0] = ucTemp[1] = 0x5a; // set interrupt mode - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - if (I2CTest(CST226_ADDR)) { - _iType = CT_TYPE_CST226; - _iAddr = CST226_ADDR; - if (iINT != -1) { - pinMode(iINT, INPUT); - } - return CT_SUCCESS; - } - if (I2CTest(GT911_ADDR1) || I2CTest(GT911_ADDR2)) { - _iType = CT_TYPE_GT911; - } - if (_iType == CT_TYPE_GT911) { // reset the sensor to start it - pinMode(iRST, OUTPUT); - pinMode(iINT, OUTPUT); - digitalWrite(iINT, LOW); - digitalWrite(iRST, LOW); - delay(5); - digitalWrite(iINT, LOW); // set I2C addr to ADDR1 - delay(1); - digitalWrite(iRST, HIGH); // when it comes out of reset, it samples INT - delay(10); - digitalWrite(iINT, LOW); - delay(50); - pinMode(iINT, INPUT); - // double check the I2C addr in case it changed - if (I2CTest(GT911_ADDR1)) { - _iAddr = GT911_ADDR1; - } else if (I2CTest(GT911_ADDR2)) { - _iAddr = GT911_ADDR2; - } - } else if (I2CTest(FT6X36_ADDR1)) { - _iType = CT_TYPE_FT6X36; - _iAddr = FT6X36_ADDR1; - } else if (I2CTest(FT6X36_ADDR2)) { - _iType = CT_TYPE_FT6X36; - _iAddr = FT6X36_ADDR2; - } else if (I2CTest(CST820_ADDR)) { - _iType = CT_TYPE_CST820; - _iAddr = CST820_ADDR; - if (iRST != -1) { - reset(iRST); - } - } else { -#ifdef ARDUINO - myWire->end(); -#else - i2c_driver_delete(I2C_NUM_0); -#endif - return CT_ERROR; // no device found - } - return CT_SUCCESS; -} /* init() */ - -// Initialize the touch controller from a pre-defined configuration name -#ifdef ARDUINO -int BBCapTouch::init(int iConfigName) -{ -const BBCT_CONFIG *pC = &_configs[iConfigName]; - - if (iConfigName < 0 || iConfigName >= TOUCH_COUNT) { - return CT_ERROR; - } - - if (iConfigName == TOUCH_WS_AMOLED_241) { // touch is rotated - _iOrientation = 270; - _iWidth = 450; - _iHeight = 600; - - } - if (iConfigName == TOUCH_WS_AMOLED_18 || iConfigName == TOUCH_WS_ROUND_146) { - // need to release the RESET line which is controlled by an - // I/O expander (TCA9554) - uint8_t ucEXIO; - if (iConfigName == TOUCH_WS_AMOLED_18) ucEXIO = 6; // touch reset (AMOLED 1.8) - else ucEXIO = 1; // touch reset (1.46" round) - Wire.end(); - Wire.begin(pC->i8SDA, pC->i8SCL); - Wire.beginTransmission(0x20); - Wire.write(1); // output port register - Wire.write(~ucEXIO); // set touch controller reset low - Wire.write(0); // polarity inversion all disabled - Wire.write(~7); // enable P0+P1+P2 as an output (connected to RESET) - Wire.endTransmission(); - delay(50); - Wire.beginTransmission(0x20); - Wire.write(1); // output port register - Wire.write(0xff); // set all outputs high (disable resets) - Wire.endTransmission(); - delay(50); - if (iConfigName == TOUCH_WS_AMOLED_18) { - Wire.beginTransmission(0x38); - Wire.write(0xa5); // power mode - Wire.write(0); // active - Wire.endTransmission(); - } - Wire.end(); - } - return init(pC->i8SDA, pC->i8SCL, pC->i8RST, pC->i8IRQ, -#ifdef ARDUINO - 400000, &Wire); -#else - 400000); -#endif -} /* init() */ -#endif // ARDUINO -// -// Test if an I2C device is monitoring an address -// return true if it responds, false if no response -// -bool BBCapTouch::I2CTest(uint8_t u8Addr) -{ - // Check if a device acknowledges the address. -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - return(myWire->endTransmission(true) == 0); -#else // allow 100ms for device to respond - uint8_t c = 0; - return (i2c_master_write_to_device(I2C_NUM_0, u8Addr, &c, 1, 10) == ESP_OK); -#endif -} /* I2CTest() */ -// -// Write I2C data -// quits if a NACK is received and returns 0 -// otherwise returns the number of bytes written -// -int BBCapTouch::I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen) -{ - int rc = 0; - -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - myWire->write(pData, (uint8_t)iLen); - rc = !myWire->endTransmission(); -#else - rc = (i2c_master_write_to_device(I2C_NUM_0, u8Addr, pData, iLen, 100) == ESP_OK); -#endif - return rc; -} /* I2CWrite() */ -// -// Read N bytes starting at a specific 16-bit I2C register -// -int BBCapTouch::I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen) -{ - int i = 0; - -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - if (_iType == CT_TYPE_MXT144) { // little endian - myWire->write((uint8_t)u16Register); // low byte - myWire->write((uint8_t)(u16Register>>8)); // high byte - } else { // big endian address - myWire->write((uint8_t)(u16Register>>8)); // high byte - myWire->write((uint8_t)u16Register); // low byte - } - myWire->endTransmission(); - myWire->requestFrom(u8Addr, (uint8_t)iLen); - while (i < iLen) - { - pData[i++] = myWire->read(); - } -#else - uint8_t ucTemp[4]; - int rc; - if (_iType == CT_TYPE_MXT144) { // little endian - ucTemp[1] = (uint8_t)(u16Register>>8); // high byte - ucTemp[0] = (uint8_t)u16Register; // low byte - } else { - ucTemp[0] = (uint8_t)(u16Register>>8); // high byte - ucTemp[1] = (uint8_t)u16Register; // low byte - } - rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, ucTemp, 2, pData, iLen, 100); - if (rc == ESP_OK) { - i = iLen; - } -#endif - return i; - -} /* I2CReadRegister16() */ -// -// Read N bytes starting at a specific I2C internal register -// returns 1 for success, 0 for error -// -int BBCapTouch::I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen) -{ - int rc; - int i = 0; - -#ifdef ARDUINO - myWire->beginTransmission(u8Addr); - myWire->write(u8Register); - myWire->endTransmission(); - myWire->requestFrom(u8Addr, (uint8_t)iLen); - // i = myWire->readBytes(pData, iLen); - while (myWire->available() && i < iLen) - { - pData[i++] = myWire->read(); - } -#else - rc = i2c_master_write_read_device(I2C_NUM_0, u8Addr, &u8Register, 1, pData, iLen, 100); - i = (rc == ESP_OK); -#endif - return i; -} /* I2CReadRegister() */ -// -// Read N bytes -// -int BBCapTouch::I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen) -{ - int i = 0; - -#ifdef ARDUINO - myWire->requestFrom(u8Addr, (uint8_t)iLen); - while (i < iLen) - { - pData[i++] = myWire->read(); - } -#else - int rc; - rc = i2c_master_read_from_device(I2C_NUM_0, u8Addr, pData, iLen, 100); - i = (rc == ESP_OK) ? iLen : 0; -#endif - return i; -} /* I2CRead() */ -// -// Private function to rotate touch samples if the user -// specified a new display orientation -// -void BBCapTouch::fixSamples(TOUCHINFO *pTI) -{ -int i, x, y; - - for (i=0; icount; i++) { - switch (_iOrientation) { - case 90: - x = pTI->y[i]; - y = _iWidth - 1 - pTI->x[i]; - pTI->x[i] = x; - pTI->y[i] = y; - break; - case 180: - pTI->x[i] = _iWidth - 1 - pTI->x[i]; - pTI->y[i] = _iHeight - 1 - pTI->y[i]; - break; - case 270: - x = _iHeight - 1 - pTI->y[i]; - y = pTI->x[i]; - pTI->x[i] = x; - pTI->y[i] = y; - break; - default: // do nothing - break; - } - } -} /* fixSamples() */ -void BBCapTouch::SPD2010ClearInt(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 2; - ucTemp[1] = 0; - ucTemp[2] = 1; - ucTemp[3] = 0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010ClearInt() */ - -void BBCapTouch::SPD2010CPUStart(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 4; - ucTemp[1] = 0; - ucTemp[2] = 1; - ucTemp[3] = 0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010CPUStart() */ - -uint8_t BBCapTouch::SPD2010Status(int *iNextLen) -{ - uint8_t ucTemp[8]; - I2CReadRegister16(_iAddr, 0xfc02, ucTemp, 8); - *iNextLen = (ucTemp[3] << 8) | ucTemp[2]; - return ucTemp[5]; -} /* SPD2010Status() */ - -void BBCapTouch::SPD2010TouchStart(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 0x46; - ucTemp[1] = 0x0; - ucTemp[2] = 0x0; - ucTemp[3] = 0x0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010TouchStart() */ - -void BBCapTouch::SPD2010PointMode(void) -{ - uint8_t ucTemp[4]; - ucTemp[0] = 0x50; - ucTemp[1] = 0x0; - ucTemp[2] = 0x0; - ucTemp[3] = 0x0; - I2CWrite(_iAddr, ucTemp, 4); -} /* SPD2010PointMode() */ - -// -// Read the touch points -// returns 0 (none), 1 if touch points are available -// The point count and info is returned in the TOUCHINFO structure -// -int BBCapTouch::getSamples(TOUCHINFO *pTI) -{ -uint8_t c, *s, ucTemp[32]; -int i, j, rc = 0; - - if (!pTI) - return 0; - pTI->count = 0; - if (_iType == CT_TYPE_UNKNOWN) return 0; // library not initialized? - - if (_iType == CT_TYPE_SPD2010) { - static int iNextLen = 0; - int iReadLen; - uint8_t ucStatus; - // first read the status - I2CReadRegister16(_iAddr, 0x2000, ucTemp, 4); - // Byte 0 has a bit field with the following info: - // 0 = point exists - // 1 = gesture - // 3 = aux, cytang - // Byte 1 - // 3 = cpu run - // 4 = tint low - // 5 = tic in cpu - // 6 = tic in bios - // 7 = tic busy - iReadLen = (ucTemp[3]<<8) + ucTemp[2]; - // Serial.printf("status byte 0: 0x%02x, 0x%02x, read len = %d\n", ucTemp[0], ucTemp[1], iReadLen); - if (ucTemp[1] & 0x40) { // tic in bios - SPD2010ClearInt(); // Write Clear TINT Command - SPD2010CPUStart(); // Write CPU Start Command - } else if (ucTemp[1] & 0x20) { // tic in cpu - SPD2010PointMode(); // Write Touch Change Command - SPD2010TouchStart(); // Write Touch Start Command - SPD2010ClearInt(); - } else if ((ucTemp[1] & 8) && iReadLen == 0) { // cpu run - SPD2010ClearInt(); - } else if (ucTemp[0] & 1 || ucTemp[0] & 2) { // point or gesture - uint8_t ucData[64]; // 4-byte header plus up to 10 fingers of 6 bytes each - I2CReadRegister16(_iAddr, 0x0003, ucData, iReadLen); - // Serial.printf("readlen: %d, data[4]: 0x%02x\n", iReadLen, ucData[4]); - if (ucData[4] <= 0xa && ucTemp[0] & 1) { // check_id < 10 && point exists - rc = 1; // touch event - pTI->count = (iReadLen - 4)/6; // number of touch points - for (int i=0; icount; i++) { - int iOffset = i*6; - pTI->x[i] = ((ucData[7+iOffset] & 0xf0) << 4) | ucData[5+iOffset]; - pTI->y[i] = ((ucData[7+iOffset] & 0x0f) << 8) | ucData[6+iOffset]; - pTI->area[i] = ucData[8+iOffset]; - } - } - // gestures... - hdp_done_check: - /* Read HDP Status */ - ucStatus = SPD2010Status(&iNextLen); -// Serial.printf("status: 0x%02\n", ucStatus); - if (ucStatus == 0x82) { - SPD2010ClearInt(); - } else if (ucStatus == 0x00) { // Read HDP Remain Data - // Read_HDP_REMAIN_DATA(&tp_hdp_status); - goto hdp_done_check; - } - } else if (ucTemp[1] & 8 && ucTemp[0] & 8) { // cpu run && aux - SPD2010ClearInt(); - } - return rc; - } - if (_iType == CT_TYPE_TMA445) { - uint8_t hst_mode; - I2CReadRegister(_iAddr, 0, ucTemp, 14); // read up to 2 touch points - pTI->count = ucTemp[2]; // touch point count - if (pTI->count > 0) { - pTI->y[0] = (ucTemp[5]*256) + ucTemp[6]; - pTI->x[0] = (ucTemp[3]*256) + ucTemp[4]; - pTI->area[0] = ucTemp[7]; - if (pTI->count == 2) { // get second touch point - pTI->y[1] = (ucTemp[11]*256) + ucTemp[12]; - pTI->x[1] = (ucTemp[9]*256) + ucTemp[10]; - pTI->area[1] = ucTemp[13]; - } - // do handshake - I2CReadRegister(_iAddr, 0, &hst_mode, 1); - hst_mode ^= CY_HNDSHK_BIT; // toggle handshake bit - ucTemp[0] = 0; - ucTemp[1] = hst_mode; // send it back - I2CWrite(_iAddr, ucTemp, 2); - return 1; - } - return 0; - } - if (_iType == CT_TYPE_MXT144) { - if (!_mxtdata.t44_message_count_address) { - return 0; // No message offset, so we can't read anything :( - } - I2CReadRegister16(_iAddr, _mxtdata.t44_message_count_address, ucTemp, 1); - j = ucTemp[0]; // object count - // As each message is read from the sensor, the internal count - // is decremented. It appears that it can hold 6 messages maximum - // before you must read them to receive more. - for (i = 0; i < j; i++) { // read the messages - I2CReadRegister16(_iAddr, _mxtdata.t5_message_processor_address, ucTemp, MXT_MESSAGE_SIZE); // each message is 6 bytes - // check report_id - if (ucTemp[0] >= _mxtdata.t100_first_report_id + 2 && - ucTemp[0] < _mxtdata.t100_first_report_id + 2 + 5) { - uint8_t finger_idx = ucTemp[0] - _mxtdata.t100_first_report_id - 2; - uint8_t event = ucTemp[1] & 0xf; - if (finger_idx+1 > pTI->count) pTI->count = finger_idx+1; - pTI->x[finger_idx] = ucTemp[2] + (ucTemp[3] << 8); - pTI->y[finger_idx] = ucTemp[4] + (ucTemp[5] << 8); - if (event == 1 || event == 4) { // move/press event - pTI->area[finger_idx] = 50; - } else if (event == 5) { // release - pTI->area[finger_idx] = 0; - } - } // if touch report - } // for each report - return (pTI->count > 0); - } // MXT144 - - if (_iType == CT_TYPE_AXS15231) { - uint8_t ucReadCMD[8] = {0xb5,0xab,0xa5,0x5a,0,0,0,0x8}; - I2CWrite(_iAddr, (uint8_t *)ucReadCMD, 8); - I2CRead(_iAddr, ucTemp, 14); // read up to 2 touch points - c = ucTemp[1]; // number of touch points - if (c == 0 || c > 2 || ucTemp[0] != 0) return 0; - pTI->count = c; - j = 0; // buffer offset - for (i=0; ix[i] = ((ucTemp[j+2] & 0xf) << 8) + ucTemp[j+3]; - pTI->y[i] = ((ucTemp[j+4] & 0xf) << 8) + ucTemp[j+5]; - pTI->area[i] = 1; - j += 6; - } - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } // AXS15231 - - if (_iType == CT_TYPE_CST226) { - i = I2CReadRegister(_iAddr, 0, ucTemp, 28); // read the whole block of regs -// Serial.printf("I2CReadRegister returned %d\n", i); -#ifdef FUTURE - if (ucTemp[0] == 0x83 && ucTemp[1] == 0x17 && ucTemp[5] == 0x80) { - // home button pressed - return 0; - } - if (ucTemp[6] != 0xab) return 0; - if (ucTemp[0] == 0xab) return 0; - if (ucTemp[5] == 0x80) return 0; - c = ucTemp[5] & 0x7f; - if (c > 5 || c == 0) { // invalid point count - ucTemp[0] = 0; - ucTemp[1] = 0xab; - I2CWrite(_iAddr, ucTemp, 2); // reset - return 0; - } -#endif - c = 1; // debug - pTI->count = c; - // Serial.printf("count = %d\n", c); - j = 0; - for (i=0; ix[i] = (uint16_t)((ucTemp[j+1] << 4) | ((ucTemp[j+3] >> 4) & 0xf)); - pTI->y[i] = (uint16_t)((ucTemp[j+2] << 4) | (ucTemp[j+3] & 0xf)); - pTI->pressure[i] = ucTemp[j+4]; - j = (i == 0) ? (j+7) : (j+5); - } - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } - - if (_iType == CT_TYPE_CHSC6540) { - if (digitalRead(_iINT) == LOW) { - I2CReadRegister(_iAddr, 2, ucTemp, 13); // read touch points - if (ucTemp[2] == 1 || ucTemp[2] == 2) { - pTI->count = ucTemp[2]; - pTI->x[0] = ((ucTemp[3] & 0xf) << 8) | ucTemp[4]; - pTI->y[0] = ((ucTemp[5] & 0xf) << 8) | ucTemp[6]; - if (ucTemp[0] == 2) { // second touch point - pTI->x[0] = ((ucTemp[9] & 0xf) << 8) | ucTemp[10]; - pTI->y[0] = ((ucTemp[11] & 0xf) << 8) | ucTemp[12]; - } - return 1; - } - } - return 0; - } - if (_iType == CT_TYPE_CST820) { - I2CReadRegister(_iAddr, CST820_TOUCH_REGS+1, ucTemp, 1); // read touch count - if (ucTemp[0] < 1 || ucTemp[0] > 5) { // something went wrong - return 0; - } - if (ucTemp[0] >= 1) { // touch data available, read it - pTI->count = ucTemp[0]; - I2CReadRegister(_iAddr, CST820_TOUCH_REGS+2, ucTemp, pTI->count * 6); - s = ucTemp; - for (i=0; icount; i++) { - pTI->x[i] = ((s[0] & 0xf) << 8) | s[1]; - pTI->y[i] = ((s[2] & 0xf) << 8) | s[3]; - pTI->area[i] = 1; // no data available - s += 6; - } - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } - } - if (_iType == CT_TYPE_FT6X36) { - rc = I2CReadRegister(_iAddr, TOUCH_REG_STATUS, ucTemp, 1); // read touch status - if (rc == 0) { // something went wrong - return 0; - } - i = ucTemp[0]; // number of touch points available - if (i >= 1 && i <= 5) { // get data - rc = I2CReadRegister(_iAddr, TOUCH_REG_XH, ucTemp, 6*i); // read X+Y position(s) - if ((ucTemp[0] & 0x40) == 0 && (ucTemp[2] & 0xf0) != 0xf0) { // finger is down - pTI->x[0] = ((ucTemp[0] & 0xf) << 8) | ucTemp[1]; - pTI->y[0] = ((ucTemp[2] & 0xf) << 8) | ucTemp[3]; - // get touch pressure and area - pTI->pressure[0] = ucTemp[4]; - pTI->area[0] = ucTemp[5]; - pTI->count++; - } - if (i > 1) { // get second point - if ((ucTemp[6] & 0x40) == 0 && (ucTemp[8] & 0xf0) != 0xf0) { // finger is down - pTI->x[1] = ((ucTemp[6] & 0xf) << 8) | ucTemp[7]; - pTI->y[1] = ((ucTemp[8] & 0xf) << 8) | ucTemp[9]; - // get touch pressure and area - pTI->pressure[1] = ucTemp[10]; - pTI->area[1] = ucTemp[11]; - pTI->count++; - } - } - } // if touch points available - if (_iOrientation != 0) fixSamples(pTI); - return 1; - } else { // GT911 - I2CReadRegister16(_iAddr, GT911_POINT_INFO, ucTemp, 1); // get number of touch points - i = ucTemp[0] & 0xf; // number of touches - if (i <= 5 && ucTemp[0] & 0x80) { // if buffer status is good + >= 1 touch points - ucTemp[0] = (uint8_t)(GT911_POINT_INFO >> 8); - ucTemp[1] = (uint8_t)GT911_POINT_INFO; - ucTemp[2] = 0; // clear touch info for next time - I2CWrite(_iAddr, ucTemp, 3); - - pTI->count = i; - for (int j=0; jx[j] = ucTemp[1] + (ucTemp[2] << 8); - pTI->y[j] = ucTemp[3] + (ucTemp[4] << 8); - pTI->area[j] = ucTemp[5] + (ucTemp[6] << 8); - pTI->pressure[j] = 0; - } - if (i && _iOrientation != 0) fixSamples(pTI); - return (i > 0); - } - } // GT911 - return 0; -} /* getSamples() */ - -int BBCapTouch::setOrientation(int iOrientation, int iWidth, int iHeight) -{ - if (iOrientation != 0 && iOrientation != 90 && iOrientation != 180 && iOrientation != 270) { - return CT_ERROR; - } - _iOrientation = iOrientation; - _iWidth = iWidth; - _iHeight = iHeight; - return CT_SUCCESS; -} /* setOrientation() */ - -int BBCapTouch::sensorType(void) -{ - return _iType; -} /* type() */ - -int BBCapTouch::sleep(void) -{ -uint8_t ucTemp[8]; - - if (_iType == CT_TYPE_AXS15231) { - ucTemp[0] = 0x90; // enter deep sleep - ucTemp[1] = 0xa5; - ucTemp[2] = 0x5a; - ucTemp[3] = 0x15; - ucTemp[4] = 0x23; - I2CWrite(_iAddr, ucTemp, 5); - return CT_SUCCESS; - } - if (_iType == CT_TYPE_GT911 && _iINT != -1) { - pinMode(_iINT, OUTPUT); - digitalWrite(_iINT, 0); // setting interrupt pin low to prepare sleep mode - ucTemp[0] = (uint8_t)(GT911_ENTER_SLEEP >> 8); - ucTemp[1] = (uint8_t)GT911_ENTER_SLEEP; - ucTemp[2] = 0x05; //?? - I2CWrite(_iAddr, ucTemp, 3); // enter sleep mode - return CT_SUCCESS; - } - if (_iType == CT_TYPE_CST226) { - ucTemp[0] = 0xd1; - ucTemp[1] = 0x05; - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - return CT_ERROR; -} /* sleep() */ - -int BBCapTouch::wake(void) -{ -uint8_t ucTemp[4]; - - if (_iType == CT_TYPE_AXS15231) { - digitalWrite(_iRST, 0); - delay(50); - digitalWrite(_iRST, 1); - return CT_SUCCESS; - } - if (_iType == CT_TYPE_GT911 && _iINT != -1) { - digitalWrite(_iINT, 1); // wake up the controller - delay(5); // allow it time to wake - pinMode(_iINT, INPUT); // change pin mode back to floating - } - if (_iType == CT_TYPE_CST226) { - ucTemp[0] = 0xd1; - ucTemp[1] = 0x06; - I2CWrite(_iAddr, ucTemp, 2); - return CT_SUCCESS; - } - return CT_ERROR; -} /* wake() */ - - diff --git a/grid_esp/components/grid_esp32_touch/bb_captouch.h b/grid_esp/components/grid_esp32_touch/bb_captouch.h deleted file mode 100644 index 8fa6c0bc..00000000 --- a/grid_esp/components/grid_esp32_touch/bb_captouch.h +++ /dev/null @@ -1,266 +0,0 @@ -// -// BitBank Capacitive Touch Sensor Library -// written by Larry Bank -// -// Copyright 2023 BitBank Software, Inc. All Rights Reserved. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// http://www.apache.org/licenses/LICENSE-2.0 -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -//=========================================================================== - -// -// Written for the many variants of ESP32 + Capacitive touch LCDs on the market -// -#ifdef ARDUINO -#include -#include -#else -#define INPUT 0 -#define OUTPUT 1 -#define INPUT_PULLUP 2 -#define LOW 0 -#define HIGH 1 -#include "driver/gpio.h" -#include "driver/i2c.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -static inline void delay(uint32_t ms) { vTaskDelay(pdMS_TO_TICKS(ms)); } -static inline int digitalRead(uint8_t pin) { return (int)gpio_get_level((gpio_num_t)pin); } -#endif // ARDUINO - -#ifndef __BB_CAPTOUCH__ -#define __BB_CAPTOUCH__ - -#define CT_SUCCESS 0 -#define CT_ERROR -1 -// -// Pre-configured device names -// Don't change the order of this list! -// the structure values follow it. Always -// add new values to the end -// -enum { - TOUCH_T_QT_C6=0, - TOUCH_CYD_550, - TOUCH_T_DISPLAY_S3_PRO, - TOUCH_T_DISPLAY_S3_LONG, - TOUCH_CYD_22C, - TOUCH_CYD_24C, - TOUCH_CYD_128, - TOUCH_CYD_35C, - TOUCH_CYD_518, - TOUCH_CYD_543, - TOUCH_M5_CORE2, - TOUCH_M5_CORES3, - TOUCH_M5_PAPER, - TOUCH_WT32_SC01_PLUS, - TOUCH_MAKERFABS_480x480, - TOUCH_MAKERFABS_320x480, - TOUCH_T_DISPLAY_S3_AMOLED, - TOUCH_WS_AMOLED_18, - TOUCH_M5_PAPERS3, - TOUCH_WS_ROUND_146, - TOUCH_WS_AMOLED_241, - TOUCH_WS_LCD_169, - TOUCH_VIEWE_2432, - TOUCH_T_DISPLAY_S3_AMOLED_164, - TOUCH_COUNT -}; -// structure holding the configurations -typedef struct bbct_config_tag { - int8_t i8SDA, i8SCL, i8IRQ, i8RST; -} BBCT_CONFIG; - -enum { - CT_TYPE_UNKNOWN = 0, - CT_TYPE_FT6X36, - CT_TYPE_GT911, - CT_TYPE_CST820, - CT_TYPE_CST226, - CT_TYPE_MXT144, - CT_TYPE_AXS15231, - CT_TYPE_TMA445, - CT_TYPE_SPD2010, - CT_TYPE_CHSC6540, - CT_TYPE_COUNT -}; - -#define SPD2010_ADDR 0x53 -#define GT911_ADDR1 0x5D -#define GT911_ADDR2 0x14 -#define FT6X36_ADDR1 0x38 -#define FT6X36_ADDR2 0x48 -#define CST820_ADDR 0x15 -#define CST226_ADDR 0x5A -#define CHSC6540_ADDR 0x2E -#define MXT144_ADDR 0x4A -#define TMA445_ADDR 0x24 -#define AXS15231_ADDR 0x3B - -// CST8xx gestures -enum { - GESTURE_NONE = 0, - GESTURE_SWIPE_UP, - GESTURE_SWIPE_DOWN, - GESTURE_SWIPE_LEFT, - GESTURE_SWIPE_RIGHT, - GESTURE_SINGLE_CLICK, - GESTURE_DOUBLE_CLICK = 0x0B, - GESTURE_LONG_PRESS = 0x0C -}; - -// TMA445 Security KEY -static uint8_t tma445_key[] = {0x00, 0x00, 0xFF, 0xA5, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; - -/* TrueTouch Standard Product Gen3 (Txx3xx) interface definition */ -typedef struct cyttsp_xydata_tag { - uint8_t hst_mode; - uint8_t tt_mode; - uint8_t tt_stat; - uint16_t x1 __attribute__ ((packed)); - uint16_t y1 __attribute__ ((packed)); - uint8_t z1; - uint8_t touch12_id; - uint16_t x2 __attribute__ ((packed)); - uint16_t y2 __attribute__ ((packed)); - uint8_t z2; -} cyttsp_xydata; -#define CY_HNDSHK_BIT 0x80 -typedef struct cyttsp_bootloader_data_tag { - uint8_t bl_file; - uint8_t bl_status; - uint8_t bl_error; - uint8_t blver_hi; - uint8_t blver_lo; - uint8_t bld_blver_hi; - uint8_t bld_blver_lo; - uint8_t ttspver_hi; - uint8_t ttspver_lo; - uint8_t appid_hi; - uint8_t appid_lo; - uint8_t appver_hi; - uint8_t appver_lo; - uint8_t cid_0; - uint8_t cid_1; - uint8_t cid_2; -} cyttsp_bootloader_data; - - -typedef struct mxt_data_tag { - uint16_t t2_encryption_status_address; - uint16_t t5_message_processor_address; - uint16_t t5_max_message_size; - uint16_t t6_command_processor_address; - uint16_t t7_powerconfig_address; - uint16_t t8_acquisitionconfig_address; - uint16_t t44_message_count_address; - uint16_t t46_cte_config_address; - uint16_t t100_multiple_touch_touchscreen_address; - uint16_t t100_first_report_id; -} MXTDATA; - -typedef struct mxt_object_tag { - uint8_t type; - uint16_t position; - uint8_t size_minus_one; - uint8_t instances_minus_one; - uint8_t report_ids_per_instance; -} MXTOBJECT; - -#define MXT_MESSAGE_SIZE 6 - -// CST820 registers -#define CST820_TOUCH_REGS 1 - -// GT911 registers -#define GT911_POINT_INFO 0x814E -#define GT911_POINT_1 0x814F -#define GT911_CONFIG_FRESH 0x8100 -#define GT911_CONFIG_SIZE 0xb9 -#define GT911_CONFIG_START 0x8047 -#define GT911_ENTER_SLEEP 0x8040 - -// FT6x36 registers -#define TOUCH_REG_STATUS 0x02 -#define TOUCH_REG_XH 0x03 -#define TOUCH_REG_XL 0x04 -#define TOUCH_REG_YH 0x05 -#define TOUCH_REG_YL 0x06 -#define TOUCH_REG_WEIGHT 0x07 -#define TOUCH_REG_AREA 0x08 -// register offset to info for the second touch point -#define PT2_OFFSET 6 - -#ifndef __TOUCHINFO_STRUCT__ -#define __TOUCHINFO_STRUCT__ - -typedef struct _fttouchinfo -{ - int count; - uint16_t x[5], y[5]; - uint8_t pressure[5], area[5]; -} TOUCHINFO; -#endif - -//extern TwoWire* myWire; - -class BBCapTouch -{ -public: - BBCapTouch() { _iOrientation = 0; _iType = CT_TYPE_UNKNOWN;} -// ~BBCapTouch() { Wire.end(); } -#ifdef ARDUINO - ~BBCapTouch() { myWire->end(); } -#else - ~BBCapTouch() {} -#endif - -#ifdef ARDUINO - int init(int iConfigName); - int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000, TwoWire* _myWire=&Wire); -#else - int init(int iSDA, int iSCL, int iRST=-1, int iINT=-1, uint32_t u32Speed=400000); -#endif - int getSamples(TOUCHINFO *pTI); - uint8_t interruptPin(void) {return (uint8_t)_iINT;} - int sensorType(void); - int setOrientation(int iOrientation, int iWidth, int iHeight); - int sleep(void); - int wake(void); - -protected: - void reset(int iResetPin); - -private: - int _iAddr; - int _iType; - int _iOrientation, _iWidth, _iHeight; - MXTDATA _mxtdata; - int _iINT; // interrupt GPIO pin needed for sleep/wake of GT911 - int _iRST; // reset GPIO needed for AXS15206 to wake from deep sleep -#ifdef ARDUINO - TwoWire* myWire; -#else - void pinMode(uint8_t u8Pin, uint8_t u8Mode); - void digitalWrite(uint8_t u8Pin, uint8_t u8State); -#endif - int initMXT(void); - void fixSamples(TOUCHINFO *pTI); - bool I2CTest(uint8_t u8Addr); - int I2CRead(uint8_t u8Addr, uint8_t *pData, int iLen); - int I2CReadRegister(uint8_t u8Addr, uint8_t u8Register, uint8_t *pData, int iLen); - int I2CReadRegister16(uint8_t u8Addr, uint16_t u16Register, uint8_t *pData, int iLen); - int I2CWrite(uint8_t u8Addr, uint8_t *pData, int iLen); - void SPD2010ClearInt(void); - void SPD2010CPUStart(void); - uint8_t SPD2010Status(int *iNextLen); - void SPD2010TouchStart(void); - void SPD2010PointMode(void); -}; // class BBCapTouch -#endif // __BB_CAPTOUCH__ diff --git a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp deleted file mode 100644 index 8cdf76af..00000000 --- a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ - -#include "grid_esp32_touch.h" -#include "bb_captouch.h" - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - -#include "rom/ets_sys.h" - -DRAM_ATTR struct grid_esp32_touch_model grid_esp32_touch_state; - -static struct grid_esp32_touch_model* touch_ptr = NULL; -static BBCapTouch bbc; - -void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, - grid_process_touch_t process_touch) { - - touch_ptr = touch; - touch->i2c_port = i2c_port; - touch->scl_gpio = scl_gpio; - touch->sda_gpio = sda_gpio; - touch->reset_gpio = reset_gpio; - touch->int_gpio = int_gpio; - touch->i2c_freq_hz = i2c_freq_hz; - touch->process_touch = process_touch; - - int rc = bbc.init(touch->sda_gpio, touch->scl_gpio, touch->reset_gpio, touch->int_gpio, touch->i2c_freq_hz); - if (rc == CT_SUCCESS) { - ets_printf("MXT144 init OK\r\n"); - } else { - ets_printf("MXT144 init FAILED\r\n"); - } -} - -void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch) { - - ets_printf("I2C scan (SCL=GPIO%d SDA=GPIO%d):\r\n", touch->scl_gpio, touch->sda_gpio); - int found = 0; - for (uint8_t addr = 0x08; addr < 0x78; addr++) { - i2c_cmd_handle_t cmd = i2c_cmd_link_create(); - i2c_master_start(cmd); - i2c_master_write_byte(cmd, (addr << 1) | I2C_MASTER_WRITE, true); - i2c_master_stop(cmd); - esp_err_t ret = i2c_master_cmd_begin(touch->i2c_port, cmd, pdMS_TO_TICKS(10)); - i2c_cmd_link_delete(cmd); - if (ret == ESP_OK) { - ets_printf(" found device at 0x%02X\r\n", addr); - found++; - } - } - if (found == 0) { - ets_printf(" no devices found\r\n"); - } -} - -int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI) { - (void)touch; - return bbc.getSamples(pTI); -} diff --git a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h b/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h deleted file mode 100644 index 7da47412..00000000 --- a/grid_esp/components/grid_esp32_touch/grid_esp32_touch.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD - * - * SPDX-License-Identifier: Apache-2.0 - */ -#pragma once - -#include - -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" - -#include "driver/gpio.h" -#include "driver/i2c.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef __TOUCHINFO_STRUCT__ -#define __TOUCHINFO_STRUCT__ -typedef struct _fttouchinfo { - int count; // number of pressed keys - uint32_t key_state; // T15 key bitmap (1 bit per key, up to 32 keys) - uint16_t x[5], y[5]; - uint8_t pressure[5], area[5]; -} TOUCHINFO; -#endif - -typedef void (*grid_process_touch_t)(void); - -struct grid_esp32_touch_model { - i2c_port_t i2c_port; - gpio_num_t scl_gpio; - gpio_num_t sda_gpio; - gpio_num_t reset_gpio; - gpio_num_t int_gpio; - uint32_t i2c_freq_hz; - grid_process_touch_t process_touch; -}; - -extern struct grid_esp32_touch_model grid_esp32_touch_state; - -void grid_esp32_touch_init(struct grid_esp32_touch_model* touch, i2c_port_t i2c_port, gpio_num_t scl_gpio, gpio_num_t sda_gpio, gpio_num_t reset_gpio, gpio_num_t int_gpio, uint32_t i2c_freq_hz, - grid_process_touch_t process_touch); - -void grid_esp32_touch_scan(struct grid_esp32_touch_model* touch); - -int grid_esp32_touch_get_samples(struct grid_esp32_touch_model* touch, TOUCHINFO* pTI); - -#ifdef __cplusplus -} -#endif diff --git a/maxtouch.c b/maxtouch.c deleted file mode 100644 index 367dbca7..00000000 --- a/maxtouch.c +++ /dev/null @@ -1,654 +0,0 @@ - // Copyright 2024 George Norton (@george-norton) -// SPDX-License-Identifier: GPL-2.0-or-later - -#include QMK_KEYBOARD_H -#include "i2c_master.h" -#include "maxtouch.h" - -#include "digitizer.h" -#include "digitizer_driver.h" - -#ifdef MAXTOUCH_DEBUG -# include "raw_hid.h" -#endif - -#define SWAP_BYTES(a) (((a << 8) & 0xff00) | ((a >> 8) & 0xff)) - -// Mandatory configuration. These are hardware specific. -#ifndef MXT_SENSOR_WIDTH_MM -# error "You must define the MXT_SENSOR_WIDTH_MM" -#endif - -#ifndef MXT_SENSOR_HEIGHT_MM -# error "You must define the MXT_SENSOR_HEIGHT_MM" -#endif - -// By default we assume all available X and Y pins are in use, but a designer -// may decide to leave some pins unconnected, so the size can be overridden here. -#ifndef MXT_MATRIX_X_SIZE -# define MXT_MATRIX_X_SIZE information.matrix_x_size -#endif - -#ifndef MXT_MATRIX_Y_SIZE -# define MXT_MATRIX_Y_SIZE information.matrix_y_size -#endif - -#ifndef MXT_SCROLL_DIVISOR -# define MXT_SCROLL_DIVISOR 4 -#endif - -// We detect a tap gesture if an UP event occurs within MXT_TAP_TIME -// milliseconds of the DOWN event. -#ifndef MXT_TAP_TIME -# define MXT_TAP_TIME 100 -#endif - -// We detect a tap and hold gesture if a finger does not move -// further than MXT_TAP_AND_HOLD_DISTANCE within MXT_TAP_AND_HOLD_TIME -// milliseconds of being put down on the sensor. -#ifndef MXT_TAP_AND_HOLD_TIME -# define MXT_TAP_AND_HOLD_TIME 200 -#endif -#ifndef MXT_TAP_AND_HOLD_DISTANCE -# define MXT_TAP_AND_HOLD_DISTANCE 5 -#endif - -#ifndef MXT_RECALIBRATE_AFTER -// Steps of 200ms, 25 = 5 seconds -# define MXT_RECALIBRATE_AFTER 50 -#endif - -#ifndef MXT_TOUCH_THRESHOLD -# define MXT_TOUCH_THRESHOLD 18 -#endif - -#ifndef MXT_GAIN -# define MXT_GAIN 4 -#endif - -#ifndef MXT_TOUCH_HYST -# define MXT_TOUCH_HYST 0 -#endif - -#ifndef MXT_INTERNAL_TOUCH_HYST -# define MXT_INTERNAL_TOUCH_HYST 0 -#endif - -#ifndef MXT_INTERNAL_TOUCH_THRESHOLD -# define MXT_INTERNAL_TOUCH_THRESHOLD 0 -#endif - -#ifndef MXT_DX_GAIN -# define MXT_DX_GAIN 0 -#endif - -#ifndef MXT_X_PITCH -# define MXT_X_PITCH (MXT_SENSOR_WIDTH_MM * 10 / MXT_MATRIX_X_SIZE) -#endif - -#ifndef MXT_Y_PITCH -# define MXT_Y_PITCH (MXT_SENSOR_HEIGHT_MM * 10 / MXT_MATRIX_Y_SIZE) -#endif - -#ifndef MXT_MESALLOW -# define MXT_MESALLOW 3 -#endif - -#ifndef MXT_IDLE_SYNCS_PER_X -# define MXT_IDLE_SYNCS_PER_X 0 -#endif - -#ifndef MXT_ACTIVE_SYNCS_PER_X -# define MXT_ACTIVE_SYNCS_PER_X 0 -#endif - -#ifndef MXT_IDLE_ACQUISITION_INTERVAL -# define MXT_IDLE_ACQUISITION_INTERVAL 32 -#endif - -#ifndef MXT_ACTIVE_ACQUISITION_INTERVAL -# define MXT_ACTIVE_ACQUISITION_INTERVAL 10 -#endif - -#ifndef MXT_RETRANSMISSION_COMPENSATION_ENABLE -# define MXT_RETRANSMISSION_COMPENSATION_ENABLE 1 -#endif - -#ifndef MXT_MOVE_HYSTERESIS_INITIAL -# define MXT_MOVE_HYSTERESIS_INITIAL 10 -#endif - -#ifndef MXT_MOVE_HYSTERESIS_NEXT -# define MXT_MOVE_HYSTERESIS_NEXT 4 -#endif - -#ifndef MXT_LOW_PASS_FILTER_COEFFICIENT -# define MXT_LOW_PASS_FILTER_COEFFICIENT 0 -#endif - -#ifndef MXT_CHARGE_TIME -# define MXT_CHARGE_TIME 1 -#endif - -// Any stylus event smaller than this, is treated as a hover rather than a press. -#ifndef MXT_STYLUS_HOVER_THRESHOLD -# define MXT_STYLUS_HOVER_THRESHOLD 6 -#endif - -#ifndef MXT_CONFTHR -# define MXT_CONFTHR 2 -#endif - -// Data from the object table. Registers are not at fixed addresses, they may vary between firmware -// versions. Instead must read the addresses from the object table. -static uint16_t t2_encryption_status_address = 0; -static uint16_t t5_message_processor_address = 0; -static uint16_t t5_max_message_size = 0; -static uint16_t t6_command_processor_address = 0; -static uint16_t t6_command_processor_report_id = 0; -static uint16_t t7_powerconfig_address = 0; -static uint16_t t8_acquisitionconfig_address = 0; -static uint16_t t25_self_test_address = 0; -static uint16_t t37_diagnostic_debug_address = 0; -static uint16_t t42_proci_touchsupression_address = 0; -static uint16_t t44_message_count_address = 0; -static uint16_t t46_cte_config_address = 0; -static uint16_t t47_proci_stylus_address = 0; -static uint16_t t56_proci_shieldless_address = 0; -static uint16_t t65_proci_lensbending_address = 0; -static uint16_t t80_proci_retransmissioncompensation_address = 0; -static uint16_t t100_multiple_touch_touchscreen_address = 0; - -// The object table also contains report_ids. These are used to identify which object generated a -// message. Again we must lookup these values rather than using hard coded values. -// Most messages are ignored, we basically just want the messages from the t100 object for now. -static uint16_t t25_self_test_report_id = 0; -static uint16_t t100_first_report_id = 0; -static uint16_t t100_second_report_id = 0; -static uint16_t t100_subsequent_report_ids[DIGITIZER_CONTACT_COUNT] = {}; -static uint16_t t100_num_reports = 0; -static mxt_information_block information = {0}; - -void maxtouch_print_info(void) { - // Pavonis: Found MXT 164:75, fw 16.170 with 32 objects. Matrix size 41x26 - uprintf("Found MXT %d:%d, fw %d.%d with %d objects. Matrix size %dx%d\n", information.family_id, information.variant_id, information.version, information.build, information.num_objects, information.matrix_x_size, information.matrix_y_size); -} - -void maxtouch_init(void) { -#ifdef MXT_I2CMODE_PIN - gpio_set_pin_output(MXT_I2CMODE_PIN); - gpio_write_pin_high(MXT_I2CMODE_PIN); -#endif -#ifdef MXT_RESET_PIN - gpio_set_pin_output(MXT_RESET_PIN); - gpio_write_pin_low(MXT_RESET_PIN); - wait_ms(500); - gpio_write_pin_high(MXT_RESET_PIN); - wait_ms(300); -#endif - i2c_init(); - i2c_status_t status = i2c_readReg16(MXT336UD_ADDRESS, MXT_REG_INFORMATION_BLOCK, (uint8_t *)&information, sizeof(mxt_information_block), MXT_I2C_TIMEOUT_MS); - - // First read the object table to lookup addresses and report_ids of the various objects - if (status == I2C_STATUS_SUCCESS) { - // I2C found device family: 166 with 34 objects - dprintf("Found MXT %d:%d, fw %d.%d with %d objects. Matrix size %dx%d\n", information.family_id, information.variant_id, information.version, information.build, information.num_objects, information.matrix_x_size, information.matrix_y_size); - int report_id = 1; - uint16_t object_table_element_address = sizeof(mxt_information_block); - for (int i = 0; i < information.num_objects; i++) { - mxt_object_table_element object = {}; - i2c_status_t status = i2c_readReg16(MXT336UD_ADDRESS, SWAP_BYTES(object_table_element_address), (uint8_t *)&object, sizeof(mxt_object_table_element), MXT_I2C_TIMEOUT_MS); - if (status == I2C_STATUS_SUCCESS) { - // Store addresses in network byte order - const uint16_t address = object.position_ms_byte | (object.position_ls_byte << 8); - switch (object.type) { - case 2: - t2_encryption_status_address = address; - break; - case 5: - t5_message_processor_address = address; - t5_max_message_size = object.size_minus_one - 1; - break; - case 6: - t6_command_processor_address = address; - t6_command_processor_report_id = report_id; - break; - case 7: - t7_powerconfig_address = address; - break; - case 8: - t8_acquisitionconfig_address = address; - break; - case 25: - t25_self_test_address = address; - t25_self_test_report_id = report_id; - break; - case 37: - t37_diagnostic_debug_address = address; - break; - case 42: - t42_proci_touchsupression_address = address; - break; - case 44: - t44_message_count_address = address; - break; - case 46: - t46_cte_config_address = address; - break; - case 47: - t47_proci_stylus_address = address; - break; - case 56: - t56_proci_shieldless_address = address; - break; - case 65: - t65_proci_lensbending_address = address; - break; - case 80: - t80_proci_retransmissioncompensation_address = address; - break; - case 100: - t100_multiple_touch_touchscreen_address = address; - t100_first_report_id = report_id; - t100_second_report_id = report_id + 1; - for (t100_num_reports = 0; t100_num_reports < DIGITIZER_CONTACT_COUNT && t100_num_reports < object.report_ids_per_instance; t100_num_reports++) { - t100_subsequent_report_ids[t100_num_reports] = report_id + 2 + t100_num_reports; - } - break; - } - object_table_element_address += sizeof(mxt_object_table_element); - report_id += object.report_ids_per_instance * (object.instances_minus_one + 1); - } else { - dprintf("Failed to read object table element. Status: %d\n", status); - } - } - } else { - dprintf("Failed to read object table. Status: %d\n", status); - } - - // TODO Remove? Maybe not interesting unless for whatever reason encryption is enabled and we need to turn it off - if (t2_encryption_status_address) { - mxt_gen_encryptionstatus_t2 t2 = {}; - i2c_status_t status = i2c_readReg16(MXT336UD_ADDRESS, t2_encryption_status_address, (uint8_t *)&t2, sizeof(mxt_gen_encryptionstatus_t2), MXT_I2C_TIMEOUT_MS); - if (status != I2C_STATUS_SUCCESS) { - dprintf("Failed to read T2. Status: %02x %d\n", t2.status, t2.error); - } - } - - // Configure power saving features - if (t7_powerconfig_address) { - mxt_gen_powerconfig_t7 t7 = {}; - t7.idleacqint = MXT_IDLE_ACQUISITION_INTERVAL; // The acquisition interval while in idle mode. 255 is free-running (as fast as possible). - t7.actacqint = MXT_ACTIVE_ACQUISITION_INTERVAL; // The acquisition interval while in active mode. 255 is free-running (as fast as possible). - t7.actv2idelto = 50; // The timeout for transitioning from active to idle mode - t7.cfg = T7_CFG_ACTVPIPEEN | T7_CFG_IDLEPIPEEN; // Enable pipelining in both active and idle mode - - i2c_writeReg16(MXT336UD_ADDRESS, t7_powerconfig_address, (uint8_t *)&t7, sizeof(mxt_gen_powerconfig_t7), MXT_I2C_TIMEOUT_MS); - } - - // Configure capacitive acquision, currently we use all the default values but it feels like some of this stuff might be important. - if (t8_acquisitionconfig_address) { - mxt_gen_acquisitionconfig_t8 t8 = {}; - t8.chrgtime = MXT_CHARGE_TIME; - t8.tchautocal = MXT_RECALIBRATE_AFTER; - t8.atchcalst = 0; - - // Antitouch detection - reject palms etc.. - t8.atchcalsthr = 50; - t8.atchfrccalthr = 50; - t8.atchfrccalratio = 25; - t8.measallow = MXT_MESALLOW; - - i2c_writeReg16(MXT336UD_ADDRESS, t8_acquisitionconfig_address, (uint8_t *)&t8, sizeof(mxt_gen_acquisitionconfig_t8), MXT_I2C_TIMEOUT_MS); - } - -#ifdef DIGITIZER_HAS_STYLUS - if (t42_proci_touchsupression_address) { - mxt_proci_touchsupression_t42 t42 = {}; - - t42.ctrl = T42_CTRL_ENABLE | T42_CTRL_SHAPEEN; - t42.maxapprarea = 0; // Default (0): suppress any touch that approaches >40 channels. - t42.maxtcharea = 0; // Default (0): suppress any touch that covers >35 channels. - t42.maxnumtchs = 6; // Suppress all touches if >6 are detected. - t42.supdist = 0; // Default (0): Suppress all touches within 5 nodes of a suppressed large object detection. - t42.disthyst = 0; - t42.supstrength = 0; // Default (0): suppression strength of 128. - t42.supextto = 0; // Timeout to save power; set to 0 to disable. - t42.shapestrength = 0; // Default (0): shape suppression strength of 10, range [0, 31]. - t42.maxscrnarea = 0; - t42.edgesupstrength = 0; - t42.cfg = 1; - i2c_writeReg16(MXT336UD_ADDRESS, t42_proci_touchsupression_address, (uint8_t *)&t42, sizeof(mxt_proci_touchsupression_t42), MXT_I2C_TIMEOUT_MS); - } -#endif - - // Mutural Capacitive Touch Engine (CTE) configuration, currently we use all the default values but it feels like some of this stuff might be important. - if (t46_cte_config_address) { - mxt_spt_cteconfig_t46 t46 = {}; - t46.idlesyncsperx = MXT_IDLE_SYNCS_PER_X; // ADC samples per X. - t46.activesyncsperx = MXT_ACTIVE_SYNCS_PER_X; // ADC samples per X. - t46.inrushcfg = 0; // Set Y-line inrush limit resistors. - - i2c_writeReg16(MXT336UD_ADDRESS, t46_cte_config_address, (uint8_t *)&t46, sizeof(mxt_spt_cteconfig_t46), MXT_I2C_TIMEOUT_MS); - } - -#ifdef DIGITIZER_HAS_STYLUS - if (t47_proci_stylus_address) { - mxt_proci_stylus_t47 t47 = {}; - t47.ctrl = 1; // Enable stylus detection - t47.cfg = T47_CFG_SUPSTY; // Supress stylus detections when normal touches are present. - t47.contmax = 80; // The maximum contact diameter of the stylus in 0.1mm increments - t47.maxtcharea = 100; // Maximum touch area a contact can have an still be considered a stylus - t47.stability = 30; // Higher values prevent the stylus from dropping out when it gets small - t47.confthr = 6; // Higher values increase the chances of correctly detecting as stylus, but introduce a delay - t47.amplthr = 60; // Any touches smaller than this are classified as stylus touches - t47.supstyto = 5; // Continue to suppress stylus touches until supstyto x 200ms after the last touch is removed. - t47.hoversup = 200; // 255 Disables hover supression - t47.maxnumsty = 1; // Only report a single stylus - i2c_writeReg16(MXT336UD_ADDRESS, t47_proci_stylus_address, (uint8_t *)&t47, sizeof(mxt_proci_stylus_t47), MXT_I2C_TIMEOUT_MS); - } -#endif - - if (t80_proci_retransmissioncompensation_address) { - mxt_proci_retransmissioncompensation_t80 t80 = {}; - t80.ctrl = MXT_RETRANSMISSION_COMPENSATION_ENABLE; - t80.compgain = 5; - t80.targetdelta = 125; - t80.compthr = 60; - i2c_writeReg16(MXT336UD_ADDRESS, t80_proci_retransmissioncompensation_address, (uint8_t *)&t80, sizeof(mxt_proci_retransmissioncompensation_t80), MXT_I2C_TIMEOUT_MS); - } - - // Multiple touch touchscreen confguration - defines an area of the sensor to use as a trackpad/touchscreen. This object generates all our interesting report messages. - if (t100_multiple_touch_touchscreen_address) { - mxt_touch_multiscreen_t100 cfg = {}; - - cfg.ctrl = T100_CTRL_RPTEN | T100_CTRL_ENABLE | T100_CTRL_SCANEN; // Enable the t100 object, and enable message reporting for the t100 object.1. Also enable close scanning mode. - // TODO: Generic handling of rotation/inversion for absolute mode? - uint8_t rotation = 0; -#ifdef MXT_INVERT_X - rotation |= T100_CFG_INVERTX; -#endif -#ifdef MXT_INVERT_Y - rotation |= T100_CFG_INVERTY; -#endif -#ifdef MXT_SWITCH_XY - rotation |= T100_CFG_SWITCHXY; -#endif - cfg.cfg1 = rotation; - cfg.scraux = 0x7; // AUX data: Report the number of touch events, touch area, anti touch area - cfg.tchaux = 0x2; // report amplitude - cfg.tcheventcfg = 24; // Disable reporting suppressed events - cfg.numtch = DIGITIZER_CONTACT_COUNT; // The number of touch reports we want to receive (upto 10) - cfg.xsize = MXT_MATRIX_X_SIZE; // Make configurable as this depends on the sensor design. - cfg.ysize = MXT_MATRIX_Y_SIZE; // Make configurable as this depends on the sensor design. - cfg.xpitch = MXT_X_PITCH; // Pitch between X-Lines in 0.1mm increments. - cfg.ypitch = MXT_Y_PITCH; // Pitch between Y-Lines in 0.1mm increments. - cfg.xedgecfg = 9; - cfg.xedgedist = 10; - cfg.yedgecfg = 9; - cfg.yedgedist = 10; - cfg.gain = MXT_GAIN; // Single transmit gain for mutual capacitance measurements - cfg.dxgain = MXT_DX_GAIN; // Dual transmit gain for mutual capacitance measurements (255 = auto calibrate) - cfg.tchthr = MXT_TOUCH_THRESHOLD; // Touch threshold - cfg.tchhyst = MXT_TOUCH_HYST; - cfg.intthr = MXT_INTERNAL_TOUCH_THRESHOLD; - cfg.intthryst = MXT_INTERNAL_TOUCH_HYST; - cfg.mrgthr = 5; // Merge threshold - cfg.mrghyst = 10; // Merge threshold hysteresis - cfg.mrgthradjstr = 20; - cfg.movsmooth = 0; // The amount of smoothing applied to movements, this tails off at higher speeds - cfg.movfilter = 0; // The lower 4 bits are the speed response value, higher values reduce lag, but also smoothing - // These two fields implement a simple filter for reducing jitter, but large values cause the pointer to stick in place before moving. - cfg.movhysti = MXT_MOVE_HYSTERESIS_INITIAL; // Initial movement hysteresis - cfg.movhystn = MXT_MOVE_HYSTERESIS_NEXT; // Next movement hysteresis - - cfg.tchdiup = 4; // MXT_UP touch detection integration - the number of cycles before the sensor decides an MXT_UP event has occurred - cfg.tchdidown = 2; // MXT_DOWN touch detection integration - the number of cycles before the sensor decides an MXT_DOWN event has occurred - cfg.nexttchdi = 2; - cfg.calcfg = 0; -#ifdef MXT_SWITCH_XY - cfg.xrange = DIGITIZER_RESOLUTION_Y - 1; // The logical and physical resolution is reported in our USB descriptor - cfg.yrange = DIGITIZER_RESOLUTION_X - 1; // the host uses this to set the speed of the pointer. -#else - cfg.xrange = DIGITIZER_RESOLUTION_X - 1; // The logical and physical resolution is reported in our USB descriptor - cfg.yrange = DIGITIZER_RESOLUTION_Y - 1; // the host uses this to set the speed of the pointer. -#endif - cfg.cfg2 = MXT_CONFTHR; // Touch debounce - - i2c_status_t status = i2c_writeReg16(MXT336UD_ADDRESS, t100_multiple_touch_touchscreen_address, (uint8_t *)&cfg, sizeof(mxt_touch_multiscreen_t100), MXT_I2C_TIMEOUT_MS); - if (status != I2C_STATUS_SUCCESS) { - dprintf("T100 Configuration failed: %d\n", status); - } - } - - // Configure shieldless and lensbending objects to provide some additional resistance - // against bad behaviour. -#ifdef MXT_T56_SHIELDLESS_ENABLE - if (t56_proci_shieldless_address) { - mxt_proci_shieldless_t56 t56 = {}; - t56.ctrl = T56_CTRL_ENABLE; - t56.optint = 1; - t56.inttime = 10; - i2c_writeReg16(MXT336UD_ADDRESS, t56_proci_shieldless_address, (uint8_t *)&t56, sizeof(mxt_proci_shieldless_t56), MXT_I2C_TIMEOUT_MS); - } -#endif -#ifdef MXT_T65_LENS_BENDING_ENABLE - if (t65_proci_lensbending_address) { - mxt_proci_lensbending_t65 t65 = {}; - t65.ctrl = T65_CTRL_ENABLE; - t65.lpfiltcoef = MXT_LOW_PASS_FILTER_COEFFICIENT; // default (0): 5, range 1 to 15. - i2c_writeReg16(MXT336UD_ADDRESS, t65_proci_lensbending_address, (uint8_t *)&t65, sizeof(mxt_proci_lensbending_t65), MXT_I2C_TIMEOUT_MS); - } -#endif -} - -// Store state different from report so we can report MXT_DOWNUP as MXT_DOWN, but remember we are MXT_UP -digitizer_t maxtouch_get_report(digitizer_t digitizer_report) { - if (t44_message_count_address) { - mxt_message_count message_count = {}; - - i2c_status_t status = i2c_readReg16(MXT336UD_ADDRESS, t44_message_count_address, (uint8_t *)&message_count, sizeof(mxt_message_count), MXT_I2C_TIMEOUT_MS); - if (status == I2C_STATUS_SUCCESS) { - for (int i = 0; i < message_count.count; i++) { - mxt_message message = {}; - status = i2c_readReg16(MXT336UD_ADDRESS, t5_message_processor_address, (uint8_t *)&message, sizeof(mxt_message), MXT_I2C_TIMEOUT_MS); - - if (message.report_id == t100_first_report_id) { - const uint8_t fingers = message.data[1]; -#ifdef MAXTOUCH_BOOTLOADER_GESTURE - // Debug feature - reboot to bootloader if 5 fingers are MXT_DOWN - // TODO: A better gesture. - if (fingers == 5) reset_keyboard(); -#endif - if (fingers == 0) { - // Belt and braces, make sure we dont have any stuck contacts - for (int j = 0; j < DIGITIZER_CONTACT_COUNT; j++) { - digitizer_report.contacts[j].type = UNKNOWN; - digitizer_report.contacts[j].tip = false; - digitizer_report.contacts[j].in_range = false; - digitizer_report.contacts[j].confidence = false; - } - } - } else if (message.report_id == t25_self_test_report_id) { - const uint8_t result = message.data[0]; - switch (result) { - case T25_TEST_PASSED: - uprintf("Self Tests passed\n"); - break; - case T25_TEST_INVALID: - uprintf("Invalid self test command\n"); - break; - case T25_TEST_POWER: - uprintf("Power fault detected\n"); - break; - case T25_TEST_PIN_FAULT: - uprintf("Pin fault detected. Seq %d, pin %dx%d\n", message.data[2], message.data[3], message.data[4]); - break; - case T25_TEST_SIGNAL_LIMIT: - uprintf("Signal limit fault detected\n"); - break; - } - } else if ((message.report_id >= t100_subsequent_report_ids[0]) && (message.report_id <= t100_subsequent_report_ids[t100_num_reports - 1])) { - const uint8_t contact_id = message.report_id - t100_subsequent_report_ids[0]; - const int event = (message.data[0] & 0xf); - const int type = (message.data[0] >> 4) & 0x7; - const uint16_t x = message.data[1] | (message.data[2] << 8); - const uint16_t y = message.data[3] | (message.data[4] << 8); - const uint8_t ampl = message.data[5]; - // uprintf("EVT[%u] %d %d %ux%u %u\n", contact_id, event, type, x, y, ampl); - - switch (type) { - case MXT_FINGER: - digitizer_report.contacts[contact_id].type = FINGER; - break; - case MXT_PASSIVE_STYLUS: - digitizer_report.contacts[contact_id].type = STYLUS; - break; - default: - digitizer_report.contacts[contact_id].type = UNKNOWN; - break; - } - - digitizer_report.contacts[contact_id].in_range = true; - - if (type == MXT_FINGER) { - if (event == MXT_DOWN || event == MXT_MOVE) { - digitizer_report.contacts[contact_id].tip = true; - } - } - else if (type == MXT_PASSIVE_STYLUS) { - digitizer_report.contacts[contact_id].tip = ampl > MXT_STYLUS_HOVER_THRESHOLD; - } - - if (event == MXT_UP || event == MXT_UNSUPSUP) { - digitizer_report.contacts[contact_id].tip = false; - } - - if (event == MXT_MOVE || event == MXT_DOWN || event == MXT_DOWNSUP || event == MXT_UP || event == MXT_UNSUPUP || event == MXT_UNSUP) { - digitizer_report.contacts[contact_id].x = x; - digitizer_report.contacts[contact_id].y = y; - } - if (event == MXT_SUP || event == MXT_UNSUPSUP || event == MXT_DOWNSUP) { - digitizer_report.contacts[contact_id].confidence = 0; - } else { - digitizer_report.contacts[contact_id].confidence = 1; - } - } else if (message.report_id == t6_command_processor_report_id) { - const uint8_t status = message.data[0]; - uprintf("T6 status: RESET: %d, OFL: %d. SIGERR: %d, CAL: %d, CFGERR: %d. COMSERR: %d\n", status & (1 << 7) ? 1 : 0, status & (1 << 6) ? 1 : 0, status & (1 << 5) ? 1 : 0, status & (1 << 4) ? 1 : 0, status & (1 << 3) ? 1 : 0, status & (1 << 2) ? 1 : 0); - // Run all self tests after a reset - if (t25_self_test_address && status & (1 << 7)) { - mxt_spt_selftest_t25 t25 = {}; - t25.ctrl = 0x3; - t25.cmd = T25_TEST_ALL; - - // Min/Max values from the 1066u datasheet - t25.losiglim_msb = 0x44; // 17500 - t25.losiglim_lsb = 0x5c; - t25.upsiglim_msb = 0x79; // 31000 - t25.upsiglim_lsb = 0x18; - - // Observed reference signal is approx 6000, and we get - // a 700 delta when touching. So create a range of 7000. - t25.sigrangelim_lsb = 0x58; - t25.sigrangelim_msb = 0x1B; - - t25.sesiglimits[1] = MXT_GAIN; - t25.sesiglimits[2] = MXT_DX_GAIN; - - i2c_writeReg16(MXT336UD_ADDRESS, t25_self_test_address, (uint8_t *)&t25, sizeof(mxt_spt_selftest_t25), MXT_I2C_TIMEOUT_MS); - } - } else { - uprintf("Unhandled event %d (%02x %02x %02x %02x %02x %02x) %d\n", message.report_id, message.data[0], message.data[1], message.data[2], message.data[3], message.data[4], message.data[5], t25_self_test_report_id); - } - } - } - } - return digitizer_report; -} - -#ifdef MAXTOUCH_DEBUG -# define MAXTOUCH_DEBUG_MAGIC 0x9A4D -# define MAXTOUCH_DEBUG_VERSION 0x0001 - -typedef enum { - MAXTOUCH_DEBUG_CHECK_VERSION, - MAXTOUCH_DEBUG_COMMAND, - MAXTOUCH_DEBUG_READ, - MAXTOUCH_DEBUG_WRITE, -} maxtouch_debug_command; - -typedef enum { MAXTOUCH_DEBUG_REBOOT_BOOTLOADER, MAXTOUCH_DEBUG_SET_MOUSE_MODE, MAXTOUCH_DEBUG_GET_MOUSE_MODE } maxtouch_debug_command_type; - -typedef enum { MAXTOUCH_DEBUG_OK, MAXTOUCH_DEBUG_INVALID_VERSION, MAXTOUCH_DEBUG_INVALID_CMD, MAXTOUCH_DEBUG_INVALID_LENGTH, MAXTOUCH_DEBUG_I2C_ERR } maxtouch_debug_status; - -void raw_hid_receive(uint8_t *data, uint8_t length) { - maxtouch_debug_status status = MAXTOUCH_DEBUG_OK; - maxtouch_debug_command cmd = (maxtouch_debug_command)data[0]; - - switch (cmd) { - case MAXTOUCH_DEBUG_CHECK_VERSION: { - const uint16_t magic = (data[1] << 8) | data[2]; - const uint16_t version = (data[3] << 8) | data[4]; - if (magic != MAXTOUCH_DEBUG_MAGIC || version != MAXTOUCH_DEBUG_VERSION) { - status = MAXTOUCH_DEBUG_INVALID_VERSION; - } - break; - } - case MAXTOUCH_DEBUG_COMMAND: { - const maxtouch_debug_command_type cmd_type = data[1]; - switch (cmd_type) { - case MAXTOUCH_DEBUG_REBOOT_BOOTLOADER: - reset_keyboard(); - break; -#if defined(POINTING_DEVICE_DRIVER_digitizer) - case MAXTOUCH_DEBUG_SET_MOUSE_MODE: { - extern bool digitizer_send_mouse_reports; - digitizer_send_mouse_reports = (bool)data[2]; - break; - } - case MAXTOUCH_DEBUG_GET_MOUSE_MODE: { - extern bool digitizer_send_mouse_reports; - data[1] = digitizer_send_mouse_reports; - break; - } -#endif - default: - status = MAXTOUCH_DEBUG_INVALID_CMD; - break; - } - break; - } - case MAXTOUCH_DEBUG_READ: { - const uint16_t read_address = (data[1] << 8) | data[2]; - const uint16_t read_length = data[3]; - if (read_length > 0x1c) { - status = MAXTOUCH_DEBUG_INVALID_LENGTH; - } else { - if (i2c_readReg16(MXT336UD_ADDRESS, read_address, (uint8_t *)&data[4], read_length, MXT_I2C_TIMEOUT_MS) != I2C_STATUS_SUCCESS) { - status = MAXTOUCH_DEBUG_I2C_ERR; - } - } - break; - } - case MAXTOUCH_DEBUG_WRITE: { - const uint16_t write_address = (data[1] << 8) | data[2]; - const uint16_t write_length = data[3]; - if (write_length > 0x1c) { - status = MAXTOUCH_DEBUG_INVALID_LENGTH; - } else { - if (i2c_writeReg16(MXT336UD_ADDRESS, write_address, (uint8_t *)&data[4], write_length, MXT_I2C_TIMEOUT_MS) != I2C_STATUS_SUCCESS) { - status = MAXTOUCH_DEBUG_I2C_ERR; - } - } - break; - } - default: { - status = MAXTOUCH_DEBUG_INVALID_CMD; - } - } - - data[0] = (uint8_t)status; - raw_hid_send(data, length); -} -#endif From 863850b5a9082bfeee7813aa3c0eb606dcab696a Mon Sep 17 00:00:00 2001 From: sukuwc Date: Tue, 5 May 2026 14:05:09 +0200 Subject: [PATCH 7/9] SUKU xy module with events --- common/src/c/grid_module.c | 12 ++- common/src/c/grid_protocol.h | 47 ++++++++- common/src/c/grid_ui.c | 1 + common/src/c/grid_ui_touch.c | 98 +++++++++++++++++++ common/src/c/grid_ui_touch.h | 42 ++++++++ .../grid_esp32_module_xy.c | 23 +++-- 6 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 common/src/c/grid_ui_touch.c create mode 100644 common/src/c/grid_ui_touch.h diff --git a/common/src/c/grid_module.c b/common/src/c/grid_module.c index d5c22eb5..06346117 100644 --- a/common/src/c/grid_module.c +++ b/common/src/c/grid_module.c @@ -13,6 +13,7 @@ #include "grid_ui_lcd.h" #include "grid_ui_potmeter.h" #include "grid_ui_system.h" +#include "grid_ui_touch.h" extern struct luaL_Reg* grid_lua_api_gui_lib_reference; @@ -60,6 +61,9 @@ void grid_lua_ui_init(struct grid_lua_model* lua) { case GRID_PARAMETER_ELEMENT_LCD: { GRID_LUA_UI_INIT_ASSIGN(GRID_LUA_L); } break; + case GRID_PARAMETER_ELEMENT_TOUCH: { + GRID_LUA_UI_INIT_ASSIGN(GRID_LUA_T); + } break; default: assert(0); break; @@ -261,10 +265,12 @@ void grid_module_xy_ui_init(struct grid_ain_model* ain, struct grid_led_model* l grid_led_init(led, 25); grid_led_lookup_alloc_identity(led, 0, 25); - grid_ui_model_init(ui, 1); + grid_ui_model_init(ui, 6); - struct grid_ui_element* ele = grid_ui_element_model_init(ui, 0); - grid_ui_element_system_init(ele); + for (uint8_t i = 0; i < 5; i++) { + grid_ui_element_touch_init(grid_ui_element_model_init(ui, i)); + } + grid_ui_element_system_init(grid_ui_element_model_init(ui, 5)); ui->lua_ui_init_callback = grid_lua_ui_init; } diff --git a/common/src/c/grid_protocol.h b/common/src/c/grid_protocol.h index c31dfecb..6f94a482 100644 --- a/common/src/c/grid_protocol.h +++ b/common/src/c/grid_protocol.h @@ -26,7 +26,8 @@ #define GRID_PARAMETER_ELEMENT_ENCODER 3 #define GRID_PARAMETER_ELEMENT_ENDLESS 4 #define GRID_PARAMETER_ELEMENT_LCD 5 -#define GRID_PARAMETER_ELEMENT_COUNT 6 +#define GRID_PARAMETER_ELEMENT_TOUCH 6 +#define GRID_PARAMETER_ELEMENT_COUNT 7 // must not change because it would break profiles #define GRID_PARAMETER_EVENT_INIT 0 @@ -38,7 +39,8 @@ #define GRID_PARAMETER_EVENT_TIMER 6 #define GRID_PARAMETER_EVENT_ENDLESS 7 #define GRID_PARAMETER_EVENT_DRAW 8 -#define GRID_PARAMETER_EVENT_COUNT 9 +#define GRID_PARAMETER_EVENT_TOUCH 9 +#define GRID_PARAMETER_EVENT_COUNT 10 // Module HWCFG definitions @@ -807,6 +809,44 @@ #define GRID_LUA_FNC_S_LIST_length 1 +#define GRID_LUA_FNC_T_ELEMENT_INDEX_index 0 +#define GRID_LUA_FNC_T_ELEMENT_INDEX_short "ind" +#define GRID_LUA_FNC_T_ELEMENT_INDEX_human "element_index" + +#define GRID_LUA_FNC_T_LED_INDEX_index 1 +#define GRID_LUA_FNC_T_LED_INDEX_short "lix" +#define GRID_LUA_FNC_T_LED_INDEX_human "led_index" + +#define GRID_LUA_FNC_T_TOUCH_X_index 2 +#define GRID_LUA_FNC_T_TOUCH_X_short "tsx" +#define GRID_LUA_FNC_T_TOUCH_X_human "touch_x" + +#define GRID_LUA_FNC_T_TOUCH_X_MIN_index 3 +#define GRID_LUA_FNC_T_TOUCH_X_MIN_short "txmi" +#define GRID_LUA_FNC_T_TOUCH_X_MIN_human "touch_x_min" + +#define GRID_LUA_FNC_T_TOUCH_X_MAX_index 4 +#define GRID_LUA_FNC_T_TOUCH_X_MAX_short "txma" +#define GRID_LUA_FNC_T_TOUCH_X_MAX_human "touch_x_max" + +#define GRID_LUA_FNC_T_TOUCH_Y_index 5 +#define GRID_LUA_FNC_T_TOUCH_Y_short "tsy" +#define GRID_LUA_FNC_T_TOUCH_Y_human "touch_y" + +#define GRID_LUA_FNC_T_TOUCH_Y_MIN_index 6 +#define GRID_LUA_FNC_T_TOUCH_Y_MIN_short "tymi" +#define GRID_LUA_FNC_T_TOUCH_Y_MIN_human "touch_y_min" + +#define GRID_LUA_FNC_T_TOUCH_Y_MAX_index 7 +#define GRID_LUA_FNC_T_TOUCH_Y_MAX_short "tyma" +#define GRID_LUA_FNC_T_TOUCH_Y_MAX_human "touch_y_max" + +#define GRID_LUA_FNC_T_TOUCH_AREA_index 8 +#define GRID_LUA_FNC_T_TOUCH_AREA_short "tar" +#define GRID_LUA_FNC_T_TOUCH_AREA_human "touch_area" + +#define GRID_LUA_FNC_T_LIST_length 9 + // ========================= UI EVENT HANDLER FUNCTIONS =========================== // #define GRID_LUA_FNC_A_INIT_short "ini" @@ -836,6 +876,9 @@ #define GRID_LUA_FNC_A_DRAW_short "ld" #define GRID_LUA_FNC_A_DRAW_human "draw_handler" +#define GRID_LUA_FNC_A_TOUCH_short "tc" +#define GRID_LUA_FNC_A_TOUCH_human "touch_handler" + #define GRID_LUA_KW_ELEMENT_short "ele" #define GRID_LUA_KW_ELEMENT_human "element" diff --git a/common/src/c/grid_ui.c b/common/src/c/grid_ui.c index 406882d6..5e383528 100644 --- a/common/src/c/grid_ui.c +++ b/common/src/c/grid_ui.c @@ -64,6 +64,7 @@ void grid_ele_eve_to_value_idx_init(uint8_t map[GRID_PARAMETER_ELEMENT_COUNT][GR map[GRID_PARAMETER_ELEMENT_ENCODER][GRID_PARAMETER_EVENT_ENCODER] = GRID_LUA_FNC_E_ENCODER_VALUE_index; map[GRID_PARAMETER_ELEMENT_ENDLESS][GRID_PARAMETER_EVENT_BUTTON] = GRID_LUA_FNC_EP_BUTTON_VALUE_index; map[GRID_PARAMETER_ELEMENT_ENDLESS][GRID_PARAMETER_EVENT_ENDLESS] = GRID_LUA_FNC_EP_ENDLESS_VALUE_index; + map[GRID_PARAMETER_ELEMENT_TOUCH][GRID_PARAMETER_EVENT_TOUCH] = GRID_LUA_FNC_T_TOUCH_X_index; } struct grid_ui_model grid_ui_state = {0}; diff --git a/common/src/c/grid_ui_touch.c b/common/src/c/grid_ui_touch.c new file mode 100644 index 00000000..ee2f2d89 --- /dev/null +++ b/common/src/c/grid_ui_touch.c @@ -0,0 +1,98 @@ +#include "grid_ui_touch.h" + +#include +#include +#include + +#include "grid_lua_api.h" +#include "grid_math.h" +#include "grid_platform.h" +#include "grid_ui_system.h" + +const luaL_Reg GRID_LUA_T_INDEX_META[] = {{GRID_LUA_FNC_T_ELEMENT_INDEX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_ELEMENT_INDEX_index)}, + {GRID_LUA_FNC_T_LED_INDEX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_LED_INDEX_index)}, + {GRID_LUA_FNC_T_TOUCH_X_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_X_index)}, + {GRID_LUA_FNC_T_TOUCH_Y_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_Y_index)}, + {GRID_LUA_FNC_T_TOUCH_AREA_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_AREA_index)}, + {GRID_LUA_FNC_T_TOUCH_X_MIN_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_X_MIN_index)}, + {GRID_LUA_FNC_T_TOUCH_X_MAX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_X_MAX_index)}, + {GRID_LUA_FNC_T_TOUCH_Y_MIN_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_Y_MIN_index)}, + {GRID_LUA_FNC_T_TOUCH_Y_MAX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_Y_MAX_index)}, + {GRID_LUA_FNC_G_TIMER_START_short, XAFTERX(GRID_LUA_FNC_META_NAME, gtt)}, + {GRID_LUA_FNC_G_TIMER_STOP_short, XAFTERX(GRID_LUA_FNC_META_NAME, gtp)}, + {GRID_LUA_FNC_G_EVENT_TRIGGER_short, XAFTERX(GRID_LUA_FNC_META_NAME, get)}, + {GRID_LUA_FNC_G_ELEMENTNAME_SET_short, XAFTERX(GRID_LUA_FNC_META_NAME, gsen)}, + {GRID_LUA_FNC_G_ELEMENTNAME_GET_short, XAFTERX(GRID_LUA_FNC_META_NAME, ggen)}, + {NULL, NULL}}; + +void grid_ui_element_touch_init(struct grid_ui_element* ele) { + + ele->type = GRID_PARAMETER_ELEMENT_TOUCH; + + ele->primary_state = grid_platform_allocate_volatile(sizeof(struct grid_ui_touch_state)); + memset(ele->primary_state, 0, sizeof(struct grid_ui_touch_state)); + ((struct grid_ui_touch_state*)ele->primary_state)->parent = ele; + + grid_ui_element_malloc_events(ele, 3); + grid_ui_event_init(ele, 0, GRID_PARAMETER_EVENT_INIT, GRID_LUA_FNC_A_INIT_short, GRID_ACTIONSTRING_TOUCH_INIT); + grid_ui_event_init(ele, 1, GRID_PARAMETER_EVENT_TOUCH, GRID_LUA_FNC_A_TOUCH_short, GRID_ACTIONSTRING_TOUCH_TOUCH); + grid_ui_event_init(ele, 2, GRID_PARAMETER_EVENT_TIMER, GRID_LUA_FNC_A_TIMER_short, GRID_ACTIONSTRING_SYSTEM_TIMER); + + ele->template_initializer = &grid_ui_element_touch_template_parameter_init; + ele->template_parameter_list_length = GRID_LUA_FNC_T_LIST_length; + + ele->event_clear_cb = NULL; + ele->page_change_cb = NULL; +} + +void grid_ui_element_touch_template_parameter_init(struct grid_ui_template_buffer* buf) { + + uint8_t element_index = buf->parent->index; + int32_t* template_parameter_list = buf->template_parameter_list; + + template_parameter_list[GRID_LUA_FNC_T_ELEMENT_INDEX_index] = element_index; + template_parameter_list[GRID_LUA_FNC_T_LED_INDEX_index] = element_index; + template_parameter_list[GRID_LUA_FNC_T_TOUCH_X_index] = 0; + template_parameter_list[GRID_LUA_FNC_T_TOUCH_Y_index] = 0; + template_parameter_list[GRID_LUA_FNC_T_TOUCH_AREA_index] = 0; + template_parameter_list[GRID_LUA_FNC_T_TOUCH_X_MIN_index] = 0; + template_parameter_list[GRID_LUA_FNC_T_TOUCH_X_MAX_index] = 127; + template_parameter_list[GRID_LUA_FNC_T_TOUCH_Y_MIN_index] = 0; + template_parameter_list[GRID_LUA_FNC_T_TOUCH_Y_MAX_index] = 127; +} + +static int32_t touch_scale(uint16_t raw, int32_t out_min, int32_t out_max) { + int32_t scaled = out_min + ((int64_t)raw * (out_max - out_min)) / 1023; + return clampi32(scaled, MIN(out_min, out_max), MAX(out_min, out_max)); +} + +void grid_ui_touch_store_input(struct grid_ui_touch_state* state, uint16_t x, uint16_t y, uint8_t area) { + + struct grid_ui_element* ele = state->parent; + int32_t* tpl = ele->template_parameter_list; + + state->x = x; + state->y = y; + state->area = area; + + x = 1023 - x; + + int32_t x_min = tpl[GRID_LUA_FNC_T_TOUCH_X_MIN_index]; + int32_t x_max = tpl[GRID_LUA_FNC_T_TOUCH_X_MAX_index]; + int32_t y_min = tpl[GRID_LUA_FNC_T_TOUCH_Y_MIN_index]; + int32_t y_max = tpl[GRID_LUA_FNC_T_TOUCH_Y_MAX_index]; + + int32_t new_x = touch_scale(x, x_min, x_max); + int32_t new_y = touch_scale(y, y_min, y_max); + + bool changed = (new_x != tpl[GRID_LUA_FNC_T_TOUCH_X_index]) || (new_y != tpl[GRID_LUA_FNC_T_TOUCH_Y_index]); + + tpl[GRID_LUA_FNC_T_TOUCH_X_index] = new_x; + tpl[GRID_LUA_FNC_T_TOUCH_Y_index] = new_y; + tpl[GRID_LUA_FNC_T_TOUCH_AREA_index] = area; + + if (changed) { + struct grid_ui_event* eve = grid_ui_event_find(ele, GRID_PARAMETER_EVENT_TOUCH); + grid_ui_event_state_set(eve, GRID_EVE_STATE_TRIG); + } +} diff --git a/common/src/c/grid_ui_touch.h b/common/src/c/grid_ui_touch.h new file mode 100644 index 00000000..b6af46da --- /dev/null +++ b/common/src/c/grid_ui_touch.h @@ -0,0 +1,42 @@ +#ifndef GRID_UI_TOUCH_H +#define GRID_UI_TOUCH_H + +#include + +#include "grid_protocol.h" +#include "grid_ui.h" + +struct grid_ui_touch_state { + struct grid_ui_element* parent; + uint16_t x; + uint16_t y; + uint8_t area; // 0 = not pressed +}; + +void grid_ui_element_touch_init(struct grid_ui_element* ele); +void grid_ui_element_touch_template_parameter_init(struct grid_ui_template_buffer* buf); + +static inline struct grid_ui_touch_state* grid_ui_touch_get_state(struct grid_ui_element* ele) { return (struct grid_ui_touch_state*)ele->primary_state; } + +void grid_ui_touch_store_input(struct grid_ui_touch_state* state, uint16_t x, uint16_t y, uint8_t area); + +#define GRID_LUA_T_TYPE "Touch" + +extern const luaL_Reg GRID_LUA_T_INDEX_META[]; + +#define GRID_LUA_T_META_init \ + GRID_LUA_T_TYPE " = { __index = {" \ + "type = 'touch', " \ + "post_init_cb = function (self) " \ + "self:" GRID_LUA_FNC_A_INIT_short "() " \ + "self:" GRID_LUA_FNC_A_TOUCH_short "() " \ + "end," \ + GRID_LUA_FNC_ASSIGN_META_PAR1_RET("gen", GRID_LUA_FNC_G_ELEMENTNAME_short) "," \ + "}}" + +#define GRID_ACTIONSTRING_TOUCH_INIT "--[[@cb]]--[[Touch Init]]" + +#define GRID_ACTIONSTRING_TOUCH_TOUCH \ + "--[[@cb]]print(self:ind(),self:tsx(),self:tsy(),self:tar())" + +#endif /* GRID_UI_TOUCH_H */ diff --git a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c index 582e8d7d..b4a1d349 100644 --- a/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c +++ b/esp32s3/components/grid_esp32_module_xy/grid_esp32_module_xy.c @@ -10,11 +10,10 @@ #include "grid_sys.h" #include "grid_ui.h" +#include "grid_ui_touch.h" #include "grid_esp32_touch.h" -#include "rom/ets_sys.h" - #define XY_I2C_PORT I2C_NUM_0 #define XY_I2C_SCL_GPIO 40 #define XY_I2C_SDA_GPIO 41 @@ -25,11 +24,21 @@ void grid_esp32_module_xy_handle_touch(void) { TOUCHINFO ti = {}; - int rc = grid_esp32_touch_get_samples(&grid_esp32_touch_state, &ti); - if (rc) { - ets_printf("touch count=%d\r\n", ti.count); - for (int i = 0; i < ti.count; i++) { - ets_printf(" [%d] x=%d y=%d area=%d\r\n", i, ti.x[i], ti.y[i], ti.area[i]); + if (!grid_esp32_touch_get_samples(&grid_esp32_touch_state, &ti)) { + return; + } + + for (uint8_t i = 0; i < 5; i++) { + struct grid_ui_element* ele = grid_ui_element_find(&grid_ui_state, i); + if (!ele) { + continue; + } + struct grid_ui_touch_state* state = grid_ui_touch_get_state(ele); + + if (i < ti.count) { + grid_ui_touch_store_input(state, ti.x[i], ti.y[i], ti.area[i]); + } else if (state->area > 0) { + grid_ui_touch_store_input(state, state->x, state->y, 0); } } } From fa676e420520246167575a209e96a6b9b849c6ce Mon Sep 17 00:00:00 2001 From: sukuwc Date: Tue, 5 May 2026 14:06:49 +0200 Subject: [PATCH 8/9] SUKU format fixe --- common/src/c/grid_ui_touch.c | 28 ++++++++++++++-------------- common/src/c/grid_ui_touch.h | 20 +++++++++----------- 2 files changed, 23 insertions(+), 25 deletions(-) diff --git a/common/src/c/grid_ui_touch.c b/common/src/c/grid_ui_touch.c index ee2f2d89..b2d6b4e7 100644 --- a/common/src/c/grid_ui_touch.c +++ b/common/src/c/grid_ui_touch.c @@ -10,20 +10,20 @@ #include "grid_ui_system.h" const luaL_Reg GRID_LUA_T_INDEX_META[] = {{GRID_LUA_FNC_T_ELEMENT_INDEX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_ELEMENT_INDEX_index)}, - {GRID_LUA_FNC_T_LED_INDEX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_LED_INDEX_index)}, - {GRID_LUA_FNC_T_TOUCH_X_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_X_index)}, - {GRID_LUA_FNC_T_TOUCH_Y_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_Y_index)}, - {GRID_LUA_FNC_T_TOUCH_AREA_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_AREA_index)}, - {GRID_LUA_FNC_T_TOUCH_X_MIN_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_X_MIN_index)}, - {GRID_LUA_FNC_T_TOUCH_X_MAX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_X_MAX_index)}, - {GRID_LUA_FNC_T_TOUCH_Y_MIN_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_Y_MIN_index)}, - {GRID_LUA_FNC_T_TOUCH_Y_MAX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_Y_MAX_index)}, - {GRID_LUA_FNC_G_TIMER_START_short, XAFTERX(GRID_LUA_FNC_META_NAME, gtt)}, - {GRID_LUA_FNC_G_TIMER_STOP_short, XAFTERX(GRID_LUA_FNC_META_NAME, gtp)}, - {GRID_LUA_FNC_G_EVENT_TRIGGER_short, XAFTERX(GRID_LUA_FNC_META_NAME, get)}, - {GRID_LUA_FNC_G_ELEMENTNAME_SET_short, XAFTERX(GRID_LUA_FNC_META_NAME, gsen)}, - {GRID_LUA_FNC_G_ELEMENTNAME_GET_short, XAFTERX(GRID_LUA_FNC_META_NAME, ggen)}, - {NULL, NULL}}; + {GRID_LUA_FNC_T_LED_INDEX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_LED_INDEX_index)}, + {GRID_LUA_FNC_T_TOUCH_X_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_X_index)}, + {GRID_LUA_FNC_T_TOUCH_Y_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_Y_index)}, + {GRID_LUA_FNC_T_TOUCH_AREA_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_AREA_index)}, + {GRID_LUA_FNC_T_TOUCH_X_MIN_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_X_MIN_index)}, + {GRID_LUA_FNC_T_TOUCH_X_MAX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_X_MAX_index)}, + {GRID_LUA_FNC_T_TOUCH_Y_MIN_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_Y_MIN_index)}, + {GRID_LUA_FNC_T_TOUCH_Y_MAX_short, XAFTERX(GRID_LUA_FNC_GTV_NAME, GRID_LUA_FNC_T_TOUCH_Y_MAX_index)}, + {GRID_LUA_FNC_G_TIMER_START_short, XAFTERX(GRID_LUA_FNC_META_NAME, gtt)}, + {GRID_LUA_FNC_G_TIMER_STOP_short, XAFTERX(GRID_LUA_FNC_META_NAME, gtp)}, + {GRID_LUA_FNC_G_EVENT_TRIGGER_short, XAFTERX(GRID_LUA_FNC_META_NAME, get)}, + {GRID_LUA_FNC_G_ELEMENTNAME_SET_short, XAFTERX(GRID_LUA_FNC_META_NAME, gsen)}, + {GRID_LUA_FNC_G_ELEMENTNAME_GET_short, XAFTERX(GRID_LUA_FNC_META_NAME, ggen)}, + {NULL, NULL}}; void grid_ui_element_touch_init(struct grid_ui_element* ele) { diff --git a/common/src/c/grid_ui_touch.h b/common/src/c/grid_ui_touch.h index b6af46da..c6011f28 100644 --- a/common/src/c/grid_ui_touch.h +++ b/common/src/c/grid_ui_touch.h @@ -24,19 +24,17 @@ void grid_ui_touch_store_input(struct grid_ui_touch_state* state, uint16_t x, ui extern const luaL_Reg GRID_LUA_T_INDEX_META[]; -#define GRID_LUA_T_META_init \ - GRID_LUA_T_TYPE " = { __index = {" \ - "type = 'touch', " \ - "post_init_cb = function (self) " \ - "self:" GRID_LUA_FNC_A_INIT_short "() " \ - "self:" GRID_LUA_FNC_A_TOUCH_short "() " \ - "end," \ - GRID_LUA_FNC_ASSIGN_META_PAR1_RET("gen", GRID_LUA_FNC_G_ELEMENTNAME_short) "," \ - "}}" +#define GRID_LUA_T_META_init \ + GRID_LUA_T_TYPE " = { __index = {" \ + "type = 'touch', " \ + "post_init_cb = function (self) " \ + "self:" GRID_LUA_FNC_A_INIT_short "() " \ + "self:" GRID_LUA_FNC_A_TOUCH_short "() " \ + "end," GRID_LUA_FNC_ASSIGN_META_PAR1_RET("gen", GRID_LUA_FNC_G_ELEMENTNAME_short) "," \ + "}}" #define GRID_ACTIONSTRING_TOUCH_INIT "--[[@cb]]--[[Touch Init]]" -#define GRID_ACTIONSTRING_TOUCH_TOUCH \ - "--[[@cb]]print(self:ind(),self:tsx(),self:tsy(),self:tar())" +#define GRID_ACTIONSTRING_TOUCH_TOUCH "--[[@cb]]print(self:ind(),self:tsx(),self:tsy(),self:tar())" #endif /* GRID_UI_TOUCH_H */ From 534c2128f92d5a6065fbd687d023ccedd6fca50b Mon Sep 17 00:00:00 2001 From: sukuwc Date: Tue, 5 May 2026 14:43:53 +0200 Subject: [PATCH 9/9] SUKU makefile updated to build ui_touch correctly --- d51n20a/gcc/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/d51n20a/gcc/Makefile b/d51n20a/gcc/Makefile index 7e2a11c8..4c2d3355 100644 --- a/d51n20a/gcc/Makefile +++ b/d51n20a/gcc/Makefile @@ -89,6 +89,7 @@ SRCS = \ common/src/c/grid_ui_lcd.c \ common/src/c/grid_ui_potmeter.c \ common/src/c/grid_ui_system.c \ + common/src/c/grid_ui_touch.c \ common/src/c/grid_usb.c \ common/src/c/grid_utask.c \ common/dep/lua-5.4.3/src/dirent.c \