Esempio n. 1
0
/*
 * \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;
}
Esempio n. 2
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(MAC_reversed);
            break;
        /*Set 16-bit address*/
        case PHY_MAC_16BIT:
            short_address = address_ptr[0] << 8 | address_ptr[1];
            RAIL_IEEE802154_SetShortAddress(short_address);
            break;
        /*Set PAN Id*/
        case PHY_MAC_PANID:
            PAN_address = address_ptr[0] << 8 | address_ptr[1];
            RAIL_IEEE802154_SetPanId(PAN_address);
            break;
    }
    return ret_val;
}
Esempio n. 3
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:
            RAIL_RfIdle();
            radio_state = RADIO_IDLE;
            break;
        /* Disable PHY Interface driver */
        case PHY_INTERFACE_DOWN:
            RAIL_RfIdle();
            radio_state = RADIO_IDLE;
            break;
        /* Enable RX */
        case PHY_INTERFACE_UP:
            if(rail_checkAndSwitchChannel(rf_channel)) {
                RAIL_IEEE802154_SetPromiscuousMode(false);
                RAIL_RxStart(channel);
                radio_state = RADIO_RX;
            } 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_IEEE802154_SetPromiscuousMode(true);
                RAIL_RxStart(channel);
                radio_state = RADIO_RX;
            } else {
                ret_val = -1;
            }
            break;
    }
    return ret_val;
}
Esempio n. 4
0
/**
 * Interrupt level callback
 * Allows the user finer granularity in tx radio events.
 *
 * Radio Statuses:
 * RAIL_TX_CONFIG_BUFFER_UNDERFLOW
 * RAIL_TX_CONFIG_CHANNEL_BUSY
 *
 * @param[in] status A bit field that defines what event caused the callback
 */
void RAILCb_TxRadioStatus(uint8_t status) {
   if(device_driver.phy_tx_done_cb != NULL) {
    if(status == RAIL_TX_CONFIG_BUFFER_UNDERFLOW ||
       status == RAIL_TX_CONFIG_CHANNEL_BUSY ||
       status == RAIL_TX_CONFIG_TX_ABORTED ||
       status == RAIL_TX_CONFIG_TX_BLOCKED) {
        waiting_for_ack = false;
#ifdef MBED_CONF_RTOS_PRESENT
        osSignalSet(rf_thread_id, SL_TX_ERR);
    }
#else
        device_driver.phy_tx_done_cb(rf_radio_driver_id,
                                      current_tx_handle,
                                      PHY_LINK_CCA_FAIL,
                                      8,
                                      1);
    } else {
        SL_DEBUG_PRINT("Packet TX error %d\n", status);
    }
#endif
  }
Esempio n. 5
0
/*
 * \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 )
{

    RAIL_TxData_t txData = {
        data_ptr,
        data_length + 3
    };

    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_RfStateGet() == 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();

        data_ptr[0] = data_length + 2;
        RAIL_RfIdleExt(RAIL_IDLE_ABORT , true);
        RAIL_TxDataLoad(&txData);
        radio_state = RADIO_TX;

        RAIL_TxOptions_t txOpt;
        //Check to see whether we'll be waiting for an ACK
        if(data_ptr[1] & (1 << 5)) {
            txOpt.waitForAck = true;
            waiting_for_ack = true;
        } else {
            txOpt.waitForAck = 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_TxStartWithOptions(channel, &txOpt, &RAIL_CcaCsma, (RAIL_CsmaConfig_t*) &csma_config) == 0) {
          //Save packet number and sequence
          current_tx_handle = tx_handle;
          current_tx_sequence = data_ptr[3];
          platform_exit_critical();
          return 0;
        } else {
          RAIL_RfIdle();
          RAIL_RxStart(channel);
          radio_state = RADIO_RX;
          platform_exit_critical();
          return -1;
        }
    }
    //Should never get here...
    platform_exit_critical();
    return -1;
}
Esempio n. 6
0
static void rf_thread_loop(const void *arg)
{
    SL_DEBUG_PRINT("rf_thread_loop: starting (id: %d)\n", 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) {
                void* handle = (void*) rx_queue[rx_queue_tail];
                RAIL_RxPacketInfo_t* info = (RAIL_RxPacketInfo_t*) memoryPtrFromHandle(handle);
                device_driver.phy_rx_cb(
                        info->dataPtr + 1,
                        info->dataLength - 1, 
                        info->appendedInfo.lqi, 
                        info->appendedInfo.rssiLatch, 
                        rf_radio_driver_id);

                memoryFree(handle);
                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_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, event.value.signals);
        }

        platform_exit_critical();
    }
}
Esempio n. 7
0
/*
 * \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");

#if MBED_CONF_SL_RAIL_BAND == 2400
    RADIO_PA_Init((RADIO_PAInit_t*)&paInit2p4);
#elif (MBED_CONF_SL_RAIL_BAND == 915) || (MBED_CONF_SL_RAIL_BAND == 868)
    RADIO_PA_Init((RADIO_PAInit_t*)&paInitSubGhz);
#endif

    // Set up PTI since it makes life so much easier
#if defined(MBED_CONF_SL_RAIL_PTI) && (MBED_CONF_SL_RAIL_PTI == 1)
    RADIO_PTIInit_t ptiInit = {
        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
    };

    RADIO_PTI_Init(&ptiInit);
#endif

    // Set up RAIL
    RAIL_RfInit(&railInitParams);
    RAIL_ChannelConfig(&channels);
#if (MBED_CONF_SL_RAIL_BAND == 2400)
    RAIL_RadioConfig((void*) ieee802154_config_base);
    channel = 11;
#elif (MBED_CONF_SL_RAIL_BAND == 915)
    RAIL_RadioConfig((void*) ieee802154_config_915);
    channel = 1;
#elif (MBED_CONF_SL_RAIL_BAND == 868)
    RAIL_RadioConfig((void*) ieee802154_config_863);
    channel = 0;
#endif
    RAIL_IEEE802154_Init((RAIL_IEEE802154_Config_t*)&config);

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

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

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

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

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

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

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

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

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

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

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

            // TX Event Bitmasks

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

            // Scheduler Event Bitmasks: Not used

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

            // Other Event Bitmasks

            /*
            * Notifies the application that a calibration is needed.
            * It occurs whenever the RAIL library detects that a
            * calibration is needed. An application determines a valid
            * window to call \ref RAIL_Calibrate().
            */
            case RAIL_EVENT_CAL_NEEDED_SHIFT:
#ifdef MBED_CONF_RTOS_PRESENT
                osSignalSet(rf_thread_id, SL_CAL_REQ);
#else
                SL_DEBUG_PRINT("!!!! Calling for calibration\n");
#endif
                break;
            default:
                break;
            }
        }
        events = events >> 1;
        index += 1;
    }
    while (events != 0);
}
/*
 * \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 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 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;
}
static void rf_thread_loop(const void *arg)
{
    SL_DEBUG_PRINT("rf_thread_loop: starting (id: %d)\n", (int)rf_thread_id);
    for (;;) {
        osEvent event = osSignalWait(0, osWaitForever);

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

        platform_enter_critical();

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

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

        platform_exit_critical();
    }
}