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

Error 0x3400 when calling sd_ble_gatts_hvx()

When I call sd_ble_gatts_hvx() it returns 0x3400 and I'm not sure why.  The error indicates the sum of these three errors:

NRF_ERROR_STK_BASE_NUM (0x3000)
NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM+0x400)
BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000)

so I think it's telling me "Invalid attribute type."  I'm not sure why?

set_temp() is called on a one second timer, but only if connected (tracked by the BLE_GAP_EVT_DISCONNECTED and BLE_GAP_EVT_CONNECTED events).

One thing I wasn't sure about was setting up the characteristic.  The char_props for indicate and notify are both set to false, but if I set either one of them to true I get an app exception on initialization.  I checked the blinky app, though, and the don't set those fields at all (meaning the memset() sets them to zero).

This is with SDK 17.0.2 and a DK board.


void rv_char_init(rv_service_t *service) {

  uint32_t err_code;


  ble_add_char_params_t add_char_params;

  memset(&add_char_params, 0, sizeof(add_char_params));
  add_char_params.uuid = BLE_UUID_RV_TEMP;
  add_char_params.uuid_type = service->uuid_type; /* BLE_UUID_TYPE_BLE (16 bit) or BLE_UUID_TYPE_VENDOR_BEGIN (128 bit) */
  add_char_params.init_len = sizeof(uint8_t);
  add_char_params.max_len = sizeof(uint8_t);
  add_char_params.char_props.read = true;
  add_char_params.char_props.write = true;
  add_char_params.char_props.notify = false;
  add_char_params.char_props.indicate = false;
  add_char_params.is_value_user = false;

  add_char_params.read_access = SEC_OPEN;
  add_char_params.write_access = SEC_OPEN;

                                                                                    
  err_code = characteristic_add(service->service_handle, &add_char_params, &service->temp_char_handle);
  APP_ERROR_CHECK(err_code);
}



ret_code_t set_temp(uint16_t conn_handle, rv_service_t * service, uint8_t newValue)
{
    ble_gatts_hvx_params_t params;
    uint16_t len = sizeof(newValue);
    ret_code_t err_code;

    memset(&params, 0, sizeof(params));
    params.type   = BLE_GATT_HVX_NOTIFICATION;
    params.handle = service->temp_char_handle.value_handle;
    params.p_data = &newValue;
    params.p_len  = &len;


    err_code = sd_ble_gatts_hvx(conn_handle, &params);
    return err_code;
}

