Newer
Older
mbed-os / connectivity / drivers / 802.15.4_RF / TARGET_Silicon_Labs / TARGET_SL_RAIL / NanostackRfPhyEfr32.cpp
/*
 * Copyright (c) 2016 Silicon Laboratories, Inc. http://www.silabs.com
 * SPDX-License-Identifier: Apache-2.0
 * Licensed under the Apache License, Version 2.0 (the License); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "NanostackRfPhyEfr32.h"

#include <string.h>

#include "mbed.h"
#include "mbed_power_mgmt.h"
#include "ns_types.h"
#include "platform/arm_hal_interrupt.h"
#include "nanostack/platform/arm_hal_phy.h"
#include "mbed_toolchain.h"

#include "mbed-trace/mbed_trace.h"
#define  TRACE_GROUP  "SLRF"

/* Enable debug printing with SL_RADIO_DEBUG, override debug printer with SL_DEBUG_PRINT. */
#ifdef SL_RADIO_DEBUG
#ifndef SL_DEBUG_PRINT
#define SL_DEBUG_PRINT(...) tr_debug(__VA_ARGS__)
#endif
#else
#define SL_DEBUG_PRINT(...)
#endif

/* RF_THREAD_STACK_SIZE defines tack size for the RF adaptor thread */
#ifndef RF_THREAD_STACK_SIZE
#define RF_THREAD_STACK_SIZE 1024
#endif

/* RF_QUEUE_SIZE defines queue size for incoming messages */
#ifndef RF_QUEUE_SIZE
#define RF_QUEUE_SIZE  8
#endif

/* 802.15.4 maximum size of a single packet including PHY byte is 128 bytes */
#define MAC_PACKET_MAX_LENGTH   128
/* Offsets of prepended data in packet buffer */
#define MAC_PACKET_OFFSET_RSSI  0
#define MAC_PACKET_OFFSET_LQI   1
/* This driver prepends RSSI and LQI */
#define MAC_PACKET_INFO_LENGTH  2

/* RFThreadSignal used to signal from interrupts to the adaptor thread */
enum RFThreadSignal {
    SL_RX_DONE          = (1 << 1),
    SL_TX_DONE          = (1 << 2),
    SL_TX_ERR           = (1 << 3),
    SL_TX_TIMEOUT       = (1 << 4),
    SL_ACK_RECV         = (1 << 5),
    SL_ACK_TIMEOUT      = (1 << 6),
    SL_TXFIFO_ERR       = (1 << 7),
    SL_RXFIFO_ERR       = (1 << 8),
    SL_CAL_REQ          = (1 << 9),
    SL_RSSI_DONE        = (1 << 10),
    SL_QUEUE_FULL       = (1 << 11),

    // ACK pend flag can be signalled in addition to RX_DONE
    SL_ACK_PEND         = (1 << 30),
};

/*  Adaptor thread definitions */
static void rf_thread_loop(const void *arg);
static osThreadDef(rf_thread_loop, osPriorityRealtime, RF_THREAD_STACK_SIZE);
static osThreadId rf_thread_id = 0;

/* Queue for passing messages from interrupt to adaptor thread */
static volatile uint8_t rx_queue[RF_QUEUE_SIZE][MAC_PACKET_MAX_LENGTH + MAC_PACKET_INFO_LENGTH];
static volatile size_t rx_queue_head = 0;
static volatile size_t rx_queue_tail = 0;

/* Silicon Labs headers */
extern "C" {
#include "rail/rail.h"
#include "rail/pa.h"
#include "rail/pti.h"
#include "rail/ieee802154/rail_ieee802154.h"
}

/* RF driver data */
static phy_device_driver_s device_driver;
static int8_t  rf_radio_driver_id = -1;
static uint8_t MAC_address[8];
static uint16_t PAN_address;
static uint16_t short_address;

/* Driver instance handle */
static NanostackRfPhyEfr32 *rf = NULL;

/* Channel configurations */
static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK};
static const phy_rf_channel_configuration_s phy_subghz = {868300000U, 2000000U, 250000U, 11U, M_OQPSK};

static const phy_device_channel_page_s phy_channel_pages[] = {
    { CHANNEL_PAGE_0, &phy_24ghz},
    { CHANNEL_PAGE_2, &phy_subghz},
    { CHANNEL_PAGE_0, NULL}
};

/* Driver structures */
typedef enum {
    RADIO_UNINIT,
    RADIO_INITING,
    RADIO_IDLE,
    RADIO_TX,
    RADIO_RX,
    RADIO_CALIBRATION
} siliconlabs_modem_state_t;

static const RAIL_CsmaConfig_t csma_config = RAIL_CSMA_CONFIG_802_15_4_2003_2p4_GHz_OQPSK_CSMA;

#if defined(TARGET_EFR32_1)
#include "ieee802154_subg_efr32xg1_configurator_out.h"
#elif defined(TARGET_EFR32_12)
/* TODO: Add SubG support for EFR32_12 */
#else
#error "Not a valid target."
#endif

#if MBED_CONF_SL_RAIL_HAS_SUBGIG
static RAIL_ChannelConfigEntryAttr_t entry_868;
static RAIL_ChannelConfigEntryAttr_t entry_915;
static const RAIL_ChannelConfigEntry_t entry[] = {
    {
        .phyConfigDeltaAdd = NULL, // Add this to default config for this entry
        .baseFrequency = 868300000U,
        .channelSpacing = 600000U,
        .physicalChannelOffset = 0,
        .channelNumberStart = 0,
        .channelNumberEnd = 0,
        .maxPower = RAIL_TX_POWER_MAX,
        .attr = &entry_868
    },
    {
        .phyConfigDeltaAdd = NULL, // Add this to default config for this entry
        .baseFrequency = 906000000U,
        .channelSpacing = 2000000U,
        .physicalChannelOffset = 1,
        .channelNumberStart = 1,
        .channelNumberEnd = 10,
        .maxPower = RAIL_TX_POWER_MAX,
        .attr = &entry_915
    }
};
#endif

