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

How to use BLE_GATTS_VLOC_USER ?

Do I still have to call sd_ble_gatts_value_set() on the characteristic handle [using whatever temporary buffer I would have been using anyway for BLE_GATTS_VLOC_STACK]?

Or can I simply modify the referenced buffer, and characteristic reads will magically start returning the updated buffer value? (I am not using rd_auth for characteristic reads; the ble_gatts_attr_md_t for the characteristic has rd_auth=0.)

Thanks!

  • You can in principle just modify the buffer, but if the attribute is of variable length it may cause problems since the softdevice will not know any longer how much of the buffer is actually valid. If the attribute has constant length, modifying the buffer directly shouldn't cause any problems.

    I'd still recommend to do the sd_ble_gatts_value_set(), just for consistency and code style, but that's your call. :-)

  • Ah, I understand the problem with variable-length attributes, so things would break without rd_auth.

    So if variable-length attributes are being used with VLOC_USER, then sd_ble_gatts_value_set() must be called? If the characteristic value is large, is there any way to avoid the memcpy penalty in sd_ble_gatts_value_set()?

    Would it be OK to call sd_ble_gatts_value_set() with the correct p_len, but then to specify a NULL p_value (since the value is VLOC_USER)? That should satisfy the softdevice bookkeeping for variable-length attributes without actually unnecessarily copying data around?

  • Ah, I understand the problem with variable-length attributes, so things would break without rd_auth.

    We keep the actual (current) length and the maximum length in the stack memory space, the only thing that exists in app memory space is the value itself. When you add an attribute (characteristic, descriptor, whatever) you specify both current length and max length, and if you are using VLOC_USER you just need to make sure that the buffer you provide is at least max_len bytes long. However, if that attribute is variable length then of course you need to tell the stack if the length changes (this is not needed if the peer device writes to it changing the length, since at that point the stack already knows about the new length, it is only needed if you want to change it locally). Currently the only way to do this is via sd_ble_gatts_value_set().

    So if variable-length attributes are being used with VLOC_USER, then sd_ble_gatts_value_set() must be called? If the characteristic value is large, is there any way to avoid the memcpy penalty in sd_ble_gatts_value_set()?

    Yes, and no. This is unfortunate, we realize. Stay tuned for updates on this issue.

    Would it be OK to call sd_ble_gatts_value_set() with the correct p_len, but then to specify a NULL p_value (since the value is VLOC_USER)? That should satisfy the softdevice bookkeeping for variable-length attributes without actually unnecessarily copying data around?

    No, today sd_ble_gatts_value_set() only accepts valid pointers. If you call with a NULL pointer you will get an error back and no values will be changed inside the stack.

    Carles

  • So if variable-length attributes are being used with VLOC_USER, then sd_ble_gatts_value_set() must be called? If the characteristic value is large, is there any way to avoid the memcpy penalty in sd_ble_gatts_value_set()?

    For now please use the same pointer in the call to sd_ble_gatts_value_set() as the one you supplied when creating the attribute. This should work fine for your case and should not require any additional memory on the application side.

Related