此教程基于SD 2.0
原理:添加HID服务模拟外设滑鼠给手机发送音量加或减实现控制相机拍照,参照SDK工程->ble_app_hids_mouse
需要添加的功能
1.HID服务
2.设备管理机制DM
3.储存设备信息pstorage
流程
1.蓝牙初始化内添加device_manager_init(0);参数0代表保存以往连接设备,方便自动连接
void device_manager_init(bool erase_bonds)
{uint32_t err_code;dm_init_param_t init_param = {.clear_persistent_data = erase_bonds};dm_application_param_t register_param;// Initialize peer device handle.err_code = dm_handle_initialize(&m_bonded_peer_handle);APP_ERROR_CHECK(err_code);// Initialize persistent storage module.err_code = pstorage_init();APP_ERROR_CHECK(err_code);err_code = dm_init(&init_param);APP_ERROR_CHECK(err_code);memset(®ister_param.sec_param, 0, sizeof(ble_gap_sec_params_t));register_param.sec_param.bond = SEC_PARAM_BOND;register_param.sec_param.mitm = SEC_PARAM_MITM;register_param.sec_param.lesc = SEC_PARAM_LESC;register_param.sec_param.keypress = SEC_PARAM_KEYPRESS;register_param.sec_param.io_caps = SEC_PARAM_IO_CAPABILITIES;register_param.sec_param.oob = SEC_PARAM_OOB;register_param.sec_param.min_key_size = SEC_PARAM_MIN_KEY_SIZE;register_param.sec_param.max_key_size = SEC_PARAM_MAX_KEY_SIZE;register_param.evt_handler = device_manager_evt_handler;register_param.service_type = DM_PROTOCOL_CNTXT_GATT_SRVR_ID;err_code = dm_register(&m_app_handle, ®ister_param);APP_ERROR_CHECK(err_code);
}
2.services_init()内增加HID服务hids_init();
void hids_init(void)
{uint32_t err_code;ble_hids_init_t hids_init_obj;ble_hids_inp_rep_init_t inp_rep_array[INPUT_REPORT_COUNT];ble_hids_inp_rep_init_t * p_input_report;uint8_t hid_info_flags;static uint8_t rep_map_data[] ={0x05, 0x01, // Usage Page (Generic Desktop)0x09, 0x02, // Usage (Mouse)0xA1, 0x01, // Collection (Application)// Report ID 1: Mouse buttons + scroll/pan0x85, 0x01, // Report Id 10x09, 0x01, // Usage (Pointer)0xA1, 0x00, // Collection (Physical)0x95, 0x05, // Report Count (3)0x75, 0x01, // Report Size (1)0x05, 0x09, // Usage Page (Buttons)0x19, 0x01, // Usage Minimum (01)0x29, 0x05, // Usage Maximum (05)0x15, 0x00, // Logical Minimum (0)0x25, 0x01, // Logical Maximum (1)0x81, 0x02, // Input (Data, Variable, Absolute)0x95, 0x01, // Report Count (1)0x75, 0x03, // Report Size (3)0x81, 0x01, // Input (Constant) for padding0x75, 0x08, // Report Size (8)0x95, 0x01, // Report Count (1)0x05, 0x01, // Usage Page (Generic Desktop)0x09, 0x38, // Usage (Wheel)0x15, 0x81, // Logical Minimum (-127)0x25, 0x7F, // Logical Maximum (127)0x81, 0x06, // Input (Data, Variable, Relative)0x05, 0x0C, // Usage Page (Consumer)0x0A, 0x38, 0x02, // Usage (AC Pan)0x95, 0x01, // Report Count (1)0x81, 0x06, // Input (Data,Value,Relative,Bit Field)0xC0, // End Collection (Physical)// Report ID 2: Mouse motion0x85, 0x02, // Report Id 20x09, 0x01, // Usage (Pointer)0xA1, 0x00, // Collection (Physical)0x75, 0x0C, // Report Size (12)0x95, 0x02, // Report Count (2)0x05, 0x01, // Usage Page (Generic Desktop)0x09, 0x30, // Usage (X)0x09, 0x31, // Usage (Y)0x16, 0x01, 0xF8, // Logical maximum (2047)0x26, 0xFF, 0x07, // Logical minimum (-2047)0x81, 0x06, // Input (Data, Variable, Relative)0xC0, // End Collection (Physical)0xC0, // End Collection (Application)// Report ID 3: Advanced buttons0x05, 0x0C, // Usage Page (Consumer)0x09, 0x01, // Usage (Consumer Control)0xA1, 0x01, // Collection (Application)0x85, 0x03, // Report Id (3)0x15, 0x00, // Logical minimum (0)0x25, 0x01, // Logical maximum (1)0x75, 0x01, // Report Size (1)0x95, 0x01, // Report Count (1)0x09, 0xCD, // Usage (Play/Pause)0x81, 0x06, // Input (Data,Value,Relative,Bit Field)0x0A, 0x83, 0x01, // Usage (AL Consumer Control Configuration)0x81, 0x06, // Input (Data,Value,Relative,Bit Field)0x09, 0xB5, // Usage (Scan Next Track)0x81, 0x06, // Input (Data,Value,Relative,Bit Field)0x09, 0xB6, // Usage (Scan Previous Track)0x81, 0x06, // Input (Data,Value,Relative,Bit Field)0x09, 0xEA, // Usage (Volume Down)0x81, 0x06, // Input (Data,Value,Relative,Bit Field)0x09, 0xE9, // Usage (Volume Up)0x81, 0x06, // Input (Data,Value,Relative,Bit Field)0x0A, 0x25, 0x02, // Usage (AC Forward)0x81, 0x06, // Input (Data,Value,Relative,Bit Field)0x0A, 0x24, 0x02, // Usage (AC Back)0x81, 0x06, // Input (Data,Value,Relative,Bit Field)0xC0 // End Collection};memset(inp_rep_array, 0, sizeof(inp_rep_array));// Initialize HID Service.p_input_report = &inp_rep_array[INPUT_REP_BUTTONS_INDEX];p_input_report->max_len = INPUT_REP_BUTTONS_LEN;p_input_report->rep_ref.report_id = INPUT_REP_REF_BUTTONS_ID;p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm);p_input_report = &inp_rep_array[INPUT_REP_MOVEMENT_INDEX];p_input_report->max_len = INPUT_REP_MOVEMENT_LEN;p_input_report->rep_ref.report_id = INPUT_REP_REF_MOVEMENT_ID;p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm);p_input_report = &inp_rep_array[INPUT_REP_MPLAYER_INDEX];p_input_report->max_len = INPUT_REP_MEDIA_PLAYER_LEN;p_input_report->rep_ref.report_id = INPUT_REP_REF_MPLAYER_ID;p_input_report->rep_ref.report_type = BLE_HIDS_REP_TYPE_INPUT;BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.cccd_write_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.read_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&p_input_report->security_mode.write_perm);hid_info_flags = HID_INFO_FLAG_REMOTE_WAKE_MSK | HID_INFO_FLAG_NORMALLY_CONNECTABLE_MSK;memset(&hids_init_obj, 0, sizeof(hids_init_obj));hids_init_obj.evt_handler = on_hids_evt;hids_init_obj.error_handler = NULL;hids_init_obj.is_kb = false;hids_init_obj.is_mouse = true;hids_init_obj.inp_rep_count = INPUT_REPORT_COUNT;hids_init_obj.p_inp_rep_array = inp_rep_array;hids_init_obj.outp_rep_count = 0;hids_init_obj.p_outp_rep_array = NULL;hids_init_obj.feature_rep_count = 0;hids_init_obj.p_feature_rep_array = NULL;hids_init_obj.rep_map.data_len = sizeof(rep_map_data);hids_init_obj.rep_map.p_data = rep_map_data;hids_init_obj.hid_information.bcd_hid = BASE_USB_HID_SPEC_VERSION;hids_init_obj.hid_information.b_country_code = 0;hids_init_obj.hid_information.flags = hid_info_flags;hids_init_obj.included_services_count = 0;hids_init_obj.p_included_services_array = NULL;BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.rep_map.security_mode.read_perm);BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.rep_map.security_mode.write_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.hid_information.security_mode.read_perm);BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.hid_information.security_mode.write_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_mouse_inp_rep.cccd_write_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_mouse_inp_rep.read_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_mouse_inp_rep.write_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_protocol.read_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_protocol.write_perm);BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.security_mode_ctrl_point.read_perm);BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_ctrl_point.write_perm);err_code = ble_hids_init(&m_hids, &hids_init_obj);APP_ERROR_CHECK(err_code);
}
3.ble_evt_dispatch内添加
dm_ble_evt_handler(p_ble_evt);
ble_hids_on_ble_evt(&m_hids, p_ble_evt);
4.sys_evt_dispatch内添加
pstorage_sys_event_handler(sys_evt);
5.添加UUID
static ble_uuid_t m_adv_uuids[] = {
{BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE, BLE_UUID_TYPE_BLE} };
6.增加发送音量函数
void media_player_control(uint8_t control)
{uint32_t err_code;uint8_t buffer[1];buffer[0] = control;err_code = ble_hids_inp_rep_send( &m_hids,INPUT_REP_MPLAYER_INDEX,1,buffer );if(( err_code != NRF_SUCCESS ) &&( err_code != NRF_ERROR_INVALID_STATE ) &&( err_code != BLE_ERROR_NO_TX_PACKETS ) &&( err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING )){NRF_LOG_PRINTF("-step1error-");APP_ERROR_HANDLER( err_code );}buffer[0] = 0;err_code = ble_hids_inp_rep_send( &m_hids,INPUT_REP_MPLAYER_INDEX,1,buffer );if(( err_code != NRF_SUCCESS ) &&( err_code != NRF_ERROR_INVALID_STATE ) &&( err_code != BLE_ERROR_NO_TX_PACKETS ) &&( err_code != BLE_ERROR_GATTS_SYS_ATTR_MISSING )){NRF_LOG_PRINTF("-step-2-error-\r\n");APP_ERROR_HANDLER( err_code );}}
这里兼容IOS和Android,触发了2次发送
7.device_manager_cnfg.h修改CCCD连接数
#define DM_GATT_CCCD_COUNT 6
8.可能的问题和解决方法
1.连接了一台设备,断开他后其他设备搜不到设备的广播。
办法:device_manager_init(0);DEVICE_MANAGER_MAX_CONNECTIONS改大;DEVICE_MANAGER_MAX_BONDS改大。
2.手机系统拒绝配对。
办法:on_ble_evt函数内将BLE_GAP_EVT_SEC_PARAMS_REQUEST下的内容全部注释掉
3.每次正常使用都需要重新配对。
办法:CCCD设置太少,DM_GATT_CCCD_COUNT改大
4.程序下到板子后一直重启。办法:
1.注意SOFTDEVICE_HANDLER_INIT(&clock_lf_cfg, NULL);是否多次使用
2.步骤5.添加UUID时注意内容,有时候添加多个UUID会死机
3.注意gap_params_init();设置
4.services_init();和advertising_init();的先后顺序
感谢这些哥们:
https://blog.csdn.net/sinat_20059415/article/details/80777813
https://blog.csdn.net/pig10086/article/details/72402066
https://blog.csdn.net/everestzhang/article/details/47165417
https://blog.csdn.net/gyb510/article/details/70188616
https://blog.csdn.net/weixin_40204595/article/details/81179361