ESPHome  2024.9.0
gt911_touchscreen.cpp
Go to the documentation of this file.
1 #include "gt911_touchscreen.h"
2 
3 #include "esphome/core/helpers.h"
4 #include "esphome/core/log.h"
5 
6 namespace esphome {
7 namespace gt911 {
8 
9 static const char *const TAG = "gt911.touchscreen";
10 
11 static const uint8_t GET_TOUCH_STATE[2] = {0x81, 0x4E};
12 static const uint8_t CLEAR_TOUCH_STATE[3] = {0x81, 0x4E, 0x00};
13 static const uint8_t GET_TOUCHES[2] = {0x81, 0x4F};
14 static const uint8_t GET_SWITCHES[2] = {0x80, 0x4D};
15 static const uint8_t GET_MAX_VALUES[2] = {0x80, 0x48};
16 static const size_t MAX_TOUCHES = 5; // max number of possible touches reported
17 static const size_t MAX_BUTTONS = 4; // max number of buttons scanned
18 
19 #define ERROR_CHECK(err) \
20  if ((err) != i2c::ERROR_OK) { \
21  ESP_LOGE(TAG, "Failed to communicate!"); \
22  this->status_set_warning(); \
23  return; \
24  }
25 
27  i2c::ErrorCode err;
28  ESP_LOGCONFIG(TAG, "Setting up GT911 Touchscreen...");
29  if (this->reset_pin_ != nullptr) {
30  this->reset_pin_->setup();
31  this->reset_pin_->digital_write(false);
32  if (this->interrupt_pin_ != nullptr) {
33  // The interrupt pin is used as an input during reset to select the I2C address.
35  this->interrupt_pin_->setup();
36  this->interrupt_pin_->digital_write(false);
37  }
38  delay(2);
39  this->reset_pin_->digital_write(true);
40  delay(50); // NOLINT
41  if (this->interrupt_pin_ != nullptr) {
43  this->interrupt_pin_->setup();
44  }
45  }
46 
47  // check the configuration of the int line.
48  uint8_t data[4];
49  err = this->write(GET_SWITCHES, 2);
50  if (err == i2c::ERROR_OK) {
51  err = this->read(data, 1);
52  if (err == i2c::ERROR_OK) {
53  ESP_LOGD(TAG, "Read from switches: 0x%02X", data[0]);
54  if (this->interrupt_pin_ != nullptr) {
55  // datasheet says NOT to use pullup/down on the int line.
57  this->interrupt_pin_->setup();
60  }
61  }
62  }
63  if (err == i2c::ERROR_OK) {
64  err = this->write(GET_MAX_VALUES, 2);
65  if (err == i2c::ERROR_OK) {
66  err = this->read(data, sizeof(data));
67  if (err == i2c::ERROR_OK) {
68  if (this->x_raw_max_ == this->x_raw_min_) {
69  this->x_raw_max_ = encode_uint16(data[1], data[0]);
70  }
71  if (this->y_raw_max_ == this->y_raw_min_) {
72  this->y_raw_max_ = encode_uint16(data[3], data[2]);
73  }
74  esph_log_d(TAG, "calibration max_x/max_y %d/%d", this->x_raw_max_, this->y_raw_max_);
75  }
76  }
77  }
78  if (err != i2c::ERROR_OK) {
79  ESP_LOGE(TAG, "Failed to communicate!");
80  this->mark_failed();
81  return;
82  }
83 
84  ESP_LOGCONFIG(TAG, "GT911 Touchscreen setup complete");
85 }
86 
88  i2c::ErrorCode err;
89  uint8_t touch_state = 0;
90  uint8_t data[MAX_TOUCHES + 1][8]; // 8 bytes each for each point, plus extra space for the key byte
91 
92  err = this->write(GET_TOUCH_STATE, sizeof(GET_TOUCH_STATE), false);
93  ERROR_CHECK(err);
94  err = this->read(&touch_state, 1);
95  ERROR_CHECK(err);
96  this->write(CLEAR_TOUCH_STATE, sizeof(CLEAR_TOUCH_STATE));
97  uint8_t num_of_touches = touch_state & 0x07;
98 
99  if ((touch_state & 0x80) == 0 || num_of_touches > MAX_TOUCHES) {
100  this->skip_update_ = true; // skip send touch events, touchscreen is not ready yet.
101  return;
102  }
103 
104  err = this->write(GET_TOUCHES, sizeof(GET_TOUCHES), false);
105  ERROR_CHECK(err);
106  // num_of_touches is guaranteed to be 0..5. Also read the key data
107  err = this->read(data[0], sizeof(data[0]) * num_of_touches + 1);
108  ERROR_CHECK(err);
109 
110  for (uint8_t i = 0; i != num_of_touches; i++) {
111  uint16_t id = data[i][0];
112  uint16_t x = encode_uint16(data[i][2], data[i][1]);
113  uint16_t y = encode_uint16(data[i][4], data[i][3]);
114  this->add_raw_touch_position_(id, x, y);
115  }
116  auto keys = data[num_of_touches][0] & ((1 << MAX_BUTTONS) - 1);
117  if (keys != this->button_state_) {
118  this->button_state_ = keys;
119  for (size_t i = 0; i != MAX_BUTTONS; i++) {
120  for (auto *listener : this->button_listeners_)
121  listener->update_button(i, (keys & (1 << i)) != 0);
122  }
123  }
124 }
125 
127  ESP_LOGCONFIG(TAG, "GT911 Touchscreen:");
128  LOG_I2C_DEVICE(this);
129  LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_);
130 }
131 
132 } // namespace gt911
133 } // namespace esphome
virtual void digital_write(bool value)=0
uint16_t x
Definition: tt21100.cpp:17
ErrorCode read(uint8_t *data, size_t len)
reads an array of bytes from the device using an I2CBus
Definition: i2c.h:160
virtual void pin_mode(gpio::Flags flags)=0
virtual void setup()=0
ErrorCode write(const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a device using an I2CBus
Definition: i2c.h:186
uint16_t y
Definition: tt21100.cpp:18
std::vector< GT911ButtonListener * > button_listeners_
void attach_interrupt_(InternalGPIOPin *irq_pin, esphome::gpio::InterruptType type)
Call this function to send touch points to the on_touch listener and the binary_sensors.
Definition: touchscreen.cpp:12
No error found during execution of method.
Definition: i2c_bus.h:13
constexpr uint16_t encode_uint16(uint8_t msb, uint8_t lsb)
Encode a 16-bit value given the most and least significant byte.
Definition: helpers.h:182
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
void add_raw_touch_position_(uint8_t id, int16_t x_raw, int16_t y_raw, int16_t z_raw=0)
Definition: touchscreen.cpp:74
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
ErrorCode
Error codes returned by I2CBus and I2CDevice methods.
Definition: i2c_bus.h:11
void IRAM_ATTR HOT delay(uint32_t ms)
Definition: core.cpp:26