Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nrf52840 802.15.4: mlme_start_req: nonbeacon-enabled mode doesn't work

Hi,

I have a problem with the mlme_start_req:

I have defined the following structure for mlme_start_req_t:

#define SUPERFRAME_ORDER 15u

#define BEACON_ORDER 15u

static mlme_start_req_t start_req =
{
.pan_id = 0x1234,
.logical_channel = 14,
.start_time = 0x000000,
.beacon_order = BEACON_ORDER,
.superframe_order = SUPERFRAME_ORDER,
.pan_coordinator = true,
.battery_life_extension = false,
.coord_realignment = false,
#if (CONFIG_SECURE == 1)
.coord_realign_security_level = false,
.beacon_security_level = false,
#endif
};
mlme_start_req(&start_req, start_callback);

If I understand the 802.15.4 standard correctly, this conficuration means, that I want to start the device as PAN-Coordinator in the nonbeacon-enabled mode.

But if I start on another 802.15.4 device an ACTIVE-SCAN, I don't get any Response beacon from the PAN-Coordinator. (The Device where an ACTIVE-Scan is started should have the ACTIVE-Scan implemented just right, because with other PAN-Coordinators in the nonbeacon-enabled mode, it receives the beacons)

Interestingly, if I change the SUPERFRAME_ORDER and BEACON_ORDER macros from 15u to something smaller (i.e. enforce the PAN-Coordinator to work in beacon-enabled mode),

the device which performs the ACTIVE-SCAN then receives the beacons.

Before calling the mlme_start_req, I configured the extended (0xcau, 0xfeu, 0xbeu, 0xefu, 0x00u, 0x00u, 0xffu, 0xffu) and the short address (MAC_EXTENDED_ADDRESS_ONLY) and also the beacon payload and the beacon length, set the gts-permit to false and enabled rx-on-when-idle.

I think, there is something, I missed to configure, but I don't get it.

I have added my complete code here:

#ifdef __cplusplus
extern "C" {
#endif
#include "802_15_4_config.h"

#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#include "ral_irq_handlers.h"

#include "nrf_drv_clock.h"

#include "boards.h"
#include "mac_mcps_data.h"
#include "sys_init.h"
#include "sys_task_scheduler.h"

#include "mac_common.h"
#include "mac_mlme_beacon_notify.h"
#include "mac_mlme_comm_status.h"
#include "mac_mlme_pib.h"
#include "mac_mlme_associate.h"
#include "mac_mlme_poll.h"
#include "mac_mlme_scan.h"
#include "mac_mlme_start.h"
#include "mac_security.h"
#ifdef __cplusplus
}
#endif

#include "SEGGER_RTT.h"
#include "SEGGER_RTT_Conf.h"

#define CONFIG_POOL_SIZE 0x2000
static __ALIGN(ALIGN_VALUE) uint8_t m_heap[CONFIG_POOL_SIZE];
#define CONFIG_ERROR_PIN LED_4

#define C11 (1 << 11)
#define C12 (1 << 12)
#define C13 (1 << 13)
#define C14 (1 << 14)
#define C15 (1 << 15)
#define C16 (1 << 16)
#define C17 (1 << 17)
#define C18 (1 << 18)
#define C19 (1 << 19)
#define C20 (1 << 20)
#define C21 (1 << 21)
#define C22 (1 << 22)
#define C23 (1 << 23)
#define C24 (1 << 24)
#define C25 (1 << 25)
#define C26 (1 << 26)

static void out_of_memory_callback(const void* data);
static void memory_freed_callback(const void* data);

#ifdef __cplusplus
constexpr sys_event_desc_t gen_sys_event_desc_t(sys_event_id_t event_id,
                                                void(callback)(const void*)) {
    return sys_event_desc_t{sys_queue_item_t{}, event_id, callback};
}
static sys_event_desc_t m_out_of_memory_desc =
    gen_sys_event_desc_t(SYS_EVENT_OUT_OF_MEMORY, out_of_memory_callback);
