查看: 25353|回复: 48

已入门选手进一步学习的重点

[复制链接]
kennan 发表于 2011-9-1 09:05:08 | 显示全部楼层 |阅读模式
我发现最近群里很多人已经可以算是大致入门了,能够在原有例子的基础上进行一些简单工作,实现数据传输。但是我也发现很多人开始把精力投入到钻研协议栈代码细节上面去了,实际上这种学习方式是有问题的。第一:如果从应用的角度看,协议栈的一些实现细节是没有必要钻研的,这就好比是现在的PC机,已经有了Windows系统了,我们在这个系统之上实现自己应用程序的时候其实并不需要对Windows内部实现细节过多地关注,只要能够自由地在Windows下开发应用程序(其实就是调用大量的API函数)就可以了;第二:如果想从协议栈本身入手去做一些深入的工作,Zstack是不适合的,因为它不是完全开源,真想在路由算法、加密算法等方面做工作的话,目前TinyOS这样的开源协议栈才是首选。所以,进一步学习的重点应该是:在什么时间什么地点调用什么函数的问题!
      那么如何来提高这方面的技能呢?
    1、浏览ZDP和ZDO相关代码,熟悉一下都有什么函数,这两个部分都做了什么,学习的过程中千万不要去钻研代码实现的细节,只要了解其流程以及都作了什么就可以了,否则你一定会迷失在那成千上万行的代码之中而不能自拔。ZDP和ZDO的实现文件里面有大量的函数在以后具体应用中可以去调用。
    2、典型例子中的ZDO消息使用其实只有那么几个例子,比如:ZDO_RegisterForZDOMsg(TaskID,End_Device_Bind_rsp)这样的,这是讲底层的一些事件消息引入到应用层的注册方法。在深入应用的时候那么几个典型的消息注册是不够用的,比如我在一个应用中就注册了以下:
ZDO_RegisterForZDOMsg( TaskID, End_Device_Bind_rsp ); // 我自己解析End_Device_Bind_rsp
  ZDO_RegisterForZDOMsg( TaskID, Match_Desc_rsp );         //我自己解析Match_Desc_rsp
  ZDO_RegisterForZDOMsg( TaskID, Device_annce);              //我自己解析Device_annce
  ZDO_RegisterForZDOMsg( TaskID, Active_EP_rsp);              //我自己解析Active_EP_rsp
  ZDO_RegisterForZDOMsg( TaskID, Simple_Desc_rsp);         //我自己解析Simple_Desc_rsp
  ZDO_RegisterForZDOMsg( TaskID, NWK_addr_rsp);            //我自己解析NWK_addr_rsp
在具体应用中,你会根据不同的网络需求去调用很多协议栈的设置好的req和处理rsp消息,那么协议栈都有那些req和rsp是你进一步学习所应该深入认识的。
    3、在自己使用系统的req和rsp的时候,如果你不知道该如何处理,你最好去看看MT是如何实现的,在MT功能模块中,对协议栈的绝大多数req和rsp都有调用和实现的例子可以参考,虽然我们在自己的应用中很少回去使用MT,但是Mt 的实现代码却是最好的参考资料。
    上面几点是我目前能够想到的一些事情,以后有想法再补充吧!

最后我举个例子:比如你想实现节点入网后自动报告自己的长短地址,然后主控节点处理节点的报告,并且向这个节点要求其发回存在于其上的EP信息,我们应该这样做:
1、在新节点的ZDO_STATE_CHANGE消息处理函数中调用:
ZDP_DeviceAnnce( NLME_GetShortAddr(), NLME_GetExtAddr(),  \
                     ZDO_Config_Node_Descriptor.CapabilityFlags, 0 );
这个函数会自动以广播方式报告自己的短地址和长地址,其余在网的节点都可以收到;你也可以采用按键策略,新节点入网后通过按键触发来报告自己的长短地址:
2、在主控节点的初始化函数中添加:
ZDO_RegisterForZDOMsg( TaskID, Device_annce);              //我自己解析Device_annce
这样,当新入网节点Annce的时候,主控节点收到这个消息,然后通知给你的任务(TaskID),你的任务则需要在case ZDO_CB_MSG:处理函数中添加处理这个annce的代码,如:
     case Device_annce:  //device annouce process.
        ProcessDeviceAnnce(inMsg);
     break;
在自己实现的ProcessDeviceAnnce函数中,你可以提取出新来节点的长短地址。。。。。
3、有了新节点的长短地址,其实什么都可以做了,我现在利用新节点的长短地址来请求其返回它的EP信息:
在适当的地方调用ZDP_ActiveEPReq( &zDestAddr, shortAddr, SECURITY_FLAG);
       这是一个直接面向目标短地址的单播req,目标节点收到这个req之后,会自动处理的(代码协议栈已经实现了),Zstack协议栈实际上实现了绝大多数响应req的函数,然后返回一个rsp,这一部分其实你不用管,也就是说目标节点方面你一行代码都不用写,存在其上的所有EP信息就会被返回到主控节点;但是Zstack没有实现绝大多数rsp处理函数,因为rsp一般来将用户会有不同的想法,所以他也没办法实现;
4、主控节点如果想处理返回的活动EP信息(比如EP号),那么需要在任务初始化的时候注册一下由任务处理这个返回消息:
ZDO_RegisterForZDOMsg( TaskID, Active_EP_rsp);
然后在ZDO_CB_MSG处理函数中添加自己的处理代码:
     case Active_EP_rsp://active ep response process.
        ProcessActiveEpRsp(inMsg);
    break;