#if MBED_CONF_SL_RAIL_BAND == 868
#if !MBED_CONF_SL_RAIL_HAS_SUBGIG
#error "Sub-Gigahertz band is not supported on this target."
#endif
static const RAIL_ChannelConfig_t channels = {
    ieee802154_config_863,
    ieee802154_config_863_min,
    &entry[0],
    1
};
#elif MBED_CONF_SL_RAIL_BAND == 915
#if !MBED_CONF_SL_RAIL_HAS_SUBGIG
#error "Sub-Gigahertz band is not supported on this target."
#endif
static const RAIL_ChannelConfig_t channels = {
    ieee802154_config_915,
    ieee802154_config_915_min,
    &entry[1],
    1
};
#elif MBED_CONF_SL_RAIL_BAND == 2400
#ifndef MBED_CONF_SL_RAIL_HAS_2P4
#error "2.4GHz band is not supported on this target."
#endif
#else
#error "sl-rail.band is not correctly defined"
#endif

#if defined (MBED_CONF_SL_RAIL_HAS_2P4)
// Set up the PA for 2.4 GHz operation
static const RAIL_TxPowerConfig_t paInit2p4 = {
    .mode = RAIL_TX_POWER_MODE_2P4_HP,
    .voltage = 1800,
    .rampTime = 10,
};
#endif

#if MBED_CONF_SL_RAIL_HAS_SUBGIG
// Set up the PA for sub-GHz operation
static const RAIL_TxPowerConfig_t paInitSubGhz = {
    .mode = RAIL_TX_POWER_MODE_SUBGIG,
    .voltage = 1800,
    .rampTime = 10,
};
#endif

static const RAIL_StateTiming_t timings = {
    .idleToRx = 100,
    // Make txToRx slightly lower than desired to make sure we get to
    // RX in time
    .txToRx = 192 - 10,
    .idleToTx = 100,
    .rxToTx = 192,
    .rxSearchTimeout = 0,
    .txToRxSearchTimeout = 0
};

static const RAIL_IEEE802154_Config_t config = {
    .addresses = NULL,
    .ackConfig = {
        .enable = true,
        .ackTimeout = 1200,
        .rxTransitions = {
            .success = RAIL_RF_STATE_RX,
            .error = RAIL_RF_STATE_RX // ignored
        },
        .txTransitions = {
            .success = RAIL_RF_STATE_RX,
            .error = RAIL_RF_STATE_RX // ignored
        }
    },
    .timings = timings,
    .framesMask = RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES,
    .promiscuousMode = false,
    .isPanCoordinator = false
};

static volatile siliconlabs_modem_state_t radio_state = RADIO_UNINIT;
static volatile bool sleep_blocked = false;
static volatile int8_t channel = -1;
static volatile uint8_t current_tx_handle = 0;
static volatile uint8_t current_tx_sequence = 0;
static volatile bool waiting_for_ack = false;
static volatile bool data_pending = false, last_ack_pending_bit = false;
static volatile uint32_t last_tx = 0;
static volatile RAIL_Handle_t gRailHandle = NULL;
static uint8_t txFifo[256];

/* ARM_NWK_HAL prototypes */
static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr);
static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel);
static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr);
static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol);

/* Local function prototypes */
static bool rail_checkAndSwitchChannel(uint8_t channel);
static void RAILCb_RfReady(RAIL_Handle_t railHandle);
static void radioEventHandler(RAIL_Handle_t railHandle, RAIL_Events_t events);

static RAIL_Config_t railCfg = { // Must never be const
    .eventsCallback = &radioEventHandler,
    .protocol = NULL, // For BLE, pointer to a RAIL_BLE_State_t. For IEEE802.15.4 this must be NULL.
    .scheduler = NULL, // For MultiProtocol, pointer to a RAIL_SchedConfig_t
};

static void rf_thread_loop(const void *arg)
{
    SL_DEBUG_PRINT("rf_thread_loop: starting (id: %d)\n", (int)rf_thread_id);
    for (;;) {
        osEvent event = osSignalWait(0, osWaitForever);

        if (event.status != osEventSignal) {
            continue;
        }

        platform_enter_critical();

        if (event.value.signals & SL_RX_DONE) {
            while (rx_queue_tail != rx_queue_head) {
                uint8_t *packet = (uint8_t *) rx_queue[rx_queue_tail];
                SL_DEBUG_PRINT("rPKT %d\n", packet[MAC_PACKET_INFO_LENGTH] - 2);
                device_driver.phy_rx_cb(
                    &packet[MAC_PACKET_INFO_LENGTH + 1], /* Data payload for Nanostack starts at FCS */
                    packet[MAC_PACKET_INFO_LENGTH] - 2, /* Payload length is part of frame, but need to subtract CRC bytes */
                    packet[MAC_PACKET_OFFSET_LQI], /* LQI in second byte */
                    packet[MAC_PACKET_OFFSET_RSSI], /* RSSI in first byte */
                    rf_radio_driver_id);
                rx_queue_tail = (rx_queue_tail + 1) % RF_QUEUE_SIZE;
            }

        } else if (event.value.signals & SL_TX_DONE) {
            device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                         current_tx_handle,
                                         PHY_LINK_TX_SUCCESS,
                                         1,
                                         1);
        } else if (event.value.signals & SL_ACK_RECV) {
            device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                         current_tx_handle,
                                         (event.value.signals & SL_ACK_PEND) ? PHY_LINK_TX_DONE_PENDING : PHY_LINK_TX_DONE,
                                         1,
                                         1);
        } else if (event.value.signals & SL_ACK_TIMEOUT) {
            waiting_for_ack = false;
            device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                         current_tx_handle,
                                         PHY_LINK_TX_FAIL,
                                         1,
                                         1);
        } else if (event.value.signals & SL_TX_ERR) {
            device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                         current_tx_handle,
                                         PHY_LINK_CCA_FAIL,
                                         8,
                                         1);
        } else if (event.value.signals & SL_TX_TIMEOUT) {
            device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                         current_tx_handle,
                                         PHY_LINK_CCA_FAIL,
                                         8,
                                         1);
        } else if (event.value.signals & SL_CAL_REQ) {
            SL_DEBUG_PRINT("rf_thread_loop: SL_CAL_REQ signal received (unhandled)\n");
        } else if (event.value.signals & SL_RXFIFO_ERR) {
            SL_DEBUG_PRINT("rf_thread_loop: SL_RXFIFO_ERR signal received (unhandled)\n");
        } else if (event.value.signals & SL_TXFIFO_ERR) {
            SL_DEBUG_PRINT("rf_thread_loop: SL_TXFIFO_ERR signal received (unhandled)\n");
        } else if (event.value.signals & SL_QUEUE_FULL) {
            SL_DEBUG_PRINT("rf_thread_loop: SL_QUEUE_FULL signal received (packet dropped)\n");
        } else {
            SL_DEBUG_PRINT("rf_thread_loop unhandled event status: %d value: %d\n", event.status, (int)event.value.signals);
        }

        platform_exit_critical();
    }
}