static sys_event_desc_t m_memory_freed_desc =
    gen_sys_event_desc_t(SYS_EVENT_MEMORY_FREED, memory_freed_callback);
#else
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};
#endif

void wait_ms(const uint32_t count) {
    SEGGER_RTT_printf(0, "dummy wait: ");
    for(volatile uint32_t i=0; i<2432u*count; i++) {
        uint32_t j = i%(2432u*100u);
        if(j == 0) {
            SEGGER_RTT_printf(0, ".", j);
        }
    }
    SEGGER_RTT_printf(0, "\n");
}

static void out_of_memory_callback(const void* data) {
    LEDS_ON(BIT(CONFIG_ERROR_PIN));
}

static void memory_freed_callback(const void* data) {
    LEDS_OFF(BIT(CONFIG_ERROR_PIN));
}

static void app_task_init(void) {
    LEDS_CONFIGURE(LEDS_MASK);
    LEDS_OFF(LEDS_MASK);

    sys_init(m_heap, CONFIG_POOL_SIZE);

    sys_event_subscribe(&m_out_of_memory_desc);
    sys_event_subscribe(&m_memory_freed_desc);
}

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
    }
}

void print_mac_status(const mac_status_t status) {
    switch (status) {
        case MAC_NO_BEACON:
            SEGGER_RTT_printf(0, "MAC_NO_BEACON");
            break;
        case MAC_SUCCESS:
            SEGGER_RTT_printf(0, "MAC_SUCCESS");
            break;
        case MAC_LIMIT_REACHED:
            SEGGER_RTT_printf(0, "MAC_LIMIT_REACHED");
            break;
        default:
            SEGGER_RTT_printf(0, "0x%x", status);
            break;
    }
}

void print_addr(const mac_addr_t* addr, const mac_addr_mode_t addr_mode,
                const char* field) {
    SEGGER_RTT_printf(0, "%s: ", field);
    switch (addr_mode) {
        case MAC_ADDR_NONE:
            SEGGER_RTT_printf(0, "NONE");
            break;
        case MAC_ADDR_SHORT:
            SEGGER_RTT_printf(0, "0x%04x (short)", addr->short_address);
            break;
        case MAC_ADDR_LONG:
        default:
            SEGGER_RTT_printf(0, "0x%08x%08x (long)",
                              (uint32_t)(addr->long_address >> 32),
                              (uint32_t)(addr->long_address));
            break;
    }
}

void print_pan_desc(const mac_pan_descriptor_t* pan) {
    SEGGER_RTT_printf(0, "{coord_pan_id: 0x%04x, ", pan->coord_pan_id);
    print_addr(&(pan->coord_address), pan->coord_addr_mode, "address");
    SEGGER_RTT_printf(0,
                      ", logical_channel: %u, timestamp: 0x%x, link_quality: "
                      "%u, superframe_spec: 0x%x, gts: %s}",
                      pan->logical_channel, pan->timestamp, pan->link_quality,
                      pan->superframe_spec, pan->gts_permit ? "true" : "false");
}

void print_scan_conf(const mlme_scan_conf_t* sc) {
    SEGGER_RTT_printf(0, "{status: ");
    print_mac_status(sc->status);
    SEGGER_RTT_printf(0, ", scan_type: ");
    switch (sc->scan_type) {
        case ED_SCAN:
            SEGGER_RTT_printf(0, "ED_SCAN");
            break;
        case ACTIVE_SCAN:
            SEGGER_RTT_printf(0, "ACTIVE_SCAN");
            break;
        case PASSIVE_SCAN:
            SEGGER_RTT_printf(0, "PASSIVE_SCAN");
            break;
        case ORPHAN_SCAN:
            SEGGER_RTT_printf(0, "ORPHAN_SCAN");
            break;
        default:
            SEGGER_RTT_printf(0, "Unknown(%x)", sc->scan_type);
            break;
    }
    SEGGER_RTT_printf(0, ", unscanned_channels: %x", sc->unscanned_channels);
    SEGGER_RTT_printf(0, ", result_list_size: %u, results: {",
                      sc->result_list_size);
    for (size_t i = 0; i < sc->result_list_size; i++) {
        const mac_pan_descriptor_t* pan = &(sc->pan_descriptor_list[i]);
        SEGGER_RTT_printf(0, "Result %u: {pan_descriptor: ", i);
        print_pan_desc(pan);

        //for an active scan, the content of the energy_detect_list must not be read.
        //const uint8_t energy = sc->energy_detect_list[i];
        //(void)energy;
        //SEGGER_RTT_printf(0, ", energy: %x",  energy);
        SEGGER_RTT_printf(0, "}, ");
    }
    SEGGER_RTT_printf(0, "}\n");
}

