THB2/bthome_phy6222/SDK/components/driver/kscan/kscan.c

403 lines
12 KiB
C

/*******************************************************************************
@file kscan.c
@brief Contains all functions support for key scan driver
@version 0.0
@date 13. Nov. 2017
@author Ding
SDK_LICENSE
*******************************************************************************/
#include "rom_sym_def.h"
#include <string.h>
#include "clock.h"
#include "OSAL.h"
#include "kscan.h"
#include "pwrmgr.h"
#include "error.h"
#include "gpio.h"
#include "uart.h"
#include "bus_dev.h"
#include "log.h"
#include "jump_function.h"
typedef struct
{
bool enable;
kscan_Cfg_t cfg;
uint16_t key_state[MULTI_KEY_NUM<<1];
uint8_t pin_state[NUM_KEY_ROWS];
uint8_t kscan_task_id;
uint16_t timeout_event;
} kscan_Ctx_t;
static kscan_Ctx_t m_kscanCtx;
static kscan_Key_t m_keys[MAX_KEY_NUM];
static uint8_t reScan_flag=0;
//PRIVATE FUNCTIONS
static void kscan_hw_config(void);
static void hal_kscan_config_row(KSCAN_ROWS_e row);
static void hal_kscan_config_col(KSCAN_COLS_e col);
static void kscan_sleep_handler(void);
static void kscan_wakeup_handler(void);
static void get_key_matrix(uint16_t* key_matrix);
static void rmv_ghost_key(uint16_t* key_matrix);
static kscan_Evt_t kscan_compare_key(uint16_t* key_pre, uint16_t* key_nxt);
static void hal_kscan_clear_config(void);
extern void hal_gpioin_set_flag(gpio_pin_e pin);
#define TIMEOUT_DELTA 10
/**************************************************************************************
@fn hal_kscan_init
@brief This function process for key scan initial
input parameters
@param None.
output parameters
@param None.
@return None.
**************************************************************************************/
int hal_kscan_init(kscan_Cfg_t cfg, uint8 task_id, uint16 event)
{
if(m_kscanCtx.enable)
return PPlus_ERR_INVALID_STATE;
m_kscanCtx.cfg = cfg;
m_kscanCtx.kscan_task_id = task_id;
m_kscanCtx.timeout_event = event;
m_kscanCtx.enable = TRUE;
kscan_hw_config();
JUMP_FUNCTION(KSCAN_IRQ_HANDLER) = (uint32_t)&hal_KSCAN_IRQHandler;
hal_pwrmgr_register(MOD_KSCAN, kscan_sleep_handler, kscan_wakeup_handler);
return PPlus_SUCCESS;
}
/**************************************************************************************
@fn hal_kscan_clear_config
@brief This function process for key scan clear config
input parameters
@param None.
output parameters
@param None.
@return None.
**************************************************************************************/
void hal_kscan_clear_config()
{
subWriteReg(&(AP_IOMUX->keyscan_in_en),10,0,0);//iomux:key_scan_in_en and key_scan_out_en
subWriteReg(&(AP_IOMUX->keyscan_out_en),11,0,0);
subWriteReg((&AP_KSCAN->ctrl0), 13, 2, 0);//kscan:mattrix scan outputs and mattrix scan inputs
subWriteReg((&AP_KSCAN->mk_in_en), 10, 0, 0);
}
void __attribute__((used)) hal_KSCAN_IRQHandler()
{
uint16_t key_nxt[MULTI_KEY_NUM<<1];
if(reScan_flag==1)
reScan_flag=0;
osal_stop_timerEx(m_kscanCtx.kscan_task_id, m_kscanCtx.timeout_event);//todo
get_key_matrix(key_nxt);
if(m_kscanCtx.cfg.ghost_key_state == IGNORE_GHOST_KEY)
rmv_ghost_key(key_nxt);
if(m_kscanCtx.cfg.evt_handler)
{
kscan_Evt_t evt = kscan_compare_key(m_kscanCtx.key_state, key_nxt);
if(evt.num>0)
m_kscanCtx.cfg.evt_handler(&evt);
}
memcpy(m_kscanCtx.key_state, key_nxt, sizeof(uint16_t)*(MULTI_KEY_NUM<<1));
osal_start_timerEx(m_kscanCtx.kscan_task_id, m_kscanCtx.timeout_event, (2*m_kscanCtx.cfg.interval+TIMEOUT_DELTA));//todo
}
void hal_kscan_timeout_handler()
{
if(reScan_flag==0)
{
// LOG("kscan_reScan\n\r");
hal_kscan_clear_config();
reScan_flag=1;
kscan_hw_config();
osal_start_timerEx(m_kscanCtx.kscan_task_id, m_kscanCtx.timeout_event, m_kscanCtx.cfg.interval+TIMEOUT_DELTA);
}
else if(reScan_flag==1)
{
//LOG("kscan_timeout_handler\n\r");
osal_stop_timerEx(m_kscanCtx.kscan_task_id, m_kscanCtx.timeout_event);
uint16_t key_nxt[MULTI_KEY_NUM<<1];
memset(&key_nxt[0],0,sizeof(uint16_t)*(MULTI_KEY_NUM<<1)); //all register must be 0.teedy add 2019/01/23
//get_key_matrix(key_nxt); //no need to read the register,because keyScan didn't update the register .teedy add 2019/01/23
if(m_kscanCtx.cfg.ghost_key_state == IGNORE_GHOST_KEY)
rmv_ghost_key(key_nxt);
if(m_kscanCtx.cfg.evt_handler)
{
kscan_Evt_t evt = kscan_compare_key(m_kscanCtx.key_state, key_nxt);
m_kscanCtx.cfg.evt_handler(&evt);
}
memcpy(m_kscanCtx.key_state, key_nxt, sizeof(uint16_t)*(MULTI_KEY_NUM<<1));
reScan_flag=0;
hal_pwrmgr_unlock(MOD_KSCAN);
}
}
static void kscan_hw_config(void)
{
kscan_Cfg_t* cfg = &(m_kscanCtx.cfg);
hal_clk_gate_enable(MOD_KSCAN);
hal_kscan_clear_config();
for(uint8_t i=0; i<NUM_KEY_ROWS; i++)
hal_kscan_config_row(cfg->key_rows[i]);
for(uint8_t i=0; i<NUM_KEY_COLS; i++)
hal_kscan_config_col(cfg->key_cols[i]);
subWriteReg((&AP_KSCAN->ctrl0),20,20,NOT_IGNORE_MULTI_KEY);
subWriteReg((&AP_KSCAN->ctrl0),23,23,SENCE_LOW);//SENCE_HIGH
subWriteReg((&AP_KSCAN->ctrl0),31,24,cfg->interval);
NVIC_SetPriority((IRQn_Type)KSCAN_IRQn, IRQ_PRIO_HAL);
NVIC_EnableIRQ((IRQn_Type)KSCAN_IRQn);
subWriteReg((&AP_KSCAN->ctrl0),1,1,1);//kscan int enable
subWriteReg((&AP_KSCAN->ctrl0),0,0,1);//kscan enable
}
/**************************************************************************************
@fn hal_kscan_config_row
@brief This function process for setting key row pin
input parameters
@param KSCAN_ROWS_e row
output parameters
@param None.
@return None.
**************************************************************************************/
static void hal_kscan_config_row(KSCAN_ROWS_e row)
{
gpio_pin_e row_pin = (gpio_pin_e)KSCAN_ROW_GPIO[row];
hal_gpio_fmux(row_pin, Bit_DISABLE);
hal_gpio_pull_set(row_pin,GPIO_PULL_UP_S);
subWriteReg(&(AP_IOMUX->keyscan_in_en),row,row,1);
subWriteReg((&AP_KSCAN->mk_in_en),row,row, 1);
}
/**************************************************************************************
@fn hal_kscan_config_col
@brief This function process for setting key scan col pin
input parameters
@param KSCAN_COLS_e col
output parameters
@param None.
@return None.
**************************************************************************************/
static void hal_kscan_config_col(KSCAN_COLS_e col)
{
gpio_pin_e col_pin = (gpio_pin_e)KSCAN_COL_GPIO[col];
hal_gpio_fmux(col_pin, Bit_DISABLE);
hal_gpio_pull_set(col_pin,GPIO_PULL_UP_S);
subWriteReg(&(AP_IOMUX->keyscan_out_en),col,col,1);
subWriteReg((&AP_KSCAN->ctrl0),(col+2),(col+2), 1);
}
static void kscan_sleep_handler(void)
{
gpio_polarity_e pol;
hal_kscan_clear_config();
for(uint8_t i=0; i<NUM_KEY_COLS; i++)
{
gpio_pin_e col_pin = (gpio_pin_e)KSCAN_COL_GPIO[m_kscanCtx.cfg.key_cols[i]];
subWriteReg(&(AP_IOMUX->keyscan_out_en),m_kscanCtx.cfg.key_cols[i],m_kscanCtx.cfg.key_cols[i],0);
hal_gpioin_set_flag(col_pin);
hal_gpio_pull_set(col_pin, GPIO_PULL_DOWN);
hal_gpio_pin_init(col_pin, GPIO_INPUT);
}
for(uint8_t i=0; i<NUM_KEY_ROWS; i++)
{
gpio_pin_e row_pin = (gpio_pin_e)KSCAN_ROW_GPIO[m_kscanCtx.cfg.key_rows[i]];
subWriteReg(&(AP_IOMUX->keyscan_in_en),m_kscanCtx.cfg.key_rows[i],m_kscanCtx.cfg.key_rows[i],0);
hal_gpioin_set_flag(row_pin);
hal_gpio_pull_set(row_pin, GPIO_PULL_UP);
hal_gpio_pin_init(row_pin, GPIO_INPUT);
pol = hal_gpio_read(row_pin) ? POL_FALLING:POL_RISING;
hal_gpio_wakeup_set(row_pin, pol);
m_kscanCtx.pin_state[i] = pol;
}
}
static void kscan_wakeup_handler(void)
{
for(uint8_t i=0; i<NUM_KEY_COLS; i++)
{
gpio_pin_e col_pin = (gpio_pin_e)KSCAN_COL_GPIO[m_kscanCtx.cfg.key_cols[i]];
subWriteReg(&(AP_IOMUX->keyscan_out_en),m_kscanCtx.cfg.key_cols[i],m_kscanCtx.cfg.key_cols[i],0);
hal_gpio_pull_set(col_pin, GPIO_PULL_DOWN);
hal_gpio_pin_init(col_pin, GPIO_INPUT);
}
for(uint8_t i=0; i<NUM_KEY_ROWS; i++)
{
gpio_pin_e row_pin = (gpio_pin_e)KSCAN_ROW_GPIO[m_kscanCtx.cfg.key_rows[i]];
subWriteReg(&(AP_IOMUX->keyscan_in_en),m_kscanCtx.cfg.key_rows[i],m_kscanCtx.cfg.key_rows[i],0);
hal_gpio_pull_set(row_pin, GPIO_PULL_UP);//teddy add 20190122
hal_gpio_pin_init(row_pin, GPIO_INPUT);
}
for(uint8_t i=0; i<NUM_KEY_ROWS; i++)
{
gpio_pin_e row_pin = (gpio_pin_e)KSCAN_ROW_GPIO[m_kscanCtx.cfg.key_rows[i]];
hal_gpio_pin_init(row_pin, GPIO_INPUT);
gpio_polarity_e pol = hal_gpio_read(row_pin) ? POL_RISING:POL_FALLING;
if(pol == m_kscanCtx.pin_state[i])
{
break;
}
else if(i == (NUM_KEY_ROWS-1))
{
return;
}
}
hal_pwrmgr_lock(MOD_KSCAN);
for(uint8_t i=0; i<NUM_KEY_COLS; i++) //teddy add 20190122
{
gpio_pin_e col_pin = (gpio_pin_e)KSCAN_COL_GPIO[m_kscanCtx.cfg.key_cols[i]];
hal_gpio_pull_set(col_pin, GPIO_PULL_UP);
hal_gpio_pin_init(col_pin, GPIO_INPUT);
}
kscan_hw_config();
reScan_flag=0;
osal_start_timerEx(m_kscanCtx.kscan_task_id, m_kscanCtx.timeout_event, (m_kscanCtx.cfg.interval + TIMEOUT_DELTA));
}
/**************************************************************************************
@fn get_key_matrix
@brief This function process for reading key row and col
input parameters
@param uint16_t* key_matrix
output parameters
@param None.
@return None.
**************************************************************************************/
static void get_key_matrix(uint16_t* key_matrix)
{
for(uint8_t i=0; i < MULTI_KEY_NUM; i++)
{
uint16_t low = (read_reg(&(AP_KSCAN->mkc[i])) & 0x0000FFFF);
uint16_t high = (read_reg(&(AP_KSCAN->mkc[i])) & 0xFFFF0000) >> 16;
key_matrix[i*2] = low;
key_matrix[i*2+1] = high;
}
}
/**************************************************************************************
@fn rmv_ghost_key
@brief This function process for removing ghost key
input parameters
@param uint16_t* key_matrix
output parameters
@param None.
@return None.
**************************************************************************************/
static void rmv_ghost_key(uint16_t* key_matrix)
{
uint16_t mix_final = 0;
for (uint8_t i=0; i<MAX_KEY_COLS; ++i)
{
for (uint8_t j=i+1; j<MAX_KEY_ROWS; ++j)
{
uint16_t mix = key_matrix[i] & key_matrix[j];
uint8_t bit_is_pow2 = (mix&(mix-1)) == 0;
if (mix && !bit_is_pow2)
mix_final |= mix;
}
key_matrix[i] &= ~mix_final;
}
}
static kscan_Evt_t kscan_compare_key(uint16_t* key_pre, uint16_t* key_nxt)
{
uint16_t multi_key_num = 0;
for(uint8_t i=0; i<MAX_KEY_COLS; i++)
{
uint16_t chg_key = key_pre[i] ^ key_nxt[i];
uint16_t key_sta = chg_key & key_nxt[i];
if(chg_key != 0)
{
for(uint8_t j=0; j<MAX_KEY_ROWS; j++)
{
if((chg_key & BIT(j)) != 0)
{
kscan_Key_t key_param;
key_param.row = j;
key_param.col = i;
key_param.type = (key_sta & BIT(j)) ? KEY_PRESSED:KEY_RELEASED;
m_keys[multi_key_num] = key_param;
multi_key_num++;
}
if(multi_key_num == MAX_KEY_NUM)
break;
}
}
}
kscan_Evt_t evt;
evt.keys = m_keys;
evt.num = multi_key_num;
return evt;
}