TI提供的例子简介

来源:互联网 发布:近年来的交通事故数据 编辑:程序博客网 时间:2024/05/19 09:17

Zigbee好好研究给的例子的功能,到时候直接简单修改就能用而不是从新写

 此文档在是Zigbee软件自带的,翻译了一些东西

Z-Stack Sample Applications.Pdf文档学习

文档是介绍关于SampleApp例子的。下面是一点重点

1.1

1.开发zigbee方法就是利用板子配套的例子在其上就行修改而已这是最快有效的方法

2.例子中的ProfileID是随机设定的要修改成国标才能通用,

3.系统中每一个应用要对应一个endpoint(类似端口)及相应描述结构,端口号也是随机选的,要自行修改

4.例子中只有一个应用但是在实际中同一设备中可能包含多个应用进程。不同的应用进程对应不同的应用方面所以profileID是不同的可以参考国标设定或自行选择但是就不通用了和其他标准

1.2

OSAL系统有源码。自己可以修改但是用于开发时,没有太大的必要自己修改源码而是利用就行。但是源码必须User自己修改的是系统任务初始化(OSAL Taskinitialization)的函数--osalInitTasks();其中需要User自己定义添加应用函数,完成自己想要的功能。

OSAL_GenericApp.c就是用户自己编写的应用功能文件。一般就是用OSAL_XX.c的形式定义名字方便查找。BSP(板级支持包)初始化时调用osalInitTasks();其过程是

Main.c--osal_init_system();--osalInitTasks();--SampleApp_Init(taskID );就会再次定义应用处理函数。有OSAL的运行机理知道,每一个Z-STACk的子系统都是作为OSAL的一个任务task来运行的(把每个逻辑层归为一个task,而每一层不同的操作处理归为不同的event)。User必须把自己应用以osal系统任务的形式给出。这需要一下操作:1.osalInitTask()中添加SampleApp_Init( taskID );项做相关的初始化2、在OSAL_XX.c中寻找tasksArr数组后添加XXXApp_ProcessEvent (自己编写的应用处理函数,应用消息的方式来选择不同应用事件的)(不同的应用都在一块么还是要另写一个??要找一个多应用的例子看看比较一下)

任务优先级是按照在tasksArr出现的顺序依次降低

1.25

应用层的设计:

每次应用对象可以创建一个task或者所有的应用对象服务在一个任务里。如何选择有几个考虑:

1.     一个task包含多个ApplicationObjects

优点:当有一个事件发生时,处理函数被简化;节省建立多个task的堆栈空间;

缺点:当收到AF信息且信息的确认很复杂时,此时分解多工作机制的任务在一个task中负担重;通过请求标志来寻找相应的请求服务的困难度增加

2.     一对一

优点:上述第二个缺点解决了

缺点:堆栈空间浪费;当多个应用使用相同的专用资源的事件发生时,所采取的多个行动之间协调复杂度提高

 

每个OSALtask都有两个必须的处理,(1)初始化函数(2task_event处理函数

1)初始化函数

1.     命名XXX_init

2.     要初始化应用对象的局部变量和该应用对象专用的变量。长时间都运行存在使用的堆栈此时应该分配,这样可以更加高效管理内存(等到使用时就不需要动态分配了)

