This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf51822 + Keyboard/Consumer Control + Android7.0, both keyboard and consumer features failed

SDK: nRF5_SDK_12.2.0_f012efa
SD: s130_nrf51_2.0.1_softdevice.hex
nRF DK: nrf51822 board
IDE: uVision V5.22.0.0
Code template: .\examples\ble_peripheral\ble_app_hids_keyboard

Base on the above, I did two tests.

1. Only test Consumer device feature for music playing.It works with Android 7.1 phone.

static void hids_init(void)
{
ret_code_t err_code;
ble_hids_init_t hids_init_obj;
ble_hids_inp_rep_init_t input_report_array[2];
ble_hids_inp_rep_init_t * p_input_report;
ble_hids_outp_rep_init_t output_report_array[1];
ble_hids_outp_rep_init_t * p_output_report;
uint8_t hid_info_flags;

memset((void *)input_report_array, 0, sizeof(ble_hids_inp_rep_init_t));
memset((void *)output_report_array, 0, sizeof(ble_hids_outp_rep_init_t));

static uint8_t report_map_data[] =
{
// Report ID 1: Advanced buttons
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Control)

0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report Id (1)
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, 0x02, // Input (Data,Value,Relative,Bit Field)
0x0A, 0x83, 0x01, // Usage (AL Consumer Control Configuration)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0x09, 0xB5, // Usage (Scan Next Track)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0x09, 0xB6, // Usage (Scan Previous Track)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)

0x09, 0xEA, // Usage (Volume Down)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0x09, 0xE9, // Usage (Volume Up)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)

0x0A, 0x25, 0x02, // Usage (AC Forward)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0x0A, 0x24, 0x02, // Usage (AC Back)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0xC0 // End Collection
};

// Initialize HID Service - ConsumerControl
p_input_report = &input_report_array[INPUT_CCONTROL_KEYS_INDEX];
p_input_report->max_len = INPUT_CC_REPORT_KEYS_MAX_LEN;
p_input_report->rep_ref.report_id = INPUT_CC_REP_REF_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 = service_error_handler;
hids_init_obj.is_kb = false;
hids_init_obj.is_mouse = false;
hids_init_obj.inp_rep_count = 1;
hids_init_obj.p_inp_rep_array = input_report_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(report_map_data);
hids_init_obj.rep_map.p_data = report_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_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);
}
static void hid_button_timeout_handler(void * p_context)
{
UNUSED_PARAMETER(p_context);
multimedia_keys_t mm_key_release = MM_KEY_RELEASE;
uint32_t err_code;
// Send release for multimedia key
err_code = ble_hids_inp_rep_send(&m_hids,
0,
INPUT_REP_ZOOM_MAX_LEN,
(uint8_t*)&mm_key_release);
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)
)
{
APP_ERROR_CHECK(err_code);
}

NRF_LOG_INFO("send media release key.\n");
}

static void mouse_media_send(uint8_t action)
{
uint32_t err_code;
uint8_t buffer[INPUT_REP_ZOOM_MAX_LEN] = {0};

APP_ERROR_CHECK_BOOL(INPUT_REP_ZOOM_MAX_LEN == 1);

buffer[0] = action;
err_code = ble_hids_inp_rep_send(&m_hids,
0,
INPUT_REP_ZOOM_MAX_LEN,
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)) {
APP_ERROR_HANDLER(err_code);
} else {
// Start timer for sending release key
app_timer_start(m_hid_button_timer_id, BUTTON_DETECTION_DELAY, NULL);
}
}

