Files
JBao_Temp_Humi_Fan_FW/apps/common/device/key/iokey.c
T
2026-08-29 11:06:52 +08:00

356 lines
9.1 KiB
C

#include "key_driver.h"
#include "iokey.h"
#include "gpio.h"
#include "system/event.h"
#include "app_config.h"
#include "asm/clock.h"
#if TCFG_IOKEY_ENABLE
static const struct iokey_platform_data *__this = NULL;
u8 io_get_key_value(void);
#if MOUSE_KEY_SCAN_MODE
struct key_driver_para iokey_scan_para = {
.scan_time = 5, //按键扫描频率, 单位: ms
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
.filter_time = 2, //按键消抖延时;
.long_time = 5, //按键判定长按数量
.hold_time = (5 + 0), //按键判定HOLD数量
.click_delay_time = 20, //按键被抬起后等待连击延时数量
.key_type = KEY_DRIVER_TYPE_IO,
.get_value = io_get_key_value,
};
#else
//按键驱动扫描参数列表
struct key_driver_para iokey_scan_para = {
.scan_time = 10, //按键扫描频率, 单位: ms
.last_key = NO_KEY, //上一次get_value按键值, 初始化为NO_KEY;
.filter_time = 4, //按键消抖延时;
.long_time = 75, //按键判定长按数量
.hold_time = (75 + 15), //按键判定HOLD数量
.click_delay_time = 20, //按键被抬起后等待连击延时数量
.key_type = KEY_DRIVER_TYPE_IO,
.get_value = io_get_key_value,
};
#endif
#define MARK_BIT_VALUE(b, v) do {if ((v & (~BIT(7))) < 7) b |= BIT(v & (~BIT(7)));} while(0)
static void key_io_pull_down_input(u8 key_io)
{
gpio_direction_input(key_io);
gpio_set_pull_down(key_io, 1);
gpio_set_pull_up(key_io, 0);
gpio_set_die(key_io, 1);
}
static void key_io_pull_up_input(u8 key_io)
{
gpio_direction_input(key_io);
gpio_set_pull_down(key_io, 0);
gpio_set_pull_up(key_io, 1);
gpio_set_die(key_io, 1);
}
static void key_io_output_high(u8 key_io)
{
gpio_set_pull_down(key_io, 0);
gpio_set_pull_up(key_io, 0);
gpio_direction_output(key_io, 1);
}
static void key_io_output_low(u8 key_io)
{
gpio_set_pull_down(key_io, 0);
gpio_set_pull_up(key_io, 0);
gpio_direction_output(key_io, 0);
}
static int get_io_key_value(u8 key_io)
{
return gpio_read(key_io);
}
static void key_io_reset(void)
{
int i;
for (i = 0; i < __this->num; i++) {
switch (__this->port[i].connect_way) {
case ONE_PORT_TO_HIGH:
key_io_pull_down_input(__this->port[i].key_type.one_io.port);
break;
case ONE_PORT_TO_LOW:
#if (TCFG_IO_MULTIPLEX_WITH_SD == ENABLE)
if (TCFG_MULTIPLEX_PORT != __this->port[i].key_type.one_io.port) {
key_io_pull_up_input(__this->port[i].key_type.one_io.port);
}
#else
key_io_pull_up_input(__this->port[i].key_type.one_io.port);
#endif
break;
case DOUBLE_PORT_TO_IO:
break;
default:
ASSERT(0, "IO KEY CONNECT ERR!!!");
break;
}
}
}
#if MULT_KEY_ENABLE
extern const struct key_remap_data iokey_remap_data;
static u8 iokey_value_remap(u8 bit_mark)
{
for (int i = 0; i < iokey_remap_data.remap_num; i++) {
if (iokey_remap_data.table[i].bit_value == bit_mark) {
return iokey_remap_data.table[i].remap_value;
}
}
return NO_KEY;
}
#endif
#if TCFG_IO_MULTIPLEX_WITH_SD == ENABLE
static u8 mult_key_value = 1;
static void udelay(u32 usec)
{
JL_TIMER0->CON = BIT(14);
JL_TIMER0->CNT = 0;
JL_TIMER0->PRD = clk_get("lsb") / 1000000L * usec;
JL_TIMER0->CON = BIT(0); //lsb clk
while ((JL_TIMER0->CON & BIT(15)) == 0);
JL_TIMER0->CON = BIT(14);
}
extern u8 sd_io_suspend(u8 sdx, u8 sd_io);
extern u8 sd_io_resume(u8 sdx, u8 sd_io);
void sd_mult_io_detect(void *arg)
{
static u32 cnt = 0;
if (sd_io_suspend(1, 1) == 0) {
gpio_set_direction(TCFG_MULTIPLEX_PORT, 0);
gpio_write(TCFG_MULTIPLEX_PORT, 0);
udelay(10);
gpio_set_die(TCFG_MULTIPLEX_PORT, 1);
gpio_set_pull_down(TCFG_MULTIPLEX_PORT, 0);
gpio_set_pull_up(TCFG_MULTIPLEX_PORT, 1);
gpio_set_direction(TCFG_MULTIPLEX_PORT, 1);
udelay(10);
mult_key_value = gpio_read(TCFG_MULTIPLEX_PORT);
sd_io_resume(1, 1);
}
}
#endif
__attribute__((weak)) u8 iokey_filter_hook(u8 io_state)
{
return 0;
}
/* 开机锁键剩余确认次数;非 0 时扫描一律返回 NO_KEY */
static u8 s_boot_lock_cnt;
/**
* @brief 启动/关闭开机锁键
* @param release_cnt >0:松开后连续确认次数;0:关闭
*/
void iokey_boot_lock_start(u8 release_cnt)
{
#if TCFG_IOKEY_BOOT_LOCK_ENABLE
s_boot_lock_cnt = release_cnt;
#else
(void)release_cnt;
s_boot_lock_cnt = 0;
#endif
}
/**
* @brief 立即关闭开机锁键
*/
void iokey_boot_lock_stop(void)
{
s_boot_lock_cnt = 0;
}
/**
* @brief 扫描路径更新锁键:监视 port[0],松开则递减计数
* @return 1=仍锁定(应返回 NO_KEY),0=已解锁可正常扫描
*/
static u8 iokey_boot_lock_update(void)
{
#if !TCFG_IOKEY_BOOT_LOCK_ENABLE
return 0;
#else
u8 key_io;
u8 io_level;
u8 released;
if (!s_boot_lock_cnt)
{
return 0;
}
if (!__this || (__this->num == 0))
{
return 1;
}
key_io = __this->port[0].key_type.one_io.port;
io_level = gpio_read(key_io);
if (__this->port[0].connect_way == ONE_PORT_TO_LOW)
{
released = io_level; /* 上拉输入,松开为高 */
}
else
{
released = !io_level; /* 下拉输入,松开为低 */
}
if (released)
{
s_boot_lock_cnt--;
if (s_boot_lock_cnt == 0)
{
puts("iokey boot lock released\n");
}
}
return 1; /* 本拍仍屏蔽;计数到 0 后下一拍才开放 */
#endif
}
u8 io_get_key_value(void)
{
int i;
u8 press_value = 0;
u8 read_value = 0;
u8 read_io;
u8 write_io;
u8 connect_way;
u8 ret_value = NO_KEY;
u8 bit_mark = 0;
if (!__this->enable) {
return NO_KEY;
}
if (iokey_boot_lock_update()) {
return NO_KEY;
}
//先扫描单IO接按键方式
for (i = 0; i < __this->num; i++) {
connect_way = __this->port[i].connect_way;
if (connect_way == ONE_PORT_TO_HIGH) {
press_value = 1;
} else if (connect_way == ONE_PORT_TO_LOW) {
press_value = 0;
} else {
continue;
}
read_io = __this->port[i].key_type.one_io.port;
#if (TCFG_IO_MULTIPLEX_WITH_SD == ENABLE)
if (read_io == TCFG_MULTIPLEX_PORT) {
read_value = mult_key_value;
} else {
read_value = get_io_key_value(read_io);
}
#else
read_value = get_io_key_value(read_io);
#endif
if (iokey_filter_hook(read_value)) {
#ifdef TCFG_IOKEY_TIME_REDEFINE
extern struct key_driver_para iokey_scan_user_para;
iokey_scan_user_para.filter_cnt = 0;
iokey_scan_user_para.press_cnt = 0;
iokey_scan_user_para.click_cnt = 0;
iokey_scan_user_para.click_delay_cnt = 0;
iokey_scan_user_para.last_key = NO_KEY;
#else
iokey_scan_para.filter_cnt = 0;
iokey_scan_para.press_cnt = 0;
iokey_scan_para.click_cnt = 0;
iokey_scan_para.click_delay_cnt = 0;
iokey_scan_para.last_key = NO_KEY;
#endif
return NO_KEY;
}
if (read_value == press_value) {
ret_value = __this->port[i].key_value;
#if MULT_KEY_ENABLE
MARK_BIT_VALUE(bit_mark, ret_value); //标记被按下的按键
#else
goto _iokey_get_value_end;
#endif
}
}
//再扫描两个IO接按键方式, in_port: 上拉输入, out_port: 输出低
for (i = 0; i < __this->num; i++) {
connect_way = __this->port[i].connect_way;
if (connect_way == DOUBLE_PORT_TO_IO) {//标准双io
press_value = 0;
read_io = __this->port[i].key_type.two_io.in_port;
key_io_output_low(__this->port[i].key_type.two_io.out_port); //输出低
key_io_pull_up_input(read_io); //上拉
read_value = get_io_key_value(read_io);
key_io_reset(); //按键初始化为单IO检测状态
if (read_value == press_value) {
ret_value = __this->port[i].key_value;
#if MULT_KEY_ENABLE
MARK_BIT_VALUE(bit_mark, ret_value); //标记被按下的按键
#else
goto _iokey_get_value_end;
#endif
}
}
}
#if MULT_KEY_ENABLE
bit_mark = iokey_value_remap(bit_mark); //组合按键重新映射按键值
ret_value = (bit_mark != NO_KEY) ? bit_mark : ret_value;
#endif
_iokey_get_value_end:
return ret_value;
}
int iokey_init(const struct iokey_platform_data *iokey_data)
{
int i;
__this = iokey_data;
if (__this == NULL) {
return -EINVAL;
}
if (!__this->enable) {
return KEY_NOT_SUPPORT;
}
/* 长按开机场景:等电源键(port[0])松开后再开放按键扫描 */
#if TCFG_IOKEY_BOOT_LOCK_ENABLE
iokey_boot_lock_start(IOKEY_BOOT_LOCK_DEFAULT_CNT);
#else
iokey_boot_lock_stop();
#endif
key_io_reset();
return 0;
}
#endif /* #if TCFG_IOKEY_ENABLE */