3.     相应应用对象的初始化,通过AF层相应的注册函数完成注册(afRegister()

4.     硬件和系统提供的服务的注册(RegisterForKeys()等)

2task_event处理函数

1、命名XXX_ProcessEvent,一个任务可以定义15event

在此事件处理函数中通过逐一比较查找的方式,在确定是哪个事件的发生

1.27

事件种类:

SYS_EVENT_MSG:有系统消息发给该task(该逻辑层)

osal_start_system()--osal_run_system()(不停循环)查找tasksEvents其实就是哪个逻辑层上有事情需要处理,取出该层的event后进入此事件的处理函数,event比较看是哪个事件发生,找到 SYS_EVENT_MSG发生选项后,会调用取信息函数,得到该task的信息,查看消息根据类型,后做相应的处理

注意系统消息又分为不同种类,告知应该做什么事情处理如下,

AF_DATA_CONFIRM_CMD:如果有数据请求就通过调用AF_DataRequest()函数会发出无线请求信息,发射的每一个无线信息成功后返回一个结果指示表明发射成功就是它

AF_INCOMING_MSG_CMD 表明有来自AF层的消息

KEY_CHANGE表明有按键按下

ZDO_STATE_CHANGE 表明网络状态改变(由于重启,或拓扑改变等)

ZDO_CB_MSG表明此信息是响应信息,当完成ZDO注册后会给该应用层发出响应信息,ZDO_CB_MSG就标志此信息就是该响应信息

通过switch ( MSGpkt->hdr.event)来选择对应的处理过程。MSGpkt是读取的系统消息结构体。

各个层之间存在哪些信息,或者说信息是怎么流动的?及发送不同信息后为什么做这样的处理,各层消息和相关处理的一一对应

1.3


组网

在一个项目中的设备根据硬件分为全功能设备和受限的设备,全功能一般用作协调器或路由,受限的只能是终端,而协调器路由和终端的区分是从代码的角度区分的,根据不同的编译选项区分,查看代码知道ZCD_NV_CHANLIST处使用zgDefaultChannelList。而此又使用DEFAULT_CHANLIST。协调器会扫描在ZCD_NV_CHANLIST配置参数中设置的所有信道,选择一个能量最低的频道最为建网的频道,如果多余一个低能量网,就选择已存在网络数最少的频道加入     ,确定频道之后协调器使用ZCD_NV_PANID参数决定PAN_ID  ,ZCD_NV_PANID使用zgConfigPANID而此又使用  ZDAPP_CONFIG_PAN_ID,当ZDAPP_CONFIG_PAN_ID为0xffff时根据IEEE地址来产生随机数当做PAN_ID,否则PAN_ID是ZDAPP_CONFIG_PAN_ID要是跟周边环境重复,就自动改变知道产生不同的唯一的为止(注意此时会出现BUG,因为当在编码中设置了路由和终端要加入的频道和PAN_ID后,如果协调器出现设定的PAN_IN不能用的情况就会出现错误了让路由和终端加入到不该加入的网络)

如果是路由或终端话就使用ZCD_NV_CHANLIST配置参数,而此数使用 zgDefaultChannelList 而此数又使用 DEFAULT_CHANLIST决定加入的网络的频道,然后据当ZCD_NV_PANID。。。。ZDAPP_CONFIG_PAN_ID不为0xFFFF时加入该网络,要是0xffff,就??

还是没懂路由或终端是怎么加入一个已经处在多个网络和多个频道的找到想要的协调器的???

1.3.1网络组建启动方式

1、Auto Start---SOFT_START

BSP上电后的初始化后设备会自动的建立或加入网络(设备的类型决定了操作是加入还是建立网络)。

2、手动启动---HOLD_AUTO_START当采取等待一事件发生后才加入或建立网络的策略时就要定义HOLD_AUTO_START且在等待事件发生后的处理函数中调用ZDOInitDevice(),这就开启加入或建立网络了

当一设备(终端路由或协调器)定义了NV_RESTORE and/orNV_INIT.时,由于意外重启或断电后就能再次重建或加入之前的网络(相同的频道和PAN_ID),原因就是该参数设定后,就会把该类信息存放在断电不丢的ROM中。要是没设置相应的参数的话重启后出现什么情况??

设备加入或建立一网络或者自身所处的网络状态改变后后会得到一个网络变化的系统信息为ZDO_STATE_CHANGE

1.4

绑定和发现

TI的例子讲解,当协调器组网完成后设备加入网络,协调器会有一段特殊的时间(还不清楚什么时候开启的)再此时间段内,如果有两个设备同时按下SW2则会在协调器中建立绑定条目,实现两个设备的绑定,而如果按下的是SW4,进行的是两两绑定,以广播的形式发现匹配设备。绑定成功后一灯亮,没有成功的绑定就会灯闪烁不停

1.4.1绑定:

SW2类型的绑定过程中使用ZDApp_SendEndDeviceBindReq()函数。当一个设备按下SW2后调用ZDApp_SendEndDeviceBindReq(),会给reflector(一般由协调器担当)发送绑定请求,此绑定请求的clustersinputoutput)类型,此时必须有另外一个设备也同时按下SW2调用ZDApp_SendEndDeviceBindReq(),发送clustersoutputinput)类型的绑定请求。就是说绑定clusters必须相反互补,这样的按键操作发送绑定请求必须在APS_DEFAULT_MAXBINDING_TIMEmilliseconds时间内完成,而且在简单描述结构中的command_ID 必须相同。此类绑定优缺点:

优点:

1、绑定表存储在network reflectorRAM中,节省了绑定两端设备的空间

2、network reflector必须时刻处在RxOnWhenIdle状态,就是说及时不工作没有任务处理也不能进入省电而是处在允许接受的空闲状态,当绑定一端的设备地址改变时,该设备广播地址改变的信息,network reflector会受到信息并改变绑定条目,而绑定表的另一端的设备哪怕处在睡眠也无所谓,也不会出错

缺点:

1、当发送端设备绑定了多个接受设备时,如果发送端设备只想给一个或者部分接收端绑定设备时,此时就无能无力了,network reflector是根据绑定表采用逐一单点发送给接收方的

2、发送方使用AF_ACK_REQUESTflag.时也不会接受到接收方的相应信息

3、所有信息传递必须经过network reflector,负荷增加,网络带宽降低。

优点/缺点:如果一发送终端绑定六个接受终端,发送方在A区域边缘,接收方在B区域另一边缘,network reflector在两区域的中间线上,则通过绑定的方式运行时,发送方发送一条信息给network reflector,在A区域只有一条信息在传送,之后network reflector发送6条单播信息给接收方,在B区域有六条信息在传送,而如果不用绑定的话AB区域都会有6条信息在传送,比较的绑定减少了网络流量,但是当发送方和接受方在同一区域。但是收发方在临近且在一区域深处时,通过非绑定的单播形式可以降低此大区域的数据流量,因为信息传输只在一个小区域内,要是绑定的话,整个区域内信息要走一遍,造成大片区域网络阻塞。

 

1.4.2发现(Auto Find)Match DescriptorRequest

设备A用于发现网络中相匹配的设备B进行绑定,A是发送发,B是接收方

A设备程序要执行的步骤:

1、 执行ZDO_RegisterForZDOMsg()进行ZDO注册,用来说明此设备要处理收到的ZDO Match DescriptorResponse类型的信息(ZDO层接受无线信息,此函数就是告知ZDO层把收到的消息匹配,注册的信息类型就留下并通过一定方式发送给对应的注册函数,对于没注册和不是本设备的信息都扔掉)

 

2、 调用ZDP_MatchDescReq()(本例是以按下SW4启动此函数),产生一个广播信息,此信息中含有一个output clusters列表,是本设备可以与之绑定的cluster ID 凡是收到此广播信息的设备都会把自己的cluster 与此信息的output clusters列表匹配且设备属性是接受方才行,符合条件的设备会发送一条单播给发广播的设备

 

3、 处理收到的ZDO Match Descriptor Response 类型的信息(ZDO_CB_MSG类型) 提取出发送该响应信息的地址,建立绑定标最为默认的发送信息的地址(查看源码怎么处理ZDO_CB_MSG类型的信息的)

优缺点:

优点:

1、收到的相应信息可以不保存,如果建立了很多绑定地址,可以只是用其中的几个不必同时全部使用

2、当发送方使用AF_ACK_REQUEST标志发送信息时会得到接受方的相应

3、信息可以被投放到最好的路由处,保存网络带宽

 

 

