Endpoint
1、他是一个字节编号的,数据收和发送的基本单元,在模块通信的时候,发送模块必须指定收发双方模块的网络地址和端点。
2、端点要使用必须要和模块里的某个任务挂钩定义;
首先每一个端点可以看成是一个1个字节数字编号的开有一扇门的房间,数据最终的目标是进入到无线数据包指定的目标端点房间,而取无线数据这个相关的代码在任务事件处理函数里,TI协议栈有那么多的任务事件处理函数,所以必须要指定在哪个任务事件处理函数 来取这个无线数据包里面的有用数据。
3、一个端点只能挂钩在一个任务上,而一个任务可以挂钩多个端点,且端点对所有的任务是公用的,定义一个少一个。
一个端点假如可以挂钩在多个任务上,那么接收模块接到无线数据时候,这个时候同一个端点有多个任务事件处理函数去处理,不合理;一个任务上挂多个端点(6 7 挂应用层任务),发送给协调器模块的6 7端点的数据都会进入到应用层任务事件处理函数里来,仅仅做个判断到底是投递到6房间还是7号房间就可以了。
结合代码,定义端点和任务挂钩在基础实验的代码里是那些代码
SimonApp.c
void SimonApp_Init( byte task_id ) //定义了10号端点并且和这个模块的应用层任务挂钩
{
..
// Fill out the endpoint description.
SimonApp_epDesc.endPoint = 10;//SimonApp_ENDPOINT; 此端点编号为10
SimonApp_epDesc.task_id = &SimonApp_TaskID; 和我们应用层任务挂钩
SimonApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SimonApp_SimpleDesc;//更加详细的描述这个端点一些情况就像我们定义一个编号房间,描述房间里大概有多少人之类的信息。
SimonApp_epDesc.latencyReq = noLatencyReqs;//差不多
// Register the endpoint description with the AF
afRegister( &SimonApp_epDesc );//这个函数必须要调用才能完成整个挂钩操作
..
}
端点描述符,代码里一个结构体SimonApp_epDesc
所以,基本实验是0xA406 10 <—–>0x0000 10 无线数据包发出去以后,首先目标协调器模块的网络地址0x0000对上了,协调器可以拿到这个无线数据包。在底层任务,判断10号端点房间已经定义且和应用层任务挂钩,那么这个无线数据包发送一个消息到们应用层任务 。
case AF_INCOMING_MSG_CMD:
SimonApp_MessageMSGCB( MSGpkt );
break;
在消息处理里,把hello Simon 通过串口送出去
Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
端点就相当于一个房间的门牌号!!!
簇 ClusterID
簇就是相当于端点房间里面的人,是接收最终的目标。这东西是2个字节编号,在射频发送的时候,必须要指定接收模块的镞,发送模块不需要指定。
结合代码发送模块:
在发送模块里,我们用的数据发送源端点,也是10,所以我们也定义这个10端点也挂钩应用层任务,原则上,外部给我们终端模块10号端点来数据,也会进入终端应用层任务事件处理 函数里。而我们这个端点仅仅这里作为发送模块,但是我们要实用10端点,必须要挂钩定义。
发送帧里面的东西在代码里体现:
byte SimonApp_TransID; // This is the unique message ID (counter) SimonApp.c全局变量,记录我们应用层任务发送的数据包的个数
void SimonApp_Init( byte task_id )
{
..
SimonApp_TransID = 0;
..
}
if(0==P1_1)
{//按钮3按下
char theMessageData[] ="Hello lao da";
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;//接收模块的网络地址
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint =SimonApp_ENDPOINT ;//接收模块的端点房间号
//SimonApp_epDesc 结构体 端点描述符有源端点的信息,也是10
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
SimonApp_CLUSTERID,//目标端点镞,房间里的接收人数据宏是1,2个字节,所以在射频帧里面是0x0001
(byte)osal_strlen( theMessageData ) + 1,//发送字符串的长度
(byte *)&theMessageData,//字符串内容数组的首地址
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
P1SEL &=0Xfe;// 1111 1110
P1DIR |=0X01;
P1_0 ^=1;
再发送方总体框架:
if ( events & SimonApp_MY_EVT )
{
if(0==P1_1)
{//按钮3按下
char theMessageData[] ={3};
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = 7;
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
0x0001,
1,//(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
if(0==P2_0)
{//按钮4按下
char theMessageData[] ={4};
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = 7;
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
0x0002,
1,//(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
if(0==P0_5)
{//按钮5按下
char theMessageData[] ={5};
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = 6;
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
0x0001,
1,//(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
return (events ^ SimonApp_MY_EVT);
}
在接收方可使用如下代码识别具体端点、具体簇:
void SimonApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
if ( 7 == pkt->endPoint )
{
switch ( pkt->clusterId )
{
case 0x0001:
// "the" message
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
#elif defined( WIN32 )
WPRINTSTR( pkt->cmd.Data );
#endif
Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
LS164_BYTE(pkt->cmd.Data[0]);
MYLED1 ^= 1;
break;
case 0x0002:
Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
LS164_BYTE(pkt->cmd.Data[0]);
MYLED2 ^= 1;
break;
}
}
if ( 6 == pkt->endPoint )
{
switch ( pkt->clusterId )
{
case 0x0001:
// "the" message
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
#elif defined( WIN32 )
WPRINTSTR( pkt->cmd.Data );
#endif
Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
LS164_BYTE(pkt->cmd.Data[0]);
MYLED3 ^= 1;
break;
}
}
}
初始化函数里面有如下语句用来填充端点描述符和簇信息:
>// Fill out the endpoint description.
SimonApp_epDesc.endPoint = 11;//SimonApp_ENDPOINT;
SimonApp_epDesc.task_id = &SimonApp_TaskID;
SimonApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SimonApp_SimpleDesc;
SimonApp_epDesc.latencyReq = noLatencyReqs;
// Register the endpoint description with the AF
afRegister( &SimonApp_epDesc );
其中的
SimonApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SimonApp_SimpleDesc;
完成了簇信息表的构建,因为簇信息封装在SimonApp_SimpleDesc里面,这里面却只是起到一个信息表的作用!方便数据到来的时候查询相关信息表!但真正的一个房间(端点)有多少人(簇),却是在SimonApp_MessageMSGCB函数中判断数据包携带的clusterId成员时决定的!!!
具体的SimonApp_SimpleDesc相关定义如下:
// This list should be filled with Application specific Cluster IDs.
const cId_t SimonApp_ClusterList[SimonApp_MAX_CLUSTERS] =
{
SimonApp_CLUSTERID
};
const SimpleDescriptionFormat_t SimonApp_SimpleDesc =
{
SimonApp_ENDPOINT, // int Endpoint;
SimonApp_PROFID, // uint16 AppProfId[2];
SimonApp_DEVICEID, // uint16 AppDeviceId[2];
SimonApp_DEVICE_VERSION, // int AppDevVer:4;
SimonApp_FLAGS, // int AppFlags:4;
SimonApp_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)SimonApp_ClusterList, // byte *pAppInClusterList;
SimonApp_MAX_CLUSTERS, // byte AppNumInClusters;
(cId_t *)SimonApp_ClusterList // byte *pAppInClusterList;
};
规范
也叫作属性(ProfileID),实际上他就是代表不同类型的应用具有不同的ProfileID,这些表现在有效载荷里面!所以不同协议栈版本主要区别就是这个属性不同而已!!!
属性就是在应用层有用的数据载荷,做专门规定应用类型的最小单元
#define SimonApp_PROFID 0x0F04
在端点描述符里有提到,所以在无线数据包(抓包)里有看到相关的信息!!
综合实例
终端节点–发送
Enddevice.c
- 填充端点,和应用挂钩
void SimonApp_Init( byte task_id )
{
SimonApp_TaskID = task_id;
SimonApp_NwkState = DEV_INIT;
SimonApp_TransID = 0;
... ...
// Fill out the endpoint description.
SimonApp_epDesc.endPoint = 11;//SimonApp_ENDPOINT;
SimonApp_epDesc.task_id = &SimonApp_TaskID;
SimonApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SimonApp_SimpleDesc;
SimonApp_epDesc.latencyReq = noLatencyReqs;
// Register the endpoint description with the AF
afRegister( &SimonApp_epDesc );
... ...
}
- 处理按键事件
按键通过自定义的中断函数设置SimonApp_MY_EVT 事件,导致调用以下代码:
if ( events & SimonApp_MY_EVT )
{
if(0==P1_1)
{//按钮3按下
char theMessageData[] ={3};
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = 7;
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
0x0001,
1,//(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
if(0==P2_0)
{//按钮4按下
char theMessageData[] ={4};
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = 7;
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
0x0002,
1,//(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
if(0==P0_5)
{//按钮5按下
char theMessageData[] ={5};
SimonApp_DstAddr.addrMode = (afAddrMode_t)Addr16Bit;
SimonApp_DstAddr.addr.shortAddr = 0x0000;
// Take the first endpoint, Can be changed to search through endpoints
SimonApp_DstAddr.endPoint = 6;
AF_DataRequest( &SimonApp_DstAddr, &SimonApp_epDesc,
0x0001,
1,//(byte)osal_strlen( theMessageData ) + 1,
(byte *)&theMessageData,
&SimonApp_TransID,
AF_DISCV_ROUTE, AF_DEFAULT_RADIUS );
}
return (events ^ SimonApp_MY_EVT);
}
协调器–接收
- 填充端点、绑定应用层任务
SimonAPP.c
void SimonApp_Init( byte task_id )
{
... ...
// Fill out the endpoint description.
SimonApp_epDesc.endPoint = 7;//SimonApp_ENDPOINT;
SimonApp_epDesc.task_id = &SimonApp_TaskID;
SimonApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SimonApp_SimpleDesc;
SimonApp_epDesc.latencyReq = noLatencyReqs;
// Register the endpoint description with the AF
afRegister( &SimonApp_epDesc );
/*=========================================================================*/
// Fill out the endpoint description.
SimonApp_epDesc1.endPoint = 6;//SimonApp_ENDPOINT;
SimonApp_epDesc1.task_id = &SimonApp_TaskID;
SimonApp_epDesc1.simpleDesc
= (SimpleDescriptionFormat_t *)&SimonApp_SimpleDesc;
SimonApp_epDesc1.latencyReq = noLatencyReqs;
// Register the endpoint description with the AF
afRegister( &SimonApp_epDesc1 );
... ...
}
- 接收到数据以后,判断是属于哪一个端点、属于哪一个簇
void SimonApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
if ( 7 == pkt->endPoint )
{
switch ( pkt->clusterId )
{
case 0x0001:
Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
LS164_BYTE(pkt->cmd.Data[0]);
MYLED1 ^= 1;
break;
case 0x0002:
Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
LS164_BYTE(pkt->cmd.Data[0]);
MYLED2 ^= 1;
break;
}
}
if ( 6 == pkt->endPoint )
{
switch ( pkt->clusterId )
{
case 0x0001:
// "the" message
#if defined( LCD_SUPPORTED )
HalLcdWriteScreen( (char*)pkt->cmd.Data, "rcvd" );
#elif defined( WIN32 )
WPRINTSTR( pkt->cmd.Data );
#endif
Uart_Send_String(pkt->cmd.Data,pkt->cmd.DataLength);
LS164_BYTE(pkt->cmd.Data[0]);
MYLED3 ^= 1;
break;
}
}
}
这里才是真正的判断一个房间有哪些人,具体数据又属于谁!!实际上与初始化的时候指定的簇数组无关!!!