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

Multiple value in one characteristic

Hello,

My project requires me to send acceleration data to phone. So, i have started with Custom BLE app.

Since i need to send 3 values, of x, y and z-axis. So i need to send multiple values to same characteristic. Can you guide me regarding this?

If any other approach serves me better, kindly do suggest me.

  • Hello,

    Yes, you may use a custom service with multiple characteristics for this purpose.
    Have you seen our Service tutorial, and characteristics tutorial? I highly recommend completing these tutorials in order to familiarize yourself with creating both custom services and characteristics.

    Best regards,
    Karl

  • The definition of a "Characteristic", from the Bluetooth SIG website, is:

    "Characteristics are defined attribute types that contain a single logical value."

    https://www.bluetooth.com/specifications/gatt/characteristics/

    (my emphasis)

    However, there's nothing to stop you having a 3-byte value - where the 1st byte represents X, the 2nd byte represents Y, and the 3rd byte represents Z

    Or have a 6-byte value - where the 1st two bytes represent X, the 2nd two bytes represent Y, and the 3rd two bytes represent Z

    etc, etc, ...

    Or, as  says, have a characteristic for X, and characteristic for Y, and a characteristic for Z.

    See those tutorials.

    EDIT

    The Thingy:52 adopts the scheme of "packing" multiple values into a single Characteristic; eg, see the "Raw Data" Characteristic:

    https://nordicsemiconductor.github.io/Nordic-Thingy52-FW/documentation/firmware_architecture.html#arch_motion

  • Thank you so much,  and  for your suggestions.

    So,

    Question 1

    a. Sending 3 values, one after the other , through the same value and characteristics (This would consume power for all 3 transmissions)

    b. Sending 3 values to 3 different characteristics (Would this also means im trying to send the data in 3 transmissions?)

    c. Sending all 3 values packed would save power and could send all data in one transmission.

    Kindly correct me, if I'm wrong.

    ------------------------------------------------------------------------------------------------------------------------------------------------------

    Question 2

    So, currently my code is pushing 8 bits of data . To change this to 64bits, i tried following corrections, Kindly let me know, if this is okay and if anything else has to be changed

           a. change the size of custom value (main.c)

                           

           b. change the argument size and gatts_value.len (ble_cus.c)

    uint32_t ble_cus_custom_value_update(ble_cus_t * p_cus, uint64_t custom_value){
        NRF_LOG_INFO("In ble_cus_custom_value_update. \r\n"); 
         
        if (p_cus == 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(uint64_t);
        gatts_value.offset  = 0;
        gatts_value.p_value = &custom_value;
    
        // Update database.
        err_code = sd_ble_gatts_value_set(p_cus->conn_handle,
                                            p_cus->custom_value_handles.value_handle,
                                            &gatts_value);
        if (err_code != NRF_SUCCESS)
        {
            return err_code;
        }
    
            // Send value if connected and notifying.
        if ((p_cus->conn_handle != BLE_CONN_HANDLE_INVALID)) 
        {
            ble_gatts_hvx_params_t hvx_params;
    
            memset(&hvx_params, 0, sizeof(hvx_params));
    
            hvx_params.handle = p_cus->custom_value_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(p_cus->conn_handle, &hvx_params);
            NRF_LOG_INFO("sd_ble_gatts_hvx result: %x. \r\n", err_code);
        }
            else
        {
            err_code = NRF_ERROR_INVALID_STATE;
            NRF_LOG_INFO("sd_ble_gatts_hvx result: NRF_ERROR_INVALID_STATE. \r\n"); 
        }
    
        return err_code;
        }

             c. Change the size of custom value in prototype declaration. (ble_cus.h)

             d. Change the value of structure of GATT attribute value and HVx value as below (ble_gatts.h)

    /**@brief GATT Attribute Value. */
    typedef struct
    {
      uint64_t  len;        /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/
      uint64_t  offset;     /**< Attribute value offset. */
      uint64_t  *p_value;    /**< Pointer to where value is stored or will be stored.
                                 If value is stored in user memory, only the attribute length is updated when p_value == NULL.
                                 Set to NULL when reading to obtain the complete length of the attribute value */
    } ble_gatts_value_t;
    
    
    /**@brief GATT HVx parameters. */
    typedef struct
    {
      uint64_t          handle;             /**< Characteristic Value Handle. */
      uint64_t           type;               /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */
      uint64_t          offset;             /**< Offset within the attribute value. */
      uint64_t         *p_len;              /**< Length in bytes to be written, length in bytes written after return. */
      uint64_t const    *p_data;             /**< Actual data content, use NULL to use the current attribute value. */
    } ble_gatts_hvx_params_t;

  • Hello,

    I do not understand the format of your questions, am I to select one of the a, b, c options presented? There are also no actual question posed in "Question 1". 

    Nats said:
    Question 1

    Yes, less active radio time consumes less power, this is correct.

    However, you might want the characteristics to be read by the central whenever the central pleases(read characteristic) or you might want the central to be notified as soon as there is an update to the characteristics.
    So it also depends on how the characteristics are configured, but in general it would cost the least power to have all the values in a single characteristic.
    To reduce power consumption, you could also use the slave latency feature, combined with longer connection intervals(longer time in between each transmission). You will have to weight these possibilities against the real-time constraints of your application.

    I do not know where you are going with your included screenshot in question 1, but be advised that the value is only incremented once each function call, and thus not in between each update call - if that was the intention.

    Nats said:

    Question 2

    a, b, and c is correct at least.
    The changes made in d are incorrect, and you should not just change these types without looking into what they intend to contain. Please have a look at their documentation.

    Best regards,
    Karl

  • Sorry, if i wasn't clear, I'm very new to this whole concept. I just wanted to know, that the three points i understood were correct or not.

    With regards to Question 1 snapshot, It is was just a demo code, to explain what i meant, when i said, sending three values in the same characteristics.

    (I thought of sending X and Y and Z, one after the other in this format, until the concept of packing was introduced.)

    In regards to Question2, Is there any other reference to explain more in detail regarding sending packed data. What are the functions in which the modifications have to be made, in order to achieve sending more than 8 bits. or array.

Related