mirror of
https://github.com/esphome/esphome.git
synced 2025-10-05 19:33:47 +01:00
preen
This commit is contained in:
@@ -31,6 +31,9 @@ void ESP32TouchComponent::setup() {
|
|||||||
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
|
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
|
||||||
|
|
||||||
// Create queue for touch events
|
// Create queue for touch events
|
||||||
|
// Queue size calculation: children * 4 allows for burst scenarios where ISR
|
||||||
|
// fires multiple times before main loop processes. This is important because
|
||||||
|
// ESP32 v1 scans all pads on each interrupt, potentially sending multiple events.
|
||||||
size_t queue_size = this->children_.size() * 4;
|
size_t queue_size = this->children_.size() * 4;
|
||||||
if (queue_size < 8)
|
if (queue_size < 8)
|
||||||
queue_size = 8;
|
queue_size = 8;
|
||||||
@@ -75,11 +78,13 @@ void ESP32TouchComponent::setup() {
|
|||||||
// Design note: ESP32 v1 hardware limitation - interrupts only fire on touch (not release)
|
// Design note: ESP32 v1 hardware limitation - interrupts only fire on touch (not release)
|
||||||
// We must use timeout-based detection for release events
|
// We must use timeout-based detection for release events
|
||||||
// Formula: 3 sleep cycles converted to ms, with MINIMUM_RELEASE_TIME_MS minimum
|
// Formula: 3 sleep cycles converted to ms, with MINIMUM_RELEASE_TIME_MS minimum
|
||||||
|
// The division by 2 accounts for the fact that sleep_cycle is in half-cycles
|
||||||
uint32_t rtc_freq = rtc_clk_slow_freq_get_hz();
|
uint32_t rtc_freq = rtc_clk_slow_freq_get_hz();
|
||||||
this->release_timeout_ms_ = (this->sleep_cycle_ * 1000 * 3) / (rtc_freq * 2);
|
this->release_timeout_ms_ = (this->sleep_cycle_ * 1000 * 3) / (rtc_freq * 2);
|
||||||
if (this->release_timeout_ms_ < MINIMUM_RELEASE_TIME_MS) {
|
if (this->release_timeout_ms_ < MINIMUM_RELEASE_TIME_MS) {
|
||||||
this->release_timeout_ms_ = MINIMUM_RELEASE_TIME_MS;
|
this->release_timeout_ms_ = MINIMUM_RELEASE_TIME_MS;
|
||||||
}
|
}
|
||||||
|
// Check for releases at 1/4 the timeout interval, capped at 50ms
|
||||||
this->release_check_interval_ms_ = std::min(this->release_timeout_ms_ / 4, (uint32_t) 50);
|
this->release_check_interval_ms_ = std::min(this->release_timeout_ms_ / 4, (uint32_t) 50);
|
||||||
|
|
||||||
// Enable touch pad interrupt
|
// Enable touch pad interrupt
|
||||||
@@ -115,9 +120,11 @@ void ESP32TouchComponent::loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process any queued touch events from interrupts
|
// Process any queued touch events from interrupts
|
||||||
|
// Note: Events are only sent by ISR for pads that were measured in that cycle (value != 0)
|
||||||
|
// This is more efficient than sending all pad states every interrupt
|
||||||
TouchPadEventV1 event;
|
TouchPadEventV1 event;
|
||||||
while (xQueueReceive(this->touch_queue_, &event, 0) == pdTRUE) {
|
while (xQueueReceive(this->touch_queue_, &event, 0) == pdTRUE) {
|
||||||
// Find the corresponding sensor
|
// Find the corresponding sensor - O(n) search is acceptable since events are infrequent
|
||||||
for (auto *child : this->children_) {
|
for (auto *child : this->children_) {
|
||||||
if (child->get_touch_pad() == event.pad) {
|
if (child->get_touch_pad() == event.pad) {
|
||||||
child->value_ = event.value;
|
child->value_ = event.value;
|
||||||
@@ -130,7 +137,7 @@ void ESP32TouchComponent::loop() {
|
|||||||
this->last_touch_time_[event.pad] = now;
|
this->last_touch_time_[event.pad] = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only publish if state changed
|
// Only publish if state changed - this filters out repeated events
|
||||||
if (new_state != child->last_state_) {
|
if (new_state != child->last_state_) {
|
||||||
child->last_state_ = new_state;
|
child->last_state_ = new_state;
|
||||||
child->publish_state(new_state);
|
child->publish_state(new_state);
|
||||||
@@ -219,6 +226,8 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
|
|||||||
touch_pad_clear_status();
|
touch_pad_clear_status();
|
||||||
|
|
||||||
// Process all configured pads to check their current state
|
// Process all configured pads to check their current state
|
||||||
|
// Note: ESP32 v1 doesn't tell us which specific pad triggered the interrupt,
|
||||||
|
// so we must scan all configured pads to find which ones were touched
|
||||||
for (auto *child : component->children_) {
|
for (auto *child : component->children_) {
|
||||||
touch_pad_t pad = child->get_touch_pad();
|
touch_pad_t pad = child->get_touch_pad();
|
||||||
|
|
||||||
@@ -234,6 +243,8 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Skip pads with 0 value - they haven't been measured in this cycle
|
// Skip pads with 0 value - they haven't been measured in this cycle
|
||||||
|
// This is important: not all pads are measured every interrupt cycle,
|
||||||
|
// only those that the hardware has updated
|
||||||
if (value == 0) {
|
if (value == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -242,12 +253,14 @@ void IRAM_ATTR ESP32TouchComponent::touch_isr_handler(void *arg) {
|
|||||||
bool is_touched = value < child->get_threshold();
|
bool is_touched = value < child->get_threshold();
|
||||||
|
|
||||||
// Always send the current state - the main loop will filter for changes
|
// Always send the current state - the main loop will filter for changes
|
||||||
|
// We send both touched and untouched states because the ISR doesn't
|
||||||
|
// track previous state (to keep ISR fast and simple)
|
||||||
TouchPadEventV1 event;
|
TouchPadEventV1 event;
|
||||||
event.pad = pad;
|
event.pad = pad;
|
||||||
event.value = value;
|
event.value = value;
|
||||||
event.is_touched = is_touched;
|
event.is_touched = is_touched;
|
||||||
|
|
||||||
// Send to queue from ISR
|
// Send to queue from ISR - non-blocking, drops if queue full
|
||||||
BaseType_t x_higher_priority_task_woken = pdFALSE;
|
BaseType_t x_higher_priority_task_woken = pdFALSE;
|
||||||
xQueueSendFromISR(component->touch_queue_, &event, &x_higher_priority_task_woken);
|
xQueueSendFromISR(component->touch_queue_, &event, &x_higher_priority_task_woken);
|
||||||
if (x_higher_priority_task_woken) {
|
if (x_higher_priority_task_woken) {
|
||||||
|
Reference in New Issue
Block a user