This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Advertising module ble_advertising_start() returns error code 0x7

While developing a set of C++ tools to simplify configuring and managing BLE on NRF52 chips, I've encountered an error code returned from the advertising module's ble_advertising_start function that is not listed as one of the possible return values for that function, 0x7 (NRF_ERROR_INVALID_PARAM).

Digging into advertising_start's implementation, I found the code to be thrown by sd_ble_gap_adv_set_configure.

My code for starting up the BLE stack is as follows:

void BluetoothLE::begin(){
	
	// Perform intialization procedure
	NRF_LOG_INFO("Beginning BLE initiliazation procedure...");
	
	bleStackInit();
	NRF_LOG_INFO("\tStack Initilized");
	
	gapParamsInit();
	NRF_LOG_INFO("\tGAP Parameters Established");
	
	gattInit();
	NRF_LOG_INFO("\tGATT Initilized");
	
	servicesInit();
	NRF_LOG_INFO("\tServices Initilized");
	
	advertisingInit();
	NRF_LOG_INFO("\tAdvertising Initilized");
	
	connParamsInit();
	NRF_LOG_INFO("\tConnection Parameters Established");
	
	// Begin advertising
	advertisingStart();
	NRF_LOG_INFO("--BLE Stack Operable--");
}

/**
 * Initializes the softdevice and sets up the BLE event interrupt.
 *
 * Derived from Nordic sample code.
 */
void BluetoothLE::bleStackInit(){
	ret_code_t errCode = nrf_sdh_enable_request();
	APP_ERROR_CHECK(errCode);
	
	// Get the start address of app RAM
	uint32_t ramStart = 0;
	errCode = nrf_sdh_ble_default_cfg_set(bleConf.bleConnCfgTag, &ramStart);
	APP_ERROR_CHECK(errCode);
	
	// Enable BLE stack.
    errCode = nrf_sdh_ble_enable(&ramStart);
    APP_ERROR_CHECK(errCode);
	
	// Register handler for BLE events
	NRF_SDH_BLE_OBSERVER(m_ble_observer, 3, bleEventHandler, NULL);
}

/**
 * Setup generic access profile ("GAP") for the device.
 *
 * This includes device name and other connection parameters
 */
void BluetoothLE::gapParamsInit(){
	ble_gap_conn_params_t   gapConnParams;
    ble_gap_conn_sec_mode_t secMode;
	ret_code_t errCode;

    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&secMode);
	
	errCode = sd_ble_gap_device_name_set(&secMode,
                                        (const uint8_t *)(bleConf.deviceName.data()),
                                        bleConf.deviceName.size());								
	APP_ERROR_CHECK(errCode);
							
	memset(&gapConnParams, 0, sizeof(gapConnParams));
	
	gapConnParams.min_conn_interval = bleConf.minConnInt;
    gapConnParams.max_conn_interval = bleConf.maxConnInt;
    gapConnParams.slave_latency     = bleConf.slaveLat;
    gapConnParams.conn_sup_timeout  = bleConf.connSupTimeout;
	
	errCode = sd_ble_gap_ppcp_set(&gapConnParams);
	APP_ERROR_CHECK(errCode);
}

void BluetoothLE::gattInit(){
	ret_code_t errCode = nrf_ble_gatt_init(&mGatt, NULL);
	APP_ERROR_CHECK(errCode);
}

void BluetoothLE::servicesInit(){
	uint32_t errCode;
	
	for(BleService s : services){ // BleService is a custom class representing a service and the necessary code to register one with the stack
		errCode = s.initService(); // See service initilization procedure below
		APP_ERROR_CHECK(errCode);
		serviceNrfUUIDs.push_back(s.getNrfUUID()); // Add uuid to list of implemented services
	}
}

