Created
November 9, 2017 00:38
-
-
Save sjlongland/0606f07c69851ec55367c09d2b730a1d to your computer and use it in GitHub Desktop.
OpenThread radio.c with CC2592 calibration
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016, 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 <openthread/config.h> | |
#include <openthread/openthread.h> | |
#include <openthread/platform/alarm-milli.h> | |
#include <openthread/platform/diag.h> | |
#include <openthread/platform/platform.h> | |
#include <openthread/platform/radio.h> | |
#include "platform-cc2538.h" | |
#include "common/logging.hpp" | |
#include "utils/code_utils.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 | |
{ | |
CC2538_RSSI_OFFSET = 73, | |
CC2538_CRC_BIT_MASK = 0x80, | |
CC2538_LQI_BIT_MASK = 0x7f, | |
}; | |
enum | |
{ | |
CC2538_RECEIVE_SENSITIVITY = -100, // dBm | |
}; | |
typedef struct TxPowerTable | |
{ | |
int8_t mTxPowerVal; | |
uint8_t mTxPowerReg; | |
} TxPowerTable; | |
// The transmit power table, the values are from application note 130 | |
static const TxPowerTable sTxPowerTable[] = | |
{ | |
{ 22, 0xFF }, /* 22.0dBm =~ 158.5mW */ | |
{ 21, 0xD5 }, /* 20.9dBm =~ 123.0mW */ | |
{ 20, 0xC5 }, /* 20.1dBm =~ 102.3mW */ | |
{ 19, 0xB0 }, /* 19.0dBm =~ 79.4mW */ | |
{ 18, 0xA1 }, /* 17.8dBm =~ 60.3mW */ | |
{ 16, 0x91 }, /* 16.4dBm =~ 43.7mW */ | |
{ 15, 0x88 }, /* 14.9dBm =~ 30.9mW */ | |
{ 13, 0x72 }, /* 13.0dBm =~ 20.0mW */ | |
{ 11, 0x62 }, /* 11.0dBm =~ 12.6mW */ | |
{ 10, 0x58 }, /* 9.5dBm =~ 8.9mW */ | |
{ 8, 0x42 }, /* 7.5dBm =~ 5.6mW */ | |
}; | |
static otRadioFrame sTransmitFrame; | |
static otRadioFrame sReceiveFrame; | |
static otError sTransmitError; | |
static otError sReceiveError; | |
static uint8_t sTransmitPsdu[IEEE802154_MAX_LENGTH]; | |
static uint8_t sReceivePsdu[IEEE802154_MAX_LENGTH]; | |
static uint8_t sChannel = 0; | |
static int8_t sTxPower = 0; | |
static otRadioState sState = OT_RADIO_STATE_DISABLED; | |
static bool sIsReceiverEnabled = false; | |
void enableReceiver(void) | |
{ | |
if (!sIsReceiverEnabled) | |
{ | |
otLogInfoPlat(sInstance, "Enabling receiver", NULL); | |
// flush rxfifo | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; | |
// enable receiver | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_RXON; | |
sIsReceiverEnabled = true; | |
} | |
} | |
void disableReceiver(void) | |
{ | |
if (sIsReceiverEnabled) | |
{ | |
otLogInfoPlat(sInstance, "Disabling receiver", NULL); | |
while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); | |
// flush rxfifo | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; | |
if (HWREG(RFCORE_XREG_RXENABLE) != 0) | |
{ | |
// disable receiver | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_RFOFF; | |
} | |
sIsReceiverEnabled = false; | |
} | |
} | |
void setChannel(uint8_t aChannel) | |
{ | |
if (sChannel != aChannel) | |
{ | |
bool enabled = false; | |
if (sIsReceiverEnabled) | |
{ | |
disableReceiver(); | |
enabled = true; | |
} | |
otLogInfoPlat(sInstance, "Channel=%d", aChannel); | |
HWREG(RFCORE_XREG_FREQCTRL) = 11 + (aChannel - 11) * 5; | |
sChannel = aChannel; | |
if (enabled) | |
{ | |
enableReceiver(); | |
} | |
} | |
} | |
void setTxPower(int8_t aTxPower) | |
{ | |
uint8_t i = 0; | |
if (sTxPower != aTxPower) | |
{ | |
otLogInfoPlat(sInstance, "TxPower=%d", aTxPower); | |
for (i = sizeof(sTxPowerTable) / sizeof(TxPowerTable) - 1; i > 0; i--) | |
{ | |
if (aTxPower < sTxPowerTable[i].mTxPowerVal) | |
{ | |
break; | |
} | |
} | |
HWREG(RFCORE_XREG_TXPOWER) = sTxPowerTable[i].mTxPowerReg; | |
sTxPower = aTxPower; | |
} | |
} | |
void otPlatRadioGetIeeeEui64(otInstance *aInstance, uint8_t *aIeeeEui64) | |
{ | |
uint8_t *eui64 = (uint8_t *)IEEE_EUI64; | |
(void)aInstance; | |
for (uint8_t i = 0; i < OT_EXT_ADDRESS_SIZE; i++) | |
{ | |
aIeeeEui64[i] = eui64[7 - i]; | |
} | |
} | |
void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanid) | |
{ | |
(void)aInstance; | |
otLogInfoPlat(sInstance, "PANID=%X", aPanid); | |
HWREG(RFCORE_FFSM_PAN_ID0) = aPanid & 0xFF; | |
HWREG(RFCORE_FFSM_PAN_ID1) = aPanid >> 8; | |
} | |
void otPlatRadioSetExtendedAddress(otInstance *aInstance, const otExtAddress *aAddress) | |
{ | |
(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]); | |
for (int i = 0; i < 8; i++) | |
{ | |
((volatile uint32_t *)RFCORE_FFSM_EXT_ADDR0)[i] = aAddress->m8[i]; | |
} | |
} | |
void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aAddress) | |
{ | |
(void)aInstance; | |
otLogInfoPlat(sInstance, "ShortAddr=%X", aAddress); | |
HWREG(RFCORE_FFSM_SHORT_ADDR0) = aAddress & 0xFF; | |
HWREG(RFCORE_FFSM_SHORT_ADDR1) = aAddress >> 8; | |
} | |
void cc2538RadioInit(void) | |
{ | |
sTransmitFrame.mLength = 0; | |
sTransmitFrame.mPsdu = sTransmitPsdu; | |
sReceiveFrame.mLength = 0; | |
sReceiveFrame.mPsdu = sReceivePsdu; | |
// enable clock | |
HWREG(SYS_CTRL_RCGCRFC) = SYS_CTRL_RCGCRFC_RFC0; | |
HWREG(SYS_CTRL_SCGCRFC) = SYS_CTRL_SCGCRFC_RFC0; | |
HWREG(SYS_CTRL_DCGCRFC) = SYS_CTRL_DCGCRFC_RFC0; | |
// Table 23-7. | |
HWREG(RFCORE_XREG_AGCCTRL1) = 0x15; | |
HWREG(RFCORE_XREG_TXFILTCFG) = 0x09; | |
HWREG(ANA_REGS_BASE + ANA_REGS_O_IVCTRL) = 0x0b; | |
HWREG(RFCORE_XREG_CCACTRL0) = 0xf8; | |
HWREG(RFCORE_XREG_FIFOPCTRL) = IEEE802154_MAX_LENGTH; | |
HWREG(RFCORE_XREG_FRMCTRL0) = RFCORE_XREG_FRMCTRL0_AUTOCRC | RFCORE_XREG_FRMCTRL0_AUTOACK; | |
// default: SRCMATCH.SRC_MATCH_EN(1), SRCMATCH.AUTOPEND(1), | |
// SRCMATCH.PEND_DATAREQ_ONLY(1), RFCORE_XREG_FRMCTRL1_PENDING_OR(0) | |
HWREG(RFCORE_XREG_TXPOWER) = sTxPowerTable[0].mTxPowerReg; | |
sTxPower = sTxPowerTable[0].mTxPowerVal; | |
otLogInfoPlat(sInstance, "Initialized", NULL); | |
} | |
bool otPlatRadioIsEnabled(otInstance *aInstance) | |
{ | |
(void)aInstance; | |
return (sState != OT_RADIO_STATE_DISABLED) ? true : false; | |
} | |
otError otPlatRadioEnable(otInstance *aInstance) | |
{ | |
if (!otPlatRadioIsEnabled(aInstance)) | |
{ | |
otLogDebgPlat(sInstance, "State=OT_RADIO_STATE_SLEEP", NULL); | |
sState = OT_RADIO_STATE_SLEEP; | |
} | |
return OT_ERROR_NONE; | |
} | |
otError otPlatRadioDisable(otInstance *aInstance) | |
{ | |
if (otPlatRadioIsEnabled(aInstance)) | |
{ | |
otLogDebgPlat(sInstance, "State=OT_RADIO_STATE_DISABLED", NULL); | |
sState = OT_RADIO_STATE_DISABLED; | |
} | |
return OT_ERROR_NONE; | |
} | |
otError otPlatRadioSleep(otInstance *aInstance) | |
{ | |
otError error = OT_ERROR_INVALID_STATE; | |
(void)aInstance; | |
if (sState == OT_RADIO_STATE_SLEEP || sState == OT_RADIO_STATE_RECEIVE) | |
{ | |
otLogDebgPlat(sInstance, "State=OT_RADIO_STATE_SLEEP", NULL); | |
error = OT_ERROR_NONE; | |
sState = OT_RADIO_STATE_SLEEP; | |
disableReceiver(); | |
} | |
return error; | |
} | |
otError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel) | |
{ | |
otError error = OT_ERROR_INVALID_STATE; | |
(void)aInstance; | |
if (sState != OT_RADIO_STATE_DISABLED) | |
{ | |
otLogDebgPlat(sInstance, "State=OT_RADIO_STATE_RECEIVE", NULL); | |
error = OT_ERROR_NONE; | |
sState = OT_RADIO_STATE_RECEIVE; | |
setChannel(aChannel); | |
sReceiveFrame.mChannel = aChannel; | |
enableReceiver(); | |
} | |
return error; | |
} | |
otError otPlatRadioTransmit(otInstance *aInstance, otRadioFrame *aFrame) | |
{ | |
otError error = OT_ERROR_INVALID_STATE; | |
(void)aInstance; | |
if (sState == OT_RADIO_STATE_RECEIVE) | |
{ | |
int i; | |
error = OT_ERROR_NONE; | |
sState = OT_RADIO_STATE_TRANSMIT; | |
sTransmitError = OT_ERROR_NONE; | |
while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); | |
// flush txfifo | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHTX; | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHTX; | |
// frame length | |
HWREG(RFCORE_SFR_RFDATA) = aFrame->mLength; | |
// frame data | |
for (i = 0; i < aFrame->mLength; i++) | |
{ | |
HWREG(RFCORE_SFR_RFDATA) = aFrame->mPsdu[i]; | |
} | |
setChannel(aFrame->mChannel); | |
setTxPower(aFrame->mPower); | |
while ((HWREG(RFCORE_XREG_FSMSTAT1) & 1) == 0); | |
// wait for valid rssi | |
while ((HWREG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0); | |
otEXPECT_ACTION(((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_CCA) && | |
!((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_SFD))), | |
sTransmitError = OT_ERROR_CHANNEL_ACCESS_FAILURE); | |
// begin transmit | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_TXON; | |
otPlatRadioTxStarted(aInstance, aFrame); | |
while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE); | |
otLogDebgPlat(sInstance, "Transmitted %d bytes", aFrame->mLength); | |
} | |
exit: | |
return error; | |
} | |
otRadioFrame *otPlatRadioGetTransmitBuffer(otInstance *aInstance) | |
{ | |
(void)aInstance; | |
return &sTransmitFrame; | |
} | |
int8_t otPlatRadioGetRssi(otInstance *aInstance) | |
{ | |
(void)aInstance; | |
return 0; | |
} | |
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance) | |
{ | |
(void)aInstance; | |
return OT_RADIO_CAPS_NONE; | |
} | |
bool otPlatRadioGetPromiscuous(otInstance *aInstance) | |
{ | |
(void)aInstance; | |
return (HWREG(RFCORE_XREG_FRMFILT0) & RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN) == 0; | |
} | |
void otPlatRadioSetPromiscuous(otInstance *aInstance, bool aEnable) | |
{ | |
(void)aInstance; | |
otLogInfoPlat(sInstance, "PromiscuousMode=%d", aEnable ? 1 : 0); | |
if (aEnable) | |
{ | |
HWREG(RFCORE_XREG_FRMFILT0) &= ~RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN; | |
} | |
else | |
{ | |
HWREG(RFCORE_XREG_FRMFILT0) |= RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN; | |
} | |
} | |
void readFrame(void) | |
{ | |
uint8_t length; | |
uint8_t crcCorr; | |
int i; | |
otEXPECT(sState == OT_RADIO_STATE_RECEIVE || sState == OT_RADIO_STATE_TRANSMIT); | |
otEXPECT((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) != 0); | |
// read length | |
length = HWREG(RFCORE_SFR_RFDATA); | |
otEXPECT(IEEE802154_MIN_LENGTH <= length && length <= IEEE802154_MAX_LENGTH); | |
#if OPENTHREAD_ENABLE_RAW_LINK_API | |
// Timestamp | |
sReceiveFrame.mMsec = otPlatAlarmMilliGetNow(); | |
sReceiveFrame.mUsec = 0; // Don't support microsecond timer for now. | |
#endif | |
// read psdu | |
for (i = 0; i < length - 2; i++) | |
{ | |
sReceiveFrame.mPsdu[i] = HWREG(RFCORE_SFR_RFDATA); | |
} | |
sReceiveFrame.mPower = (int8_t)HWREG(RFCORE_SFR_RFDATA) - CC2538_RSSI_OFFSET; | |
crcCorr = HWREG(RFCORE_SFR_RFDATA); | |
if (crcCorr & CC2538_CRC_BIT_MASK) | |
{ | |
sReceiveFrame.mLength = length; | |
sReceiveFrame.mLqi = crcCorr & CC2538_LQI_BIT_MASK; | |
} | |
else | |
{ | |
// resets rxfifo | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; | |
otLogDebgPlat(sInstance, "Dropping %d received bytes (Invalid CRC)", length); | |
} | |
// check for rxfifo overflow | |
if ((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) != 0 && | |
(HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFO) == 0) | |
{ | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; | |
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX; | |
} | |
exit: | |
return; | |
} | |
void cc2538RadioProcess(otInstance *aInstance) | |
{ | |
readFrame(); | |
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 (((HWREG(RFCORE_XREG_FRMFILT0) & RFCORE_XREG_FRMFILT0_FRAME_FILTER_EN) == 0) || | |
(sReceiveFrame.mLength > IEEE802154_ACK_LENGTH)) | |
{ | |
otLogDebgPlat(sInstance, "Received %d bytes", sReceiveFrame.mLength); | |
otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError); | |
} | |
} | |
} | |
if (sState == OT_RADIO_STATE_TRANSMIT) | |
{ | |
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; | |
otPlatRadioTxDone(aInstance, &sTransmitFrame, &sReceiveFrame, sTransmitError); | |
} | |
} | |
sReceiveFrame.mLength = 0; | |
} | |
void RFCoreRxTxIntHandler(void) | |
{ | |
HWREG(RFCORE_SFR_RFIRQF0) = 0; | |
} | |
void RFCoreErrIntHandler(void) | |
{ | |
HWREG(RFCORE_SFR_RFERRF) = 0; | |
} | |
uint32_t getSrcMatchEntriesEnableStatus(bool aShort) | |
{ | |
uint32_t status = 0; | |
uint32_t *addr = aShort ? (uint32_t *) RFCORE_XREG_SRCSHORTEN0 : (uint32_t *) RFCORE_XREG_SRCEXTEN0; | |
for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++) | |
{ | |
status |= HWREG(addr++) << (i * 8); | |
} | |
return status; | |
} | |
int8_t findSrcMatchShortEntry(const uint16_t aShortAddress) | |
{ | |
int8_t entry = -1; | |
uint16_t shortAddr; | |
uint32_t bitMask; | |
uint32_t *addr = NULL; | |
uint32_t status = getSrcMatchEntriesEnableStatus(true); | |
for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_SHORT_ENTRIES; i++) | |
{ | |
bitMask = 0x00000001 << i; | |
if ((status & bitMask) == 0) | |
{ | |
continue; | |
} | |
addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE + (i * RFCORE_XREG_SRCMATCH_SHORT_ENTRY_OFFSET); | |
shortAddr = HWREG(addr + 2); | |
shortAddr |= HWREG(addr + 3) << 8; | |
if ((shortAddr == aShortAddress)) | |
{ | |
entry = i; | |
break; | |
} | |
} | |
return entry; | |
} | |
int8_t findSrcMatchExtEntry(const otExtAddress *aExtAddress) | |
{ | |
int8_t entry = -1; | |
uint32_t bitMask; | |
uint32_t *addr = NULL; | |
uint32_t status = getSrcMatchEntriesEnableStatus(false); | |
for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_EXT_ENTRIES; i++) | |
{ | |
uint8_t j = 0; | |
bitMask = 0x00000001 << 2 * i; | |
if ((status & bitMask) == 0) | |
{ | |
continue; | |
} | |
addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE + (i * RFCORE_XREG_SRCMATCH_EXT_ENTRY_OFFSET); | |
for (j = 0; j < sizeof(otExtAddress); j++) | |
{ | |
if (HWREG(addr + j) != aExtAddress->m8[j]) | |
{ | |
break; | |
} | |
} | |
if (j == sizeof(otExtAddress)) | |
{ | |
entry = i; | |
break; | |
} | |
} | |
return entry; | |
} | |
void setSrcMatchEntryEnableStatus(bool aShort, uint8_t aEntry, bool aEnable) | |
{ | |
uint8_t entry = aShort ? aEntry : (2 * aEntry); | |
uint8_t index = entry / 8; | |
uint32_t *addrEn = aShort ? (uint32_t *)RFCORE_XREG_SRCSHORTEN0 : (uint32_t *)RFCORE_XREG_SRCEXTEN0; | |
uint32_t *addrAutoPendEn = aShort ? (uint32_t *)RFCORE_FFSM_SRCSHORTPENDEN0 : (uint32_t *)RFCORE_FFSM_SRCEXTPENDEN0; | |
uint32_t bitMask = 0x00000001; | |
if (aEnable) | |
{ | |
HWREG(addrEn + index) |= (bitMask) << (entry % 8); | |
HWREG(addrAutoPendEn + index) |= (bitMask) << (entry % 8); | |
} | |
else | |
{ | |
HWREG(addrEn + index) &= ~((bitMask) << (entry % 8)); | |
HWREG(addrAutoPendEn + index) &= ~((bitMask) << (entry % 8)); | |
} | |
} | |
int8_t findSrcMatchAvailEntry(bool aShort) | |
{ | |
int8_t entry = -1; | |
uint32_t bitMask; | |
uint32_t shortEnableStatus = getSrcMatchEntriesEnableStatus(true); | |
uint32_t extEnableStatus = getSrcMatchEntriesEnableStatus(false); | |
otLogDebgPlat(sInstance, "Short enable status: 0x%x", shortEnableStatus); | |
otLogDebgPlat(sInstance, "Ext enable status: 0x%x", extEnableStatus); | |
if (aShort) | |
{ | |
bitMask = 0x00000001; | |
for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_SHORT_ENTRIES; i++) | |
{ | |
if ((extEnableStatus & bitMask) == 0) | |
{ | |
if ((shortEnableStatus & bitMask) == 0) | |
{ | |
entry = i; | |
break; | |
} | |
} | |
if (i % 2 == 1) | |
{ | |
extEnableStatus = extEnableStatus >> 2; | |
} | |
shortEnableStatus = shortEnableStatus >> 1; | |
} | |
} | |
else | |
{ | |
bitMask = 0x00000003; | |
for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_EXT_ENTRIES; i++) | |
{ | |
if (((extEnableStatus | shortEnableStatus) & bitMask) == 0) | |
{ | |
entry = i; | |
break; | |
} | |
extEnableStatus = extEnableStatus >> 2; | |
shortEnableStatus = shortEnableStatus >> 2; | |
} | |
} | |
return entry; | |
} | |
void otPlatRadioEnableSrcMatch(otInstance *aInstance, bool aEnable) | |
{ | |
(void)aInstance; | |
otLogInfoPlat(sInstance, "EnableSrcMatch=%d", aEnable ? 1 : 0); | |
if (aEnable) | |
{ | |
// only set FramePending when ack for data poll if there are queued messages | |
// for entries in the source match table. | |
HWREG(RFCORE_XREG_FRMCTRL1) &= ~RFCORE_XREG_FRMCTRL1_PENDING_OR; | |
} | |
else | |
{ | |
// set FramePending for all ack. | |
HWREG(RFCORE_XREG_FRMCTRL1) |= RFCORE_XREG_FRMCTRL1_PENDING_OR; | |
} | |
} | |
otError otPlatRadioAddSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) | |
{ | |
otError error = OT_ERROR_NONE; | |
int8_t entry = findSrcMatchAvailEntry(true); | |
uint32_t *addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE; | |
(void)aInstance; | |
otLogDebgPlat(sInstance, "Add ShortAddr entry: %d", entry); | |
otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_BUFS); | |
addr += (entry * RFCORE_XREG_SRCMATCH_SHORT_ENTRY_OFFSET); | |
HWREG(addr++) = HWREG(RFCORE_FFSM_PAN_ID0); | |
HWREG(addr++) = HWREG(RFCORE_FFSM_PAN_ID1); | |
HWREG(addr++) = aShortAddress & 0xFF; | |
HWREG(addr++) = aShortAddress >> 8; | |
setSrcMatchEntryEnableStatus(true, (uint8_t)(entry), true); | |
exit: | |
return error; | |
} | |
otError otPlatRadioAddSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress) | |
{ | |
otError error = OT_ERROR_NONE; | |
int8_t entry = findSrcMatchAvailEntry(false); | |
uint32_t *addr = (uint32_t *)RFCORE_FFSM_SRCADDRESS_TABLE; | |
(void)aInstance; | |
otLogDebgPlat(sInstance, "Add ExtAddr entry: %d", entry); | |
otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_BUFS); | |
addr += (entry * RFCORE_XREG_SRCMATCH_EXT_ENTRY_OFFSET); | |
for (uint8_t i = 0; i < sizeof(otExtAddress); i++) | |
{ | |
HWREG(addr++) = aExtAddress->m8[i]; | |
} | |
setSrcMatchEntryEnableStatus(false, (uint8_t)(entry), true); | |
exit: | |
return error; | |
} | |
otError otPlatRadioClearSrcMatchShortEntry(otInstance *aInstance, const uint16_t aShortAddress) | |
{ | |
otError error = OT_ERROR_NONE; | |
int8_t entry = findSrcMatchShortEntry(aShortAddress); | |
(void)aInstance; | |
otLogDebgPlat(sInstance, "Clear ShortAddr entry: %d", entry); | |
otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_ADDRESS); | |
setSrcMatchEntryEnableStatus(true, (uint8_t)(entry), false); | |
exit: | |
return error; | |
} | |
otError otPlatRadioClearSrcMatchExtEntry(otInstance *aInstance, const otExtAddress *aExtAddress) | |
{ | |
otError error = OT_ERROR_NONE; | |
int8_t entry = findSrcMatchExtEntry(aExtAddress); | |
(void)aInstance; | |
otLogDebgPlat(sInstance, "Clear ExtAddr entry: %d", entry); | |
otEXPECT_ACTION(entry >= 0, error = OT_ERROR_NO_ADDRESS); | |
setSrcMatchEntryEnableStatus(false, (uint8_t)(entry), false); | |
exit: | |
return error; | |
} | |
void otPlatRadioClearSrcMatchShortEntries(otInstance *aInstance) | |
{ | |
uint32_t *addrEn = (uint32_t *)RFCORE_XREG_SRCSHORTEN0; | |
uint32_t *addrAutoPendEn = (uint32_t *)RFCORE_FFSM_SRCSHORTPENDEN0; | |
(void)aInstance; | |
otLogDebgPlat(sInstance, "Clear ShortAddr entries", NULL); | |
for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++) | |
{ | |
HWREG(addrEn++) = 0; | |
HWREG(addrAutoPendEn++) = 0; | |
} | |
} | |
void otPlatRadioClearSrcMatchExtEntries(otInstance *aInstance) | |
{ | |
uint32_t *addrEn = (uint32_t *)RFCORE_XREG_SRCEXTEN0; | |
uint32_t *addrAutoPendEn = (uint32_t *)RFCORE_FFSM_SRCEXTPENDEN0; | |
(void)aInstance; | |
otLogDebgPlat(sInstance, "Clear ExtAddr entries", NULL); | |
for (uint8_t i = 0; i < RFCORE_XREG_SRCMATCH_ENABLE_STATUS_SIZE; i++) | |
{ | |
HWREG(addrEn++) = 0; | |
HWREG(addrAutoPendEn++) = 0; | |
} | |
} | |
otError otPlatRadioEnergyScan(otInstance *aInstance, uint8_t aScanChannel, uint16_t aScanDuration) | |
{ | |
(void)aInstance; | |
(void)aScanChannel; | |
(void)aScanDuration; | |
return OT_ERROR_NOT_IMPLEMENTED; | |
} | |
void otPlatRadioSetDefaultTxPower(otInstance *aInstance, int8_t aPower) | |
{ | |
// TODO: Create a proper implementation for this driver. | |
(void)aInstance; | |
(void)aPower; | |
} | |
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance) | |
{ | |
(void)aInstance; | |
return CC2538_RECEIVE_SENSITIVITY; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment