-
-
Notifications
You must be signed in to change notification settings - Fork 3.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
318 additions
and
2 deletions.
There are no files selected for viewing
Validating CODEOWNERS rules …
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import esphome.codegen as cg | ||
import esphome.config_validation as cv | ||
|
||
from esphome import pins | ||
from esphome.components import binary_sensor, i2c, touchscreen | ||
from esphome.const import CONF_ID, CONF_INTERRUPT_PIN, CONF_RESET_PIN | ||
|
||
CODEOWNERS = ["@kroimon"] | ||
DEPENDENCIES = ["i2c"] | ||
AUTO_LOAD = ["binary_sensor"] | ||
|
||
tt21100_ns = cg.esphome_ns.namespace("tt21100") | ||
TT21100Touchscreen = tt21100_ns.class_( | ||
"TT21100Touchscreen", | ||
touchscreen.Touchscreen, | ||
cg.Component, | ||
i2c.I2CDevice, | ||
) | ||
|
||
CONF_TT21100_ID = "tt21100_id" | ||
CONF_BUTTON1 = "button1" | ||
CONF_BUTTON2 = "button2" | ||
CONF_BUTTON3 = "button3" | ||
CONF_BUTTON4 = "button4" | ||
CONF_MIRROR_X = "mirror_x" | ||
CONF_MIRROR_Y = "mirror_y" | ||
|
||
CONFIG_SCHEMA = touchscreen.TOUCHSCREEN_SCHEMA.extend( | ||
cv.Schema( | ||
{ | ||
cv.GenerateID(): cv.declare_id(TT21100Touchscreen), | ||
cv.Required(CONF_INTERRUPT_PIN): pins.internal_gpio_input_pin_schema, | ||
cv.Optional(CONF_RESET_PIN): pins.gpio_output_pin_schema, | ||
cv.Optional(CONF_BUTTON1): binary_sensor.binary_sensor_schema(), | ||
cv.Optional(CONF_BUTTON2): binary_sensor.binary_sensor_schema(), | ||
cv.Optional(CONF_BUTTON3): binary_sensor.binary_sensor_schema(), | ||
cv.Optional(CONF_BUTTON4): binary_sensor.binary_sensor_schema(), | ||
} | ||
) | ||
.extend(i2c.i2c_device_schema(0x24)) | ||
.extend(cv.COMPONENT_SCHEMA) | ||
) | ||
|
||
|
||
async def to_code(config): | ||
var = cg.new_Pvariable(config[CONF_ID]) | ||
await cg.register_component(var, config) | ||
await i2c.register_i2c_device(var, config) | ||
await touchscreen.register_touchscreen(var, config) | ||
|
||
interrupt_pin = await cg.gpio_pin_expression(config[CONF_INTERRUPT_PIN]) | ||
cg.add(var.set_interrupt_pin(interrupt_pin)) | ||
if CONF_RESET_PIN in config: | ||
rts_pin = await cg.gpio_pin_expression(config[CONF_RESET_PIN]) | ||
cg.add(var.set_reset_pin(rts_pin)) | ||
|
||
if CONF_BUTTON1 in config: | ||
sensor = await binary_sensor.new_binary_sensor(config[CONF_BUTTON1]) | ||
cg.add(var.set_button(0, sensor)) | ||
if CONF_BUTTON2 in config: | ||
sensor = await binary_sensor.new_binary_sensor(config[CONF_BUTTON2]) | ||
cg.add(var.set_button(1, sensor)) | ||
if CONF_BUTTON3 in config: | ||
sensor = await binary_sensor.new_binary_sensor(config[CONF_BUTTON3]) | ||
cg.add(var.set_button(2, sensor)) | ||
if CONF_BUTTON4 in config: | ||
sensor = await binary_sensor.new_binary_sensor(config[CONF_BUTTON4]) | ||
cg.add(var.set_button(3, sensor)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
#include "tt21100.h" | ||
#include "esphome/core/helpers.h" | ||
#include "esphome/core/log.h" | ||
|
||
namespace esphome { | ||
namespace tt21100 { | ||
|
||
static const char *const TAG = "tt21100"; | ||
|
||
void TT21100TouchscreenStore::gpio_intr(TT21100TouchscreenStore *store) { store->touch = true; } | ||
|
||
float TT21100Touchscreen::get_setup_priority() const { return setup_priority::HARDWARE - 1.0f; } | ||
|
||
void TT21100Touchscreen::setup() { | ||
ESP_LOGCONFIG(TAG, "Setting up TT21100 Touchscreen..."); | ||
|
||
// Register interrupt pin | ||
this->interrupt_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); | ||
this->interrupt_pin_->setup(); | ||
this->store_.pin = this->interrupt_pin_->to_isr(); | ||
this->interrupt_pin_->attach_interrupt(TT21100TouchscreenStore::gpio_intr, &this->store_, | ||
gpio::INTERRUPT_FALLING_EDGE); | ||
|
||
// Perform reset if necessary | ||
if (this->reset_pin_ != nullptr) { | ||
this->reset_pin_->setup(); | ||
this->reset_(); | ||
} | ||
|
||
// Update display dimensions if they were updated during display setup | ||
this->display_width_ = this->display_->get_width_internal(); | ||
this->display_height_ = this->display_->get_height_internal(); | ||
this->rotation_ = static_cast<TouchRotation>(this->display_->get_rotation()); | ||
|
||
// Trigger initial read to activate the interrupt | ||
this->store_.touch = true; | ||
} | ||
|
||
void TT21100Touchscreen::loop() { | ||
if (!this->store_.touch) | ||
return; | ||
this->store_.touch = false; | ||
|
||
// Read report length | ||
uint16_t data_len; | ||
this->read((uint8_t *) &data_len, sizeof(data_len)); | ||
|
||
// Read report data | ||
uint8_t data[MAX_DATA_LEN]; | ||
if (data_len > 0 && data_len < sizeof(data)) { | ||
this->read(data, data_len); | ||
|
||
if (data_len == 14) { | ||
// Button event | ||
auto *report = (TT21100ButtonReport *) data; | ||
|
||
ESP_LOGV(TAG, "Button report: Len=%d, ID=%d, Time=%5u, Val=[%u] - [%04X][%04X][%04X][%04X]", report->length, | ||
report->report_id, report->timestamp, report->btn_val, report->btn_signal[0], report->btn_signal[1], | ||
report->btn_signal[2], report->btn_signal[3]); | ||
|
||
for (int i = 0; i < 4; i++) { | ||
if (this->buttons_[i] != nullptr) { | ||
this->buttons_[i]->publish_state(report->btn_signal[i] > 0); | ||
} | ||
} | ||
|
||
} else if (data_len >= 7) { | ||
// Touch point event | ||
auto *report = (TT21100TouchReport *) data; | ||
|
||
ESP_LOGV(TAG, | ||
"Touch report: Len=%d, ID=%d, Time=%5u, LargeObject=%u, RecordNum=%u, RecordCounter=%u, NoiseEfect=%u", | ||
report->length, report->report_id, report->timestamp, report->large_object, report->record_num, | ||
report->report_counter, report->noise_efect); | ||
|
||
uint8_t touch_count = (data_len - sizeof(TT21100TouchReport)) / sizeof(TT21100TouchRecord); | ||
|
||
if (touch_count == 0) { | ||
for (auto *listener : this->touch_listeners_) | ||
listener->release(); | ||
return; | ||
} | ||
|
||
for (int i = 0; i < touch_count; i++) { | ||
auto *touch = &report->touch_record[i]; | ||
|
||
ESP_LOGV(TAG, | ||
"Touch %d: Type=%u, Tip=%u, EventId=%u, TouchId=%u, X=%u, Y=%u, Pressure=%u, MajorAxisLen=%u, " | ||
"Orientation=%u", | ||
i, touch->touch_type, touch->tip, touch->event_id, touch->touch_id, touch->x, touch->y, | ||
touch->pressure, touch->major_axis_length, touch->orientation); | ||
|
||
TouchPoint tp; | ||
switch (this->rotation_) { | ||
case ROTATE_0_DEGREES: | ||
// Origin is top right, so mirror X by default | ||
tp.x = this->display_width_ - touch->x; | ||
tp.y = touch->y; | ||
break; | ||
case ROTATE_90_DEGREES: | ||
tp.x = touch->y; | ||
tp.y = touch->x; | ||
break; | ||
case ROTATE_180_DEGREES: | ||
tp.x = touch->x; | ||
tp.y = this->display_height_ - touch->y; | ||
break; | ||
case ROTATE_270_DEGREES: | ||
tp.x = this->display_height_ - touch->y; | ||
tp.y = this->display_width_ - touch->x; | ||
break; | ||
} | ||
tp.id = touch->tip; | ||
tp.state = touch->pressure; | ||
|
||
this->defer([this, tp]() { this->send_touch_(tp); }); | ||
} | ||
} | ||
} | ||
} | ||
|
||
void TT21100Touchscreen::reset_() { | ||
if (this->reset_pin_ != nullptr) { | ||
this->reset_pin_->digital_write(false); | ||
delay(10); | ||
this->reset_pin_->digital_write(true); | ||
delay(10); | ||
} | ||
} | ||
|
||
void TT21100Touchscreen::dump_config() { | ||
ESP_LOGCONFIG(TAG, "TT21100 Touchscreen:"); | ||
LOG_I2C_DEVICE(this); | ||
LOG_PIN(" Interrupt Pin: ", this->interrupt_pin_); | ||
LOG_PIN(" Reset Pin: ", this->reset_pin_); | ||
LOG_BINARY_SENSOR(" ", "Button 1", this->buttons_[0]); | ||
LOG_BINARY_SENSOR(" ", "Button 2", this->buttons_[1]); | ||
LOG_BINARY_SENSOR(" ", "Button 3", this->buttons_[2]); | ||
LOG_BINARY_SENSOR(" ", "Button 4", this->buttons_[3]); | ||
} | ||
|
||
} // namespace tt21100 | ||
} // namespace esphome |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
#pragma once | ||
|
||
#include "esphome/components/binary_sensor/binary_sensor.h" | ||
#include "esphome/components/i2c/i2c.h" | ||
#include "esphome/components/touchscreen/touchscreen.h" | ||
#include "esphome/core/automation.h" | ||
#include "esphome/core/component.h" | ||
#include "esphome/core/hal.h" | ||
|
||
namespace esphome { | ||
namespace tt21100 { | ||
|
||
using namespace touchscreen; | ||
|
||
static const uint8_t MAX_BUTTONS = 4; | ||
static const uint8_t MAX_TOUCH_POINTS = 5; | ||
static const uint8_t MAX_DATA_LEN = (7 + MAX_TOUCH_POINTS * 10); // 7 Header + (Points * 10 data bytes) | ||
|
||
struct TT21100TouchscreenStore { | ||
volatile bool touch; | ||
ISRInternalGPIOPin pin; | ||
|
||
static void gpio_intr(TT21100TouchscreenStore *store); | ||
}; | ||
|
||
class TT21100Touchscreen : public Touchscreen, public Component, public i2c::I2CDevice { | ||
public: | ||
void setup() override; | ||
void loop() override; | ||
void dump_config() override; | ||
float get_setup_priority() const override; | ||
|
||
void set_interrupt_pin(InternalGPIOPin *pin) { this->interrupt_pin_ = pin; } | ||
void set_reset_pin(GPIOPin *pin) { this->reset_pin_ = pin; } | ||
void set_button(int index, binary_sensor::BinarySensor *sensor) { this->buttons_[index] = sensor; } | ||
|
||
protected: | ||
void reset_(); | ||
|
||
InternalGPIOPin *interrupt_pin_; | ||
GPIOPin *reset_pin_{nullptr}; | ||
std::array<binary_sensor::BinarySensor *, MAX_BUTTONS> buttons_; | ||
|
||
TT21100TouchscreenStore store_; | ||
}; | ||
|
||
struct TT21100ButtonReport { | ||
uint16_t length; /*!< Always 14(0x000E) */ | ||
uint8_t report_id; /*!< Always 0x03 */ | ||
uint16_t timestamp; /*!< Number in units of 100 us */ | ||
uint8_t btn_val; /*!< Only use bit[0..3] */ | ||
uint16_t btn_signal[MAX_BUTTONS]; | ||
} __attribute__((packed)); | ||
|
||
struct TT21100TouchRecord { | ||
uint8_t : 5; | ||
uint8_t touch_type : 3; | ||
uint8_t tip : 1; | ||
uint8_t event_id : 2; | ||
uint8_t touch_id : 5; | ||
uint16_t x; | ||
uint16_t y; | ||
uint8_t pressure; | ||
uint16_t major_axis_length; | ||
uint8_t orientation; | ||
} __attribute__((packed)); | ||
|
||
struct TT21100TouchReport { | ||
uint16_t length; | ||
uint8_t report_id; | ||
uint16_t timestamp; | ||
uint8_t : 2; | ||
uint8_t large_object : 1; | ||
uint8_t record_num : 5; | ||
uint8_t report_counter : 2; | ||
uint8_t : 3; | ||
uint8_t noise_efect : 3; | ||
TT21100TouchRecord touch_record[0]; | ||
} __attribute__((packed)); | ||
|
||
} // namespace tt21100 | ||
} // namespace esphome |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters