I'm working on a inertial sensor (peripheral/server) which shoiuld communicate througth BLE with a custom USB dongle (central/client). Both systems mount the nRF52840 and I developing the firmware in VS Code with NRF Connect SDK 2.3.0.
Now when I connect the sensor to the nRf Connect application on my phone all seems to be ok: I can write on my custom characteristic and I can enable notify for my two custom characteristic as well. So I can confirm that the sensor works fine for now.
But If I connect the sensor to my custom dongle, I can't forward the USB commands to the BLE because when I write to my characteristic I get the BT_ATT_ERR_NOT_SUPPORTED. For the dongle I used the central_uart example that uses the NUS client. I modified it creating my own sensor client. The code of my dongle is the following (only the BLE) and the starting point is the Ble_Connection_Initialize function at the bottom. Whats the problem?
#include "ble_connection.h" /******************************************************************************* * Global Variables ******************************************************************************/ static bt_addr_le_t deviceAddr; static struct bt_conn_cb bluetootCallbacks; static struct bt_conn *currentConnection; static struct bt_uuid_128 uuid = BT_UUID_INIT_128( 0 ); static struct bt_gatt_discover_params discoverParams; static struct bt_gatt_subscribe_params subscribeParams; static bool deviceConnected; static gravity_client_t gravityClient; static K_THREAD_STACK_DEFINE( bleSendDataStackArea, BLE_CONNECTION_SEND_DATA_THREAD_STACKSIZE ); static struct k_thread bleSendDataThreadData; static k_tid_t bleSendDataThreadId; K_SEM_DEFINE( bleWriteSemaphore, 0, 1 ); K_FIFO_DEFINE( fifoBleTxData ); K_FIFO_DEFINE( fifoBleRxData ); K_FIFO_DEFINE( fifoBleRxInertialData ); /******************************************************************************* * Function Definitions ******************************************************************************/ static void Discovery_Gatt( struct bt_conn *conn ); static void Discovery_Complete( struct bt_gatt_dm *dm, void *context ); static void Discovery_Service_Not_Found( struct bt_conn *conn, void *context ); static void Discovery_Error( struct bt_conn *conn, int err, void *context ); static void Ble_Connection_Mtu_Exchange( struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params ); static void Ble_Connection_On_Connect( struct bt_conn *conn, uint8_t err ); static void Ble_Connection_On_Disconnect( struct bt_conn *conn, uint8_t reason ); static void Ble_Connection_Security_Changed( struct bt_conn *conn, bt_security_t level, enum bt_security_err err ); static void Ble_Connection_Message_Tx_Sent( gravity_client_t *client, uint8_t err, const uint8_t *const data, uint16_t len ); static uint8_t Ble_Connection_Message_Rx_Notify_Func( gravity_client_t *client, const uint8_t *data, uint16_t len ); static uint8_t Ble_Connection_Inertial_Rx_Notify_Func( gravity_client_t *client, const uint8_t *data, uint16_t len ); static void Ble_Connection_Scan_Filter_Match( struct bt_scan_device_info *device_info, struct bt_scan_filter_match *filter_match, bool connectable ); static void Ble_Connection_Scan_Connecting_Error( struct bt_scan_device_info *device_info ); static void Ble_Connection_Scan_Connecting( struct bt_scan_device_info *device_info, struct bt_conn *conn ); static system_error_t Ble_Connection_Scan_Initialize( void ); static system_error_t Ble_Connection_Start_Scan( void ); static void Ble_Connection_Auth_Cancel( struct bt_conn *conn ); static void Ble_Connection_Pairing_Complete( struct bt_conn *conn, bool bonded ); static void Ble_Connection_Pairing_Failed( struct bt_conn *conn, enum bt_security_err reason ); static system_error_t Ble_Connection_Gravity_Client_Initialize( void ); static void Ble_Connection_Send_Data_Thread( void ); struct bt_gatt_dm_cb discoveryCb = { .completed = Discovery_Complete, .service_not_found = Discovery_Service_Not_Found, .error_found = Discovery_Error, }; BT_SCAN_CB_INIT( scanCb, Ble_Connection_Scan_Filter_Match, NULL, Ble_Connection_Scan_Connecting_Error, Ble_Connection_Scan_Connecting ); static struct bt_conn_auth_cb connAuthCallbacks = { .cancel = Ble_Connection_Auth_Cancel, }; static struct bt_conn_auth_info_cb connAuthInfoCallbacks = { .pairing_complete = Ble_Connection_Pairing_Complete, .pairing_failed = Ble_Connection_Pairing_Failed }; /******************************************************************************* * Function: * * static void Discovery_Gatt( struct bt_conn *conn ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Discovery_Gatt( struct bt_conn *conn ) { if ( conn != currentConnection ) { return; } if ( bt_gatt_dm_start( conn, BT_UUID_GRAVITY_SERV, &discoveryCb, &gravityClient ) != 0 ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Could not start the discovery procedure" ); } } /******************************************************************************* * Function: * * static void Discovery_Complete( struct bt_gatt_dm *dm, void *context ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Discovery_Complete( struct bt_gatt_dm *dm, void *context ) { struct bt_gravity_client *client = context; SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Service discovery completed" ); bt_gatt_dm_data_print( dm ); Gravity_Client_Handles_Assign( dm, client ); Gravity_Client_Subscribe_Receive( client ); bt_gatt_dm_data_release( dm ); } /******************************************************************************* * Function: * * static void Discovery_Service_Not_Found( struct bt_conn *conn, uint8_t err ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Discovery_Service_Not_Found( struct bt_conn *conn, void *context ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Service not found" ); } /******************************************************************************* * Function: * * static void Discovery_Error( struct bt_conn *conn, int err, void *context ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Discovery_Error( struct bt_conn *conn, int err, void *context ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Error while discovering GATT database: %d", err ); } /******************************************************************************* * Function: * * static void Ble_Connection_Mtu_Exchange( struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params ) * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Mtu_Exchange( struct bt_conn *conn, uint8_t err, struct bt_gatt_exchange_params *params ) { if ( !err ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] MTU exchange done" ); } else { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] MTU exchange failed (err %" PRIu8 ")", err ); } // Discovery_Gatt( conn ); } /******************************************************************************* * Function: * * static void Ble_Connection_On_Connect( struct bt_conn *conn, uint8_t err ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_On_Connect( struct bt_conn *conn, uint8_t connErr ) { char addr[ BT_ADDR_LE_STR_LEN ]; int err; static struct bt_gatt_exchange_params exchangeParams; bt_addr_le_to_str( bt_conn_get_dst( conn ), addr, sizeof( addr ) ); if ( connErr ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Failed to connect to %s ( %u )", addr, connErr ); bt_conn_unref( currentConnection ); currentConnection = NULL; Ble_Connection_Start_Scan(); App_Change_State( APP_STATE_ERROR ); return; } SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Connected to %s", addr ); deviceConnected = true; App_Change_State( APP_STATE_CONNECTED ); exchangeParams.func = Ble_Connection_Mtu_Exchange; if ( bt_gatt_exchange_mtu( conn, &exchangeParams ) != 0 ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] MTU exchange failed" ); // Discovery_Gatt( conn ); } if ( bt_conn_set_security( conn, BT_SECURITY_L2 ) != 0 ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Failed to set security" ); Discovery_Gatt( conn ); } err = bt_scan_stop(); if ( ( !err ) && ( err != -EALREADY ) ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Stop LE scan failed (err %d)", err ); } } /******************************************************************************* * Function: * * static void Ble_Connection_On_Disconnect( struct bt_conn *conn, uint8_t reason ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_On_Disconnect( struct bt_conn *conn, uint8_t reason ) { char addr[ BT_ADDR_LE_STR_LEN ]; if ( currentConnection == conn ) { bt_addr_le_to_str( bt_conn_get_dst( conn ), addr, sizeof( addr ) ); SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Disconnected: %s ( reason 0x%02x )", addr, reason ); deviceConnected = false; App_Change_State( APP_STATE_IDLE ); bt_conn_unref( currentConnection ); currentConnection = NULL; Ble_Connection_Start_Scan(); } } /******************************************************************************* * Function: * * static void Ble_Connection_Security_Changed( struct bt_conn *conn, bt_security_t level, enum bt_security_err err ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Security_Changed( struct bt_conn *conn, bt_security_t level, enum bt_security_err err ) { char addr[ BT_ADDR_LE_STR_LEN ]; bt_addr_le_to_str( bt_conn_get_dst( conn ), addr, sizeof( addr ) ); if ( !err ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Security changed: %s level %u", addr, level ); } else { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Security failed: %s level %u err %d", addr, level, err ); } Discovery_Gatt( conn ); } /******************************************************************************* * Function: * * static void Ble_Connection_Message_Tx_Sent( gravity_client_t *client, uint8_t err, const uint8_t *const data, uint16_t len ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Message_Tx_Sent( gravity_client_t *client, uint8_t err, const uint8_t *const data, uint16_t len ) { ARG_UNUSED( client ); k_sem_give( &bleWriteSemaphore ); if ( err ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] ATT error code: 0x%02X", err ); } } /******************************************************************************* * Function: * * static uint8_t Ble_Connection_Message_Rx_Notify_Func( gravity_client_t *client, const uint8_t *data, uint16_t len ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static uint8_t Ble_Connection_Message_Rx_Notify_Func( gravity_client_t *client, const uint8_t *data, uint16_t len ) { ARG_UNUSED( client ); SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "%s", data ); return BT_GATT_ITER_CONTINUE; } /******************************************************************************* * Function: * * static uint8_t Ble_Connection_Inertial_Rx_Notify_Func( gravity_client_t *client, const uint8_t *data, uint16_t len ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static uint8_t Ble_Connection_Inertial_Rx_Notify_Func( gravity_client_t *client, const uint8_t *data, uint16_t len ) { ARG_UNUSED( client ); Usb_Connection_Send_Inertial_Data( ( char * )data, len ); return BT_GATT_ITER_CONTINUE; } /******************************************************************************* * Function: * * static void Ble_Connection_Scan_Filter_Match( struct bt_scan_device_info *device_info, struct bt_scan_filter_match *filter_match, bool connectable ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Scan_Filter_Match( struct bt_scan_device_info *device_info, struct bt_scan_filter_match *filter_match, bool connectable ) { char addr[ BT_ADDR_LE_STR_LEN ]; bt_addr_le_to_str( device_info->recv_info->addr, addr, sizeof( addr ) ); SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Filters matched. Address: %s connectable: %d", addr, connectable ); } /******************************************************************************* * Function: * * static void Ble_Connection_Scan_Connecting_Error( struct bt_scan_device_info *device_info ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Scan_Connecting_Error( struct bt_scan_device_info *device_info ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Connecting failed" ); } /******************************************************************************* * Function: * * static void Ble_Connection_Scan_Connecting( struct bt_scan_device_info *device_info, struct bt_conn *conn ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Scan_Connecting( struct bt_scan_device_info *device_info, struct bt_conn *conn ) { currentConnection = bt_conn_ref( conn ); } /******************************************************************************* * Function: * * static system_error_t Ble_Connection_Start_Scan( void ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static system_error_t Ble_Connection_Scan_Initialize( void ) { struct bt_scan_init_param scanInit = { .connect_if_match = 1, }; bt_scan_init( &scanInit ); bt_scan_cb_register( &scanCb ); if ( bt_scan_filter_add( BT_SCAN_FILTER_TYPE_UUID, BT_UUID_GRAVITY_SERV ) != 0 ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Scanning filters cannot be set" ); return SYSTEM_ERROR; } if ( bt_scan_filter_enable( BT_SCAN_UUID_FILTER, false ) != 0 ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Filters cannot be turned on" ); return SYSTEM_ERROR; } SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Scan module initialized" ); return SYSTEM_NO_ERROR; } /******************************************************************************* * Function: * * static system_error_t Ble_Connection_Start_Scan( void ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static system_error_t Ble_Connection_Start_Scan( void ) { if ( bt_scan_start( BT_SCAN_TYPE_SCAN_ACTIVE ) != 0 ) { return SYSTEM_ERROR; } return SYSTEM_NO_ERROR; } /******************************************************************************* * Function: * * static void Ble_Connection_Auth_Cancel( struct bt_conn *conn ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Auth_Cancel( struct bt_conn *conn ) { char addr[ BT_ADDR_LE_STR_LEN ]; bt_addr_le_to_str( bt_conn_get_dst( conn ), addr, sizeof( addr ) ); SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Pairing cancelled: %s", addr ); } /******************************************************************************* * Function: * * static void Ble_Connection_Pairing_Complete( struct bt_conn *conn, bool bonded ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Pairing_Complete( struct bt_conn *conn, bool bonded ) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Pairing completed: %s, bonded: %d", addr, bonded ); } /******************************************************************************* * Function: * * static void Ble_Connection_Pairing_Failed( struct bt_conn *conn, enum bt_security_err reason ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Pairing_Failed( struct bt_conn *conn, enum bt_security_err reason ) { char addr[BT_ADDR_LE_STR_LEN]; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Pairing failed conn: %s, reason %d", addr, reason ); } /******************************************************************************* * Function: * * static system_error_t Ble_Connection_Gravity_Client_Initialize( void ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static system_error_t Ble_Connection_Gravity_Client_Initialize( void ) { gravity_client_init_param_t init = { .cb = { .sent = Ble_Connection_Message_Tx_Sent, .messageReceived = Ble_Connection_Message_Rx_Notify_Func, .messageUnsubscribed = NULL, .inertialReceived = Ble_Connection_Inertial_Rx_Notify_Func, .inertialUnsubscribed = NULL, } }; if ( Gravity_Client_Initialize( &gravityClient, &init ) != SYSTEM_NO_ERROR ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Gravity client initialization failed" ); return SYSTEM_ERROR; } SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Gravity client module initialized" ); return SYSTEM_NO_ERROR; } /******************************************************************************* * Function: * * static void Ble_Connection_Send_Data_Thread( void ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ static void Ble_Connection_Send_Data_Thread( void ) { ble_tx_data_t *txBuf; for ( ;; ) { txBuf = k_fifo_get( &fifoBleTxData, K_FOREVER ); if ( Gravity_Client_Send_Data( &gravityClient, txBuf->data, txBuf->len ) != SYSTEM_NO_ERROR ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Failed to send data over BLE connection" ); } if ( k_sem_take( &bleWriteSemaphore, K_MSEC( 150 ) ) != 0 ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Send data timeout" ); } } } /******************************************************************************* * Function: * * system_error_t Ble_Connection_Initialize( void ) * * Description: * * None. * * Parameters: * * None. * * Returns: * * None. * ******************************************************************************/ system_error_t Ble_Connection_Initialize( void ) { deviceConnected = false; bluetootCallbacks.connected = Ble_Connection_On_Connect; bluetootCallbacks.disconnected = Ble_Connection_On_Disconnect; bluetootCallbacks.security_changed = Ble_Connection_Security_Changed; bt_conn_cb_register( &bluetootCallbacks ); bt_addr_le_from_str( BT_GRAVITY_DEVICE_ADDR, BT_GRAVITY_DEVICE_TYPE, &deviceAddr ); if ( bt_conn_auth_cb_register( &connAuthCallbacks ) != 0 ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Failed to register authorization callbacks" ); System_Dbg_Err_Type_Set( SYSTEM_ERROR_INIT_BLE_CONNECTION ); return SYSTEM_ERROR; } if ( bt_conn_auth_info_cb_register( &connAuthInfoCallbacks ) != 0 ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Failed to register authorization info callbacks" ); System_Dbg_Err_Type_Set( SYSTEM_ERROR_INIT_BLE_CONNECTION ); return SYSTEM_ERROR; } if ( bt_enable( NULL ) != 0 ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Bluetooth init failed" ); System_Dbg_Err_Type_Set( SYSTEM_ERROR_INIT_BLE_CONNECTION ); return SYSTEM_ERROR; } SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_INFO, "\n[I] Bluetooth initialized" ); if ( Ble_Connection_Scan_Initialize() != SYSTEM_NO_ERROR ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Bluetooth scan initialize failed" ); System_Dbg_Err_Type_Set( SYSTEM_ERROR_INIT_BLE_CONNECTION ); return SYSTEM_ERROR; } if ( Ble_Connection_Gravity_Client_Initialize() != SYSTEM_NO_ERROR ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Bluetooth gravity client initialize failed" ); System_Dbg_Err_Type_Set( SYSTEM_ERROR_INIT_BLE_CONNECTION ); return SYSTEM_ERROR; } if ( Ble_Connection_Start_Scan() != SYSTEM_NO_ERROR ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Bluetooth scan start failed" ); System_Dbg_Err_Type_Set( SYSTEM_ERROR_INIT_BLE_CONNECTION ); return SYSTEM_ERROR; } bleSendDataThreadId = NULL; bleSendDataThreadId = k_thread_create( &bleSendDataThreadData, bleSendDataStackArea, K_THREAD_STACK_SIZEOF( bleSendDataStackArea ), Ble_Connection_Send_Data_Thread, NULL, NULL, NULL, BLE_CONNECTION_SEND_DATA_THREAD_PRIORITY, 0, K_NO_WAIT); if ( bleSendDataThreadId == NULL ) { SYSTEM_DBG_PRINT( SYSTEM_DBG_LEVEL_WARNING, "\n[W] Creating Ble_Connection_Send_Data_Thread failed" ); System_Dbg_Err_Type_Set( SYSTEM_ERROR_INIT_STATUS_LED ); return SYSTEM_ERROR; } return SYSTEM_NO_ERROR; }