AC63_BT_SDK/apps/common/device/key/matrix_keyboard.c
2025-02-18 15:40:42 +08:00

352 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "matrix_keyboard.h"
#include "key_driver.h"
#include "gpio.h"
#include "system/event.h"
#include "app_config.h"
#include "timer.h"
#include "asm/power_interface.h"
#include "asm/power/p33.h"
#if TCFG_MATRIX_KEY_ENABLE && !TCFG_EX_MCU_ENABLE
#define MATRIX_NO_KEY 0x1 //没有按键时的IO电平
#define MATRIX_LONG_TIME 35
#define MATRIX_HOLD_TIME 35+10
#define MATRIX_KEY_FILTER_TIME 2
int (*matrix_key_data_send)(u8 report_id, u8 *data, u16 len) = NULL;
static volatile u8 is_key_active = 0;
static volatile u8 keep_wakeup_hold = 0;
static int matrix_key_wakeup_hold_timer = 0;
static int matrix_key_timer = 0;
static matrix_key_st key_st[ROW_MAX][COL_MAX];
static matrix_key_param *this = NULL;
u8 notify_key_array[8] = {0};
u8 key_map[COL_MAX] = {0};
static u16 key_status_array[6] = {0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff};
static void full_key_array(u8 row, u8 col, u8 st)
{
u8 offset = 0;
u8 mark = 0, mark_offset = 0;
//最多推6个按键出来如果需要推多个按键需要自行修改每个u16 低八位标识row 高八位标识col
u16 key_value = (row | col << 8);
for (offset = 0; offset < sizeof(key_status_array) / sizeof(u16); offset++) {
if (key_status_array[offset] == key_value && st == MATRIX_KEY_UP) { //找到列表中有当前按键且按键状态抬起,则将按键移除列表
mark = 1; //记录相同键值所在位置
mark_offset = offset;
if (mark_offset == sizeof(key_status_array) / sizeof(u16) - 1) {
key_status_array[mark_offset] = 0xffff;
break;
}
} else if (key_status_array[offset] == 0xffff) {
if (mark) {
memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (offset - mark_offset - 1) * 2);
key_status_array[offset - 1] = 0xffff;
} else if (st == MATRIX_KEY_SHORT) { //需要状态为短按才会把键值填充到数组中,防止按键满了之后把抬起也填充进去
key_status_array[offset] = key_value;
}
break;
} else if (mark && (offset == sizeof(key_status_array) / sizeof(u16) - 1)) {
memcpy(key_status_array + mark_offset, key_status_array + mark_offset + 1, (sizeof(key_status_array) / sizeof(u16) - mark_offset - 1) * 2);
key_status_array[sizeof(key_status_array) / sizeof(u16) - 1] = 0xffff;
break;
}
}
}
void full_key_map(u8 row, u8 col, u8 st)
{
if (st) {
key_map[col] |= BIT(row);
} else {
key_map[col] &= ~BIT(row);
}
}
void P33_AND_WKUP_EDGE(u8 data);
void P33_OR_WKUP_EDGE(u8 data);
enum {
IO_STATUS_HIGH_DRIVER = 0,
IO_STATUS_OUTPUT_HIGH,
IO_STATUS_OUTPUT_LOW,
IO_STATUS_INPUT_PULL_DOWN,
IO_STATUS_INPUT_PULL_UP,
};
void matrix_key_set_io_state(u8 state, u32 *io_table, u8 len)
{
u8 i = 0;
u32 porta_value = 0;
u32 portb_value = 0;
u32 portc_value = 0;
u32 portd_value = 0;
for (; i < len; i++) {
switch (io_table[i] / IO_GROUP_NUM) {
case 0: //JL_PORTA
porta_value |= BIT(io_table[i] % IO_GROUP_NUM);
break;
case 1: //JL_PORTB
portb_value |= BIT(io_table[i] % IO_GROUP_NUM);
break;
case 2: //JL_PORTC
portc_value |= BIT(io_table[i] % IO_GROUP_NUM);
break;
case 3: //JL_PORTD
portd_value |= BIT(io_table[i] % IO_GROUP_NUM);
break;
default://USB
break;
}
}
switch (state) {
case IO_STATUS_HIGH_DRIVER:
JL_PORTA->DIR |= porta_value;
JL_PORTA->DIE |= porta_value;
JL_PORTA->PU &= ~porta_value;
JL_PORTA->PD &= ~porta_value;
JL_PORTB->DIR |= portb_value;
JL_PORTB->DIE |= portb_value;
JL_PORTB->PU &= ~portb_value;
JL_PORTB->PD &= ~portb_value;
JL_PORTC->DIR |= portc_value;
JL_PORTC->DIE |= portc_value;
JL_PORTC->PU &= ~portc_value;
JL_PORTC->PD &= ~portc_value;
JL_PORTD->DIR |= portd_value;
JL_PORTD->DIE |= portd_value;
JL_PORTD->PU &= ~portd_value;
JL_PORTD->PD &= ~portd_value;
break;
case IO_STATUS_OUTPUT_HIGH:
JL_PORTA->DIR &= ~porta_value;
JL_PORTA->OUT |= porta_value;
JL_PORTB->DIR &= ~portb_value;
JL_PORTB->OUT |= portb_value;
JL_PORTC->DIR &= ~portc_value;
JL_PORTC->OUT |= portc_value;
JL_PORTD->DIR &= ~portd_value;
JL_PORTD->OUT |= portd_value;
break;
case IO_STATUS_OUTPUT_LOW:
JL_PORTA->DIR &= ~porta_value;
JL_PORTA->OUT &= ~porta_value;
JL_PORTB->DIR &= ~portb_value;
JL_PORTB->OUT &= ~portb_value;
JL_PORTC->DIR &= ~portc_value;
JL_PORTC->OUT &= ~portc_value;
JL_PORTD->DIR &= ~portd_value;
JL_PORTD->OUT &= ~portd_value;
break;
case IO_STATUS_INPUT_PULL_DOWN:
JL_PORTA->DIR |= porta_value;
JL_PORTA->DIE |= porta_value;
JL_PORTA->PU &= ~porta_value;
JL_PORTA->PD |= porta_value;
JL_PORTB->DIR |= portb_value;
JL_PORTB->DIE |= portb_value;
JL_PORTB->PU &= ~portb_value;
JL_PORTB->PD |= portb_value;
JL_PORTC->DIR |= portc_value;
JL_PORTC->DIE |= portc_value;
JL_PORTC->PU &= ~portc_value;
JL_PORTC->PD |= portc_value;
JL_PORTD->DIR |= portd_value;
JL_PORTD->DIE |= portd_value;
JL_PORTD->PU &= ~portd_value;
JL_PORTD->PD |= portd_value;
break;
case IO_STATUS_INPUT_PULL_UP:
JL_PORTA->DIR |= porta_value;
JL_PORTA->DIE |= porta_value;
JL_PORTA->PU |= porta_value;
JL_PORTA->PD &= ~porta_value;
JL_PORTB->DIR |= portb_value;
JL_PORTB->DIE |= portb_value;
JL_PORTB->PU |= portb_value;
JL_PORTB->PD &= ~portb_value;
JL_PORTC->DIR |= portc_value;
JL_PORTC->DIE |= portc_value;
JL_PORTC->PU |= portc_value;
JL_PORTC->PD &= ~portc_value;
JL_PORTD->DIR |= portd_value;
JL_PORTD->DIE |= portd_value;
JL_PORTD->PU |= portd_value;
JL_PORTD->PD &= ~portd_value;
break;
}
}
#if 1
void port_edge_wakeup_control(u16 data);
void matrix_key_scan(void)
{
u8 row, col;
u8 cur_key_value = MATRIX_NO_KEY, notify = 0;
static u8 wk_toggle = 0;
//g_printf("scan...\n");
//P33_LEVEL_WKUP_EN(0);
port_edge_wakeup_control(0);
//p33_tx_1byte(P3_WKUP_EN, 0); //关掉wakeup防止扫描过程一直唤醒
//不直接调用gpio.c的接口主要是由于想控制扫描时间。这样能把时间从1.8ms缩减到800us
matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, this->col_pin_list, this->col_num);
is_key_active = 0;
for (col = 0; col < this->col_num; col ++) {
matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, &(this->col_pin_list[col]), 1);
//gpio_direction_output(this->col_pin_list[col], !MATRIX_NO_KEY);
for (row = 0; row < this->row_num; row ++) {
cur_key_value = gpio_read(this->row_pin_list[row]);
if (cur_key_value != MATRIX_NO_KEY) {
is_key_active = 1;
}
if (cur_key_value != (key_st[row][col]).last_st) {
if (cur_key_value == MATRIX_NO_KEY) { //按键抬起判断
(key_st[row][col]).press_cnt = 0;
//printf("row:%d col:%d [UP]\n", row, col);
(MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);
//P33_AND_WKUP_EDGE(row);
full_key_map(row, col, 0);
notify = 1;
} else { //按键初次按下
printf("row:%d col:%d [SHORT]\n", row, col);
full_key_map(row, col, 1);
(MATRIX_NO_KEY) ? P33_AND_WKUP_EDGE(row) : P33_OR_WKUP_EDGE(row);
//P33_OR_WKUP_EDGE(row);
notify = 1;
}
} else { //判断是否按键抬起
if (cur_key_value != MATRIX_NO_KEY) {
(key_st[row][col]).press_cnt ++;
if ((key_st[row][col]).press_cnt == MATRIX_LONG_TIME) {
/* printf("row:%d col:%d [LONG]\n", row, col); */
} else if ((key_st[row][col]).press_cnt == MATRIX_HOLD_TIME) {
/* printf("row:%d col:%d [HOLD]\n", row, col); */
(key_st[row][col]).press_cnt = MATRIX_LONG_TIME;
} else {
//press_cnt还未累加够
}
}
}
(key_st[row][col]).last_st = cur_key_value;
}
//gpio_direction_input(this->col_pin_list[col]);
matrix_key_set_io_state(IO_STATUS_HIGH_DRIVER, &(this->col_pin_list[col]), 1);
}
matrix_key_set_io_state((MATRIX_NO_KEY == 1) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, this->col_pin_list, this->col_num);
port_edge_wakeup_control(0xff);
//p33_tx_1byte(P3_WKUP_EN, 0xff);
//P33_LEVEL_WKUP_EN(1);
if (notify) {
struct sys_event e;
e.type = SYS_MATRIX_KEY_EVENT;
e.u.matrix_key.map = key_map;
e.arg = (void *)DEVICE_EVENT_FROM_KEY;
sys_event_notify(&e);
}
}
#else
void matrix_key_scan(void)
{
u8 row, col;
u8 cur_key_value = MATRIX_NO_KEY, notify = 0;
for (row = 0; row < this->row_num; row ++) {
gpio_direction_input(this->row_pin_list[row]);
gpio_set_die(this->row_pin_list[row], 1);
gpio_set_pull_up(this->row_pin_list[row], 1);
gpio_set_pull_down(this->row_pin_list[row], 0);
}
for (col = 0; col < this->col_num; col ++) {
gpio_direction_output(this->col_pin_list[col], 0);
gpio_set_die(this->col_pin_list[col], 1);
for (row = 0; row < this->row_num; row ++) {
if (gpio_read(this->row_pin_list[row]) == 0) {
printf("col:%x row:%x\n", col, row);
}
}
gpio_direction_input(this->col_pin_list[col]);
gpio_set_pull_up(this->col_pin_list[col], 0);
gpio_set_pull_up(this->col_pin_list[col], 0);
gpio_set_die(this->col_pin_list[col], 0);
}
}
#endif
void matrix_key_wakeup_timeout_handler(void *arg)
{
is_key_active = 1;
}
void matrix_key_wakeup_keep(void)
{
is_key_active = 1;
if (matrix_key_wakeup_hold_timer) {
sys_s_hi_timeout_del(matrix_key_wakeup_hold_timer);
}
matrix_key_wakeup_hold_timer = sys_s_hi_timerout_add(NULL, matrix_key_wakeup_timeout_handler, 10);
}
void matrix_key_wakeup(u8 idx, u32 gpio)
{
r_printf("matrix_key wkup!\n");
matrix_key_wakeup_keep();
}
int matrix_key_init(matrix_key_param *param)
{
if (!param) {
return -1; //参数无效
}
this = param;
u8 row, col;
for (row = 0; row < this->row_num; row ++) {
(MATRIX_NO_KEY) ? P33_OR_WKUP_EDGE(row) : P33_AND_WKUP_EDGE(row);
for (col = 0; col < this->col_num; col ++) {
(key_st[row][col]).last_st = MATRIX_NO_KEY;
(key_st[row][col]).press_cnt = 0;
}
}
printf("key_row:%d rol:%d\n", this->row_num, this->col_num);
if (matrix_key_timer) {
sys_s_hi_timer_del(matrix_key_timer);
}
matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_OUTPUT_LOW : IO_STATUS_OUTPUT_HIGH, this->col_pin_list, this->col_num);
matrix_key_set_io_state((MATRIX_NO_KEY) ? IO_STATUS_INPUT_PULL_UP : IO_STATUS_INPUT_PULL_DOWN, this->row_pin_list, this->row_num);
port_edge_wkup_set_callback(matrix_key_wakeup);
matrix_key_timer = sys_s_hi_timer_add(NULL, matrix_key_scan, 10);
return 0;
}
static u8 matrix_key_idle_query(void)
{
return !is_key_active;
}
REGISTER_LP_TARGET(matrix_key_lp_target) = {
.name = "matrix_key",
.is_idle = matrix_key_idle_query,
};
#endif