缺点:

1、绑定表建立在终端出,占用RAM甚至可能是ROM用于备份,当断电时地址的恢复

2、发送端要时刻处于RxOnWhenIdle状态不能休眠保存电力,以用来监测接收方可能的地址的变化

 

优缺点:如果一发送终端绑定六个接受终端,发送方在A区域边缘,接收方在B区域另一边缘,则通过此绑定的方式运行时,发送方发送六条信息通过A区域到达并经过B区域后6条单播信息给接收方,增大了整个区域的数据流量,但是当发送方和接受方在同一区域时信息的流通局限在一个小区域,降低大区域的数据流量

 

1.6程序流程

GenericApp_TaskID =task_id;有一个全局变量保存了任务号

系统采用为每个任务建立时钟定时,设置事件标志,自己给自己传送个消息等方式为的是把一个复杂的系统处理过程分治为多个小的模块,可以再小周期内依次轮流处理各个事务,防止在一个事务上花太多的时间

GenericApp_NwkState= DEV_INIT;

设备上电时默认的网络的状态是没有连接或称为DEV_INIT,当电源启动过程中及启动完成后,系统都不会接受到网络默认状态改变的信息,所以网络的状态必须本地初始化,应该是自己调用函数接受无线信息进行相关网络状态初始化。初始化完后系统会得到ZDO_STATE_CHANGE的信息。当系统使用NV_RESTORE选项后就会使系统自动保存网络状态信息到ROM中断电不丢失,当再次断电重启过程中就会使用保存的网络状态进行恢复,在电源开启过程中就得到ZDO_STATE_CHANGE的信息。

GenericApp_DstAddr.addrMode = (afAddrMode_t)AddrNotPresent;

GenericApp_DstAddr.endPoint = 0;

GenericApp_DstAddr.addr.shortAddr = 0;

系统开启后默认的发送信息目的地址的设置如上,采用的是保存的绑定表的地址,要是没有则按上述设置后的结果是信息被丢弃,因为找不到目的地址

GenericApp_epDesc.endPoint = GENERICAPP_ENDPOINT;

GenericApp_epDesc.task_id = &GenericApp_TaskID;

GenericApp_epDesc.simpleDesc =

SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;

GenericApp_epDesc.latencyReq = noLatencyReqs;

// Register the endpoint description with the AF

afRegister(&GenericApp_epDesc );

在AF层注册端点

GenericApp Application Object自己定义的应用对象通过上述进行具体实例化,注册的作用就是建立目的地址查找表,告知AF层对于进入到AF层的信息通过profile和endpoint进行路由找到接收方。当AF层发送OSAL SYS_EVENT_MSG-message(AF_INCOMING_MSG_CMD)给相应的taskID时就需要上述的task的注册

RegisterForKeys( GenericApp_TaskID );

特定的按键注册函数

比较afRegister(&GenericApp_epDesc );和RegisterForKeys(GenericApp_TaskID );

两个注册函数区别

搞懂信息是怎么传到AF层的又怎么通过注册传到task的????

 

 

 

1.6.2事件处理

当应用层的事件发生时就会标记相应的event位,在事务循环过程中查到到后就进入相应的事件处理函数中当有多个事件发生时推荐一个循环查找之处理一个事件,且是时间最紧迫的优先处理,通过先后顺序决定优先级,因为OSAL机制就是为了达到在一小段时间内处理一个小事务而不是大量事件处理一整个过程,当时在处理if ( events & SYS_EVENT_MSG )时也建议将不同的信息处理放在一块分类处理而不是分开处理。

按键事件处理--KEY_CHANGEmessage.

1、系统任务要注册,RegisterForKeys(GenericApp_TaskID );这样按键发生时GenericApp_TaskID就会得到按键相关的消息

2、按键按下后系统会通过轮询或者中断的方式得到此事件的发生

3、HAL OSAL task检测到按键状态的改变,调用相应层-HAL层的处理函数

