Zigbee学习日记(九)(下)进阶单播通信
goJhou 发布于2018-01-11 浏览:1770 回复:3
0
收藏

在了解了端点和簇的概念后,再进阶尝试基于ZStack协议栈的单播通信协议。

1.在ZMain的main函数中,osal_start_system上方处理自定义的硬件初始化代码。

在用用层的.h文件中,新增一个按钮事件,然后在.c文件的事件处理函数中先创建一个按键框架

 

if(events & JhouXerox_MY_EVT)
 {
   if(0==P1_1)
   {//按钮3
     
   }
   
   if(0==P2_0)
   {//按钮4
     
   }
   
   if(0==P0_5)
   {//按钮5
     
   }
   return (events ^ JhouXerox_MY_EVT);
 }

 

之后定义一个11号端点与应用层挂钩
在应用层.c文件的Init函数中,寻找定义EndPoint的语句,将11直接赋进去,不用宏了。

 

然后从ProcessZDOMsgs消息处理函数中将if中的代码复制到按钮3按下事件的if中。为了自定义发送对象,修改一下数据包头内的地址。

 

if(0==P1_1)
   {//按钮3
     JhouXerox_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
           JhouXerox_DstAddr.addr.shortAddr = pRsp->nwkAddr;
           // Take the first endpoint, Can be changed to search through endpoints
           JhouXerox_DstAddr.endPoint = pRsp->epList[0];
   }

 

将DstAddr的shortAddr改成0x0000,指定发送给协调器

目标端点改成7。意味着我将指定发送给协调器的7号端点。

随后加入发送函数,修改簇号和发送长度

之后模拟按钮4发给7号端点的簇2 按钮5发给8号端点的簇1

最后得到如下代码

