BasicRF 简析
更新时间:2023-11-15 02:02:01 阅读量: 教育文库 文档下载
- basicrf简介推荐度:
- 相关推荐
BasicRF 简析(四:appSwitch()简析)
appSwitch()在SI中的函数关系如图1所示,其中basicRfInit()和
basicRfSendPacket()两个函数比较有内容的,本文主要针对这两个函数进行展开。
图1
开始之前先介绍三个比较重要的结构体: basicRfRxInfo_t、basicRfTxState_t和 basicRfPktHdr_t
//接收帧信息 typedef struct {
uint8 seqNumber; //帧序号; uint16 srcAddr; //源地址;
uint16 srcPanId; //源节点的PANID; int8 length; //帧长度;
uint8* pPayload; //该指针指向帧数据即:净载荷数据; uint8 ackRequest; //帧控制域的应答位信息; int8 rssi; //接收信号强度指示;
volatile uint8 isReady; //通过CRC校验,数据接收完成,该标志位进行后续读取操作;
uint8 status; //待定???? } basicRfRxInfo_t;
//发送状态信息 typedef struct {
uint8 txSeqNumber; //帧序号;
volatile uint8 ackReceived; //ACK是否接收完成; uint8 receiveOn; //是否处于接收状态; uint32 frameCounter; //发送帧计数; } basicRfTxState_t;
//BasicRf 帧头(IEEE 802.15.4) 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;
(一) 关于basicRfInit()
/*********************************************************************************** * @fn basicRfInit *
* @brief Initialise basic RF datastructures. Sets channel, short address and
* PAN id in the chip and configures interrupt on packet reception * 初始化BasicRF数据结构,如:通道选择、短地址、PANID及接收中断的配置;
* @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) //Rf初始化,启用Rf的推荐简单配置,可选的PA模块配置,始终返回Success; return FAILED;
halIntOff(); //关闭总中断; // Set the protocol configuration
pConfig = pRfConfig; //指向相关配置信息;
rxi.pPayload = NULL; //清空本节点的接收载荷数据;
txState.receiveOn = TRUE; //halRfInit()中开启接收; txState.frameCounter = 0; //发送帧计数值;
txState.txSeqNumber = 0x88; //自行修改第一个发送帧序号初始值;
// Set channel
halRfSetChannel(pConfig->channel); //将定义的通道号写入相关寄存器;
// Write the short address and the PAN ID to the CC2520 RAM halRfSetShortAddr(pConfig->myAddr); //将定义的本节点地址写入相关寄存器;
//#define SHORT_ADDR0 XREG( 0x6174 )
//#define SHORT_ADDR1 XREG( 0x6175 )
halRfSetPanId(pConfig->panId); //将定义的PANID写入相关寄存器;
//#define PAN_ID0 XREG( 0x6172 )
//#define PAN_ID1 XREG( 0x6173 )
// 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; }
basicRfInit()如上代码所示,该函数仅对RF做简单初始化、通道选择、PANID、本节点地址进行配置,最后为RF接收中断 声明一个函数指针basicRfRxFrmDoneIsr;
/*********************************************************************************** * @fn halRfRxInterruptConfig *
* @brief Configure RX interrupt.
* //配置接收中断,将RX中断 指向 一段可执行程序; * @param none *
* @return none
*/
void halRfRxInterruptConfig(ISR_FUNC_PTR pf) {
uint8 x;
HAL_INT_LOCK(x); //保存EA并将其清零;
pfISR= pf; //将函数指针赋值,而 pfISR将在RX中断时被执行;
HAL_INT_UNLOCK(x); //恢复之前EA的值; }
/************************************************************************************
* @fn rfIsr *
* @brief Interrupt service routine that handles RFPKTDONE interrupt. * //RX中断服务程序; * @param none *
* @return none */
HAL_ISR_FUNCTION( rfIsr, RF_VECTOR )
{ uint8 x;
HAL_INT_LOCK(x);
if( RFIRQF0 & IRQ_RXPKTDONE ) {
if(pfISR){
(*pfISR)(); // Execute the custom ISR
//如果pfISR不为空则将调用 函数指针所指向的函数basicRfRxFrmDoneIsr(); }
S1CON= 0; // Clear general RF interrupt flag
RFIRQF0&= ~IRQ_RXPKTDONE; // Clear RXPKTDONE interrupt }
HAL_INT_UNLOCK(x); }
RF中断采用了宏声明的方式(协议栈中多采用宏来声明中断,而非常规C语言函数),其声明语句如下:
#define HAL_ISR_FUNC_DECLARATION(f,v) _PRAGMA(vector=v) __near_func __interrupt void f(void) //中断函数声明的宏;
#define HAL_ISR_FUNC_PROTOTYPE(f,v) _PRAGMA(vector=v) __near_func __interrupt void f(void) //中断函数原型的宏;
#define HAL_ISR_FUNCTION(f,v) HAL_ISR_FUNC_PROTOTYPE(f,v); HAL_ISR_FUNC_DECLARATION(f,v) //中断函数定义宏,包括
//原型和声明;
其中rfIsr对应于宏中的 f(void),类似于指向其自身HAL_ISR_FUNCTION()。
(二)关于basicRfSendPacket()
/*********************************************************************************** * @fn basicRfSendPacket *
* @brief Send packet *
* @param destAddr - destination short address //目的地址; * pPayload - pointer to payload buffer. This buffer must be
* allocated by higher layer. //需要MAC层以上产生要发送的数据(指针或数组); * 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
//保证设备处于接收状态,其初始值在halRfInit()中开启接收并在basicRfInit()中被赋值为TRUE;
if(!txState.receiveOn) { halRfReceiveOn(); }
// Check packet length
//取最小的有效数据长度,类似与可变长度域,可变长度值是很有用的例如:串口透传的数据长度;
//最大数据载荷为
//#define BASIC_RF_MAX_PAYLOAD_SIZE (127 -
BASIC_RF_PACKET_OVERHEAD_SIZE - BASIC_RF_AUX_HDR_LENGTH - BASIC_RF_LEN_MIC)
//后面两项为安全选项的附加信息,可根据需要自行调整; length = min(length, BASIC_RF_MAX_PAYLOAD_SIZE);
// Wait until the transceiver is idle
//根据SFD和TX_Active 状态位来判定设备是否处于空闲状态; //SFD状态位为0说明设备目前无发送无接收;
halRfWaitTransceiverReady();
// Turn off RX frame done interrupt to avoid interference on the SPI interface
//防止2591冲突??? 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); //使用ISFLUSHTX()清空TXFIFO 并清除IRQ_TXDONE中断溢出标志位,将MPDU一个字节一个字节的写入RFD; #endif
// Turn on RX frame done interrupt for ACK reception
//仅仅是始能接收中断,为发送完成后自动进入接收模式 接收 ACK做准备性工作;
//仅作为发送节点且不启用ACK的话,这部分语句都可以省略去; halRfEnableRxInterrupt();
// Send frame with CCA. return FAILED if not successful
//仅仅进行数据发送并没有进行CCA(比较坑爹的注释,事实是自己也没怎么仔细看- -!);
//若发送前进行CCA,需要ISSAMPLECCA 再进行ISTXONCCA 判断CCA标志位的值进行后续操作;
if(halRfTransmit() != SUCCESS) { status = FAILED; }
// Wait for the acknowledge to be received, if any //如果启用ACK,则在发送完成后进行进行等待580μs
//实际测试中发送7个字节的数据,两个节点先后发送A和B两个数据帧,两个数据帧的间隔大概需要不小于440μs+580μs+330μs (粗略估计^_^)的时间间隔Sniffer才能捕捉到A的应答帧(这些多出的时间 由节点程序准备和结束时间?)可以确定的是接受节点接收先后两个数据帧的时间间隔要大于580μs,时间间隔太短不能正确接收后一个数据帧,可以通过启用CCA解决这个冲突;
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; }
根据以上basicRfSendPacket()基本流程:确保设备处于接收状态→确认数据有效长度→等待设备处于发送空闲状态→构建
LEN+MPDU→LEN+MPDU写入TXFIFO→始能接收中断→执行发送选通命令进行数据发送→如果要求有ACK应答,则延时等待ACK→关闭接收状态; 另外从上述流程中可以看出,将数据写入TXFIFO并不进行数据的发送,需要通过相关的选通命令在启动发送!!
其中basicRfSendPacket()调用basicRfBuildMpdu()对上层(通常为应用层)产生的数据进行封包操作,介绍basicRfBuildMpdu()之前简单介绍下802.15.4数据帧结构。
图2
以数据帧为例:
MAC的上层产生Payload作为 MAC Payload,即:MSDU; MPDU = MHR + MAC Payload + MFR,即:PSDU;
PPDU = SHR + PHR + MPDU ;//PHR+MHR+MAC Payload 需要写入TXFIFO,SHR和MFR(AUTOCRC = 1时)硬件自动完成;
802.15.4数据帧结构简单介绍完毕,更具体的参见802.15.4协议文档,下面恢复正题;
/*********************************************************************************** * @fn basicRfBuildMpdu *
* @brief Builds mpdu (MAC header + payload) according to IEEE 802.15.4
* frame format //根据802.15.4协议的帧结构 构建 MPDU(MAC帧头+净载荷数据,而由于AUTOCRC = 1则FCS不必手动写入TXFIFO,可以忽略但空间长度需要保留);
*
* @param destAddr - Destination short address //目的地址; * pPayload - pointer to buffer with payload //净载荷数据buffer; * payloadLength - length of payload buffer //净载荷数据长度; *
* @return uint8 - length of mpdu //MPDU的长度= MAC Hdr + MAC Payload;
*/
static uint8 basicRfBuildMpdu(uint16 destAddr, uint8* pPayload, uint8 payloadLength)
{
uint8 hdrLength, n;
hdrLength = basicRfBuildHeader(txMpdu, destAddr, payloadLength); //构建lEN+MHR,见下面代码;
//将净载荷数据放置于 MHR 后 组成MPDU; for(n=0;n txMpdu[hdrLength+n] = pPayload[n]; } return hdrLength + payloadLength; // total mpdu length } /*********************************************************************************** * @fn basicRfBuildHeader * * @brief Builds packet header according to IEEE 802.15.4 frame format * //根据802.15.4 协议构建 帧头; * @param buffer - Pointer to buffer to write the header //MPDU的buffer; * 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; //帧头buffer 指向 MPDU buffer; // Populate packet header //将相关信息 存至 帧头buffer; //帧头长度定义为 //#define BASIC_RF_PACKET_OVERHEAD_SIZE ((2 + 1 + 2 + 2 + 2) + (2)) //其对应关系为((FCF+SeqNum+PANID+DestAddr+SrcAddr)+(FCS)) //然后将帧头信息 赋值给帧头 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; 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 //高低位变换;无线电数据传输为先低位后高位,这样做是在为无线传输做准备?? UINT16_HTON(pHdr->panId); UINT16_HTON(pHdr->destAddr); UINT16_HTON(pHdr->srcAddr); return BASIC_RF_HDR_SIZE; } 阅读(441)| 评论(0)
正在阅读:
BasicRF 简析11-15
萨缪尔森《宏观经济学》(第19版)习题详解(含考研真题)(第1702-27
实验5 组合逻辑电路的应用10-08
领导班子民主生活会谈心谈话记录08-01
绩效考核管理推行建议书 doc(HR)04-11
《化学实验基本方法》教案 - 图文04-07
大别山精神04-07
页面提取自-ANSYS FLUENT 14.0 Tutorial Guide-211-11
红外防盗报警器12-13
2020医院护理的下半年工作计划04-28
- exercise2
- 铅锌矿详查地质设计 - 图文
- 厨余垃圾、餐厨垃圾堆肥系统设计方案
- 陈明珠开题报告
- 化工原理精选例题
- 政府形象宣传册营销案例
- 小学一至三年级语文阅读专项练习题
- 2014.民诉 期末考试 复习题
- 巅峰智业 - 做好顶层设计对建设城市的重要意义
- (三起)冀教版三年级英语上册Unit4 Lesson24练习题及答案
- 2017年实心轮胎现状及发展趋势分析(目录)
- 基于GIS的农用地定级技术研究定稿
- 2017-2022年中国医疗保健市场调查与市场前景预测报告(目录) - 图文
- 作业
- OFDM技术仿真(MATLAB代码) - 图文
- Android工程师笔试题及答案
- 生命密码联合密码
- 空间地上权若干法律问题探究
- 江苏学业水平测试《机械基础》模拟试题
- 选课走班实施方案
- 简析
- BasicRF
- 机械制造技术习题
- DEK INFINITY 印刷机简易故障排除 - 图文
- 资金时间价值 - 61127
- 实验13 电动势的测定
- 500吨年产香菇多糖提取综合车间设计
- 基于AutoCAD的多边形间的间隙核查
- 破碎机轴承常用轴承型号
- 2010级华南师范大学物理化学实验练习题目 - 图文
- 在线测试题试题库及解答(第十章)结构动力学
- 张集矿(中央区)东翼瓦斯抽采系统及西三8—13煤采区一通三防管路工程标书 - 图文
- 2010全国高中数学联赛模拟试题(一) 新人教A版
- 事业单位年度考核登记表个人总结教师
- 铁路职业技能鉴定参考丛书技师、公共和道德题库
- 四边形性质探索总结综合习题
- 康奈尔健康问卷
- 人大网校《国际经济法》20177月考试考前练习试题
- 调档函最新调档函格式模板3篇精选推荐
- 组织行为期末复习
- 2012年1季度高级管理人员任免情况通报 - 图文
- 新建住宅小区供配电工程委托建设合同