4、调用的HAL处理函数时就会发送状态改变的消息到之前注册的函数中去

 

case AF_DATA_CONFIRM_CMD:

// The status is of ZStatus_t type [defined in ZComDef.h]

// The message fields are defined in AF.h

//此处是说明该应用系统消息,取出该消息之后,判断消息类型为AF_DATA_CONFIRM_CMD

//之后做如下处理

afDataConfirm = (afDataConfirm_t *)MSGpkt;   //读取得系统信息

sentEP = afDataConfirm->endpoint;              

sentStatus = afDataConfirm->hdr.status;    //解释3

sentTransID = afDataConfirm->transID;      //解释1

 

 

当收发方不同时:

每次调用AF_DataRequest()要是没有AF_ACK_REQUEST看代码知道不会产生AF_DATA_CONFIRM_CMD的事件要处理,只是把信息传送到网络层的数据缓冲区(原来信息空间在此释放了?)但是要是设置了怎会在得到接受方的ACK信息后产生AF_DATA_CONFIRM_CMD的事件

当收发方相同时会看到无论设置与否都会有AF_DATA_CONFIRM_CMD,对于此类信息不会到达网络层的数据缓冲区,估计是挂在到系统消息队列中并进行事件标记了

在哪里释放此信息的空间ne????

如果此函数返回值是success分两种情况,

要是第七个参数没有AF_ACK_REQUEST选项表示只是把信息发到下一层(网络层),网络层会后续处理该信息。而此时没有要是有也只是起到作用是作为MAC层ACK;如果第七个参数包含AF_ACK_REQUEST且返回success表示信息被目的地成功接收,此时AF_DATA_CONFIRM_CMD的事件的作用是作为APS 的ACK,如果地址是绑定形式的则意味着信息发到the network reflector成功。

解释1:sentTransID是一种确认信息的方式。在同一cluster上的不同的endpoint甚至是不同cluster的每个endpoint保存一个单独的Transaction Id,为的是信息确认重传解析和重装信息。当每次成功调用AF_DataRequest()后transaction ID 状态变量被增加,说明transaction ID是个应用指针而不是值。(*transID)++

解释3:当AF_DataRequest()函数第七个参数没有设置AF_ACK_REQUEST则返回成功意味着信息已经被网络层接受,网络层接受后把信息发到MAC层,之后MAC层把信息通过无线发送出去。无线发送的结果状态是用sentStatus标志的,sentStatus成功表示这信息被发送到网络中的下一跳设备上,在代码中sentStatus和AF_DataRequest()的同一值都是APSDE_DataReq()返回值

如果AF_DataRequest()调用时第七个参数设置为AF_ACK_REQUEST,则返回的成功意味着目的地址已经成功接受到此信息,

 


对于非广播消息,有两种基本的消息重试类型:端到端的确认(APS ACK)和单级确认(single hop acknowledgement)(MAC ACK)。MAC ACK默认情况下是一直打开的,通常能够充分保证网络的高可靠性。为了提供附加的可靠性,同时使发送设备能够得到数据包已经被发送到目的地的确认,可以使用APS ACK。

APS acknowledgement在APS层完成,是从目标设备到源设备的一个消息确认系统。源设备将保留这个消息知道目标设备发送一个APS ACK消息表明它已经收到了消息。对于每个发出的消息可以通过调用函数AF_DataRequest()的选项来使能/禁止来禁止这个功能。这个选项区域是一个位映射选项,对于将要发送的消息的选项区域或上(OR)AF_ACK_REQUEST就可以使能APS ACK。消息重试(如果APSACK消息没有收到)的次数和重试之间的时间间隔的配置项在f8wConfig.cfg文件中。APSC_MAX_FRAME_RETRIES是APS层在放弃发送数据之前,没有收到APS ACK确认重新发送消息的次数。APSC_ACK_WAIT_DURATION_POLLED是重新发送之间的时间间隔。