BLE_ADVERTISING_DEF(mAdvertising); // Create a static C-styled object representing the advertising module
void BluetoothLE::advertisingInit(){
	ret_code_t errCode = NRF_SUCCESS;
	ble_advertising_init_t advInit;
	memset(&advInit, 0, sizeof(advInit));
	
	advInit.advdata.name_type          = BLE_ADVDATA_FULL_NAME;
    advInit.advdata.include_appearance = false;
    advInit.advdata.flags              = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;

    advInit.srdata.uuids_complete.uuid_cnt = serviceNrfUUIDs.size(); // Service UUIDs stored in a C++ vector, constructed at compile time
    advInit.srdata.uuids_complete.p_uuids  = serviceNrfUUIDs.data();

    advInit.config.ble_adv_fast_enabled  = true;
    advInit.config.ble_adv_fast_interval = bleConf.appAdvInterval;
    advInit.config.ble_adv_fast_timeout  = bleConf.appAdvDuration;
    //advInit.evt_handler = onAdvEvt;
	
    errCode = ble_advertising_init(&mAdvertising, &advInit);
	APP_ERROR_CHECK(errCode);

    ble_advertising_conn_cfg_tag_set(&mAdvertising, bleConf.bleConnCfgTag);
}

void BluetoothLE::connParamsInit(){
	ble_conn_params_init_t cpInit;
	
	memset(&cpInit, 0, sizeof(cpInit));

    cpInit.p_conn_params                  = NULL;
    cpInit.first_conn_params_update_delay = bleConf.firstConnParamsUpdateDelay;
    cpInit.next_conn_params_update_delay  = bleConf.nextConnParamsUpdateDelay;
    cpInit.max_conn_params_update_count   = bleConf.maxConnParamsUpdateCnt;
    cpInit.start_on_notify_cccd_handle    = BLE_GATT_HANDLE_INVALID;
    cpInit.disconnect_on_fail             = false;
	
	// TODO - I don't think I need these handlers
    //cpInit.evt_handler                    = on_conn_params_evt;
    //cpInit.error_handler                  = conn_params_error_handler;
	
	ret_code_t errCode = ble_conn_params_init(&cpInit);
	APP_ERROR_CHECK(errCode);
}

void BluetoothLE:: advertisingStart(){
	ret_code_t errCode =  ble_advertising_start(&mAdvertising, BLE_ADV_MODE_FAST); // XXX - Error code 7 tossed here
	APP_ERROR_CHECK(errCode);
}

Where "bleConf" is a reference to a custom structure containing configuration parameters that would normally be defined in macros. Defined as follows:

/**
 * Struct defining the various configuration parameters used in the initilization of the radio.
 *	The default values are those defined by Nordic and will work in the vast majority of cases
 */
 // Parameter                        Default Value                                Definition
typedef struct{
	int bleConnCfgTag              = 1;                                        // A tag identifying the SoftDevice BLE configuration
	int minConnInt                 = MSEC_TO_UNITS(100, UNIT_1_25_MS);         // Minimum acceptable connection interval (0.5 seconds)
	int maxConnInt                 = MSEC_TO_UNITS(200, UNIT_1_25_MS);         // Maximum acceptable connection interval (1 second)
	int slaveLat                   = 0;                                        // Slave latency
	int connSupTimeout             = MSEC_TO_UNITS(4000, UNIT_10_MS);          // Connection supervisory time-out (4 seconds)
	int firstConnParamsUpdateDelay = APP_TIMER_TICKS(20000);                   // Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (15 seconds)
	int nextConnParamsUpdateDelay  = APP_TIMER_TICKS(5000);                    // Time between each call to sd_ble_gap_conn_param_update after the first call (5 seconds)
	int maxConnParamsUpdateCnt     = 3;                                        // Number of attempts before giving up the connection parameter negotiation
	int appAdvInterval             = 64;                                       // The advertising interval (in units of 0.625 ms; this value corresponds to 40 ms).
	int appAdvDuration             = BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED;
	uint8_t advHandle              = BLE_GAP_ADV_SET_HANDLE_NOT_SET;
    std::string deviceName         = "BleDevice";                         // The advertised name of this device
} bleConf_T; 

And services are initialized via the following functions:

uint32_t BleService::initService(){
	
	uint32_t errCode;
	
	// Set connection to open. No security implemented for now.
	BLE_GAP_CONN_SEC_MODE_SET_OPEN(&securityAttr.read_perm);
	BLE_GAP_CONN_SEC_MODE_SET_OPEN(&securityAttr.write_perm);
	BLE_GAP_CONN_SEC_MODE_SET_OPEN(&securityAttr.cccd_write_perm);
	
	// Register UUID
	errCode = sd_ble_uuid_vs_add(&baseUUID, &(this->uuidType));
	VERIFY_SUCCESS(errCode);
	
	ble_uuid_t nrfUUID = getNrfUUID();
	errCode = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY, &nrfUUID, &serviceHandle);
	if(errCode != NRF_SUCCESS) // No point in continuing if the above line biffs it
		return errCode;
	
	// Register characteristics
	for(BleChar c : *chars){
		errCode = registerChar(c);
		if(errCode != NRF_SUCCESS)
			return errCode;
	}
	
	return NRF_SUCCESS;
}

 uint32_t BleService::registerChar(BleChar c){
	ble_gatts_char_md_t charMd;
    ble_gatts_attr_md_t cccdMd;
    ble_gatts_attr_t    attrCharValue;
    ble_uuid_t          nrfCharUUID;
    ble_gatts_attr_md_t attrMd;
	
	memset(&cccdMd, 0, sizeof(cccdMd));
	
	//  Read  operation on Cccd should be possible without authentication.
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccdMd.read_perm);
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccdMd.write_perm);
    
    cccdMd.vloc = BLE_GATTS_VLOC_STACK;
	
	memset(&charMd, 0, sizeof(charMd));
	
	if(c.isReadable)
		charMd.char_props.read = 1;
	if(c.isWritable)
		charMd.char_props.write = 1;
	if(c.isSubscribable)
		charMd.char_props.notify = 1;
	
	charMd.p_cccd_md         = &cccdMd; 
    charMd.p_char_user_desc  = NULL;
    charMd.p_char_pf         = NULL;
    charMd.p_user_desc_md    = NULL;
    charMd.p_sccd_md         = NULL;
	
	nrfCharUUID.type = uuidType;
	nrfCharUUID.uuid = c.UUID;
	
	memset(&attrMd, 0, sizeof(attrMd));
	
	attrMd.read_perm  = securityAttr.read_perm; 
    attrMd.write_perm = securityAttr.write_perm; 
    attrMd.vloc       = BLE_GATTS_VLOC_STACK;
    attrMd.rd_auth    = 0;
    attrMd.wr_auth    = 0;
    attrMd.vlen       = 0;
	
	memset(&attrCharValue, 0, sizeof(attrCharValue));
	
	attrCharValue.p_uuid    = &nrfCharUUID;
    attrCharValue.p_attr_md = &attrMd;
    attrCharValue.init_len  = sizeof(uint8_t);
    attrCharValue.init_offs = 0;
    attrCharValue.max_len   = 50; // TODO

	return sd_ble_gatts_characteristic_add(serviceHandle, &charMd,
														  &attrCharValue,
                                                          &c.handle);

 }

Are there any obvious issues that poke out that would cause the advertising module to provide malformed advertising data/params to sd_ble_gap_adv_set_configure? Is there some step or nuance I am missing?

As you can see, I have omitted several event handlers that I believe I do not need. I have tried implementing these to see if they fixed the problem, but their inclusion had no effect. 

  • Hi Aaron, 

    If you use BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE flags you shouldn't use BLE_GAP_ADV_TIMEOUT_GENERAL_UNLIMITED

    If you want to advertise without timeout, you should use BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE flags. 
    Please try and let us know if it works. 

Related