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_scan_request doesn't return unscanned_channels

I use the nRF52-SDK on an nRF52840 PDK, but if I start a scan request, I don't get the number of scanned channels back in the mlme_scan_conf_t.

I.e. mlme_scan_conf_t::unscanned_channels is always zero.

Additionally, the mlme_scan_conf_t::energy_detect_list is not a NULL-ptr, if I start an ACTIVE-scan. (But it should be according to Table 68 in IEEE Std 802.15.4-2006)

I have included a test program, which can simply be added to the existing 802.15.4 wireless uart example in the sdk-folder:

#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_scan.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

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

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_scan_conf(const mlme_scan_conf_t* sc) {
    if(sc->status == MAC_SUCCESS) {
        SEGGER_RTT_printf(0, "unscanned_channels: %x\n", sc->unscanned_channels);
        SEGGER_RTT_printf(0, "result_list_size: %u\n", sc->result_list_size);
        if(sc->energy_detect_list != NULL) {
            SEGGER_RTT_printf(0, "Energy Detect List is not a nullptr.\n");
        }
    } else {
        SEGGER_RTT_printf(0, "unsuccessful scan\n");
    }
}

bool callback_called = false;

void scan_callback(mlme_scan_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;
}

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 SCAN....\n");

    SEGGER_RTT_printf(0, "starting the scan\n");
    print_scan_conf(scan_req(ACTIVE_SCAN, 1<<14, 7));
    SEGGER_RTT_printf(0, "finished the scan\n");

    while (true) {
        sys_task_run();
    }
}

It outputs the following via RTT:

starting the scan
unscanned_channels: 0
result_list_size: 1
Energy Detect List is not a nullptr.
finished the scan

I am using the nRF52-SDK-14.2.0 and gcc-7.2.0.

Parents
  • Hi,

    here is something that may be useful for you.

    When you look at the UnscannedChannels parameter in the Table 68 (IEEE Std 802.15.4-2006 specification), you can see following sentence in the Description section:

    "Indicates which channels given in the request were not scanned (1 = not scanned, 0 = scanned or not requested)."

    You request scanning on one channel and it is probably scanned correctly. Remaining channels in the UnscannedChannels field are set to zero, because scanning procedure is not performed on them.

    Energy Detect List isn't null pointer, because your automatic variable:

    mlme_scan_req_t ret;

    contains some trash inside, which is later on propagated inside scan confirmation. Please try resetting automatic variable before scan request configuration:

    memset(&ret, 0, sizeof(mlme_scan_req_t));


Reply
  • Hi,

    here is something that may be useful for you.

    When you look at the UnscannedChannels parameter in the Table 68 (IEEE Std 802.15.4-2006 specification), you can see following sentence in the Description section:

    "Indicates which channels given in the request were not scanned (1 = not scanned, 0 = scanned or not requested)."

    You request scanning on one channel and it is probably scanned correctly. Remaining channels in the UnscannedChannels field are set to zero, because scanning procedure is not performed on them.

    Energy Detect List isn't null pointer, because your automatic variable:

    mlme_scan_req_t ret;

    contains some trash inside, which is later on propagated inside scan confirmation. Please try resetting automatic variable before scan request configuration:

    memset(&ret, 0, sizeof(mlme_scan_req_t));


Children
No Data
Related