/*============ CODE =========*/

/*
 * \brief Function initialises and registers the RF driver.
 *
 * \param none
 *
 * \return rf_radio_driver_id Driver ID given by NET library
 */
static int8_t rf_device_register(void)
{
    // If we already exist, bail.
    if (radio_state != RADIO_UNINIT) {
        return -1;
    }

    SL_DEBUG_PRINT("rf_device_register: entry\n");

    // Set up RAIL
    // Initialize the RAIL library and any internal state it requires
    gRailHandle = RAIL_Init(&railCfg, &RAILCb_RfReady);

    // Configure calibration settings
    RAIL_ConfigCal(gRailHandle, RAIL_CAL_ALL);

    // Set up library for IEEE802.15.4 PHY operation
#if (MBED_CONF_SL_RAIL_BAND == 2400)
    RAIL_IEEE802154_Config2p4GHzRadio(gRailHandle);
    channel = 11;
#elif (MBED_CONF_SL_RAIL_BAND == 915)
    RAIL_ConfigChannels(gRailHandle, &channels, NULL);
    channel = 1;
#elif (MBED_CONF_SL_RAIL_BAND == 868)
    RAIL_ConfigChannels(gRailHandle, &channels, NULL);
    channel = 0;
#endif

    // Enable 802.15.4 acceleration features
    RAIL_IEEE802154_Init(gRailHandle, &config);

    // Fire all events by default
    RAIL_ConfigEvents(gRailHandle,
                      RAIL_EVENTS_ALL,
                      RAIL_EVENTS_ALL);

    // Setup the transmit buffer
    RAIL_SetTxFifo(gRailHandle, txFifo, 0, sizeof(txFifo));

#if MBED_CONF_SL_RAIL_BAND == 2400
    if (RAIL_ConfigTxPower(gRailHandle, &paInit2p4) != RAIL_STATUS_NO_ERROR) {
        // Error: The PA could not be initialized due to an improper configuration.
        // Please ensure your configuration is valid for the selected part.
        while (1) ;
    }
#elif (MBED_CONF_SL_RAIL_BAND == 915) || (MBED_CONF_SL_RAIL_BAND == 868)
    if (RAIL_ConfigTxPower(gRailHandle, &paInitSubGhz) != RAIL_STATUS_NO_ERROR) {
        // Error: The PA could not be initialized due to an improper configuration.
        // Please ensure your configuration is valid for the selected part.
        while (1) ;
    }
#endif
    // Set the output power to the maximum supported by this chip
    RAIL_SetTxPower(gRailHandle, 255);

    // Set up PTI since it makes life so much easier
#if defined(MBED_CONF_SL_RAIL_PTI) && (MBED_CONF_SL_RAIL_PTI == 1)
    RAIL_PtiConfig_t ptiConfig = {
        MBED_CONF_SL_RAIL_PTI_MODE,
        MBED_CONF_SL_RAIL_PTI_BAUDRATE,
        MBED_CONF_SL_RAIL_PTI_DOUT_LOCATION,
        MBED_CONF_SL_RAIL_PTI_DOUT_PORT,
        MBED_CONF_SL_RAIL_PTI_DOUT_PIN,
        MBED_CONF_SL_RAIL_PTI_DCLK_LOCATION,
        MBED_CONF_SL_RAIL_PTI_DCLK_PORT,
        MBED_CONF_SL_RAIL_PTI_DCLK_PIN,
        MBED_CONF_SL_RAIL_PTI_DFRAME_LOCATION,
        MBED_CONF_SL_RAIL_PTI_DFRAME_PORT,
        MBED_CONF_SL_RAIL_PTI_DFRAME_PIN
    };

    // Initialize the Packet Trace Interface (PTI) for the EFR32
    RAIL_ConfigPti(RAIL_EFR32_HANDLE, &ptiConfig);
    // Enable Packet Trace (PTI)
    RAIL_EnablePti(RAIL_EFR32_HANDLE, true);
#endif

    /* Get real MAC address */
    /* MAC is stored MSB first */
    memcpy(MAC_address, (const void *)&DEVINFO->UNIQUEH, 4);
    memcpy(&MAC_address[4], (const void *)&DEVINFO->UNIQUEL, 4);

    /*Set pointer to MAC address*/
    device_driver.PHY_MAC = MAC_address;
    device_driver.driver_description = (char *)"EFR32_154";

    /*Type of RF PHY*/
#if MBED_CONF_SL_RAIL_BAND == 2400
    device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE;
#elif (MBED_CONF_SL_RAIL_BAND == 915) || (MBED_CONF_SL_RAIL_BAND == 868)
    device_driver.link_type = PHY_LINK_15_4_SUBGHZ_TYPE;
#endif

    device_driver.phy_channel_pages = phy_channel_pages;
    /*Maximum size of payload is 127*/
    device_driver.phy_MTU = 127;
    /*1 byte header in PHY layer (length)*/
    device_driver.phy_header_length = 1;
    /*No tail in PHY layer*/
    device_driver.phy_tail_length = 0;
    /*Set address write function*/
    device_driver.address_write = &rf_address_write;
    /*Set RF extension function*/
    device_driver.extension = &rf_extension;
    /*Set RF state control function*/
    device_driver.state_control = &rf_interface_state_control;
    /*Set transmit function*/
    device_driver.tx = &rf_start_cca;
    /*Upper layer callbacks init to NULL, get populated by arm_net_phy_register*/
    device_driver.phy_rx_cb = NULL;
    device_driver.phy_tx_done_cb = NULL;
    /*Virtual upper data callback init to NULL*/
    device_driver.arm_net_virtual_rx_cb = NULL;
    device_driver.arm_net_virtual_tx_cb = NULL;

    /*Register device driver*/
    rf_radio_driver_id = arm_net_phy_register(&device_driver);

    // If the radio hasn't called the ready callback by now, place it in the initing state
    if (radio_state == RADIO_UNINIT) {
        radio_state = RADIO_INITING;
    }

#ifdef MBED_CONF_RTOS_PRESENT
    rx_queue_head = 0;
    rx_queue_tail = 0;
    rf_thread_id = osThreadCreate(osThread(rf_thread_loop), NULL);
#endif

    return rf_radio_driver_id;
}

