2.3.6. 翻页器

  • 本 APP 基于 HID 开发,主要用于浏览当下火爆的抖音等小视频的上下翻页、左右菜单切换、暂 停等操作。首先选择需要用到的应用本案例选择,然后进行对应的支持板级选择,具体参考下文的 步骤。通过软件编译下载到对应的开发板,打开手机蓝牙进行连接,进入视频浏览界面操作对应按 键即可。

  • 支持的板级: br25、br23、bd19、br34 支持的芯片: AC636N、AC635N、AC638N

2.3.6.1. 翻页器case使用

  • 使用快捷键Alt + g 打开app_config.h,配置CONFIG_APP_KEYFOB使能

//app case 选择,只选1,要配置对应的board_config.h
#define CONFIG_APP_KEYPAGE                  1//翻页器
  • 使用快捷键Alt + g 打开board_config.h,板级选择CONFIG_BOARD_AC632N_DEMO

#define CONFIG_BOARD_AC632N_DEMO       // CONFIG_APP_KEYBOARD,CONFIG_APP_PAGE_TURNER
// #define CONFIG_BOARD_AC6321A_MOUSE  // CONFIG_APP_MOUSE
  • 按照 :HID DEMO说明 编译下载代码、接线、复位设备,再使用手机搜索设备进行连接。

  • 开发者可以操作板子AD key实现蓝牙翻页器的功能。

2.3.6.2. 主要代码说明

APP注册运行(函数位于apps/hid/app_keypage.c):

  • 在系统进行初始化的过程中,根据以下信息进行APP注册。执行的大致流程为:REGISTER_APPLICATION—>state_machine—>app_start()—>sys_key_event_enable();这条流程主要进行设备的初始化设置以及一些功能使能。

REGISTER_APPLICATION—>event_handler—>app_key_event_handler()—>app_key_deal_test();这条流程在event_handler之下有多个case,上述选择按键事件的处理流程进行代码流说明,主要展示按键事件发生时,程序的处理流程。

REGISTER_LP_TARGET(app_hid_lp_target) = {
    .name = "app_keypage",
    .is_idle = app_hid_idle_query,
};
static const struct application_operation app_hid_ops = {
    .state_machine  = state_machine,
    .event_handler  = event_handler,
};
 * 注册模式
REGISTER_APPLICATION(app_hid) = {
    .name   = "keypage",
    .action = ACTION_KEYPAGE,
    .ops    = &app_hid_ops,
    .state  = APP_STA_DESTROY,
};