自己编写的ProcessActiveEpRsp函数就可以提取到目标节点上所有EP信息,比如我自己实现的一段代码就是这样的(注释解释):
static void ProcessActiveEpRsp(zdoIncomingMsg_t *inMsg)
{
   
uint8 *pData;
uint8 i;
ZDO_ActiveEndpointRsp_t *pRsp = ZDO_ParseEPListRsp( inMsg );     //调用ZDO_ParseEPListRsp函数(这个函数协议栈已经实现了,什么时间什么地点调
                                                                         //用什么函数问题的具体体现,即:在rsp处理的时候调用这个函数,不知道你理解没?
//下面我处理经过Parse后的消息:                                                                        
uint8 cnt = pRsp->cnt;                                                     
pData = (uint8 *)osal_mem_alloc(6 + cnt);
                         //here, 3 is one for status, two for short address.one is cnt
      if(pData)
      {
        
        pData[0] = LO_UINT16(pRsp->nwkAddr);
        pData[1] = HI_UINT16(pRsp->nwkAddr);
        pData[2] = pRsp->status;
        pData[3] = pData[0];
        pData[4] = pData[1];
        pData[5] = cnt;
        for(i=0;i < cnt;i++)
          pData[6 + i] = pRsp->epList;
        osal_mem_free(pRsp);      
        Uart_SendBack(pData,(6 + cnt));  //串口方式把获得的信息发给PC,你可以存起来,也可以进一步做别的;
        osal_mem_free(pData);
      }  
      HalLedSet(HAL_LED_GREEN,HAL_LED_MODE_FLASH); //用闪灯方式表示收到了消息。。。
}
                 
//函数里面这段代码我实现的依据是什么?这你就的去找找看协议栈是如何处理这个req的了,看看ZDP_ActiveEPReq函数的协议栈实现,
//#define ZDP_ActiveEPReq( dstAddr, NWKAddrOfInterest, SecurityEnable ) \
//                          ZDP_NWKAddrOfInterestReq(  dstAddr, \
//                            NWKAddrOfInterest, Active_EP_req, SecurityEnable )

//看到这里就够了,我们知道这个函数调用会发一个Active_EP_req给目标节点,至于怎么发出去的,没必要研究了。
//再去查查看协议栈是如何处理Active_EP_req的,找到了:
//{ Active_EP_req,          ZDO_ProcessActiveEPReq },        
//这个函数的具体实现(协议栈中的)
/*
void ZDO_ProcessActiveEPReq( zdoIncomingMsg_t *inMsg )
{
  byte cnt = 0;
  uint16 aoi;
  byte stat = ZDP_SUCCESS;

  aoi = BUILD_UINT16( inMsg->asdu[0], inMsg->asdu[1] );

  if ( aoi == NLME_GetShortAddr() )
  {
    cnt = afNumEndPoints() - 1;  // -1 for ZDO endpoint descriptor
    afEndPoints( (uint8 *)ZDOBuildBuf, true );
  }
  else
  {
    stat = ZDP_INVALID_REQTYPE;
  }

  ZDP_ActiveEPRsp( inMsg->TransSeq, &(inMsg->srcAddr), stat,
                  aoi, cnt, (uint8 *)ZDOBuildBuf, inMsg->SecurityUse );

*/
//这个你要看懂了,实际上就是向你报告有几个活动EP,每个EP的号是多少。。。。

例子大致说完了,如果不知道我在说什么,也不知道我说的这些函数怎么找的同学,那还得去好好入门入门,这篇文档不适合你!
如果能大致领会意思,我想你就体会到了我们的学习重点在哪里,再说一遍:在什么时间、什么地点调用什么函数!而不是研究协议栈到底怎么实现的。
outman 发表于 2011-9-1 09:54:11 | 显示全部楼层
毛毛新作,再来坐沙发
支持毛毛老师的说法,先不要急着一头扑进协议栈实现细节,否则只能“只见树木,不见森林”,要先从全局来掌握,先看看应用层在怎么用,这个很重要,哪怕对想研究协议层的来讲,也是一样。
orange 发表于 2011-9-1 11:25:34 | 显示全部楼层
又有新动作了,顶一个先
F117C 发表于 2011-9-2 09:02:25 | 显示全部楼层
楼主说的是有道理的,呵呵,Freaklabs开源的也很好
toddhan 发表于 2011-9-2 22:17:19 | 显示全部楼层
在什么时间,什么地点,调用什么函数!!!
不要研究协议栈的具体实现细节!——经典
神经火光 发表于 2011-9-11 19:50:40 | 显示全部楼层
毛毛老师,给力啊,学习了!
wuxiujiang 发表于 2011-9-12 10:20:41 | 显示全部楼层
好久没有来了,回来叙旧哈!!!
NangelQ 发表于 2011-9-15 16:04:17 | 显示全部楼层
谢谢提点,所谓及时雨啊
不知道楼主对ZCL的学习有什么看法?
 楼主| kennan 发表于 2011-9-16 09:43:49 | 显示全部楼层
ZCL?先去看ZCL规范文档,然后去看HA规范,然后去看homeautomation例子是如何使用ZCL的。
814812332 发表于 2011-9-19 10:57:21 | 显示全部楼层
“你最好去看看MT是如何实现的”, ,请问柯南这个具体得去看哪个文档呀?
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表