/*
 * \brief Function unregisters the RF driver.
 *
 * \param none
 *
 * \return none
 */
static void rf_device_unregister(void)
{
    arm_net_phy_unregister(rf_radio_driver_id);
    if (sleep_blocked) {
        sleep_manager_unlock_deep_sleep();
        sleep_blocked = false;
    }
}

/*
 * \brief Function starts the CCA process before starting data transmission and copies the data to RF TX FIFO.
 *
 * \param data_ptr Pointer to TX data
 * \param data_length Length of the TX data
 * \param tx_handle Handle to transmission
 * \return 0 Success
 * \return -1 Busy
 */
static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol)
{
    switch (radio_state) {
        case RADIO_UNINIT:
            SL_DEBUG_PRINT("rf_start_cca: Radio uninit\n");
            return -1;
        case RADIO_INITING:
            SL_DEBUG_PRINT("rf_start_cca: Radio initing\n");
            return -1;
        case RADIO_CALIBRATION:
            SL_DEBUG_PRINT("rf_start_cca: Radio calibrating\n");
            return -1;
        case RADIO_TX:
            SL_DEBUG_PRINT("rf_start_cca: Radio in TX mode\n");
            return -1;
        case RADIO_IDLE:
        case RADIO_RX:
            // If we're still waiting for an ACK, don't mess up the internal state
            if (waiting_for_ack || RAIL_GetRadioState(gRailHandle) == RAIL_RF_STATE_TX) {
                if ((RAIL_GetTime() - last_tx) < 30000) {
                    SL_DEBUG_PRINT("rf_start_cca: Still waiting on previous ACK\n");
                    return -1;
                } else {
                    SL_DEBUG_PRINT("rf_start_cca: TXerr\n");
                }
            }

            platform_enter_critical();

            /* Since we set up Nanostack to give us a 1-byte PHY header, we get the one extra byte at the start of data_ptr
             * and need to populate it with the MAC-frame length byte (including the 2-byte hardware-inserted CRC) */
            data_ptr[0] = data_length + 2;

            RAIL_Idle(gRailHandle, RAIL_IDLE_ABORT, true);
            RAIL_WriteTxFifo(gRailHandle, data_ptr, data_length + 1, true);
            radio_state = RADIO_TX;

            RAIL_TxOptions_t txOpt = RAIL_TX_OPTIONS_DEFAULT;
            //Check to see whether we'll be waiting for an ACK
            if (data_ptr[1] & (1 << 5)) {
                txOpt |= RAIL_TX_OPTION_WAIT_FOR_ACK;
                waiting_for_ack = true;
            } else {
                waiting_for_ack = false;
            }

            SL_DEBUG_PRINT("rf_start_cca: Called TX, len %d, chan %d, ack %d\n", data_length, channel, waiting_for_ack ? 1 : 0);

            if (RAIL_StartCcaCsmaTx(gRailHandle, channel, txOpt, &csma_config, NULL) == 0) {
                //Save packet number and sequence
                current_tx_handle = tx_handle;
                current_tx_sequence = data_ptr[3];
                platform_exit_critical();
                return 0;
            } else {
                RAIL_Idle(gRailHandle, RAIL_IDLE_ABORT, true);
                RAIL_StartRx(gRailHandle, channel, NULL);
                radio_state = RADIO_RX;
                platform_exit_critical();
                return -1;
            }
    }
    //Should never get here...
    return -1;
}

/*
 * \brief Function gives the control of RF states to MAC.
 *
 * \param new_state RF state
 * \param rf_channel RF channel
 *
 * \return 0 Success
 */
static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
{
    int8_t ret_val = 0;
    switch (new_state) {
        /* Reset PHY driver and set to idle */
        case PHY_INTERFACE_RESET:
            RAIL_Idle(gRailHandle, RAIL_IDLE_FORCE_SHUTDOWN_CLEAR_FLAGS, true);
            radio_state = RADIO_IDLE;
            if (sleep_blocked) {
                sleep_manager_unlock_deep_sleep();
                sleep_blocked = false;
            }
            break;
        /* Disable PHY Interface driver */
        case PHY_INTERFACE_DOWN:
            RAIL_Idle(gRailHandle, RAIL_IDLE_FORCE_SHUTDOWN_CLEAR_FLAGS, true);
            radio_state = RADIO_IDLE;
            if (sleep_blocked) {
                sleep_manager_unlock_deep_sleep();
                sleep_blocked = false;
            }
            break;
        /* Enable RX */
        case PHY_INTERFACE_UP:
            if (rail_checkAndSwitchChannel(rf_channel)) {
                RAIL_Idle(gRailHandle, RAIL_IDLE_FORCE_SHUTDOWN_CLEAR_FLAGS, true);
                RAIL_IEEE802154_SetPromiscuousMode(gRailHandle, false);
                RAIL_StartRx(gRailHandle, channel, NULL);
                radio_state = RADIO_RX;
                if (!sleep_blocked) {
                    /* RX can only happen in EM0/1*/
                    sleep_manager_lock_deep_sleep();
                    sleep_blocked = true;
                }
            } else {
                ret_val = -1;
            }
            break;
        /* Enable wireless interface ED scan mode */
        case PHY_INTERFACE_RX_ENERGY_STATE:
            SL_DEBUG_PRINT("rf_interface_state_control: Energy det req\n");
            // TODO: implement energy detection
            break;
        /* Enable RX in promiscuous mode (aka no address filtering) */
        case PHY_INTERFACE_SNIFFER_STATE:
            if (rail_checkAndSwitchChannel(rf_channel)) {
                RAIL_Idle(gRailHandle, RAIL_IDLE_FORCE_SHUTDOWN_CLEAR_FLAGS, true);
                RAIL_IEEE802154_SetPromiscuousMode(gRailHandle, true);
                RAIL_StartRx(gRailHandle, channel, NULL);
                radio_state = RADIO_RX;
                if (!sleep_blocked) {
                    /* RX can only happen in EM0/1*/
                    sleep_manager_lock_deep_sleep();
                    sleep_blocked = true;
                }
            } else {
                ret_val = -1;
            }
            break;
    }
    return ret_val;
}