bool callback_called = false;
void scan_callback(mlme_scan_conf_t* sc) { callback_called = true; };
void start_callback(mlme_start_conf_t* sc) { callback_called = true; };

mlme_scan_req_t gen_mac_scan_req_t(
    mac_scan_type_t scan_type, uint32_t scan_channels, uint8_t scan_duration,
    mac_pan_descriptor_t* pan_desc_buf, size_t pan_desc_size,
    uint8_t* energy_detect_buf, size_t energy_detect_size) {

    mlme_scan_req_t ret;
    ret.scan_type = scan_type;
    ret.scan_channels = scan_channels;
    ret.scan_duration = scan_duration;
    ret.pan_descriptors_buf = pan_desc_buf;
    ret.pan_descriptors_buf_size = pan_desc_size;
    ret.energy_detect_buf = energy_detect_buf;
    ret.energy_detect_buf_size = energy_detect_size;
    return ret;
}

const mlme_scan_conf_t* scan_req(mac_scan_type_t scan_type,
                                 uint32_t scan_channels,
                                 uint8_t scan_duration) {
#define _ENERGY_DET_SIZE 8
#define _PAN_DESC_SIZE 8
    static mac_pan_descriptor_t pd[_PAN_DESC_SIZE];
    static uint8_t ed[_ENERGY_DET_SIZE];

    static mlme_scan_req_t scan_req;
    scan_req = gen_mac_scan_req_t(scan_type, scan_channels, scan_duration, pd,
                                  _PAN_DESC_SIZE, ed, _ENERGY_DET_SIZE);

    callback_called = false;

    mlme_scan_req(&scan_req, scan_callback);

    while (!callback_called) {
        sys_task_run();
    }

    return &scan_req.confirm;
}

void gen_mac_key_descr_t(mac_key_descr_t* key_descr) {
    mac_table_init(&key_descr->id_lookup_list);
    mac_table_init(&key_descr->key_device_list);
    mac_table_init(&key_descr->key_usage_list);
}

mac_device_descr_t gen_mac_device_descr_t(uint16_t pan_id,
                                          uint16_t short_address,
                                          uint64_t extended_address,
                                          uint32_t frame_counter, bool exempt) {
    mac_device_descr_t ret;
    ret.pan_id = pan_id;
    ret.short_address = short_address;
    ret.extended_address = extended_address;
    ret.frame_counter = frame_counter;
    ret.exempt = exempt;
    return ret;
}

mac_security_level_descr_t gen_mac_security_level_descr_t(
    uint8_t frame_type, uint8_t cmd_frame_id, uint8_t security_min,
    uint8_t override_min) {
    mac_security_level_descr_t ret;
    ret.security_min = security_min;
    ret.override_min = override_min;
    ret.frame_type = frame_type;
    ret.cmd_frame_id = cmd_frame_id;
    return ret;
}

mac_key_id_lookup_descr_t gen_mac_key_id_lookup_descr_t(
    mac_key_lookup_size_t size) {
    mac_key_id_lookup_descr_t ret;
    ret.size = size;
    return ret;
}

mac_key_device_descr_t gen_mac_key_device_descr_t(uint8_t device_handle,
                                                  uint8_t unique_device,
                                                  uint8_t blacklisted) {
    mac_key_device_descr_t ret;
    ret.device_handle = device_handle;
    ret.blacklisted = blacklisted;
    ret.unique_device = unique_device;
    return ret;
}

