TIMAC是TI公司推出的基于IEEE 802.15.4的通讯协议栈,编译环境为IAR,使用IAR自带的CLIB库,CLIB库提供了轻量级的C库,它不支持嵌入式C++。适用于RF4CE协议和ZigBee-Pro产品。
目前学习的MAC层协议版本为1.5.0.
为什么要学习TIMAC呢?在开发基于ZigBee的项目中,遇到了一些底层上的问题,再深入时,发现卡在底层封装的库中去,TIMAC比ZStack的底层开放程度更高,为了更好的理解无线传输的一些细节问题,才会去看TIMAC协议。
特点
1. 多平台支持,CC2538,2530,2531无线MCUs,CC2520收发器,
2. 支持星型拓扑,点对点,一点对多点
3. 支持同步信标和异步非信标模式。目前的ZStack是不支持同步信标网络的。
4. 支持网络安全,无版权和license费用
应用领域
1. 无线点对点和点对多点传输环境
2. 电池供电设备,需要支持ACK和重传的环境,低速率无线传输要求(<100Kbps)
学习步骤
1. 先从TIMAC自带的文档看起,先大体的浏览一次,以后遇到相关的函数,能够记得在哪里去找就可以了。
802.14.4 MAC API.pdf 整个分三部分
1.1 文档目的,参考引用和相关的缩写
1.2 API总览,分为内部接口机制、数据接口和管理接口等、常用常量和结构体
1.3 下面按照功能来介绍相关接口,初始化接口、数据接口、管理接口、扩展接口、回调接口和一些常见的使用场景。每部分接口按照介绍、通用常量和结构体、函数接口详细介绍来描述,条理分明,层次清楚,参考价值非常高。
2. 看TIMAC 提供的例程
目录位于 D:Texas InstrumentsTIMAC 1.5.0ProjectsmacSamplecc2530IAR Project,工程名称为msa_cc2530.eww.此工程有四项配置,如下图所示:
TIMAC的CC2350例程提供了两种不同大小程序配置,分为bank(最大可用256K FLASH)和non-banked(最大可用 64K FLASH).提供了安全和正常两种数据传输方式,为Normal和Secure.程序默认选择配置:Normal,含义是正常传输,non-banked配置,总共有4种不同的配置选项,含义以此类推。
IEEE 802.15.4 规范在2.4G 频率范围内,定义了16个信道,编号从11到26.
下面开始,逐步分析实例程序的整体结构。
从任务数组(见下图)来看,整个系统只有三个任务在跑,一个是mac层,一个应用层msa,一个硬件抽象层hal。
mac层的事件处理肯定是被封掉了啦,封在哪里呢?代码里面肯定是找不到的,搜一下lib文件,发现如下几个可疑文件。
很明显,从名字上来看,mac层的相关操作函数封在这里了,四种库,对上上图工程配置里面的四种情况,对应上了。从大小和编译生成的时间上来看,安全传输要求的MAC库比普通传输的MAC要大,Banked模式要比Non-Banked的库要大,原因很明显,就不用解释啦。具体在IAR的哪里把库文件的路径引用进入的呢?从Option for node—>Linker—>Extra Options里面,应该是要包含引用库所在的路径的,但是默认配置里面没有包含,是少些了吗?还是在其他什么地方包含了?这一点还没想明白。
还是回到程序本身,TIMAC里面的例程,提供了基本的协议和函数接口,用于测试和验证IEEE 802.15.4 MAC层的相关操作。能够演示设备角色的建立、加入/建立网络、连接和断开连接、收发数据和信标支持。
示例程序由4部分组成,main,初始化,系统事件处理和回调函数处理。
当编译出现下图的错误时,需要修改IAR使用的虚拟寄存器数量,将原数值改为8,就可以编译通过了。
下图给出了四种不同工程配置的宏配置区别,便于以后在代码中对照。
工程配置 | normal | secure | normal-banked | normal-secure |
默认宏配置 | CC2530EB | CC2530EB HAL_FLASH=FALSE NON_BANKED FEATURE_ENHANCED_BEACON | CC2530EB
| CC2530EB
|
在MSA的事件处理函数中,通过macCbackEvent_t类型的指针来统一处理接收到的各种不同的数据包。这是怎么做到的呢?原来,macCbackEvent_t是一个枚举类型的变量指针,其原型定义如下:
typedef union { macEventHdr_t hdr; macMlmeAssociateInd_t associateInd; /* MAC_MLME_ASSOCIATE_IND */ macMlmeAssociateCnf_t associateCnf; /* MAC_MLME_ASSOCIATE_CNF */ macMlmeDisassociateInd_t disassociateInd; /* MAC_MLME_DISASSOCIATE_IND */ macMlmeDisassociateCnf_t disassociateCnf; /* MAC_MLME_DISASSOCIATE_CNF */ macMlmeBeaconNotifyInd_t beaconNotifyInd; /* MAC_MLME_BEACON_NOTIFY_IND */ macMlmeOrphanInd_t orphanInd; /* MAC_MLME_ORPHAN_IND */ macMlmeScanCnf_t scanCnf; /* MAC_MLME_SCAN_CNF */ macMlmeStartCnf_t startCnf; /* MAC_MLME_START_CNF */ macMlmeSyncLossInd_t syncLossInd; /* MAC_MLME_SYNC_LOSS_IND */ macMlmePollCnf_t pollCnf; /* MAC_MLME_POLL_CNF */ macMlmePollInd_t pollInd; /* MAC_MLME_POLL_IND */ macMlmeCommStatusInd_t commStatusInd; /* MAC_MLME_COMM_STATUS_IND */ macMcpsDataCnf_t dataCnf; /* MAC_MCPS_DATA_CNF */ macMcpsDataInd_t dataInd; /* MAC_MCPS_DATA_IND */ macMcpsPurgeCnf_t purgeCnf; /* MAC_MCPS_PURGE_CNF */ } macCbackEvent_t;
从名字上,应该可以看出什么端倪了吧。对于每一种命令,几乎都有一个IND和CNF。其中,IND应该是指的发出这个命令的事件,而对于的CNF为MAC层完成这个命令后对应用层的确认,简单来理解,IND就是发出去的命令,CNF就是底层完成这个命令后给应用层的确认信息或者底层收到数据时给应用层的信息,(更正了理解,IND和CNF其实都是MAC层根据接收到的命令,而向应用层发送的事件通知,只不过接收命令的来源不同。CNF类型的事件通知是本地MAC接收到本地应用发来的请求,完成时反馈给本地应用层,而IND类型事件通知,是本地MAC接收到外来MAC层发送的请求,处理完后反馈给本地应用层,恩,他们之间就是这个区别,这下应该是没错了,^_^。)以建立连接为例子来说明:
MAC层的SYS_EVENT_MSG回调事件处理共有16个,刚刚好够两个字节的16个位,再多一个状态信息就不行啦。除了SYS_EVENT_MSG之外,还有对于终端设备的轮训请求事件MSA_POLL_EVENT,数据发送事件MSA_SEND_EVENT.
在调用发送数据函数MSA_McpsDataReq,有一个directMsg参数,从名字上,可以大概猜出它的意思,直接发送的信息。根据后面的代码可以得知,当这个参数为真时,协调器直接向终端发送数据,而无需缓存数据等待终端发送poll来请求数据.作为协调器来说,在MAC层空闲时,其接收机要始终保持打开状态,作为终端设备来说,MAC层接收机的设置取决于msa_IsDirectMsg,如果它为真,则需要在MAC层接收机空闲时,保持打开状态。
MAC_CbackEvent函数,是MAC层的回调函数,用于向应用层传递MAC层发生的事件,在这个函数里面,应该要分配OSAL消息空间,拷贝MAC层消息到OSAL的消息结构体来,然后传递给应用层。因为此回调函数可能在任务或者中断上下文中频繁调用,因此需要设计成可重入的。在函数的开头,为了统一不同消息的长度信息,采用一个消息长度数组
在函数的开始,使用
来根据不同的事件类型来分配不同的消息长度,这个做法很好,学习记录下。
从使用说明上来看,对于同一工程来说,程序启动后,它的行为取决于外部的按键,在有任何物理动作之前,只会有对于的闪灯行为。
对于协调器来说,有信标使能和非信标使能两种模式,对于终端设备来说,有直接发送模式和间接发送模式,因此,它们之间两两组合就有4种网络情况。如下表:
注意:当终端设备尝试加入信标网络时,它只能是直接模式。为什么呢?深入想一想,既然是信标模式,那么终端设备就会定时与协调器同步信标,这个动作产生的效果就和poll是一样的了,所以,处于此模式下的终端设备是直接模式。
好了,今天就先学习到这里,明天继续深入各个代码的执行流程去学习TIMAC层的各个设计思路和流程,为以后的开发奠定基础。