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

BLE transmission method of multiple data

Hello

I am using Android and BLE communication with nRF52832 (BLENano2) now.

I am using SDK 15.0.0 with keil uversion.

Central is Android and peripheral is nRF52832.

Use the SDK "ble_app_blinky".

I now want to send arbitrary data from peripheral to central.

By calling the following code "send_data" in the main for loop, it was possible to send the value to central.

uint32_t send_value(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t sensor_value)
{
	
	if (p_lbs == NULL)
    {
        return NRF_ERROR_NULL;
    }
		
	
	uint32_t err_code = NRF_SUCCESS;
	ble_gatts_value_t gatts_value;
	
	// Initialize value struct.
  memset(&gatts_value, 0, sizeof(gatts_value));

	gatts_value.len     = sizeof(uint8_t);
  gatts_value.offset  = 0;
  gatts_value.p_value = &sensor_value;

	// Update database.
  err_code = sd_ble_gatts_value_set(BLE_CONN_HANDLE_ALL,////////////
                                      p_lbs->sensor_char_handles.value_handle,
                                      &gatts_value);

	
		
		if (err_code != NRF_SUCCESS)
		{
				return err_code;
		}


	
	// Send value if connected and notifying.
    if ((conn_handle != BLE_CONN_HANDLE_INVALID)) 
    {
        ble_gatts_hvx_params_t hvx_params;

        memset(&hvx_params, 0, sizeof(hvx_params));

        hvx_params.handle = p_lbs->sensor_char_handles.value_handle;
        hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
        hvx_params.offset = gatts_value.offset;
        hvx_params.p_len  = &gatts_value.len;
        hvx_params.p_data = gatts_value.p_value;

        err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);
    }
    else
    {
        err_code = NRF_ERROR_INVALID_STATE;
    }
		return err_code;
}

I am currently sending uint8_t data, but I want to be able to send multiple data.

Since we are transmitting the output value of the acceleration sensor, we want to transmit a total of 6 bytes of data.

The problem here is that even if uint16_t is executed with uint8_t as the argument of "send_data" in order to send multiple data at once, the data was not sent.

What should I do to send multiple data?

As a possible way,
1) Separate the characteristic for each data you want to send and send each.
2) As I said earlier, prepare a larger sized variable instead of uint8_t.

I thought that.

I tried to increase the characteristic, but only one characteristic worked.

If you know the solution please tell me.

Thank you.

  • This piece of code is what sets the length to 1 byte. Note also that you can't send data longer than the negotiated MTU size - 3 in one operation.

    uint8_t sensor_value;
    
    gatts_value.len     = sizeof(uint8_t);
    gatts_value.offset  = 0;
    gatts_value.p_value = &sensor_value;

    So, you can modify this to instead of taking a uint8_t as value argument, take a pointer and a length. Then you define the data format elsewhere, this just sends the data.

  • Thank you for reply!

    uint32_t send_value(uint16_t conn_handle, ble_lbs_t * p_lbs, uint16_t sensor_value)
    {
    	
    	if (p_lbs == NULL)
        {
            return NRF_ERROR_NULL;
        }
    		
    	
    	uint32_t err_code = NRF_SUCCESS;
    	ble_gatts_value_t gatts_value;
    	
    	// Initialize value struct.
      memset(&gatts_value, 0, sizeof(gatts_value));
    
    	gatts_value.len     = sizeof(uint16_t);
      gatts_value.offset  = 0;
      gatts_value.p_value = &sensor_value;
    
    	// Update database.
      err_code = sd_ble_gatts_value_set(BLE_CONN_HANDLE_ALL,////////////
                                          p_lbs->sensor_char_handles.value_handle,
                                          &gatts_value);
    
    	
    		
    		if (err_code != NRF_SUCCESS)
    		{
    				return err_code;
    		}
    
    
    	
    	// Send value if connected and notifying.
        if ((conn_handle != BLE_CONN_HANDLE_INVALID)) 
        {
            ble_gatts_hvx_params_t hvx_params;
    
            memset(&hvx_params, 0, sizeof(hvx_params));
    
            hvx_params.handle = p_lbs->sensor_char_handles.value_handle;
            hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
            hvx_params.offset = gatts_value.offset;
            hvx_params.p_len  = &gatts_value.len;
            hvx_params.p_data = gatts_value.p_value;
    
            err_code = sd_ble_gatts_hvx(conn_handle, &hvx_params);
        }
        else
        {
            err_code = NRF_ERROR_INVALID_STATE;
        }
    		return err_code;
    }
    

    Should I make this change?

    Also, as settings, ble_gatts_value_t of "ble_gatts.h" and * p_value of ble_gatts_hvx_params_t have been changed to uint16_t.

    After making these changes, nRFConnect did not receive a value when trying to send 2 bytes worth of data.

  • What return code did you get from send_value? Did you enable notifications from nRFConnect?

    I have successfully done like this:

    uint32_t ble_tx(uint16_t conn_key, const uint8_t *p_data, uint16_t length)
    {
        le_client_internal_t *p_client = NULL;
        ble_gatts_hvx_params_t hvx_params;
    
        ret_code_t err_code = blcm_link_ctx_get(m_ble.p_link_ctx_storage,
                                     conn_key,
                                     (void *) &p_client);
    
        if (err_code != NRF_SUCCESS)
        {
            NRF_LOG_ERROR("Link context for 0x%02X connection handle could not be fetched.",
                          conn_key);
            return NRF_ERROR_INVALID_STATE;
        }
    
        if (p_client == NULL)
        {
            return NRF_ERROR_INVALID_STATE;
        }
    
        if (length > p_client->data_size)
        {
            /* TODO: Compare against the actual MTU negotiated. */
            return NRF_ERROR_INVALID_PARAM;
        }
    
        memset(&hvx_params, 0, sizeof(hvx_params));
    
        hvx_params.handle = m_ble.tx_char_handle.value_handle;
        hvx_params.p_data = p_data;
        hvx_params.p_len  = &length;
        hvx_params.type   = BLE_GATT_HVX_NOTIFICATION;
    
        return sd_ble_gatts_hvx(conn_key, &hvx_params);
    }

    I also have an internal structure that keeps track of if the MTU size is renegotiated. Another layer actually checks that so I never end up in the (lengt > p_client->data_size) branch.

  • The value of "sensor_value" was displayed as 0x61 as the default value on nRFconnect.
    Since sensor_value has a variable that is incremented each time just before calling so that the value update can be understood, it is strange that it is 0x61 all the time.
    Also, notifications have been enabled.

    In that code, p_value is uint8_t, but can you send 2 bytes?

    When calling, is the part corresponding to p_value an array or something?

  • It is a uint8_t pointer, meaning that it points to some data that is defined elsewhere. Also i provide the length value of that data.

    Does all your data fit into a uint16_t then your API is enough, but as you wrote you want to send 6 bytes of data. So a nicer API would be something that can send all that data at once (if that is what you wish).

    /* API Could look like */
    uint32_t send_data(uint16_t conn_handle, ble_lbs_t * p_lbs, uint8_t *data, uint16_t size)
    
    {
    
     /* Collect sensor data here */
     uint8_t data[6];
     collect_sensor_data(data);
     
     uint32_t err_code = send_data(..., data, sizeof(data));
    
    }

Related