Newer
Older
mbed-os / features / nanostack / FEATURE_NANOSTACK / targets / TARGET_SL_RAIL / NanostackRfPhyEfr32.cpp
@Bartek Szatkowski Bartek Szatkowski on 28 Feb 2018 45 KB Add system_reset() function to Mbed OS
/*
 * 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


/* 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;

/* Queue for passing messages from interrupt to adaptor thread */
static volatile void* rx_queue[8];
static volatile size_t rx_queue_head;
static volatile size_t rx_queue_tail;

/* 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

#ifdef 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
#ifndef 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
#ifndef 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 defined (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[2] - 2);
                device_driver.phy_rx_cb(
                        &packet[3], /* Data payload for Nanostack starts at FCS */
                        packet[2] - 2, /* Payload length is part of frame, but need to subtract CRC bytes */
                        packet[1], /* LQI in second byte */
                        packet[0], /* RSSI in first byte */
                        rf_radio_driver_id);

                free(packet);
                rx_queue[rx_queue_tail] = NULL;
                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;

    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) {
                        /* 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);

                        /* Allocate a contiguous buffer for this packet's payload */
                        uint8_t* packetBuffer = (uint8_t*) malloc(rxPacketInfo.packetBytes + 2);
                        if(packetBuffer == NULL) {
                            SL_DEBUG_PRINT("Out of memory\n");
                            break;
                        }

                        /* First two bytes are RSSI and LQI, respecitvely */
                        packetBuffer[0] = (uint8_t)rxPacketDetails.rssi;
                        packetBuffer[1] = (uint8_t)rxPacketDetails.lqi;

                        /* Copy packet payload from circular FIFO into contiguous memory */
                        memcpy(&packetBuffer[2], rxPacketInfo.firstPortionData, rxPacketInfo.firstPortionBytes);
                        if (rxPacketInfo.firstPortionBytes < rxPacketInfo.packetBytes) {
                            memcpy(&packetBuffer[2+rxPacketInfo.firstPortionBytes],
                                   rxPacketInfo.lastPortionData,
                                   rxPacketInfo.packetBytes - rxPacketInfo.firstPortionBytes);
                        }

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

                        /* If this is an ACK, deal with it */
                        if( packetBuffer[2] == 5                         &&
                            packetBuffer[2+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 = (packetBuffer[2+1] & (1 << 4)) != 0;
                            /* 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
                            free(packetBuffer);
                        } else {
                            /* 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[2+1] & (1 << 5)) == 0 ) {
                                /* Cancel the ACK if the sender did not request one */
                                RAIL_CancelAutoAck(gRailHandle);
                            }
#ifdef MBED_CONF_RTOS_PRESENT
                            if (((rx_queue_head + 1) % RF_QUEUE_SIZE) != rx_queue_tail) {
                                rx_queue[rx_queue_head] = (void*)packetBuffer;
                                rx_queue_head = (rx_queue_head + 1) % RF_QUEUE_SIZE;
                                osSignalSet(rf_thread_id, SL_RX_DONE);
                            } else {
                                free(packetBuffer);
                                osSignalSet(rf_thread_id, SL_QUEUE_FULL);
                            }
#else
                            SL_DEBUG_PRINT("rPKT %d\n", rxPacket[2] - 2);
                            device_driver.phy_rx_cb(&rxPacket[3], /* Data payload for Nanostack starts at FCS */
                                                    rxPacket[2] - 2, /* Payload length is part of frame, but need to subtract CRC bytes */
                                                    rxPacket[1], /* LQI in second byte */
                                                    rxPacket[0], /* RSSI in first byte */
                                                    rf_radio_driver_id);
                            free(packetBuffer);
#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);
}