[分享] TI 的ZigBee无线射频程序解析

Jacktang   2020-7-9 09:14 楼主

1.ZigBee是一种近距离、低复杂度、低功耗、低成本的双线无线通信技术,它主要用在距离短、功耗低且传输速率不高的各种电子设备之间的数据传输(包括周期性数据、间歇性数据和低反应时间数据)。
2.ZigBee的基础是IEEE802.15.4,但是IEEE802.15.4仅处理低级的MAC(媒体接入控制协议)层和物理层协议,ZigBee联盟对网络层协议和应用层协议进行了标准化。**
3.IEEE802.15.4射频程序主要分为发送和接收部分,其主要函数的程序流程图为

image.png

1.下载软件安装包
首先从TI官网TI官网上下载sfr05-cc2530软件包。解压后用IAR打开CC2530 BasicRf=F—->ide—->sfr05_cc2530—->iar—->light_switch.eww文件如图所示

image.png

2.定义发送和接收选项
为了实现端点到端点的发送和接收。需要对light_switch工程做如下部分的改动,首先需要定义“发送”和”接收两个不同的工程选项”,这两个选项分别为light和switch,定义过程如下:
点击工程的Project选项,选择下拉菜单中的“Edit Configurations…”

image.png

点击”Edit Configurations…“选项后,弹出”Edit Configurations…“对话框点击New…创建两个配置选项

image.png

添加完成后出现下面的界面

image.png

选择SWITCH选项,右击“light_switch-SWITCH”选择”option“选项,编译“option”选项,编辑”option“选项并添加条件编译选项”SWTH“,如图所示

image.png

3.修改程序将”light_switch.c“修改为如下的形式

/***********************************************************************************
  Filename: light_switch.c

  Description:  This application function either as a light or a
  switch toggling the ligh. The role of the
  application is chosen in the menu with the joystick at initialisation.

  Push S1 to enter the menu. Choose either switch or
  light and confirm choice with S1.
  Joystick Up: Sends data from switch to light

***********************************************************************************/

/***********************************************************************************
* INCLUDES
*/
#include <hal_lcd.h>
#include <hal_led.h>
#include <hal_joystick.h>
#include <hal_assert.h>
#include <hal_board.h>
#include <hal_int.h>
#include "hal_mcu.h"
#include "hal_button.h"
#include "hal_rf.h"
#include "util_lcd.h"
#include "basic_rf.h"


/***********************************************************************************
* CONSTANTS
*/
// Application parameters
#define RF_CHANNEL              20          // 信道设置2.4 GHz RF channel

// BasicRF address definitions
#define PAN_ID                  0x2007      //个域网ID标识符
#define SWITCH_ADDR             0x2520      //按键设备的网络地址
#define LIGHT_ADDR              0x1234      //灯设备的网络地址
#define APP_PAYLOAD_LENGTH      1           //APP负载信息长度
#define LIGHT_TOGGLE_CMD        0           //需要发送的命令

// Application states
#define IDLE                    0
#define SEND_CMD                1

// Application role
#define NONE                    0
#define SWITCH                  1
#define LIGHT                   2
#define APP_MODES               2

/***********************************************************************************
* LOCAL VARIABLES
*/
static uint8 pTxData[APP_PAYLOAD_LENGTH];
static uint8 pRxData[APP_PAYLOAD_LENGTH];
static basicRfCfg_t basicRfConfig;          //MAC数据帧头结构体
#ifdef SECURITY_CCM
// Security key
static uint8 key[]= 
{
    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
};
#endif

