Files
xiaozhi-esp32/main/boards/xingzhi-metal-1.54-wifi/cst816x.cc
Xiaoxia b7db68457c v2.1.0: Upgrade esp-wifi-connect to 3.0; New device state machine (#1528)
* 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
2025-12-09 09:24:56 +08:00

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);
}