mac_key_usage_descr_t gen_mac_key_usage_descr_t(uint8_t frame_type,
                                                uint8_t cmd_frame_id) {
    mac_key_usage_descr_t ret;
    ret.frame_type = frame_type;
    ret.cmd_frame_id = cmd_frame_id;
    return ret;
}

pib_id_t gen_pib_id_t_plme(plme_pib_attr_id_t id) {
    pib_id_t ret;
    ret.plme_id = id;
    return ret;
}

pib_id_t gen_pib_id_t(mlme_pib_attr_id_t id) {
    pib_id_t ret;
    ret.mlme_id = id;
    return ret;
}

const char* pib_id_str(pib_id_t id) {
    switch(id.mlme_id) {
        case MAC_PAN_ID:
            return "MAC_PAN_ID";
        case MAC_PAN_COORD_EXTENDED_ADDRESS:
            return "MAC_PAN_COORD_EXTENDED_ADDRESS";
        case MAC_PROMISCUOUS_MODE:
            return "MAC_PROMISCUOUS_MODE";
        case MAC_EXTENDED_ADDRESS:
            return "MAC_EXTENDED_ADDRESS";
        case MAC_SHORT_ADDRESS:
            return "MAC_SHORT_ADDRESS";
        case MAC_BEACON_PAYLOAD_LENGTH:
            return "MAC_BEACON_PAYLOAD_LENGTH";
        case MAC_BEACON_PAYLOAD:
            return "MAC_BEACON_PAYLOAD";
        case MAC_BEACON_ORDER:
            return "MAC_BEACON_ORDER";
        case MAC_RX_ON_WHEN_IDLE:
            return "MAC_RX_ON_WHEN_IDLE";
        case MAC_BATT_LIFE_EXT:
            return "MAC_BATT_LIFE_EXT";
        case MAC_IS_PAN_COORD:
            return "MAC_IS_PAN_COORD";
        case MAC_ASSOCIATION_PERMIT:
            return "MAC_ASSOCIATION_PERMIT";
        case MAC_GTS_PERMIT:
            return "MAC_GTS_PERMIT";
        default:
            return "**************UNKNOWN****************";
    }
}

void print_pib_get_request(const uint8_t* value, uint16_t size,
                           const char* name) {
    SEGGER_RTT_printf(0, "mlme_get: %s: 0x", name);
    for (uint16_t i = 0; i < size; i++) {
        SEGGER_RTT_printf(0, "%02x", value[i]);
    }
    SEGGER_RTT_printf(0, "\n");
}

const uint8_t* pib_get_request(pib_id_t id) {
    static uint8_t value[256];
    mac_status_t res = mlme_get(id, 0, value);
    const char* name = pib_id_str(id);
    if (res != MAC_SUCCESS) {
        SEGGER_RTT_printf(0, "failure in pib-get request(%s): ", name);
        print_mac_status(res);
        SEGGER_RTT_printf(0, "\n");
        // TODO: handle this error
        return NULL;
    }
    print_pib_get_request(value, mlme_pib_attr_size_calc(id, 0), name);
    return value;
}

void pib_set_request(pib_id_t id, void * data) {
    mac_status_t state = mlme_set(id, 0, data);
    if (state != MAC_SUCCESS) {
        SEGGER_RTT_printf(0, "failure in pib-set request(%s): ", pib_id_str(id));
        print_mac_status(state);
        SEGGER_RTT_printf(0, "\n");
        //TODO: handle this error
    }
}

const uint8_t* pib_set_get_request(pib_id_t id, void * data) {
    pib_set_request(id, data);
    return pib_get_request(id);
}

void print_beacon_notify_ind(const mlme_beacon_notify_ind_t* ind) {
    SEGGER_RTT_printf(0, "{bsn: %u, pan_descriptor: ", ind->bsn);
    print_pan_desc(&(ind->pan_descriptor));
    SEGGER_RTT_printf(0, ", sdu_length: %u, sdu: 0x", ind->sdu_length);
    for (size_t i = 0u; i < ind->sdu_length; i++) {
        SEGGER_RTT_printf(0, "%02x", ind->sdu.p_payload[i]);
    }
    SEGGER_RTT_printf(0, ", pend_addr_spec: %x}\n", ind->pend_addr_spec);
}

void print_data_ind(const mcps_data_ind_t* ind) {
    SEGGER_RTT_printf(0, "{src_pan_id: 0x%04x, ", ind->src_pan_id);
    print_addr(&(ind->src_addr), ind->src_addr_mode, "src_addr");
    SEGGER_RTT_printf(0, ", dst_pan_id: 0x%04x, ", ind->dst_pan_id);
    print_addr(&(ind->dst_addr), ind->dst_addr_mode, "dst_addr");
    SEGGER_RTT_printf(0, ", msdu_length: %u, sdu: 0x", ind->msdu_length);
    for (size_t i = 0u; i < ind->msdu_length; i++) {
        SEGGER_RTT_printf(0, "%02x", ind->msdu.p_payload[i]);
    }
    SEGGER_RTT_printf(0, ", mpdu_link_quality: %u", ind->mpdu_link_quality);
    SEGGER_RTT_printf(0, ", dsn: %u", ind->dsn);
    SEGGER_RTT_printf(0, ", timestamp: %u}\n", ind->timestamp);
    SEGGER_RTT_printf(0, "\n");
}

void mlme_beacon_notify_ind(mlme_beacon_notify_ind_t* _ind) {
    SEGGER_RTT_printf(0, "Received Beacon:\n");
    print_beacon_notify_ind(_ind);
}

void mlme_poll_ind(mlme_poll_ind_t* _ind) {
    SEGGER_RTT_printf(0, "Received Poll:\n");
}

//void mac_auto_request_notify_ind(mac_beacon_ind_t* _ind) {
//    SEGGER_RTT_printf(0, "Received Auto Request Notif:\n");
//}
//
//void mac_panid_conflict_beacon_notify_ind(const mac_beacon_ind_t * p_beacon) {
//    SEGGER_RTT_printf(0, "Received Panid Conflict beacon:\n");
//}

void mcps_data_ind(mcps_data_ind_t* _ind) {
    SEGGER_RTT_printf(0, "Received Data:\n");
    print_data_ind(_ind);
}

void mlme_associate_ind(mlme_associate_ind_t* _ind) {
    SEGGER_RTT_printf(0, "Received Association:\n");
}

#define UINT16_TO_ARR(value) {((uint8_t)(value>>8u)), ((uint8_t)(0xffu & value))}