/***********************************************************************************
* LOCAL FUNCTIONS
*/
static void appLight();
static void appSwitch();
static void Delay(void);
/***********************************************************************************
* @fn          appLight
*
* @brief       Application code for light application. Puts MCU in endless
*              loop waiting for user input from joystick.
*
* @param       basicRfConfig - file scope variable. Basic RF configuration data
*              pRxData - file scope variable. Pointer to buffer for RX data
*
* @return      none
*/
static void appLight()
{
    basicRfConfig.myAddr = LIGHT_ADDR;      //MAC帧头初始化,设置源地址
    if(basicRfInit(&basicRfConfig)==FAILED) //初始化射频
    {
      HAL_ASSERT(FALSE);
    }
    basicRfReceiveOn();     //打开接收机
    while (TRUE) 
    {
        while(!basicRfPacketIsReady());
        if(basicRfReceive(pRxData, APP_PAYLOAD_LENGTH, NULL)>0)     //如果接收到数据
        {
            if(pRxData[0] == LIGHT_TOGGLE_CMD)  //判断命令是否为开关灯命令
            {
                halLedToggle(1);    //执行LED状态改变
            }
        }
    }
}
/***********************************************************************************
* @fn          appSwitch
*
* @brief       Application code for switch application. Puts MCU in
*              endless loop to wait for commands from from switch
*
* @param       basicRfConfig - file scope variable. Basic RF configuration data
*              pTxData - file scope variable. Pointer to buffer for TX
*              payload
*              appState - file scope variable. Holds application state
*
* @return      none
*/
static void appSwitch()
{
    basicRfConfig.myAddr = SWITCH_ADDR;     //MAC帧头初始化,赋予源地址信息
    if(basicRfInit(&basicRfConfig)==FAILED) //射频初始化
    {
        HAL_ASSERT(FALSE);
    }

    pTxData[0] = LIGHT_TOGGLE_CMD;  //要发送的命令
    basicRfReceiveOff();            //为了节省能源关闭接收
    while (TRUE)
    { 
      if(halButtonPushed()==HAL_BUTTON_1)   //按键按下
        {
            basicRfSendPacket(LIGHT_ADDR, pTxData, APP_PAYLOAD_LENGTH); //发送命令
            halIntOff();    //关中断
            halMcuSetLowPowerMode(HAL_MCU_LPM_3);   //进入低功耗模式,目前没实现
            halIntOn();     //开中断

        }
    }
}
/***********************************************************************************
* @fn          main
*
* @brief       This is the main entry of the "Light Switch" application.
*              After the application modes are chosen the switch can
*              send toggle commands to a light device.
*
* @param       basicRfConfig - file scope variable. Basic RF configuration
*              data
*              appState - file scope variable. Holds application state
*
* @return      none
*/
void main(void)
{
    uint8 appMode = NONE;               //模式定义为空
    /******************RF 配置*****************/
    basicRfConfig.panId = PAN_ID;       //PANID配置
    basicRfConfig.channel = RF_CHANNEL; //信道设置
    basicRfConfig.ackRequest = TRUE;    //确认请求
#ifdef SECURITY_CCM
    basicRfConfig.securityKey = key;    //安全选型设置
#endif

    /*********板级外围设备初始化**************/
    halBoardInit();                     //硬件初始化
    halJoystickInit();                  //控制杆初始化                


    if(halRfInit()==FAILED)             //射频初始化
    {
        HAL_ASSERT(FALSE);
    }
    halLedSet(1);                       //点亮LED1
    utilPrintLogo("Light Switch");      //显示开机画面


    while (halButtonPushed()!=HAL_BUTTON_1);    //等待S1按下  
    halMcuWaitMs(350);
    halLcdClear();                      //清除屏幕
    #ifdef SWTH
     appMode=SWITCH;                    //按键模式
    #endif

    #ifdef LIGH
     appMode=LIGHT;                     //灯模式
    #endif
    if(appMode == SWITCH) 
    {
        appSwitch();                   //发送命令
    }
    else if(appMode == LIGHT) 
    {
        appLight();                     //接收命令
    }
    HAL_ASSERT(FALSE);                  //如果执行错误则执行闪灯命令
}



基于IEEE802.15.4点对点的数据接收和发送,由于数据的接收和发送需要符合IEEE802.15.4规范,因此在发送和接收数据的时候必须符合IEEE802.15.4规范,所以在本工程中比较重要的结构体有两个,这连个结构体分别是
射频初始化结构体basicRfCfg_t。
MAC数据帧帧头结构体basicRfPktHdr_t。
basicRfCfg_t结构体定义为:

