forked from xiaozhi/xiaozhi-esp32
* Upgrade component version * update fonts component version * Handle OTA error code * Update project version to 2.1.0 and add device state machine implementation - Upgrade esp-wifi-connect to 3.0.0, allowing reconfiguring wifi without rebooting - Introduce device state machine with state change notification in new files - Remove obsolete device state event files - Update application logic to utilize new state machine - Minor adjustments in various board implementations for state handling * fix compile errors * Refactor power saving mode implementation to use PowerSaveLevel enumeration - Updated Application class to replace SetPowerSaveMode with SetPowerSaveLevel, allowing for LOW_POWER and PERFORMANCE settings. - Modified various board implementations to align with the new power save level structure. - Ensured consistent handling of power save levels across different board files, enhancing code maintainability and clarity. * Refactor power save level checks across multiple board implementations - Updated the condition for power save level checks in various board files to ensure that the power save timer only wakes up when the level is not set to LOW_POWER. - Improved consistency in handling power save levels, enhancing code clarity and maintainability. * Refactor EnterWifiConfigMode calls in board implementations - Updated calls to EnterWifiConfigMode to use the appropriate instance reference (self or board) across multiple board files. - Improved code consistency and clarity in handling device state during WiFi configuration mode entry. * Add cellular modem event handling and improve network status updates - Introduced new network events for cellular modem operations, including detecting, registration errors, and timeouts. - Enhanced the Application class to handle different network states and update the display status accordingly. - Refactored Ml307Board to implement a callback mechanism for network events, improving modularity and responsiveness. - Updated dual_network_board and board headers to support new network event callbacks, ensuring consistent handling across board implementations. * update esp-wifi-connect version * Update WiFi configuration tool messages across multiple board implementations to clarify user actions
213 lines
9.0 KiB
C++
213 lines
9.0 KiB
C++
#include "cst816x.h"
|
|
#include "board.h"
|
|
#include "application.h"
|
|
#include "display.h"
|
|
#include "assets/lang_config.h"
|
|
#include "wifi_board.h"
|
|
#include "power_save_timer.h"
|
|
#include "codecs/es8311_audio_codec.h"
|
|
#include <algorithm> // 用于std::max/std::min
|
|
|
|
#define TAG "Cst816x"
|
|
|
|
const Cst816x::TouchThresholdConfig& Cst816x::getThresholdConfig(int x, int y) {
|
|
for (const auto& config : TOUCH_THRESHOLD_TABLE) {
|
|
if (config.x == x && config.y == y) {
|
|
return config;
|
|
}
|
|
}
|
|
return DEFAULT_THRESHOLD;
|
|
}
|
|
|
|
Cst816x::Cst816x(i2c_master_bus_handle_t i2c_bus, uint8_t addr) : I2cDevice(i2c_bus, addr) {
|
|
uint8_t chip_id = ReadReg(0xA7);
|
|
ESP_LOGI(TAG, "Get CST816x chip ID: 0x%02X", chip_id);
|
|
read_buffer_ = new uint8_t[6];
|
|
}
|
|
|
|
Cst816x::~Cst816x() {
|
|
if (read_buffer_ != nullptr) {
|
|
delete[] read_buffer_;
|
|
read_buffer_ = nullptr;
|
|
}
|
|
}
|
|
|
|
int64_t Cst816x::getCurrentTimeUs() {
|
|
struct timeval tv;
|
|
gettimeofday(&tv, nullptr);
|
|
return (int64_t)tv.tv_sec * 1000000L + tv.tv_usec;
|
|
}
|
|
|
|
void Cst816x::UpdateTouchPoint() {
|
|
ReadRegs(0x02, read_buffer_, 6);
|
|
tp_.num = read_buffer_[0] & 0x0F;
|
|
tp_.x = ((read_buffer_[1] & 0x0F) << 8) | read_buffer_[2];
|
|
tp_.y = ((read_buffer_[3] & 0x0F) << 8) | read_buffer_[4];
|
|
memset(read_buffer_, 0, 6);
|
|
}
|
|
|
|
void Cst816x::resetTouchCounters() {
|
|
is_touching_ = false;
|
|
touch_start_time_ = 0;
|
|
last_release_time_ = 0;
|
|
click_count_ = 0;
|
|
long_press_started_ = false;
|
|
|
|
is_volume_long_pressing_ = false;
|
|
volume_long_press_dir_ = 0;
|
|
last_volume_adjust_time_ = 0;
|
|
}
|
|
|
|
void Cst816x::touchpad_daemon(void* arg) {
|
|
Cst816x* cst816x = static_cast<Cst816x*>(arg);
|
|
auto& board = Board::GetInstance();
|
|
auto codec = board.GetAudioCodec();
|
|
auto display = board.GetDisplay();
|
|
|
|
while (1) {
|
|
cst816x->UpdateTouchPoint();
|
|
auto& tp = cst816x->GetTouchPoint();
|
|
int64_t current_time = cst816x->getCurrentTimeUs();
|
|
|
|
const auto& config = cst816x->getThresholdConfig(tp.x, tp.y);
|
|
if (tp.num > 0) {
|
|
ESP_LOGD(TAG, "Touch at (%d,%d) → SingleThresh:%lldms, DoubleWindow:%lldms, LongThresh:%lldms",
|
|
tp.x, tp.y,
|
|
config.single_click_thresh_us / 1000,
|
|
config.double_click_window_us / 1000,
|
|
config.long_press_thresh_us / 1000);
|
|
}
|
|
|
|
TouchEvent current_event;
|
|
bool event_detected = false;
|
|
|
|
if (tp.num > 0 && !cst816x->is_touching_) {
|
|
cst816x->is_touching_ = true;
|
|
cst816x->touch_start_time_ = current_time;
|
|
cst816x->long_press_started_ = false;
|
|
}
|
|
else if (tp.num > 0 && cst816x->is_touching_) {
|
|
if (!cst816x->long_press_started_ &&
|
|
(current_time - cst816x->touch_start_time_ >= config.long_press_thresh_us)) {
|
|
current_event = {TouchEventType::LONG_PRESS_START, tp.x, tp.y};
|
|
event_detected = true;
|
|
cst816x->long_press_started_ = true;
|
|
}
|
|
}
|
|
else if (tp.num == 0 && cst816x->is_touching_) {
|
|
cst816x->is_touching_ = false;
|
|
int64_t touch_duration = current_time - cst816x->touch_start_time_;
|
|
cst816x->last_release_time_ = current_time;
|
|
if (cst816x->long_press_started_) {
|
|
current_event = {TouchEventType::LONG_PRESS_END, tp.x, tp.y};
|
|
event_detected = true;
|
|
}
|
|
else if (touch_duration <= config.single_click_thresh_us) {
|
|
cst816x->click_count_++;
|
|
}
|
|
}
|
|
else if (tp.num == 0 && !cst816x->is_touching_) {
|
|
if (cst816x->click_count_ > 0 &&
|
|
(current_time - cst816x->last_release_time_ >= config.double_click_window_us)) {
|
|
if (cst816x->click_count_ == 2) {
|
|
current_event = {TouchEventType::DOUBLE_CLICK, tp.x, tp.y};
|
|
event_detected = true;
|
|
}
|
|
else if (cst816x->click_count_ == 1) {
|
|
current_event = {TouchEventType::SINGLE_CLICK, tp.x, tp.y};
|
|
event_detected = true;
|
|
}
|
|
cst816x->click_count_ = 0;
|
|
}
|
|
}
|
|
|
|
if (event_detected) {
|
|
if (current_event.y == 600 && (current_event.x == 20 || current_event.x == 40 || current_event.x == 60)) {
|
|
switch (current_event.type) {
|
|
case TouchEventType::SINGLE_CLICK:
|
|
if (current_event.x == 40) {
|
|
board.SetPowerSaveLevel(PowerSaveLevel::PERFORMANCE);
|
|
auto& app = Application::GetInstance();
|
|
if (app.GetDeviceState() == kDeviceStateStarting) {
|
|
auto& wifi_board = static_cast<WifiBoard&>(Board::GetInstance());
|
|
wifi_board.EnterWifiConfigMode();
|
|
return;
|
|
}
|
|
app.ToggleChatState();
|
|
} else if (current_event.x == 20) { // 20,600 单击:音量+
|
|
int current_vol = codec->output_volume();
|
|
int new_vol = current_vol + 10;
|
|
new_vol = (new_vol >= ES8311_VOL_MAX) ? ES8311_VOL_MAX : new_vol;
|
|
ESP_LOGI(TAG, "current_vol, new_vol(%d, %d)", current_vol, new_vol);
|
|
codec->EnableOutput(true);
|
|
codec->SetOutputVolume(new_vol);
|
|
display->ShowNotification(Lang::Strings::VOLUME + std::to_string(new_vol));
|
|
} else if (current_event.x == 60) { // 60,600 单击:音量-
|
|
int current_vol = codec->output_volume();
|
|
int new_vol = current_vol - 10;
|
|
new_vol = (new_vol <= ES8311_VOL_MIN) ? ES8311_VOL_MIN : new_vol;
|
|
ESP_LOGI(TAG, "current_vol, new_vol(%d, %d)", current_vol, new_vol);
|
|
codec->EnableOutput(true);
|
|
codec->SetOutputVolume(new_vol);
|
|
display->ShowNotification(Lang::Strings::VOLUME + std::to_string(new_vol));
|
|
}
|
|
break;
|
|
|
|
case TouchEventType::DOUBLE_CLICK:
|
|
ESP_LOGI(TAG, "Double click detected at (%d, %d)", current_event.x, current_event.y);
|
|
break;
|
|
|
|
case TouchEventType::LONG_PRESS_START:
|
|
ESP_LOGI(TAG, "Long press started at (%d, %d) → Start volume adjust", current_event.x, current_event.y);
|
|
if (current_event.x == 20) {
|
|
cst816x->is_volume_long_pressing_ = true;
|
|
cst816x->volume_long_press_dir_ = 1;
|
|
cst816x->last_volume_adjust_time_ = current_time;
|
|
} else if (current_event.x == 60) {
|
|
cst816x->is_volume_long_pressing_ = true;
|
|
cst816x->volume_long_press_dir_ = -1;
|
|
cst816x->last_volume_adjust_time_ = current_time;
|
|
}
|
|
break;
|
|
|
|
case TouchEventType::LONG_PRESS_END:
|
|
ESP_LOGI(TAG, "Long press ended at (%d, %d) → Stop volume adjust", current_event.x, current_event.y);
|
|
if (current_event.x == 20 || current_event.x == 60) {
|
|
cst816x->is_volume_long_pressing_ = false;
|
|
cst816x->volume_long_press_dir_ = 0;
|
|
cst816x->last_volume_adjust_time_ = 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cst816x->is_volume_long_pressing_) {
|
|
int64_t now = cst816x->getCurrentTimeUs();
|
|
if (now - cst816x->last_volume_adjust_time_ >= cst816x->VOL_ADJ_INTERVAL_US) {
|
|
int current_vol = codec->output_volume();
|
|
int new_vol = current_vol + (cst816x->volume_long_press_dir_ * cst816x->VOL_ADJ_STEP);
|
|
|
|
new_vol = std::max(ES8311_VOL_MIN, std::min(ES8311_VOL_MAX, new_vol));
|
|
|
|
if (new_vol != current_vol) {
|
|
codec->EnableOutput(true);
|
|
codec->SetOutputVolume(new_vol);
|
|
display->ShowNotification(Lang::Strings::VOLUME + std::to_string(new_vol));
|
|
cst816x->last_volume_adjust_time_ = now;
|
|
} else {
|
|
cst816x->is_volume_long_pressing_ = false;
|
|
cst816x->volume_long_press_dir_ = 0;
|
|
ESP_LOGI(TAG, "Volume reached limit (%d), stop adjusting", new_vol);
|
|
}
|
|
}
|
|
}
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(40));
|
|
}
|
|
}
|
|
|
|
void Cst816x::InitCst816d() {
|
|
ESP_LOGI(TAG, "Init CST816x touch driver");
|
|
xTaskCreate(touchpad_daemon, "touch_daemon", 2048, this, 1, NULL);
|
|
} |