cc2530-projects/Zigbee无线通信/A板/CC2530_lib/basicrf/basic_rf.c
2021-10-04 22:26:10 +08:00

524 lines
18 KiB
C

//-------------------------------------------------------------------
// Filename: basic_rf.c
// Description: Basic RF library
//-------------------------------------------------------------------
//-------------------------------------------------------------------
// INCLUDES
//-------------------------------------------------------------------
#include "hal_defs.h"
#include "hal_int.h"
#include "hal_mcu.h" // Using halMcuWaitUs()
#include "hal_rf.h"
#include "basic_rf.h"
#ifdef SECURITY_CCM
#include "hal_rf_security.h"
#include "basic_rf_security.h"
#endif
#include <string.h>
//-------------------------------------------------------------------
// CONSTANTS AND DEFINES
//-------------------------------------------------------------------
// Packet and packet part lengths
#define PKT_LEN_MIC 8
#define PKT_LEN_SEC PKT_LEN_UNSEC + PKT_LEN_MIC
#define PKT_LEN_AUTH 8
#define PKT_LEN_ENCR 24
// Packet overhead ((frame control field, sequence number, PAN ID,
// destination and source) + (footer))
// Note that the length byte itself is not included included in the packet length
#define BASIC_RF_PACKET_OVERHEAD_SIZE ((2 + 1 + 2 + 2 + 2) + (2))
#define BASIC_RF_MAX_PAYLOAD_SIZE (127 - BASIC_RF_PACKET_OVERHEAD_SIZE - BASIC_RF_AUX_HDR_LENGTH - BASIC_RF_LEN_MIC)
#define BASIC_RF_ACK_PACKET_SIZE 5
#define BASIC_RF_FOOTER_SIZE 2
#define BASIC_RF_HDR_SIZE 10
// The time it takes for the acknowledgment packet to be received after the
// data packet has been transmitted.
#define BASIC_RF_ACK_DURATION (0.5 * 32 * 2 * ((4 + 1) + (1) + (2 + 1) + (2)))
#define BASIC_RF_SYMBOL_DURATION (32 * 0.5)
// The length byte
#define BASIC_RF_PLD_LEN_MASK 0x7F
// Frame control field
#define BASIC_RF_FCF_NOACK 0x8841
#define BASIC_RF_FCF_ACK 0x8861
#define BASIC_RF_FCF_ACK_BM 0x0020
#define BASIC_RF_FCF_BM (~BASIC_RF_FCF_ACK_BM)
#define BASIC_RF_SEC_ENABLED_FCF_BM 0x0008
// Frame control field LSB
#define BASIC_RF_FCF_NOACK_L LO_UINT16(BASIC_RF_FCF_NOACK)
#define BASIC_RF_FCF_ACK_L LO_UINT16(BASIC_RF_FCF_ACK)
#define BASIC_RF_FCF_ACK_BM_L LO_UINT16(BASIC_RF_FCF_ACK_BM)
#define BASIC_RF_FCF_BM_L LO_UINT16(BASIC_RF_FCF_BM)
#define BASIC_RF_SEC_ENABLED_FCF_BM_L LO_UINT16(BASIC_RF_SEC_ENABLED_FCF_BM)
// Auxiliary Security header
#define BASIC_RF_AUX_HDR_LENGTH 5
#define BASIC_RF_LEN_AUTH BASIC_RF_PACKET_OVERHEAD_SIZE + BASIC_RF_AUX_HDR_LENGTH - BASIC_RF_FOOTER_SIZE
#define BASIC_RF_SECURITY_M 2
#define BASIC_RF_LEN_MIC 8
#ifdef SECURITY_CCM
#undef BASIC_RF_HDR_SIZE
#define BASIC_RF_HDR_SIZE 15
#endif
// Footer
#define BASIC_RF_CRC_OK_BM 0x80
//-------------------------------------------------------------------
// TYPEDEFS
//-------------------------------------------------------------------
// The receive struct
typedef struct
{
uint8 seqNumber;
uint16 srcAddr;
uint16 srcPanId;
int8 length;
uint8 *pPayload;
uint8 ackRequest;
int8 rssi;
volatile uint8 isReady;
uint8 status;
} basicRfRxInfo_t;
// Tx state
typedef struct
{
uint8 txSeqNumber;
volatile uint8 ackReceived;
uint8 receiveOn;
uint32 frameCounter;
} basicRfTxState_t;
// Basic RF packet header (IEEE 802.15.4)
typedef struct
{
uint8 packetLength;
uint8 fcf0; // Frame control field LSB
uint8 fcf1; // Frame control field MSB
uint8 seqNumber;
uint16 panId;
uint16 destAddr;
uint16 srcAddr;
#ifdef SECURITY_CCM
uint8 securityControl;
uint8 frameCounter[4];
#endif
} basicRfPktHdr_t;
//-------------------------------------------------------------------
// LOCAL VARIABLES
//-------------------------------------------------------------------
static basicRfRxInfo_t rxi =
{
0xFF
}; // Make sure sequence numbers are
static basicRfTxState_t txState =
{
0x00
}; // initialised and distinct.
static basicRfCfg_t *pConfig;
static uint8 txMpdu[BASIC_RF_MAX_PAYLOAD_SIZE + BASIC_RF_PACKET_OVERHEAD_SIZE + 1];
static uint8 rxMpdu[128];
//-------------------------------------------------------------------
// LOCAL FUNCTIONS
//-------------------------------------------------------------------
//-------------------------------------------------------------------
// @fn basicRfBuildHeader
// @brief Builds packet header according to IEEE 802.15.4 frame format
// @param buffer - Pointer to buffer to write the header
// destAddr - destination short address
// payloadLength - length of higher layer payload
// @return uint8 - length of header
//-------------------------------------------------------------------
static uint8 basicRfBuildHeader(uint8 *buffer, uint16 destAddr, uint8 payloadLength)
{
basicRfPktHdr_t *pHdr;
uint16 fcf;
pHdr = (basicRfPktHdr_t*)buffer;
// Populate packet header
pHdr->packetLength = payloadLength + BASIC_RF_PACKET_OVERHEAD_SIZE;
//pHdr->frameControlField = pConfig->ackRequest ? BASIC_RF_FCF_ACK : BASIC_RF_FCF_NOACK;
fcf = pConfig->ackRequest ? BASIC_RF_FCF_ACK : BASIC_RF_FCF_NOACK;
pHdr->fcf0 = LO_UINT16(fcf);
pHdr->fcf1 = HI_UINT16(fcf);
pHdr->seqNumber = txState.txSeqNumber;
pHdr->panId = pConfig->panId;
pHdr->destAddr = destAddr;
pHdr->srcAddr = pConfig->myAddr;
#ifdef SECURITY_CCM
// Add security to FCF, length and security header
pHdr->fcf0 |= BASIC_RF_SEC_ENABLED_FCF_BM_L;
pHdr->packetLength += PKT_LEN_MIC;
pHdr->packetLength += BASIC_RF_AUX_HDR_LENGTH;
pHdr->securityControl = SECURITY_CONTROL;
pHdr->frameCounter[0] = LO_UINT16(LO_UINT32(txState.frameCounter));
pHdr->frameCounter[1] = HI_UINT16(LO_UINT32(txState.frameCounter));
pHdr->frameCounter[2] = LO_UINT16(HI_UINT32(txState.frameCounter));
pHdr->frameCounter[3] = HI_UINT16(HI_UINT32(txState.frameCounter));
#endif
return BASIC_RF_HDR_SIZE;
}
//-------------------------------------------------------------------
// @fn basicRfBuildMpdu
// @brief Builds mpdu (MAC header + payload) according to IEEE 802.15.4
// frame format
// @param destAddr - Destination short address
// pPayload - pointer to buffer with payload
// payloadLength - length of payload buffer
// @return uint8 - length of mpdu
//-------------------------------------------------------------------
static uint8 basicRfBuildMpdu(uint16 destAddr, uint8 *pPayload, uint8 payloadLength)
{
uint8 hdrLength, n;
hdrLength = basicRfBuildHeader(txMpdu, destAddr, payloadLength);
for (n = 0; n < payloadLength; n++)
{
txMpdu[hdrLength + n] = pPayload[n];
}
return hdrLength + payloadLength; // total mpdu length
}
//-------------------------------------------------------------------
// @fn basicRfRxFrmDoneIsr
// @brief Interrupt service routine for received frame from radio
// (either data or acknowlegdement)
// @param rxi - file scope variable info extracted from the last incoming
// frame
// txState - file scope variable that keeps tx state info
// @return none
//-------------------------------------------------------------------
static void basicRfRxFrmDoneIsr(void)
{
basicRfPktHdr_t *pHdr;
uint8 *pStatusWord;
#ifdef SECURITY_CCM
uint8 authStatus = 0;
#endif
// Map header to packet buffer
pHdr = (basicRfPktHdr_t*)rxMpdu;
// Clear interrupt and disable new RX frame done interrupt
halRfDisableRxInterrupt();
// Enable all other interrupt sources (enables interrupt nesting)
halIntOn();
// Read payload length.
halRfReadRxBuf(&pHdr->packetLength, 1);
pHdr->packetLength &= BASIC_RF_PLD_LEN_MASK; // Ignore MSB
// Is this an acknowledgment packet?
// Only ack packets may be 5 bytes in total.
if (pHdr->packetLength == BASIC_RF_ACK_PACKET_SIZE)
{
// Read the packet
halRfReadRxBuf(&rxMpdu[1], pHdr->packetLength);
rxi.ackRequest = !!(pHdr->fcf0 &BASIC_RF_FCF_ACK_BM_L);
// Read the status word and check for CRC OK
pStatusWord = rxMpdu + 4;
// Indicate the successful ACK reception if CRC and sequence number OK
if ((pStatusWord[1] &BASIC_RF_CRC_OK_BM) && (pHdr->seqNumber == txState.txSeqNumber))
{
txState.ackReceived = TRUE;
}
// No, it is data
}
else
{
// It is assumed that the radio rejects packets with invalid length.
// Subtract the number of bytes in the frame overhead to get actual payload.
rxi.length = pHdr->packetLength - BASIC_RF_PACKET_OVERHEAD_SIZE;
#ifdef SECURITY_CCM
rxi.length -= (BASIC_RF_AUX_HDR_LENGTH + BASIC_RF_LEN_MIC);
authStatus = halRfReadRxBufSecure(&rxMpdu[1], pHdr->packetLength, rxi.length, BASIC_RF_LEN_AUTH, BASIC_RF_SECURITY_M);
#else
halRfReadRxBuf(&rxMpdu[1], pHdr->packetLength);
#endif
rxi.ackRequest = !!(pHdr->fcf0 &BASIC_RF_FCF_ACK_BM_L);
// Read the source address
rxi.srcAddr = pHdr->srcAddr;
// Read the packet payload
rxi.pPayload = rxMpdu + BASIC_RF_HDR_SIZE;
// Read the FCS to get the RSSI and CRC
pStatusWord = rxi.pPayload + rxi.length;
#ifdef SECURITY_CCM
pStatusWord += BASIC_RF_LEN_MIC;
#endif
rxi.rssi = pStatusWord[0];
// Notify the application about the received data packet if the CRC is OK
// Throw packet if the previous packet had the same sequence number
if ((pStatusWord[1] &BASIC_RF_CRC_OK_BM) )//&& (rxi.seqNumber != pHdr->seqNumber))
{
// If security is used check also that authentication passed
#ifdef SECURITY_CCM
if (authStatus == SUCCESS)
{
if ((pHdr->fcf0 &BASIC_RF_FCF_BM_L) == (BASIC_RF_FCF_NOACK_L | BASIC_RF_SEC_ENABLED_FCF_BM_L))
{
rxi.isReady = TRUE;
}
}
#else
if (((pHdr->fcf0 &(BASIC_RF_FCF_BM_L)) == BASIC_RF_FCF_NOACK_L))
{
rxi.isReady = TRUE;
}
#endif
}
rxi.seqNumber = pHdr->seqNumber;
}
// Enable RX frame done interrupt again
halIntOff();
halRfEnableRxInterrupt();
}
//-------------------------------------------------------------------
// GLOBAL FUNCTIONS
//-------------------------------------------------------------------
//-------------------------------------------------------------------
// @fn basicRfInit
// @brief Initialise basic RF datastructures. Sets channel, short address and
// PAN id in the chip and configures interrupt on packet reception
// @param pRfConfig - pointer to BASIC_RF_CONFIG struct.
// This struct must be allocated by higher layer
// txState - file scope variable that keeps tx state info
// rxi - file scope variable info extracted from the last incoming frame
// @return none
//-------------------------------------------------------------------
uint8 basicRfInit(basicRfCfg_t *pRfConfig)
{
if (halRfInit() == FAILED)
{
return FAILED;
}
halIntOff();
// Set the protocol configuration
pConfig = pRfConfig;
rxi.pPayload = NULL;
txState.receiveOn = TRUE;
txState.frameCounter = 0;
// Set channel
halRfSetChannel(pConfig->channel);
// Write the short address and the PAN ID to the CC2520 RAM
halRfSetShortAddr(pConfig->myAddr);
halRfSetPanId(pConfig->panId);
// if security is enabled, write key and nonce
#ifdef SECURITY_CCM
basicRfSecurityInit(pConfig);
#endif
// Set up receive interrupt (received data or acknowlegment)
halRfRxInterruptConfig(basicRfRxFrmDoneIsr);
halIntOn();
return SUCCESS;
}
//-------------------------------------------------------------------
// @fn basicRfSendPacket
// @brief Send packet
// @param destAddr - destination short address
// pPayload - pointer to payload buffer. This buffer must be
// allocated by higher layer.
// length - length of payload
// txState - file scope variable that keeps tx state info
// mpdu - file scope variable. Buffer for the frame to send
// @return basicRFStatus_t - SUCCESS or FAILED
//-------------------------------------------------------------------
uint8 basicRfSendPacket(uint16 destAddr, uint8 *pPayload, uint8 length)
{
uint8 mpduLength;
uint8 status;
// Turn on receiver if its not on
if (!txState.receiveOn)
{
halRfReceiveOn();
}
// Check packet length
length = MIN(length, BASIC_RF_MAX_PAYLOAD_SIZE);
// Wait until the transceiver is idle
halRfWaitTransceiverReady();
// Turn off RX frame done interrupt to avoid interference on the SPI interface
halRfDisableRxInterrupt();
mpduLength = basicRfBuildMpdu(destAddr, pPayload, length);
#ifdef SECURITY_CCM
halRfWriteTxBufSecure(txMpdu, mpduLength, length, BASIC_RF_LEN_AUTH, BASIC_RF_SECURITY_M);
txState.frameCounter++; // Increment frame counter field
#else
halRfWriteTxBuf(txMpdu, mpduLength);
#endif
// Turn on RX frame done interrupt for ACK reception
halRfEnableRxInterrupt();
// Send frame with CCA. return FAILED if not successful
if (halRfTransmit() != SUCCESS)
{
status = FAILED;
}
// Wait for the acknowledge to be received, if any
if (pConfig->ackRequest)
{
txState.ackReceived = FALSE;
// We'll enter RX automatically, so just wait until we can be sure that the ack reception should have finished
// The timeout consists of a 12-symbol turnaround time, the ack packet duration, and a small margin
halMcuWaitUs((12 *BASIC_RF_SYMBOL_DURATION) + (BASIC_RF_ACK_DURATION) + (2 *BASIC_RF_SYMBOL_DURATION) + 10);
// If an acknowledgment has been received (by RxFrmDoneIsr), the ackReceived flag should be set
status = txState.ackReceived ? SUCCESS : FAILED;
}
else
{
status = SUCCESS;
}
// Turn off the receiver if it should not continue to be enabled
if (!txState.receiveOn)
{
halRfReceiveOff();
}
if (status == SUCCESS)
{
txState.txSeqNumber++;
}
#ifdef SECURITY_CCM
halRfIncNonceTx(); // Increment nonce value
#endif
return status;
}
//-------------------------------------------------------------------
// @fn basicRfPacketIsReady
// @brief Check if a new packet is ready to be read by next higher layer
// @param none
// @return uint8 - TRUE if a packet is ready to be read by higher layer
//-------------------------------------------------------------------
uint8 basicRfPacketIsReady(void)
{
return rxi.isReady;
}
//-------------------------------------------------------------------
// @fn basicRfReceive
// @brief Copies the payload of the last incoming packet into a buffer
// @param pRxData - pointer to data buffer to fill. This buffer must be
// allocated by higher layer.
// len - Number of bytes to read in to buffer
// rxi - file scope variable holding the information of the last
// incoming packet
// @return uint8 - number of bytes actually copied into buffer
//-------------------------------------------------------------------
uint8 basicRfReceive(uint8 *pRxData, uint16 len, int16 *pRssi)
{
// Accessing shared variables -> this is a critical region
// Critical region start
halIntOff();
memcpy(pRxData, rxi.pPayload, MIN(rxi.length, len));
if (pRssi != NULL)
{
if (rxi.rssi < 128)
{
*pRssi = rxi.rssi - halRfGetRssiOffset();
}
else
{
*pRssi = (rxi.rssi - 256) - halRfGetRssiOffset();
}
}
rxi.isReady = FALSE;
halIntOn();
// Critical region end
return MIN(rxi.length, len);
}
//-------------------------------------------------------------------
// @fn basicRfGetRssi
// @brief Copies the payload of the last incoming packet into a buffer
// @param none
// @return int8 - RSSI value
//-------------------------------------------------------------------
int8 basicRfGetRssi(void)
{
if (rxi.rssi < 128)
{
return rxi.rssi - halRfGetRssiOffset();
}
else
{
return (rxi.rssi - 256) - halRfGetRssiOffset();
}
}
//-------------------------------------------------------------------
// @fn basicRfReceiveOn
// @brief Turns on receiver on radio
// @param txState - file scope variable
// @return none
//-------------------------------------------------------------------
void basicRfReceiveOn(void)
{
txState.receiveOn = TRUE;
halRfReceiveOn();
}
//-------------------------------------------------------------------
// @fn basicRfReceiveOff
// @brief Turns off receiver on radio
// @param txState - file scope variable
// @return none
//-------------------------------------------------------------------
void basicRfReceiveOff(void)
{
txState.receiveOn = FALSE;
halRfReceiveOff();
}