452 lines
12 KiB
C
452 lines
12 KiB
C
/*
|
|
* 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-types.h>
|
|
#include <openthread.h>
|
|
#include <openthread-config.h>
|
|
|
|
#include <common/code_utils.hpp>
|
|
#include <platform/platform.h>
|
|
#include <platform/radio.h>
|
|
#include <platform/diag.h>
|
|
#include "platform-cc2538.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,
|
|
};
|
|
|
|
static RadioPacket sTransmitFrame;
|
|
static RadioPacket sReceiveFrame;
|
|
static ThreadError sTransmitError;
|
|
static ThreadError sReceiveError;
|
|
|
|
static uint8_t sTransmitPsdu[IEEE802154_MAX_LENGTH];
|
|
static uint8_t sReceivePsdu[IEEE802154_MAX_LENGTH];
|
|
|
|
static PhyState sState = kStateDisabled;
|
|
static bool sIsReceiverEnabled = false;
|
|
|
|
void enableReceiver(void)
|
|
{
|
|
if (!sIsReceiverEnabled)
|
|
{
|
|
// 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)
|
|
{
|
|
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 channel)
|
|
{
|
|
HWREG(RFCORE_XREG_FREQCTRL) = 11 + (channel - 11) * 5;
|
|
}
|
|
|
|
ThreadError otPlatRadioSetPanId(otInstance *aInstance, uint16_t panid)
|
|
{
|
|
ThreadError error = kThreadError_Busy;
|
|
(void)aInstance;
|
|
|
|
if (sState != kStateTransmit)
|
|
{
|
|
HWREG(RFCORE_FFSM_PAN_ID0) = panid & 0xFF;
|
|
HWREG(RFCORE_FFSM_PAN_ID1) = panid >> 8;
|
|
error = kThreadError_None;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
ThreadError otPlatRadioSetExtendedAddress(otInstance *aInstance, uint8_t *address)
|
|
{
|
|
ThreadError error = kThreadError_Busy;
|
|
(void)aInstance;
|
|
|
|
if (sState != kStateTransmit)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
((volatile uint32_t *)RFCORE_FFSM_EXT_ADDR0)[i] = address[i];
|
|
}
|
|
|
|
error = kThreadError_None;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
ThreadError otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t address)
|
|
{
|
|
ThreadError error = kThreadError_Busy;
|
|
(void)aInstance;
|
|
|
|
if (sState != kStateTransmit)
|
|
{
|
|
HWREG(RFCORE_FFSM_SHORT_ADDR0) = address & 0xFF;
|
|
HWREG(RFCORE_FFSM_SHORT_ADDR1) = address >> 8;
|
|
error = kThreadError_None;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
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;
|
|
HWREG(RFCORE_XREG_FRMCTRL1) |= RFCORE_XREG_FRMCTRL1_PENDING_OR;
|
|
|
|
// disable source address matching
|
|
HWREG(RFCORE_XREG_SRCMATCH) = 0;
|
|
}
|
|
|
|
ThreadError otPlatRadioEnable(otInstance *aInstance)
|
|
{
|
|
ThreadError error = kThreadError_Busy;
|
|
(void)aInstance;
|
|
|
|
if (sState == kStateSleep || sState == kStateDisabled)
|
|
{
|
|
error = kThreadError_None;
|
|
sState = kStateSleep;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
ThreadError otPlatRadioDisable(otInstance *aInstance)
|
|
{
|
|
ThreadError error = kThreadError_Busy;
|
|
(void)aInstance;
|
|
|
|
if (sState == kStateDisabled || sState == kStateSleep)
|
|
{
|
|
error = kThreadError_None;
|
|
sState = kStateDisabled;
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
bool otPlatRadioIsEnabled(otInstance *aInstance)
|
|
{
|
|
(void)aInstance;
|
|
return (sState != kStateDisabled) ? true : false;
|
|
}
|
|
|
|
ThreadError otPlatRadioSleep(otInstance *aInstance)
|
|
{
|
|
ThreadError error = kThreadError_Busy;
|
|
(void)aInstance;
|
|
|
|
if (sState == kStateSleep || sState == kStateReceive)
|
|
{
|
|
error = kThreadError_None;
|
|
sState = kStateSleep;
|
|
disableReceiver();
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
ThreadError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
|
|
{
|
|
ThreadError error = kThreadError_Busy;
|
|
(void)aInstance;
|
|
|
|
if (sState != kStateDisabled)
|
|
{
|
|
error = kThreadError_None;
|
|
sState = kStateReceive;
|
|
setChannel(aChannel);
|
|
sReceiveFrame.mChannel = aChannel;
|
|
enableReceiver();
|
|
}
|
|
|
|
return error;
|
|
}
|
|
|
|
ThreadError otPlatRadioTransmit(otInstance *aInstance)
|
|
{
|
|
ThreadError error = kThreadError_Busy;
|
|
(void)aInstance;
|
|
|
|
if (sState == kStateReceive)
|
|
{
|
|
int i;
|
|
|
|
error = kThreadError_None;
|
|
sState = kStateTransmit;
|
|
sTransmitError = kThreadError_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) = sTransmitFrame.mLength;
|
|
|
|
// frame data
|
|
for (i = 0; i < sTransmitFrame.mLength; i++)
|
|
{
|
|
HWREG(RFCORE_SFR_RFDATA) = sTransmitFrame.mPsdu[i];
|
|
}
|
|
|
|
setChannel(sTransmitFrame.mChannel);
|
|
|
|
while ((HWREG(RFCORE_XREG_FSMSTAT1) & 1) == 0);
|
|
|
|
// wait for valid rssi
|
|
while ((HWREG(RFCORE_XREG_RSSISTAT) & RFCORE_XREG_RSSISTAT_RSSI_VALID) == 0);
|
|
|
|
VerifyOrExit(HWREG(RFCORE_XREG_FSMSTAT1) & (RFCORE_XREG_FSMSTAT1_CCA | RFCORE_XREG_FSMSTAT1_SFD),
|
|
sTransmitError = kThreadError_ChannelAccessFailure);
|
|
|
|
// begin transmit
|
|
HWREG(RFCORE_SFR_RFST) = RFCORE_SFR_RFST_INSTR_TXON;
|
|
|
|
while (HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_TX_ACTIVE);
|
|
}
|
|
|
|
exit:
|
|
return error;
|
|
}
|
|
|
|
RadioPacket *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
|
|
{
|
|
(void)aInstance;
|
|
return &sTransmitFrame;
|
|
}
|
|
|
|
int8_t otPlatRadioGetRssi(otInstance *aInstance)
|
|
{
|
|
(void)aInstance;
|
|
return 0;
|
|
}
|
|
|
|
otRadioCaps otPlatRadioGetCaps(otInstance *aInstance)
|
|
{
|
|
(void)aInstance;
|
|
return kRadioCapsNone;
|
|
}
|
|
|
|
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;
|
|
|
|
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;
|
|
|
|
VerifyOrExit(sState == kStateReceive || sState == kStateTransmit, ;);
|
|
VerifyOrExit((HWREG(RFCORE_XREG_FSMSTAT1) & RFCORE_XREG_FSMSTAT1_FIFOP) != 0, ;);
|
|
|
|
// read length
|
|
length = HWREG(RFCORE_SFR_RFDATA);
|
|
VerifyOrExit(IEEE802154_MIN_LENGTH <= length && length <= IEEE802154_MAX_LENGTH, ;);
|
|
|
|
// 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;
|
|
}
|
|
|
|
// 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 == kStateReceive) && (sReceiveFrame.mLength > 0))
|
|
{
|
|
#if OPENTHREAD_ENABLE_DIAG
|
|
|
|
if (otPlatDiagModeGet())
|
|
{
|
|
otPlatDiagRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
otPlatRadioReceiveDone(aInstance, &sReceiveFrame, sReceiveError);
|
|
}
|
|
}
|
|
|
|
if (sState == kStateTransmit)
|
|
{
|
|
if (sTransmitError != kThreadError_None || (sTransmitFrame.mPsdu[0] & IEEE802154_ACK_REQUEST) == 0)
|
|
{
|
|
sState = kStateReceive;
|
|
|
|
#if OPENTHREAD_ENABLE_DIAG
|
|
|
|
if (otPlatDiagModeGet())
|
|
{
|
|
otPlatDiagRadioTransmitDone(aInstance, false, sTransmitError);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
otPlatRadioTransmitDone(aInstance, false, 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 = kStateReceive;
|
|
|
|
#if OPENTHREAD_ENABLE_DIAG
|
|
|
|
if (otPlatDiagModeGet())
|
|
{
|
|
otPlatDiagRadioTransmitDone(aInstance, (sReceiveFrame.mPsdu[0] & IEEE802154_FRAME_PENDING) != 0, sTransmitError);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
otPlatRadioTransmitDone(aInstance, (sReceiveFrame.mPsdu[0] & IEEE802154_FRAME_PENDING) != 0, sTransmitError);
|
|
}
|
|
}
|
|
}
|
|
|
|
sReceiveFrame.mLength = 0;
|
|
}
|
|
|
|
void RFCoreRxTxIntHandler(void)
|
|
{
|
|
HWREG(RFCORE_SFR_RFIRQF0) = 0;
|
|
}
|
|
|
|
void RFCoreErrIntHandler(void)
|
|
{
|
|
HWREG(RFCORE_SFR_RFERRF) = 0;
|
|
}
|