BES按键模块

一、前言

上一章简单介绍了一下BES代码框架的组成,本章主要讲解一下BES按键模块,包含驱动、按键响应以及对应的消息处理。

二、按键驱动

1、按键的GPIO配置:

const struct HAL_KEY_GPIOKEY_CFG_T cfg_hw_gpio_key_cfg[CFG_HW_GPIOKEY_NUM] = {
#if (CFG_HW_GPIOKEY_NUM > 0)
#ifdef BES_AUDIO_DEV_Main_Board_9v0
    {HAL_KEY_CODE_FN1,{HAL_IOMUX_PIN_P0_0, HAL_IOMUX_FUNC_AS_GPIO,HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENABLE}},
    {HAL_KEY_CODE_FN2,{HAL_IOMUX_PIN_P0_1, HAL_IOMUX_FUNC_AS_GPIO,HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENABLE}},
#else
    {HAL_KEY_CODE_FN1,{HAL_IOMUX_PIN_P1_3, HAL_IOMUX_FUNC_AS_GPIO,HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENABLE}},
    //{HAL_KEY_CODE_FN2,{HAL_IOMUX_PIN_P0_5, HAL_IOMUX_FUNC_AS_GPIO,HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENABLE}},
    {HAL_KEY_CODE_FN2,{HAL_IOMUX_PIN_P1_2, HAL_IOMUX_FUNC_AS_GPIO,HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENABLE}},
#endif
#endif
};

2、按键驱动的相关函数

int app_key_open(int checkPwrKey)

开启按键功能,初始化按键线程、申请按键链表资源。

int hal_key_open(int checkPwrKey, int (* cb)(uint32_t, uint8_t))

按键驱动初始化,启动包含GPIO按键、ADC按键、拨码按键等。主要功能是初始化按键。

static void hal_key_boot_handler(void *param)

static void hal_key_debounce_handler(void *param)

上面两个函数均为键值生成函数,其中hal_key_boot_handler为启动过程中电源键的键值生成函数,仅仅在启动过程中使用,hal_key_debounce_handler为普通按键的键值生成函数,该函数功能包含了按键的防抖、键值的转化等,有兴趣可以深入研究下其中的流程,还是有点东西的。

static int send_key_event(enum HAL_KEY_CODE_T code, enum HAL_KEY_EVENT_T event)

按键事件上报。

3、按键参数的配置

下面的主要是按键长按、短按、抖动时间,以及多击的间隔时间等配置,可以根据实际的项目要求及形态进行配置。

#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

三、按键响应和处理

第二节的内容有兴趣可以深入研究下,对于实际项目来说,还是需要多关注下按键的响应流程和处理。

1、按键响应流程

当按键初始化完成后,当硬件上按键按键后,驱动层会上报按键的键值和按键事件,具体函数见第二节。上报的按键信息通过消息队列传递至对应的按键执行函数,对应的函数及功能描述如下:

static int key_event_process(uint32_t key_code, uint8_t key_event)

按键消息传递函数,同时增加了按键消息过滤机制,当按键上报太多,就废弃掉最新的按键。

static int app_key_handle_process(APP_MESSAGE_BODY *msg_body)

按键消息接收函数,该函数会通过键值和事件找到对应的执行函数。

void app_key_init(void)

按键初始化,TWS模式和Stereo模式的处理不一致,需要特别注意。该函数非常重要,涉及到按键的执行函数设定,需要特别注意。

下面是按键键值、按键事件和按键执行函数的对应对应关系,用户可以按照需求定义。此处展示的TWS模式的按键配置。