Parents
  • I think I have something out of sync in the characteristic definition relating to CCCD.  I know from the docs permissions must agree between the two.

    The code below doesn't set CCCD metadata in the characteristic metadata meaning it's default (all zeros).  When it's turned on, I think it's supposed to be setting the security permissions in the CCCD block the same as in the attribute description, though it forces read permission to OPEN for some reason (this was taken from ble_srv_common.c which I copied/modified a little including adding the comments below).

    uint32_t help_characteristic_add(uint16_t service_handle,
        ble_add_char_params_t *p_char_props,
        ble_gatts_char_handles_t *p_char_handle) {
      ble_gatts_char_md_t char_md;
      ble_gatts_attr_t attr_char_value;
      ble_uuid_t char_uuid;
      ble_gatts_attr_md_t attr_md;
      ble_gatts_attr_md_t user_descr_attr_md;
      ble_gatts_attr_md_t cccd_md;
    
      /*
       * Set up the UUID with the service's default UUID type
       */
      if (p_char_props->uuid_type == 0) {
        char_uuid.type = BLE_UUID_TYPE_BLE;
      } else {
        char_uuid.type = p_char_props->uuid_type;
      }
      char_uuid.uuid = p_char_props->uuid;
    
    
      /*
       * Set up the attribute metadata. This is a structure holding permissions
       * and authorization levels required by characteristic value attributes.
       * It also holds information on whether or not the characteristic value is
       * of variable length and where in memory it is stored.
       */
      memset(&attr_md, 0, sizeof(ble_gatts_attr_md_t));
      set_security_req(p_char_props->read_access, &attr_md.read_perm);
      set_security_req(p_char_props->write_access, &attr_md.write_perm);
      attr_md.rd_auth = (p_char_props->is_defered_read ? 1 : 0);
      attr_md.wr_auth = (p_char_props->is_defered_write ? 1 : 0);
      attr_md.vlen = (p_char_props->is_var_len ? 1 : 0);
      attr_md.vloc = (p_char_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
    
      /*
       * Set up the characteristic metadata.  This is a structure holding the
       * value properties of the characteristic value. It also holds metadata
       * of the CCCD and possibly other kinds of descriptors.
       */
      memset(&char_md, 0, sizeof(ble_gatts_char_md_t));
    
    #if 0
      /*
       * Note: if indicate or notify is set there must be a CCCD
       */
      if ((p_char_props->char_props.notify == 1) || (p_char_props->char_props.indicate == 1)) {
    
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        /* Follow write permission as requested */
        set_security_req(p_char_props->cccd_write_access, &cccd_md.write_perm);
    
        /* Force read permission, since it is implied by notify and indicate */
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
    
        cccd_md.vloc = BLE_GATTS_VLOC_STACK;
        char_md.p_cccd_md = &cccd_md;
      }
    #endif
    
      char_md.char_props = p_char_props->char_props;
      char_md.char_ext_props = p_char_props->char_ext_props;
    
      /*
       * Set up the value descriptor. This structure holds the actual value of
       * the characteristic (like the temperature value). It also holds the
       * maximum length of the value (it might e.g. be four bytes long) and
       * it's UUID.
       */
      memset(&attr_char_value, 0, sizeof(ble_gatts_attr_t));
      attr_char_value.p_uuid = &char_uuid;
      attr_char_value.p_attr_md = &attr_md;
      attr_char_value.max_len = p_char_props->max_len;
      if (p_char_props->p_init_value != NULL) {
        attr_char_value.init_len = p_char_props->init_len;
        attr_char_value.p_value = p_char_props->p_init_value;
      }
    
      /*
       * If the caller has provided a user description for this
       * characteristic, add it
       */
      if (p_char_props->p_user_descr != NULL) {
        memset(&user_descr_attr_md, 0, sizeof(ble_gatts_attr_md_t));
        char_md.char_user_desc_max_size = p_char_props->p_user_descr->max_size;
        char_md.char_user_desc_size = p_char_props->p_user_descr->size;
        char_md.p_char_user_desc = p_char_props->p_user_descr->p_char_user_desc;
    
        char_md.p_user_desc_md = &user_descr_attr_md;
    
        set_security_req(p_char_props->p_user_descr->read_access, &user_descr_attr_md.read_perm);
        set_security_req(p_char_props->p_user_descr->write_access, &user_descr_attr_md.write_perm);
    
        user_descr_attr_md.rd_auth = (p_char_props->p_user_descr->is_defered_read ? 1 : 0);
        user_descr_attr_md.wr_auth = (p_char_props->p_user_descr->is_defered_write ? 1 : 0);
        user_descr_attr_md.vlen = (p_char_props->p_user_descr->is_var_len ? 1 : 0);
        user_descr_attr_md.vloc = (p_char_props->p_user_descr->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
      }
    
      /*
       * If the user has provided a presentation format, add it
       */
      if (p_char_props->p_presentation_format != NULL) {
        char_md.p_char_pf = p_char_props->p_presentation_format;
      }
    
      /*
       * Call the SoftDevice system call to add the characteristic
       */
      return sd_ble_gatts_characteristic_add(service_handle,
          &char_md,
          &attr_char_value,
          p_char_handle);
    }

Reply
  • I think I have something out of sync in the characteristic definition relating to CCCD.  I know from the docs permissions must agree between the two.

    The code below doesn't set CCCD metadata in the characteristic metadata meaning it's default (all zeros).  When it's turned on, I think it's supposed to be setting the security permissions in the CCCD block the same as in the attribute description, though it forces read permission to OPEN for some reason (this was taken from ble_srv_common.c which I copied/modified a little including adding the comments below).

    uint32_t help_characteristic_add(uint16_t service_handle,
        ble_add_char_params_t *p_char_props,
        ble_gatts_char_handles_t *p_char_handle) {
      ble_gatts_char_md_t char_md;
      ble_gatts_attr_t attr_char_value;
      ble_uuid_t char_uuid;
      ble_gatts_attr_md_t attr_md;
      ble_gatts_attr_md_t user_descr_attr_md;
      ble_gatts_attr_md_t cccd_md;
    
      /*
       * Set up the UUID with the service's default UUID type
       */
      if (p_char_props->uuid_type == 0) {
        char_uuid.type = BLE_UUID_TYPE_BLE;
      } else {
        char_uuid.type = p_char_props->uuid_type;
      }
      char_uuid.uuid = p_char_props->uuid;
    
    
      /*
       * Set up the attribute metadata. This is a structure holding permissions
       * and authorization levels required by characteristic value attributes.
       * It also holds information on whether or not the characteristic value is
       * of variable length and where in memory it is stored.
       */
      memset(&attr_md, 0, sizeof(ble_gatts_attr_md_t));
      set_security_req(p_char_props->read_access, &attr_md.read_perm);
      set_security_req(p_char_props->write_access, &attr_md.write_perm);
      attr_md.rd_auth = (p_char_props->is_defered_read ? 1 : 0);
      attr_md.wr_auth = (p_char_props->is_defered_write ? 1 : 0);
      attr_md.vlen = (p_char_props->is_var_len ? 1 : 0);
      attr_md.vloc = (p_char_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
    
      /*
       * Set up the characteristic metadata.  This is a structure holding the
       * value properties of the characteristic value. It also holds metadata
       * of the CCCD and possibly other kinds of descriptors.
       */
      memset(&char_md, 0, sizeof(ble_gatts_char_md_t));
    
    #if 0
      /*
       * Note: if indicate or notify is set there must be a CCCD
       */
      if ((p_char_props->char_props.notify == 1) || (p_char_props->char_props.indicate == 1)) {
    
        memset(&cccd_md, 0, sizeof(cccd_md));
    
        /* Follow write permission as requested */
        set_security_req(p_char_props->cccd_write_access, &cccd_md.write_perm);
    
        /* Force read permission, since it is implied by notify and indicate */
        BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
    
        cccd_md.vloc = BLE_GATTS_VLOC_STACK;
        char_md.p_cccd_md = &cccd_md;
      }
    #endif
    
      char_md.char_props = p_char_props->char_props;
      char_md.char_ext_props = p_char_props->char_ext_props;
    
      /*
       * Set up the value descriptor. This structure holds the actual value of
       * the characteristic (like the temperature value). It also holds the
       * maximum length of the value (it might e.g. be four bytes long) and
       * it's UUID.
       */
      memset(&attr_char_value, 0, sizeof(ble_gatts_attr_t));
      attr_char_value.p_uuid = &char_uuid;
      attr_char_value.p_attr_md = &attr_md;
      attr_char_value.max_len = p_char_props->max_len;
      if (p_char_props->p_init_value != NULL) {
        attr_char_value.init_len = p_char_props->init_len;
        attr_char_value.p_value = p_char_props->p_init_value;
      }
    
      /*
       * If the caller has provided a user description for this
       * characteristic, add it
       */
      if (p_char_props->p_user_descr != NULL) {
        memset(&user_descr_attr_md, 0, sizeof(ble_gatts_attr_md_t));
        char_md.char_user_desc_max_size = p_char_props->p_user_descr->max_size;
        char_md.char_user_desc_size = p_char_props->p_user_descr->size;
        char_md.p_char_user_desc = p_char_props->p_user_descr->p_char_user_desc;
    
        char_md.p_user_desc_md = &user_descr_attr_md;
    
        set_security_req(p_char_props->p_user_descr->read_access, &user_descr_attr_md.read_perm);
        set_security_req(p_char_props->p_user_descr->write_access, &user_descr_attr_md.write_perm);
    
        user_descr_attr_md.rd_auth = (p_char_props->p_user_descr->is_defered_read ? 1 : 0);
        user_descr_attr_md.wr_auth = (p_char_props->p_user_descr->is_defered_write ? 1 : 0);
        user_descr_attr_md.vlen = (p_char_props->p_user_descr->is_var_len ? 1 : 0);
        user_descr_attr_md.vloc = (p_char_props->p_user_descr->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
      }
    
      /*
       * If the user has provided a presentation format, add it
       */
      if (p_char_props->p_presentation_format != NULL) {
        char_md.p_char_pf = p_char_props->p_presentation_format;
      }
    
      /*
       * Call the SoftDevice system call to add the characteristic
       */
      return sd_ble_gatts_characteristic_add(service_handle,
          &char_md,
          &attr_char_value,
          p_char_handle);
    }

Children
Related