Hello.
I'm trying to control a GoPro camera via ble. Gopro has documentation that describes the available services and chars, as well as the exchange protocol (https://gopro.github.io/OpenGoPro/ble/).
At the moment I am trying to send a command to the camera and get a response from it. I need to write the command in the characteristic 0x0072 of the service 0xFEA6, and get the response in the notification of the characteristic 0x0073.
I used the ble-nus-c example (for central device) and modified it a little. I posted the full code on GitHub https://github.com/Sergey1560/nrf52_gopro/tree/master
If I understand correctly, in my case, service 0xFEA6 is type 1 (BLE_UUID_TYPE_BLE), and the characteristics of this are type 2 (BLE_UUID_TYPE_VENDOR_BEGIN).
Init function:
#define GOPRO_BASE_UUID {{0x1b, 0xc5, 0xd5, 0xa5, 0x02, 0x00, 0x46, 0x90, 0xe3, 0x11, 0x8d, 0xaa, 0x00, 0x00, 0xf9, 0xb5}} /**< Used vendor-specific UUID. */ #define BLE_UUID16_GOPRO_SERVICE 0xFEA6 uint32_t ble_gopro_init(ble_nus_c_t * p_ble_nus_c, ble_nus_c_init_t * p_ble_nus_c_init) { uint32_t err_code; ble_uuid_t uart_uuid; ble_uuid128_t nus_base_uuid = GOPRO_BASE_UUID; VERIFY_PARAM_NOT_NULL(p_ble_nus_c); VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init); VERIFY_PARAM_NOT_NULL(p_ble_nus_c_init->p_gatt_queue); err_code = sd_ble_uuid_vs_add(&nus_base_uuid, &p_ble_nus_c->uuid_type); VERIFY_SUCCESS(err_code); uart_uuid.type = BLE_UUID_TYPE_BLE; uart_uuid.uuid = BLE_UUID16_GOPRO_SERVICE; NRF_LOG_DEBUG("Register uuid 0x%0X type %d",uart_uuid.uuid,uart_uuid.type); p_ble_nus_c->conn_handle = BLE_CONN_HANDLE_INVALID; p_ble_nus_c->evt_handler = p_ble_nus_c_init->evt_handler; p_ble_nus_c->error_handler = p_ble_nus_c_init->error_handler; p_ble_nus_c->handles.command_tx_handle = BLE_GATT_HANDLE_INVALID; p_ble_nus_c->handles.command_rx_handle = BLE_GATT_HANDLE_INVALID; p_ble_nus_c->p_gatt_queue = p_ble_nus_c_init->p_gatt_queue; return ble_db_discovery_evt_register(&uart_uuid); }.
Discovery event function:
#define BLE_UUID_GOPRO_COMMAND_TX_CHARACTERISTIC 0x0072 #define BLE_UUID_GOPRO_COMMAND_RX_CHARACTERISTIC 0x0073 void ble_nus_c_on_db_disc_evt(ble_nus_c_t * p_ble_nus_c, ble_db_discovery_evt_t * p_evt) { ble_nus_c_evt_t nus_c_evt; memset(&nus_c_evt,0,sizeof(ble_nus_c_evt_t)); ble_gatt_db_char_t * p_chars = p_evt->params.discovered_db.charateristics; NRF_LOG_DEBUG("DB discovery evt Type: %d uuid 0x%0X uuid type: %d",p_evt->evt_type,p_evt->params.discovered_db.srv_uuid.uuid,p_evt->params.discovered_db.srv_uuid.type); if ( (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE) && (p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID16_GOPRO_SERVICE)) // && (p_evt->params.discovered_db.srv_uuid.type == p_ble_nus_c->uuid_type)) { for (uint32_t i = 0; i < p_evt->params.discovered_db.char_count; i++) { nrf_delay_ms(100); //to prevent log overflow NRF_LOG_INFO("Discovery %d / %d char 0x%0X handle 0x%0X",i, p_evt->params.discovered_db.char_count,p_chars[i].characteristic.uuid.uuid,p_chars[i].characteristic.handle_value); switch (p_chars[i].characteristic.uuid.uuid) { case BLE_UUID_GOPRO_COMMAND_TX_CHARACTERISTIC: NRF_LOG_DEBUG("TX handle: 0x%0X",p_chars[i].characteristic.handle_value); nus_c_evt.handles.command_tx_handle = p_chars[i].characteristic.handle_value; break; case BLE_UUID_GOPRO_COMMAND_RX_CHARACTERISTIC: NRF_LOG_DEBUG("RX handle: 0x%0X cccd: 0x%0X",p_chars[i].characteristic.handle_value,p_chars[i].cccd_handle); nus_c_evt.handles.command_rx_handle = p_chars[i].characteristic.handle_value; nus_c_evt.handles.command_rx_cccd_handle = p_chars[i].cccd_handle; break; default: break; } } if (p_ble_nus_c->evt_handler != NULL) { nus_c_evt.conn_handle = p_evt->conn_handle; nus_c_evt.evt_type = BLE_NUS_C_EVT_DISCOVERY_COMPLETE; p_ble_nus_c->evt_handler(p_ble_nus_c, &nus_c_evt); } } }
Now, I can scan for camera (scan for device with service 0xFEA6), found it and connect. Connection log:
<info> app_timer: RTC: initialized. <debug> app: Register uuid 0xFEA6 type 1 <info> app: INIT strcut type: 2 <debug> ble_scan: Added filter on UUID FEA6 <info> app: BLE UART central example started. <debug> ble_scan: Scanning <debug> app: Scan not found <debug> ble_scan: Scanning <debug> app: Scan not found <debug> ble_scan: Scanning <debug> app: Scan not found <debug> ble_scan: Scanning <debug> app: Scan not found <debug> ble_scan: Scanning <debug> app: Scan not found <debug> ble_scan: Scanning <debug> ble_scan: Connecting <debug> ble_scan: Connection status: 0 <debug> app: Scan filter match <debug> ble_scan: Scanning <info> app: Connecting to target C0:3D:0B:EF:2F:77 <debug> nrf_ble_gatt: Requesting to update ATT MTU to 247 bytes on connection 0x0. <debug> nrf_ble_gatt: Updating data length to 251 on connection 0x0. <info> app: BLE EVT Connected <debug> app: Assign handles RX: 0x400 CCCD 0x2000 <debug> nrf_ble_gq: Registering connection handle: 0x0000 <info> app: Start discovery <debug> ble_db_disc: Starting discovery of service with UUID 0xFEA6 on connection handle 0x0. <debug> nrf_ble_gatt: Data length updated to 251 on connection 0x0. <debug> nrf_ble_gatt: max_rx_octets: 251 <debug> nrf_ble_gatt: max_tx_octets: 251 <debug> nrf_ble_gatt: max_rx_time: 2120 <debug> nrf_ble_gatt: max_tx_time: 2120 <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: GATTC Primary Service Discovery Request <debug> nrf_ble_gq: SD GATT procedure (2) succeeded on connection handle: 0. <debug> nrf_ble_gatt: ATT MTU updated to 247 bytes on connection 0x0 (response). <info> app: ATT MTU exchange completed. <info> app: Ble NUS max data length set to 0xF4(244) <debug> nrf_ble_gq: Processing the request queue... <debug> ble_db_disc: Found service UUID 0xFEA6. <debug> nrf_ble_gq: Adding item to the request queue <debug> nrf_ble_gq: GATTC Characteristic Discovery Request <debug> nrf_ble_gq: SD GATT procedure (3) succeeded on connection handle: 0. <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: Adding item to the request queue <debug> nrf_ble_gq: GATTC Characteristic Discovery Request <debug> nrf_ble_gq: SD GATT procedure (3) succeeded on connection handle: 0. <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: Adding item to the request queue <debug> nrf_ble_gq: GATTC Characteristic Descriptor Request <debug> nrf_ble_gq: SD GATT procedure (4) succeeded on connection handle: 0. <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: Adding item to the request queue <debug> nrf_ble_gq: GATTC Characteristic Descriptor Request <debug> nrf_ble_gq: SD GATT procedure (4) succeeded on connection handle: 0. <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: Adding item to the request queue <debug> nrf_ble_gq: GATTC Characteristic Descriptor Request <debug> nrf_ble_gq: SD GATT procedure (4) succeeded on connection handle: 0. <debug> nrf_ble_gq: Processing the request queue... <debug> nrf_ble_gq: Adding item to the request queue <debug> nrf_ble_gq: GATTC Characteristic Descriptor Request <debug> nrf_ble_gq: SD GATT procedure (4) succeeded on connection handle: 0. <debug> nrf_ble_gq: Processing the request queue... <debug> ble_db_disc: Discovery of service with UUID 0xFEA6 completed with success on connection handle 0x0. <debug> app: DB discovery evt Type: 0 uuid 0xFEA6 uuid type: 1 <info> app: Discovery 0 / 8 char 0x72 handle 0x38 <debug> app: TX handle: 0x38 <info> app: Discovery 1 / 8 char 0x73 handle 0x3A <debug> app: RX handle: 0x3A cccd: 0x3B <info> app: Discovery 2 / 8 char 0x74 handle 0x3D <info> app: Discovery 3 / 8 char 0x75 handle 0x3F <info> app: Discovery 4 / 8 char 0x76 handle 0x42 <info> app: Discovery 5 / 8 char 0x77 handle 0x44 <info> app: Discovery 6 / 8 char 0x78 handle 0x47 <info> app: Discovery 7 / 8 char 0x79 handle 0x49 <info> app: NUS EVT Discovery complete. <debug> app: Assign handles RX: 0x3A CCCD 0x3B <debug> app: Enable notify RX handles: 0x0 0x3B <info> app: CCCD Config
All chars are discovered. I try to write command to char 0x0072 with handle 0x38:
uint32_t ble_gopro_cmd_send(ble_nus_c_t * p_ble_nus_c, uint8_t * p_cmd, uint16_t length) { VERIFY_PARAM_NOT_NULL(p_ble_nus_c); nrf_ble_gq_req_t write_req; memset(&write_req, 0, sizeof(nrf_ble_gq_req_t)); if (length > BLE_NUS_MAX_DATA_LEN) { NRF_LOG_WARNING("Content too long."); return NRF_ERROR_INVALID_PARAM; } if (p_ble_nus_c->conn_handle == BLE_CONN_HANDLE_INVALID) { NRF_LOG_WARNING("Connection handle invalid."); return NRF_ERROR_INVALID_STATE; } NRF_LOG_DEBUG("Send %d bytes data on handle 0x%0X",length,p_ble_nus_c->handles.command_tx_handle); NRF_LOG_HEXDUMP_DEBUG(p_cmd, length); write_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE; write_req.error_handler.cb = gatt_error_handler; write_req.error_handler.p_ctx = p_ble_nus_c; write_req.params.gattc_write.handle = p_ble_nus_c->handles.command_tx_handle; write_req.params.gattc_write.len = length; write_req.params.gattc_write.offset = 0; write_req.params.gattc_write.p_value = p_cmd; write_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ; write_req.params.gattc_write.flags = BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE; return nrf_ble_gq_item_add(p_ble_nus_c->p_gatt_queue, &write_req, p_ble_nus_c->conn_handle); }
Log:
<info> app: Button 0 <debug> app: Send 4 bytes data on handle 0x38 <debug> app: 03 01 01 01 |.... <debug> nrf_ble_gq: Adding item to the request queue <debug> nrf_ble_gq: GATTC Write Request <debug> nrf_ble_gq: SD GATT procedure (1) succeeded on connection handle: 0. <info> app: Send ret: 0 <debug> nrf_ble_gq: Processing the request queue...
But the camera does not respond to the command.
I used a sniffer to see what is happening and compare the command that I send from the phone via nRF Connect and from my code.
From nRF Connect:
From my code:
The difference is that when writing from my code, service 0xFEA6 is not specified in Handle 0x38, only UUID . That's why I get an error reply from camera.
What am I doing wrong, why is the service not specified when writing?
I use old SDK v17.1.0, but I think the problem is not in SDK, but in my code. New SDK uses Zephyr OS and switching to it takes time.