const APP_KEY_HANDLE  app_ibrt_ui_test_key_cfg[] =
{
    {{APP_KEY_CODE_GOOGLE, APP_KEY_EVENT_FIRST_DOWN}, "google assistant key",app_ibrt_ui_test_voice_assistant_key, NULL},
    {{APP_KEY_CODE_GOOGLE, APP_KEY_EVENT_UP}, "google assistant key",app_ibrt_ui_test_voice_assistant_key, NULL},
    {{APP_KEY_CODE_GOOGLE, APP_KEY_EVENT_LONGPRESS}, "google assistant key",app_ibrt_ui_test_voice_assistant_key, NULL},
    {{APP_KEY_CODE_GOOGLE, APP_KEY_EVENT_CLICK}, "google assistant key",app_ibrt_ui_test_voice_assistant_key, NULL},
    {{APP_KEY_CODE_GOOGLE, APP_KEY_EVENT_DOUBLECLICK}, "google assistant key",app_ibrt_ui_test_voice_assistant_key, NULL},                   
    {{APP_KEY_CODE_PWR,APP_KEY_EVENT_DOWN},"app_ibrt_ui_test_key_local",app_ibrt_ui_test_key_local, NULL},
    {{APP_KEY_CODE_PWR,APP_KEY_EVENT_CLICK},"bt anc key",app_anc_key, NULL}
    {{APP_KEY_CODE_PWR,APP_KEY_EVENT_LONGPRESS},"app_ibrt_ui_test_key",app_ibrt_ui_test_key, NULL},
    {{APP_KEY_CODE_PWR,APP_KEY_EVENT_LONGLONGPRESS},"app_ibrt_ui_test_key",app_ibrt_ui_test_key, NULL},
    {{APP_KEY_CODE_PWR,APP_KEY_EVENT_DOUBLECLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key, NULL},
    {{APP_KEY_CODE_PWR,APP_KEY_EVENT_TRIPLECLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key, NULL},
    {{APP_KEY_CODE_PWR,APP_KEY_EVENT_ULTRACLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key, NULL},
    {{APP_KEY_CODE_PWR,APP_KEY_EVENT_RAMPAGECLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key, NULL},
    {{APP_KEY_CODE_PWR,APP_KEY_EVENT_RAMPAGECLICK},"bt i2c key",app_factorymode_i2c_switch, NULL},
    {{APP_KEY_CODE_FN1,APP_KEY_EVENT_CLICK},"app_ibrt_ui_test_key",app_ibrt_simulate_charger_plugin_key, NULL},
    {{APP_KEY_CODE_FN1,APP_KEY_EVENT_DOUBLECLICK},"app_ibrt_ui_test_key",app_ibrt_simulate_tws_role_switch, NULL},
    {{APP_KEY_CODE_FN1,APP_KEY_EVENT_CLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key_io_event, NULL},
    {{APP_KEY_CODE_FN1,APP_KEY_EVENT_DOUBLECLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key_io_event, NULL},
    {{APP_KEY_CODE_FN2,APP_KEY_EVENT_CLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key_io_event, NULL},
    {{APP_KEY_CODE_FN2,APP_KEY_EVENT_DOUBLECLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key_io_event, NULL},
    {{APP_KEY_CODE_FN3,APP_KEY_EVENT_CLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key_io_event, NULL},
    {{APP_KEY_CODE_FN3,APP_KEY_EVENT_DOUBLECLICK},"app_ibrt_ui_test_key",app_ibrt_ui_test_key_io_event, NULL},
};

2、按键处理

上面的按键执行函数,例如:

void app_ibrt_ui_test_key_io_event(APP_KEY_STATUS *status, void *param)
void app_ibrt_simulate_charger_plugout_key(APP_KEY_STATUS *status, void *param)
void app_ibrt_simulate_tws_role_switch(APP_KEY_STATUS *status, void *param)
void app_ibrt_simulate_charger_plugout_key(APP_KEY_STATUS *status, void *param)
void app_factorymode_i2c_switch(APP_KEY_STATUS *status, void *param)
void app_ibrt_ui_test_key(APP_KEY_STATUS *status, void *param)
void app_ibrt_ui_test_key_local(APP_KEY_STATUS *status, void *param)
void app_ibrt_ui_test_voice_assistant_key(APP_KEY_STATUS *status, void *param)

此处单使用下面函数举例

void app_ibrt_ui_test_key(APP_KEY_STATUS *status, void *param)
{
    TRACE(3,"%s %d,%d",__func__, status->code, status->event);
#ifndef TILE_DATAPATH
    ibrt_ctrl_t *p_ibrt_ctrl = app_tws_ibrt_get_bt_ctrl_ctx();
    uint8_t shutdown_key = HAL_KEY_EVENT_LONGLONGPRESS;
#endif

#ifndef TILE_DATAPATH
    if (IBRT_SLAVE == p_ibrt_ctrl->current_role && status->event != shutdown_key)
    {
        app_ibrt_if_keyboard_notify(status,param);
    }
    else
#endif
    {
#ifdef IBRT_SEARCH_UI
        app_ibrt_search_ui_handle_key(status,param);
#else
        app_ibrt_normal_ui_handle_key(status,param);
#endif
    }
}

这里需要注意的地方就是需要区分主从耳的按键事件,Stereo方案就不需要这一步,收到按键直接执行即可。由于主耳按键和Stereo方案处理方式是一致的,这里就不多展开了,只需要在对应的键值下面做好需要执行的事件就行,下面的函数是按键响应的入口。

void app_ibrt_search_ui_handle_key(APP_KEY_STATUS *status, void *param)

对应的响应事件则通过对应的函数去实现,可以自由调用,例如双击事件。

void bt_key_handle_func_doubleclick()
{
    TRACE(0,"!!!APP_KEY_EVENT_DOUBLECLICK\n");
    if((app_bt_device.hfchan_callSetup[BT_DEVICE_ID_1] == BTIF_HF_CALL_SETUP_NONE)&&(app_bt_device.hfchan_call[BT_DEVICE_ID_1] == BTIF_HF_CALL_NONE)){
        hfp_handle_key(HFP_KEY_REDIAL_LAST_CALL);
    }
    if(app_bt_device.hf_audio_state[BT_DEVICE_ID_1] == BTIF_HF_AUDIO_CON){
        if(app_bt_device.hf_mute_flag == 0){
            hfp_handle_key(HFP_KEY_MUTE);
            app_bt_device.hf_mute_flag = 1;
        }else{
            hfp_handle_key(HFP_KEY_CLEAR_MUTE);
            app_bt_device.hf_mute_flag = 0;
        }
    }
}

此处根据当前的场景,双击事件有三个操作,无业务状态下,双击自动重拨,通话中,则自动在Mute麦克风和Open麦克风之间切换。这里需要注意的就是判断条件需要考虑周全,否则对应的按键起不到对应的效果。

对于从耳来说,执行相对复杂一点,不过也只是多了一步双耳之间按键同步的消息,不过也需要注意,若该操作仅从耳执行,那操作和主耳一致,判断按键事件,执行对应的操作即可,不需要同步,例如单耳关机。其中从耳执行流程如下:

int app_ibrt_if_keyboard_notify(APP_KEY_STATUS *status, void *param)
{
    if (app_tws_ibrt_slave_ibrt_link_connected())
    {
        tws_ctrl_send_cmd(APP_TWS_CMD_KEYBOARD_REQUEST, (uint8_t *)status,sizeof(APP_KEY_STATUS)); 
    }
    return 0;
}

其中下面的函数就是双耳同步消息的函数,此处不展开,暂时也不需要深入了解,知道函数咋用就行了。进阶后可以研究一下完整的流程和原理。

int tws_ctrl_send_cmd(uint32_t cmd_code, uint8_t *p_buff, uint16_t length)

从耳发出按键消息后,主耳会同步收到对应的消息,随后的流程和主耳执行的按键流程一致。对应的入口为:

void app_ibrt_keyboard_request_handler(uint16_t rsp_seq, uint8_t *p_buff, uint16_t length)
{
    if (app_tws_ibrt_mobile_link_connected())
    {
#ifdef IBRT_SEARCH_UI
        app_ibrt_search_ui_handle_key((APP_KEY_STATUS *)p_buff, NULL);
#else
        app_ibrt_normal_ui_handle_key((APP_KEY_STATUS *)p_buff, NULL);
#endif
#ifdef __AI_VOICE__
        app_ibrt_ui_test_voice_assistant_key((APP_KEY_STATUS *)p_buff, NULL);
#endif
    }
}

其中对应的按键响应入口和主耳操作一样。如下:

void app_ibrt_search_ui_handle_key(APP_KEY_STATUS *status, void *param)

四、补充

此处补充一下平时遇到的一些按键模块中的一些小问题。

1、按键响应函数中的事件处理不宜添加延时等阻塞型函数和锁函数,否则有可能导致系统死机和死锁;

2、有些用户需要修改双击和三击的间隔,而且还不一致,这个可以在驱动层做修改,不过需要注意其中的按键释放,否则可能会导致按键持续触发;

3、按键的GPIO映射时,对应的高低电平和触发需要注意,保持和原理图一致。GPIO的上下拉需要设定好。

{HAL_KEY_CODE_FN2,{HAL_IOMUX_PIN_P0_1, HAL_IOMUX_FUNC_AS_GPIO, HAL_IOMUX_PIN_VOLTAGE_VIO, HAL_IOMUX_PIN_PULLUP_ENABLE}},

4、给按键设置别名时,参考按键的功能。其中组合键可以将对应的按键或在一起。

#define   BTAPP_FUNC_KEY            APP_KEY_CODE_PWR
#define   BTAPP_VOLUME_DOWN_KEY     APP_KEY_CODE_FN1
#define   BTAPP_VOLUME_UP_KEY       APP_KEY_CODE_FN2
#define   BTAPP_PLAY_KEY            APP_KEY_CODE_FN3
#define   BTAPP_SLEEP_KEY           APP_KEY_CODE_FN4
#define   BTAPP_FUNC_UP_DOWN_KEY    (BTAPP_FUNC_KEY|BTAPP_VOLUME_DOWN_KEY|BTAPP_VOLUME_UP_KEY)

按键模块总体比较简单,对于其他类型的按键,例如触摸按键、ADC按键,以及其他类似按键(如佩戴、陀螺仪等外设,可以通过模拟成按键来操作)的处理,后续想到新的再补充。

  • 15
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值