typedef struct {
    uint16 myAddr;          //原地址信息:16位短地址
    uint16 panId;           //网络PANID:16位信息
    uint8 channel;          //信道:11-26
    uint8 ackRequest;       //确认请求:1接收却认帧,0不接收
    #ifdef SECURITY_CCM     
    uint8* securityKey;     //安全密钥
    uint8* securityNonce;   //安全密钥
    #endif
} basicRfCfg_t;

basicRfPktHdr_t结构体定义为:

typedef struct 
{
    uint8   packetLength;   // 包的长度
    uint8   fcf0;           // 帧控制域的低字节Frame control field LSB
    uint8   fcf1;           // 帧控制域的高字节Frame control field MSB
    uint8   seqNumber;      // 帧序号
    uint16  panId;          // PANID
    uint16  destAddr;       // 目的地址
    uint16  srcAddr;        // 原地址
    #ifdef SECURITY_CCM 
    uint8   securityControl;// 安全控制域
    uint8  frameCounter[4]; // 安全帧控制域
    #endif
} basicRfPktHdr_t;

4.发送过程简单分析
在主函数中判断发送模式和接收模式,如果为发送模式,将调用appSwitch()函数发送数据,

static void appSwitch()
{  
    basicRfConfig.myAddr = SWITCH_ADDR;     //MAC帧头初始化,赋予源地址信息
    if(basicRfInit(&basicRfConfig)==FAILED) //射频初始化
    {
        HAL_ASSERT(FALSE);
    }

    pTxData[0] = LIGHT_TOGGLE_CMD;          //要发送的命令
    basicRfReceiveOff();                    //为了节省能源关闭接收
    while (TRUE)
    { 
      if(halButtonPushed()==HAL_BUTTON_1)   //按键按下
        {
            basicRfSendPacket(LIGHT_ADDR, pTxData, APP_PAYLOAD_LENGTH); //发送命令
            halIntOff();    //关中断
            halMcuSetLowPowerMode(HAL_MCU_LPM_3);   //进入低功耗模式,目前没实现
            halIntOn();     //开中断

        }
    }
}

在发送函数中调用了一个重要的函数basicRfSendPacket(),由此函数将要发送的数据发送出去,basicRfSendPacket()实现将按照IEEE802.15.4的数据格式将数据发送出去,如果发送成功就将帧序号加1,。

/***********************************************************************************
* @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;

    if(!txState.receiveOn)                              //如果接收器没有打开则打开接收器 
    {
        halRfReceiveOn();
    }
    length = min(length, BASIC_RF_MAX_PAYLOAD_SIZE);    //将要发送的数据帧的长度

    halRfWaitTransceiverReady();                        //等待发送就绪


    halRfDisableRxInterrupt();                          // 关闭接收中断,避免干扰SPI接口

    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);                //将txbuffer写入RFD寄存器
    #endif


    halRfEnableRxInterrupt();                           //打开中断接收终端ACK帧

    if(halRfTransmit() != SUCCESS)                      //发送数据帧的同时检测信道是否空闲,如果不成功则返回FAILD
    {
        status = FAILED;
    }

    if (pConfig->ackRequest)                            //等待接确认帧,如果没有收到却认帧则返回FALSE
    {
        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
        //等待收到却认帧,等待的时间为收到一个ACT帧的持续时间
        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
        //如果接收到却认帧,接收却认帧位置为1 则返回SUCCESS
        status = txState.ackReceived ? SUCCESS : FAILED;

    } 
    else 
    {
        status = SUCCESS;
    }
    if (!txState.receiveOn)                             //关闭接收器 
    {
        halRfReceiveOff();
    }

    if(status == SUCCESS)                               //如果发送成功则发送帧序号加1 
    {
        txState.txSeqNumber++;
    }

#ifdef SECURITY_CCM                                     //安全
    halRfIncNonceTx();          // Increment nonce value
#endif

    return status;                       //返回状态(成功或者失败)

}

在basicRfSendPacket()函数中调用了basicRfBuildMpdu()函数获得发送数据的长度。

/***********************************************************************************
* @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);    //按照MAC数据帧结构添加帧头

    for(n=0;n<payloadLength;n++)
    {
        txMpdu[hdrLength+n] = pPayload[n];                              //将要发送的信息传递给txMpdu
    }
    return hdrLength + payloadLength;                                //返回帧长度
}

在basicRfBuildMpdu()函数中调用basicRfBuildHeader()组织IEEE802.15.4规范的数据帧结构,这里是添加头部信息。

/***********************************************************************************
* 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;

    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;            //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

    // Make sure bytefields are network byte order
    //确保地址信息为IEEE802.15.4所定义的类型
    UINT16_HTON(pHdr->panId);
    UINT16_HTON(pHdr->destAddr);
    UINT16_HTON(pHdr->srcAddr);

    return BASIC_RF_HDR_SIZE;           //返回MAC帧头长度
}

数据的发送和接收是通过halRfWriteTxBuf()和halRfTransmit()函数进行的。

/***********************************************************************************
* @fn      halRfWriteTxBuf
*
* @brief   Write to TX buffer
*
* @param   uint8* pData - buffer to write
*          uint8 length - number of bytes
*
* @return  none
*/
void halRfWriteTxBuf(uint8* pData, uint8 length)
{
    uint8 i;

    ISFLUSHTX();            //清除TXFIFO缓存 

    RFIRQF1 = ~IRQ_TXDONE;  //清除发送中断
    for(i=0;i<length;i++)
    {
        RFD = pData;     //将要发送的数据写入RFD寄存器
    }
}
 

