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

Only two correct bytes when for read and notify as BLE central

I am trying to read (the report map) and receive notifications (the report) from an HID device as a BLE central. The bonding process has been completedsuccessfully to my knowledge.

When using sd_ble_gattc_read(), only the first two bytes of the response in the BLE_GATTC_EVT_READ_RSP event is correct. I can call sd_ble_gattc_read() multiple times with the offset increasing and only the first two bytes for each call is correct. Since 22 bytes are read with each call, only bytes 1 and 2, 23 and 24, 45 and 46, and so on are correct.

Similarly, only the first two bytes received in BLE_GATTC_EVT_HVX is correct.

To begin with, I registered the HID UUID with the discovery module.

ble_uuid_t hids_uuid = {
    .uuid = BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE,
    .type = BLE_UUID_TYPE_BLE,
};

APP_ERROR_CHECK(ble_db_discovery_init(db_disc_handler));
APP_ERROR_CHECK(ble_db_discovery_evt_register(&hids_uuid));

I start service discovery inside ble_evt_handler.

case BLE_GAP_EVT_CONNECTED: {
        // Initiate bonding.
        err_code = pm_conn_secure(p_ble_evt->evt.gap_evt.conn_handle, false);
        if (err_code != NRF_ERROR_BUSY) {
                APP_ERROR_CHECK(err_code);
        }

        err_code = ble_db_discovery_start(&m_db_disc, p_ble_evt->evt.gap_evt.conn_handle);
        APP_ERROR_CHECK(err_code);
} break;

Inside the service discover handler, I begin reading the report map value.

uint16_t report_map_handle, report_handle;

static void db_disc_handler(ble_db_discovery_evt_t * p_evt) {
    if (p_evt->evt_type != BLE_DB_DISCOVERY_COMPLETE) {
                return;
        }
        if (p_evt->params.discovered_db.srv_uuid.uuid != hids_uuid.uuid) {
                return;
        }
        if (p_evt->params.discovered_db.srv_uuid.type != hids_uuid.type) {
                return;
        }

    for (int i = 0; i < p_evt->params.discovered_db.char_count; i++) {
                ble_gatt_db_char_t chr = p_evt->params.discovered_db.charateristics[i];
                uint16_t uuid = chr.characteristic.uuid.uuid;
        switch (uuid) {
                case BLE_UUID_REPORT_MAP_CHAR:
                        report_map_handle = chr.characteristic.handle_value;
                        break;
                case BLE_UUID_REPORT_CHAR:
                        report_handle = chr.cccd_handle;
                        break;
                default:
                        break;
                }
    }

        APP_ERROR_CHECK(sd_ble_gattc_read(p_evt->conn_handle, report_map_handle, 0));
}

Also inside ble_evt_handler, I handle the read values. Once all of the report map has been read, I enable notifications on the report characteristic using the CCCD.

case BLE_GATTC_EVT_READ_RSP: {
        ble_gattc_evt_read_rsp_t resp = p_ble_evt->evt.gattc_evt.params.read_rsp;
        memcpy(&hid_data[hid_len], resp.data, resp.len);
        hid_len += resp.len;
        NRF_LOG_HEXDUMP_INFO(resp.data, resp.len);
        NRF_LOG_INFO("total read %d", hid_len);
        uint16_t ch = p_ble_evt->evt.gattc_evt.conn_handle;
        if (resp.len > 0) {
                APP_ERROR_CHECK(sd_ble_gattc_read(ch, report_map_handle, hid_len));
        } else {
                start_notify(ch);
        }
} break;

For start_notify(), I used code from cccd_configure() in components/ble/ble_services/ble_nus_c/ble_nus_c.c

static void start_notify(uint16_t ch) {
    uint8_t buf[BLE_CCCD_VALUE_LEN];
    buf[0] = BLE_GATT_HVX_NOTIFICATION;
    buf[1] = 0;

    ble_gattc_write_params_t const write_params = {
        .write_op = BLE_GATT_OP_WRITE_REQ,
        .flags    = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE,
        .handle   = report_handle,
        .offset   = 0,
        .len      = sizeof(buf),
        .p_value  = buf
    };

    APP_ERROR_CHECK(sd_ble_gattc_write(ch, &write_params));
}

Inside ble_evt_handler I simply dump all of the notification data.

case BLE_GATTC_EVT_HVX: {
        ble_gattc_evt_hvx_t hvx = p_ble_evt->evt.gattc_evt.params.hvx;
        NRF_LOG_HEXDUMP_INFO(hvx.data, hvx.len);
} break;

For the report map, I get the following log output. Note that bytes 3 through 22 of each read is identical.

<info> app:  05 01 00 00 00 00 08 D9|........
<info> app:  03 00 1C FD 03 20 08 D9|..... ..
<info> app:  03 00 F4 01 00 00      |......
<info> app: total read 22
<info> app:  81 02 00 00 00 00 08 D9|........
<info> app:  03 00 1C FD 03 20 08 D9|..... ..
<info> app:  03 00 F4 01 00 00      |......
<info> app: total read 44
<info> app:  01 A1 00 00 00 00 08 D9|........
<info> app:  03 00 1C FD 03 20 08 D9|..... ..
<info> app:  03 00 F4 01 00 00      |......
<info> app: total read 66
<info> app:  05 01 00 00 00 00 08 D9|........
<info> app:  03 00 1C FD 03 20 08 D9|..... ..
<info> app:  03 00 F4 01 00 00      |......
<info> app: total read 88
<info> app:  15 00 00 00 00 00 08 D9|........
<info> app:  03 00 1C FD 03 20 08 D9|..... ..
<info> app:  03 00 F4 01 00 00      |......
<info> app: total read 110
<info> app:  09 38 00 00 00 00 08 D9|.8......
<info> app:  03 00                  |..
<info> app: total read 120

I'm inclined to think there is something wrong on the central side since the HID device works correctly. Suggestions on how to debug this would be appreciated.

Parents Reply Children
No Data
Related