Example #1
0
/**
 * Callback for when a Data Request is being received
 *
 * @param address The source address of the data request command
 *
 * This function is called when the command byte of an incoming frame is for a
 * data request, which requests an ACK. This callback will be called before the
 * packet is fully received, to allow the node to have more time to decide
 * whether to set frame pending in the outgoing ACK.
 */
void RAILCb_IEEE802154_DataRequestCommand(RAIL_IEEE802154_Address_t *address) {
    if(data_pending) {
        RAIL_IEEE802154_SetFramePending();
    }
}
/**
 * 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);
}