/***********************************************************************************
* @fn      halRfTransmit
*
* @brief   Transmit frame with Clear Channel Assessment.
*
* @param   none
*
* @return  uint8 - SUCCESS or FAILED
*/
uint8 halRfTransmit(void)
{
    uint8 status;

    ISTXON();                       //使能TX发送
    while(!(RFIRQF1 & IRQ_TXDONE) );//等待发送完成(检测到接收到一个完整的帧)

    RFIRQF1 = ~IRQ_TXDONE;          //清除中断标志
    status= SUCCESS;                //发送成功返回SUCCESS
    return status;
}

5.接收过程简单分析
在主函数中判断为接收模式的时候,程序将执行appLight(),该函数对射频初始化,然后按照IEEE802.15.4规定的数据格式进行数据的接收。

/***********************************************************************************
* @fn          appLight
*
* @brief       Application code for light application. Puts MCU in endless
*              loop waiting for user input from joystick.
*
* @param       basicRfConfig - file scope variable. Basic RF configuration data
*              pRxData - file scope variable. Pointer to buffer for RX data
*
* @return      none
*/
static void appLight()
{
    basicRfConfig.myAddr = LIGHT_ADDR;      //MAC帧头初始化,设置源地址
    if(basicRfInit(&basicRfConfig)==FAILED) //初始化射频
    {
      HAL_ASSERT(FALSE);
    }
    basicRfReceiveOn();     //打开接收机
    while (TRUE) 
    {
        while(!basicRfPacketIsReady());
        if(basicRfReceive(pRxData, APP_PAYLOAD_LENGTH, NULL)>0)     //如果接收到数据
        {
            if(pRxData[0] == LIGHT_TOGGLE_CMD)  //判断命令是否为开关灯命令
            {
                halLedToggle(1);    //执行LED状态改变
            }
        }
    }
}

在appLight()中调用basicRfInit()函数实现对数据的接收。具体为什么这样初始化,请参考手册,里面说的很详细了,我就不再论述了。


