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();
    }
}
  • Hello Mathias,

    Have you tried "ble_radio_notification" module? That might solve your problem without need to use timers, just alter data and channel through standard SD function calls after every adv. event so it's ready to use different channel (and data) on the very next event and keep time and other management to SoftDevice.

    Cheers Jan

    Edit 9-March-2017

    I've forgotten that there is no SD API function to just alter adv. channel map, this works only for adv./scan rsp. data and device (advertising) address. So the only way how to do it today is to stop/start advertising and that's not possible on radio notification event (to be precise it is but will destroy adv. interval timing). Would be great if Nordic adds such function to SD API in next Soft Device release but hard to say if such feature would be very useful. For the time being either application timer or hacking Soft Device RAM structures (and writing into them directly on radio notification event) is the way forward.

    Cheers Jan

  • Thanks for the response Jan!

    I have taken a look into ble_radio_notification and tried to implement it with this module.

    This is my code:

        void radio_notification_evt_handler(bool radio_evt)
    {
        if (radio_evt) 
    		{
            //radio going active
            //turn on LED
            LEDS_ON(BSP_LED_2_MASK);
        } 
    		else
    		{
    			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_set_data(&m_channel_mode, sizeof(m_channel_mode));
    }
    

    And i have replaced advertising_init with advertising_set_data

    static void advertising_set_data(const uint8_t* p_in_data, size_t dlen)
    {
    			SEGGER_RTT_printf(0, "Advertising set data\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;
    
    		if(*p_in_data == 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;
    		}
    		if(*p_in_data == 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;
    		}
    		if(*p_in_data == 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 is as follows:

        int main(void)
    {
        uint32_t err_code;
        // Initialize.
    		APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_OP_QUEUE_SIZE, false); 
    		err_code = bsp_init(BSP_INIT_LED, APP_TIMER_TICKS(100, APP_TIMER_PRESCALER), NULL);
        APP_ERROR_CHECK(err_code);
        ble_stack_init();
    		
    		err_code = ble_radio_notification_init(6, NRF_RADIO_NOTIFICATION_DISTANCE_5500US, radio_notification_evt_handler);
    		APP_ERROR_CHECK(err_code);
    			
    		advertising_start();
    
    	// Enter main loop.
        for (;;)
        {
            power_manage();
        }
    }
    

    But this doesn't work as well. I am not quite sure where it goes wrong...

  • So it seems like my radio_notification_evt_handler never gets called - and therefor advertising_set_data() is never called.

    As i understand the ble_radio_notification my event_handler would get called distance (5500µS in this case) before an radio event with ble_radio_notification_init.

    As far as i can read my IRQ priority should be low which is 6 on nRF52 defined in app_util_platform.h..

    Any suggestions what i should do?

  • Try with

    memcpy(&m_adv_params.channel_mask, &ch_mask, sizeof(ble_gap_adv_ch_mask_t));
    

    Also I would rather use the SoftDevice radio notification API directly, just take a look at how it is done in the ble_radio_notification.c file.

  • Hi Ole.

    I guess what you mean is that i should do like this:

    if(*p_in_data == 37)
    		{
    			ch_mask.ch_37_off				 = 0;
    			ch_mask.ch_38_off				 = 1;
    			ch_mask.ch_39_off 			 = 1;
    			memcpy(&m_adv_params.channel_mask, &ch_mask, sizeof(ble_gap_adv_ch_mask_t));
    		}
    		if(*p_in_data == 38)
    		{
    			ch_mask.ch_37_off				 = 1;
    			ch_mask.ch_38_off				 = 0;
    			ch_mask.ch_39_off 			 = 1;
    			memcpy(&m_adv_params.channel_mask, &ch_mask, sizeof(ble_gap_adv_ch_mask_t));
    
    		}
    		if(*p_in_data == 39)
    		{
    			ch_mask.ch_37_off				 = 0;
    			ch_mask.ch_38_off				 = 1;
    			ch_mask.ch_39_off 			 = 1;
    			memcpy(&m_adv_params.channel_mask, &ch_mask, sizeof(ble_gap_adv_ch_mask_t));
    		}
    }
    

    But that doesn't matter when my advertising_set_data is never called, because it never reaches the event_handler that calls advertising_set_data. I must be doing something wrong when initializing the radio notification?

Related