/*
 * \brief Function controls the ACK pending, channel setting and energy detection.
 *
 * \param extension_type Type of control
 * \param data_ptr Data from NET library
 *
 * \return 0 Success
 */
static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr)
{
    switch (extension_type) {
        /* Control MAC pending bit for Indirect data transmission */
        case PHY_EXTENSION_CTRL_PENDING_BIT:
            if (*data_ptr) {
                data_pending = true;
            } else {
                data_pending = false;
            }
            break;
        /* Return frame pending bit from last received ACK */
        case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
            if (last_ack_pending_bit) {
                *data_ptr = 0xFF;
            } else {
                *data_ptr = 0;
            }
            break;
        /* Set channel */
        case PHY_EXTENSION_SET_CHANNEL:
            channel = *data_ptr;
            break;
        /* Read energy on the channel */
        case PHY_EXTENSION_READ_CHANNEL_ENERGY:
            // TODO: implement energy detection
            *data_ptr = 0;
            break;
        /* Read status of the link */
        case PHY_EXTENSION_READ_LINK_STATUS:
            // TODO: return accurate value here
            SL_DEBUG_PRINT("rf_extension: Trying to read link status\n");
            break;
        /* Convert between LQI and RSSI */
        case PHY_EXTENSION_CONVERT_SIGNAL_INFO:
            // TODO: return accurate value here
            SL_DEBUG_PRINT("rf_extension: Trying to read signal info\n");
            break;
        case PHY_EXTENSION_ACCEPT_ANY_BEACON:
            SL_DEBUG_PRINT("rf_extension: Trying to accept any beacon\n");
            break;
    }
    return 0;
}

/*
 * \brief Function sets the addresses to RF address filters.
 *
 * \param address_type Type of address
 * \param address_ptr Pointer to given address
 *
 * \return 0 Success
 */
static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
{
    int8_t ret_val = 0;
    switch (address_type) {
        /*Set 48-bit address*/
        case PHY_MAC_48BIT:
            // 15.4 does not support 48-bit addressing
            ret_val = -1;
            break;
        /*Set 64-bit MAC address*/
        case PHY_MAC_64BIT:
            /* Store MAC in MSB order */
            memcpy(MAC_address, address_ptr, 8);
            SL_DEBUG_PRINT("rf_address_write: MACw ");
            for (unsigned int i = 0; i < sizeof(MAC_address); i ++) {
                SL_DEBUG_PRINT("%02x:", MAC_address[i]);
            }
            SL_DEBUG_PRINT("\n");
            /* Pass MAC to the RF driver in LSB order */
            uint8_t MAC_reversed[8];
            for (unsigned int i = 0; i < sizeof(MAC_address); i ++) {
                MAC_reversed[i] = MAC_address[sizeof(MAC_address) - 1 - i];
            }
            RAIL_IEEE802154_SetLongAddress(gRailHandle, MAC_reversed, 0);
            break;
        /*Set 16-bit address*/
        case PHY_MAC_16BIT:
            short_address = address_ptr[0] << 8 | address_ptr[1];
            RAIL_IEEE802154_SetShortAddress(gRailHandle, short_address, 0);
            break;
        /*Set PAN Id*/
        case PHY_MAC_PANID:
            PAN_address = address_ptr[0] << 8 | address_ptr[1];
            RAIL_IEEE802154_SetPanId(gRailHandle, PAN_address, 0);
            break;
    }
    return ret_val;
}

/*****************************************************************************/
/*****************************************************************************/

static void rf_if_lock(void)
{
    platform_enter_critical();
}

static void rf_if_unlock(void)
{
    platform_exit_critical();
}

NanostackRfPhyEfr32::NanostackRfPhyEfr32() : NanostackRfPhy()
{
    // Do nothing
}

NanostackRfPhyEfr32::~NanostackRfPhyEfr32()
{
    rf_unregister();
}

int8_t NanostackRfPhyEfr32::rf_register()
{

    rf_if_lock();

    if (rf != NULL) {
        rf_if_unlock();
        error("Multiple registrations of NanostackRfPhyEfr32 not supported");
        return -1;
    }

    int8_t radio_id = rf_device_register();
    if (radio_id < 0) {
        rf = NULL;
    } else {
        rf = this;
    }

    rf_if_unlock();
    return radio_id;
}

void NanostackRfPhyEfr32::rf_unregister()
{
    rf_if_lock();

    if (rf != this) {
        rf_if_unlock();
        return;
    }

    rf_device_unregister();
    rf = NULL;

    rf_if_unlock();
}

void NanostackRfPhyEfr32::get_mac_address(uint8_t *mac)
{
    rf_if_lock();

    memcpy(mac, MAC_address, sizeof(MAC_address));

    rf_if_unlock();
}

void NanostackRfPhyEfr32::set_mac_address(uint8_t *mac)
{
    rf_if_lock();

    if (NULL != rf) {
        error("NanostackRfPhyEfr32 cannot change mac address when running");
        rf_if_unlock();
        return;
    }

    memcpy(MAC_address, mac, sizeof(MAC_address));

    rf_if_unlock();
}

