GoPro control over BLE, write char issue.

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.

Parents
  • Hi!

    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.

    Seems like they are sending 2 different values as well.

    nRF Connect:

    Your code:

    From the log:
    <debug> app: Send 4 bytes data on handle 0x38
    <debug> app: 03 01 01 01 |....

    Maybe it works better if you send the same value as with nRF Connect? 03 01 01 00

Reply
  • Hi!

    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.

    Seems like they are sending 2 different values as well.

    nRF Connect:

    Your code:

    From the log:
    <debug> app: Send 4 bytes data on handle 0x38
    <debug> app: 03 01 01 01 |....

    Maybe it works better if you send the same value as with nRF Connect? 03 01 01 00

Children
Related