pinebuds/platform/hal/hal_key.c

1184 lines
34 KiB
C

/***************************************************************************
*
* Copyright 2015-2019 BES.
* All rights reserved. All unpublished rights reserved.
*
* No part of this work may be used or reproduced in any form or by any
* means, or stored in a database or retrieval system, without prior written
* permission of BES.
*
* Use of this work is governed by a license granted by BES.
* This work contains confidential and proprietary information of
* BES. which is protected by copyright, trade secret,
* trademark and other intellectual property rights.
*
****************************************************************************/
#include "plat_addr_map.h"
#include "plat_types.h"
#include "string.h"
#include "hal_iomux.h"
#include "hal_timer.h"
#include "hwtimer_list.h"
#include "hal_sleep.h"
#include "hal_trace.h"
#include "hal_chipid.h"
#include "hal_key.h"
#include "cmsis_nvic.h"
#include "pmu.h"
#include "tgt_hardware.h"
#ifdef KEY_DEBUG
#define HAL_KEY_TRACE(n, s, ...) TRACE(n, "[%u]" s, TICKS_TO_MS(hal_sys_timer_get()), ##__VA_ARGS__)
#else
#define HAL_KEY_TRACE(n, s, ...) TRACE_DUMMY(n, s, ##__VA_ARGS__)
#endif
#ifdef CHIP_BEST2000
#define GPIO_MAP_64BIT
#endif
#ifdef GPIO_MAP_64BIT
typedef uint64_t GPIO_MAP_T;
#else
typedef uint32_t GPIO_MAP_T;
#endif
// #ifndef APP_TEST_MODE
// #define CHECK_PWRKEY_AT_BOOT
// #endif
#ifdef NO_PWRKEY
#undef CHECK_PWRKEY_AT_BOOT
#endif
#ifdef NO_GPIOKEY
#undef CFG_HW_GPIOKEY_NUM
#define CFG_HW_GPIOKEY_NUM 0
#endif
#ifdef NO_ADCKEY
#undef CFG_HW_ADCKEY_NUMBER
#define CFG_HW_ADCKEY_NUMBER 0
#endif
#ifndef CFG_SW_KEY_LLPRESS_THRESH_MS
#define CFG_SW_KEY_LLPRESS_THRESH_MS 5000
#endif
#ifndef CFG_SW_KEY_LPRESS_THRESH_MS
#define CFG_SW_KEY_LPRESS_THRESH_MS 1500
#endif
#ifndef CFG_SW_KEY_REPEAT_THRESH_MS
#define CFG_SW_KEY_REPEAT_THRESH_MS 500
#endif
#ifndef CFG_SW_KEY_DBLCLICK_THRESH_MS
#define CFG_SW_KEY_DBLCLICK_THRESH_MS 400
#endif
#ifndef CFG_SW_KEY_INIT_DOWN_THRESH_MS
#define CFG_SW_KEY_INIT_DOWN_THRESH_MS 200
#endif
#ifndef CFG_SW_KEY_INIT_LPRESS_THRESH_MS
#define CFG_SW_KEY_INIT_LPRESS_THRESH_MS 3000
#endif
#ifndef CFG_SW_KEY_INIT_LLPRESS_THRESH_MS
#define CFG_SW_KEY_INIT_LLPRESS_THRESH_MS 10000
#endif
#ifndef CFG_SW_KEY_CHECK_INTERVAL_MS
#define CFG_SW_KEY_CHECK_INTERVAL_MS 40
#endif
//common key define
#define KEY_LONGLONGPRESS_THRESHOLD MS_TO_TICKS(CFG_SW_KEY_LLPRESS_THRESH_MS)
#define KEY_LONGPRESS_THRESHOLD MS_TO_TICKS(CFG_SW_KEY_LPRESS_THRESH_MS)
#define KEY_DOUBLECLICK_THRESHOLD MS_TO_TICKS(CFG_SW_KEY_DBLCLICK_THRESH_MS)
#define KEY_LONGPRESS_REPEAT_THRESHOLD MS_TO_TICKS(CFG_SW_KEY_REPEAT_THRESH_MS)
#define KEY_INIT_DOWN_THRESHOLD MS_TO_TICKS(CFG_SW_KEY_INIT_DOWN_THRESH_MS)
#define KEY_INIT_LONGPRESS_THRESHOLD MS_TO_TICKS(CFG_SW_KEY_INIT_LPRESS_THRESH_MS)
#define KEY_INIT_LONGLONGPRESS_THRESHOLD MS_TO_TICKS(CFG_SW_KEY_INIT_LLPRESS_THRESH_MS)
#define KEY_CHECKER_INTERVAL MS_TO_TICKS(CFG_SW_KEY_CHECK_INTERVAL_MS)
#define KEY_DEBOUNCE_INTERVAL (KEY_CHECKER_INTERVAL * 2)
#define KEY_DITHER_INTERVAL (KEY_CHECKER_INTERVAL * 1)
#define MAX_KEY_CLICK_COUNT (HAL_KEY_EVENT_RAMPAGECLICK - HAL_KEY_EVENT_CLICK)
struct HAL_KEY_ADCKEY_T {
bool debounce;
bool dither;
enum HAL_KEY_CODE_T code_debounce;
enum HAL_KEY_CODE_T code_down;
uint32_t time;
};
struct HAL_KEY_GPIOKEY_T {
GPIO_MAP_T pin_debounce;
GPIO_MAP_T pin_dither;
GPIO_MAP_T pin_down;
uint32_t time_debounce;
uint32_t time_dither;
};
struct HAL_KEY_PWRKEY_T {
bool debounce;
bool dither;
bool pressed;
uint32_t time;
};
struct HAL_KEY_STATUS_T {
enum HAL_KEY_CODE_T code_down;
enum HAL_KEY_CODE_T code_ready;
enum HAL_KEY_CODE_T code_click;
enum HAL_KEY_EVENT_T event;
uint32_t time_updown;
uint32_t time_click;
uint8_t cnt_repeat;
uint8_t cnt_click;
};
static int (*key_detected_callback)(uint32_t, uint8_t) = NULL;
static HWTIMER_ID debounce_timer = NULL;
static bool timer_active = false;
static struct HAL_KEY_STATUS_T key_status;
static void hal_key_disable_allint(void);
static void hal_key_enable_allint(void);
static int send_key_event(enum HAL_KEY_CODE_T code, enum HAL_KEY_EVENT_T event)
{
if (key_detected_callback) {
return key_detected_callback(code, event);
}
return 0;
}
static void hal_key_debounce_timer_restart(void)
{
uint32_t lock;
bool set = false;
lock = int_lock();
if (!timer_active) {
timer_active = true;
set = true;
}
int_unlock(lock);
if (set) {
hwtimer_stop(debounce_timer);
hwtimer_start(debounce_timer, KEY_CHECKER_INTERVAL);
//hal_sys_wake_lock(HAL_SYS_WAKE_LOCK_USER_KEY);
}
}
#if (CFG_HW_ADCKEY_NUMBER > 0)
static uint16_t adckey_volt_table[CFG_HW_ADCKEY_NUMBER];
struct HAL_KEY_ADCKEY_T adc_key;
static inline POSSIBLY_UNUSED void hal_adckey_enable_press_int(void)
{
hal_adckey_set_irq(HAL_ADCKEY_IRQ_PRESSED);
}
static inline POSSIBLY_UNUSED void hal_adckey_enable_release_int(void)
{
hal_adckey_set_irq(HAL_ADCKEY_IRQ_RELEASED);
}
static inline POSSIBLY_UNUSED void hal_adckey_enable_adc_int(void)
{
hal_gpadc_open(HAL_GPADC_CHAN_ADCKEY, HAL_GPADC_ATP_NULL, NULL);
}
static inline POSSIBLY_UNUSED void hal_adckey_disable_adc_int(void)
{
hal_gpadc_close(HAL_GPADC_CHAN_ADCKEY);
}
static inline POSSIBLY_UNUSED void hal_adckey_disable_allint(void)
{
hal_gpadc_close(HAL_GPADC_CHAN_ADCKEY);
hal_adckey_set_irq(HAL_ADCKEY_IRQ_NONE);
}
static inline POSSIBLY_UNUSED void hal_adckey_reset(void)
{
memset(&adc_key, 0, sizeof(adc_key));
}
static enum HAL_KEY_CODE_T hal_adckey_findkey(uint16_t volt)
{
int index = 0;
#if 0
if (volt == HAL_GPADC_BAD_VALUE) {
return HAL_KEY_CODE_NONE;
}
#endif
if (CFG_HW_ADCKEY_ADC_KEYVOLT_BASE < volt && volt < CFG_HW_ADCKEY_ADC_MAXVOLT) {
for (index = 0; index < CFG_HW_ADCKEY_NUMBER; index++) {
if (volt <= adckey_volt_table[index]) {
return CFG_HW_ADCKEY_MAP_TABLE[index];
}
}
}
return HAL_KEY_CODE_NONE;
}
static void hal_adckey_irqhandler(enum HAL_ADCKEY_IRQ_STATUS_T irq_status, HAL_GPADC_MV_T val)
{
enum HAL_KEY_CODE_T code;
#ifdef NO_GROUPKEY
hal_key_disable_allint();
#else
hal_adckey_disable_allint();
#endif
if (irq_status & (HAL_ADCKEY_ERR0 | HAL_ADCKEY_ERR1)) {
HAL_KEY_TRACE(1,"irq,adckey err 0x%04X", irq_status);
adc_key.debounce = true;
adc_key.code_debounce = HAL_KEY_CODE_NONE;
goto _debounce;
}
if (irq_status & HAL_ADCKEY_PRESSED) {
HAL_KEY_TRACE(0,"irq,adckey press");
adc_key.debounce = true;
adc_key.code_debounce = HAL_KEY_CODE_NONE;
adc_key.time = hal_sys_timer_get();
hal_adckey_enable_adc_int();
goto _exit;
}
if (irq_status & HAL_ADCKEY_RELEASED) {
HAL_KEY_TRACE(0,"irq,adckey release");
adc_key.code_debounce = HAL_KEY_CODE_NONE;
goto _debounce;
}
if(irq_status & HAL_ADCKEY_ADC_VALID) {
code = hal_adckey_findkey(val);
HAL_KEY_TRACE(3,"irq,adckey cur:0x%X pre:0x%X volt:%d", code, adc_key.code_debounce, val);
if (adc_key.code_debounce == HAL_KEY_CODE_NONE) {
adc_key.code_debounce = code;
} else if (adc_key.code_debounce != code) {
adc_key.code_debounce = HAL_KEY_CODE_NONE;
}
}
_debounce:
hal_key_debounce_timer_restart();
_exit:
return;
}
static void hal_adckey_open(void)
{
uint16_t i;
uint32_t basevolt;
HAL_KEY_TRACE(1,"%s\n", __func__);
hal_adckey_reset();
basevolt = (CFG_HW_ADCKEY_ADC_MAXVOLT - CFG_HW_ADCKEY_ADC_MINVOLT) / (CFG_HW_ADCKEY_NUMBER + 2);
adckey_volt_table[0] = CFG_HW_ADCKEY_ADC_KEYVOLT_BASE + basevolt;
for(i = 1; i < CFG_HW_ADCKEY_NUMBER-1; i++) {
adckey_volt_table[i] = adckey_volt_table[i - 1] + basevolt;
}
adckey_volt_table[CFG_HW_ADCKEY_NUMBER - 1] = CFG_HW_ADCKEY_ADC_MAXVOLT;
hal_adckey_set_irq_handler(hal_adckey_irqhandler);
}
static void hal_adckey_close(void)
{
HAL_KEY_TRACE(1,"%s\n", __func__);
hal_adckey_reset();
hal_adckey_disable_allint();
}
#endif // (CFG_HW_ADCKEY_NUMBER > 0)
#ifndef NO_PWRKEY
struct HAL_KEY_PWRKEY_T pwr_key;
static inline POSSIBLY_UNUSED void hal_pwrkey_enable_riseedge_int(void)
{
hal_pwrkey_set_irq(HAL_PWRKEY_IRQ_RISING_EDGE);
}
static inline POSSIBLY_UNUSED void hal_pwrkey_enable_falledge_int(void)
{
hal_pwrkey_set_irq(HAL_PWRKEY_IRQ_FALLING_EDGE);
}
static inline POSSIBLY_UNUSED void hal_pwrkey_enable_bothedge_int(void)
{
hal_pwrkey_set_irq(HAL_PWRKEY_IRQ_BOTH_EDGE);
}
static inline void hal_pwrkey_enable_int(void)
{
#ifdef __POWERKEY_CTRL_ONOFF_ONLY__
hal_pwrkey_enable_riseedge_int();
#else
hal_pwrkey_enable_falledge_int();
#endif
}
static inline void hal_pwrkey_disable_int(void)
{
hal_pwrkey_set_irq(HAL_PWRKEY_IRQ_NONE);
}
static inline void hal_pwrkey_reset(void)
{
memset(&pwr_key, 0, sizeof(pwr_key));
}
static inline bool hal_pwrkey_get_status(void)
{
#ifdef CHIP_BEST1000
if (hal_get_chip_metal_id() < HAL_CHIP_METAL_ID_2) {
return pwr_key.pressed;
} else
#endif
{
return hal_pwrkey_pressed();
}
}
static void hal_pwrkey_handle_irq_state(enum HAL_PWRKEY_IRQ_T state)
{
// uint32_t time = hal_sys_timer_get();
#ifdef NO_GROUPKEY
hal_key_disable_allint();
#else
hal_pwrkey_disable_int();
#endif
#ifdef __POWERKEY_CTRL_ONOFF_ONLY__
if (state & HAL_PWRKEY_IRQ_RISING_EDGE) {
HAL_KEY_TRACE(0,"pwr_key irq up");
pwr_key.debounce = true;
}
#else // !__POWERKEY_CTRL_ONOFF_ONLY__
if (state & HAL_PWRKEY_IRQ_FALLING_EDGE) {
HAL_KEY_TRACE(0,"pwr_key irq down");
#ifdef CHIP_BEST1000
if (hal_get_chip_metal_id() < HAL_CHIP_METAL_ID_2) {
pwr_key.debounce = true;
pwr_key.pressed = true;
hal_pwrkey_enable_riseedge_int();
} else
#endif
{
pwr_key.pressed = hal_pwrkey_pressed();
if (pwr_key.pressed) {
pwr_key.debounce = true;
} else {
pwr_key.dither = true;
}
}
// pwr_key.time = time;
}
#ifdef CHIP_BEST1000
if (state & HAL_PWRKEY_IRQ_RISING_EDGE) {
if (hal_get_chip_metal_id() < HAL_CHIP_METAL_ID_2) {
HAL_KEY_TRACE(0,"pwr_key irq up");
pwr_key.pressed = false;
hal_pwrkey_enable_falledge_int();
}
}
#endif
#endif // !__POWERKEY_CTRL_ONOFF_ONLY__
hal_key_debounce_timer_restart();
}
#ifdef CHIP_HAS_EXT_PMU
#define PWRKEY_IRQ_HDLR_PARAM uint16_t irq_status
#else
#define PWRKEY_IRQ_HDLR_PARAM void
#endif
static void hal_pwrkey_irqhandler(PWRKEY_IRQ_HDLR_PARAM)
{
enum HAL_PWRKEY_IRQ_T state;
#ifdef CHIP_HAS_EXT_PMU
state = pmu_pwrkey_irq_value_to_state(irq_status);
#else
state = hal_pwrkey_get_irq_state();
#endif
HAL_KEY_TRACE(2,"%s: %08x", __func__, state);
hal_pwrkey_handle_irq_state(state);
}
static void hal_pwrkey_open(void)
{
hal_pwrkey_reset();
#ifdef CHIP_HAS_EXT_PMU
pmu_set_irq_unified_handler(PMU_IRQ_TYPE_PWRKEY, hal_pwrkey_irqhandler);
#else
NVIC_SetVector(PWRKEY_IRQn, (uint32_t)hal_pwrkey_irqhandler);
NVIC_SetPriority(PWRKEY_IRQn, IRQ_PRIORITY_NORMAL);
NVIC_ClearPendingIRQ(PWRKEY_IRQn);
NVIC_EnableIRQ(PWRKEY_IRQn);
#endif
}
static void hal_pwrkey_close(void)
{
hal_pwrkey_reset();
hal_pwrkey_disable_int();
#ifdef CHIP_HAS_EXT_PMU
pmu_set_irq_unified_handler(PMU_IRQ_TYPE_PWRKEY, NULL);
#else
NVIC_SetVector(PWRKEY_IRQn, (uint32_t)NULL);
NVIC_DisableIRQ(PWRKEY_IRQn);
#endif
}
#endif // !NO_PWRKEY
#if (CFG_HW_GPIOKEY_NUM > 0)
struct HAL_KEY_GPIOKEY_T gpio_key;
static void hal_gpiokey_disable_irq(enum HAL_GPIO_PIN_T pin);
static inline void hal_gpiokey_reset(void)
{
memset(&gpio_key, 0, sizeof(gpio_key));
}
static int hal_gpiokey_find_index(enum HAL_GPIO_PIN_T pin)
{
int i;
for (i = 0; i < CFG_HW_GPIOKEY_NUM; i++) {
if (cfg_hw_gpio_key_cfg[i].key_config.pin == (enum HAL_IOMUX_PIN_T)pin) {
return i;
}
}
ASSERT(i < CFG_HW_GPIOKEY_NUM, "GPIOKEY IRQ: Invalid pin=%d", pin);
return i;
}
static bool hal_gpiokey_pressed(enum HAL_GPIO_PIN_T pin)
{
int i = hal_gpiokey_find_index(pin);
return (hal_gpio_pin_get_val(pin) == cfg_hw_gpio_key_cfg[i].key_down);
}
static void hal_gpiokey_irqhandler(enum HAL_GPIO_PIN_T pin)
{
bool pressed;
uint32_t lock;
uint32_t time;
#ifdef NO_GROUPKEY
hal_key_disable_allint();
#else
hal_gpiokey_disable_irq(pin);
#endif
pressed = hal_gpiokey_pressed(pin);
HAL_KEY_TRACE(2,"gpio_key trig=%d pressed=%d", pin, pressed);
time = hal_sys_timer_get();
lock = int_lock();
if (pressed) {
gpio_key.pin_debounce |= ((GPIO_MAP_T)1 << pin);
gpio_key.time_debounce = time;
} else {
gpio_key.pin_dither |= ((GPIO_MAP_T)1 << pin);
gpio_key.time_dither = time;
}
int_unlock(lock);
hal_key_debounce_timer_restart();
}
static void hal_gpiokey_enable_irq(enum HAL_GPIO_PIN_T pin, enum HAL_GPIO_IRQ_POLARITY_T polarity)
{
struct HAL_GPIO_IRQ_CFG_T gpiocfg;
hal_gpio_pin_set_dir(pin, HAL_GPIO_DIR_IN, 0);
gpiocfg.irq_enable = true;
gpiocfg.irq_debounce = true;
gpiocfg.irq_polarity = polarity;
gpiocfg.irq_handler = hal_gpiokey_irqhandler;
gpiocfg.irq_type = HAL_GPIO_IRQ_TYPE_LEVEL_SENSITIVE;
hal_gpio_setup_irq(pin, &gpiocfg);
}
static void hal_gpiokey_disable_irq(enum HAL_GPIO_PIN_T pin)
{
static const struct HAL_GPIO_IRQ_CFG_T gpiocfg = {
.irq_enable = false,
.irq_debounce = false,
.irq_polarity = HAL_GPIO_IRQ_POLARITY_LOW_FALLING,
.irq_handler = NULL,
.irq_type = HAL_GPIO_IRQ_TYPE_LEVEL_SENSITIVE,
};
hal_gpio_setup_irq(pin, &gpiocfg);
}
static inline void hal_gpiokey_enable_allint(void)
{
uint8_t i;
enum HAL_GPIO_IRQ_POLARITY_T polarity;
for (i = 0; i < CFG_HW_GPIOKEY_NUM; i++){
if (cfg_hw_gpio_key_cfg[i].key_code == HAL_KEY_CODE_NONE) {
continue;
}
if (cfg_hw_gpio_key_cfg[i].key_down == HAL_KEY_GPIOKEY_VAL_LOW) {
polarity = HAL_GPIO_IRQ_POLARITY_LOW_FALLING;
} else {
polarity = HAL_GPIO_IRQ_POLARITY_HIGH_RISING;
}
hal_gpiokey_enable_irq((enum HAL_GPIO_PIN_T)cfg_hw_gpio_key_cfg[i].key_config.pin, polarity);
}
}
static inline void hal_gpiokey_disable_allint(void)
{
uint8_t i;
for (i = 0; i < CFG_HW_GPIOKEY_NUM; i++) {
if (cfg_hw_gpio_key_cfg[i].key_code == HAL_KEY_CODE_NONE) {
continue;
}
hal_gpiokey_disable_irq((enum HAL_GPIO_PIN_T)cfg_hw_gpio_key_cfg[i].key_config.pin);
}
}
static void hal_gpiokey_open(void)
{
uint8_t i;
HAL_KEY_TRACE(1,"%s\n", __func__);
hal_gpiokey_reset();
for (i = 0; i < CFG_HW_GPIOKEY_NUM; i++) {
if (cfg_hw_gpio_key_cfg[i].key_code == HAL_KEY_CODE_NONE) {
continue;
}
hal_iomux_init(&cfg_hw_gpio_key_cfg[i].key_config, 1);
}
}
static void hal_gpiokey_close(void)
{
HAL_KEY_TRACE(1,"%s\n", __func__);
hal_gpiokey_reset();
hal_gpiokey_disable_allint();
}
#endif // (CFG_HW_GPIOKEY_NUM > 0)
enum HAL_KEY_EVENT_T hal_key_read_status(enum HAL_KEY_CODE_T code)
{
uint8_t gpio_val;
int i;
if (code == HAL_KEY_CODE_PWR){
if (hal_pwrkey_pressed())
return HAL_KEY_EVENT_DOWN;
else
return HAL_KEY_EVENT_UP;
}else{
for(i = 0; i < CFG_HW_GPIOKEY_NUM; i++) {
if(cfg_hw_gpio_key_cfg[i].key_code == code) {
gpio_val = hal_gpio_pin_get_val((enum HAL_GPIO_PIN_T)cfg_hw_gpio_key_cfg[i].key_config.pin);
if (gpio_val == cfg_hw_gpio_key_cfg[i].key_down) {
return HAL_KEY_EVENT_DOWN;
} else {
return HAL_KEY_EVENT_UP;
}
}
}
}
return HAL_KEY_EVENT_NONE;
}
static void hal_key_disable_allint(void)
{
#ifndef NO_PWRKEY
hal_pwrkey_disable_int();
#endif
#if (CFG_HW_ADCKEY_NUMBER > 0)
hal_adckey_disable_allint();
#endif
#if (CFG_HW_GPIOKEY_NUM > 0)
hal_gpiokey_disable_allint();
#endif
}
static void hal_key_enable_allint(void)
{
#ifndef NO_PWRKEY
hal_pwrkey_enable_int();
#endif
#if (CFG_HW_ADCKEY_NUMBER > 0)
hal_adckey_enable_press_int();
#endif
#if (CFG_HW_GPIOKEY_NUM > 0)
hal_gpiokey_enable_allint();
#endif
}
static void hal_key_debounce_handler(void *param)
{
uint32_t time;
enum HAL_KEY_CODE_T code_down = HAL_KEY_CODE_NONE;
int index;
bool need_timer = false;
timer_active = false;
time = hal_sys_timer_get();
#ifndef NO_PWRKEY
#ifdef __POWERKEY_CTRL_ONOFF_ONLY__
if (pwr_key.debounce) {
pwr_key.debounce = false;
code_down |= HAL_KEY_CODE_PWR;
#ifdef NO_GROUPKEY
hal_key_enable_allint();
#else
hal_pwrkey_enable_int();
#endif
}
#else
if (pwr_key.debounce || pwr_key.dither || pwr_key.pressed) {
bool pressed = hal_pwrkey_get_status();
//HAL_KEY_TRACE(4,"keyDbnPwr: dbn=%d dither=%d pressed=%d/%d", pwr_key.debounce, pwr_key.dither, pwr_key.pressed, pressed);
if (pwr_key.debounce) {
pwr_key.pressed = pressed;
if (pressed) {
pwr_key.dither = false;
if (time - pwr_key.time >= KEY_DEBOUNCE_INTERVAL) {
pwr_key.debounce = false;
pwr_key.dither = false;
code_down |= HAL_KEY_CODE_PWR;
}
} else {
pwr_key.debounce = false;
pwr_key.dither = true;
pwr_key.time = time;
}
} else if (pwr_key.dither) {
if (time - pwr_key.time >= KEY_DITHER_INTERVAL) {
pwr_key.dither = false;
pwr_key.pressed = false;
#ifdef NO_GROUPKEY
hal_key_enable_allint();
#else
hal_pwrkey_enable_int();
#endif
}
} else if (pwr_key.pressed) {
if (pressed) {
code_down |= HAL_KEY_CODE_PWR;
} else {
pwr_key.pressed = false;
#ifdef NO_GROUPKEY
hal_key_enable_allint();
#else
hal_pwrkey_enable_int();
#endif
}
}
}
if (pwr_key.debounce || pwr_key.dither || pwr_key.pressed) {
need_timer = true;
}
#endif
#endif
#if (CFG_HW_ADCKEY_NUMBER > 0)
if (adc_key.debounce || adc_key.dither || adc_key.code_down != HAL_KEY_CODE_NONE) {
bool skip_check = false;
//HAL_KEY_TRACE(4,"keyDbnAdc: dbn=%d dither=%d code_dbn=0x%X code_down=0x%X", adc_key.debounce, adc_key.dither, adc_key.code_debounce, adc_key.code_down);
if (adc_key.debounce) {
if (adc_key.code_debounce == HAL_KEY_CODE_NONE) {
adc_key.debounce = false;
adc_key.dither = true;
adc_key.time = time;
} else {
if (time - adc_key.time >= KEY_DEBOUNCE_INTERVAL) {
adc_key.debounce = false;
adc_key.dither = false;
adc_key.code_down = adc_key.code_debounce;
adc_key.code_debounce = HAL_KEY_CODE_NONE;
code_down |= adc_key.code_down;
}
}
} else if (adc_key.dither) {
if (time - adc_key.time >= KEY_DITHER_INTERVAL) {
adc_key.dither = false;
adc_key.code_debounce = HAL_KEY_CODE_NONE;
adc_key.code_down = HAL_KEY_CODE_NONE;
#ifdef NO_GROUPKEY
hal_key_enable_allint();
#else
hal_adckey_enable_press_int();
#endif
}
skip_check = true;
} else if (adc_key.code_down != HAL_KEY_CODE_NONE) {
if (adc_key.code_debounce == adc_key.code_down) {
code_down |= adc_key.code_down;
} else {
adc_key.code_down = HAL_KEY_CODE_NONE;
#ifdef NO_GROUPKEY
hal_key_enable_allint();
#else
hal_adckey_enable_press_int();
#endif
skip_check = true;
}
}
if (!skip_check) {
hal_adckey_enable_adc_int();
}
}
if (adc_key.debounce || adc_key.dither || adc_key.code_down != HAL_KEY_CODE_NONE) {
need_timer = true;
}
#endif
#if (CFG_HW_GPIOKEY_NUM > 0)
enum HAL_GPIO_PIN_T gpio;
GPIO_MAP_T pin;
uint32_t lock;
#ifdef GPIO_MAP_64BIT
ASSERT((gpio_key.pin_debounce & gpio_key.pin_dither) == 0 &&
(gpio_key.pin_debounce & gpio_key.pin_dither) == 0 &&
(gpio_key.pin_debounce & gpio_key.pin_dither) == 0,
"Bad gpio_key pin map: dbn=0x%X-%X dither=0x%X-%X down=0x%X-%X",
(uint32_t)(gpio_key.pin_debounce >> 32), (uint32_t)(gpio_key.pin_debounce),
(uint32_t)(gpio_key.pin_dither >> 32), (uint32_t)(gpio_key.pin_dither),
(uint32_t)(gpio_key.pin_down >> 32), (uint32_t)(gpio_key.pin_down));
#if 0
HAL_KEY_TRACE(6,"keyDbnGpio: pin_dbn=0x%X-%X pin_dither=0x%X-%X pin_down=0x%X-%X",
(uint32_t)(gpio_key.pin_debounce >> 32), (uint32_t)(gpio_key.pin_debounce),
(uint32_t)(gpio_key.pin_dither >> 32), (uint32_t)(gpio_key.pin_dither),
(uint32_t)(gpio_key.pin_down >> 32), (uint32_t)(gpio_key.pin_down));
#endif
#else // !GPIO_MAP_64BIT
ASSERT((gpio_key.pin_debounce & gpio_key.pin_dither) == 0 &&
(gpio_key.pin_debounce & gpio_key.pin_dither) == 0 &&
(gpio_key.pin_debounce & gpio_key.pin_dither) == 0,
"Bad gpio_key pin map: dbn=0x%X dither=0x%X down=0x%X",
(uint32_t)gpio_key.pin_debounce, (uint32_t)gpio_key.pin_dither, (uint32_t)gpio_key.pin_down);
#if 0
HAL_KEY_TRACE(3,"keyDbnGpio: pin_dbn=0x%X pin_dither=0x%X pin_down=0x%X",
(uint32_t)gpio_key.pin_debounce, (uint32_t)gpio_key.pin_dither, (uint32_t)gpio_key.pin_down);
#endif
#endif // !GPIO_MAP_64BIT
if (gpio_key.pin_dither) {
if (time - gpio_key.time_dither >= KEY_DITHER_INTERVAL) {
pin = gpio_key.pin_dither;
lock = int_lock();
gpio_key.pin_dither &= ~pin;
int_unlock(lock);
#ifdef NO_GROUPKEY
hal_key_enable_allint();
#else
gpio = HAL_GPIO_PIN_P0_0;
while (pin) {
if (pin & ((GPIO_MAP_T)1 << gpio)) {
pin &= ~((GPIO_MAP_T)1 << gpio);
index = hal_gpiokey_find_index(gpio);
hal_gpiokey_enable_irq(gpio, (cfg_hw_gpio_key_cfg[index].key_down == HAL_KEY_GPIOKEY_VAL_LOW) ?
HAL_GPIO_IRQ_POLARITY_LOW_FALLING : HAL_GPIO_IRQ_POLARITY_HIGH_RISING);
}
gpio++;
}
#endif
}
}
if (gpio_key.pin_down) {
pin = gpio_key.pin_down;
gpio = HAL_GPIO_PIN_P0_0;
while (pin) {
if (pin & ((GPIO_MAP_T)1 << gpio)) {
pin &= ~((GPIO_MAP_T)1 << gpio);
index = hal_gpiokey_find_index(gpio);
if (hal_gpio_pin_get_val(gpio) == cfg_hw_gpio_key_cfg[index].key_down) {
code_down |= cfg_hw_gpio_key_cfg[index].key_code;
} else {
gpio_key.pin_down &= ~((GPIO_MAP_T)1 << gpio);
#ifdef NO_GROUPKEY
hal_key_enable_allint();
#else
hal_gpiokey_enable_irq(gpio, (cfg_hw_gpio_key_cfg[index].key_down == HAL_KEY_GPIOKEY_VAL_LOW) ?
HAL_GPIO_IRQ_POLARITY_LOW_FALLING : HAL_GPIO_IRQ_POLARITY_HIGH_RISING);
#endif
}
}
gpio++;
}
}
if (gpio_key.pin_debounce) {
GPIO_MAP_T down_added = 0;
GPIO_MAP_T dither_added = 0;
pin = gpio_key.pin_debounce;
gpio = HAL_GPIO_PIN_P0_0;
while (pin) {
if (pin & ((GPIO_MAP_T)1 << gpio)) {
pin &= ~((GPIO_MAP_T)1 << gpio);
index = hal_gpiokey_find_index(gpio);
if (hal_gpio_pin_get_val(gpio) == cfg_hw_gpio_key_cfg[index].key_down) {
if (time - gpio_key.time_debounce >= KEY_DEBOUNCE_INTERVAL) {
down_added |= ((GPIO_MAP_T)1 << gpio);
code_down |= cfg_hw_gpio_key_cfg[index].key_code;
gpio_key.pin_down |= ((GPIO_MAP_T)1 << gpio);
}
} else {
dither_added |= ((GPIO_MAP_T)1 << gpio);
}
}
gpio++;
}
lock = int_lock();
gpio_key.pin_debounce &= ~(down_added | dither_added);
gpio_key.pin_dither |= dither_added;
int_unlock(lock);
}
if (gpio_key.pin_dither || gpio_key.pin_down || gpio_key.pin_debounce) {
need_timer = true;
}
#endif
enum HAL_KEY_CODE_T down_new;
enum HAL_KEY_CODE_T up_new;
enum HAL_KEY_CODE_T map;
down_new = code_down & ~key_status.code_down;
up_new = ~code_down & key_status.code_down;
//HAL_KEY_TRACE(5,"keyDbn: code_down=0x%X/0x%X down_new=0x%X up_new=0x%X event=%d", key_status.code_down, code_down, down_new, up_new, key_status.event);
// Check newly up keys
map = up_new;
index = 0;
while (map) {
if (map & (1 << index)) {
map &= ~(1 << index);
send_key_event((1 << index), HAL_KEY_EVENT_UP);
if (key_status.event == HAL_KEY_EVENT_LONGPRESS || key_status.event == HAL_KEY_EVENT_LONGLONGPRESS) {
send_key_event((1 << index), HAL_KEY_EVENT_UP_AFTER_LONGPRESS);
}
key_status.time_updown = time;
}
index++;
}
if (up_new) {
if (key_status.event == HAL_KEY_EVENT_LONGPRESS || key_status.event == HAL_KEY_EVENT_LONGLONGPRESS) {
// LongPress is finished when all of the LongPress keys are released
if ((code_down & key_status.code_ready) == 0) {
key_status.event = HAL_KEY_EVENT_NONE;
}
} else if (key_status.event == HAL_KEY_EVENT_DOWN) {
// Enter click handling if not in LongPress
key_status.event = HAL_KEY_EVENT_UP;
}
}
if (key_status.event == HAL_KEY_EVENT_UP) {
//ASSERT(key_status.code_ready != HAL_KEY_CODE_NONE, "Bad code_ready");
if (key_status.code_click == HAL_KEY_CODE_NONE || key_status.code_click != key_status.code_ready) {
if (key_status.code_click != HAL_KEY_CODE_NONE) {
send_key_event(key_status.code_click, HAL_KEY_EVENT_CLICK + key_status.cnt_click);
}
key_status.code_click = key_status.code_ready;
key_status.cnt_click = 0;
key_status.time_click = time;
} else if (up_new && (up_new | key_status.code_down) == key_status.code_click) {
key_status.cnt_click++;
key_status.time_click = time;
}
if (time - key_status.time_click >= KEY_DOUBLECLICK_THRESHOLD || key_status.cnt_click >= MAX_KEY_CLICK_COUNT) {
send_key_event(key_status.code_click, HAL_KEY_EVENT_CLICK + key_status.cnt_click);
key_status.code_click = HAL_KEY_CODE_NONE;
key_status.cnt_click = 0;
key_status.event = HAL_KEY_EVENT_NONE;
}
}
// Update key_status.code_down
key_status.code_down = code_down;
// Check newly down keys and update key_status.code_ready
map = down_new;
index = 0;
while (map) {
if (map & (1 << index)) {
map &= ~(1 << index);
send_key_event((1 << index), HAL_KEY_EVENT_DOWN);
if (key_status.event == HAL_KEY_EVENT_NONE) {
send_key_event((1 << index), HAL_KEY_EVENT_FIRST_DOWN);
} else {
send_key_event((1 << index), HAL_KEY_EVENT_CONTINUED_DOWN);
}
if (key_status.event == HAL_KEY_EVENT_NONE ||
key_status.event == HAL_KEY_EVENT_DOWN ||
key_status.event == HAL_KEY_EVENT_UP) {
key_status.code_ready = code_down;
}
key_status.time_updown = time;
}
index++;
}
if (down_new) {
if (key_status.event == HAL_KEY_EVENT_NONE || key_status.event == HAL_KEY_EVENT_UP) {
key_status.event = HAL_KEY_EVENT_DOWN;
}
}
// LongPress should be stopped if any key is released
if ((code_down & key_status.code_ready) == key_status.code_ready) {
if (key_status.event == HAL_KEY_EVENT_DOWN) {
if (time - key_status.time_updown >= KEY_LONGPRESS_THRESHOLD) {
key_status.cnt_repeat = 0;
key_status.event = HAL_KEY_EVENT_LONGPRESS;
send_key_event(key_status.code_ready, key_status.event);
}
} else if (key_status.event == HAL_KEY_EVENT_LONGPRESS || key_status.event == HAL_KEY_EVENT_LONGLONGPRESS) {
key_status.cnt_repeat++;
if (key_status.cnt_repeat == KEY_LONGPRESS_REPEAT_THRESHOLD / KEY_CHECKER_INTERVAL) {
key_status.cnt_repeat = 0;
send_key_event(key_status.code_ready, HAL_KEY_EVENT_REPEAT);
}
if (key_status.event == HAL_KEY_EVENT_LONGPRESS) {
if (time - key_status.time_updown >= KEY_LONGLONGPRESS_THRESHOLD) {
key_status.event = HAL_KEY_EVENT_LONGLONGPRESS;
send_key_event(key_status.code_ready, key_status.event);
}
}
}
}
if (key_status.event != HAL_KEY_EVENT_NONE) {
need_timer = true;
}
if (need_timer) {
hal_key_debounce_timer_restart();
} else {
//hal_sys_wake_unlock(HAL_SYS_WAKE_LOCK_USER_KEY);
}
}
#if 0//def CHECK_PWRKEY_AT_BOOT
static void hal_key_boot_handler(void *param)
{
#ifndef NO_PWRKEY
uint32_t time;
timer_active = false;
time = hal_sys_timer_get();
if (pwr_key.debounce || pwr_key.dither || pwr_key.pressed) {
bool pressed = hal_pwrkey_get_status();
//HAL_KEY_TRACE(5,"keyBoot: dbn=%d dither=%d pressed=%d/%d event=%d", pwr_key.debounce, pwr_key.dither, pwr_key.pressed, pressed, key_status.event);
if (pwr_key.debounce) {
pwr_key.pressed = pressed;
if (pressed) {
pwr_key.dither = false;
if (time - pwr_key.time >= KEY_DEBOUNCE_INTERVAL) {
pwr_key.debounce = false;
key_status.time_updown = time;
}
} else {
pwr_key.debounce = false;
pwr_key.dither = true;
pwr_key.time = time;
}
} else if (pwr_key.dither) {
if (time - pwr_key.time >= KEY_DITHER_INTERVAL) {
pwr_key.dither = false;
pwr_key.pressed = false;
}
} else if (pwr_key.pressed) {
if (!pressed) {
pwr_key.pressed = false;
}
}
}
if (pwr_key.debounce || pwr_key.dither || pwr_key.pressed) {
if (pwr_key.pressed) {
if (key_status.event == HAL_KEY_EVENT_NONE) {
if (time - key_status.time_updown >= KEY_INIT_DOWN_THRESHOLD) {
key_status.event = HAL_KEY_EVENT_INITDOWN;
send_key_event(HAL_KEY_CODE_PWR, key_status.event);
}
} else if (key_status.event == HAL_KEY_EVENT_INITDOWN) {
if (time - key_status.time_updown >= KEY_INIT_LONGPRESS_THRESHOLD) {
key_status.cnt_repeat = 0;
key_status.event = HAL_KEY_EVENT_INITLONGPRESS;
send_key_event(HAL_KEY_CODE_PWR, key_status.event);
}
} else if (key_status.event == HAL_KEY_EVENT_INITLONGPRESS) {
if (time - key_status.time_updown >= KEY_INIT_LONGLONGPRESS_THRESHOLD) {
key_status.event = HAL_KEY_EVENT_INITLONGLONGPRESS;
send_key_event(HAL_KEY_CODE_PWR, key_status.event);
}
}
}
hal_key_debounce_timer_restart();
} else {
if (key_status.event == HAL_KEY_EVENT_NONE || key_status.event == HAL_KEY_EVENT_INITDOWN) {
send_key_event(HAL_KEY_CODE_PWR, HAL_KEY_EVENT_INITUP);
}
send_key_event(HAL_KEY_CODE_PWR, HAL_KEY_EVENT_INITFINISHED);
hwtimer_update(debounce_timer, hal_key_debounce_handler, NULL);
//hal_sys_wake_unlock(HAL_SYS_WAKE_LOCK_USER_KEY);
memset(&key_status, 0, sizeof(key_status));
hal_pwrkey_reset();
hal_key_enable_allint();
}
#endif
}
#endif //CHECK_PWRKEY_AT_BOOT
int hal_key_open(int checkPwrKey, int (* cb)(uint32_t, uint8_t))
{
int nRet = 0;
uint32_t lock;
key_detected_callback = cb;
memset(&key_status, 0, sizeof(key_status));
lock = int_lock();
#ifdef CHECK_PWRKEY_AT_BOOT
if (checkPwrKey) {
int cnt;
int i = 0;
cnt = 10;
do {
hal_sys_timer_delay(MS_TO_TICKS(150));
if (!hal_pwrkey_startup_pressed()) {
HAL_KEY_TRACE(0,"pwr_key init DITHERING");
nRet = -1;
goto _exit;
}
} while (++i < cnt);
}
#endif
#ifndef NO_PWRKEY
hal_pwrkey_open();
#endif
#if (CFG_HW_ADCKEY_NUMBER > 0)
hal_adckey_open();
#endif
#if (CFG_HW_GPIOKEY_NUM > 0)
hal_gpiokey_open();
#endif
#ifdef CHECK_PWRKEY_AT_BOOT
#ifndef __POWERKEY_CTRL_ONOFF_ONLY__
if (checkPwrKey) {
debounce_timer = hwtimer_alloc(hal_key_boot_handler, NULL);
hal_pwrkey_handle_irq_state(HAL_PWRKEY_IRQ_FALLING_EDGE);
} else
#endif
#endif
{
debounce_timer = hwtimer_alloc(hal_key_debounce_handler, NULL);
hal_key_enable_allint();
}
ASSERT(debounce_timer, "Failed to alloc key debounce timer");
goto _exit; // Avoid compiler warnings
_exit:
int_unlock(lock);
return nRet;
}
int hal_key_close(void)
{
hal_key_disable_allint();
#ifndef NO_PWRKEY
hal_pwrkey_close();
#endif
#if (CFG_HW_ADCKEY_NUMBER > 0)
hal_adckey_close();
#endif
#if (CFG_HW_GPIOKEY_NUM > 0)
hal_gpiokey_close();
#endif
if (debounce_timer) {
hwtimer_stop(debounce_timer);
hwtimer_free(debounce_timer);
debounce_timer = NULL;
}
timer_active = false;
key_detected_callback = NULL;
//hal_sys_wake_unlock(HAL_SYS_WAKE_LOCK_USER_KEY);
return 0;
}