在了解了端点和簇的概念后,再进阶尝试基于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 归我了
这个板块被你占屏了 嘿嘿嘿