mbed-os/features/nanostack/FEATURE_NANOSTACK/targets/TARGET_SL_RAIL/NanostackRfPhyEfr32.cpp

890 lines
28 KiB
C++

/*
* Copyright (c) 2016 Silicon Laboratories, Inc. http://www.silabs.com
* SPDX-License-Identifier: Apache-2.0
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "NanostackRfPhyEfr32.h"
#include "ns_types.h"
#include "platform/arm_hal_interrupt.h"
#include "nanostack/platform/arm_hal_phy.h"
#include "mbed_toolchain.h"
#include <string.h>
#include "mbed-trace/mbed_trace.h"
#define TRACE_GROUP "SLRF"
/* Silicon Labs headers */
extern "C" {
#include "rail/rail.h"
#include "rail/pa.h"
#include "rail/pti.h"
#include "rail/ieee802154/rail_ieee802154.h"
#include "buffer-pool-memory-manager/buffer_pool_allocator.h"
}
/* RF driver data */
static phy_device_driver_s device_driver;
static int8_t rf_radio_driver_id = -1;
static uint8_t MAC_address[8];
static uint16_t PAN_address;
static uint16_t short_address;
/* Driver instance handle */
static NanostackRfPhyEfr32 *rf = NULL;
/* Channel configurations */
static const phy_rf_channel_configuration_s phy_24ghz = {2405000000U, 5000000U, 250000U, 16U, M_OQPSK};
static const phy_rf_channel_configuration_s phy_subghz = {868300000U, 2000000U, 250000U, 11U, M_OQPSK};
static const phy_device_channel_page_s phy_channel_pages[] = {
{ CHANNEL_PAGE_0, &phy_24ghz},
{ CHANNEL_PAGE_2, &phy_subghz},
{ CHANNEL_PAGE_0, NULL}
};
/* Driver structures */
typedef enum {
RADIO_UNINIT,
RADIO_INITING,
RADIO_IDLE,
RADIO_TX,
RADIO_RX,
RADIO_CALIBRATION
} siliconlabs_modem_state_t;
static const RAIL_CsmaConfig_t csma_config = RAIL_CSMA_CONFIG_802_15_4_2003_2p4_GHz_OQPSK_CSMA;
#if defined(TARGET_EFR32MG1)
#include "ieee802154_subg_efr32xg1_configurator_out.h"
#include "ieee802154_efr32xg1_configurator_out.h"
#elif defined(TARGET_EFR32MG12)
#include "ieee802154_efr32xg12_configurator_out.h"
#else
#error "Not a valid target."
#endif
static const RAIL_ChannelConfigEntry_t entry[] = {
{0U, 0U, 600000U, 868300000U},
{1U, 10U, 2000000U, 906000000U},
{11U, 26U, 5000000U, 2405000000U}
};
#if MBED_CONF_SL_RAIL_BAND == 868
#ifndef MBED_CONF_SL_RAIL_HAS_SUBGIG
#error "Sub-Gigahertz band is not supported on this target."
#endif
static const RAIL_ChannelConfig_t channels = {
(RAIL_ChannelConfigEntry_t *) &entry[0],
1
};
#elif MBED_CONF_SL_RAIL_BAND == 915
#ifndef MBED_CONF_SL_RAIL_HAS_SUBGIG
#error "Sub-Gigahertz band is not supported on this target."
#endif
static const RAIL_ChannelConfig_t channels = {
(RAIL_ChannelConfigEntry_t *) &entry[1],
1
};
#elif MBED_CONF_SL_RAIL_BAND == 2400
#ifndef MBED_CONF_SL_RAIL_HAS_2P4
#error "2.4GHz band is not supported on this target."
#endif
static const RAIL_ChannelConfig_t channels = {
(RAIL_ChannelConfigEntry_t *) &entry[2],
1
};
#else
#error "sl-rail.band is not correctly defined"
#endif
static const RAIL_IEEE802154_Config_t config = { false, false,
RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES,
RAIL_RF_STATE_RX, 100, 192, 894, NULL };
static const RAIL_Init_t railInitParams = { 140, 38400000, RAIL_CAL_ALL_PENDING };
#if defined (MBED_CONF_SL_RAIL_HAS_2P4)
// Set up the PA for 2.4 GHz operation
static const RADIO_PAInit_t paInit2p4 = {
PA_SEL_2P4_HP, /* Power Amplifier mode */
PA_VOLTMODE_DCDC, /* Power Amplifier vPA Voltage mode */
100, /* Desired output power in dBm * 10 */
0, /* Output power offset in dBm * 10 */
10 /* Desired ramp time in us */
};
#endif
#if defined (MBED_CONF_SL_RAIL_HAS_SUBGIG)
// Set up the PA for sub-GHz operation
static const RADIO_PAInit_t paInitSubGhz = {
PA_SEL_SUBGIG, /* Power Amplifier mode */
PA_VOLTMODE_DCDC, /* Power Amplifier vPA Voltage mode */
100, /* Desired output power in dBm * 10 */
0, /* Output power offset in dBm * 10 */
10 /* Desired ramp time in us */
};
#endif
static volatile siliconlabs_modem_state_t radio_state = RADIO_UNINIT;
static volatile int8_t channel = -1;
static volatile uint8_t current_tx_handle = 0;
static volatile uint8_t current_tx_sequence = 0;
static volatile bool waiting_for_ack = false;
static volatile bool data_pending = false, last_ack_pending_bit = false;
static volatile uint32_t last_tx = 0;
/* ARM_NWK_HAL prototypes */
static int8_t rf_extension(phy_extension_type_e extension_type, uint8_t *data_ptr);
static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel);
static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr);
static int8_t rf_start_cca(uint8_t *data_ptr, uint16_t data_length, uint8_t tx_handle, data_protocol_e data_protocol );
/* Local function prototypes */
static bool rail_checkAndSwitchChannel(uint8_t channel);
/*============ CODE =========*/
/*
* \brief Function initialises and registers the RF driver.
*
* \param none
*
* \return rf_radio_driver_id Driver ID given by NET library
*/
static int8_t rf_device_register(void)
{
// If we already exist, bail.
if(radio_state != RADIO_UNINIT) {
return -1;
}
#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;
}
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 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:
tr_debug("Radio uninit\n");
return -1;
case RADIO_INITING:
tr_debug("Radio initing\n");
return -1;
case RADIO_CALIBRATION:
tr_debug("Radio calibrating\n");
return -1;
case RADIO_TX:
tr_debug("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) {
tr_debug("Still waiting on previous ACK\n");
return -1;
} else {
tr_debug("TXerr\n");
}
}
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;
}
//tr_debug("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];
return 0;
} else {
RAIL_RfIdle();
RAIL_RxStart(channel);
radio_state = RADIO_RX;
return -1;
}
}
//Should never get here...
return -1;
}
/*
* \brief Function gives the control of RF states to MAC.
*
* \param new_state RF state
* \param rf_channel RF channel
*
* \return 0 Success
*/
static int8_t rf_interface_state_control(phy_interface_state_e new_state, uint8_t rf_channel)
{
int8_t ret_val = 0;
switch (new_state)
{
/* Reset PHY driver and set to idle */
case PHY_INTERFACE_RESET:
RAIL_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:
tr_debug("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;
}
/*
* \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
tr_debug("Trying to read link status\n");
break;
/* Convert between LQI and RSSI */
case PHY_EXTENSION_CONVERT_SIGNAL_INFO:
// TODO: return accurate value here
tr_debug("Trying to read signal info\n");
break;
}
return 0;
}
/*
* \brief Function sets the addresses to RF address filters.
*
* \param address_type Type of address
* \param address_ptr Pointer to given address
*
* \return 0 Success
*/
static int8_t rf_address_write(phy_address_type_e address_type, uint8_t *address_ptr)
{
int8_t ret_val = 0;
switch (address_type)
{
/*Set 48-bit address*/
case PHY_MAC_48BIT:
// 15.4 does not support 48-bit addressing
ret_val = -1;
break;
/*Set 64-bit MAC address*/
case PHY_MAC_64BIT:
/* Store MAC in MSB order */
memcpy(MAC_address, address_ptr, 8);
tr_debug("MACw ");
for(unsigned int i = 0; i < sizeof(MAC_address); i ++) {
tr_debug("%02x:", MAC_address[i]);
}
tr_debug("\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];
tr_debug("Filter EUI16 %04x\n", short_address);
RAIL_IEEE802154_SetShortAddress(short_address);
break;
/*Set PAN Id*/
case PHY_MAC_PANID:
PAN_address = address_ptr[0] << 8 | address_ptr[1];
tr_debug("Filter PAN %04x\n", PAN_address);
RAIL_IEEE802154_SetPanId(PAN_address);
break;
}
return ret_val;
}
/*****************************************************************************/
/*****************************************************************************/
static void rf_if_lock(void)
{
platform_enter_critical();
}
static void rf_if_unlock(void)
{
platform_exit_critical();
}
NanostackRfPhyEfr32::NanostackRfPhyEfr32() : NanostackRfPhy()
{
// Do nothing
}
NanostackRfPhyEfr32::~NanostackRfPhyEfr32()
{
rf_unregister();
}
int8_t NanostackRfPhyEfr32::rf_register()
{
rf_if_lock();
if (rf != NULL) {
rf_if_unlock();
error("Multiple registrations of NanostackRfPhyEfr32 not supported");
return -1;
}
int8_t radio_id = rf_device_register();
if (radio_id < 0) {
rf = NULL;
} else {
rf = this;
}
rf_if_unlock();
return radio_id;
}
void NanostackRfPhyEfr32::rf_unregister()
{
rf_if_lock();
if (rf != this) {
rf_if_unlock();
return;
}
rf_device_unregister();
rf = NULL;
rf_if_unlock();
}
void NanostackRfPhyEfr32::get_mac_address(uint8_t *mac)
{
rf_if_lock();
memcpy(mac, MAC_address, sizeof(MAC_address));
rf_if_unlock();
}
void NanostackRfPhyEfr32::set_mac_address(uint8_t *mac)
{
rf_if_lock();
if (NULL != rf) {
error("NanostackRfPhyEfr32 cannot change mac address when running");
rf_if_unlock();
return;
}
memcpy(MAC_address, mac, sizeof(MAC_address));
rf_if_unlock();
}
uint32_t NanostackRfPhyEfr32::get_driver_version()
{
RAIL_Version_t railversion;
RAIL_VersionGet(&railversion, true);
return (railversion.major << 24) |
(railversion.minor << 16) |
(railversion.rev << 8) |
(railversion.build);
}
//====================== RAIL-defined callbacks =========================
/**
* Callback that lets the app know when the radio has finished init
* and is ready.
*/
void RAILCb_RfReady(void) {
radio_state = RADIO_IDLE;
}
/**
* 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;
device_driver.phy_tx_done_cb( rf_radio_driver_id,
current_tx_handle,
PHY_LINK_CCA_FAIL,
8,
1);
} else {
tr_debug("Packet TX error %d\n", status);
}
}
radio_state = RADIO_RX;
}
/**
* Called whenever an enabled radio status event occurs
*
* Triggers:
* RAIL_RX_CONFIG_PREAMBLE_DETECT
* RAIL_RX_CONFIG_SYNC1_DETECT
* RAIL_RX_CONFIG_SYNC2_DETECT
* RAIL_RX_CONFIG_INVALID_CRC
* RAIL_RX_CONFIG_BUFFER_OVERFLOW
* RAIL_RX_CONFIG_ADDRESS_FILTERED
*
* @param[in] status The event that triggered this callback
*/
void RAILCb_RxRadioStatus(uint8_t status) {
switch(status) {
case RAIL_RX_CONFIG_ADDRESS_FILTERED:
break;
default:
tr_debug("RXE %d\n", status);
break;
}
}
/**
* Callback that notifies the application that a calibration is needed.
*
* This callback function is called whenever the RAIL library detects that a
* calibration is needed. It is up to the application to determine a valid
* window to call RAIL_CalStart().
*
*/
void RAILCb_CalNeeded(void) {
// TODO: Implement on-the-fly recalibration
tr_debug("!!!! Calling for calibration\n");
}
/**
* Interrupt level callback to signify when the radio changes state.
*
* @param[in] state Current state of the radio, as defined by EFR32 data sheet
*/
void RAILCb_RadioStateChanged(uint8_t state) {
return;
}
/**
* This function is called when the RAIL timer expires
*
* You must implement a stub for this in your RAIL application even if you
* don't use the timer.
*/
void RAILCb_TimerExpired(void) {
}
/**
* Interrupt level callback to signify when the packet was sent
* @param txPacketInfo Information about the packet that was transmitted.
* @note that this structure is only valid during the timeframe of the
* callback.
*/
void RAILCb_TxPacketSent(RAIL_TxPacketInfo_t *txPacketInfo) {
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);
}
last_tx = RAIL_GetTime();
radio_state = RADIO_RX;
}
/**
* Receive packet callback.
*
* @param[in] rxPacketHandle Contains a handle that points to the memory that
* the packet was stored in. This handle will be the same as something
* returned by the RAILCb_AllocateMemory() API. To convert this into a receive
* packet info struct use the *** function.
*
* This function is called whenever a packet is received and returns to you the
* memory handle for where this received packet and its appended information was
* stored. After this callback is done we will release the memory handle so you
* must somehow increment a reference count or copy the data out within this
* function.
*/
void RAILCb_RxPacketReceived(void *rxPacketHandle) {
RAIL_RxPacketInfo_t* rxPacketInfo = (RAIL_RxPacketInfo_t*) memoryPtrFromHandle(rxPacketHandle);
if(rxPacketInfo->appendedInfo.crcStatus) {
/* If this is an ACK, deal with it */
if( rxPacketInfo->dataLength == 4 &&
rxPacketInfo->dataPtr[3] == (current_tx_sequence) &&
waiting_for_ack) {
/* Tell the radio to not ACK an ACK */
RAIL_AutoAckCancelAck();
waiting_for_ack = false;
/* Save the pending bit */
last_ack_pending_bit = (rxPacketInfo->dataPtr[1] & (1 << 4)) != 0;
/* Tell the stack we got an ACK */
//tr_debug("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);
} else {
/* Figure out whether we want to not ACK this packet */
/*
* dataPtr[0] = length
* dataLength = length w/o length byte
* dataptr[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( (rxPacketInfo->dataPtr[1] & (1 << 5)) == 0 ) {
/* Cancel the ACK if the sender did not request one */
RAIL_AutoAckCancelAck();
}
//tr_debug("rPKT %d\n", rxPacketInfo->dataLength);
/* Feed the received packet into the stack */
device_driver.phy_rx_cb(rxPacketInfo->dataPtr + 1,
rxPacketInfo->dataLength - 1,
//TODO: take a new RAIL release that exposes LQI, or have LQI as function of RSSI
255,
rxPacketInfo->appendedInfo.rssiLatch,
rf_radio_driver_id);
}
}
}
/**
* 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();
}
}
/**
* Callback that notifies the application when searching for an ACK has timed
* out.
*
* @return void
*
* This callback function is called whenever the timeout for searching for an
* ack is exceeded.
*/
void RAILCb_RxAckTimeout(void) {
if(waiting_for_ack) {
tr_debug("nACK\n");
waiting_for_ack = false;
device_driver.phy_tx_done_cb( rf_radio_driver_id,
current_tx_handle,
PHY_LINK_TX_FAIL,
1,
1);
}
}
/**
* Function to check the requested channel against the current channel,
* and change the radio configuration if necessary.
*
* @param channel The new channel number requested
* @return bool True if able to switch to the requested channel
*
*/
static bool rail_checkAndSwitchChannel(uint8_t newChannel) {
if(channel == newChannel) {
return true;
}
if(newChannel > 0 && newChannel < 11) {
if(MBED_CONF_SL_RAIL_BAND == 915) {
channel = newChannel;
return true;
} else {
return false;
}
} else if(newChannel >= 11 && newChannel <= 26) {
if(MBED_CONF_SL_RAIL_BAND == 2400) {
channel = newChannel;
return true;
} else {
return false;
}
} else {
return false;
}
}
/**
* Callback that fires when the receive fifo exceeds the configured threshold
* value
*
* @param[in] bytesAvailable Number of bytes available in the receive fifo at
* the time of the callback dispatch
*
* @return void
* @warning You must implement a stub for this in your RAIL application.
*
* Callback that fires when the receive fifo exceeds the configured threshold
* value. Provides the number of bytes available in the receive fifo at the
* time of the callback dispatch.
*/
void RAILCb_RxFifoAlmostFull(uint16_t bytesAvailable) {
tr_debug("RX near full (%d)\n", bytesAvailable);
}
/**
* Callback that fires when the transmit fifo falls under the configured
* threshold value
*
* @param[in] spaceAvailable Number of bytes open in the transmit fifo at the
* time of the callback dispatch
*
* @return void
* @warning You must implement a stub for this in your RAIL application.
*
* Callback that fires when the transmit fifo falls under the configured
* threshold value. It only fires if a rising edge occurs across this
* threshold. This callback will not fire on initailization nor after resetting
* the transmit fifo with RAIL_ResetFifo().
*
* Provides the number of bytes open in the transmit fifo at the time of the
* callback dispatch.
*/
void RAILCb_TxFifoAlmostEmpty(uint16_t spaceAvailable) {
tr_debug("TX near empty (%d)\n", spaceAvailable);
}
/**
* Callback for when AGC averaged RSSI is done
*
* @param avgRssi Contains the the RSSI in quarter dBm (dbm*4) on success and
* returns \ref RAIL_RSSI_INVALID if there was a problem computing the result.
*
* Called in response to RAIL_StartAverageRSSI() to indicate that the hardware
* has completed averaging. If you would like you can instead use the
* RAIL_AverageRSSIReady() to wait for completion and RAIL_GetAverageRSSI() to
* get the result.
*/
void RAILCb_RssiAverageDone(int16_t avgRssi) {
tr_debug("RSSI done (%d)\n", avgRssi);
}