2. If I add Keyboard's mapdata following Consumer mapdata, both functionalities failed.
static void hids_init(void)
{
ret_code_t err_code;
ble_hids_init_t hids_init_obj;
ble_hids_inp_rep_init_t input_report_array[2];
ble_hids_inp_rep_init_t * p_input_report;
ble_hids_outp_rep_init_t output_report_array[1];
ble_hids_outp_rep_init_t * p_output_report;
uint8_t hid_info_flags;

memset((void *)input_report_array, 0, sizeof(ble_hids_inp_rep_init_t));
memset((void *)output_report_array, 0, sizeof(ble_hids_outp_rep_init_t));

static uint8_t report_map_data[] =
{
//-----------------------Advanced buttons -----------------
0x05, 0x0C, // Usage Page (Consumer)
0x09, 0x01, // Usage (Consumer Control)

0xA1, 0x01, // Collection (Application)
0x85, 0x01, // Report Id (1)
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, 0x02, // Input (Data,Value,Relative,Bit Field)
0x0A, 0x83, 0x01, // Usage (AL Consumer Control Configuration)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0x09, 0xB5, // Usage (Scan Next Track)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0x09, 0xB6, // Usage (Scan Previous Track)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)

0x09, 0xEA, // Usage (Volume Down)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0x09, 0xE9, // Usage (Volume Up)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)

0x0A, 0x25, 0x02, // Usage (AC Forward)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0x0A, 0x24, 0x02, // Usage (AC Back)
0x81, 0x02, // Input (Data,Value,Relative,Bit Field)
0xC0, // End Collection

//-----------------------Keyboard -----------------
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)

0xA1, 0x01, // Collection (Application)
0x85, 0x02, // Report ID (2)

0x05, 0x07, // Usage Page (Key Codes)
0x19, 0xe0, // Usage Minimum (224)
0x29, 0xe7, // Usage Maximum (231)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data, Variable, Absolute)

0x95, 0x01, // Report Count (1)
0x75, 0x08, // Report Size (8)
0x81, 0x01, // Input (Constant) reserved byte(1)

0x95, 0x06, // Report Count (6)
0x75, 0x08, // Report Size (8)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x65, // Logical Maximum (101)
0x05, 0x07, // Usage Page (Key codes)
0x19, 0x00, // Usage Minimum (0)
0x29, 0x65, // Usage Maximum (101)
0x81, 0x00, // Input (Data, Array) Key array(6 bytes)

0x09, 0x05, // Usage (Vendor Defined)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Count (2)
0x95, 0x02, // Report Size (8 bit)
0xB1, 0x02, // Feature (Data, Variable, Absolute)

0xC0 // End Collection (Application)
};

// Initialize HID Service - ConsumerControl
p_input_report = &input_report_array[0];
p_input_report->max_len = 1;
p_input_report->rep_ref.report_id = 1;
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 = &input_report_array[1];
p_input_report->max_len = 8;
p_input_report->rep_ref.report_id = 2;
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 = service_error_handler;
hids_init_obj.is_kb = false;
hids_init_obj.is_mouse = false;
hids_init_obj.inp_rep_count = 2;
hids_init_obj.p_inp_rep_array = input_report_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(report_map_data);
hids_init_obj.rep_map.p_data = report_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_kb_inp_rep.cccd_write_perm);
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_inp_rep.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&hids_init_obj.security_mode_boot_kb_inp_rep.write_perm);
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_outp_rep.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(&hids_init_obj.security_mode_boot_kb_outp_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);
}

I am confused, whether Android 7.1 doesn't support HID composite device with full HID features, or I have miss
some critical configuration for nRF51822 ?

Thanks,
QiangH
Parents Reply Children
  • Hi Håkon,

    1. yes, after add a keyboard descriptor afterwards; none of them work.

    2. You are right. The root cause is that I indeed ignored set '.is_kbd' to true. After corrected it, both Consumer and Keyboard work as expected.

    Maybe someone would meet same or analogous problem on nRF51822 platform,  so I attach my code for reference.

    Note:  4 key(s1, s2, s3, s4) events' define in reference code are as follows:

    s1:  input 14 chars (` 1 2 3 4 5 6 7 8 9 0 - = Backspace)

    s2: music play/pause

    s3: music volum down

    s4: music volum up

    consumer_and_keyboard_nrf51822.c

    my test environment as below:

    SDK: nRF5_SDK_12.2.0_f012efa
    SD: s130_nrf51_2.0.1_softdevice.hex
    nRF DK: nrf51822 board
    IDE: uVision V5.22.0.0
    Code template: .\examples\ble_peripheral\ble_app_hids_keyboard

    Peer side: the phone with Android 7.1

    You can replace main.c in folder ble_app_hids_keyboard with attached file, and begin your own verification.

    Thanks a lot,

    QiangH

Related