mcu_hi3321_watch/tjd/driver/encoder/encoder_port.c
2025-05-26 20:15:20 +08:00

727 lines
22 KiB
C

#include "encoder_port.h"
#include "cmsis_os2.h"
#include "gpio.h"
#include "input_manager.h"
#include "pinctrl.h"
#include "pm.h"
#include "power_display_service.h"
#include "rtc.h"
#include "semaphore.h"
#include "soc_errno.h"
#include "sys_config.h"
#include "task_driver_event.h"
#include "tcxo.h"
#include "time.h"
#if defined(TJD_PCBA_1)
#include "common_i2c.h"
#include "common_pm.h"
#include "encoder_drv_kth5763.h"
#endif
#define ENABLE_PRINT_INFO 1
#if ENABLE_PRINT_INFO
#define static_print_info(...) sys_enc_log_i(__VA_ARGS__) // 一般信息打印宏控制
#define static_print_warn(...) sys_enc_log_w(__VA_ARGS__) // 警告信息打印一般常开
#define static_print_error(...) sys_enc_log_e(__VA_ARGS__) // 错误信息打印一般常开
#define static_print_debug(...) sys_enc_log_d(__VA_ARGS__) // 调试信息打印一般常开
#else
#define static_print_info(...)
#define static_print_warn(...)
#define static_print_error(...)
#define static_print_debug(...)
#endif
#if defined(TJD_PCBA_0)
static osTimerId_t g_rotary_timer_handle;
#define A_SIGNAL_PIN S_MGPIO7
#define B_SIGNAL_PIN S_MGPIO6
#endif
#define REPORT_OUT_TIME_MS 155
static report_event_cb g_report_event_cb = NULL;
static struct rotary_encoder g_rotary_encoder = {
#if defined(TJD_PCBA_1)
.i2c_bus = I2C_BUS_2,
.i2c_speed = 400000,
#if (CALIBRATION_MODE)
.i2c_addr = KTH5701_I2C_ADDR,
#else
.i2c_addr = KTH5763_I2C_ADDR,
#endif
.int_pin = S_MGPIO9,
#endif
.steps = 10,
.pos = 0,
#if defined(TJD_PCBA_0)
.gpio_descs =
{
.desc = {A_SIGNAL_PIN, B_SIGNAL_PIN},
.ndescs = 2,
}
#endif
};
#if defined(TJD_PCBA_1)
#define I2C_RETRY_TIMES 3
static osThreadId_t g_rotary_duty_handle = NULL;
static uint8_t g_send_buf[4] = {0};
static uint8_t g_recv_buf[32] = {0};
static osThreadState_t g_rotary_duty_state = osThreadInactive;
static bool g_encoder_host_dev_init_flag = false;
static uint32_t get_currunt_time(void)
{
#define MILLISEC_TO_NANOSEC 1000000
#define SEC_TO_MILLISEC 1000
struct timespec time;
clock_gettime(CLOCK_MONOTONIC, &time);
return time.tv_sec * SEC_TO_MILLISEC + time.tv_nsec / MILLISEC_TO_NANOSEC;
}
static uint32_t get_elapse_time(uint32_t startTime)
{
uint32_t currentTime = get_currunt_time();
uint32_t elapseTime;
if (currentTime > startTime) {
elapseTime = currentTime - startTime;
} else {
elapseTime = (UINT32_MAX - startTime) + currentTime + 1;
}
return elapseTime;
}
static ext_errno encoder_peripheral_init_status_check(void)
{
if (g_encoder_host_dev_init_flag != true) {
return EXT_ERR_TP_DEV_INFO_NOT_REGISTER;
}
return ENC_SUCC;
}
uint32_t encoder_i2c_cmd_write(uint8_t cmd)
{
const struct rotary_encoder *encoder = &g_rotary_encoder;
errcode_t ret;
uint8_t retry;
i2c_data_t data;
ret = encoder_peripheral_init_status_check();
if (ret != ENC_SUCC) {
static_print_error("host peripheral not init! ret=0x%x", ret);
return ret;
}
g_send_buf[0] = cmd;
data.send_buf = g_send_buf;
data.send_len = 1;
data.receive_buf = NULL;
data.receive_len = 0;
for (retry = 0; retry < I2C_RETRY_TIMES; retry++) {
ret = tjd_driver_common_i2c_get_ops()->write(I2C_MODEL_ENCODER_ID, &data);
if (ret == ENC_SUCC) {
break;
}
}
if (ret != ENC_SUCC) {
static_print_error("encoder data write fail! ret=0x%x", ret);
return ret;
}
return ENC_SUCC;
}
uint32_t encoder_i2c_package_write(uint8_t *data_buf, uint32_t data_len)
{
const struct rotary_encoder *encoder = &g_rotary_encoder;
errcode_t ret;
uint8_t retry;
ret = encoder_peripheral_init_status_check();
if (ret != 0) {
static_print_error("host peripheral not init! ret=0x%x", ret);
return ret;
}
i2c_data_t data = {.send_buf = data_buf, .send_len = data_len};
for (retry = 0; retry < I2C_RETRY_TIMES; retry++) {
ret = tjd_driver_common_i2c_get_ops()->write(I2C_MODEL_ENCODER_ID, &data);
if (ret == ENC_SUCC) {
break;
}
}
if (ret != ENC_SUCC) {
static_print_error("encoder package write fail! ret=0x%x", ret);
return ret;
}
return ENC_SUCC;
}
uint32_t encoder_i2c_reg_write(uint32_t reg_addr, uint8_t reg_len, uint8_t reg_cfg)
{
const struct rotary_encoder *encoder = &g_rotary_encoder;
errcode_t ret;
uint32_t retry;
i2c_data_t data;
ret = encoder_peripheral_init_status_check();
if (ret != 0) {
static_print_error("host peripheral not init! ret=0x%x", ret);
return ret;
}
reg_len = reg_len & 0x0F;
memset(g_send_buf, 0, sizeof(g_send_buf));
int i = reg_len;
while (i) {
i--;
g_send_buf[i] = reg_addr;
reg_addr >>= 8;
}
g_send_buf[reg_len] = reg_cfg;
data.send_buf = g_send_buf;
data.send_len = reg_len + 1;
data.receive_buf = NULL;
data.receive_len = 0;
for (retry = 0; retry < I2C_RETRY_TIMES; retry++) {
ret = tjd_driver_common_i2c_get_ops()->write(I2C_MODEL_ENCODER_ID, &data);
if (ret == ENC_SUCC) {
break;
}
}
if (ret != ENC_SUCC) {
static_print_error("encoder reg write fail! ret=0x%x", ret);
return ret;
}
return ENC_SUCC;
}
uint32_t encoder_i2c_data_read(uint32_t reg_addr, uint8_t reg_len, uint8_t *data_buf, uint16_t data_len)
{
const struct rotary_encoder *encoder = &g_rotary_encoder;
errcode_t ret;
uint32_t retry;
i2c_data_t data;
ret = encoder_peripheral_init_status_check();
if (ret != 0) {
static_print_error("host peripheral not init! ret=0x%x", ret);
return ret;
}
reg_len = reg_len & 0x0F;
memset(g_send_buf, 0, sizeof(g_send_buf));
if (memset_s(g_recv_buf, data_len, 0, data_len) != EOK) {
static_print_error("encoder read buff set fail! ret=0x%x", ret);
return EXT_ERR_FAILURE;
}
int i = reg_len;
while (i) {
i--;
g_send_buf[i] = reg_addr;
reg_addr >>= 8;
}
data.send_buf = g_send_buf;
data.send_len = reg_len;
data.receive_buf = g_recv_buf;
data.receive_len = data_len;
for (retry = 0; retry < I2C_RETRY_TIMES; retry++) {
ret = tjd_driver_common_i2c_get_ops()->writeread(I2C_MODEL_ENCODER_ID, &data);
if (ret == ENC_SUCC) {
break;
}
}
if (ret != ENC_SUCC) {
static_print_error("encoder reg read fail! ret=0x%x", ret);
return ret;
}
ret = (uint32_t)memcpy_s(data_buf, data_len, g_recv_buf, data_len);
if (ret != EOK) {
static_print_error("encoder data buf content copy fail! ret=0x%x", ret);
return ret;
}
return ENC_SUCC;
}
uint32_t encoder_i2c_data_write_read(uint8_t *send_buf, uint16_t data_len, uint8_t *recv_buf, uint16_t recv_len)
{
const struct rotary_encoder *encoder = &g_rotary_encoder;
errcode_t ret;
uint8_t retry;
i2c_data_t data;
ret = encoder_peripheral_init_status_check();
if (ret != 0) {
static_print_error("host peripheral not init! ret=0x%x", ret);
return ret;
}
data.send_buf = send_buf;
data.send_len = data_len;
data.receive_buf = g_recv_buf;
data.receive_len = recv_len;
for (retry = 0; retry < I2C_RETRY_TIMES; retry++) {
ret = tjd_driver_common_i2c_get_ops()->writeread(I2C_MODEL_ENCODER_ID, &data);
if (ret == ENC_SUCC) {
break;
}
}
if (ret != ENC_SUCC) {
static_print_error("encoder package write fail! ret=0x%x", ret);
return ret;
}
ret = (uint32_t)memcpy_s(recv_buf, recv_len, g_recv_buf, recv_len);
if (ret != EOK) {
static_print_error("encoder data buf content copy fail! ret=0x%x", ret);
return ret;
}
return ENC_SUCC;
}
void enocder_open(void)
{
const struct power_manager_class_ops *power_manager_ops = tjd_driver_common_pm_get_ops();
power_manager_ops->set_model_power_status(POWER_MODEL_ENCODER_ID, PM_POWER_STATUS_ON);
osDelay(80);
}
void enocder_close(void)
{
const struct power_manager_class_ops *power_manager_ops = tjd_driver_common_pm_get_ops();
// power_manager_ops->set_model_power_status(POWER_MODEL_ENCODER_ID, PM_POWER_STATUS_OFF);
}
#endif
uint32_t encoder_register_report_event_cb(ReportEventCb callback)
{
if (g_report_event_cb != NULL) {
return ENC_FAIL;
}
g_report_event_cb = callback;
return ENC_SUCC;
}
uint32_t encoder_unregister_report_event_cb(void)
{
if (g_report_event_cb == NULL) {
return ENC_FAIL;
}
g_report_event_cb = NULL;
return ENC_SUCC;
}
static void rotary_encoder_report_event(struct rotary_encoder *encoder)
{
const power_display_svr_api_t *display_api = power_display_svr_get_api();
int16_t pos = encoder->pos;
// static_print_debug("rotary_encoder_get_state pos:%x", pos);
/* turning clockwise */
// if (pos < encoder->steps)
// pos++;
// encoder->pos = pos;
InputDevData data = {
.type = INDEV_TYPE_ENCODER, .state = 1, .rotate = pos, .timestamp = (uint32_t)uapi_tcxo_get_ms()};
if (display_api->get_screen_state() != SCREEN_ON) {
return;
}
display_api->set_auto_timeout_function(false);
if (g_report_event_cb != NULL) {
g_report_event_cb(&data);
}
/* 释放屏幕和低功耗 */
display_api->set_auto_timeout_function(true);
}
void rotary_out_time_callback(void *data)
{
unused(data);
struct rotary_encoder *encoder = &g_rotary_encoder;
encoder->pos = 0;
rotary_encoder_report_event(encoder);
}
typedef struct
{
signed int (*func_event_handler)(void *param); // 事件处理函数
void *param; // 事件处理函数入参
void (*func_event_debug)(char *str, ...); // 打印
void *payload;
} encoder_driver_event_info_t;
#if defined(TJD_PCBA_0)
static void rotary_encoder_get_state(struct rotary_encoder *encoder)
{
static uint16_t cnt = 0;
static uint16_t signal_b = 0;
if (uapi_gpio_get_val(encoder->gpio_descs.desc[0]) == 0 && cnt == 0) { // A相下降沿触发第一次中断
cnt++;
signal_b = 0;
if (uapi_gpio_get_val(encoder->gpio_descs.desc[1]) == 1) {
signal_b = 1;
}
}
if (uapi_gpio_get_val(encoder->gpio_descs.desc[0]) == 1 && cnt == 1) { // A相上升沿触发第二次中断
cnt = 0;
if (signal_b == 1 && uapi_gpio_get_val(encoder->gpio_descs.desc[1]) == 0) {
encoder->pos += 1; // 正转
rotary_encoder_report_event(encoder);
} else if (signal_b == 0 && uapi_gpio_get_val(encoder->gpio_descs.desc[1]) == 1) {
encoder->pos -= 1; // 反转
rotary_encoder_report_event(encoder);
}
}
}
static signed int encoder_event_handler(void *param)
{
unused(param);
const struct rotary_encoder *encoder = &g_rotary_encoder;
rotary_encoder_get_state(encoder);
if (osTimerIsRunning(g_rotary_timer_handle)) {
osTimerStop(g_rotary_timer_handle);
}
osTimerStart(g_rotary_timer_handle, REPORT_OUT_TIME_MS);
return 0;
}
static void rotary_encoder_irq(pin_t pin, uintptr_t param)
{
uint32_t ret = 0;
static encoder_driver_event_info_t g_msg_data = {
.func_event_handler = encoder_event_handler,
.param = NULL,
.func_event_debug = NULL,
.payload = NULL,
};
static unsigned int g_msg_size = sizeof(encoder_driver_event_info_t);
ret = osal_msg_queue_write_copy(tjd_task_driver_event_get_queue_id(), &g_msg_data, g_msg_size, 0);
if (ret != 0) {
static_print_error("msg send failed! err=0x%x", ret);
}
}
#endif
#if defined(TJD_PCBA_1)
struct rotary_calculate
{
uint16_t angle_old;
uint16_t diff_angle;
uint8_t power_flag : 1;
uint8_t key_update_flag : 1;
uint8_t key_state : 1;
uint8_t last_key_state : 1;
};
static void rotary_duty_task(void *arg)
{
unused(arg);
#define ANGLE_TRESHOLD 100
struct rotary_encoder *encoder = &g_rotary_encoder;
struct rotary_calculate calculate = {0};
uint16_t angle = 0;
uint32_t ret = 0;
uint32_t report_timer_counter = 0;
g_rotary_duty_state = osThreadRunning;
while (1) {
uapi_pm_add_sleep_veto_with_timeout(PM_ID_ENCODER, 50);
ret = kth5763_measurement(0x04, &angle);
if (ret != ENC_SUCC) {
static_print_error("KTH5763: measurement mode failed, %x", ret);
osDelay(50);
continue;
}
if (calculate.power_flag == 0) {
calculate.power_flag = 1;
calculate.angle_old = angle;
}
if (angle > calculate.angle_old) {
if (angle < calculate.angle_old + 1800) { // 顺时针
if (angle >= calculate.angle_old + ANGLE_TRESHOLD) {
calculate.diff_angle = angle - calculate.angle_old;
calculate.key_update_flag = 1; // 有效旋转
calculate.key_state = 1; // 正转
calculate.angle_old = angle;
}
} else if (angle >= calculate.angle_old + 1800) { // 逆时针
if (3600 - angle + calculate.angle_old >= ANGLE_TRESHOLD) {
calculate.diff_angle = calculate.angle_old + 3600 - angle;
calculate.key_update_flag = 1;
calculate.key_state = 0; // 反转
calculate.angle_old = angle;
}
}
} else if (angle < calculate.angle_old) {
if (angle + 1800 > calculate.angle_old) {
if (angle + ANGLE_TRESHOLD <= calculate.angle_old) {
calculate.diff_angle = calculate.angle_old - angle;
calculate.key_update_flag = 1;
calculate.key_state = 0; // 反转
calculate.angle_old = angle;
}
} else if (angle + 1800 <= calculate.angle_old) {
if (3600 - calculate.angle_old + angle > ANGLE_TRESHOLD) {
calculate.diff_angle = 3600 + angle - calculate.angle_old;
calculate.key_update_flag = 1;
calculate.key_state = 1; // 正转
calculate.angle_old = angle;
}
}
}
if (calculate.key_update_flag == 1) {
/* 往相反方向转动 */
if (calculate.last_key_state != calculate.key_state) {
encoder->pos = 0;
}
uint8_t pos_offset = (calculate.diff_angle / 100) * 1 + 1;
if (calculate.key_state) {
encoder->pos = 10; // 反转
} else {
encoder->pos = -10; // 正转
}
calculate.last_key_state = calculate.key_state;
// static_print_info("encoder->pos = %d", encoder->pos);
rotary_encoder_report_event(encoder);
report_timer_counter = get_currunt_time();
calculate.key_update_flag = 0;
}
if (report_timer_counter != 0 && get_elapse_time(report_timer_counter) >= 200) {
rotary_out_time_callback(NULL);
report_timer_counter = 0;
}
osDelay(50);
}
}
#if (CALIBRATION_MODE)
void rotary_calibration_duty_task(void *arg)
{
struct rotary_calibration_data
{
uint16_t x_max;
uint16_t y_max;
uint16_t z_max;
uint16_t x_min;
uint16_t y_min;
uint16_t z_min;
} rotary_data = {
.x_max = 32768,
.y_max = 32768,
.z_max = 32768,
.x_min = 32768,
.y_min = 32768,
.z_min = 32768,
};
uint16_t x_data = 0;
uint16_t y_data = 0;
uint16_t z_data = 0;
uint8_t data[9] = {0};
uint32_t ret = 0;
osDelay(100);
while (1) {
ret = kth5763_xyz_measurement(XYZ_MODE, data);
if (ret != ENC_SUCC) {
static_print_error("KTH5763: measurement mode failed, %x", ret);
osDelay(50);
continue;
}
x_data = (data[3] << 8) + data[4]; // 读取X轴输出值
y_data = (data[5] << 8) + data[6]; // 读取y轴输出值
z_data = (data[7] << 8) + data[8]; // 读取z轴输出值
static_print_info("X = %d, Y = %d, Z = %d", x_data, y_data, z_data);
if (rotary_data.x_min == 0 && rotary_data.y_min == 0 && rotary_data.z_min == 0) {
rotary_data.x_min = x_data;
rotary_data.y_min = y_data;
rotary_data.z_min = z_data;
}
if (rotary_data.x_max < x_data) {
rotary_data.x_max = x_data;
}
if (rotary_data.y_max < y_data) {
rotary_data.y_max = y_data;
}
if (rotary_data.z_max < z_data) {
rotary_data.z_max = z_data;
}
if (rotary_data.x_min > x_data) {
rotary_data.x_min = x_data;
}
if (rotary_data.y_min > y_data) {
rotary_data.y_min = y_data;
}
if (rotary_data.z_min > z_data) {
rotary_data.z_min = z_data;
}
static_print_debug("x_max = %d, y_max = %d, z_max = %d x_min = %d, y_min = %d, z_min = %d", rotary_data.x_max,
rotary_data.y_max, rotary_data.z_max, rotary_data.x_min, rotary_data.y_min,
rotary_data.z_min);
osDelay(50);
}
}
#endif
#endif
void rotary_suspend_for_i2c(void)
{
const struct rotary_encoder *encoder = &g_rotary_encoder;
static_print_info("rotary_suspend_for_i2c %d", encoder->i2c_bus);
i2c_save_reg(encoder->i2c_bus);
}
void rotary_resume_for_i2c(void)
{
const struct rotary_encoder *encoder = &g_rotary_encoder;
static_print_info("rotary_resume_for_i2c %d", encoder->i2c_bus);
i2c_recovery_reg(encoder->i2c_bus);
}
uint32_t encoder_suspend(void)
{
rotary_encoder_deinit();
return 0;
}
uint32_t encoder_resume(void)
{
rotary_encoder_init(NULL);
return 0;
}
uint32_t rotary_encoder_init(struct rotary_encoder *encoder_attr)
{
unused(encoder_attr);
uint32_t ret = 0;
struct rotary_encoder *encoder = &g_rotary_encoder;
/* register int io interrupt handler */
uapi_gpio_init();
uapi_pin_init();
#if defined(TJD_PCBA_1)
enocder_open();
/* v1版本采用i2c方式 */
ret = tjd_driver_common_i2c_get_ops()->open(I2C_MODEL_ENCODER_ID, encoder->i2c_bus, encoder->i2c_addr,
encoder->i2c_speed);
if (ret != ENC_SUCC && ret != ERRCODE_I2C_ALREADY_INIT) {
static_print_error("i2c master init failed, %x", ret);
enocder_close();
return ENC_FAIL;
}
g_encoder_host_dev_init_flag = true;
ret = kth5763_init();
if (ret != ENC_SUCC) {
static_print_error("KTH5763: init failed, %x", ret);
enocder_close();
return ENC_FAIL;
}
osDelay(10);
osThreadAttr_t task_attr = {"tjd_encoder_task", 0, NULL, 0, NULL, 0x900, 17, 0, 0};
task_attr.stack_mem = memalign(16, task_attr.stack_size);
#if (CALIBRATION_MODE)
g_rotary_duty_handle = osThreadNew(rotary_calibration_duty_task, NULL, &task_attr);
#else
g_rotary_duty_handle = osThreadNew(rotary_duty_task, NULL, &task_attr);
#endif
if (g_rotary_duty_handle == NULL) {
static_print_error("create rotary timer failed");
enocder_close();
return ENC_FAIL;
}
#endif
#if defined(TJD_PCBA_0)
g_rotary_timer_handle = osTimerNew((osTimerFunc_t)rotary_out_time_callback, osTimerOnce, 0, NULL);
if (g_rotary_timer_handle == NULL) {
static_print_error("create rotary timer failed");
return ENC_FAIL;
}
for (int i = 0; i < encoder->gpio_descs.ndescs; ++i) {
uapi_pin_set_mode(encoder->gpio_descs.desc[i], HAL_PIO_FUNC_GPIO);
uapi_pin_set_pull(encoder->gpio_descs.desc[i], HAL_PIO_PULL_UP);
uapi_gpio_set_dir(encoder->gpio_descs.desc[i], GPIO_DIRECTION_INPUT);
}
uapi_tcxo_delay_ms(5);
ret = uapi_gpio_register_isr_func(encoder->gpio_descs.desc[0], GPIO_INTERRUPT_DEDGE, rotary_encoder_irq);
if (ret != ENC_SUCC) {
static_print_error("register isr func failed, %x", ret);
return ret;
}
uapi_tcxo_delay_ms(5);
ret = uapi_gpio_enable_interrupt(encoder->gpio_descs.desc[0]);
if (ret != ENC_SUCC) {
static_print_error("enable interrupt failed, %x", ret);
return ret;
}
#endif
static_print_info("rotary encoder init success");
return ENC_SUCC;
}
uint32_t rotary_encoder_deinit(void)
{
uint32_t ret = 0;
#if defined(TJD_PCBA_0)
uapi_gpio_disable_interrupt(g_rotary_encoder.gpio_descs.desc[0]);
uapi_gpio_unregister_isr_func(g_rotary_encoder.gpio_descs.desc[0]);
#endif
#if defined(TJD_PCBA_1)
if (g_rotary_duty_handle == NULL) {
return ENC_SUCC;
}
if (g_rotary_duty_state == osThreadRunning) {
if (osThreadTerminate(g_rotary_duty_handle) != osOK) {
static_print_error("terminate rotary task failed");
}
g_rotary_duty_state = osThreadInactive;
}
osDelay(25);
kth5763_enter_idle();
tjd_driver_common_i2c_get_ops()->close(I2C_MODEL_ENCODER_ID);
g_encoder_host_dev_init_flag = false;
static_print_info("rotary encoder deinit success");
#endif
enocder_close();
return ENC_SUCC;
}