int main(void) {
    ral_irq_handler_import();

    SEGGER_RTT_Init();
    uint8_t rtt_buf_out[256u];
    SEGGER_RTT_ConfigUpBuffer(0, "OUT", rtt_buf_out, 256u,
                              SEGGER_RTT_MODE_NO_BLOCK_TRIM);

    app_task_init();
    sys_task_post(APP_TASK_ID);

    clock_init();

    SEGGER_RTT_printf(0, "....RESET COORD....\n");
#if (CONFIG_SECURE == 1)
    SEGGER_RTT_printf(0, "Compiled with CONFIG_SECURE\n");
#endif

    static uint8_t mac_association_permit = true;

#define BEACON_ORDER 0xfu        //nonbeacon-enabled   // see 7.5.1.1, page 168
#define SUPERFRAME_ORDER 0xfu    //should be set to 15 // see 7.5.1.1, page 168
    static uint8_t mac_gts_permit = false;              // see 7.5.1.1, page 168
    static uint8_t rx_on_when_idle = true;              // see table 86, page 165

    static uint8_t beacon_payload[] = {0xabu, 0xabu, 0xabu, 0xabu, 0xbbu, 0xbbu, 0xbbu, 0xbbu};
    static uint8_t beacon_payload_length = 8u;
    static const uint8_t ext_addr[] = {0xcau, 0xfeu, 0xbeu, 0xefu, 0x00u, 0x00u, 0xffu, 0xffu};

    static uint16_t ext_addr_only = MAC_EXTENDED_ADDRESS_ONLY;

    //TODO: according to page 174, If a coordinator of a nonbeacon-enabled PAN receives this command, it shall transmit a single beacon frame using unslotted CSMA-CA. => How to do this?

    pib_set_get_request(gen_pib_id_t(MAC_EXTENDED_ADDRESS), (void *)ext_addr);
    pib_set_get_request(gen_pib_id_t(MAC_SHORT_ADDRESS), &ext_addr_only);
    pib_set_get_request(gen_pib_id_t(MAC_BEACON_PAYLOAD_LENGTH), &beacon_payload_length);
    pib_set_get_request(gen_pib_id_t(MAC_BEACON_PAYLOAD), (void*)beacon_payload);
    pib_set_get_request(gen_pib_id_t(MAC_RX_ON_WHEN_IDLE), &rx_on_when_idle);
    pib_set_get_request(gen_pib_id_t(MAC_ASSOCIATION_PERMIT), &mac_association_permit);
    pib_get_request(gen_pib_id_t(MAC_GTS_PERMIT));
    pib_set_get_request(gen_pib_id_t(MAC_GTS_PERMIT), &mac_gts_permit);

    static mlme_start_req_t start_req =
	{
			.pan_id  = 0x1234,
			.logical_channel = 14,
			.start_time = 0x000000,
			.beacon_order = BEACON_ORDER,
			.superframe_order = SUPERFRAME_ORDER,
			.pan_coordinator = true,
			.battery_life_extension = false,
			.coord_realignment = false,
#if (CONFIG_SECURE == 1)
            .coord_realign_security_level = false,
            .beacon_security_level = false,
#endif
	};

    callback_called = false;
	mlme_start_req(&start_req, start_callback);
    while (!callback_called) {
        sys_task_run();
    }

    SEGGER_RTT_printf(0, "Sent the Start-Request: ");
    print_mac_status(start_req.confirm.status);
    SEGGER_RTT_printf(0, "\n");

    pib_get_request(gen_pib_id_t(MAC_IS_PAN_COORD));
    pib_get_request(gen_pib_id_t(MAC_PAN_ID));
    pib_get_request(gen_pib_id_t(MAC_SUPERFRAME_ORDER));
    pib_get_request(gen_pib_id_t(MAC_BEACON_ORDER));
    pib_get_request(gen_pib_id_t(MAC_RX_ON_WHEN_IDLE));
    pib_get_request(gen_pib_id_t(MAC_GTS_PERMIT));

    while (true) {
        sys_task_run();
    }
}

You can copy it directly into the 802.15.4 wireless uart example direktory of the SDK and build and run it.

I use Ubuntu 16.04 with gcc 7.2.0 and the SDK-Version 14.2.0

Thanks

Parents
  • Unfortunately use case with the non beacon functionality will not work with the current SDK with given IEEE 802.15.4 library. This is becuase by default the library was configured to work only in beacon enabled mode.

    , i.e. if you want to set up a device as a PAN coordinator in a non-beacon mode (not sending beacon frames periodically) - it will not work. One would need to recompile the library with a different config, and that's what we can do  if it's what is what you needed. We are still adapting and absorbing use cases and trying to make the solution more flexible in the future.

    We can try to give you the library for non beacon enabled mode if you need it.

Reply
  • Unfortunately use case with the non beacon functionality will not work with the current SDK with given IEEE 802.15.4 library. This is becuase by default the library was configured to work only in beacon enabled mode.

    , i.e. if you want to set up a device as a PAN coordinator in a non-beacon mode (not sending beacon frames periodically) - it will not work. One would need to recompile the library with a different config, and that's what we can do  if it's what is what you needed. We are still adapting and absorbing use cases and trying to make the solution more flexible in the future.

    We can try to give you the library for non beacon enabled mode if you need it.

Children
Related