SERIALAPP_MAX_CLUSTERS, (cId_t *)SerialApp_ClusterList, SERIALAPP_MAX_CLUSTERS, (cId_t *)SerialApp_ClusterList, FALSE );
}
此处发起绑定请求,等待其他节点应答,而如果有一个节点也按了Joystick右键,同样发出了绑定请求,则本节点收到一个End_Device_Bind_rsp的信息,并在
SerialApp_ProcessZDOMsgs函数中进行了处理,如下代码:
/********************************************************************* * @fn SerialApp_ProcessZDOMsgs()
*
* @brief Process response messages
*
* @param none
*
* @return none
*/
static void SerialApp_ProcessZDOMsgs( zdoIncomingMsg_t *inMsg )
{
switch ( inMsg->clusterID )
{
case End_Device_Bind_rsp:
if ( ZDO_ParseBindRsp( inMsg ) == ZSuccess )
{
// Light LED
HalLedSet( HAL_LED_4, HAL_LED_MODE_ON );
}
break;
...
}
}
至此,中国小伙已经成功加美国MM为好友了~
接下来的事,大家想必都知道了。。。
看看他们是怎么发送信息,怎么接收信息的吧?
1. “串口终端1”的数据,如何被“节点1”所接收,并且发送出去的?
串口数据是由哪层来负责的呢?--HAL。。。恩,猜对了。但这个肯定不是靠猜的,其中的过程就不讲了。让我们从主循环(osal_start_system)的Hal_ProcessPoll函数找下去(用source insight的同学可以用ctrl +),Hal_ProcessPoll ==> HalUARTPoll ==>
HalUARTPollDMA
这个HalUARTPollDMA函数里最后有这样一句话:dmaCfg.uartCB(HAL_UART_DMA-1,
evt); 对dmaCfg.uartCB这个函数进行了调用,ctrl / 搜索这个dmaCfg.uartCB,发现SerialApp_Init函数有两句话:
uartConfig.callBackFunc = SerialApp_CallBack;
HalUARTOpen (SERIAL_APP_PORT, &uartConfig);
此处将dmaCfg.uartCB这个函数注册成为SerialApp_CallBack,也就是说
SerialApp_CallBack函数每次循环中被调用一次,对串口的内容进行查询,如果DMA中接收到了数据,则调用HalUARTRead,将DMA数据读至数据buffer并通过AF_DataRequest函数发送出去,注意:送出去的信息的CLUSTERID(信息簇ID)号为
SERIALAPP_CLUSTERID1。
总结一下这个过程:串口数据==>DMA接收==>主循环中通过SerialApp_CallBack查询==>从DMA获取并发送到空中。
2. 节点2在收到空中的信号后,如何传递给与其相连的串口终端?
节点2从空中捕获到信号后,在应用层上首先收到信息的就是SerialApp_ProcessEvent这个函数了,它收到一个AF_INCOMING_MSG_CMD的事件,并通知
SerialApp_ProcessMSGCmd,执行以下代码
switch ( pkt->clusterId )
{
// A message with a serial data block to be transmitted on the serial port.
case SERIALAPP_CLUSTERID1:
... ...
// Transmit the data on the serial port.
if ( HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) ) ) {
// Save for next incoming message
SerialApp_RxSeq = seqnb;
stat = OTA_SUCCESS;
}
... ...
这样就将从空中获取到的信息,传给了串口终端2--美国MM,第一句话终于传到美国了~至于后面的事情嘛,我们就不关注了,看小伙自己的造化了~~~
另外,此例程中还有一种模式,就是这个中国小伙可以按条件搜索(Joystick左键,profileID与clusterID相同者响应),但这种条件找出的MM都比较有个性--只接受你的信息,但不给你发。想想也是,明显没诚意嘛~ 这种模式的细节,本教程不再涉及,有兴趣的读者可自行了解。
声明一点,要真想泡美国MM,只用我们所谈的Zigbee是暂时搞不定的,它最大的传
输距离能有几公里就相当不易了,不过隔壁办公室的MM,倒是可以考虑送她一个~~~
[四]网络结构及协议解析
本例程的重点是串口的应用,其中涉及的组网及绑定等网络层细节,暂不详细阐述,将在后续的“奥特曼Zigbee读书日记”中进行深入分析。
[五]扩展思考
1. DMA方式与ISR方式的UART传输,有什么区别?分别如何实现?
2. ZDO_CB_MSG与AF_INCOMING_MSG_CMD等事件的产生机制?
3. 如何完成“多对一”或者“一对多”的通信?
4. 绑定表的存储位置与生命周期?
由于我们极力倡导“开源Zigbee”,有网友对我们的CC2530开发板项目有所误解,认为我们的开发板是用freakz而不用TI提供的ZStack。实则不然,ZStack是由Zigbee组织认证通过的“Golden unit”Zigbee平台,或者叫Zigbee中的“明星工程”。而且TI公司免费提供了一整套的开发平台及代码。我们没有理由拒绝这么优秀的平台,选择freakz作为补充,只是为了深入到协议层的学习,了解更多的“为什么”。
一个有效的学习过程,应该是由浅入深,由表面到本质。我们将ZStack的学习定位为了解“是什么”和“怎么样”的过程。从上一篇SerialApp的讲解开始,到本篇的GenericApp和后面的SampleApp, TransmitApp与SimpleApp我们都会以了解例程功能,操作与基本原理为主,深入的学习将在“奥特曼Zigbee读书日记”中进行铺开。
[注:本文源自“飞比”Zigbee论坛,为尊重劳动者成果,如需转载请保留此行,并通知作者]
其实这几个例程实现了不同的功能,方便了开发者在此基本功能上进行二次开发,以缩短项目周期,一定程序上减轻了Zigbee开发的复杂度。让我们一起来一一进行分析:
例4、ZStack的“Hello, world!”例程――GenericApp
注:本例程位于C:\Texas Instruments\ZStack-CC2530-2.3.0-1.4.0\Projects\zstack\ Samples\GenericApp\CC2530DB目录下,IAR工程文件为GenericApp.eww
[一]程序功能
本例程在启动后,自动组织建立一个Zigbee网络(我们以一个协调器和终端节点组成的简单网络进行讲解),网络中的设备间通过“绑定”与“按条件搜索”两种方式,建立连接。成功之后互相发送“Hello, world!”字符信息
[二]操作说明
打开上述的工程文件,分别选择“Coordinator”与“Enddevice”两种设备进行编译、下载至两个FB2530EB板中,详细过程前文已有描述,不再重复。按Reset键后,屏幕显示如下:
如果显示信息如上图所示,则表示网络初始化成功。
此时,按下Enddevice的摇杆(Joystick)右键进行绑定申请,然后立即按下Coordinator的Joystick右键进行绑定确认。此时,两个节点的红色LED灯--LED1,同时点亮,表示绑定成功,可以开始通信。
注:绑定也可以由Coordinator发起,由Enddevice响应。
在成功建立连接后,Enddevice与Coordinator均将每5秒钟向对方发送一次“Hello World”字符串。
与前文SerialApp例程相似,建立连接的方式除了“绑定”外,还有“条件搜索”的方式。按Enddevice的摇杆(Joystick)左键发送“条件搜索”请求――即按规定的ProfileID,支持的Cluster等信息进行匹配设备查找,收到此请求后,Coordinator
将会显示如下
此信息表明Coordinator已经接收到搜索请求,并且返回了响应信息。随后,Enddevice