if(events & JhouXerox_MY_EVT)
  {
    if(0==P1_1)
    {//按钮3
      char theMessageData[] = {3};
      JhouXerox_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
      JhouXerox_DstAddr.addr.shortAddr = 0x0000;//pRsp->nwkAddr;
      // Take the first endpoint, Can be changed to search through endpoints
      JhouXerox_DstAddr.endPoint = 7;//pRsp->epList[0];
      
      AF_DataRequest(&JhouXerox_DstAddr,
                     &JhouXerox_epDesc,
                     0x0001,//JhouXerox_CLUSTERID,
                     1,//(byte)osal_strlen( theMessageData ) + 1,
                     (byte *)&theMessageData,
                     &JhouXerox_TransID,
                     AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
    }
    
    if(0==P2_0)
    {//按钮4
      char theMessageData[] = {4};
      JhouXerox_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
      JhouXerox_DstAddr.addr.shortAddr = 0x0000;//pRsp->nwkAddr;
      // Take the first endpoint, Can be changed to search through endpoints
      JhouXerox_DstAddr.endPoint = 7;//pRsp->epList[0];
      
      AF_DataRequest(&JhouXerox_DstAddr,
                     &JhouXerox_epDesc,
                     0x0002,//JhouXerox_CLUSTERID,
                     1,//(byte)osal_strlen( theMessageData ) + 1,
                     (byte *)&theMessageData,
                     &JhouXerox_TransID,
                     AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
    }
    
    if(0==P0_5)
    {//按钮5
      char theMessageData[] = {5};
      JhouXerox_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
      JhouXerox_DstAddr.addr.shortAddr = 0x0000;//pRsp->nwkAddr;
      // Take the first endpoint, Can be changed to search through endpoints
      JhouXerox_DstAddr.endPoint = 8;//pRsp->epList[0];
      
      AF_DataRequest(&JhouXerox_DstAddr,
                     &JhouXerox_epDesc,
                     0x0001,//JhouXerox_CLUSTERID,
                     1,//(byte)osal_strlen( theMessageData ) + 1,
                     (byte *)&theMessageData,
                     &JhouXerox_TransID,
                     AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
    }
    return (events ^ JhouXerox_MY_EVT);
  }

 

到这为止发送模块就完成了,将程序烧进Zigbee板中。

之后修改接收端的代码

 

在应用层的Init中修改。因为EndPoint拟了两个。将注册端点的5句代码拷贝粘帖一下,创建出7、8两个端口。并且将端点描述符重新申明一下(转到epDesc的地方新增个同类型的epDesc1)。

// Fill out the endpoint description.
GenericApp_epDesc.endPoint = 7;//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 );

  // Fill out the endpoint description.
GenericApp_epDesc1.endPoint = 8;//GENERICAPP_ENDPOINT;
GenericApp_epDesc1.task_id = &GenericApp_TaskID;
GenericApp_epDesc1.simpleDesc
          = (SimpleDescriptionFormat_t *)&GenericApp_SimpleDesc;
GenericApp_epDesc1.latencyReq = noLatencyReqs;

// Register the endpoint description with the AF
afRegister( &GenericApp_epDesc1 );

将视角集中在GenericApp_MessageMSGCB 消息接收处理函数中。将原先的代码都备注掉

可以观察一下这个函数传入的参数类型,是个结构体

{
  osal_event_hdr_t hdr;     /* OSAL Message header */
  uint16 groupId;           /* Message's group ID - 0 if not set */
  uint16 clusterId;         /* Message's cluster ID */
  afAddrType_t srcAddr;     /* Source Address, if endpoint is STUBAPS_INTER_PAN_EP,
                               it's an InterPAN message */
  uint16 macDestAddr;       /* MAC header destination short address */
  uint8 endPoint;           /* destination endpoint */
  uint8 wasBroadcast;       /* TRUE if network destination was a broadcast address */
  uint8 LinkQuality;        /* The link quality of the received data frame */
  uint8 correlation;        /* The raw correlation value of the received data frame */
  int8  rssi;               /* The received RF power in units dBm */
  uint8 SecurityUse;        /* deprecated */
  uint32 timestamp;         /* receipt timestamp from MAC */
  afMSGCommandFormat_t cmd; /* Application Data */
}

里头包含有端点endPoint,簇clusterId,数据cmd还有其他数据包会用到的东西

基于我们的程序设计,建立基于端点和簇的大框架

void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
//  switch ( pkt->clusterId )
//  {
//    case GENERICAPP_CLUSTERID:
//      // "the" message
//#if defined( LCD_SUPPORTED )
//      HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
//#elif defined( WIN32 )
//      WPRINTSTR( pkt->cmd.Data );
//#endif
//      break;
//  }
  if( 7 == pkt->endPoint)
  {
    switch(pkt->clusterId)
    {
    case 0x0001:
      
      break;
      
      
    case 0x0002:
      
      break;
      
      
    default:
      break;
    }
  }
  
  if( 8 == pkt->endPoint)
  {
    switch(pkt->clusterId)
    {
      case 0x0001:
        
      break;
      
      
       default:
      break;
    }
  }
}

之后将应用代码填入相应位置即可

 

void GenericApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
//  switch ( pkt->clusterId )
//  {
//    case GENERICAPP_CLUSTERID:
//      // "the" message
//#if defined( LCD_SUPPORTED )
//      HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
//#elif defined( WIN32 )
//      WPRINTSTR( pkt->cmd.Data );
//#endif
//      break;
//  }
  if( 7 == pkt->endPoint)
  {
    switch(pkt->clusterId)
    {
    case 0x0001:
        LS164_BYTE(pkt->cmd.Data[0]);
        
        //LED1
        P1SEL &= 0xFE;//1111 1110 普通IO口
        P1DIR |= 0x01;// 输出
        P1_0 ^=1;//取反
      break;
      
      
    case 0x0002:
        LS164_BYTE(pkt->cmd.Data[0]);
        
        //LED2
        P0SEL &= 0xFD;//1111 1101 普通IO口
        P0DIR |= 0x02;// 输出
        P0_1 ^=1;//取反
      break;
      
      
    }
  }
  
  if( 8 == pkt->endPoint)
  {
    switch(pkt->clusterId)
    {
      case 0x0001:
        LS164_BYTE(pkt->cmd.Data[0]);
        
        //LED3
        P0SEL &= 0xEF;//1110 1111 普通IO口
        P0DIR |= 0x10;// 输出
        P0_4 ^= 1;//取反
      break;
    }
  }
}

 

需要注意的是,在ZMain的初始化中,如果你自定义了相应模块的初始化代码,一定要将Init中相应的初始化if宏给置为False。以免发生冲突。

按键的外部中断一定要通过TimeEx通知到osal的任务处理函数中进行处理。要自定义一个事件来处理。

这一篇尝试了如何指定对方的端点和簇,如何绑定多个端点到应用层的事件。这是单播通信的进阶技巧。

 

 

收藏
点赞
0
个赞
共3条回复 最后由荒墨丶迷失回复于2018-01-12
#4荒墨丶迷失回复于2018-01-12
#3 goJhou回复
hhhhh 归我了

厉害了  佩服之极~

1
#3goJhou回复于2018-01-12
#2 荒墨丶迷失回复
这个板块被你占屏了 嘿嘿嘿

hhhhh 归我了

0
#2荒墨丶迷失回复于2018-01-11

这个板块被你占屏了 嘿嘿嘿

1
TOP
切换版块