/***********************************************************************************
* @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();                        //关闭所有中断
    pConfig = pRfConfig;                //按照协议配置结构体
    rxi.pPayload   = NULL;              //负载清空

    txState.receiveOn = TRUE;           //接收状态设置
    txState.frameCounter = 0;           //接收序列号设置
    halRfSetChannel(pConfig->channel);  //设置信道
    halRfSetShortAddr(pConfig->myAddr); //设置原地址
    halRfSetPanId(pConfig->panId);      //设置PANID
    #ifdef SECURITY_CCM
    basicRfSecurityInit(pConfig);       //安全设置
    #endif
    halRfRxInterruptConfig(basicRfRxFrmDoneIsr);    //设置射频中断接收函数
    halIntOn();                         //开总中断
    return SUCCESS;                     //返回成功
}

在appLight()中调用basicRfReceive()函数实现对数据的接收。

/**********************************************************************************
* @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, uint8 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)                                   //判断传入的pRssi指针是否为空
    {
        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);
}

其中接收数据是通过中断的方式进行的,中断接收函数为basicRfRxFrmDoneIsr(),在中断接收函数中个,除了接收数据外,还对接收的数据进行CRC校验。

/***********************************************************************************
* @fn          basicRfRxFrmDoneIsr
*
* @brief       Interrupt service routine for received frame from radio
*              (either data or acknowlegdement)
*               中断接收函数,在中断接收函数中,除了接收数据外,还对接收的数据进行CRC校验
*
* @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
    pHdr= (basicRfPktHdr_t*)rxMpdu;             //配置MAC层帧头(赋予存储地址)
    halRfDisableRxInterrupt();                  //清除接收中断
    halIntOn();                                 //打开所有中断
    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) //如果是却认帧 
    {
        halRfReadRxBuf(&rxMpdu[1], pHdr->packetLength); //读数据
        /****************确保地址信息为IEEE802.15.4所定义的类型***************/
        UINT16_NTOH(pHdr->panId);
        UINT16_NTOH(pHdr->destAddr);
        UINT16_NTOH(pHdr->srcAddr);
        #ifdef SECURITY_CCM
        UINT32_NTOH(pHdr->frameCounter);                //安全
        #endif

        rxi.ackRequest = !!(pHdr->fcf0 & BASIC_RF_FCF_ACK_BM_L);   //是否需要确认请求判断,判断帧控制域的确认请求是否为1
        pStatusWord= rxMpdu + 4;        //取出却认帧的最后一个字节进行CRC校验
        //CRC校验成功且如果检测到前面接受到的数据有相同的帧号则丢弃掉此帧数据
        if ((pStatusWord[1] & BASIC_RF_CRC_OK_BM) && (pHdr->seqNumber == txState.txSeqNumber)) 
        {
            txState.ackReceived = TRUE;
        }
    } 
    else    //如果是数据帧
    {
        rxi.length = pHdr->packetLength - BASIC_RF_PACKET_OVERHEAD_SIZE;        //得到MAC负载数据的真实长度

        #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);         //读MAC数据帧
        #endif

        /**************确保地址信息为IEEE802.15.4所定义的类型*********************/
        UINT16_NTOH(pHdr->panId);
        UINT16_NTOH(pHdr->destAddr);
        UINT16_NTOH(pHdr->srcAddr);
        #ifdef SECURITY_CCM
        UINT32_NTOH(pHdr->frameCounter);
        #endif

        rxi.ackRequest = !!(pHdr->fcf0 & BASIC_RF_FCF_ACK_BM_L);//是否需要确认请求判断,判断帧控制域的确认请求是否为1
        rxi.srcAddr= pHdr->srcAddr;                 //读原地址
        rxi.pPayload = rxMpdu + BASIC_RF_HDR_SIZE;  //读MAC层负载
        pStatusWord= rxi.pPayload+rxi.length;       //读数据帧尾获得CRC和RSSI
        #ifdef SECURITY_CCM     //安全
        pStatusWord+= BASIC_RF_LEN_MIC;
        #endif
        rxi.rssi = pStatusWord[0];                  //帧尾的第一个字节为RSSI
        //CRC校验成功且如果检测到前面接受到的数据有相同的帧号则丢弃掉此帧数据
        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;
    }
    halIntOff();                //使能总中断
    halRfEnableRxInterrupt();   //使能接收中断
}

好了,官方的简单的实现点灯的程序就分析到这里了,哦,对了,大家如果想要一移植到自己的开发板学习的话需要修改几个文件,主要是LED、LCD和是否使用了CC2590,做好这些,大家就可以进行试验了。

 

 

 

 

 

 

 

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复