APP状态机:

  • 状态机有create,start,pause,resume,stop,destory状态,根据不同的状态执行对应的分支。APP注册后进行初始运行,进入APP_STA_START分支,开始APP运行。

    static int state_machine(struct application *app, enum app_state state, struct intent *it)
    {    switch (state) {
        case APP_STA_CREATE:
            break;
        case APP_STA_START:
            if (!it) {
                break;          }
            switch (it->action) {
            case ACTION_TOUCHSCREEN:
                app_start();
    
  • 进入app_start()函数后进行对应的初始化,时钟初始化,模式选择,低功耗初始化,以及外部事件使能。

    static void app_start()
    {
        log_info("=======================================");
        log_info("-----------------------------KEYPAGE------------------------");
        log_info("=======================================");
    

APP 事件处理机制:

  • 事件的定义(代码位于Headersinclude_libsystemeven.h中)

    struct sys_event {
        u16 type;
        u8 consumed;
        void *arg;
        union {
            struct key_event key;
            struct axis_event axis;
            struct codesw_event codesw;
    
  • 事件的产生(include_libsystemevent.h)

    void sys_event_notify(struct sys_event *e);事件通知函数,系统有事件发生时调用此函数。

  • 事件的处理(app_keypage.c)

    • 函数执行的大致流程为:evevt_handler()—>app_key_event_handler()—>app_key_deal_test().

      static int keypage_event_handler(struct application *app, struct sys_event *event)
      {
      #if (TCFG_HID_AUTO_SHUTDOWN_TIME)
          //重置无操作定时计数
          sys_timer_modify(g_auto_shutdown_timer, TCFG_HID_AUTO_SHUTDOWN_TIME * 1000);
      #endif
      
      static void keypage_key_event_handler(struct sys_event *event)
      {
          /* u16 cpi = 0; */
          u8 event_type = 0;
          u8 key_value = 0;
      
          if (event->arg == (void *)DEVICE_EVENT_FROM_KEY) {
              event_type = event->u.key.event;
              key_value = event->u.key.value;
              printf("app_key_evnet: %d,%d\n", event_type, key_value);
                  app_key_deal_test(event_type, key_value);
          }
      }
      
      static void keypage_app_key_deal_test(u8 key_type, u8 key_value)
      {
          u16 key_msg = 0;
          void (*hid_data_send_pt)(u8 report_id, u8 * data, u16 len) = NULL;
      
          log_info("app_key_evnet: %d,%d\n", key_type, key_value);
      
          }
      
  • 数据发送:

当APP注册运行后,有按键事件发生时,会进行对应的数据发送,由于是HID设备,所以数据的发送形式从对应的HID设备的描述符产生。用户如需要对设备进行功能自定义,可以结合HID官方文档对下述描述符进行修改。部分描述符如下:(app_keypage.c)

static const u8 hid_report_map[] = {
    // 119 bytes
    0x05, 0x0D,        // Usage Page (Digitizer)
    0x09, 0x02,        // Usage (Pen)
    0xA1, 0x01,        // Collection (Application)
    0x85, 0x01,        //   Report ID (1)
    0x09, 0x22,        //   Usage (Finger)
    0xA1, 0x02,        //   Collection (Logical)
    0x09, 0x42,        //     Usage (Tip Switch)
    0x15, 0x00,        //     Logical Minimum (0)
    0x25, 0x01,        //     Logical Maximum (1)
    0x75, 0x01,        //     Report Size (1)
    0x95, 0x01,        //     Report Count (1)
    0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x09, 0x32,        //     Usage (In Range)
    0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x95, 0x06,        //     Report Count (6)
    0x81, 0x03,        //     Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x75, 0x08,        //     Report Size (8)
    0x09, 0x51,        //     Usage (0x51)
    0x95, 0x01,        //     Report Count (1)
    0x81, 0x02,        //     Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
    0x05, 0x01,        //     Usage Page (Generic Desktop Ctrls)
static const u8 pp_press[7] = {0x07,0x07,0x70,0x07,0x70,0x07,0x01}; //暂定按键对应的HID发送数据包
static const u8 pp_null[7]=   {0x00,0x07,0x70,0x07,0x70,0x07,0x00};
  • 上列为暂停按键对应的HID设备发送数据包,通过下面的hid_data_send_pt()进行数据传输(app_keypage.c)。

    log_info("point: %d,%d", point_cnt, point_len);
       if (point_cnt) {
           for (int cnt = 0; cnt < point_cnt; cnt++) {
               hid_data_send_pt(1, key_data, point_len);
               key_data += point_len;
               KEY_DELAY_TIME();
           }
       }
    
  • 由描述符可知,设备一共有5个输入实体Input,一共组成7byte的数据,所以对应的暂停按键数据包由7byte的数据组成,前2byte表示识别是否有触摸输入,中间2个2byte分别表示y坐标和x坐标,最后1byte表示contact count,不同的按键事件对应不同的数据包,数据通过hid_data_send_dt函数发送至设备。对应的按键事件通过事件处理机制和数据发送实现对应的功能。

  • 增加处理公共消息

    • 跟据识别不同的手机系统,来切换描述符(app_keypage.c)。

      static int keypage_common_event_handler(struct bt_event *bt)
      {
          log_info("--------keypage_common_event_handler: %02x %02x", bt->event, bt->value);
      
          switch (bt->event) {
          case COMMON_EVENT_EDR_REMOTE_TYPE:
              log_info(" COMMON_EVENT_EDR_REMOTE_TYPE \n");
              connect_remote_type = bt->value;
              if (connect_remote_type == REMOTE_DEV_IOS) {
                  user_hid_set_ReportMap(hid_report_map_ios, sizeof(hid_report_map_ios));
              } else {
                  user_hid_set_ReportMap(hid_report_map, sizeof(hid_report_map));
              }
              break;
      
          case COMMON_EVENT_BLE_REMOTE_TYPE:
              log_info(" COMMON_EVENT_BLE_REMOTE_TYPE \n");
              connect_remote_type = bt->value;