/* * SPDX-FileCopyrightText: 2026 M5Stack Technology CO LTD * * SPDX-License-Identifier: MIT */ #include "hal.h" #include "drivers/Si12T/Si12T.h" #include "board/hal_bridge.h" #include #include #include static const std::string _tag = "HAL-HeadTouch"; // 触摸状态 enum class TouchState { IDLE, TOUCHED, SWIPING }; // 配置参数 struct TouchConfig { uint8_t touch_threshold = 1; int16_t swipe_threshold = 40; // 使用百分比,范围-100到100 }; // 触摸数据 struct TouchData { uint8_t intensity[3]; uint32_t timestamp; // 计算位置(返回-100到100的整数) int16_t get_position() const { uint16_t total = intensity[0] + intensity[1] + intensity[2]; if (total == 0) return 0; int32_t weighted = intensity[0] * (-100) + intensity[1] * 0 + intensity[2] * 100; return static_cast(weighted / total); } uint8_t get_max_intensity() const { uint8_t max_val = intensity[0]; if (intensity[1] > max_val) max_val = intensity[1]; if (intensity[2] > max_val) max_val = intensity[2]; return max_val; } bool is_touched() const { return get_max_intensity() >= 1; } }; // 手势识别器类 class GestureRecognizer { public: GestureRecognizer() : current_state(TouchState::IDLE), initial_position(0) { } // 更新状态机,返回识别到的手势 HeadPetGesture update(const TouchData& data) { HeadPetGesture gesture = HeadPetGesture::None; switch (current_state) { case TouchState::IDLE: if (data.is_touched()) { current_state = TouchState::TOUCHED; initial_position = data.get_position(); gesture = HeadPetGesture::Press; // mclog::tagDebug(_tag, "Touch detected at position: {}", initial_position); } break; case TouchState::TOUCHED: if (!data.is_touched()) { current_state = TouchState::IDLE; gesture = HeadPetGesture::Release; } else { // Check for swipe int16_t current_pos = data.get_position(); int16_t delta = current_pos - initial_position; if (delta > config.swipe_threshold) { current_state = TouchState::SWIPING; gesture = HeadPetGesture::SwipeForward; // mclog::tagDebug(_tag, "Swipe forward detected, delta: {}", delta); } else if (delta < -config.swipe_threshold) { current_state = TouchState::SWIPING; gesture = HeadPetGesture::SwipeBackward; // mclog::tagDebug(_tag, "Swipe backward detected, delta: {}", delta); } } break; case TouchState::SWIPING: if (!data.is_touched()) { current_state = TouchState::IDLE; gesture = HeadPetGesture::Release; } break; } return gesture; } void set_config(const TouchConfig& cfg) { config = cfg; } private: TouchConfig config; TouchState current_state; int16_t initial_position; }; static void _head_touch_update_task(void* param) { mclog::tagInfo(_tag, "start update task"); si12t_handle_t si12t = (si12t_handle_t)param; uint8_t touch_result = 0; TouchData data; GestureRecognizer recognizer; HeadPetGesture gesture; vTaskDelay(pdMS_TO_TICKS(200)); while (1) { // Read data si12t_read_touch_result(si12t, &touch_result); si12t_parse_touch_result_to(touch_result, data.intensity); data.timestamp = xTaskGetTickCount(); // Update and fire event gesture = recognizer.update(data); if (gesture != HeadPetGesture::None) { GetHAL().onHeadPetGesture.emit(gesture); } vTaskDelay(pdMS_TO_TICKS(50)); } } void Hal::head_touch_init() { mclog::tagInfo(_tag, "init"); auto i2c_bus = hal_bridge::board_get_i2c_bus(); si12t_config_t si12t_cfg = { .i2c_bus = i2c_bus, .dev_addr = SI12T_GND_ADDRESS, }; static si12t_handle_t si12t; si12t_init(&si12t_cfg, &si12t); si12t_setup(si12t, SI12T_TYPE_LOW, SI12T_SENSITIVITY_LEVEL_3); xTaskCreate(_head_touch_update_task, "headtouch", 4096, si12t, 5, NULL); }