mirror of
https://github.com/m5stack/StackChan.git
synced 2026-04-27 11:02:40 +00:00
5001b7081b
* add firmware source code
163 lines
4.6 KiB
C++
163 lines
4.6 KiB
C++
/*
|
|
* 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 <mooncake_log.h>
|
|
#include <freertos/FreeRTOS.h>
|
|
#include <freertos/task.h>
|
|
|
|
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<int16_t>(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);
|
|
}
|