blob: ddf8de29ab8f8e33374c7036167570f840c918ad [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/config.h>
#include <openthread/platform/alarm-milli.h>
#include <openthread/platform/diag.h>
#include <openthread/platform/radio.h>
#include "common/logging.hpp"
#include "utils/code_utils.h"
#include "em_core.h"
#include "em_system.h"
#include "openthread-core-efr32-config.h"
#include "pa_conversions_efr32.h"
#include "rail.h"
#include "rail_config.h"
#include "rail_ieee802154.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 bool sTransmitBusy = false;
static bool sPromiscuous = false;
static bool sIsSrcMatchEnabled = false;
static otRadioState sState = OT_RADIO_STATE_DISABLED;
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];
static uint8_t sRailTxFifo[1 + IEEE802154_MAX_LENGTH];
static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents);
static RAIL_Config_t sRailConfig = {
.eventsCallback = &RAILCb_Generic,
.protocol = NULL,
.scheduler = NULL,
};
static const RAIL_IEEE802154_Config_t sRailIeee802154Config = {
NULL, // addresses
{
// ackConfig
true, // ackConfig.enable
894, // ackConfig.ackTimeout
{
// ackConfig.rxTransitions
RAIL_RF_STATE_RX, // ackConfig.rxTransitions.success
RAIL_RF_STATE_RX, // ackConfig.rxTransitions.error
},
{
// ackConfig.txTransitions
RAIL_RF_STATE_RX, // ackConfig.txTransitions.success
RAIL_RF_STATE_RX, // ackConfig.txTransitions.error
},
},
{
// timings
100, // timings.idleToRx
192 - 10, // timings.txToRx
100, // timings.idleToTx
192, // timings.rxToTx
0, // timings.rxSearchTimeout
0, // timings.txToRxSearchTimeout
},
RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES, // framesMask
false, // promiscuousMode
false, // isPanCoordinator
};
static RAIL_Handle_t sRailHandle = NULL;
RAIL_DECLARE_TX_POWER_VBAT_CURVES(piecewiseSegments, curvesSg, curves24Hp, curves24Lp);
void efr32RadioInit(void)
{
RAIL_Status_t status;
sRailHandle = RAIL_Init(&sRailConfig, NULL);
assert(sRailHandle != NULL);
RAIL_DataConfig_t railDataConfig = {
TX_PACKET_DATA,
RX_PACKET_DATA,
PACKET_MODE,
PACKET_MODE,
};
status = RAIL_ConfigData(sRailHandle, &railDataConfig);
assert(status == RAIL_STATUS_NO_ERROR);
status = RAIL_ConfigCal(sRailHandle, RAIL_CAL_ALL);
assert(status == RAIL_STATUS_NO_ERROR);
status = RAIL_IEEE802154_Config2p4GHzRadio(sRailHandle);
assert(status == RAIL_STATUS_NO_ERROR);
status = RAIL_IEEE802154_Init(sRailHandle, &sRailIeee802154Config);
assert(status == RAIL_STATUS_NO_ERROR);
status = RAIL_ConfigEvents(sRailHandle, RAIL_EVENTS_ALL,
RAIL_EVENT_RX_ACK_TIMEOUT | //
RAIL_EVENT_TX_PACKET_SENT | //
RAIL_EVENT_RX_PACKET_RECEIVED | //
RAIL_EVENT_TX_CHANNEL_BUSY | //
RAIL_EVENT_TX_ABORTED | //
RAIL_EVENT_TX_BLOCKED | //
RAIL_EVENT_TX_UNDERFLOW | //
RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND | //
RAIL_EVENT_CAL_NEEDED //
);
assert(status == RAIL_STATUS_NO_ERROR);
RAIL_TxPowerCurvesConfig_t txPowerCurvesConfig = {curves24Hp, curvesSg, curves24Lp, piecewiseSegments};
status = RAIL_InitTxPowerCurves(&txPowerCurvesConfig);
assert(status == RAIL_STATUS_NO_ERROR);
RAIL_TxPowerConfig_t txPowerConfig = {RAIL_TX_POWER_MODE_2P4_HP, 3300, 10};
status = RAIL_ConfigTxPower(sRailHandle, &txPowerConfig);
assert(status == RAIL_STATUS_NO_ERROR);
status = RAIL_SetTxPowerDbm(sRailHandle, ((RAIL_TxPower_t)OPENTHREAD_CONFIG_DEFAULT_TRANSMIT_POWER) * 10);
assert(status == RAIL_STATUS_NO_ERROR);
RAIL_SetTxFifo(sRailHandle, sRailTxFifo, 0, sizeof(sRailTxFifo));
sReceiveFrame.mLength = 0;
sReceiveFrame.mPsdu = sReceivePsdu;
sTransmitFrame.mLength = 0;
sTransmitFrame.mPsdu = sTransmitPsdu;
otLogInfoPlat(sInstance, "Initialized", NULL);
}
void efr32RadioDeinit(void)
{
RAIL_Status_t status;
RAIL_Idle(sRailHandle, RAIL_IDLE_FORCE_SHUTDOWN_CLEAR_FLAGS, true);
status = RAIL_IEEE802154_Deinit(sRailHandle);
assert(status == RAIL_STATUS_NO_ERROR);
}
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)
{
RAIL_Status_t status;
(void)aInstance;
otLogInfoPlat(sInstance, "PANID=%X", aPanId);
sPanId = aPanId;
status = RAIL_IEEE802154_SetPanId(sRailHandle, aPanId, 0);
assert(status == RAIL_STATUS_NO_ERROR);
}
void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress)
{
RAIL_Status_t status;
(void)aInstance;
otLogInfoPlat(sInstance, "ExtAddr=%X%X%X%X%X%X%X%X", aAddress->m8[7], aAddress->m8[6], aAddress->m8[5],
aAddress->m8[4], aAddress->m8[3], aAddress->m8[2], aAddress->m8[1], aAddress->m8[0]);
status = RAIL_IEEE802154_SetLongAddress(sRailHandle, (uint8_t *)aAddress->m8, 0);
assert(status == RAIL_STATUS_NO_ERROR);
}
void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress)
{
RAIL_Status_t status;
(void)aInstance;
otLogInfoPlat(sInstance, "ShortAddr=%X", aAddress);
status = RAIL_IEEE802154_SetShortAddress(sRailHandle, aAddress, 0);
assert(status == RAIL_STATUS_NO_ERROR);
}
bool otPlatRadioIsEnabled(otInstance *aInstance)
{
(void)aInstance;
return (sState != OT_RADIO_STATE_DISABLED);
}
otError otPlatRadioEnable(otInstance *aInstance)
{
otEXPECT(!otPlatRadioIsEnabled(aInstance));
otLogInfoPlat(sInstance, "State=OT_RADIO_STATE_SLEEP", NULL);
sState = OT_RADIO_STATE_SLEEP;
exit:
return OT_ERROR_NONE;
}
otError otPlatRadioDisable(otInstance *aInstance)
{
otEXPECT(otPlatRadioIsEnabled(aInstance));
otLogInfoPlat(sInstance, "State=OT_RADIO_STATE_DISABLED", NULL);
sState = OT_RADIO_STATE_DISABLED;
exit:
return OT_ERROR_NONE;
}
otError otPlatRadioSleep(otInstance *aInstance)
{
otError error = OT_ERROR_NONE;
(void)aInstance;
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;
RAIL_Idle(sRailHandle, RAIL_IDLE, true);
exit:
return error;
}
otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
{
otError error = OT_ERROR_NONE;
RAIL_Status_t status;
(void)aInstance;
otEXPECT_ACTION(sState != OT_RADIO_STATE_DISABLED, error = OT_ERROR_INVALID_STATE);
status = RAIL_StartRx(sRailHandle, aChannel, NULL);
otEXPECT_ACTION(status == RAIL_STATUS_NO_ERROR, error = OT_ERROR_FAILED);
otLogInfoPlat(sInstance, "State=OT_RADIO_STATE_RECEIVE", NULL);
sState = OT_RADIO_STATE_RECEIVE;
sReceiveFrame.mChannel = aChannel;
exit:
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_TxOptions_t txOptions = RAIL_TX_OPTIONS_NONE;
RAIL_Status_t status;
(void)aInstance;
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;
RAIL_WriteTxFifo(sRailHandle, &aFrame->mLength, sizeof(aFrame->mLength), true);
RAIL_WriteTxFifo(sRailHandle, aFrame->mPsdu, aFrame->mLength - 2, false);
if (aFrame->mPsdu[0] & IEEE802154_ACK_REQUEST)
{
txOptions |= RAIL_TX_OPTION_WAIT_FOR_ACK;
}
if (aFrame->mInfo.mTxInfo.mCsmaCaEnabled)
{
status = RAIL_StartCcaCsmaTx(sRailHandle, aFrame->mChannel, txOptions, &csmaConfig, NULL);
}
else
{
status = RAIL_StartTx(sRailHandle, aFrame->mChannel, txOptions, NULL);
}
assert(status == RAIL_STATUS_NO_ERROR);
otPlatRadioTxStarted(aInstance, aFrame);
exit:
return error;
}
otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
{
(void)aInstance;
return &sTransmitFrame;
}
int8_t otPlatRadioGetRssi(otInstance *aInstance)
{
(void)aInstance;
return (int8_t)(RAIL_GetAverageRssi(sRailHandle) >> 2);
}
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
{
(void)aInstance;
return OT_RADIO_CAPS_ACK_TIMEOUT | OT_RADIO_CAPS_CSMA_BACKOFF;
}
bool otPlatRadioGetPromiscuous(otInstance *aInstance)
{
(void)aInstance;
return sPromiscuous;
}
void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable)
{
RAIL_Status_t status;
(void)aInstance;
sPromiscuous = aEnable;
status = RAIL_IEEE802154_SetPromiscuousMode(sRailHandle, aEnable);
assert(status == RAIL_STATUS_NO_ERROR);
}
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 otExtAddress *aExtAddress)
{
int8_t entry = -1;
uint16_t checksum = sPanId;
checksum += (uint16_t)aExtAddress->m8[0] | (uint16_t)(aExtAddress->m8[1] << 8);
checksum += (uint16_t)aExtAddress->m8[2] | (uint16_t)(aExtAddress->m8[3] << 8);
checksum += (uint16_t)aExtAddress->m8[4] | (uint16_t)(aExtAddress->m8[5] << 8);
checksum += (uint16_t)aExtAddress->m8[6] | (uint16_t)(aExtAddress->m8[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 otExtAddress *aExtAddress)
{
uint16_t checksum = sPanId;
checksum += (uint16_t)aExtAddress->m8[0] | (uint16_t)(aExtAddress->m8[1] << 8);
checksum += (uint16_t)aExtAddress->m8[2] | (uint16_t)(aExtAddress->m8[3] << 8);
checksum += (uint16_t)aExtAddress->m8[4] | (uint16_t)(aExtAddress->m8[5] << 8);
checksum += (uint16_t)aExtAddress->m8[6] | (uint16_t)(aExtAddress->m8[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;
// set Frame Pending bit for all outgoing ACKs if aEnable is false
sIsSrcMatchEnabled = aEnable;
}
otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
(void)aInstance;
otError error = OT_ERROR_NONE;
int8_t entry = -1;
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:
return error;
}
otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
{
otError error = OT_ERROR_NONE;
int8_t entry = -1;
(void)aInstance;
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:
return error;
}
otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress)
{
otError error = OT_ERROR_NONE;
int8_t entry = -1;
(void)aInstance;
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:
return error;
}
otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress)
{
otError error = OT_ERROR_NONE;
int8_t entry = -1;
(void)aInstance;
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:
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));
}
static void processNextRxPacket(otInstance *aInstance, RAIL_Handle_t aRailHandle)
{
RAIL_RxPacketHandle_t packetHandle = RAIL_RX_PACKET_HANDLE_INVALID;
RAIL_RxPacketInfo_t packetInfo;
RAIL_RxPacketDetails_t packetDetails;
RAIL_Status_t status;
uint16_t length;
packetHandle = RAIL_GetRxPacketInfo(aRailHandle, RAIL_RX_PACKET_HANDLE_OLDEST, &packetInfo);
otEXPECT_ACTION(packetInfo.packetStatus == RAIL_RX_PACKET_READY_SUCCESS,
packetHandle = RAIL_RX_PACKET_HANDLE_INVALID);
packetDetails.timeReceived.timePosition = RAIL_PACKET_TIME_INVALID;
packetDetails.timeReceived.totalPacketBytes = 0;
status = RAIL_GetRxPacketDetails(aRailHandle, packetHandle, &packetDetails);
otEXPECT(status != RAIL_STATUS_INVALID_STATE);
assert(status == RAIL_STATUS_NO_ERROR);
length = packetInfo.packetBytes + 1;
// check the length in recv packet info structure
assert(length == packetInfo.firstPortionData[0]);
// check the length validity of recv packet
otEXPECT(length >= IEEE802154_MIN_LENGTH && length <= IEEE802154_MAX_LENGTH);
otLogInfoPlat(aInstance, "Received data:%d", length);
// skip length byte
assert(packetInfo.firstPortionBytes > 0);
packetInfo.firstPortionData++;
packetInfo.firstPortionBytes--;
packetInfo.packetBytes--;
// read packet
memcpy(sReceiveFrame.mPsdu, packetInfo.firstPortionData, packetInfo.firstPortionBytes);
memcpy(sReceiveFrame.mPsdu + packetInfo.firstPortionBytes, packetInfo.lastPortionData,
packetInfo.packetBytes - packetInfo.firstPortionBytes);
sReceiveFrame.mLength = length;
sReceiveFrame.mInfo.mRxInfo.mRssi = packetDetails.rssi;
sReceiveFrame.mInfo.mRxInfo.mLqi = packetDetails.lqi;
// TODO: grab timestamp and handle conversion to msec/usec
// sReceiveFrame.mInfo.mRxInfo.mMsec = packetDetails.packetTime;
// sReceiveFrame.mInfo.mRxInfo.mUsec = packetDetails.packetTime;
if (packetDetails.isAck)
{
assert((length == IEEE802154_ACK_LENGTH) &&
(sReceiveFrame.mPsdu[0] & IEEE802154_FRAME_TYPE_MASK) == IEEE802154_FRAME_TYPE_ACK);
sTransmitBusy = false;
if (sReceiveFrame.mPsdu[IEEE802154_DSN_OFFSET] == sTransmitFrame.mPsdu[IEEE802154_DSN_OFFSET])
{
sTransmitError = OT_ERROR_NONE;
}
else
{
sTransmitError = OT_ERROR_NO_ACK;
}
}
else
{
assert(length != IEEE802154_ACK_LENGTH);
sReceiveError = OT_ERROR_NONE;
#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(aInstance, "Received %d bytes", sReceiveFrame.mLength);
otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError);
}
}
}
exit:
if (packetHandle != RAIL_RX_PACKET_HANDLE_INVALID)
{
RAIL_ReleaseRxPacket(aRailHandle, packetHandle);
}
}
static void ieee802154DataRequestCommand(RAIL_Handle_t aRailHandle)
{
RAIL_Status_t status;
if (sIsSrcMatchEnabled)
{
RAIL_IEEE802154_Address_t sourceAddress;
status = RAIL_IEEE802154_GetAddress(aRailHandle, &sourceAddress);
assert(status == RAIL_STATUS_NO_ERROR);
if ((sourceAddress.length == RAIL_IEEE802154_LongAddress &&
findSrcMatchExtEntry((otExtAddress *)sourceAddress.longAddress) >= 0) ||
(sourceAddress.length == RAIL_IEEE802154_ShortAddress &&
findSrcMatchShortEntry(sourceAddress.shortAddress) >= 0))
{
status = RAIL_IEEE802154_SetFramePending(aRailHandle);
assert(status == RAIL_STATUS_NO_ERROR);
}
}
else
{
status = RAIL_IEEE802154_SetFramePending(aRailHandle);
assert(status == RAIL_STATUS_NO_ERROR);
}
}
static void RAILCb_Generic(RAIL_Handle_t aRailHandle, RAIL_Events_t aEvents)
{
if (aEvents & (RAIL_EVENT_TX_ABORTED | RAIL_EVENT_TX_BLOCKED | RAIL_EVENT_TX_UNDERFLOW))
{
sTransmitError = OT_ERROR_ABORT;
sTransmitBusy = false;
}
if (aEvents & RAIL_EVENT_RX_ACK_TIMEOUT)
{
sTransmitError = OT_ERROR_NO_ACK;
sTransmitBusy = false;
}
if (aEvents & RAIL_EVENT_RX_PACKET_RECEIVED)
{
RAIL_HoldRxPacket(aRailHandle);
}
if (aEvents & RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND)
{
ieee802154DataRequestCommand(aRailHandle);
}
if (aEvents & RAIL_EVENT_TX_PACKET_SENT)
{
if ((sTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0)
{
sTransmitError = OT_ERROR_NONE;
sTransmitBusy = false;
}
}
if (aEvents & RAIL_EVENT_TX_CHANNEL_BUSY)
{
sTransmitError = OT_ERROR_CHANNEL_ACCESS_FAILURE;
sTransmitBusy = false;
}
if (aEvents & RAIL_EVENT_CAL_NEEDED)
{
RAIL_Status_t status;
status = RAIL_Calibrate(aRailHandle, NULL, RAIL_CAL_ALL_PENDING);
assert(status == RAIL_STATUS_NO_ERROR);
}
}
otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration)
{
(void)aInstance;
(void)aScanChannel;
(void)aScanDuration;
return OT_ERROR_NOT_IMPLEMENTED;
}
void efr32RadioProcess(otInstance *aInstance)
{
if (sState == OT_RADIO_STATE_TRANSMIT && sTransmitBusy == false)
{
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
if (((sTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0) || (sTransmitError != OT_ERROR_NONE))
{
otPlatRadioTxDone(aInstance, &sTransmitFrame, NULL, sTransmitError);
}
else
{
otPlatRadioTxDone(aInstance, &sTransmitFrame, &sReceiveFrame, sTransmitError);
}
}
processNextRxPacket(aInstance, sRailHandle);
}
otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
{
otError error = OT_ERROR_NONE;
(void)aInstance;
otEXPECT_ACTION(aPower != NULL, error = OT_ERROR_INVALID_ARGS);
*aPower = (int8_t)(RAIL_GetTxPowerDbm(sRailHandle) / 10);
exit:
return error;
}
otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
{
RAIL_Status_t status;
(void)aInstance;
status = RAIL_SetTxPowerDbm(sRailHandle, ((RAIL_TxPower_t)aPower) * 10);
assert(status == RAIL_STATUS_NO_ERROR);
return OT_ERROR_NONE;
}
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
{
(void)aInstance;
return EFR32_RECEIVE_SENSITIVITY;
}