Hi
I'm trying to integrate the iBeacon and Eddystone protocol together. For this I'm using the timeslot to advertise the packets simultaneously. I have successfully integrated the ibeacon and eddystone together and it is working fine.
But the issue comes when i try to update the advertising interval the radio events are getting blocked. Always it advertises for few seconds and then error pops up. While integrating i have fixed a value for the advertising interval and successfully integrated it but when i change the values of advertising interval the issue arises.
The err_code says ERROR 17 [NRF_ERROR_BUSY]
I do have some questions reg the time-slot parameters
1. while requesting the next event or the earliest does the timeout_us event and length_us have any dependencies on advertising interval? Do we need to change those as per adv interval?
2. using the NRF_LOG_INFO has been an issue with the timeslot. ERROR 17 [NRF_ERROR_BUSY] .
I have attached my code, could you please let me know if i'm doing anything wrong
thanks
static enum packet_t packet = IBEACON;
int pdu_count = 1;
uint32_t m_request_earliest_beacon(enum NRF_RADIO_PRIORITY priority)
{
m_adv.timeslot_request.request_type = NRF_RADIO_REQ_TYPE_EARLIEST;
m_adv.timeslot_request.params.earliest.hfclk = NRF_RADIO_HFCLK_CFG_NO_GUARANTEE;
m_adv.timeslot_request.params.earliest.priority = priority;
m_adv.timeslot_request.params.earliest.length_us = SLOT_LENGTH;
m_adv.timeslot_request.params.earliest.timeout_us = 1000UL;
return sd_radio_request(&m_adv.timeslot_request);
}
nrf_radio_request_t * m_configure_next_event_beacon(uint32_t interval_us)
{
m_adv.timeslot_request.request_type = NRF_RADIO_REQ_TYPE_NORMAL;
m_adv.timeslot_request.params.normal.hfclk = NRF_RADIO_HFCLK_CFG_NO_GUARANTEE;
m_adv.timeslot_request.params.normal.priority = NRF_RADIO_PRIORITY_HIGH;
m_adv.timeslot_request.params.normal.distance_us = interval_us * 1000; //to ms
m_adv.timeslot_request.params.normal.length_us = SLOT_LENGTH;
return &m_adv.timeslot_request;
}
uint32_t m_request_normal(void)
{
m_adv.timeslot_request.request_type = NRF_RADIO_REQ_TYPE_NORMAL;
m_adv.timeslot_request.params.normal.hfclk = NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED;
m_adv.timeslot_request.params.normal.priority = NRF_RADIO_PRIORITY_NORMAL;
m_adv.timeslot_request.params.normal.distance_us = _ibeacon_ts.adv_interval * 1000 * 2;
m_adv.timeslot_request.params.normal.length_us = SLOT_LENGTH;
return sd_radio_request(&m_adv.timeslot_request);
}
/* common config */
static void m_configure_radio()
{
NRF_RADIO->POWER = 1;
NRF_RADIO->PCNF0 = (((1UL) << RADIO_PCNF0_S0LEN_Pos ) & RADIO_PCNF0_S0LEN_Msk)
| (((2UL) << RADIO_PCNF0_S1LEN_Pos ) & RADIO_PCNF0_S1LEN_Msk)
| (((6UL) << RADIO_PCNF0_LFLEN_Pos ) & RADIO_PCNF0_LFLEN_Msk);
NRF_RADIO->PCNF1 = (((RADIO_PCNF1_ENDIAN_Little) << RADIO_PCNF1_ENDIAN_Pos ) & RADIO_PCNF1_ENDIAN_Msk)
| (((3UL) << RADIO_PCNF1_BALEN_Pos ) & RADIO_PCNF1_BALEN_Msk)
| (((0UL) << RADIO_PCNF1_STATLEN_Pos ) & RADIO_PCNF1_STATLEN_Msk)
| ((((uint32_t) 37) << RADIO_PCNF1_MAXLEN_Pos ) & RADIO_PCNF1_MAXLEN_Msk)
| ((RADIO_PCNF1_WHITEEN_Enabled << RADIO_PCNF1_WHITEEN_Pos ) & RADIO_PCNF1_WHITEEN_Msk);
NRF_RADIO->CRCCNF = (((RADIO_CRCCNF_SKIPADDR_Skip) << RADIO_CRCCNF_SKIPADDR_Pos ) & RADIO_CRCCNF_SKIPADDR_Msk)
| (((RADIO_CRCCNF_LEN_Three) << RADIO_CRCCNF_LEN_Pos ) & RADIO_CRCCNF_LEN_Msk);
NRF_RADIO->CRCPOLY = 0x0000065b;
NRF_RADIO->RXADDRESSES = ((RADIO_RXADDRESSES_ADDR0_Enabled) << RADIO_RXADDRESSES_ADDR0_Pos);
NRF_RADIO->SHORTS = ((1 << RADIO_SHORTS_READY_START_Pos) | (1 << RADIO_SHORTS_END_DISABLE_Pos));
NRF_RADIO->MODE = ((RADIO_MODE_MODE_Ble_1Mbit) << RADIO_MODE_MODE_Pos ) & RADIO_MODE_MODE_Msk;
NRF_RADIO->TIFS = 150;
NRF_RADIO->INTENSET = (1 << RADIO_INTENSET_DISABLED_Pos);
NRF_RADIO->PREFIX0 = 0x0000008e; //access_addr[3]
NRF_RADIO->BASE0 = 0x89bed600; //access_addr[0:3]
NRF_RADIO->CRCINIT = 0x00555555;
NVIC_DisableIRQ(RADIO_IRQn);
NVIC_EnableIRQ(RADIO_IRQn);
}
static void periph_radio_evts_clear(void)
{
NRF_RADIO->EVENTS_ADDRESS = 0;
NRF_RADIO->EVENTS_BCMATCH = 0;
NRF_RADIO->EVENTS_DEVMATCH = 0;
NRF_RADIO->EVENTS_DEVMISS = 0;
NRF_RADIO->EVENTS_DISABLED = 0;
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->EVENTS_PAYLOAD = 0;
NRF_RADIO->EVENTS_READY = 0;
NRF_RADIO->EVENTS_RSSIEND = 0;
}
static void m_handle_start(uint8_t ch1,uint8_t ch2)
{
// Configure TX_EN on TIMER EVENT_0
NRF_PPI->CH[ch1].TEP = (uint32_t)(&NRF_RADIO->TASKS_TXEN);
NRF_PPI->CH[ch1].EEP = (uint32_t)(&NRF_TIMER0->EVENTS_COMPARE[ch2]);
NRF_PPI->CHENSET = (1 << ch1);
// Configure and initiate radio
m_configure_radio();
periph_radio_evts_clear();
NRF_RADIO->TASKS_DISABLE = 1;
}
static void m_set_adv_ch(uint32_t channel)
{
if (channel == ADV_CHANNEL_37)
{
NRF_RADIO->FREQUENCY = FREQ_ADV_CHANNEL_37;
NRF_RADIO->DATAWHITEIV = ADV_CHANNEL_37;
}
if (channel == ADV_CHANNEL_38)
{
NRF_RADIO->FREQUENCY = FREQ_ADV_CHANNEL_38;
NRF_RADIO->DATAWHITEIV = ADV_CHANNEL_38;
}
if (channel == ADV_CHANNEL_39)
{
NRF_RADIO->FREQUENCY = FREQ_ADV_CHANNEL_39;
NRF_RADIO->DATAWHITEIV = ADV_CHANNEL_39;
}
}
static void m_handle_radio_disabled(enum mode_t mode, uint8_t ch)
{
switch (mode)
{
case ADV_RX_CH37:
m_set_adv_ch(ADV_CHANNEL_37);
NRF_RADIO->TASKS_TXEN = 1;
break;
case ADV_RX_CH38:
m_set_adv_ch(ADV_CHANNEL_38);
NRF_TIMER0->TASKS_CLEAR = 1;
NRF_TIMER0->CC[ch] = 400;
break;
case ADV_RX_CH39:
m_set_adv_ch(ADV_CHANNEL_39);
NRF_TIMER0->TASKS_CLEAR = 1;
NRF_TIMER0->CC[ch] = 400;
break;
default:
break;
}
}
void get_eddystone_packet()
{
NRF_RADIO->PACKETPTR = (uint32_t) m_get_adv_packet_es_uid();
}
}
static nrf_radio_signal_callback_return_param_t * m_timeslot_callback(uint8_t signal_type)
{
static nrf_radio_signal_callback_return_param_t signal_callback_return_param;
static enum mode_t mode;
signal_callback_return_param.params.request.p_next = NULL;
signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE;
switch (signal_type)
{
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_START:
NRF_LOG_INFO("i'am in SIGNAL_TYPE_START");
switch (packet)
{
case IBEACON:
m_handle_start(7,0);
break;
case EDDYSTONE :
m_handle_start(8,1);
break;
}
mode = ADV_INIT;
mode++;
break;
case NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO:
switch (packet)
{
case IBEACON:
if (NRF_RADIO->EVENTS_DISABLED == 1)
{
NRF_RADIO->EVENTS_DISABLED = 0;
m_handle_radio_disabled(mode,0);
mode++;
NRF_RADIO->PACKETPTR = (uint32_t) m_get_adv_packet_ibeacon();
if (mode == ADV_DONE)
{
NRF_LOG_INFO("i'am in ibeacon TYPE_RADIO");
NRF_PPI->CHENCLR = (1 << 7);
packet = EDDYSTONE;
if (m_adv.is_running)
{
signal_callback_return_param.params.request.p_next = m_configure_next_event_beacon(_ibeacon_ts.adv_interval);
signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
}
else
{
signal_callback_return_param.callback_action =NRF_RADIO_SIGNAL_CALLBACK_ACTION_END;
}
}
}
break;
case EDDYSTONE:
if (NRF_RADIO->EVENTS_DISABLED == 1)
{
NRF_RADIO->EVENTS_DISABLED = 0;
m_handle_radio_disabled(mode,1);
mode++;
get_eddystone_packet();
if (mode == ADV_DONE)
{
NRF_LOG_INFO("i'am in eddystone TYPE_RADIO \n");
NRF_PPI->CHENCLR = (1 << 8);
packet = IBEACON;
if (m_adv.is_running)
{
signal_callback_return_param.params.request.p_next = m_configure_next_event_beacon(_eddystone.adv_interval);
signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END;
NRF_RADIO->INTENSET = (0 << RADIO_INTENSET_DISABLED_Pos);
}
else
{
signal_callback_return_param.callback_action = NRF_RADIO_SIGNAL_CALLBACK_ACTION_END;
}
}
}
break;
}
break;
default:
if (_ibeacon_ts.error_handler != NULL)
{
_ibeacon_ts.error_handler(NRF_ERROR_INVALID_STATE);
}
if (_eddystone.error_handler != NULL)
{
_eddystone.error_handler(NRF_ERROR_INVALID_STATE);
}
break;
}
return (&signal_callback_return_param);
}
void app_beacon_sd_evt_signal_handler(uint32_t event)
{
uint32_t err_code;
NRF_LOG_INFO("app_beacon_on_sys_evt: %d\r\n", event);
switch (event)
{
case NRF_EVT_RADIO_SESSION_IDLE:
NRF_LOG_INFO("Radio IDLE");
if (m_adv.is_running)
{
err_code = sd_radio_session_close();
APP_ERROR_CHECK(err_code);
if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
{
_ibeacon_ts.error_handler(err_code);
}
m_adv.is_running = false;
}
break;
case NRF_EVT_RADIO_SESSION_CLOSED:
NRF_LOG_INFO("Radio closed");
if (m_adv.keep_running)
{
_beacon_advertising_start();
}
break;
case NRF_EVT_RADIO_BLOCKED:
NRF_LOG_INFO("Radio blocked");
err_code = sd_radio_session_close();
APP_ERROR_CHECK(err_code);
uint32_t err_code = sd_radio_session_open(m_timeslot_callback);
NRF_LOG_INFO("Timeslot session opened");
if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
{
_ibeacon_ts.error_handler(err_code);
}
// TODO: A proper solution should try again in <block_count> * m_beacon.adv_interval
err_code = m_request_earliest_beacon(NRF_RADIO_PRIORITY_HIGH);
if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
{
_ibeacon_ts.error_handler(err_code);
}
break;
case NRF_EVT_RADIO_CANCELED: // Fall through
NRF_LOG_INFO("Timeslot CANCELED");
if (m_adv.keep_running)
{
// TODO: A proper solution should try again in <block_count> * m_beacon.adv_interval
// err_code = m_request_earliest(NRF_RADIO_PRIORITY_HIGH);
err_code = m_request_normal();
if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
{
_ibeacon_ts.error_handler(err_code);
}
}
break;
default:
NRF_LOG_INFO("Radio default");
break;
}
}
void _beacon_advertising_start(void)
{
m_adv.keep_running = true;
m_adv.is_running = true;
uint32_t err_code = sd_radio_session_open(m_timeslot_callback);
NRF_LOG_INFO("Timeslot session opened");
if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
{
_ibeacon_ts.error_handler(err_code);
}
err_code = m_request_earliest_beacon(NRF_RADIO_PRIORITY_HIGH);
NRF_LOG_INFO("Timeslot request earliest");
if ((err_code != NRF_SUCCESS) && (_ibeacon_ts.error_handler != NULL) && (_eddystone.error_handler != NULL))
{
_ibeacon_ts.error_handler(err_code);
}
}
void _beacon_advertising_stop(void)
{
m_adv.keep_running = false;
}