zoukankan      html  css  js  c++  java
  • zigbee端口的理解

    在一个终端上,可以有多个端点endpoint,这个概念是很重要的。

             一个节点可以有多个端点,0号endpoint是Zigbee device object(ZDO)用的一个端点,255号是用作广播。我们自己可以定义的是1-240这些端点。每个端点对应一个任务taskid。因此,我们每增加一个端点,就要给它配置一个新任务taskid

            举一个列子: 例子一:一个无线节点(radio unit)A上有一个温湿度传感器,有一个空调控制系统;另外一个无线节点B则负责接收A发回的温度数据,并通过一定的算法来控制空调系统。我们不管B如何实现,只研究A如何实现。这种情况的一个很规范的实现方式是:温湿度传感器设置一个endpoint,比如为10号;空调控制系统设置一个endpoint,比如为20号。还要说明的是:还应该为每一个endpoint建立一个任务,这样在注册端点描述符的时候(调用afRegister函数),就会向协议栈底层说明处理这个端点数据的任务是谁。这样:当B想要获取温湿度的时候,他将会发出一个包含A的短地址和10号端点的信息,这个信息到了A,协议栈会将这个消息转给10号端点所对应的task去处理,管理空调的20号端点根本就看不到这个消息;类似地,如果B想要控制空调,他发出的数据包将包含A的短地址和20号端点信息,A收到消息后会发给20号端点的task去处理。(需要注意的是:在网络层面经常会有发给ZDO的消息,这时候信息包的端点号就将是0号)。这种将不同功能分配到不同endpoint上的方法非常有利于任务的划分,是一种很正规的方法。

         例子二、一个无线节点(radio uint)A上有4个LED需要被控制,另外一个无线节点B则有4个开关用来控制这4个LED。这种情形的规范实现方式还是要为每一个LED设置一个endpoint(允许的范围内你任意指定,只要不重复),并为每个endpoint建立一个task。这样处理之后,B可以用同样的命令来控制4个LED,而不是每一个led 用不同的命令,这种情况在public profile实际上是必须这么做的。    上面两个例子可能很多同学认为太麻烦,完全可以变通。变通的想法就是我所有的被控对象都落在一个endpoint上,但是我发的数据包内容不同,接收端这个endpoint通过解析数据包的内容来判断具体该做什么,这种方式实际上完全可以实现,不过需要你自己规定一下数据包的格式,即第几个字节表示什么。。。。。虽然这可以实现要求,但是我很不赞成这样,一方面实际上是增加了你程序设计的复杂度,另一方面完全没有了互联的可能,尤其是当你用ZCL的时候,这种方式就行不通了

    注册一个应用的端点描述符afRegister( endPointDesc_t *epDesc )

    afRegister( endPointDesc_t *epDesc )这个函数用来注册一个新的端点到task,这样当空中有这个端点的数据到来会直接发送到对应的task。

    传入参数:

    typedef struct
    {
      byte endPoint;//端点号
      byte *task_id;  //端点对应的任务号
      SimpleDescriptionFormat_t *simpleDesc;//简单描述符
      afNetworkLatencyReq_t latencyReq;//必须用noLatencyReqs来填充
    } endPointDesc_t;

    afStatus_t afRegister( endPointDesc_t *epDesc )
    {
      epList_t *ep;
      
      // Look for duplicate endpoint
      if ( afFindEndPointDescList( epDesc->endPoint ) ) 
        return ( afStatus_INVALID_PARAMETER );
      //在端点的链表中搜索新的端点描述符,看看能不能搜到。如果能搜到,则返回错误。  

      //如果不能搜到,则说明这个端点在此之前没有被注册,则调用afRegisterExtended( epDesc, NULL )函数注册这个端点。
      ep = afRegisterExtended( epDesc, NULL );


      return ((ep == NULL) ? afStatus_MEM_FAIL : afStatus_SUCCESS);
    }

    //注册端点描述符

    epList_t *afRegisterExtended( endPointDesc_t *epDesc, pDescCB descFn )
    {
      epList_t *ep;
      epList_t *epSearch;


      //注册意味着在端点链表中增加一个新的元素,先通过osal_mem_alloc( sizeof ( epList_t ) )申请需要的内存单元
      ep = osal_mem_alloc( sizeof ( epList_t ) );
      if ( ep ) //如果申请成功
      {
        // Fill in the new list entry
        ep->epDesc = epDesc;


        // Default to allow Match Descriptor.
        ep->flags = eEP_AllowMatch;
        ep->pfnDescCB = descFn;
        ep->nextDesc = NULL;


        // Does a list exist?
        if ( epList == NULL )  //epList为全局epList_t 指针变量,当链表为空时它指向NULL,如果这是创建的第一个链表元素,则 epList = ep
          epList = ep;  // Make this the first entry
        else //如果这不是第一个链表元素,则首先找到链表的首,在首端加入这个新的元素。
        {
          // Look for the end of the list
          epSearch = epList;
          while( epSearch->nextDesc != NULL )
            epSearch = epSearch->nextDesc;


          // Add new entry to end of list
          epSearch->nextDesc = ep;
        }
      }


      return ep;
    }

    typedef struct
    {
      endPointDesc_t *epDesc;
      eEP_Flags flags;
      pDescCB  pfnDescCB;     // Don't use if this function pointer is NULL.
      void *nextDesc;
    } epList_t;

    在实际工作中,afIncomingData( aps_FrameFormat_t *aff, zAddrType_t *SrcAddress, uint16 SrcPanId,NLDE_Signal_t *sig, byte SecurityUse, uint32 timestamp )这个函数从APS层收到数据,在这个函数中判断收到数据对应的端点号在端点链表中能不能找到,如果不能找到则丢掉这包数据,如果能找到则把数据发送的端点对应的task.

    通过  afBuildMSGIncoming( aff, epDesc, SrcAddress, SrcPanId, sig, SecurityUse, timestamp )这个函数建立OSAL的数据包到对应的任务,并且置位对应任务的SYS_EVENT_MSG。

  • 相关阅读:
    数组模拟队列实现
    Vue之模板语法
    初识Vue之helloworld
    二、Lambda表达式
    一、函数式编程
    SpringCloudAlibaba之Nacos
    SpringCloudAlibaba之Sentinel
    spring的随笔2
    spring的小想法1
    关于hibernate的一些看法
  • 原文地址:https://www.cnblogs.com/F-beifeng/p/9745076.html
Copyright © 2011-2022 走看看