uint32_t NanostackRfPhyEfr32::get_driver_version()
{
    RAIL_Version_t railversion;
    RAIL_GetVersion(&railversion, false);

    return (railversion.major << 24) |
           (railversion.minor << 16) |
           (railversion.rev   << 8)  |
           (railversion.build);
}


//====================== RAIL-defined callbacks =========================
/**
 * Callback that lets the app know when the radio has finished init
 * and is ready.
 */
static void RAILCb_RfReady(RAIL_Handle_t handle)
{
    (void) handle;
    radio_state = RADIO_IDLE;
}

/**
 * Function to check the requested channel against the current channel,
 * and change the radio configuration if necessary.
 *
 * @param channel The new channel number requested
 * @return bool True if able to switch to the requested channel
 *
 */
static bool rail_checkAndSwitchChannel(uint8_t newChannel)
{
    if (channel == newChannel) {
        return true;
    }

    if (newChannel > 0 && newChannel < 11) {
        if (MBED_CONF_SL_RAIL_BAND == 915) {
            channel = newChannel;
            return true;
        } else {
            return false;
        }
    } else if (newChannel >= 11 && newChannel <= 26) {
        if (MBED_CONF_SL_RAIL_BAND == 2400) {
            channel = newChannel;
            return true;
        } else {
            return false;
        }
    } else {
        return false;
    }
}

/**
 * Event handler for RAIL-fired events. Usually gets called from IRQ context.
 * Due to IRQ latency and tailchaining, multiple event flags might be set simultaneously,
 * so we have to check all of them */
