Hi all,
I have a problem with 802.15.4 association in beaconned PAN. Basically I have two devices, PAN coordinator and an FFD. FFD is able to find the coordinator (throught scan) and tryies to associate with it. The association is successful only if I configure PAN coordinator with beacon_order == superframe_order. When beacon_order > superframe_order the association is unsuccesfull with error code MAC_NO_ACK. What may be the cause of association failure in case when beacon_order > superframe_order ?
Below is the code of coordinator and FFD. This is the vrsion that can associate FFD with coordinator successfuly. The only change that makes it to fail to associate is to change superframe_order parameter to something less than 7.
Coordinator:
#include "config.h"
#include "ral_irq_handlers.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_delay.h"
#include "app_usbd.h"
#include "bsp.h"
#include "nrf_drv_clock.h"
#include "mac_mlme_pib.h"
#include "mac_mlme_reset.h"
#include "mac_mlme_start.h"
#include "mac_mlme_associate.h"
#include "mac_mcps_data.h"
#include "sys_memory_manager.h"
#include "sys_init.h"
#include "sys_task_scheduler.h"
#include "boards.h"
static uint8_t __ALIGN(ALIGN_VALUE) m_heap[CONFIG_POOL_SIZE];
static const size_t m_heap_size = CONFIG_POOL_SIZE;
static void out_of_memory_callback(const void * data);
static void memory_freed_callback(const void * data);
uint16_t last_addr = 0xFFFF;
static sys_event_desc_t m_out_of_memory_desc =
{
.event_id = SYS_EVENT_OUT_OF_MEMORY,
.callback = out_of_memory_callback,
};
static sys_event_desc_t m_memory_freed_desc =
{
.event_id = SYS_EVENT_MEMORY_FREED,
.callback = memory_freed_callback,
};
void mcps_data_ind(mcps_data_ind_t * p_ind)
{
bool addresses_match = p_ind->dst_pan_id == CONFIG_PAN_ID &&
p_ind->dst_addr_mode == MAC_ADDR_SHORT &&
p_ind->dst_addr.short_address == CONFIG_DEVICE_SHORT_ADDRESS &&
p_ind->src_pan_id == CONFIG_PAN_ID &&
p_ind->src_addr_mode == MAC_ADDR_SHORT;
NRF_LOG_INFO("received success from %x", p_ind->src_addr.short_address);
if (addresses_match && p_ind->msdu_length > 0)
{
if (bsp_board_led_state_get(CONFIG_DOWNSTREAM_PIN))
bsp_board_led_off(CONFIG_DOWNSTREAM_PIN);
else
bsp_board_led_on(CONFIG_DOWNSTREAM_PIN);
}
mac_mem_msdu_free(&p_ind->msdu);
}
static void mcps_data_conf(mcps_data_conf_t * conf)
{
if (conf->status == MAC_SUCCESS)
{
NRF_LOG_INFO("send success");
}
else
{
NRF_LOG_INFO("send failed");
}
bsp_board_led_off(CONFIG_UPSTREAM_PIN);
}
static void send_data()
{
static uint8_t m_radio_tx_buffer[PHY_MAX_PACKET_SIZE + MAC_MAX_MHR_SIZE];
static mcps_data_req_t m_data_req;
NRF_LOG_INFO("send_data");
if (bsp_board_led_state_get(CONFIG_UPSTREAM_PIN)) {
NRF_LOG_INFO("in progress");
return;
}
m_radio_tx_buffer[MAC_MAX_MHR_SIZE] = 'x';
m_data_req.dst_addr_mode = MAC_ADDR_SHORT;
m_data_req.dst_addr.short_address = last_addr;
m_data_req.dst_pan_id = CONFIG_PAN_ID;
m_data_req.src_addr_mode = MAC_ADDR_SHORT;
m_data_req.msdu = (uint8_t *)&m_radio_tx_buffer[MAC_MAX_MHR_SIZE];
m_data_req.msdu_length = 1;
m_data_req.msdu_handle++;
m_data_req.tx_options.ack = true;
m_data_req.tx_options.gts = false;
m_data_req.tx_options.indirect = true;
mcps_data_req(&m_data_req, mcps_data_conf);
bsp_board_led_on(CONFIG_UPSTREAM_PIN);
}
static void out_of_memory_callback(const void * data)
{
bsp_board_led_on(CONFIG_ERROR_PIN);
}
static void memory_freed_callback(const void * data)
{
bsp_board_led_off(CONFIG_ERROR_PIN);
}
static void short_addr_set()
{
const pib_id_t pib_id =
{
.mlme_id = MAC_SHORT_ADDRESS,
};
uint16_t address = CONFIG_DEVICE_SHORT_ADDRESS;
mac_status_t result = mlme_set(pib_id, 0, &address);
NRF_LOG_INFO("short_addr_set: %d", result);
}
static void ext_addr_set()
{
const pib_id_t pib_id =
{
.mlme_id = MAC_EXTENDED_ADDRESS,
};
uint64_t address = CONFIG_IEEE_ADDRESS + CONFIG_DEVICE_SHORT_ADDRESS;
mac_status_t result = mlme_set(pib_id, 0, &address);
NRF_LOG_INFO("ext_addr_set: %d", result);
}
static void association_permit_set()
{
const pib_id_t pib_id =
{
.mlme_id = MAC_ASSOCIATION_PERMIT,
};
uint8_t permit = 1;
mac_status_t result = mlme_set(pib_id, 0, &permit);
NRF_LOG_INFO("association_permit_set: %d", result);
}
static void rx_on_idle_set()
{
const pib_id_t pib_id =
{
.mlme_id = MAC_RX_ON_WHEN_IDLE,
};
uint8_t rx_on_idle = 1;
mac_status_t result = mlme_set(pib_id, 0, &rx_on_idle);
NRF_LOG_INFO("rx_on_idle_set: %d", result);
}
static void mlme_start_conf_cb(mlme_start_conf_t * conf)
{
NRF_LOG_INFO("mlme_start_conf %d", conf->status);
if (conf->status == MAC_SUCCESS)
bsp_board_led_on(CONFIG_INIT_DONE_PIN);
else
bsp_board_led_off(CONFIG_INIT_DONE_PIN);
}
void mlme_reset_conf_cb(mlme_reset_conf_t *conf)
{
NRF_LOG_INFO("mlme_reset_conf: %d", conf->status);
if (conf->status == MAC_SUCCESS)
bsp_board_led_on(CONFIG_INIT_DONE_PIN);
else {
bsp_board_led_off(CONFIG_INIT_DONE_PIN);
return;
}
short_addr_set();
ext_addr_set();
association_permit_set();
rx_on_idle_set();
static mlme_start_req_t req = {
.battery_life_extension = false,
.beacon_order = 7,
.coord_realignment = false,
.logical_channel = 15,
.pan_coordinator = true,
.pan_id = CONFIG_PAN_ID,
.start_time = 0,
.superframe_order = 7
};
mlme_start_req(&req, mlme_start_conf_cb);
}
/**@brief Application task initialization for GPIO test.
*/
static void app_task_init(void)
{
sys_init(m_heap, m_heap_size);
sys_event_subscribe(&m_out_of_memory_desc);
sys_event_subscribe(&m_memory_freed_desc);
static mlme_reset_req_t req = {
.set_default_pib = true
};
mlme_reset_req(&req, mlme_reset_conf_cb);
}
static mlme_associate_resp_t associate_resp;
bool send_resp = false;
void mlme_associate_ind(mlme_associate_ind_t * ind)
{
NRF_LOG_INFO("mlme_associate_ind from %x", ind->device_address);
typedef union {
mac_capability_t mac_capability;
uint8_t capability_information;
} mac_capability_conv_t;
mac_capability_conv_t caps_conv = {.capability_information = ind->capability_information};
NRF_LOG_INFO("alternate_pan_coordinator: %d", caps_conv.mac_capability.alternate_pan_coordinator);
NRF_LOG_INFO("device_type: %d", caps_conv.mac_capability.device_type);
NRF_LOG_INFO("power_source: %d", caps_conv.mac_capability.power_source);
NRF_LOG_INFO("rx_on_when_idle: %d", caps_conv.mac_capability.rx_on_when_idle);
NRF_LOG_INFO("security_capability: %d", caps_conv.mac_capability.security_capability);
NRF_LOG_INFO("allocate_address: %d", caps_conv.mac_capability.allocate_address);
last_addr = ind->device_address & 0xffff;
associate_resp = (mlme_associate_resp_t){
.device_address = ind->device_address,
.assoc_short_address = last_addr,
.status = MAC_ASSOCIATION_SUCCESSFUL
};
send_resp = true;
}
static void clock_init(void)
{
ret_code_t err_code = nrf_drv_clock_init();
ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_MODULE_ALREADY_INITIALIZED));
nrf_drv_clock_hfclk_request(NULL);
while (!nrf_drv_clock_hfclk_is_running())
{
// spin lock
}
nrf_drv_clock_lfclk_request(NULL);
while (!nrf_drv_clock_lfclk_is_running())
{
// spin lock
}
}
/**
* @brief Function for application main entry.
*/
int main(void)
{
ral_irq_handler_import();
clock_init();
APP_ERROR_CHECK(bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, NULL));
bsp_board_leds_off();
APP_ERROR_CHECK(app_usbd_init(NULL));
app_usbd_enable();
app_usbd_start();
APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
NRF_LOG_DEFAULT_BACKENDS_INIT();
for (int i=0; i<300; i++)
{
while (app_usbd_event_queue_process());
if (i % 2)
bsp_board_leds_off();
else
bsp_board_leds_on();
nrf_delay_ms(10);
}
bsp_board_leds_on();
NRF_LOG_INFO("Wireless UART example started.");
bsp_board_leds_off();
app_task_init();
bool prev_button = bsp_board_button_state_get(CONFIG_BTN_DATA_SEND);
bool curr_button = 0;
while (true)
{
while (app_usbd_event_queue_process());
sys_task_run();
if (send_resp) {
mlme_associate_resp(&associate_resp);
send_resp = false;
}
curr_button = bsp_board_button_state_get(CONFIG_BTN_DATA_SEND);
if (prev_button == 0 && curr_button == 1) {
send_data();
}
prev_button = curr_button;
}
}
FFD:
#include "config.h"
#include "ral_irq_handlers.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "nrf_delay.h"
#include "app_usbd.h"
#include "bsp.h"
#include "nrf_drv_clock.h"
#include "mac_mlme_pib.h"
#include "mac_mlme_reset.h"
#include "mac_mlme_scan.h"
#include "mac_mlme_associate.h"
#include "mac_mlme_sync.h"
#include "mac_mcps_data.h"
#include "sys_memory_manager.h"
#include "sys_init.h"
#include "sys_task_scheduler.h"
#include "boards.h"
static uint8_t __ALIGN(ALIGN_VALUE) m_heap[CONFIG_POOL_SIZE];
static const size_t m_heap_size = CONFIG_POOL_SIZE;
static void out_of_memory_callback(const void * data);
static void memory_freed_callback(const void * data);
static mac_pan_descriptor_t pan_descriptor;
uint16_t my_addr = 0xFFFF;
//static void auto_request_set();
static sys_event_desc_t m_out_of_memory_desc =
{
.event_id = SYS_EVENT_OUT_OF_MEMORY,
.callback = out_of_memory_callback,
};
static sys_event_desc_t m_memory_freed_desc =
{
.event_id = SYS_EVENT_MEMORY_FREED,
.callback = memory_freed_callback,
};
void mcps_data_ind(mcps_data_ind_t * p_ind)
{
bool addresses_match = p_ind->dst_pan_id == pan_descriptor.coord_pan_id &&
p_ind->dst_addr_mode == pan_descriptor.coord_addr_mode &&
p_ind->dst_addr.short_address == my_addr &&
p_ind->src_pan_id == pan_descriptor.coord_pan_id;
NRF_LOG_INFO("received success from %x", p_ind->src_addr.short_address);
if (addresses_match && p_ind->msdu_length > 0)
{
if (bsp_board_led_state_get(CONFIG_DOWNSTREAM_PIN))
bsp_board_led_off(CONFIG_DOWNSTREAM_PIN);
else
bsp_board_led_on(CONFIG_DOWNSTREAM_PIN);
}
mac_mem_msdu_free(&p_ind->msdu);
}
static void mcps_data_conf(mcps_data_conf_t * conf)
{
if (conf->status == MAC_SUCCESS)
{
NRF_LOG_INFO("send success");
}
else
{
NRF_LOG_INFO("send failed");
}
bsp_board_led_off(CONFIG_UPSTREAM_PIN);
}
static void send_data()
{
static uint8_t m_radio_tx_buffer[PHY_MAX_PACKET_SIZE + MAC_MAX_MHR_SIZE];
static mcps_data_req_t m_data_req;
NRF_LOG_INFO("send_data");
if (bsp_board_led_state_get(CONFIG_UPSTREAM_PIN)) {
NRF_LOG_INFO("in progress");
return;
}
m_radio_tx_buffer[MAC_MAX_MHR_SIZE] = 'x';
m_data_req.dst_addr_mode = pan_descriptor.coord_addr_mode;
m_data_req.dst_addr = pan_descriptor.coord_address;
m_data_req.dst_pan_id = pan_descriptor.coord_pan_id;
m_data_req.src_addr_mode = MAC_ADDR_SHORT;
m_data_req.msdu = (uint8_t *)&m_radio_tx_buffer[MAC_MAX_MHR_SIZE];
m_data_req.msdu_length = 1;
m_data_req.msdu_handle++;
m_data_req.tx_options.ack = true;
m_data_req.tx_options.gts = false;
m_data_req.tx_options.indirect = false;
mcps_data_req(&m_data_req, mcps_data_conf);
bsp_board_led_on(CONFIG_UPSTREAM_PIN);
}
static void out_of_memory_callback(const void * data)
{
bsp_board_led_on(CONFIG_ERROR_PIN);
}
static void memory_freed_callback(const void * data)
{
bsp_board_led_off(CONFIG_ERROR_PIN);
}
static void mlme_associate_conf_cb(mlme_associate_conf_t * conf)
{
NRF_LOG_INFO("mlme_associate_conf: %d", conf->status);
if (conf->status == MAC_SUCCESS)
bsp_board_led_on(CONFIG_INIT_DONE_PIN);
else
bsp_board_led_off(CONFIG_INIT_DONE_PIN);
my_addr = conf->assoc_short_address;
NRF_LOG_INFO("short_address: %x", my_addr);
//auto_request_set();
//static mlme_sync_req_t req;
//req = (mlme_sync_req_t){
// .logical_channel = pan_descriptor.logical_channel,
// .track_beacon = true
//};
//mlme_sync_req(&req);
}
static void log_mac_pan_descriptor(const mac_pan_descriptor_t *mac_pan_descriptor)
{
NRF_LOG_INFO("coord_addr_mode: %d", mac_pan_descriptor->coord_addr_mode);
NRF_LOG_INFO("coord_pan_id: %x", mac_pan_descriptor->coord_pan_id);
NRF_LOG_INFO("coord_address.short_address: %x", mac_pan_descriptor->coord_address.short_address);
NRF_LOG_INFO("coord_address.long_address: %x", mac_pan_descriptor->coord_address.long_address);
NRF_LOG_INFO("logical_channel: %d", mac_pan_descriptor->logical_channel);
NRF_LOG_INFO("superframe_spec.beacon_order %d", mac_pan_descriptor->superframe_spec.beacon_order);
NRF_LOG_INFO("superframe_spec.superframe_order %d", mac_pan_descriptor->superframe_spec.superframe_order);
NRF_LOG_INFO("superframe_spec.final_cap_slot %d", mac_pan_descriptor->superframe_spec.final_cap_slot);
NRF_LOG_INFO("superframe_spec.battery_life_extension %d", mac_pan_descriptor->superframe_spec.battery_life_extension);
NRF_LOG_INFO("superframe_spec.pan_coordinator %d", mac_pan_descriptor->superframe_spec.pan_coordinator);
NRF_LOG_INFO("superframe_spec.association_permit %d", mac_pan_descriptor->superframe_spec.association_permit);
NRF_LOG_INFO("gts_permit %d", mac_pan_descriptor->gts_permit);
NRF_LOG_INFO("link_quality %d", mac_pan_descriptor->link_quality);
NRF_LOG_INFO("timestamp %d", mac_pan_descriptor->timestamp);
}
static void mlme_scan_conf_cb(mlme_scan_conf_t * conf)
{
if (conf->status == MAC_SUCCESS)
bsp_board_led_on(CONFIG_INIT_DONE_PIN);
else
bsp_board_led_off(CONFIG_INIT_DONE_PIN);
NRF_LOG_INFO("mlme_scan_conf: %d", conf->status);
NRF_LOG_INFO("unscanned channels: %x", conf->unscanned_channels);
NRF_LOG_INFO("results: %d",conf->result_list_size);
if (conf->result_list_size == 0)
return;
NRF_LOG_INFO("first result");
pan_descriptor = conf->pan_descriptor_list[0];
log_mac_pan_descriptor(&pan_descriptor);
static mlme_associate_req_t req;
req = (mlme_associate_req_t){
.logical_channel = pan_descriptor.logical_channel,
.coord_addr_mode = pan_descriptor.coord_addr_mode,
.coord_pan_id = pan_descriptor.coord_pan_id,
.coord_address = pan_descriptor.coord_address,
//FFD for now
.capability_information = {
.alternate_pan_coordinator = 0,
.device_type = 1,
.power_source = 1,
.rx_on_when_idle = 1,
.security_capability = 0,
.allocate_address = 1
}
};
mlme_associate_req(&req, mlme_associate_conf_cb);
}
static void ext_addr_set()
{
const pib_id_t pib_id =
{
.mlme_id = MAC_EXTENDED_ADDRESS,
};
uint64_t address = CONFIG_IEEE_ADDRESS + CONFIG_DEVICE_SHORT_ADDRESS;
mac_status_t result = mlme_set(pib_id, 0, &address);
NRF_LOG_INFO("ext_addr_set: %d", result);
}
static void rx_on_idle_set()
{
const pib_id_t pib_id =
{
.mlme_id = MAC_RX_ON_WHEN_IDLE,
};
uint8_t rx_on_idle = 1;
mac_status_t result = mlme_set(pib_id, 0, &rx_on_idle);
NRF_LOG_INFO("rx_on_idle_set: %d", result);
}
//static void auto_request_set()
//{
// const pib_id_t pib_id =
// {
// .mlme_id = MAC_AUTO_REQUEST,
// };
// uint8_t auto_request = 0;
// mac_status_t result = mlme_set(pib_id, 0, &auto_request);
// NRF_LOG_INFO("auto_request_set: %d", result);
//}
void mlme_reset_conf_cb(mlme_reset_conf_t *conf)
{
NRF_LOG_INFO("mlme_reset_conf: %d", conf->status);
if (conf->status == MAC_SUCCESS)
bsp_board_led_on(CONFIG_INIT_DONE_PIN);
else {
bsp_board_led_off(CONFIG_INIT_DONE_PIN);
return;
}
ext_addr_set();
rx_on_idle_set();
static mac_pan_descriptor_t pan_descriptors_buf[2];
static mlme_scan_req_t req = {
.scan_type = PASSIVE_SCAN,
.scan_channels = (1 << 15), //PHY_CHANNEL_SUPPORTED,
.scan_duration = 8,
.pan_descriptors_buf_size = sizeof(pan_descriptors_buf) / sizeof(pan_descriptors_buf[0]),
.pan_descriptors_buf = pan_descriptors_buf,
.energy_detect_buf_size = 0,
.energy_detect_buf = NULL,
};
mlme_scan_req(&req, mlme_scan_conf_cb);
}
/**@brief Application task initialization for GPIO test.
*/
static void app_task_init(void)
{
sys_init(m_heap, m_heap_size);
sys_event_subscribe(&m_out_of_memory_desc);
sys_event_subscribe(&m_memory_freed_desc);
static mlme_reset_req_t req = {
.set_default_pib = true
};
mlme_reset_req(&req, mlme_reset_conf_cb);
}
void mlme_sync_loss_ind(mlme_sync_loss_ind_t * ind)
{
NRF_LOG_INFO("mlme_sync_loss for PAN ID: %d on channel %d", ind->pan_id, ind->logical_channel);
NRF_LOG_INFO("reason: %d", ind->loss_reason);
}
void mlme_beacon_notify_ind(mlme_beacon_notify_ind_t *ind)
{
NRF_LOG_INFO("mlme_beacon_notify_ind bsn: %d", ind->bsn);
log_mac_pan_descriptor(&ind->pan_descriptor);
mac_mem_msdu_free(&ind->sdu);
}
static void clock_init(void)
{
ret_code_t err_code = nrf_drv_clock_init();
ASSERT((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_MODULE_ALREADY_INITIALIZED));
nrf_drv_clock_hfclk_request(NULL);
while (!nrf_drv_clock_hfclk_is_running())
{
// spin lock
}
nrf_drv_clock_lfclk_request(NULL);
while (!nrf_drv_clock_lfclk_is_running())
{
// spin lock
}
}
/**
* @brief Function for application main entry.
*/
int main(void)
{
ral_irq_handler_import();
clock_init();
APP_ERROR_CHECK(bsp_init(BSP_INIT_LEDS | BSP_INIT_BUTTONS, NULL));
bsp_board_leds_off();
APP_ERROR_CHECK(app_usbd_init(NULL));
app_usbd_enable();
app_usbd_start();
APP_ERROR_CHECK(NRF_LOG_INIT(NULL));
NRF_LOG_DEFAULT_BACKENDS_INIT();
for (int i=0; i<300; i++)
{
while (app_usbd_event_queue_process());
if (i % 2)
bsp_board_leds_off();
else
bsp_board_leds_on();
nrf_delay_ms(10);
}
bsp_board_leds_on();
NRF_LOG_INFO("Blinky device example started.");
bsp_board_leds_off();
app_task_init();
bool prev_button = bsp_board_button_state_get(CONFIG_BTN_DATA_SEND);
bool curr_button = 0;
while (true)
{
while (app_usbd_event_queue_process());
sys_task_run();
curr_button = bsp_board_button_state_get(CONFIG_BTN_DATA_SEND);
if (prev_button == 0 && curr_button == 1) {
send_data();
}
prev_button = curr_button;
}
}