blob: 5e82f856cb28990ab58b801e483f86ff352a54db [file] [log] [blame]
/*
* Copyright (c) 2017, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file implements the OpenThread platform abstraction for radio communication.
*
*/
#include <assert.h>
#include <openthread/types.h>
#include <openthread/config.h>
#include <openthread/platform/platform.h>
#include <openthread/platform/radio.h>
#include <openthread/platform/diag.h>
#include "common/logging.hpp"
#include "utils/code_utils.h"
#include "em_core.h"
#include "em_system.h"
#include "rail.h"
#include "rail_ieee802154.h"
#include "openthread-core-efr32-config.h"
enum
{
IEEE802154_MIN_LENGTH = 5,
IEEE802154_MAX_LENGTH = 127,
IEEE802154_ACK_LENGTH = 5,
IEEE802154_FRAME_TYPE_MASK = 0x7,
IEEE802154_FRAME_TYPE_ACK = 0x2,
IEEE802154_FRAME_PENDING = 1 << 4,
IEEE802154_ACK_REQUEST = 1 << 5,
IEEE802154_DSN_OFFSET = 2,
};
enum
{
EFR32_RECEIVE_SENSITIVITY = -100, // dBm
};
static uint16_t sPanId = 0;
static uint8_t sChannel = 0;
static bool sTransmitBusy = false;
static bool sPromiscuous = false;
static bool sIsReceiverEnabled = false;
static bool sIsSrcMatchEnabled = false;
static otRadioState sState = OT_RADIO_STATE_DISABLED;
static uint8_t sReceiveBuffer[IEEE802154_MAX_LENGTH + 1 + sizeof(RAIL_RxPacketInfo_t)];
static uint8_t sReceivePsdu[IEEE802154_MAX_LENGTH];
static otRadioFrame sReceiveFrame;
static otError sReceiveError;
static otRadioFrame sTransmitFrame;
static uint8_t sTransmitPsdu[IEEE802154_MAX_LENGTH];
static otError sTransmitError;
typedef struct srcMatchEntry
{
uint16_t checksum;
bool allocated;
} sSrcMatchEntry;
static sSrcMatchEntry srcMatchShortEntry[RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM];
static sSrcMatchEntry srcMatchExtEntry[RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM];
void efr32RadioInit(void)
{
// Data Management
RAIL_DataConfig_t railDataConfig =
{
TX_PACKET_DATA,
RX_PACKET_DATA,
PACKET_MODE,
PACKET_MODE,
};
RAIL_DataConfig(&railDataConfig);
// 802.15.4 configuration
RAIL_IEEE802154_Config_t config =
{
false, // promiscuousMode
false, // isPanCoordinator
RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES, // framesMask
RAIL_RF_STATE_RX, // defaultState
100, // idleTime
192, // turnaroundTime
894, // ackTimeout
NULL // addresses
};
sReceiveFrame.mLength = 0;
sReceiveFrame.mPsdu = sReceivePsdu;
sTransmitFrame.mLength = 0;
sTransmitFrame.mPsdu = sTransmitPsdu;
if (RAIL_IEEE802154_2p4GHzRadioConfig())
{
assert(false);
}
if (RAIL_IEEE802154_Init(&config))
{
assert(false);
}
RAIL_TxPowerSet(OPENTHREAD_CONFIG_DEFAULT_MAX_TRANSMIT_POWER);
otLogInfoPlat(sInstance, "Initialized", NULL);
}
void efr32RadioDeinit(void)
{
RAIL_RfIdle();
RAIL_IEEE802154_Deinit();
}
void setChannel(uint8_t aChannel)
{
bool enabled = false;
otEXPECT(sChannel != aChannel);
if (sIsReceiverEnabled)
{
RAIL_RfIdle();
enabled = true;
sIsReceiverEnabled = false;
}
otLogInfoPlat(sInstance, "Channel=%d", aChannel);
sChannel = aChannel;
if (enabled)
{
if (RAIL_RxStart(aChannel))
{
assert(false);
}
sIsReceiverEnabled = true;
}
exit:
return;
}
void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64)
{
uint64_t eui64;
uint8_t *eui64Ptr = NULL;
(void)aInstance;
eui64 = SYSTEM_GetUnique();
eui64Ptr = (uint8_t *)&eui64;
for (uint8_t i = 0; i < OT_EXT_ADDRESS_SIZE; i++)
{
aIeeeEui64[i] = eui64Ptr[(OT_EXT_ADDRESS_SIZE - 1) - i];
}
}
void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId)
{
(void)aInstance;
otLogInfoPlat(sInstance, "PANID=%X", aPanId);
sPanId = aPanId;
RAIL_IEEE802154_SetPanId(aPanId);
}
void otPlatRadioSetExtendedAddress(otInstance *aInstance, uint8_t *aAddress)
{
(void)aInstance;
otLogInfoPlat(sInstance, "ExtAddr=%X%X%X%X%X%X%X%X",
aAddress[7], aAddress[6], aAddress[5], aAddress[4],
aAddress[3], aAddress[2], aAddress[1], aAddress[0]);
RAIL_IEEE802154_SetLongAddress(aAddress);
}
void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress)
{
(void)aInstance;
otLogInfoPlat(sInstance, "ShortAddr=%X", aAddress);
RAIL_IEEE802154_SetShortAddress(aAddress);
}
bool otPlatRadioIsEnabled(otInstance *aInstance)
{
(void)aInstance;
return (sState != OT_RADIO_STATE_DISABLED);
}
otError otPlatRadioEnable(otInstance *aInstance)
{
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
otEXPECT(!otPlatRadioIsEnabled(aInstance));
otLogInfoPlat(sInstance, "State=OT_RADIO_STATE_SLEEP", NULL);
sState = OT_RADIO_STATE_SLEEP;
exit:
CORE_EXIT_CRITICAL();
return OT_ERROR_NONE;
}
otError otPlatRadioDisable(otInstance *aInstance)
{
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
otEXPECT(otPlatRadioIsEnabled(aInstance));
otLogInfoPlat(sInstance, "State=OT_RADIO_STATE_DISABLED", NULL);
sState = OT_RADIO_STATE_DISABLED;
exit:
CORE_EXIT_CRITICAL();
return OT_ERROR_NONE;
}
otError otPlatRadioSleep(otInstance *aInstance)
{
otError error = OT_ERROR_NONE;
(void)aInstance;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
otEXPECT_ACTION((sState != OT_RADIO_STATE_TRANSMIT) && (sState != OT_RADIO_STATE_DISABLED),
error = OT_ERROR_INVALID_STATE);
otLogInfoPlat(sInstance, "State=OT_RADIO_STATE_SLEEP", NULL);
sState = OT_RADIO_STATE_SLEEP;
if (sIsReceiverEnabled)
{
RAIL_RfIdleExt(RAIL_IDLE, true);
sIsReceiverEnabled = false;
}
exit:
CORE_EXIT_CRITICAL();
return error;
}
otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
{
otError error = OT_ERROR_NONE;
(void)aInstance;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
otEXPECT_ACTION(sState != OT_RADIO_STATE_DISABLED, error = OT_ERROR_INVALID_STATE);
otLogInfoPlat(sInstance, "State=OT_RADIO_STATE_RECEIVE", NULL);
sState = OT_RADIO_STATE_RECEIVE;
setChannel(aChannel);
sReceiveFrame.mChannel = aChannel;
if (!sIsReceiverEnabled)
{
otEXPECT_ACTION(RAIL_RxStart(aChannel) == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED);
sIsReceiverEnabled = true;
}
exit:
CORE_EXIT_CRITICAL();
return error;
}
otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame)
{
otError error = OT_ERROR_NONE;
RAIL_CsmaConfig_t csmaConfig = RAIL_CSMA_CONFIG_802_15_4_2003_2p4_GHz_OQPSK_CSMA;
RAIL_TxData_t txData;
RAIL_TxOptions_t txOption;
uint8_t frame[IEEE802154_MAX_LENGTH + 1];
(void)aInstance;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
otEXPECT_ACTION((sState != OT_RADIO_STATE_DISABLED) && (sState != OT_RADIO_STATE_TRANSMIT),
error = OT_ERROR_INVALID_STATE);
sState = OT_RADIO_STATE_TRANSMIT;
sTransmitError = OT_ERROR_NONE;
sTransmitBusy = true;
frame[0] = aFrame->mLength;
memcpy(frame + 1, aFrame->mPsdu, aFrame->mLength);
txData.dataPtr = frame;
txData.dataLength = aFrame->mLength - 1;
txOption.waitForAck = (aFrame->mPsdu[0] & IEEE802154_ACK_REQUEST) ? true : false;
txOption.removeCrc = false;
txOption.syncWordId = 0;
RAIL_TxPowerSet(aFrame->mPower);
setChannel(aFrame->mChannel);
RAIL_RfIdleExt(RAIL_IDLE, true);
otEXPECT_ACTION(RAIL_TxDataLoad(&txData) == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED);
otEXPECT_ACTION(RAIL_TxStartWithOptions(aFrame->mChannel, &txOption, RAIL_CcaCsma, &csmaConfig) == RAIL_STATUS_NO_ERROR,
error = OT_ERROR_FAILED);
exit:
CORE_EXIT_CRITICAL();
return error;
}
otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
{
(void)aInstance;
return &sTransmitFrame;
}
int8_t otPlatRadioGetRssi(otInstance *aInstance)
{
(void)aInstance;
return (uint8_t)(RAIL_RxGetRSSI() >> 2);
}
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
{
(void)aInstance;
return OT_RADIO_CAPS_ACK_TIMEOUT;
}
bool otPlatRadioGetPromiscuous(otInstance *aInstance)
{
(void)aInstance;
return sPromiscuous;
}
void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
{
(void)aInstance;
sPromiscuous = aEnable;
RAIL_IEEE802154_SetPromiscuousMode(aEnable);
}
int8_t findSrcMatchAvailEntry(bool aShortAddress)
{
int8_t entry = -1;
if (aShortAddress)
{
for (uint8_t i = 0; i < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM; i++)
{
if (!srcMatchShortEntry[i].allocated)
{
entry = i;
break;
}
}
}
else
{
for (uint8_t i = 0; i < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM; i++)
{
if (!srcMatchExtEntry[i].allocated)
{
entry = i;
break;
}
}
}
return entry;
}
int8_t findSrcMatchShortEntry(const uint16_t aShortAddress)
{
int8_t entry = -1;
uint16_t checksum = aShortAddress + sPanId;
for (uint8_t i = 0; i < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM; i++)
{
if (checksum == srcMatchShortEntry[i].checksum &&
srcMatchShortEntry[i].allocated)
{
entry = i;
break;
}
}
return entry;
}
int8_t findSrcMatchExtEntry(const uint8_t *aExtAddress)
{
int8_t entry = -1;
uint16_t checksum = sPanId;
checksum += (uint16_t)aExtAddress[0] | (uint16_t)(aExtAddress[1] << 8);
checksum += (uint16_t)aExtAddress[2] | (uint16_t)(aExtAddress[3] << 8);
checksum += (uint16_t)aExtAddress[4] | (uint16_t)(aExtAddress[5] << 8);
checksum += (uint16_t)aExtAddress[6] | (uint16_t)(aExtAddress[7] << 8);
for (uint8_t i = 0; i < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM; i++)
{
if (checksum == srcMatchExtEntry[i].checksum &&
srcMatchExtEntry[i].allocated)
{
entry = i;
break;
}
}
return entry;
}
void addToSrcMatchShortIndirect(uint8_t entry, const uint16_t aShortAddress)
{
uint16_t checksum = aShortAddress + sPanId;
srcMatchShortEntry[entry].checksum = checksum;
srcMatchShortEntry[entry].allocated = true;
}
void addToSrcMatchExtIndirect(uint8_t entry, const uint8_t *aExtAddress)
{
uint16_t checksum = sPanId;
checksum += (uint16_t)aExtAddress[0] | (uint16_t)(aExtAddress[1] << 8);
checksum += (uint16_t)aExtAddress[2] | (uint16_t)(aExtAddress[3] << 8);
checksum += (uint16_t)aExtAddress[4] | (uint16_t)(aExtAddress[5] << 8);
checksum += (uint16_t)aExtAddress[6] | (uint16_t)(aExtAddress[7] << 8);
srcMatchExtEntry[entry].checksum = checksum;
srcMatchExtEntry[entry].allocated = true;
}
void removeFromSrcMatchShortIndirect(uint8_t entry)
{
srcMatchShortEntry[entry].allocated = false;
memset(&srcMatchShortEntry[entry].checksum, 0, sizeof(uint16_t));
}
void removeFromSrcMatchExtIndirect(uint8_t entry)
{
srcMatchExtEntry[entry].allocated = false;
memset(&srcMatchExtEntry[entry].checksum, 0, sizeof(uint16_t));
}
void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable)
{
(void)aInstance;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
// set Frame Pending bit for all outgoing ACKs if aEnable is false
sIsSrcMatchEnabled = aEnable;
CORE_EXIT_CRITICAL();
}
otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
(void)aInstance;
otError error = OT_ERROR_NONE;
int8_t entry = -1;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
entry = findSrcMatchAvailEntry(true);
otLogDebgPlat(sInstance, "Add ShortAddr entry: %d", entry);
otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM,
error = OT_ERROR_NO_BUFS);
addToSrcMatchShortIndirect(entry, aShortAddress);
exit:
CORE_EXIT_CRITICAL();
return error;
}
otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress)
{
otError error = OT_ERROR_NONE;
int8_t entry = -1;
(void)aInstance;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
entry = findSrcMatchAvailEntry(false);
otLogDebgPlat(sInstance, "Add ExtAddr entry: %d", entry);
otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM,
error = OT_ERROR_NO_BUFS);
addToSrcMatchExtIndirect(entry, aExtAddress);
exit:
CORE_EXIT_CRITICAL();
return error;
}
otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
otError error = OT_ERROR_NONE;
int8_t entry = -1;
(void)aInstance;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
entry = findSrcMatchShortEntry(aShortAddress);
otLogDebgPlat(sInstance, "Clear ShortAddr entry: %d", entry);
otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_SHORT_ENTRY_NUM,
error = OT_ERROR_NO_ADDRESS);
removeFromSrcMatchShortIndirect(entry);
exit:
CORE_EXIT_CRITICAL();
return error;
}
otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const uint8_t *aExtAddress)
{
otError error = OT_ERROR_NONE;
int8_t entry = -1;
(void)aInstance;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
entry = findSrcMatchExtEntry(aExtAddress);
otLogDebgPlat(sInstance, "Clear ExtAddr entry: %d", entry);
otEXPECT_ACTION(entry >= 0 && entry < RADIO_CONFIG_SRC_MATCH_EXT_ENTRY_NUM,
error = OT_ERROR_NO_ADDRESS);
removeFromSrcMatchExtIndirect(entry);
exit:
CORE_EXIT_CRITICAL();
return error;
}
void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance)
{
(void)aInstance;
otLogDebgPlat(sInstance, "Clear ShortAddr entries", NULL);
memset(srcMatchShortEntry, 0, sizeof(srcMatchShortEntry));
}
void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance)
{
(void)aInstance;
otLogDebgPlat(sInstance, "Clear ExtAddr entries", NULL);
memset(srcMatchExtEntry, 0, sizeof(srcMatchExtEntry));
}
void RAILCb_IEEE802154_DataRequestCommand(RAIL_IEEE802154_Address_t *aAddress)
{
if (sIsSrcMatchEnabled)
{
if ((aAddress->length == RAIL_IEEE802154_LongAddress &&
findSrcMatchExtEntry(aAddress->longAddress) >= 0) ||
(aAddress->length == RAIL_IEEE802154_ShortAddress &&
findSrcMatchShortEntry(aAddress->shortAddress) >= 0))
{
RAIL_IEEE802154_SetFramePending();
}
}
else
{
(void)aAddress;
RAIL_IEEE802154_SetFramePending();
}
}
otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
{
(void)aInstance;
(void)aScanChannel;
(void)aScanDuration;
return OT_ERROR_NOT_IMPLEMENTED;
}
void RAILCb_TxRadioStatus(uint8_t aStatus)
{
switch (aStatus)
{
case RAIL_TX_CONFIG_CHANNEL_BUSY:
sTransmitError = OT_ERROR_CHANNEL_ACCESS_FAILURE;
sTransmitBusy = false;
break;
case RAIL_TX_CONFIG_TX_ABORTED:
sTransmitError = OT_ERROR_ABORT;
sTransmitBusy = false;
break;
case RAIL_TX_CONFIG_BUFFER_UNDERFLOW:
sTransmitError = OT_ERROR_ABORT;
sTransmitBusy = false;
break;
default:
break;
}
}
void RAILCb_TxPacketSent(RAIL_TxPacketInfo_t *aTxPacketInfo)
{
(void)aTxPacketInfo;
sTransmitError = OT_ERROR_NONE;
sTransmitBusy = false;
}
void RAILCb_RxPacketReceived(void *aRxPacketHandle)
{
RAIL_RxPacketInfo_t *rxPacketInfo;
uint8_t length;
rxPacketInfo = (RAIL_RxPacketInfo_t *)aRxPacketHandle;
// check recv packet appended info
otEXPECT(rxPacketInfo != NULL &&
rxPacketInfo->appendedInfo.crcStatus &&
rxPacketInfo->appendedInfo.frameCodingStatus);
length = rxPacketInfo->dataLength + 1;
// check the length in recv packet info structure
otEXPECT(length == rxPacketInfo->dataPtr[0]);
// check the lenght validity of recv packet
otEXPECT(length >= IEEE802154_MIN_LENGTH && length <= IEEE802154_MAX_LENGTH);
otLogInfoPlat(sInstance, "Received data:%d", rxPacketInfo->dataLength);
memcpy(sReceiveFrame.mPsdu, rxPacketInfo->dataPtr + 1, rxPacketInfo->dataLength);
sReceiveFrame.mPower = rxPacketInfo->appendedInfo.rssiLatch;
sReceiveFrame.mLqi = rxPacketInfo->appendedInfo.lqi;
sReceiveFrame.mLength = length;
sReceiveError = OT_ERROR_NONE;
exit:
return;
}
void efr32RadioProcess(otInstance *aInstance)
{
// ensure process would not be broken by
// the incoming interrupt with higher priority
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
if ((sState == OT_RADIO_STATE_RECEIVE && sReceiveFrame.mLength > 0) ||
(sState == OT_RADIO_STATE_TRANSMIT && sReceiveFrame.mLength > IEEE802154_ACK_LENGTH))
{
#if OPENTHREAD_ENABLE_DIAG
if (otPlatDiagModeGet())
{
otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError);
}
else
#endif
{
// signal MAC layer for each received frame if promiscous is enabled
// otherwise only signal MAC layer for non-ACK frame
if (sPromiscuous || sReceiveFrame.mLength > IEEE802154_ACK_LENGTH)
{
otLogInfoPlat(sInstance, "Received %d bytes", sReceiveFrame.mLength);
otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError);
}
}
}
if (sState == OT_RADIO_STATE_TRANSMIT && sTransmitBusy == false)
{
if (sTransmitError != OT_ERROR_NONE || (sTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0)
{
if (sTransmitError != OT_ERROR_NONE)
{
otLogDebgPlat(sInstance, "Transmit failed ErrorCode=%d", sTransmitError);
}
sState = OT_RADIO_STATE_RECEIVE;
#if OPENTHREAD_ENABLE_DIAG
if (otPlatDiagModeGet())
{
otPlatDiagRadioTransmitDone(aInstance, &sTransmitFrame, sTransmitError);
}
else
#endif
{
otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, sTransmitError);
}
}
else if (sReceiveFrame.mLength == IEEE802154_ACK_LENGTH &&
(sReceiveFrame.mPsdu[0] & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_ACK &&
(sReceiveFrame.mPsdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET]))
{
sState = OT_RADIO_STATE_RECEIVE;
otLogInfoPlat(sInstance, "Received ACK:%d", sReceiveFrame.mLength);
otPlatRadioTxDone(aInstance, &sTransmitFrame, &sReceiveFrame, sTransmitError);
}
}
sReceiveFrame.mLength = 0;
CORE_EXIT_CRITICAL();
}
void RAILCb_RxAckTimeout(void)
{
sTransmitError = OT_ERROR_NO_ACK;
}
void RAILCb_RfReady(void)
{
}
void RAILCb_CalNeeded(void)
{
}
void RAILCb_RxRadioStatus(uint8_t aStatus)
{
(void)aStatus;
}
void RAILCb_RadioStateChanged(uint8_t aState)
{
(void)aState;
}
void RAILCb_RssiAverageDone(int16_t avgRssi)
{
(void)avgRssi;
}
void RAILCb_RxFifoAlmostFull(uint16_t aBytesAvailable)
{
(void)aBytesAvailable;
}
void RAILCb_TxFifoAlmostEmpty(uint16_t aSpaceAvailable)
{
(void)aSpaceAvailable;
}
void *RAILCb_AllocateMemory(uint32_t aSize)
{
uint8_t *pointer = NULL;
CORE_DECLARE_IRQ_STATE;
CORE_ENTER_CRITICAL();
otEXPECT(aSize <= (IEEE802154_MAX_LENGTH + 1 + sizeof(RAIL_RxPacketInfo_t)));
pointer = sReceiveBuffer;
exit:
CORE_EXIT_CRITICAL();
return pointer;
}
void *RAILCb_BeginWriteMemory(void *aHandle, uint32_t aOffset,
uint32_t *available)
{
(void)available;
return ((uint8_t *)aHandle) + aOffset;
}
void RAILCb_EndWriteMemory(void *aHandle, uint32_t aOffset, uint32_t aSize)
{
(void)aHandle;
(void)aOffset;
(void)aSize;
}
void RAILCb_FreeMemory(void *aHandle)
{
(void)aHandle;
}
void otPlatRadioSetDefaultTxPower(otInstance *aInstance, int8_t aPower)
{
(void)aInstance;
RAIL_TxPowerSet(aPower);
}
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
{
(void)aInstance;
return EFR32_RECEIVE_SENSITIVITY;
}