static void radioEventHandler(RAIL_Handle_t railHandle,
                              RAIL_Events_t events)
{
    /* RAIL_Events_t is a 64-bit event mask, but a thread only supports 32
     * signal bits. This means we have to convert from a RAIL event mask to
     * our own custom event mask. */
    if (railHandle != gRailHandle) {
        return;
    }

#ifdef MBED_CONF_RTOS_PRESENT
    if (rf_thread_id == 0) {
        return;
    }
#endif

    size_t index = 0;
    do {
        if (events & 1ull) {
            switch (index) {
                /*
                * Occurs when the AGC averaged RSSI is done.
                * It occurs in response to RAIL_StartAverageRssi() to indicate that the
                * hardware has completed averaging. Call \ref RAIL_GetAverageRssi to get the
                * result.
                */
                case RAIL_EVENT_RSSI_AVERAGE_DONE_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                    osSignalSet(rf_thread_id, SL_RSSI_DONE);
#else
                    SL_DEBUG_PRINT("RSSI done (%d)\n", RAIL_GetAverageRssi(gRailHandle));
#endif
                    break;
                /*
                * Notifies the application when searching for an ACK has timed
                * out. This event occurs whenever the timeout for searching for an
                * ACK is exceeded.
                */
                case RAIL_EVENT_RX_ACK_TIMEOUT_SHIFT:
                    if (waiting_for_ack) {
                        waiting_for_ack = false;
#ifdef MBED_CONF_RTOS_PRESENT
                        osSignalSet(rf_thread_id, SL_ACK_TIMEOUT);
#else
                        device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                                     current_tx_handle,
                                                     PHY_LINK_TX_FAIL,
                                                     1,
                                                     1);
#endif
                    }
                    break;
                /*
                * Occurs when the receive FIFO exceeds the configured threshold
                * value. Call \ref RAIL_GetRxFifoBytesAvailable to get the number of bytes
                * available.
                */
                case RAIL_EVENT_RX_FIFO_ALMOST_FULL_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                    osSignalSet(rf_thread_id, SL_RXFIFO_ERR);
#else
                    SL_DEBUG_PRINT("RX near full (%d)\n", RAIL_GetRxFifoBytesAvailable(gRailHandle));
#endif
                    break;
                /*
                * Occurs whenever a packet is received.
                * Call RAIL_GetRxPacketInfo() to get basic packet information along
                * with a handle to this packet for subsequent use with
                * RAIL_PeekRxPacket(), RAIL_GetRxPacketDetails(),
                * RAIL_HoldRxPacket(), and RAIL_ReleaseRxPacket() as needed.
                *
                * If \ref RAIL_RX_OPTION_IGNORE_CRC_ERRORS is set, this event also occurs
                * for packets with CRC errors.
                */
                case RAIL_EVENT_RX_PACKET_RECEIVED_SHIFT: {
                    /* Get RX packet that got signaled */
                    RAIL_RxPacketInfo_t rxPacketInfo;
                    RAIL_RxPacketHandle_t rxHandle = RAIL_GetRxPacketInfo(gRailHandle,
                                                                          RAIL_RX_PACKET_HANDLE_NEWEST,
                                                                          &rxPacketInfo
                                                                         );

                    /* Only process the packet if it had a correct CRC */
                    if (rxPacketInfo.packetStatus == RAIL_RX_PACKET_READY_SUCCESS) {
                        uint8_t header[4];
                        RAIL_PeekRxPacket(gRailHandle, rxHandle, header, 4, 0);

                        /* If this is an ACK, deal with it early */
                        if ((header[0] == 5) &&
                                (header[3] == current_tx_sequence)  &&
                                waiting_for_ack) {
                            /* Tell the radio to not ACK an ACK */
                            RAIL_CancelAutoAck(gRailHandle);
                            waiting_for_ack = false;
                            /* Save the pending bit */
                            last_ack_pending_bit = (header[1] & (1 << 4)) != 0;
                            /* Release packet */
                            RAIL_ReleaseRxPacket(gRailHandle, rxHandle);
                            /* Tell the stack we got an ACK */
#ifdef MBED_CONF_RTOS_PRESENT
                            osSignalSet(rf_thread_id, SL_ACK_RECV | (last_ack_pending_bit ? SL_ACK_PEND : 0));
#else
                            SL_DEBUG_PRINT("rACK\n");
                            device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                                         current_tx_handle,
                                                         last_ack_pending_bit ? PHY_LINK_TX_DONE_PENDING : PHY_LINK_TX_DONE,
                                                         1,
                                                         1);
#endif
                        } else {
                            /* Get RSSI and LQI information about this packet */
                            RAIL_RxPacketDetails_t rxPacketDetails;
                            rxPacketDetails.timeReceived.timePosition = RAIL_PACKET_TIME_DEFAULT;
                            rxPacketDetails.timeReceived.totalPacketBytes = 0;
                            RAIL_GetRxPacketDetails(gRailHandle, rxHandle, &rxPacketDetails);

#ifdef MBED_CONF_RTOS_PRESENT
                            /* Drop this packet if we're out of space */
                            if (((rx_queue_head + 1) % RF_QUEUE_SIZE) == rx_queue_tail) {
                                osSignalSet(rf_thread_id, SL_QUEUE_FULL);
                                RAIL_ReleaseRxPacket(gRailHandle, rxHandle);
                                break;
                            }

                            /* Copy into queue */
                            uint8_t *packetBuffer = (uint8_t *)rx_queue[rx_queue_head];
#else
                            /* Packet going temporarily onto stack for bare-metal apps */
                            uint8_t packetBuffer[MAC_PACKET_MAX_LENGTH + MAC_PACKET_INFO_LENGTH];
#endif
                            /* First two bytes are RSSI and LQI, respecitvely */
                            packetBuffer[MAC_PACKET_OFFSET_RSSI] = (uint8_t)rxPacketDetails.rssi;
                            packetBuffer[MAC_PACKET_OFFSET_LQI] = (uint8_t)rxPacketDetails.lqi;

                            /* Copy packet payload from circular FIFO into contiguous memory */
                            RAIL_CopyRxPacket(&packetBuffer[MAC_PACKET_INFO_LENGTH], &rxPacketInfo);

                            /* Release RAIL resources early */
                            RAIL_ReleaseRxPacket(gRailHandle, rxHandle);

                            /* Figure out whether we want to not ACK this packet */

                            /*
                            * packetBuffer[0] = length
                            * dataLength = length w/o length byte
                            * packetBuffer[1:2] = 0x61C9 -> 0b01100001 0b1100 1001 (version 1, dest 3, src 2, ACKreq, type = 1)
                            *   [1] => b[0:2] frame type, b[3] = security enabled, b[4] = frame pending, b[5] = ACKreq, b[6] = intrapan
                            *   [2] => b[2:3] destmode, b[4:5] version, b[6:7] srcmode
                            */
                            if ((packetBuffer[MAC_PACKET_INFO_LENGTH + 1] & (1 << 5)) == 0) {
                                /* Cancel the ACK if the sender did not request one */
                                RAIL_CancelAutoAck(gRailHandle);
                            }
#ifdef MBED_CONF_RTOS_PRESENT
                            rx_queue_head = (rx_queue_head + 1) % RF_QUEUE_SIZE;
                            osSignalSet(rf_thread_id, SL_RX_DONE);
#else
                            SL_DEBUG_PRINT("rPKT %d\n", packetBuffer[MAC_PACKET_INFO_LENGTH] - 2);
                            device_driver.phy_rx_cb(&packetBuffer[MAC_PACKET_INFO_LENGTH + 1], /* Data payload for Nanostack starts at FCS */
                                                    packetBuffer[MAC_PACKET_INFO_LENGTH] - 2, /* Payload length is part of frame, but need to subtract CRC bytes */
                                                    packetBuffer[MAC_PACKET_OFFSET_LQI], /* LQI in second byte */
                                                    packetBuffer[MAC_PACKET_OFFSET_RSSI], /* RSSI in first byte */
                                                    rf_radio_driver_id);
#endif
                        }
                    }
                }
                break;
                /* Event for preamble detection */
                case RAIL_EVENT_RX_PREAMBLE_DETECT_SHIFT:
                    break;
                /* Event for detection of the first sync word */
                case RAIL_EVENT_RX_SYNC1_DETECT_SHIFT:
                    break;
                /** Event for detection of the second sync word */
                case RAIL_EVENT_RX_SYNC2_DETECT_SHIFT:
                    break;
                /* Event for detection of frame errors
                *
                * For efr32xg1x parts, frame errors include violations of variable length
                * minimum/maximum limits, frame coding errors, and CRC errors. If \ref
                * RAIL_RX_OPTION_IGNORE_CRC_ERRORS is set, \ref RAIL_EVENT_RX_FRAME_ERROR
                * will not occur for CRC errors.
                */
                case RAIL_EVENT_RX_FRAME_ERROR_SHIFT:
                    break;
                /* Occurs when RX buffer is full */
                case RAIL_EVENT_RX_FIFO_OVERFLOW_SHIFT:
                    break;
                /* Occurs when a packet is address filtered */
                case RAIL_EVENT_RX_ADDRESS_FILTERED_SHIFT:
                    break;
                /* Occurs when an RX event times out */
                case RAIL_EVENT_RX_TIMEOUT_SHIFT:
                    break;
                /* Occurs when the scheduled RX window ends */
                case RAIL_EVENT_RX_SCHEDULED_RX_END_SHIFT:
                    break;
                /* An event for an aborted packet. It is triggered when a more specific
                *  reason isn't known for why the packet was aborted (e.g.
                *  \ref RAIL_EVENT_RX_ADDRESS_FILTERED). */
                case RAIL_EVENT_RX_PACKET_ABORTED_SHIFT:
                    break;
                /*
                * Occurs when the packet has passed any configured address and frame
                * filtering options.
                */
                case RAIL_EVENT_RX_FILTER_PASSED_SHIFT:
                    break;
                /* Occurs when modem timing is lost */
                case RAIL_EVENT_RX_TIMING_LOST_SHIFT:
                    break;
                /* Occurs when modem timing is detected */
                case RAIL_EVENT_RX_TIMING_DETECT_SHIFT:
                    break;
                /*
                * Indicates a Data Request is being received when using IEEE 802.15.4
                * functionality. This occurs when the command byte of an incoming frame is
                * for a data request, which requests an ACK. This callback is called before
                * the packet is fully received to allow the node to have more time to decide
                * whether to set the frame pending in the outgoing ACK. This event only ever
                * occurs if the RAIL IEEE 802.15.4 functionality is enabled.
                *
                * Call \ref RAIL_IEEE802154_GetAddress to get the source address of the
                * packet.
                */
                case RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND_SHIFT:
                    if (data_pending) {
                        RAIL_IEEE802154_SetFramePending(gRailHandle);
                    }
                    break;

                // TX Event Bitmasks

                /*
                * Occurs when the transmit FIFO falls under the configured
                * threshold value. It only occurs if a rising edge occurs across this
                * threshold. This event does not occur on initailization or after resetting
                * the transmit FIFO with RAIL_ResetFifo().
                * Call \ref RAIL_GetTxFifoSpaceAvailable to get the number of bytes
                * available in the transmit FIFO at the time of the callback dispatch.
                */
                case RAIL_EVENT_TX_FIFO_ALMOST_EMPTY_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                    osSignalSet(rf_thread_id, SL_TXFIFO_ERR);
#else
                    SL_DEBUG_PRINT("TX near empty (%d)\n", spaceAvailable);
#endif
                    break;
                /*
                * Interrupt level event to signify when the packet was sent.
                * Call RAIL_GetTxPacketDetails() to get information about the packet
                * that was transmitted.
                * @note that this structure is only valid during the timeframe of the
                *   \ref RAIL_Config_t::eventsCallback.
                */
                case RAIL_EVENT_TX_PACKET_SENT_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                    osSignalSet(rf_thread_id, SL_TX_DONE);
#else
                    if (device_driver.phy_tx_done_cb != NULL) {
                        device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                                     current_tx_handle,
                                                     // Normally we'd switch on ACK requested here, but Nanostack does that for us.
                                                     PHY_LINK_TX_SUCCESS,
                                                     // Succeeded, so how many times we tried is really not relevant.
                                                     1,
                                                     1);
                    }
#endif
                    last_tx = RAIL_GetTime();
                    radio_state = RADIO_RX;
                    break;
                /*
                * An interrupt level event to signify when the packet was sent.
                * Call RAIL_GetTxPacketDetails() to get information about the packet
                * that was transmitted.
                * @note This structure is only valid during the timeframe of the
                *   \ref RAIL_Config_t::eventsCallback.
                */
                case RAIL_EVENT_TXACK_PACKET_SENT_SHIFT:
                    break;
                /* Occurs when a TX is aborted by the user */
                case RAIL_EVENT_TX_ABORTED_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                    osSignalSet(rf_thread_id, SL_TX_TIMEOUT);
#else
                    device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                                 current_tx_handle,
                                                 PHY_LINK_CCA_FAIL,
                                                 8,
                                                 1);
