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

sd_ble_gatts_characteristic_add returns NRF_ERROR_INVALID_PARAM

I am getting an NRF_ERROR_INVALID_PARAM when calling sd_ble_gatts_characteristic_add. This is the 12th characteristic added and follows the same general style of numerous other characteristics. The documentation mentions constraints but does not explain what those are.

Here is my code

static uint32_t button_status_char_add(ble_service_t * p_service, const ble_service_init_t * p_service_init) { /**@snippet [Adding proprietary characteristic to S110 SoftDevice] */ ble_gatts_char_md_t char_md; ble_gatts_attr_md_t cccd_md; ble_gatts_attr_t attr_char_value; ble_uuid_t ble_uuid; ble_gatts_attr_md_t attr_md;

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

BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.write_perm);

cccd_md.vloc = BLE_GATTS_VLOC_USER;

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

char_md.char_props.notify = 1;
char_md.char_props.read = 1;
char_md.p_char_user_desc  = NULL;
char_md.p_char_pf         = NULL;
char_md.p_user_desc_md    = NULL;
char_md.p_cccd_md         = &cccd_md;
char_md.p_sccd_md         = NULL;

ble_uuid.type             = p_service->uuid_type;
ble_uuid.uuid             = BLE_UUID_SERVICE_BUTTON_STATUS;

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

BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);

attr_md.vloc              = BLE_GATTS_VLOC_USER;
attr_md.rd_auth           = 0;
attr_md.wr_auth           = 0;
attr_md.vlen              = 0;

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

attr_char_value.p_uuid    = &ble_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len  = sizeof(ble_service_button_status_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len   = sizeof(ble_service_button_status_t);
attr_char_value.p_value = (uint8_t*) &(p_service->button_status);

return sd_ble_gatts_characteristic_add(p_service->service_handle,
                                       &char_md,
                                       &attr_char_value,
                                       &p_service->button_status_handles);
/**@snippet [Adding proprietary characteristic to S110 SoftDevice] */

}

  • I discovered the cause of the problem!

    The issue was with the VLOC setting for the cccd_md. I did not intent to set it to BLE_GATTS_VLOC_USER, it should be BLE_GATTS_VLOC_STACK.

    I don't really understand why there is a vloc value for the ble_gatts_attr_md_t since there is no p_value to allow the user to provide the location for the data.

    /@brief Attribute metadata. */ typedef struct { ble_gap_conn_sec_mode_t read_perm; /< Read permissions. */ ble_gap_conn_sec_mode_t write_perm; /< Write permissions. */ uint8_t vlen :1; /< Variable length attribute. / uint8_t vloc :2; /**< Value location, see @ref BLE_GATTS_VLOCS./ uint8_t rd_auth :1; /< Read Authorization and value will be requested from the application on every read operation. */ uint8_t wr_auth :1; /< Write Authorization will be requested from the application on every Write Request operation (but not Write Command). */ } ble_gatts_attr_md_t;

  • Hi there,

    I don't really understand why there is a vloc value for the ble_gatts_attr_md_t since there is no p_value to allow the user to provide the location for the data.

    This is because ble_gatts_attr_md_t is a structure shared between user and system attributes, so some fields (like vloc for CCCDs) are not always freely settable, depending on the limitations of the particular system attribute.

    If you wanted to have a characteristic value in user memory you would then set the "vloc" bit to 1 in ble_gatts_attr_t :: p_attr_md and provide the pointer in ble_gatts_attr_t :: p_value.

    Regards,

    Carles

Related