在了解了端点和簇的概念后,再进阶尝试基于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的任务处理函数中进行处理。要自定义一个事件来处理。
这一篇尝试了如何指定对方的端点和簇,如何绑定多个端点到应用层的事件。这是单播通信的进阶技巧。
厉害了 佩服之极~
hhhhh 归我了
这个板块被你占屏了 嘿嘿嘿