#endif
                    waiting_for_ack = false;
                    radio_state = RADIO_RX;
                    break;
                /* Occurs when a TX ACK is aborted by the user */
                case RAIL_EVENT_TXACK_ABORTED_SHIFT:
                    break;
                /* Occurs when a TX is blocked by something like PTA or RHO */
                case RAIL_EVENT_TX_BLOCKED_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                    osSignalSet(rf_thread_id, SL_TX_TIMEOUT);
#else
                    device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                                 current_tx_handle,
                                                 PHY_LINK_CCA_FAIL,
                                                 8,
                                                 1);
#endif
                    waiting_for_ack = false;
                    radio_state = RADIO_RX;
                    break;
                /* Occurs when a TX ACK is blocked by something like PTA or RHO */
                case RAIL_EVENT_TXACK_BLOCKED_SHIFT:
                    break;
                /* Occurs when the TX buffer underflows */
                case RAIL_EVENT_TX_UNDERFLOW_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                    osSignalSet(rf_thread_id, SL_TX_TIMEOUT);
#else
                    device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                                 current_tx_handle,
                                                 PHY_LINK_CCA_FAIL,
                                                 8,
                                                 1);
#endif
                    waiting_for_ack = false;
                    radio_state = RADIO_RX;
                    break;
                /* Occurs when the buffer used for TX acking underflows */
                case RAIL_EVENT_TXACK_UNDERFLOW_SHIFT:
                    break;
                /* Occurs when CCA/CSMA/LBT succeeds */
                case RAIL_EVENT_TX_CHANNEL_CLEAR_SHIFT:
                    break;
                /* Occurs when CCA/CSMA/LBT fails */
                case RAIL_EVENT_TX_CHANNEL_BUSY_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                    osSignalSet(rf_thread_id, SL_TX_TIMEOUT);
#else
                    device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                                 current_tx_handle,
                                                 PHY_LINK_CCA_FAIL,
                                                 8,
                                                 1);
#endif
                    waiting_for_ack = false;
                    radio_state = RADIO_RX;
                    break;
                /* Occurs when a CCA check is being retried */
                case RAIL_EVENT_TX_CCA_RETRY_SHIFT:
                    break;
                /** Occurs when a clear channel assessment (CCA) is begun */
                case RAIL_EVENT_TX_START_CCA_SHIFT:
                    break;

                // Scheduler Event Bitmasks: Not used

                /* Event for when the scheduler switches away from this configuration */
                case RAIL_EVENT_CONFIG_UNSCHEDULED_SHIFT:
                    break;
                /* Event for when the scheduler switches to this configuration */
                case RAIL_EVENT_CONFIG_SCHEDULED_SHIFT:
                    break;
                /* Event for when the status of the scheduler changes */
                case RAIL_EVENT_SCHEDULER_STATUS_SHIFT:
                    break;

                // Other Event Bitmasks

                /*
                * Notifies the application that a calibration is needed.
                * It occurs whenever the RAIL library detects that a
                * calibration is needed. An application determines a valid
                * window to call \ref RAIL_Calibrate().
                */
                case RAIL_EVENT_CAL_NEEDED_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                    osSignalSet(rf_thread_id, SL_CAL_REQ);
#else
                    SL_DEBUG_PRINT("!!!! Calling for calibration\n");
#endif
                    break;
                default:
                    break;
            }
        }
        events = events >> 1;
        index += 1;
    } while (events != 0);
}

NanostackRfPhy &NanostackRfPhy::get_default_instance()
{
    static NanostackRfPhyEfr32 rf_phy;
    return rf_phy;
}