#include "cst826.h" #include "display.h" #include "esp_log.h" #include "i2c_bus.h" static const char *TAG = "cst826"; #define REG_NUM_TOUCHES 0x02 #define REG_TOUCH_DATA 0x03 #define REG_CHIP_TYPE 0xAA static i2c_master_dev_handle_t s_dev; static bool s_ready; static esp_err_t read_reg(uint8_t reg, uint8_t *buf, size_t len) { return i2c_master_transmit_receive(s_dev, ®, 1, buf, len, 100); } esp_err_t cst826_init(void) { if (s_ready) { return ESP_OK; } esp_err_t err = i2c_bus_add_device(CST826_I2C_ADDR, &s_dev); if (err != ESP_OK) { ESP_LOGE(TAG, "add device 0x%02X failed: %s", CST826_I2C_ADDR, esp_err_to_name(err)); return err; } uint8_t id = 0; err = read_reg(REG_CHIP_TYPE, &id, 1); if (err != ESP_OK) { ESP_LOGE(TAG, "no response at 0x%02X: %s", CST826_I2C_ADDR, esp_err_to_name(err)); return err; } if (id != CST826_CHIP_ID) { /* Not fatal — the thermostat is fully usable from the encoder alone, * and refusing to boot over a touch panel would be a poor trade for * something that controls heat. */ ESP_LOGW(TAG, "unexpected chip id 0x%02X (expected 0x%02X) — " "continuing with touch disabled", id, CST826_CHIP_ID); return ESP_ERR_NOT_FOUND; } s_ready = true; ESP_LOGI(TAG, "ready at 0x%02X, chip id 0x%02X", CST826_I2C_ADDR, id); return ESP_OK; } bool cst826_is_ready(void) { return s_ready; } void cst826_read(cst826_touch_t *out) { if (!out) { return; } out->pressed = false; out->x = 0; out->y = 0; if (!s_ready) { return; } uint8_t n = 0; if (read_reg(REG_NUM_TOUCHES, &n, 1) != ESP_OK || n == 0 || n > 2) { return; } uint8_t d[6]; if (read_reg(REG_TOUCH_DATA, d, sizeof(d)) != ESP_OK) { return; } uint16_t x = (uint16_t)((d[0] & 0x0F) << 8 | d[1]); uint16_t y = (uint16_t)((d[2] & 0x0F) << 8 | d[3]); /* A garbage read past the panel edge means a bad transfer, not a touch at * the corner. Drop it rather than sending LVGL a bogus press. */ if (x >= DISPLAY_H_RES || y >= DISPLAY_V_RES) { return; } out->x = x; out->y = y; out->pressed = true; }