123r

Dependencies:   WNC14A2AInterface

Revision:
0:2563b0415d1f
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mcr20a-rf-driver/source/NanostackRfPhyMcr20a.cpp	Wed Apr 19 01:13:10 2017 +0000
@@ -0,0 +1,1782 @@
+/*
+ * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
+ * 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 "NanostackRfPhyMcr20a.h"
+#include "ns_types.h"
+#include "platform/arm_hal_interrupt.h"
+#include "nanostack/platform/arm_hal_phy.h"
+#include "toolchain.h"
+#include <string.h>
+
+/* Freescale headers which are for C files */
+extern "C" {
+#include "MCR20Drv.h"
+#include "MCR20Reg.h"
+#include "MCR20Overwrites.h"
+}
+
+
+#define RF_BUFFER_SIZE 128
+
+/*Radio RX and TX state definitions*/
+#define RFF_ON 0x01
+#define RFF_RX 0x02
+#define RFF_TX 0x04
+#define RFF_CCA 0x08
+
+#define RF_MODE_NORMAL  0
+#define RF_MODE_SNIFFER 1
+
+#define RF_CCA_THRESHOLD 75 /* -75 dBm */
+
+#define RF_TX_POWER_MAX 0
+
+/* PHY constants in symbols */
+#define gPhyWarmUpTime_c       9
+#define gPhySHRDuration_c     10
+#define gPhySymbolsPerOctet_c  2
+#define gPhyAckWaitDuration_c 54
+
+#define gCcaED_c               0
+#define gCcaCCA_MODE1_c        1
+
+#define gXcvrRunState_d       gXcvrPwrAutodoze_c
+#define gXcvrLowPowerState_d  gXcvrPwrHibernate_c
+
+
+/* MCR20A XCVR states */
+typedef enum xcvrState_tag{
+  gIdle_c,
+  gRX_c,
+  gTX_c,
+  gCCA_c,
+  gTR_c,
+  gCCCA_c,
+}xcvrState_t;
+
+/* MCR20A XCVR low power states */
+typedef enum xcvrPwrMode_tag{
+    gXcvrPwrIdle_c,
+    gXcvrPwrAutodoze_c,
+    gXcvrPwrDoze_c,
+    gXcvrPwrHibernate_c
+}xcvrPwrMode_t;
+
+
+/*RF Part Type*/
+typedef enum
+{
+    FREESCALE_UNKNOW_DEV = 0,
+    FREESCALE_MCR20A
+}rf_trx_part_e;
+
+/*Atmel RF states*/
+typedef enum
+{
+    NOP = 0x00,
+    BUSY_RX = 0x01,
+    RF_TX_START = 0x02,
+    FORCE_TRX_OFF = 0x03,
+    FORCE_PLL_ON = 0x04,
+    RX_ON = 0x06,
+    TRX_OFF = 0x08,
+    PLL_ON = 0x09,
+    BUSY_RX_AACK = 0x11,
+    SLEEP = 0x0F,
+    RX_AACK_ON = 0x16,
+    TX_ARET_ON = 0x19
+}rf_trx_states_t;
+
+/*RF receive buffer*/
+static uint8_t rf_buffer[RF_BUFFER_SIZE];
+
+/* TX info */
+static uint8_t  radio_tx_power = 0x17; /* 0 dBm */
+static uint8_t  mac_tx_handle = 0;
+static uint8_t  need_ack = 0;
+static uint16_t tx_len = 0;
+
+/* RF driver data */
+static xcvrState_t mPhySeqState;
+static xcvrPwrMode_t mPwrState;
+static phy_device_driver_s device_driver;
+static uint8_t mStatusAndControlRegs[8];
+static uint8_t rf_rnd = 0;
+static int8_t  rf_radio_driver_id = -1;
+static uint8_t MAC_address[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+/* Driver instance handle and hardware */
+static NanostackRfPhyMcr20a *rf = NULL;
+static SPI *spi = NULL;
+static DigitalOut *cs = NULL;
+static DigitalOut *rst = NULL;
+static InterruptIn *irq = NULL;
+static DigitalIn *irq_pin = NULL;
+
+/* Channel info */                 /* 2405    2410    2415    2420    2425    2430    2435    2440    2445    2450    2455    2460    2465    2470    2475    2480 */
+static const uint8_t  pll_int[16] =  {0x0B,   0x0B,   0x0B,   0x0B,   0x0B,   0x0B,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0C,   0x0D,   0x0D,   0x0D,   0x0D};
+static const uint16_t pll_frac[16] = {0x2800, 0x5000, 0x7800, 0xA000, 0xC800, 0xF000, 0x1800, 0x4000, 0x6800, 0x9000, 0xB800, 0xE000, 0x0800, 0x3000, 0x5800, 0x8000};
+static uint8_t rf_phy_channel = 0;
+
+/* Channel configurations for 2.4 */
+static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK};
+
+static const phy_device_channel_page_s phy_channel_pages[] = {
+        { CHANNEL_PAGE_0, &phy_24ghz},
+        { CHANNEL_PAGE_0, NULL}
+};
+
+
+static rf_trx_part_e rf_radio_type_read(void);
+
+MBED_UNUSED static void rf_ack_wait_timer_start(uint16_t slots);
+MBED_UNUSED static void rf_ack_wait_timer_stop(void);
+MBED_UNUSED static void rf_handle_cca_ed_done(void);
+MBED_UNUSED static void rf_handle_tx_end(void);
+MBED_UNUSED static void rf_handle_rx_end(void);
+MBED_UNUSED static void rf_on(void);
+MBED_UNUSED static void rf_receive(void);
+MBED_UNUSED static void rf_poll_trx_state_change(rf_trx_states_t trx_state);
+MBED_UNUSED static void rf_init(void);
+MBED_UNUSED static void rf_set_mac_address(const uint8_t *ptr);
+MBED_UNUSED static int8_t rf_device_register(void);
+MBED_UNUSED static void rf_device_unregister(void);
+MBED_UNUSED static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol );
+MBED_UNUSED static void rf_cca_abort(void);
+MBED_UNUSED static void rf_read_mac_address(uint8_t *ptr);
+MBED_UNUSED static int8_t rf_read_random(void);
+MBED_UNUSED static void rf_calibration_cb(void);
+MBED_UNUSED static void rf_init_phy_mode(void);
+MBED_UNUSED static void rf_ack_wait_timer_interrupt(void);
+MBED_UNUSED static void rf_calibration_timer_interrupt(void);
+MBED_UNUSED static void rf_calibration_timer_start(uint32_t slots);
+MBED_UNUSED static void rf_cca_timer_interrupt(void);
+MBED_UNUSED static void rf_cca_timer_start(uint32_t slots);
+MBED_UNUSED static uint16_t rf_get_phy_mtu_size(void);
+MBED_UNUSED static uint8_t rf_scale_lqi(int8_t rssi);
+
+/**
+ *  RF output power write
+ *
+ * \brief TX power has to be set before network start.
+ *
+ * \param power
+ *              See datasheet for TX power settings
+ *
+ * \return 0, Supported Value
+ * \return -1, Not Supported Value
+ */
+MBED_UNUSED static int8_t rf_tx_power_set(uint8_t power);
+MBED_UNUSED static uint8_t rf_tx_power_get(void);
+MBED_UNUSED static int8_t rf_enable_antenna_diversity(void);
+
+/* Private functions */
+MBED_UNUSED static void    rf_abort(void);
+MBED_UNUSED static void    rf_promiscuous(uint8_t mode);
+MBED_UNUSED static void    rf_get_timestamp(uint32_t *pRetClk);
+MBED_UNUSED static void    rf_set_timeout(uint32_t *pEndTime);
+MBED_UNUSED static void    rf_set_power_state(xcvrPwrMode_t newState);
+MBED_UNUSED static uint8_t rf_if_read_rnd(void);
+MBED_UNUSED static uint8_t rf_convert_LQI(uint8_t hwLqi);
+MBED_UNUSED static uint8_t rf_get_channel_energy(void);
+MBED_UNUSED static uint8_t rf_convert_energy_level(uint8_t energyLevel);
+MBED_UNUSED static int8_t  rf_convert_LQI_to_RSSI(uint8_t lqi);
+MBED_UNUSED static int8_t  rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel);
+MBED_UNUSED static int8_t  rf_extension(phy_extension_type_e extension_type,uint8_t *data_ptr);
+MBED_UNUSED static int8_t  rf_address_write(phy_address_type_e address_type,uint8_t *address_ptr);
+MBED_UNUSED static void rf_mac64_read(uint8_t *address);
+
+
+
+/*
+ * \brief Read connected radio part.
+ *
+ * This function only return valid information when rf_init() is called
+ *
+ * \return
+ */
+static rf_trx_part_e rf_radio_type_read(void)
+{
+    return FREESCALE_MCR20A;
+}
+
+/*
+ * \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)
+{
+    rf_trx_part_e radio_type;
+
+    rf_init();
+
+
+
+    radio_type = rf_radio_type_read();
+    if(radio_type == FREESCALE_MCR20A)
+    {
+        /*Set pointer to MAC address*/
+        device_driver.PHY_MAC = MAC_address;
+        device_driver.driver_description = (char*)"FREESCALE_MAC";
+
+        //Create setup Used Radio chips
+        /*Type of RF PHY is SubGHz*/
+        device_driver.link_type = PHY_LINK_15_4_2_4GHZ_TYPE;
+
+        device_driver.phy_channel_pages = phy_channel_pages;
+        /*Maximum size of payload is 127*/
+        device_driver.phy_MTU = 127;
+        /*No header in PHY*/
+        device_driver.phy_header_length = 0;
+        /*No tail in PHY*/
+        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*/
+        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);
+    }
+
+    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);
+}
+
+/*
+ * \brief Function returns the generated 8-bit random value for seeding Pseudo-random generator.
+ *
+ * \param none
+ *
+ * \return random value
+ */
+static int8_t rf_read_random(void)
+{
+    return rf_rnd;
+}
+
+/*
+ * \brief Function is a call back for ACK wait timeout.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_ack_wait_timer_interrupt(void)
+{
+    /* The packet was transmitted successfully, but no ACK was received */
+    if (device_driver.phy_tx_done_cb) {
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1);
+    }
+    rf_receive();
+}
+
+/*
+ * \brief Function is a call back for calibration interval timer.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_calibration_timer_interrupt(void)
+{
+}
+
+/*
+ * \brief Function is a call back for cca interval timer.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_cca_timer_interrupt(void)
+{
+    /* CCA time-out handled by Hardware */
+}
+
+
+/*
+ * \brief Function starts the ACK wait time-out.
+ *
+ * \param slots The ACK wait time-out in [symbols]
+ *
+ * \return none
+ */
+static void rf_ack_wait_timer_start(uint16_t time)
+{
+    uint32_t timeout;
+
+    rf_get_timestamp(&timeout);
+    timeout += time;
+    rf_set_timeout(&timeout);
+}
+
+/*
+ * \brief Function starts the calibration interval.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_calibration_timer_start(uint32_t slots)
+{
+    (void)slots;
+}
+
+/*
+ * \brief Function starts the CCA timout.
+ *
+ * \param slots Given slots, resolution 50us
+ *
+ * \return none
+ */
+static void rf_cca_timer_start(uint32_t slots)
+{
+    (void)slots;
+}
+
+/*
+ * \brief Function stops the ACK wait timeout.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_ack_wait_timer_stop(void)
+{
+}
+
+/*
+ * \brief Function reads the MAC address array.
+ *
+ * \param ptr Pointer to read array
+ *
+ * \return none
+ */
+static void rf_read_mac_address(uint8_t *ptr)
+{
+    memcpy(ptr, MAC_address, 8);
+}
+
+/*
+ * \brief Function sets the MAC address array.
+ *
+ * \param ptr Pointer to given MAC address array
+ *
+ * \return none
+ */
+static void rf_set_mac_address(const uint8_t *ptr)
+{
+    memcpy(MAC_address, ptr, 8);
+}
+
+static uint16_t rf_get_phy_mtu_size(void)
+{
+    return device_driver.phy_MTU;
+}
+
+/*
+ * \brief Function writes 16-bit address in RF address filter.
+ *
+ * \param short_address Given short address
+ *
+ * \return none
+ */
+static void rf_set_short_adr(uint8_t * short_address)
+{
+    /* Write one register at a time to be accessible from hibernate mode */
+    MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_MSB, short_address[0]);
+    MCR20Drv_IndirectAccessSPIWrite(MACSHORTADDRS0_LSB, short_address[1]);
+}
+
+/*
+ * \brief Function writes PAN Id in RF PAN Id filter.
+ *
+ * \param pan_id Given PAN Id
+ *
+ * \return none
+ */
+static void rf_set_pan_id(uint8_t *pan_id)
+{
+    /* Write one register at a time to be accessible from hibernate mode */
+    MCR20Drv_IndirectAccessSPIWrite(MACPANID0_MSB, pan_id[0]);
+    MCR20Drv_IndirectAccessSPIWrite(MACPANID0_LSB, pan_id[1]);
+}
+
+/*
+ * \brief Function writes 64-bit address in RF address filter.
+ *
+ * \param address Given 64-bit address
+ *
+ * \return none
+ */
+static void rf_set_address(uint8_t *address)
+{
+    /* Write one register at a time to be accessible from hibernate mode */
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_0,  address[7]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_8,  address[6]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_16, address[5]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_24, address[4]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_32, address[3]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_40, address[2]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_48, address[1]);
+    MCR20Drv_IndirectAccessSPIWrite(MACLONGADDRS0_56, address[0]);
+}
+
+/*
+ * \brief Function sets the RF channel.
+ *
+ * \param ch New channel
+ *
+ * \return none
+ */
+static void rf_channel_set(uint8_t channel)
+{
+    rf_phy_channel = channel;
+    MCR20Drv_DirectAccessSPIWrite(PLL_INT0, pll_int[channel - 11]);
+    MCR20Drv_DirectAccessSPIMultiByteWrite(PLL_FRAC0_LSB, (uint8_t *) &pll_frac[channel - 11], 2);
+}
+
+
+/*
+ * \brief Function initialises the radio driver and resets the radio.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_init(void)
+{
+    uint32_t index;
+    mPhySeqState = gIdle_c;
+    mPwrState = gXcvrPwrIdle_c;
+    /*Reset RF module*/
+    MCR20Drv_RESET();
+    /* Initialize the transceiver SPI driver */
+    MCR20Drv_Init();
+    /* Disable Tristate on MISO for SPI reads */
+    MCR20Drv_IndirectAccessSPIWrite(MISC_PAD_CTRL, 0x02);
+    /* Set XCVR clock output settings */
+    MCR20Drv_Set_CLK_OUT_Freq(gMCR20_ClkOutFreq_d);
+    /* Set default XCVR power state */
+    rf_set_power_state(gXcvrRunState_d);
+
+    /* PHY_CTRL1 default HW settings  + AUTOACK enabled */
+    mStatusAndControlRegs[PHY_CTRL1] = cPHY_CTRL1_AUTOACK;
+    /* PHY_CTRL2 : mask all PP interrupts */
+    mStatusAndControlRegs[PHY_CTRL2] = cPHY_CTRL2_CRC_MSK | \
+                                       cPHY_CTRL2_PLL_UNLOCK_MSK | \
+                                       /*cPHY_CTRL2_FILTERFAIL_MSK | */ \
+                                       cPHY_CTRL2_RX_WMRK_MSK | \
+                                       cPHY_CTRL2_CCAMSK | \
+                                       cPHY_CTRL2_RXMSK | \
+                                       cPHY_CTRL2_TXMSK | \
+                                       cPHY_CTRL2_SEQMSK;
+    /* PHY_CTRL3 : enable timer 3 and disable remaining interrupts */
+    mStatusAndControlRegs[PHY_CTRL3] = cPHY_CTRL3_ASM_MSK    | \
+                                       cPHY_CTRL3_PB_ERR_MSK | \
+                                       cPHY_CTRL3_WAKE_MSK   | \
+                                       cPHY_CTRL3_TMR3CMP_EN;
+    /* PHY_CTRL4 unmask global TRX interrupts, enable 16 bit mode for TC2 - TC2 prime EN */
+    mStatusAndControlRegs[PHY_CTRL4] = cPHY_CTRL4_TC2PRIME_EN | (gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c);
+    /* Clear all PP IRQ bits to avoid unexpected interrupts immediately after initialization */
+    mStatusAndControlRegs[IRQSTS1] = cIRQSTS1_PLL_UNLOCK_IRQ | \
+                                     cIRQSTS1_FILTERFAIL_IRQ | \
+                                     cIRQSTS1_RXWTRMRKIRQ | \
+                                     cIRQSTS1_CCAIRQ | \
+                                     cIRQSTS1_RXIRQ | \
+                                     cIRQSTS1_TXIRQ | \
+                                     cIRQSTS1_SEQIRQ;
+    
+    mStatusAndControlRegs[IRQSTS2] = cIRQSTS2_ASM_IRQ | cIRQSTS2_PB_ERR_IRQ | cIRQSTS2_WAKE_IRQ;
+    /* Mask and clear all TMR IRQs */
+    mStatusAndControlRegs[IRQSTS3] = cIRQSTS3_TMR4MSK | cIRQSTS3_TMR3MSK | cIRQSTS3_TMR2MSK | cIRQSTS3_TMR1MSK | \
+                                     cIRQSTS3_TMR4IRQ | cIRQSTS3_TMR3IRQ | cIRQSTS3_TMR2IRQ | cIRQSTS3_TMR1IRQ;
+    /* Write settings to XCVR */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 5);
+    /* Clear all interrupts */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, &mStatusAndControlRegs[IRQSTS1], 3);
+    
+    /*  RX_FRAME_FILTER. Accept FrameVersion 0 and 1 packets, reject all others */
+    MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, (cRX_FRAME_FLT_FRM_VER | \
+                                                      cRX_FRAME_FLT_BEACON_FT | \
+                                                      cRX_FRAME_FLT_DATA_FT | \
+                                                      cRX_FRAME_FLT_CMD_FT ));
+    /* Direct register overwrites */
+    for (index = 0; index < sizeof(overwrites_direct)/sizeof(overwrites_t); index++)
+        MCR20Drv_DirectAccessSPIWrite(overwrites_direct[index].address, overwrites_direct[index].data);
+    /* Indirect register overwrites */
+    for (index = 0; index < sizeof(overwrites_indirect)/sizeof(overwrites_t); index++)
+        MCR20Drv_IndirectAccessSPIWrite(overwrites_indirect[index].address, overwrites_indirect[index].data);
+
+    /* Set the CCA energy threshold value */
+    MCR20Drv_IndirectAccessSPIWrite(CCA1_THRESH, RF_CCA_THRESHOLD);
+    /* Set prescaller to obtain 1 symbol (16us) timebase */
+    MCR20Drv_IndirectAccessSPIWrite(TMR_PRESCALE, 0x05);
+
+    MCR20Drv_IRQ_Enable();
+
+    /*Read random variable. This will be used when seeding pseudo-random generator*/
+    rf_rnd = rf_if_read_rnd();
+    /*Read eui64*/
+    rf_mac64_read(MAC_address);
+    /*set default channel to 11*/
+    rf_channel_set(11);
+    /*Start receiver*/
+    rf_receive();
+}
+
+/**
+ * \brief Function gets called when MAC is setting radio off.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_off(void)
+{
+    /* Abort any ongoing sequences */
+    rf_abort();
+    /* Set XCVR in a low power state */
+    rf_set_power_state(gXcvrLowPowerState_d);
+}
+
+/*
+ * \brief Function polls the RF state until it has changed to desired state.
+ *
+ * \param trx_state RF state
+ *
+ * \return none
+ */
+static void rf_poll_trx_state_change(rf_trx_states_t trx_state)
+{
+    (void)trx_state;
+}
+
+/*
+ * \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 )
+{
+    uint8_t ccaMode;
+
+    /* Parameter validation */
+    if( !data_ptr || (data_length > 125) || (PHY_LAYER_PAYLOAD != data_protocol) )
+    {
+        return -1;
+    }
+
+    if( mPhySeqState == gRX_c )
+    {
+        uint8_t phyReg = MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F;
+        /* Check for an Rx in progress. */
+        if((phyReg <= 0x06) || (phyReg == 0x15) || (phyReg == 0x16))
+        {
+            if (device_driver.phy_tx_done_cb) {
+                device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1);
+            }
+            return -1;
+        }
+        rf_abort();
+    }
+
+    /*Check if transmitter is busy*/
+    if( mPhySeqState != gIdle_c )
+    {
+        /*Return busy*/
+        return -1;
+    }
+
+    /*Store TX handle*/
+    mac_tx_handle = tx_handle;
+    /*Check if transmitted data needs to be acked*/
+    need_ack = (*data_ptr & 0x20) == 0x20;
+
+    /* Set XCVR power state in run mode */
+    rf_set_power_state(gXcvrRunState_d);
+    /* Load data into XCVR */
+    tx_len = data_length + 2;
+    MCR20Drv_PB_SPIBurstWrite(data_ptr - 1, data_length + 1);
+    MCR20Drv_PB_SPIByteWrite(0,tx_len);
+    
+    /* Set CCA mode 1 */
+    ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE;
+    if( ccaMode != gCcaCCA_MODE1_c )
+    {
+        mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c);
+        mStatusAndControlRegs[PHY_CTRL4] |= gCcaCCA_MODE1_c << cPHY_CTRL4_CCATYPE_Shift_c;
+        MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]);
+    }
+
+    /* Read XCVR registers */
+    mStatusAndControlRegs[0] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[1], 4);
+    mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+    mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c;
+    mPhySeqState = gCCA_c;
+
+    /* Ensure that no spurious interrupts are raised */
+    mStatusAndControlRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */
+    mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ);
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3);
+
+    /* Write XCVR settings */
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+    
+    /* Unmask SEQ interrupt */
+    mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK);
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]);
+
+    /*Return success*/
+    return 0;
+}
+
+/*
+ * \brief Function aborts CCA process.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_cca_abort(void)
+{
+    rf_abort();
+}
+
+/*
+ * \brief Function starts the transmission of the frame. Called from ISR context!
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_start_tx(void)
+{
+    /* Perform TxRxAck sequence if required by phyTxMode */
+    if( need_ack )
+    {
+        mStatusAndControlRegs[PHY_CTRL1] |= cPHY_CTRL1_RXACKRQD;
+        mPhySeqState = gTR_c;
+    }
+    else
+    {
+        mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_RXACKRQD);
+        mPhySeqState = gTX_c;
+    }
+
+    mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+    mStatusAndControlRegs[PHY_CTRL1] |= mPhySeqState;
+    
+    /* Unmask SEQ interrupt */
+    mStatusAndControlRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK);
+
+    /* Start the sequence immediately */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(PHY_CTRL1, &mStatusAndControlRegs[PHY_CTRL1], 2);
+
+    if( need_ack )
+    {
+        rf_ack_wait_timer_start(gPhyWarmUpTime_c + gPhySHRDuration_c + tx_len * gPhySymbolsPerOctet_c + gPhyAckWaitDuration_c);
+    }
+}
+
+/*
+ * \brief Function sets the RF in RX state. Called from ISR context!
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_receive(void)
+{
+    uint8_t phyRegs[5];
+
+    /* RX can start only from Idle state */
+    if( mPhySeqState != gIdle_c )
+    {
+        return;
+    }
+
+    /* Set XCVR power state in run mode */
+    rf_set_power_state(gXcvrRunState_d);
+    /* read XVCR settings */
+    phyRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &phyRegs[IRQSTS2], 4);
+    /* unmask SEQ interrupt */
+    phyRegs[PHY_CTRL2] &= ~(cPHY_CTRL2_SEQMSK);
+    /* set XcvrSeq to RX */
+    phyRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+    phyRegs[PHY_CTRL1] |=  gRX_c;
+    mPhySeqState = gRX_c;
+    /* Ensure that no spurious interrupts are raised */
+    phyRegs[IRQSTS3] &= 0xF0; /* do not change other IRQ status */
+    phyRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ;
+    /* sync settings with XCVR */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, phyRegs, 5);
+}
+
+/*
+ * \brief Function calibrates the radio.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_calibration_cb(void)
+{
+}
+
+/*
+ * \brief Function sets RF_ON flag when radio is powered.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_on(void)
+{
+}
+
+/*
+ * \brief Function is a call back for RX end interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_handle_rx_end(void)
+{
+    uint8_t rf_lqi = MCR20Drv_DirectAccessSPIRead(LQI_VALUE);
+    int8_t rf_rssi = 0;
+    uint8_t len = mStatusAndControlRegs[RX_FRM_LEN] - 2;
+    
+
+    /*Start receiver*/
+    rf_receive();
+
+    /*Check the length is valid*/
+    if(len > 1 && len < RF_BUFFER_SIZE)
+    {
+        rf_lqi  = rf_convert_LQI(rf_lqi);
+        rf_rssi = rf_convert_LQI_to_RSSI(rf_lqi);
+        /*gcararu: Scale LQI using received RSSI, to match the LQI reported by the ATMEL radio */
+        rf_lqi  = rf_scale_lqi(rf_rssi);
+
+        /*Read received packet*/
+        MCR20Drv_PB_SPIBurstRead(rf_buffer, len);
+        if (device_driver.phy_rx_cb) {
+            device_driver.phy_rx_cb(rf_buffer, len, rf_lqi, rf_rssi, rf_radio_driver_id);
+        }
+    }
+}
+
+/*
+ * \brief Function is called when MAC is shutting down the radio.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_shutdown(void)
+{
+    /*Call RF OFF*/
+    rf_off();
+}
+
+/*
+ * \brief Function is a call back for TX end interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_handle_tx_end(void)
+{
+    uint8_t rx_frame_pending = mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_RX_FRM_PEND;
+
+    /*Start receiver*/
+    rf_receive();
+
+    if (!device_driver.phy_tx_done_cb) {
+        return;
+    }
+
+    /*Call PHY TX Done API*/
+    if( need_ack )
+    {
+        if( rx_frame_pending )
+        {
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE_PENDING, 1, 1);
+        }
+        else
+        {
+            // arm_net_phy_tx_done(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1);
+            device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_DONE, 1, 1);
+        }
+    }
+    else
+    {
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_TX_SUCCESS, 1, 1);
+    }
+}
+
+/*
+ * \brief Function is a call back for CCA ED done interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_handle_cca_ed_done(void)
+{
+    /*Check the result of CCA process*/
+    if( !(mStatusAndControlRegs[IRQSTS2] & cIRQSTS2_CCA) ) 
+    {
+        rf_start_tx();
+    }
+    else if (device_driver.phy_tx_done_cb)
+    {
+        /*Send CCA fail notification*/
+        device_driver.phy_tx_done_cb(rf_radio_driver_id, mac_tx_handle, PHY_LINK_CCA_FAIL, 1, 1);
+    }
+}
+
+/*
+ * \brief Function sets the TX power variable.
+ *
+ * \param power TX power setting
+ *
+ * \return 0 Success
+ * \return -1 Fail
+ */
+static int8_t rf_tx_power_set(uint8_t power)
+{
+    /* gcapraru: Map MCR20A Tx power levels over ATMEL values */
+    static uint8_t pwrLevelMapping[16] = {25,25,25,24,24,24,23,23,22,22,21,20,19,18,17,14};
+
+    if( power > 15 )
+    {
+        return -1;
+    }
+
+    radio_tx_power = power;
+    MCR20Drv_DirectAccessSPIWrite(PA_PWR, pwrLevelMapping[power]);
+    return 0;
+}
+
+/*
+ * \brief Function returns the TX power variable.
+ *
+ * \param none
+ *
+ * \return radio_tx_power TX power variable
+ */
+static uint8_t rf_tx_power_get(void)
+{
+    return radio_tx_power;
+}
+
+/*
+ * \brief Function enables the usage of Antenna diversity.
+ *
+ * \param none
+ *
+ * \return 0 Success
+ */
+static int8_t rf_enable_antenna_diversity(void)
+{
+    uint8_t phyReg;
+
+    phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_AGC_CTRL);
+    phyReg |= cANT_AGC_CTRL_FAD_EN_Mask_c;
+    MCR20Drv_IndirectAccessSPIWrite(ANT_AGC_CTRL, phyReg);
+
+    phyReg = MCR20Drv_IndirectAccessSPIRead(ANT_PAD_CTRL);
+    phyReg |= 0x02;
+    MCR20Drv_IndirectAccessSPIWrite(ANT_PAD_CTRL, phyReg);
+    
+    return 0;
+}
+
+/*
+ * \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:
+            break;
+        /*Disable PHY Interface driver*/
+        case PHY_INTERFACE_DOWN:
+            rf_shutdown();
+            break;
+        /*Enable PHY Interface driver*/
+        case PHY_INTERFACE_UP:
+            rf_channel_set(rf_channel);
+            rf_receive();
+            break;
+        /*Enable wireless interface ED scan mode*/
+        case PHY_INTERFACE_RX_ENERGY_STATE:
+            rf_abort();
+            rf_channel_set(rf_channel);
+            break;
+        case PHY_INTERFACE_SNIFFER_STATE:             /**< Enable Sniffer state */
+            rf_promiscuous(1);
+            rf_channel_set(rf_channel);
+            rf_receive();
+            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:
+        {
+            uint8_t reg = MCR20Drv_DirectAccessSPIRead(SRC_CTRL);
+
+            if(*data_ptr)
+            {
+                reg |= cSRC_CTRL_ACK_FRM_PND;
+            }
+            else
+            {
+                reg &= ~cSRC_CTRL_ACK_FRM_PND;
+            }
+            
+            MCR20Drv_DirectAccessSPIWrite(SRC_CTRL, reg);
+            break;
+            
+        }
+        /*Return frame pending status*/
+        case PHY_EXTENSION_READ_LAST_ACK_PENDING_STATUS:
+            *data_ptr = MCR20Drv_DirectAccessSPIRead(IRQSTS1 & cIRQSTS1_RX_FRM_PEND);
+            break;
+        /*Set channel*/
+        case PHY_EXTENSION_SET_CHANNEL:
+            break;
+        /*Read energy on the channel*/
+        case PHY_EXTENSION_READ_CHANNEL_ENERGY:
+            *data_ptr = rf_get_channel_energy();
+            break;
+        /*Read status of the link*/
+        case PHY_EXTENSION_READ_LINK_STATUS:
+            break;
+        case PHY_EXTENSION_CONVERT_SIGNAL_INFO:
+            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:
+            break;
+            /*Set 64-bit address*/
+        case PHY_MAC_64BIT:
+            rf_set_address(address_ptr);
+            break;
+        /*Set 16-bit address*/
+        case PHY_MAC_16BIT:
+            rf_set_short_adr(address_ptr);
+            break;
+        /*Set PAN Id*/
+        case PHY_MAC_PANID:
+            rf_set_pan_id(address_ptr);
+            break;
+    }
+    return ret_val;
+}
+
+static void rf_mac64_read(uint8_t *address)
+{
+    /* Write one register at a time to be accessible from hibernate mode */
+    address[7] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_0);
+    address[6] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_8);
+    address[5] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_16);
+    address[4] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_24);
+    address[3] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_32);
+    address[2] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_40);
+    address[1] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_48);
+    address[0] = MCR20Drv_DirectAccessSPIRead(MACLONGADDRS0_56);
+
+}
+
+/*
+ * \brief Function initialises the ACK wait time and returns the used PHY mode.
+ *
+ * \param none
+ *
+ * \return tmp Used PHY mode
+ */
+static void rf_init_phy_mode(void)
+{
+}
+
+/*
+ * \brief Function is a RF interrupt vector. End of frame in RX and TX are handled here as well as CCA process interrupt.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void PHY_InterruptHandler(void)
+{
+    uint8_t xcvseqCopy;
+
+    /* Disable and clear transceiver(IRQ_B) interrupt */
+    MCR20Drv_IRQ_Disable();
+    //MCR20Drv_IRQ_Clear();
+
+    /* Read transceiver interrupt status and control registers */
+    mStatusAndControlRegs[IRQSTS1] =
+        MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 7);
+
+    xcvseqCopy = mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ;
+    
+    /* Flter Fail IRQ */
+    if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_FILTERFAIL_IRQ) &&
+       !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_FILTERFAIL_MSK) )
+    {
+        if( xcvseqCopy == gRX_c )
+        {
+            /* Abort current SEQ */
+            mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+            MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+            /* Wait for Sequence Idle */
+            while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0);
+            /* Clear IRQ flags: */
+            MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ);
+            /* Restart Rx asap */
+            mStatusAndControlRegs[PHY_CTRL1] |= gRX_c;
+            MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+        }
+    }
+    
+    /* TMR3 IRQ: ACK wait time-out */
+    if( (mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3IRQ) &&
+       !(mStatusAndControlRegs[IRQSTS3] & cIRQSTS3_TMR3MSK) )
+    {
+        /* Disable TMR3 IRQ */
+        mStatusAndControlRegs[IRQSTS3] |= cIRQSTS3_TMR3MSK;
+
+        if( xcvseqCopy == gTR_c )
+        {
+            /* Set XCVR to Idle */
+            mPhySeqState = gIdle_c;
+            mStatusAndControlRegs[PHY_CTRL1] &=  ~( cPHY_CTRL1_XCVSEQ );
+            /* Mask interrupts */
+            mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK;
+            /* Sync settings with XCVR */
+            MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5);
+            
+            rf_ack_wait_timer_interrupt();
+            MCR20Drv_IRQ_Enable();
+            return;
+        }
+    }
+
+    /* Sequencer interrupt, the autosequence has completed */
+    if( (mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_SEQIRQ) && 
+       !(mStatusAndControlRegs[PHY_CTRL2] & cPHY_CTRL2_SEQMSK) )
+    {
+        /* Set XCVR to Idle */
+        mPhySeqState = gIdle_c;
+        mStatusAndControlRegs[PHY_CTRL1] &=  ~( cPHY_CTRL1_XCVSEQ );
+        /* Mask interrupts */
+        mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_CCAMSK | cPHY_CTRL2_RXMSK | cPHY_CTRL2_TXMSK | cPHY_CTRL2_SEQMSK;
+        /* Sync settings with XCVR */
+        MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 5);
+                                                               
+        /* PLL unlock, the autosequence has been aborted due to PLL unlock */
+        if( mStatusAndControlRegs[IRQSTS1] & cIRQSTS1_PLL_UNLOCK_IRQ )
+        {
+            if(xcvseqCopy == gRX_c)
+            {
+                rf_receive();
+            }
+            MCR20Drv_IRQ_Enable();
+            return;
+        }
+
+        switch(xcvseqCopy)
+        {
+        case gTX_c:
+        case gTR_c:
+            rf_handle_tx_end();
+            break;
+
+        case gRX_c:
+            rf_handle_rx_end();
+            break;
+
+        case gCCA_c:
+            rf_handle_cca_ed_done();
+            break;
+
+        default:
+            break;
+        }
+        
+        MCR20Drv_IRQ_Enable();
+        return;
+    }
+    /* Other IRQ. Clear XCVR interrupt flags */
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3);
+    MCR20Drv_IRQ_Enable();
+}
+
+/*
+ * \brief Function forces the XCVR to Idle state.
+ *
+ * \param none
+ *
+ * \return none
+ */
+static void rf_abort(void)
+{
+    /* Mask XCVR irq */
+    MCR20Drv_IRQ_Disable();
+
+    mPhySeqState = gIdle_c;
+
+    mStatusAndControlRegs[IRQSTS1] = MCR20Drv_DirectAccessSPIMultiByteRead(IRQSTS2, &mStatusAndControlRegs[IRQSTS2], 5);
+    
+    /* Mask SEQ interrupt */
+    mStatusAndControlRegs[PHY_CTRL2] |= cPHY_CTRL2_SEQMSK;
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL2, mStatusAndControlRegs[PHY_CTRL2]);
+
+    if( (mStatusAndControlRegs[PHY_CTRL1] & cPHY_CTRL1_XCVSEQ) != gIdle_c )
+    {
+        /* Abort current SEQ */
+        mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+        MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+        
+        /* Wait for Sequence Idle (if not already) */
+        while ((MCR20Drv_DirectAccessSPIRead(SEQ_STATE) & 0x1F) != 0);
+        //while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ));
+        mStatusAndControlRegs[IRQSTS1] |= cIRQSTS1_SEQIRQ;
+    }
+
+    /* Clear all PP IRQ bits to avoid unexpected interrupts and mask TMR3 interrupt.
+       Do not change TMR IRQ status. */
+    mStatusAndControlRegs[IRQSTS3] &= 0xF0;
+    mStatusAndControlRegs[IRQSTS3] |= (cIRQSTS3_TMR3MSK | cIRQSTS3_TMR3IRQ);
+    MCR20Drv_DirectAccessSPIMultiByteWrite(IRQSTS1, mStatusAndControlRegs, 3);
+
+    /* Unmask XCVR irq */
+    MCR20Drv_IRQ_Enable();
+}
+
+/*
+ * \brief Function reads a time-stamp value from XCVR [symbols]
+ *
+ * \param pEndTime pointer to location where time-stamp will be stored
+ *
+ * \return none
+ */
+static void rf_get_timestamp(uint32_t *pRetClk)
+{
+    if(NULL == pRetClk)
+    {
+        return;
+    }
+
+    platform_enter_critical();
+
+    *pRetClk = 0;
+    MCR20Drv_DirectAccessSPIMultiByteRead(EVENT_TMR_LSB, (uint8_t *) pRetClk, 3);
+
+    platform_exit_critical();
+}
+
+/*
+ * \brief Function set a time-out to an XCVR sequence.
+ *
+ * \param pEndTime pointer to the sequence time-out value [symbols]
+ *
+ * \return none
+ */
+static void rf_set_timeout(uint32_t *pEndTime)
+{
+    uint8_t phyReg;
+    
+    if(NULL == pEndTime)
+    {
+        return;
+    }
+    
+    platform_enter_critical();
+    
+    phyReg = MCR20Drv_DirectAccessSPIRead(IRQSTS3);
+    phyReg &= 0xF0;                    /* do not change IRQ status */
+    phyReg |= (cIRQSTS3_TMR3MSK);      /* mask TMR3 interrupt */
+    MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg);
+    
+    MCR20Drv_DirectAccessSPIMultiByteWrite(T3CMP_LSB, (uint8_t *) pEndTime, 3);
+    
+    phyReg &= ~(cIRQSTS3_TMR3MSK);      /* unmask TMR3 interrupt */
+    phyReg |= (cIRQSTS3_TMR3IRQ);       /* aknowledge TMR3 IRQ */
+    MCR20Drv_DirectAccessSPIWrite(IRQSTS3, phyReg);
+    
+    platform_exit_critical();
+}
+
+/*
+ * \brief Function reads a random number from RF.
+ *
+ * \param none 
+ *
+ * \return 8-bit random number
+ */
+static uint8_t rf_if_read_rnd(void)
+{
+    uint8_t phyReg;
+
+    MCR20Drv_IRQ_Disable();
+    /* Check if XCVR is idle */
+    phyReg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL1);
+
+    if( (phyReg & cPHY_CTRL1_XCVSEQ) == gIdle_c )
+    {
+        /* Program a new sequence */
+        MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, phyReg | gCCA_c);
+        /* Wait for sequence to finish */
+        while( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ) );
+        /* Clear interrupt flag */
+        MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_SEQIRQ);
+    }
+
+    MCR20Drv_IRQ_Enable();
+
+    return MCR20Drv_IndirectAccessSPIRead(_RNG);
+}
+
+/*
+ * \brief Function converts LQI into RSSI.
+ *
+ * \param LQI 
+ *
+ * \return RSSI
+ */
+static int8_t rf_convert_LQI_to_RSSI(uint8_t lqi)
+{
+    int32_t rssi = (50*lqi - 16820) / 163;
+    return (int8_t)rssi;
+}
+
+/*
+ * \brief Function scale the LQI value reported by RF into a 0-255 value.
+ *
+ * \param hwLqi - the LQI value reported by RF
+ *
+ * \return scaled LQI
+ */
+static uint8_t rf_convert_LQI(uint8_t hwLqi)
+{
+    uint32_t tmpLQI;
+
+    /* LQI Saturation Level */
+    if (hwLqi >= 230)
+    {
+        return 0xFF;
+    }
+    else if (hwLqi <= 9)
+    {
+        return 0;
+    }
+    else
+    {
+        /* Rescale the LQI values from min to saturation to the 0x00 - 0xFF range */
+        /* The LQI value mst be multiplied by ~1.1087 */
+        /* tmpLQI =  hwLqi * 7123 ~= hwLqi * 65536 * 0.1087 = hwLqi * 2^16 * 0.1087*/
+        tmpLQI = ((uint32_t)hwLqi * (uint32_t)7123 );
+        /* tmpLQI =  (tmpLQI / 2^16) + hwLqi */
+        tmpLQI = (uint32_t)(tmpLQI >> 16) + (uint32_t)hwLqi;
+
+        return (uint8_t)tmpLQI;
+    }
+}
+
+/*
+ * \brief Function enables/disables Rx promiscuous mode.
+ *
+ * \param state of XCVR promiscuous mode
+ *
+ * \return none
+ */
+static void rf_promiscuous(uint8_t state)
+{
+    uint8_t rxFrameFltReg, phyCtrl4Reg;
+
+    rxFrameFltReg = MCR20Drv_IndirectAccessSPIRead(RX_FRAME_FILTER);
+    phyCtrl4Reg = MCR20Drv_DirectAccessSPIRead(PHY_CTRL4);
+
+    if( state )
+    {
+        /* FRM_VER[1:0] = b00. 00: Any FrameVersion accepted (0,1,2 & 3) */
+        /* All frame types accepted*/
+        phyCtrl4Reg   |= cPHY_CTRL4_PROMISCUOUS;
+        rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER);
+        rxFrameFltReg |=  (cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT);
+    }
+    else
+    {
+        phyCtrl4Reg   &= ~cPHY_CTRL4_PROMISCUOUS;
+        /* FRM_VER[1:0] = b11. Accept FrameVersion 0 and 1 packets, reject all others */
+        /* Beacon, Data and MAC command frame types accepted */
+        rxFrameFltReg &= ~(cRX_FRAME_FLT_FRM_VER);
+        rxFrameFltReg |= (0x03 << cRX_FRAME_FLT_FRM_VER_Shift_c);
+        rxFrameFltReg &= ~(cRX_FRAME_FLT_ACK_FT | cRX_FRAME_FLT_NS_FT);
+    }
+
+    MCR20Drv_IndirectAccessSPIWrite(RX_FRAME_FILTER, rxFrameFltReg);
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, phyCtrl4Reg);
+}
+
+/*
+ * \brief Function used to switch XCVR power state.
+ *
+ * \param state The XCVR power mode
+ *
+ * \return none
+ */
+static void rf_set_power_state(xcvrPwrMode_t newState)
+{
+    uint8_t pwrMode;
+    uint8_t xtalState;
+
+    if( mPwrState == newState )
+    {
+        return;
+    }
+
+    /* Read power settings from RF */
+    pwrMode = MCR20Drv_DirectAccessSPIRead(PWR_MODES);
+    xtalState = pwrMode & cPWR_MODES_XTALEN;
+    
+    switch( newState )
+    {
+    case gXcvrPwrIdle_c:
+        pwrMode &= ~(cPWR_MODES_AUTODOZE);
+        pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_PMC_MODE);
+        break;
+    case gXcvrPwrAutodoze_c:
+        pwrMode |= (cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE);
+        break;
+    case gXcvrPwrDoze_c:
+        pwrMode &= ~(cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE);
+        pwrMode |= cPWR_MODES_XTALEN;
+        break;
+    case gXcvrPwrHibernate_c:
+        pwrMode &= ~(cPWR_MODES_XTALEN | cPWR_MODES_AUTODOZE | cPWR_MODES_PMC_MODE);
+        break;
+    default:
+        return;
+    }
+    
+    mPwrState = newState;
+    MCR20Drv_DirectAccessSPIWrite(PWR_MODES, pwrMode);
+    
+    if( !xtalState && (pwrMode & cPWR_MODES_XTALEN))
+    {
+        /* wait for crystal oscillator to complet its warmup */
+        while( ( MCR20Drv_DirectAccessSPIRead(PWR_MODES) & cPWR_MODES_XTAL_READY ) != cPWR_MODES_XTAL_READY);
+        /* wait for radio wakeup from hibernate interrupt */
+        while( ( MCR20Drv_DirectAccessSPIRead(IRQSTS2) & (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) ) != (cIRQSTS2_WAKE_IRQ | cIRQSTS2_TMRSTATUS) );
+
+        MCR20Drv_DirectAccessSPIWrite(IRQSTS2, cIRQSTS2_WAKE_IRQ);
+    }
+}
+
+/*
+ * \brief Function reads the energy level on the preselected channel.
+ *
+ * \return energy level
+ */
+static uint8_t rf_get_channel_energy(void)
+{
+    uint8_t ccaMode;
+
+    MCR20Drv_IRQ_Disable();
+    /* RX can start only from Idle state */
+    if( mPhySeqState != gIdle_c )
+    {
+        MCR20Drv_IRQ_Enable();
+        return 0;
+    }
+
+    /* Set XCVR power state in run mode */
+    rf_set_power_state(gXcvrRunState_d);
+
+    /* Switch to ED mode */
+    ccaMode = (mStatusAndControlRegs[PHY_CTRL4] >> cPHY_CTRL4_CCATYPE_Shift_c) & cPHY_CTRL4_CCATYPE;
+    if( ccaMode != gCcaED_c )
+    {
+        mStatusAndControlRegs[PHY_CTRL4] &= ~(cPHY_CTRL4_CCATYPE << cPHY_CTRL4_CCATYPE_Shift_c);
+        mStatusAndControlRegs[PHY_CTRL4] |= gCcaED_c << cPHY_CTRL4_CCATYPE_Shift_c;
+        MCR20Drv_DirectAccessSPIWrite(PHY_CTRL4, mStatusAndControlRegs[PHY_CTRL4]);
+    }
+    
+    /* Start ED sequence */
+    mStatusAndControlRegs[PHY_CTRL1] |= gCCA_c;
+    MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ);
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+    /* Wait for sequence to finish */
+    while ( !(MCR20Drv_DirectAccessSPIRead(IRQSTS1) & cIRQSTS1_SEQIRQ));
+    /* Set XCVR to Idle */
+    mStatusAndControlRegs[PHY_CTRL1] &= ~(cPHY_CTRL1_XCVSEQ);
+    MCR20Drv_DirectAccessSPIWrite(PHY_CTRL1, mStatusAndControlRegs[PHY_CTRL1]);
+    MCR20Drv_DirectAccessSPIWrite(IRQSTS1, cIRQSTS1_CCAIRQ | cIRQSTS1_SEQIRQ);
+    
+    MCR20Drv_IRQ_Enable();
+    
+    return rf_convert_energy_level(MCR20Drv_DirectAccessSPIRead(CCA1_ED_FNL));
+}
+
+/*
+ * \brief Function converts the energy level from dBm to a 0-255 value.
+ *
+ * \param energyLevel in dBm
+ *
+ * \return energy level (0-255)
+ */
+static uint8_t rf_convert_energy_level(uint8_t energyLevel)
+{
+    if(energyLevel >= 90)
+    {
+        /* ED value is below minimum. Return 0x00. */
+        energyLevel = 0x00;
+    }
+    else if(energyLevel <= 26)
+    {
+        /* ED value is above maximum. Return 0xFF. */
+        energyLevel = 0xFF;
+    }
+    else
+    {
+        /* Energy level (-90 dBm to -26 dBm ) --> varies form 0 to 64 */
+        energyLevel = (90 - energyLevel);
+        /* Rescale the energy level values to the 0x00-0xff range (0 to 64 translates in 0 to 255) */
+        /* energyLevel * 3.9844 ~= 4 */
+        /* Multiply with 4=2^2 by shifting left.
+        The multiplication will not overflow beacause energyLevel has values between 0 and 63 */
+        energyLevel <<= 2;
+    }
+
+    return energyLevel;
+}
+
+static uint8_t rf_scale_lqi(int8_t rssi)
+{
+    uint8_t scaled_lqi;
+    /*Worst case sensitivity*/
+    const int8_t rf_sensitivity = -98;
+
+    /*rssi < RF sensitivity*/
+    if(rssi < rf_sensitivity)
+        scaled_lqi=0;
+    /*-91 dBm < rssi < -81 dBm (AT86RF233 XPro)*/
+    /*-90 dBm < rssi < -80 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 10))
+        scaled_lqi=31;
+    /*-81 dBm < rssi < -71 dBm (AT86RF233 XPro)*/
+    /*-80 dBm < rssi < -70 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 20))
+        scaled_lqi=207;
+    /*-71 dBm < rssi < -61 dBm (AT86RF233 XPro)*/
+    /*-70 dBm < rssi < -60 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 30))
+        scaled_lqi=255;
+    /*-61 dBm < rssi < -51 dBm (AT86RF233 XPro)*/
+    /*-60 dBm < rssi < -50 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 40))
+        scaled_lqi=255;
+    /*-51 dBm < rssi < -41 dBm (AT86RF233 XPro)*/
+    /*-50 dBm < rssi < -40 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 50))
+        scaled_lqi=255;
+    /*-41 dBm < rssi < -31 dBm (AT86RF233 XPro)*/
+    /*-40 dBm < rssi < -30 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 60))
+        scaled_lqi=255;
+    /*-31 dBm < rssi < -21 dBm (AT86RF233 XPro)*/
+    /*-30 dBm < rssi < -20 dBm (AT86RF212B XPro)*/
+    else if(rssi < (rf_sensitivity + 70))
+        scaled_lqi=255;
+    /*rssi > RF saturation*/
+    else if(rssi > (rf_sensitivity + 80))
+        scaled_lqi=111;
+    /*-21 dBm < rssi < -11 dBm (AT86RF233 XPro)*/
+    /*-20 dBm < rssi < -10 dBm (AT86RF212B XPro)*/
+    else
+        scaled_lqi=255;
+
+    return scaled_lqi;
+}
+
+
+/*****************************************************************************/
+/*              Layer porting to the Freescale driver                        */
+/*****************************************************************************/
+extern "C" void xcvr_spi_init(uint32_t instance)
+{
+    (void)instance;
+}
+
+extern "C" void RF_IRQ_Init(void) {
+    MBED_ASSERT(irq != NULL);
+    irq->mode(PullUp);
+    irq->fall(&PHY_InterruptHandler);
+}
+
+extern "C" void RF_IRQ_Enable(void) {
+    MBED_ASSERT(irq != NULL);
+    irq->enable_irq();
+}
+
+extern "C" void RF_IRQ_Disable(void) {
+    MBED_ASSERT(irq != NULL);
+    irq->disable_irq();
+}
+
+extern "C" uint8_t RF_isIRQ_Pending(void) {
+    MBED_ASSERT(rf != NULL);
+    return !irq_pin->read();
+}
+
+extern "C" void RF_RST_Set(int state) {
+    MBED_ASSERT(rst != NULL);
+    *rst = state;
+}
+
+extern "C" void gXcvrAssertCS_d(void)
+{
+    MBED_ASSERT(cs != NULL);
+    *cs = 0;
+}
+
+extern "C" void gXcvrDeassertCS_d(void)
+{
+    MBED_ASSERT(cs != NULL);
+    *cs = 1;
+}
+
+extern "C" void xcvr_spi_configure_speed(uint32_t instance, uint32_t freq)
+{
+    MBED_ASSERT(spi != NULL);
+    (void)instance;
+    spi->frequency(freq);
+}
+
+extern "C" void xcvr_spi_transfer(uint32_t instance,
+                         uint8_t * sendBuffer,
+                         uint8_t * receiveBuffer,
+                         size_t transferByteCount)
+{
+    MBED_ASSERT(spi != NULL);
+    (void)instance;
+    volatile uint8_t dummy;
+
+    if( !transferByteCount )
+        return;
+
+    if( !sendBuffer && !receiveBuffer )
+        return;
+
+    while( transferByteCount-- )
+    {
+        if( sendBuffer )
+        {
+            dummy = *sendBuffer;
+            sendBuffer++;
+        }
+        else
+        {
+            dummy = 0xFF;
+        }
+
+        dummy = spi->write(dummy);
+
+        if( receiveBuffer )
+        {
+            *receiveBuffer = dummy;
+            receiveBuffer++;
+        }
+    }
+}
+
+/*****************************************************************************/
+/*****************************************************************************/
+
+static void rf_if_lock(void)
+{
+    platform_enter_critical();
+}
+
+static void rf_if_unlock(void)
+{
+    platform_exit_critical();
+}
+
+NanostackRfPhyMcr20a::NanostackRfPhyMcr20a(PinName spi_mosi, PinName spi_miso,
+        PinName spi_sclk, PinName spi_cs,  PinName spi_rst, PinName spi_irq)
+    : _spi(spi_mosi, spi_miso, spi_sclk), _rf_cs(spi_cs), _rf_rst(spi_rst),
+      _rf_irq(spi_irq), _rf_irq_pin(spi_irq)
+{
+    // Do nothing
+}
+
+NanostackRfPhyMcr20a::~NanostackRfPhyMcr20a()
+{
+    // Do nothing
+}
+
+int8_t NanostackRfPhyMcr20a::rf_register()
+{
+
+    rf_if_lock();
+
+    if (rf != NULL) {
+        rf_if_unlock();
+        error("Multiple registrations of NanostackRfPhyMcr20a not supported");
+        return -1;
+    }
+
+    _pins_set();
+    int8_t radio_id = rf_device_register();
+    if (radio_id < 0) {
+        _pins_clear();
+        rf = NULL;
+    }
+
+    rf_if_unlock();
+    return radio_id;
+}
+
+void NanostackRfPhyMcr20a::rf_unregister()
+{
+    rf_if_lock();
+
+    if (rf != this) {
+        rf_if_unlock();
+        return;
+    }
+
+    rf_device_unregister();
+    rf = NULL;
+    _pins_clear();
+
+    rf_if_unlock();
+}
+
+void NanostackRfPhyMcr20a::get_mac_address(uint8_t *mac)
+{
+    rf_if_lock();
+
+    memcpy((void*)mac, (void*)MAC_address, sizeof(MAC_address));
+
+    rf_if_unlock();
+}
+
+void NanostackRfPhyMcr20a::set_mac_address(uint8_t *mac)
+{
+    rf_if_lock();
+
+    if (NULL != rf) {
+        error("NanostackRfPhyAtmel cannot change mac address when running");
+        rf_if_unlock();
+        return;
+    }
+    memcpy((void*)MAC_address, (void*)mac, sizeof(MAC_address));
+
+    rf_if_unlock();
+}
+
+void NanostackRfPhyMcr20a::_pins_set()
+{
+    spi = &_spi;
+    cs = &_rf_cs;
+    rst = &_rf_rst;
+    irq = &_rf_irq;
+    irq_pin = &_rf_irq_pin;
+}
+
+void NanostackRfPhyMcr20a::_pins_clear()
+{
+    spi = NULL;
+    cs = NULL;
+    rst = NULL;
+    irq = NULL;
+    irq_pin = NULL;
+}