Skip to content

Instantly share code, notes, and snippets.

@sjlongland
Last active January 8, 2018 06:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sjlongland/5a3f8a3a9878396da1356c264f7fd87f to your computer and use it in GitHub Desktop.
Save sjlongland/5a3f8a3a9878396da1356c264f7fd87f to your computer and use it in GitHub Desktop.
Debugging the CC2538 radio driver.
/*
* 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"
#include "fs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.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;
static const char* get_time() {
static char _time[32];
struct timeval tv;
gettimeofday(&tv, NULL);
ctime_r(&tv.tv_sec, _time);
const char* end = rindex(_time, '\n');
if (end)
end = 0;
return _time;
}
void enableReceiver(void)
{
if (!sIsReceiverEnabled)
{
otLogInfoPlat(sInstance, "%s Enabling receiver", get_time(), 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, "%s Disabling receiver", get_time(), 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)
{
otLogDebgPlat(sInstance, "%s Set channel(%d), need to disable receiver", get_time(), aChannel);
disableReceiver();
enabled = true;
}
otLogInfoPlat(sInstance, "%s Channel=%d", get_time(), aChannel);
HWREG(RFCORE_XREG_FREQCTRL) = 11 + (aChannel - 11) * 5;
sChannel = aChannel;
if (enabled)
{
otLogDebgPlat(sInstance, "%s Set channel(%d), re-enabling receiver", get_time(), aChannel);
enableReceiver();
}
}
}
void setTxPower(int8_t aTxPower)
{
uint8_t i = 0;
if (sTxPower != aTxPower)
{
otLogInfoPlat(sInstance, "%s TxPower=%d", get_time(), 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, "%s PANID=%X", get_time(), 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, "%s ExtAddr=%X%X%X%X%X%X%X%X", get_time(),
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, "%s ShortAddr=%X", get_time(), 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, "%s Initialized", get_time());
}
bool otPlatRadioIsEnabled(otInstance *aInstance)
{
(void)aInstance;
return (sState != OT_RADIO_STATE_DISABLED) ? true : false;
}
otError otPlatRadioEnable(otInstance *aInstance)
{
if (!otPlatRadioIsEnabled(aInstance))
{
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_SLEEP [%d]", get_time(), __LINE__);
sState = OT_RADIO_STATE_SLEEP;
}
return OT_ERROR_NONE;
}
otError otPlatRadioDisable(otInstance *aInstance)
{
if (otPlatRadioIsEnabled(aInstance))
{
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_DISABLED [%d]", get_time(), __LINE__);
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, "%s State=OT_RADIO_STATE_SLEEP [%d]", get_time(), __LINE__);
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, "%s State=OT_RADIO_STATE_RECEIVE [%d]", get_time(), __LINE__);
error = OT_ERROR_NONE;
sState = OT_RADIO_STATE_RECEIVE;
setChannel(aChannel);
sReceiveFrame.mChannel = aChannel;
enableReceiver();
}
return error;
}
static void setupTransmit(otRadioFrame *aFrame)
{
int i;
// wait for current TX operation to complete, if any.
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);
}
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;
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_TRANSMIT [%d]", get_time(), __LINE__);
sState = OT_RADIO_STATE_TRANSMIT;
sTransmitError = OT_ERROR_NONE;
setupTransmit(aFrame);
// Set up a counter to inform us if we get stuck.
i = 1000000;
// Wait for radio to enter receive state.
while ((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_RX_ACTIVE) == 0)
{
// Count down the cycles, and emit a message if we get to zero.
// Ideally, we should never get there!
if (i)
{
i--;
}
else
{
otLogCritPlat(sInstance, "Radio is stuck!!! FSMSTAT0=0x%08x FSMSTAT1=0x%08x RFERRF=0x%08x", get_time(),
HWREG(RFCORE_XREG_FSMSTAT0), HWREG(RFCORE_XREG_FSMSTAT1), HWREG(RFCORE_SFR_RFERRF));
i = 1000000;
}
// Ensure we haven't overflowed the RX buffer in the mean time, as this
// will cause a deadlock here otherwise. Similarly, if we see an aborted
// RX, handle that here too to prevent deadlock.
if (HWREG(RFCORE_SFR_RFERRF) &
(RFCORE_SFR_RFERRF_RXOVERF | RFCORE_SFR_RFERRF_RXABO))
{
if (HWREG(RFCORE_SFR_RFERRF) & RFCORE_SFR_RFERRF_RXOVERF)
{
otLogCritPlat(sInstance, "RX Buffer Overflow detected", get_time(), NULL);
}
if (HWREG(RFCORE_SFR_RFERRF) & RFCORE_SFR_RFERRF_RXABO)
{
otLogCritPlat(sInstance, "Aborted RX detected", get_time(), NULL);
}
// Flush the RX buffer
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
}
// Check for idle state. After flushing the RX buffer, we may wind up here.
if (!(HWREG(RFCORE_XREG_FSMSTAT1)
& (RFCORE_XREG_FSMSTAT1_TX_ACTIVE | RFCORE_XREG_FSMSTAT1_RX_ACTIVE)))
{
otLogCritPlat(sInstance, "Idle state detected", get_time(), NULL);
// In this case, the state of our driver mis-matches our state. So force
// matters by clearing our channel variable and calling setChannel. This
// should bring our radio into the RX state, which should allow us to go
// into TX.
sChannel = 0;
setupTransmit(aFrame);
}
}
// 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, "%s Transmitted %d bytes", get_time(), aFrame->mLength);
}
else
{
otLogDebgPlat(sInstance, "%s Not in RECEIVE state (state %d)", get_time(), sState);
}
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, "%s PromiscuousMode=%d", get_time(), 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.mRssi = (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, "%s Dropping %d received bytes (Invalid CRC)", get_time(), 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, "%s Received %d bytes", get_time(), 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, "%s Transmit failed ErrorCode=%s", get_time(),
otThreadErrorToString(sTransmitError));
}
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_RECEIVE [%d]", get_time(), __LINE__);
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]))
{
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_RECEIVE [%d]", get_time(), __LINE__);
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, "%s Short enable status: 0x%x", get_time(), shortEnableStatus);
otLogDebgPlat(sInstance, "%s Ext enable status: 0x%x", get_time(), 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, "%s EnableSrcMatch=%d", get_time(), 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, "%s Add ShortAddr entry: %d", get_time(), 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, "%s Add ExtAddr entry: %d", get_time(), 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, "%s Clear ShortAddr entry: %d", get_time(), 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, "%s Clear ExtAddr entry: %d", get_time(), 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, "%s Clear ShortAddr entries", get_time(), 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, "%s Clear ExtAddr entries", get_time(), 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;
}
otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
{
otError error = OT_ERROR_NONE;
(void)aInstance;
otEXPECT_ACTION(aPower != NULL, error = OT_ERROR_INVALID_ARGS);
*aPower = sTxPower;
exit:
return error;
}
otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
{
(void)aInstance;
setTxPower(aPower);
return OT_ERROR_NONE;
}
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
{
(void)aInstance;
return CC2538_RECEIVE_SENSITIVITY;
}
/*
* 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"
#define RFCORE_RXTX_INT (141)
#define RFCORE_XREG_RFIRQM0 0x4008868C // RF interrupt masks
#define RFCORE_XREG_RFIRQM1 0x40088690 // RF interrupt masks
#define RFCORE_XREG_RFERRM 0x40088694 // RF error interrupt mask
#define RFCORE_SFR_RFIRQF0_RXMASKZERO 0x00000080 // RXENABLE is now completely clear
#define RFCORE_SFR_RFIRQF0_RXPKTDONE 0x00000040 // A complete frame has been received
#define RFCORE_SFR_RFIRQF0_FRAME_ACCEPTED 0x00000020 // Frame has passed frame filtering
#define RFCORE_SFR_RFIRQF0_SRC_MATCH_FOUND 0x00000010 // Source match is found
#define RFCORE_SFR_RFIRQF0_SRC_MATCH_DONE 0x00000008 // Source matching is complete
#define RFCORE_SFR_RFIRQF0_FIFOP 0x00000004 // The number of bytes in the RX fifo is above threshold
#define RFCORE_SFR_RFIRQF0_SFD 0x00000002 // SFD has been received or transmitted
#define RFCORE_SFR_RFIRQF0_ACT_UNUSED 0x00000001 // Reserved
#define RFCORE_XREG_RFIRQM0_RXMASKZERO 0x00000080
#define RFCORE_XREG_RFIRQM0_RXPKTDONE 0x00000040
#define RFCORE_XREG_RFIRQM0_FRAME_ACCEPTED 0x00000020
#define RFCORE_XREG_RFIRQM0_SRC_MATCH_FOUND 0x00000010
#define RFCORE_XREG_RFIRQM0_SRC_MATCH_DONE 0x00000008
#define RFCORE_XREG_RFIRQM0_FIFOP 0x00000004
#define RFCORE_XREG_RFIRQM0_SFD 0x00000002
#define RFCORE_XREG_RFIRQM0_ACT_UNUSED 0x00000001
#define RFCORE_SFR_RFIRQF1_CSP_WAIT 0x00000020
#define RFCORE_SFR_RFIRQF1_CSP_STOP 0x00000010
#define RFCORE_SFR_RFIRQF1_CSP_MANINT 0x00000008
#define RFCORE_SFR_RFIRQF1_RF_IDLE 0x00000004
#define RFCORE_SFR_RFIRQF1_TXDONE 0x00000002
#define RFCORE_SFR_RFIRQF1_TXACKDONE 0x00000001
#define RFCORE_XREG_RFIRQM1_CSP_WAIT 0x00000020
#define RFCORE_XREG_RFIRQM1_CSP_STOP 0x00000010
#define RFCORE_XREG_RFIRQM1_CSP_MANINT 0x00000008
#define RFCORE_XREG_RFIRQM1_RF_IDLE 0x00000004
#define RFCORE_XREG_RFIRQM1_TXDONE 0x00000002
#define RFCORE_XREG_RFIRQM1_TXACKDONE 0x00000001
#define RFCORE_XREG_RFERRM_STROBE_ERR 0x00000040
#define RFCORE_XREG_RFERRM_TXUNDERF 0x00000020
#define RFCORE_XREG_RFERRM_TXOVERF 0x00000010
#define RFCORE_XREG_RFERRM_RXUNDERF 0x00000008
#define RFCORE_XREG_RFERRM_RXOVERF 0x00000004
#define RFCORE_XREG_RFERRM_RXABO 0x00000002
#define RFCORE_XREG_RFERRM_NLOCK 0x00000001
#include "interrupt.h"
#include "fs.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <time.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;
static const char* get_time() {
static char _time[32];
struct timeval tv;
gettimeofday(&tv, NULL);
ctime_r(&tv.tv_sec, _time);
const char* end = rindex(_time, '\n');
if (end)
end = 0;
return _time;
}
void enableReceiver(void)
{
if (!sIsReceiverEnabled)
{
otLogInfoPlat(sInstance, "%s Enabling receiver", get_time(), 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, "%s Disabling receiver", get_time(), 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)
{
otLogDebgPlat(sInstance, "%s Set channel(%d), need to disable receiver", get_time(), aChannel);
disableReceiver();
enabled = true;
}
otLogInfoPlat(sInstance, "%s Channel=%d", get_time(), aChannel);
HWREG(RFCORE_XREG_FREQCTRL) = 11 + (aChannel - 11) * 5;
sChannel = aChannel;
if (enabled)
{
otLogDebgPlat(sInstance, "%s Set channel(%d), re-enabling receiver", get_time(), aChannel);
enableReceiver();
}
}
}
void setTxPower(int8_t aTxPower)
{
uint8_t i = 0;
if (sTxPower != aTxPower)
{
otLogInfoPlat(sInstance, "%s TxPower=%d", get_time(), 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, "%s PANID=%X", get_time(), 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, "%s ExtAddr=%X%X%X%X%X%X%X%X", get_time(),
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, "%s ShortAddr=%X", get_time(), 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 interrupts for RX/TX, not sure which is being used.
nvic_enable(RFCORE_RXTX_INT);
HWREG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_RXPKTDONE;
// 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, "%s Initialized", get_time());
}
bool otPlatRadioIsEnabled(otInstance *aInstance)
{
(void)aInstance;
return (sState != OT_RADIO_STATE_DISABLED) ? true : false;
}
otError otPlatRadioEnable(otInstance *aInstance)
{
if (!otPlatRadioIsEnabled(aInstance))
{
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_SLEEP [%d]", get_time(), __LINE__);
sState = OT_RADIO_STATE_SLEEP;
}
return OT_ERROR_NONE;
}
otError otPlatRadioDisable(otInstance *aInstance)
{
if (otPlatRadioIsEnabled(aInstance))
{
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_DISABLED [%d]", get_time(), __LINE__);
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, "%s State=OT_RADIO_STATE_SLEEP [%d]", get_time(), __LINE__);
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, "%s State=OT_RADIO_STATE_RECEIVE [%d]", get_time(), __LINE__);
error = OT_ERROR_NONE;
sState = OT_RADIO_STATE_RECEIVE;
setChannel(aChannel);
sReceiveFrame.mChannel = aChannel;
enableReceiver();
}
return error;
}
static void setupTransmit(otRadioFrame *aFrame)
{
int i;
// wait for current TX operation to complete, if any.
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);
}
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;
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_TRANSMIT [%d]", get_time(), __LINE__);
sState = OT_RADIO_STATE_TRANSMIT;
sTransmitError = OT_ERROR_NONE;
setupTransmit(aFrame);
// Set up a counter to inform us if we get stuck.
i = 1000000;
// Wait for radio to enter receive state.
while ((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_RX_ACTIVE) == 0)
{
// Count down the cycles, and emit a message if we get to zero.
// Ideally, we should never get there!
if (i)
{
i--;
}
else
{
otLogCritPlat(sInstance, "Radio is stuck!!! FSMSTAT0=0x%08x FSMSTAT1=0x%08x RFERRF=0x%08x", get_time(),
HWREG(RFCORE_XREG_FSMSTAT0), HWREG(RFCORE_XREG_FSMSTAT1), HWREG(RFCORE_SFR_RFERRF));
i = 1000000;
}
// Ensure we haven't overflowed the RX buffer in the mean time, as this
// will cause a deadlock here otherwise. Similarly, if we see an aborted
// RX, handle that here too to prevent deadlock.
if (HWREG(RFCORE_SFR_RFERRF) &
(RFCORE_SFR_RFERRF_RXOVERF | RFCORE_SFR_RFERRF_RXABO))
{
if (HWREG(RFCORE_SFR_RFERRF) & RFCORE_SFR_RFERRF_RXOVERF)
{
otLogCritPlat(sInstance, "RX Buffer Overflow detected", get_time(), NULL);
}
if (HWREG(RFCORE_SFR_RFERRF) & RFCORE_SFR_RFERRF_RXABO)
{
otLogCritPlat(sInstance, "Aborted RX detected", get_time(), NULL);
}
// Flush the RX buffer
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_FLUSHRX;
}
// Check for idle state. After flushing the RX buffer, we may wind up here.
if (!(HWREG(RFCORE_XREG_FSMSTAT1)
& (RFCORE_XREG_FSMSTAT1_TX_ACTIVE | RFCORE_XREG_FSMSTAT1_RX_ACTIVE)))
{
otLogCritPlat(sInstance, "Idle state detected", get_time(), NULL);
// In this case, the state of our driver mis-matches our state. So force
// matters by clearing our channel variable and calling setChannel. This
// should bring our radio into the RX state, which should allow us to go
// into TX.
sChannel = 0;
setupTransmit(aFrame);
}
}
// 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, "%s Transmitted %d bytes", get_time(), aFrame->mLength);
}
else
{
otLogDebgPlat(sInstance, "%s Not in RECEIVE state (state %d)", get_time(), sState);
}
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, "%s PromiscuousMode=%d", get_time(), 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);
otEXPECT(sReceiveFrame.mLength == 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.mRssi = (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, "%s Dropping %d received bytes (Invalid CRC)", get_time(), 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)
{
HWREG(RFCORE_XREG_RFIRQM0) &= ~RFCORE_XREG_RFIRQM0_RXPKTDONE;
readFrame();
HWREG(RFCORE_XREG_RFIRQM0) |= RFCORE_XREG_RFIRQM0_RXPKTDONE;
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, "%s Received %d bytes", get_time(), 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, "%s Transmit failed ErrorCode=%s", get_time(),
otThreadErrorToString(sTransmitError));
}
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_RECEIVE [%d]", get_time(), __LINE__);
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]))
{
otLogDebgPlat(sInstance, "%s State=OT_RADIO_STATE_RECEIVE [%d]", get_time(), __LINE__);
sState = OT_RADIO_STATE_RECEIVE;
otPlatRadioTxDone(aInstance, &sTransmitFrame, &sReceiveFrame, sTransmitError);
}
}
sReceiveFrame.mLength = 0;
}
void RFCoreRxTxIntHandler(void)
{
if (HWREG(RFCORE_SFR_RFIRQF0) & RFCORE_SFR_RFIRQF0_RXPKTDONE)
{
readFrame();
}
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, "%s Short enable status: 0x%x", get_time(), shortEnableStatus);
otLogDebgPlat(sInstance, "%s Ext enable status: 0x%x", get_time(), 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, "%s EnableSrcMatch=%d", get_time(), 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, "%s Add ShortAddr entry: %d", get_time(), 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, "%s Add ExtAddr entry: %d", get_time(), 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, "%s Clear ShortAddr entry: %d", get_time(), 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, "%s Clear ExtAddr entry: %d", get_time(), 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, "%s Clear ShortAddr entries", get_time(), 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, "%s Clear ExtAddr entries", get_time(), 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;
}
otError otPlatRadioGetTransmitPower(otInstance *aInstance, int8_t *aPower)
{
otError error = OT_ERROR_NONE;
(void)aInstance;
otEXPECT_ACTION(aPower != NULL, error = OT_ERROR_INVALID_ARGS);
*aPower = sTxPower;
exit:
return error;
}
otError otPlatRadioSetTransmitPower(otInstance *aInstance, int8_t aPower)
{
(void)aInstance;
setTxPower(aPower);
return OT_ERROR_NONE;
}
int8_t otPlatRadioGetReceiveSensitivity(otInstance *aInstance)
{
(void)aInstance;
return CC2538_RECEIVE_SENSITIVITY;
}
/*
* 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 gcc-specific startup code for the cc2538.
*/
#include <stdint.h>
#include <string.h>
#include "sysctrl.h"
#include "uart.h"
#include "gpio.h"
#include "pulsein.h"
#include "powerctl.h"
extern uint8_t _ldata;
extern uint8_t _data;
extern uint8_t _edata;
extern uint8_t _bss;
extern uint8_t _ebss;
extern uint8_t _init_array;
extern uint8_t _einit_array;
__extension__ typedef int __guard __attribute__((mode(__DI__)));
int __cxa_guard_acquire(__guard *g) { return !*(char *)(g); }
void __cxa_guard_release(__guard *g) { *(char *)g = 1; }
void __cxa_guard_abort(__guard *g) { (void)g; }
void __cxa_pure_virtual(void) { while (1); }
void HardFaultHandler(uint32_t* hardfault_args);
void IntDefaultHandler(void);
void ResetHandler(void);
extern void SysTick_Handler(void);
extern void UART0IntHandler(void);
extern void RFCoreRxTxIntHandler(void);
extern void RFCoreErrIntHandler(void);
extern void main(void);
static uint64_t stack[512] __attribute__((section(".stack")));
__attribute__((section(".vectors"), used))
void (*const vectors[])(void) =
{
(void (*)(void))((unsigned long)stack + sizeof(stack)), // Initial Stack Pointer
ResetHandler, // 1 The reset handler
ResetHandler, // 2 The NMI handler
(void (*)(void))HardFaultHandler, // 3 The hard fault handler
(void (*)(void))HardFaultHandler, // 4 The MPU fault handler
(void (*)(void))HardFaultHandler, // 5 The bus fault handler
(void (*)(void))HardFaultHandler, // 6 The usage fault handler
0, // 7 Reserved
0, // 8 Reserved
0, // 9 Reserved
0, // 10 Reserved
IntDefaultHandler, // 11 SVCall handler
IntDefaultHandler, // 12 Debug monitor handler
0, // 13 Reserved
IntDefaultHandler, // 14 The PendSV handler
SysTick_Handler, // 15 The SysTick handler
gpio_a_int, // 16 GPIO Port A
gpio_b_int, // 17 GPIO Port B
gpio_c_int, // 18 GPIO Port C
gpio_d_int, // 19 GPIO Port D
0, // 20 none
cc2538_uart0_handler, // 21 UART0 Rx and Tx
IntDefaultHandler, // 22 UART1 Rx and Tx
IntDefaultHandler, // 23 SSI0 Rx and Tx
IntDefaultHandler, // 24 I2C Master and Slave
0, // 25 Reserved
0, // 26 Reserved
0, // 27 Reserved
0, // 28 Reserved
0, // 29 Reserved
IntDefaultHandler, // 30 ADC Sequence 0
0, // 31 Reserved
0, // 32 Reserved
0, // 33 Reserved
IntDefaultHandler, // 34 Watchdog timer, timer 0
IntDefaultHandler, // 35 Timer 0 subtimer A
IntDefaultHandler, // 36 Timer 0 subtimer B
powerctl_fault_timeout, // 37 Timer 1 subtimer A
IntDefaultHandler, // 38 Timer 1 subtimer B
IntDefaultHandler, // 39 Timer 2 subtimer A
IntDefaultHandler, // 40 Timer 2 subtimer B
IntDefaultHandler, // 41 Analog Comparator 0
RFCoreRxTxIntHandler, // 42 RFCore Rx/Tx
RFCoreErrIntHandler, // 43 RFCore Error
IntDefaultHandler, // 44 IcePick
IntDefaultHandler, // 45 FLASH Control
IntDefaultHandler, // 46 AES
IntDefaultHandler, // 47 PKA
IntDefaultHandler, // 48 Sleep Timer
IntDefaultHandler, // 49 MacTimer
IntDefaultHandler, // 50 SSI1 Rx and Tx
pulsein_timeout, // 51 Timer 3 subtimer A
IntDefaultHandler, // 52 Timer 3 subtimer B
0, // 53 Reserved
0, // 54 Reserved
0, // 55 Reserved
0, // 56 Reserved
0, // 57 Reserved
0, // 58 Reserved
0, // 59 Reserved
IntDefaultHandler, // 60 USB 2538
0, // 61 Reserved
IntDefaultHandler, // 62 uDMA
IntDefaultHandler, // 63 uDMA Error
0, // 64 Reserved
0, // 65 Reserved
0, // 66 Reserved
0, // 67 Reserved
0, // 68 Reserved
0, // 69 Reserved
0, // 70 Reserved
0, // 71 Reserved
0, // 72 Reserved
0, // 73 Reserved
0, // 74 Reserved
0, // 75 Reserved
0, // 76 Reserved
0, // 77 Reserved
0, // 78 Reserved
0, // 79 Reserved
0, // 80 Reserved
0, // 81 Reserved
0, // 82 Reserved
0, // 83 Reserved
0, // 84 Reserved
0, // 85 Reserved
0, // 86 Reserved
0, // 87 Reserved
0, // 88 Reserved
0, // 89 Reserved
0, // 90 Reserved
0, // 91 Reserved
0, // 92 Reserved
0, // 93 Reserved
0, // 94 Reserved
0, // 95 Reserved
0, // 96 Reserved
0, // 97 Reserved
0, // 98 Reserved
0, // 99 Reserved
0, // 100 Reserved
0, // 101 Reserved
0, // 102 Reserved
0, // 103 Reserved
0, // 104 Reserved
0, // 105 Reserved
0, // 106 Reserved
0, // 107 Reserved
0, // 108 Reserved
0, // 109 Reserved
0, // 110 Reserved
0, // 111 Reserved
0, // 112 Reserved
0, // 113 Reserved
0, // 114 Reserved
0, // 115 Reserved
0, // 116 Reserved
0, // 117 Reserved
0, // 118 Reserved
0, // 119 Reserved
0, // 120 Reserved
0, // 121 Reserved
0, // 122 Reserved
0, // 123 Reserved
0, // 124 Reserved
0, // 125 Reserved
0, // 126 Reserved
0, // 127 Reserved
0, // 128 Reserved
0, // 129 Reserved
0, // 130 Reserved
0, // 131 Reserved
0, // 132 Reserved
0, // 133 Reserved
0, // 134 Reserved
0, // 135 Reserved
0, // 136 Reserved
0, // 137 Reserved
0, // 138 Reserved
0, // 139 Reserved
0, // 140 Reserved
0, // 141 Reserved
0, // 142 Reserved
0, // 143 Reserved
0, // 144 Reserved
0, // 145 Reserved
0, // 146 Reserved
0, // 147 Reserved
0, // 148 Reserved
0, // 149 Reserved
0, // 150 Reserved
0, // 151 Reserved
0, // 152 Reserved
0, // 153 Reserved
0, // 154 Reserved
0, // 155 Reserved
0, // 156 USB
RFCoreRxTxIntHandler, // 157 RF Core Rx/Tx
RFCoreErrIntHandler, // 158 RF Core Error
0, // 159 AES
0, // 160 PKA
0, // 161 SM Timer
0, // 162 MAC Timer
0, // 163 Reserved
};
void IntDefaultHandler(void) {
while(1);
}
void HardFaultHandler(uint32_t *hardfault_args)
{
#if 0
static volatile struct fault_regs {
uint32_t r0;
uint32_t r1;
uint32_t r2;
uint32_t r3;
uint32_t r12;
uint32_t lr;
uint32_t pc;
uint32_t psr;
uint32_t bfar;
uint32_t cfsr;
uint32_t hfsr;
uint32_t dfsr;
uint32_t afsr;
uint32_t shcsr;
} fault_regs;
fault_regs.r0 = hardfault_args[0];
fault_regs.r1 = hardfault_args[1];
fault_regs.r2 = hardfault_args[2];
fault_regs.r3 = hardfault_args[3];
fault_regs.r12 = hardfault_args[4];
fault_regs.lr = hardfault_args[5];
fault_regs.pc = hardfault_args[6];
fault_regs.psr = hardfault_args[7];
fault_regs.bfar = HWREG(0xe000ed38);
fault_regs.cfsr = HWREG(0xe000ed28);
fault_regs.hfsr = HWREG(0xe000ed2c);
fault_regs.dfsr = HWREG(0xe000ed30);
fault_regs.afsr = HWREG(0xe000ed3c);
fault_regs.shcsr = HWREG(0xe000ed24);
(void)fault_regs;
#else
(void)hardfault_args;
#endif
while (1);
}
#define FLASH_CCA_BOOTLDR_CFG_DISABLE 0xEFFFFFFF ///< Disable backdoor function
#define FLASH_CCA_BOOTLDR_CFG_ENABLE 0xF0FFFFFF ///< Enable backdoor function
#define FLASH_CCA_BOOTLDR_CFG_ACTIVE_HIGH 0x08000000 ///< Selected pin on pad A active high
#define FLASH_CCA_BOOTLDR_CFG_PORT_A_PIN_M 0x07000000 ///< Selected pin on pad A mask
#define FLASH_CCA_BOOTLDR_CFG_PORT_A_PIN_S 24 ///< Selected pin on pad A shift
#define FLASH_CCA_IMAGE_VALID 0x00000000 ///< Indicates valid image in flash
#define FLASH_CCA_CONF_BOOTLDR_BACKDOOR_PORT_A_PIN 6 ///< Select Button on SmartRF06 Eval Board
typedef struct
{
uint32_t ui32BootldrCfg;
uint32_t ui32ImageValid;
uint32_t ui32ImageVectorAddr;
uint8_t ui8lock[32];
} flash_cca_lock_page_t;
__attribute__((__section__(".flashcca"), used))
const flash_cca_lock_page_t flash_cca_lock_page =
{
FLASH_CCA_BOOTLDR_CFG_ENABLE
| (FLASH_CCA_CONF_BOOTLDR_BACKDOOR_PORT_A_PIN
<< FLASH_CCA_BOOTLDR_CFG_PORT_A_PIN_S),
FLASH_CCA_IMAGE_VALID,
(uint32_t) &vectors,
{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
}
};
typedef void (*init_fn_t)(void);
void ResetHandler(void)
{
SYS_CTRL_EMUOVR = 0xFF;
// configure clocks
SYS_CTRL_CLOCK_CTRL |= SYS_CTRL_CLOCK_CTRL_AMP_DET;
SYS_CTRL_CLOCK_CTRL = (0 << SYS_CTRL_CLOCK_CTRL_SYS_DIV) |
(1 << SYS_CTRL_CLOCK_CTRL_IO_DIV) |
SYS_CTRL_CLOCK_CTRL_OSC_PD;
// alternate map
SYS_CTRL_I_MAP |= SYS_CTRL_I_MAP_ALTMAP;
// copy the data segment initializers from flash to SRAM
memcpy(&_data, &_ldata, &_edata - &_data);
// zero-fill the bss segment
memset(&_bss, 0, &_ebss - &_bss);
// C++ runtime initialization (BSS, Data, relocation, etc.)
init_fn_t *fp;
for (fp = (init_fn_t *)&_init_array; fp < (init_fn_t *)&_einit_array; fp++)
{
(*fp)();
}
// call the application's entry point
main();
// end here if main() returns
while (1);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment