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

Advertise on one channel at a time - app_timer problem

Hi DevZone

I want to make a little beacon app, that advertises on channel 37 then waits 700 ms, advertises on channel 38, waits 700 and advertises on channel 39. The below is what i have implemented, yet it doesn't work. It seems like the timeout handler is never called and therefor it is never starting advertising.

static void timers_init(void)
{
	uint32_t err_code;
	APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false);
	
	err_code = app_timer_create(&channel_timer_id, APP_TIMER_MODE_REPEATED, channel_timeout_handler);
	APP_ERROR_CHECK(err_code);	
}

My timeout handler which switches the channel_mode

static void channel_timeout_handler(void *p_context)
{
	SEGGER_RTT_printf(0, "Channel timeout handler %d\n, channel_mode");
	
	if(m_channel_mode == 37)
	{
		m_channel_mode = 38;
	}
	else if(m_channel_mode == 38)
	{
		m_channel_mode = 39;
	}
	else if(m_channel_mode == 39)
	{
		m_channel_mode = 37;
	}
	
	advertising_stop();
	advertising_init(m_channel_mode);
	advertising_start();
}

And here is my advertising_init where i set what channel it advertises on

static void advertising_init(uint8_t channel_mode)
{
	
		SEGGER_RTT_printf(0, "Advertising init\n");
    uint32_t      err_code;
    ble_advdata_t advdata;		
		ble_gap_adv_ch_mask_t ch_mask; // channel mask
		
	
	  uint8_t flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
	
		ble_uuid_t adv_uuids[] = 	
		{
				{BLE_CUSTOM_16UUID, 		BLE_UUID_TYPE_BLE}
		};

    // Build and set advertising data.
    memset(&advdata, 0, sizeof(advdata));
    advdata.name_type             = BLE_ADVDATA_NO_NAME;
		advdata.include_appearance		= false;
		advdata.flags 								= flags;
		
    err_code = ble_advdata_set(&advdata, NULL);
    APP_ERROR_CHECK(err_code);
		

		// Prepare the Manufacturer specific data packet
		ble_gap_addr_t gap_addr;
		sd_ble_gap_address_get(&gap_addr);
		ble_advdata_manuf_data_t manuf_data;
		
		manuf_data.company_identifier           = 0x028C; // 0x028C; // NanoLink Aps company ID
		//www.bluetooth.org/.../company-identifiers
		
		manuf_data.data.p_data									= gap_addr.addr;
		manuf_data.data.size                    = sizeof(gap_addr.addr);
		
    advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]);
    advdata.uuids_complete.p_uuids  = adv_uuids;
		
		advdata.p_manuf_specific_data   = &manuf_data;

    err_code = ble_advdata_set(&advdata, NULL);
    APP_ERROR_CHECK(err_code);
	
    // Initialize advertising parameters (used when starting advertising).
    memset(&m_adv_params, 0, sizeof(m_adv_params));	
		
		m_adv_params.type					= BLE_GAP_ADV_TYPE_ADV_NONCONN_IND;
		m_adv_params.p_peer_addr	= NULL;
		m_adv_params.fp					  = BLE_GAP_ADV_FP_ANY;
		m_adv_params.interval			= NON_CONNECTABLE_ADV_INTERVAL;
		m_adv_params.timeout			= 0;
		m_adv_params.p_whitelist	= NULL;
				
		SEGGER_RTT_printf(0, "channel mode %d\n", channel_mode);
		if(channel_mode == 37)
		{
			ch_mask.ch_37_off				 = 0;
			ch_mask.ch_38_off				 = 1;
			ch_mask.ch_39_off 			 = 1;
			m_adv_params.channel_mask = ch_mask;
		}
		else if(channel_mode == 38)
		{
			ch_mask.ch_37_off				 = 1;
			ch_mask.ch_38_off				 = 0;
			ch_mask.ch_39_off 			 = 1;
			m_adv_params.channel_mask = ch_mask;
		}
		else if(channel_mode == 39)
		{
			ch_mask.ch_37_off				 = 0;
			ch_mask.ch_38_off				 = 1;
			ch_mask.ch_39_off 			 = 1;
			m_adv_params.channel_mask = ch_mask;
		}
}

And my main looks like this:

int main(void)
{
	
    uint32_t err_code;
    // Initialize.
//  APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false); // Comment this when channel switching on
		timers_init(); // init timers
		//gap_params_init();
	
    err_code = bsp_init(BSP_INIT_LED, APP_TIMER_TICKS(100, APP_TIMER_PRESCALER), NULL);
    APP_ERROR_CHECK(err_code);
    ble_stack_init();
		//advertising_init(m_channel_mode); // 		

		err_code = app_timer_start(channel_timer_id, CHANNEL_TIMER_INTERVAL, NULL);
		APP_ERROR_CHECK(err_code);

	// Enter main loop.
    for (;; )
    {
        power_manage();
    }
}
  • Hi Mathias, my deep apology to dragging you into Radio Notification implementation. I've tried to improve my dynamic beacon example to change also Adv. channel and arrived to the same problem as indicated by you: there is no SD call to change just adv. channel map except sd_ble_gap_adv_start and if I do stop/start at on_ble_radio_active_evt it does the job (channel switching is visible on correct order) but timing is completely destroyed. So the "easy" solution would be to either use adv. timeout (which is in seconds so it's usable only for certain adv. intervals) or do the adv. by applicative timer (really cumbersome). I'm still looking to some more elegant solution with using radio_active event and editing adv. channel map directly in Soft Device RAM structures or registry (because it should be just static field lying somewhere and there is no memory protection...

  • ... between SD and APP RAM memory on ARM Cortex-M as far as I know). Hard to say if and when I succeed;) The proper solution would be to get new Soft Device API function by Nordic which would allow change of adv. channel map similar how you can change adv. and scan rsp. data or adv. address on the flight without need to stop/start the advertisement itself.

  • Hi Jan, no worries! I learned quite a bit about how the softdevice works, which will be useful :-)

    I will try and write to the support and propose them to implement that feature in a newer version of the softDevice. In the meantime i think i will go back to application timer and try to implement it that way.

    If you succeed to write the channel map directly in the RAM structure, please give me a heads up :-)

    Mathias

Related