APS ACK数据确认命令在应用层event-loop函数中,通过AF_DATA_CONFIRM_CMD进行处理,原始AF层函数为afDataConfirm(uint8 endPoint, uint8 transID, ZStatus_t status )

 

GenericApp_SendTheMessage()->AF_DataRequest()->

case ZDO_STATE_CHANGE:

GenericApp_NwkState = (devStates_t)(MSGpkt->hdr.status);

if ( (GenericApp_NwkState == DEV_ZB_COORD)

||(GenericApp_NwkState == DEV_ROUTER)

||(GenericApp_NwkState == DEV_END_DEVICE) )

{

// Start sending "the" message in a regular interval.

osal_start_timer( GENERICAPP_SEND_MSG_EVT,

GENERICAPP_SEND_MSG_TIMEOUT );

}

break;

当网络状态改变的时候所有的task都会收到ZDO_STATE_CHANGE.的信息事件

osal_msg_deallocate( (uint8 *)MSGpkt );

收到信息的task要做信息空间释放的工作

可以尝试一次task循环读取多个该任务的系统消息

1.7信息流程

当发送一个auto find ZDO匹配请求是要注意对于受到的相应信息要判断其地址模式必须是afAddr16Bit才行其他类型的都过滤掉,在响应信息中可得到匹配的地址和端口

当收发方不同时,调用AF_DataRequest()函数只是把信息放到了网络层的数据缓冲区至于空间怎么管理的不知道,进入网络层后不会立即进入MAC层并无线发送,而是等到下一个taskLOOP是出现MAC层事件才处理信息从网络层到MAC层及无线发送,当时当MAC原本就有信息时也不会立即处理新信息而是先发送MAC层原有信息后再处理把信息从网络层移到MAC层。AF_DataRequest()的调用失败大多是因为因为网络层没有足够空间接纳新的信息。

信息经过无线发送,路由,到达目的地后要根据信息的内容决定目的端口,后做准备工作告知应该此工作不知道哪个层做的??目的应用对象会通过SYS_EVENT_MSG   信息  AF_INCOMING_MSG_CMD被告知自己有信息到来

case AF_INCOMING_MSG_CMD:

GenericApp_MessageMSGCB( MSGpkt );

break;

当某一task有信息到来后调用该task的信息处理函数GenericApp_MessageMSGCB()

 

 

The GenericAppSample Application 介绍

本例中每5秒发送一个信息,设备一旦加入网路,就会开启一个时钟,此时信息不会发出,直到找到目的地址或建立了绑定

当设备加入到一个网络后ZDO_STATE_CHANGE信息就会在各个task中收到,所以可以再自己的task中的ZDO_STATE_CHANGE项中自己写相应的处理函数。每一此定时器到了之后,处理函数就是设置相应的事件本例是设备发送信息的事件GENERICAPP_SEND_MSG_EVT对应的event位,然后再taskloop中处理该事件就是发送信息

 

The SerialAppSample Application解释

本例介绍的PC与PC通过ZIgbee模块进行通讯,PC与zigbee设备之间用串口联系。

 

为了使用串口一些初始化设置



HAL层通过轮训或者中断方式得到串口上的数据,等到了flowControlThresold或者idleTimeout时间才会读串口数据 这两个时间在HalUARTOpen()设置,调用rxCB()处理该数据

通过HalUARTWrite().发送串口数据

 

 

The TransmitAppSample Application

 

本例是演示无线发送数据的最大吞吐量会显示平均速率和总发送数据量

 

 

The HomeAutomation Profile

 

 


64位的地址 没有在AF_DataRequest()出现或者说没有此种模式(16位组播广播和NOpresant的绑定)

不会出现64位但是能否使用呢,

当想给以设备发送数据是需要16位地址要是不知道但是如果知道对方64位可以通过函数获得16位,但是如何获得的?发送函数时怎样的用的64位?那么此处为什么不能用64位,还费劲找16位干什么,或者不知道对方64位通过广播匹配方式得到16位地址

1 0
原创粉丝点击