目录
110_ZigBee网络通信的实现
1一、控制台的基本结构
3二、第一个命令’h’帮助
6三、广播
8四、点对点通信
13五、远程
20五、
总结
初级经济法重点总结下载党员个人总结TXt高中句型全总结.doc高中句型全总结.doc理论力学知识点总结pdf
10_ZigBee网络通信的实现
----(转载请注明出处 774910349@qq.com)Everhuai写于
2011-12-24
上一次笔记中主要讲了一些原理性的东西,现在将对我的代码进行解读。
一、控制台的基本结构
在代码中我单独为控制台增加了两个文件Console.c和Console.h。
#ifndef CONSOLE_H
#define CONSOLE_H
#ifdef __cplusplus
extern "C"
{
#endif
#define USER_DEBUG 1 //调试
#undef USER_DEBUG
//函数指针原型
typedef void (*console_f)(void);
struct console_config{
console_f console; //入口函数指针
console_f menu;
//打印菜单
console_f broadcast; //广播函数指针
console_f search; //搜索节点
console_f cmd; //通过无线发送命令给节点进行操作的函数指针
console_f serialCB; //提供给串口
//这样就能与应用层共用缓冲
uint8 *Console_TxBuf; //缓冲区指针
uint8 *Console_TxLen; //数据量指针
};
extern struct console_config console;
extern unsigned short strlen_c(char* buf);
#ifdef __cplusplus
}
#endif
#endif /* CONSOLE_H */
我使用结构console_config对控制台进行封装,其中函数指针broadcast、search、cmd是有应用层提供的。使用指针Console_TxBuf和Console_TxLen主要为了能和原来的代码接口,因为我主要是基于无线串口透明传输进行更改的。
struct console_config console = {
.console
= console_entry, //入口函数
.menu
= menu, //打印菜单
/**********************由应用层提供***************************/
.broadcast = NULL, //广播函数指针
.search = NULL, //搜索节点,函数有应用层提供
.cmd = NULL, //通过无线发送命令给节点进行操作的函数指针,函数又应用层提供
/**********************由应用层提供**************************/
.serialCB = console_entry, //提供给串口
.Console_TxBuf
= NULL, //没有指定数据缓冲区
.Console_TxLen
= NULL, //没有数据
};
应用层填充如下:
//填充接口函数
console.broadcast = LEDSApp_Broadcast; //广播
console.search = LEDSApp_EndSearch; //用于搜索节点的函数指针
console.cmd = LEDSApp_EndCmd; //用于远程
//控制台初始化
console.Console_TxBuf = SerialApp_TxBuf;
console.Console_TxLen = &SerialApp_TxLen;
这些接口函数放到应用层去实现主要是考虑到其中要用到一些应用层的静态变量,而我也不想把它改成外部的。其中串口只调用接口函数console.serialCB,这样我只要让其指向不同的对象就可以让不同的对象占用串口。
static void SerialApp_CallBack(uint8 port, uint8 event)
{
(void)port;
#ifdef USER_DEBUG
//为了节省资源,只有调试的时候才使用该LED指示串口工作状态
HalLedSet( HAL_LED_2, HAL_LED_MODE_TOGGLE );
#endif //USER_DEBUG
if ((event & (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL | HAL_UART_RX_TIMEOUT)) &&
#if SERIAL_APP_LOOPBACK
/*数据长度检查*/
(SerialApp_TxLen < SERIAL_APP_TX_MAX))
#else
!SerialApp_TxLen)
#endif
{
//SerialApp_Send();//第一次触发任务SERIALAPP_SEND_EVT
console.serialCB(); //用于把串口让给不同的任务
}
}
操作完成是使用语句
console.serialCB = console.console; //释放串口
把串口还给控制台。
二、第一个命令’h’帮助
现在来讲一下命令是如何实现的,这里以’h’帮助命令为例;
从前面我们知道控制台的入口函数是console_entry(),
static void console_entry(void)
{
static uint8 commond = 0; //保存命令
uint8 *IEEEAddr;
uint16 nwkAddr;
if(commond != 0) //命令还没有执行完毕
{
goto cmd;//运行命令
}
//读取命令,2个字节,格式:命令 + 回车
*console.Console_TxLen = HalUARTRead(CONSOLE_PORT, console.Console_TxBuf+STR_START, CONSOLE_TX_MAX);
//以十六进制形式打印输入命令字节数,前三字节为命令
show_hex(console.Console_TxLen, console.Console_TxBuf+STR_START+3, 1);
//串口调试助手把回车当成两个字符 '\t' '\n'
if((*console.Console_TxLen != 2) && (*console.Console_TxLen != 3)) // 命令为两个字符,命令格式:'commond' + 'Enter'
{
//HalUARTWrite(CONSOLE_PORT, "error!command 2 byte!\n", 22);
printz("error!command 2 byte!\n");
while(*console.Console_TxLen) //清空串口
{
*console.Console_TxLen = HalUARTRead(CONSOLE_PORT, console.Console_TxBuf+STR_START,CONSOLE_TX_MAX );
}
return;//结束运行
}
if(console.Console_TxBuf[STR_START + 1] != '\r') //命令格式错误,命令格式:'commond' + 'Enter'
{
console.Console_TxBuf[STR_START + 1] = ':';
HalUARTWrite(CONSOLE_PORT, console.Console_TxBuf + STR_START, 2);
HalUARTWrite(CONSOLE_PORT, menu_str[1], strlen_c((char*)menu_str[1]));
while(*console.Console_TxLen) //清空串口
{
*console.Console_TxLen = HalUARTRead(CONSOLE_PORT, console.Console_TxBuf+STR_START, CONSOLE_TX_MAX );
}
return;//结束运行
}
//检查命令并运行
//if(console.Console_TxBuf[STR_START + 1] == '\r') //命令格式:'commond' + '\r'
{
commond = console.Console_TxBuf[STR_START];//拷贝命令,数据的第一个字符为命令
HalUARTWrite(CONSOLE_PORT, &console.Console_TxBuf[STR_START], 3);//命令回显
//运行命令
cmd:
switch(commond)//命令匹配
{
case 'h': //帮助命令
num = 0;//从第一条命令开始打印
osal_set_event(SerialApp_TaskID, SERIALAPP_MENU);//添加一个发送任务,打印菜单
while(*console.Console_TxLen) //清空串口
{
*console.Console_TxLen = HalUARTRead(CONSOLE_PORT, console.Console_TxBuf+STR_START,CONSOLE_TX_MAX );
}
commond = 0; //清除命令
break;
…
default: //不被支持的命令
commond = 0; //不支持,清除命令
//HalUARTWrite(CONSOLE_PORT, "command nonsupport\n", 19);
printz("command nonsupport\n");
while(*console.Console_TxLen) //清空串口
{
*console.Console_TxLen = HalUARTRead(CONSOLE_PORT, console.Console_TxBuf+STR_START,CONSOLE_TX_MAX - STR_START);
}
}
}
*console.Console_TxLen = 0;
}
在开始处我们定义了命令、长地址、短地址。其中命令在执行完成后被立即清除,是可以不保存的,主要是我一开始就这样做就保留了它。长地址、短地址是因为我实现了获取地址的命令。然后是从串口读取数据,并以十六进制形式打印输入的字节数,正确输入一个命令同样会打印命令,这是给用户的提示。我把命令定义为:'commond' + 'Enter'。但由于实际调试过程中发现串口调试助手把回车拆成两个字符,所以命令会是三个字符。当输入的命令符合命令的格式时,就打印命令并对命令进行判断,如果定义了该命令就执行命令,没有定义则打印命令不被支持。最后把*console.Console_TxLen清零,它保存了从串口读到的数据的长度,如不把它清零,下一次串口将无法调用该函数。在这里需要说明的是凡命令都使用统一的格式,从广播/单播中退出来也是一样,使用的用'q' + 'Enter'命令。
最后我们是通过任务SERIALAPP_MENU实现菜单的打印的。
if ( events & SERIALAPP_MENU)
//打印菜单
{
console.menu();
//打印菜单
return ( events ^ SERIALAPP_MENU);
}
并最终通过函数menu()完成菜单的打印
static void menu(void)
{
char i = 5; //每次打印5条菜单
while(i--)
{
if(!HalUARTWrite(CONSOLE_PORT,menu_str[num],strlen_c((char*)menu_str[num])))
{
return; //写入失败
}
num++;//下一项菜单
if(menu_str[num] == NULL)
{
num = 0;//下一次调用从第一项菜单开始打印
return; //结束运行
}
}
osal_start_timerEx( SerialApp_TaskID, SERIALAPP_MENU, 20);//添加一个任务,打印菜单
}
这样做主要是因为我们的串口使用DMA进行传输,当调用函数HalUARTWrite()进行串口打印时数据实际上是保存在DMA缓存中,最多12
0字
个人自传范文3000字为中华之崛起而读书的故事100字新时代好少年事迹1500字绑架的故事5000字个人自传范文2000字
节,数据比较多时没办法打印完,故分多次打印。到这里一个帮助命令就实现了。理解了帮助命令其它命令也就号理解了。
三、广播
广播命令的实现如下:
case 'b': //广播数据命令
printz("commond 'q' exit broadcast!\n");
console.serialCB = console.broadcast; //占用串口
commond = 0; //清除命令
break;
在应用层使用如下语句填充其函数指针
console.broadcast = LEDSApp_Broadcast; //广播
所以广播的入口函数是LEDSApp_Broadcast()
static void LEDSApp_Broadcast(void)
{
//广播不发送序号
if(StrBro == NULL)
//从串口获取数据
{
//SerialApp_TxLen不为0时代
表
关于同志近三年现实表现材料材料类招标技术评分表图表与交易pdf视力表打印pdf用图表说话 pdf
有数据等待发送或正在发送
if (!(SerialApp_TxLen = HalUARTRead(SERIAL_APP_PORT, SerialApp_TxBuf+1, SERIAL_APP_TX_MAX)))
{ //没有数据并且串口也没有数据时不发送直接返回
return; //结束运行
}
//串口调试助手把回车当成两个字符 '\t' '\n'
if(((SerialApp_TxLen == 2) || ((SerialApp_TxLen == 3))) && (SerialApp_TxBuf[2] == '\r') && (SerialApp_TxBuf[1] == 'q')) //如果是退出命令q 就退出广播
{
SerialApp_TxLen = 0; //没有数据
console.serialCB = console.console; //释放串口
osal_set_event(SerialApp_TaskID, SERIALAPP_MENU);//添加一个发送任务,打印菜单
return; //结束运行
}
//SerialApp_TxBuf[0] = ++SerialApp_TxSeq; //序列号
}
else
{
SerialApp_TxLen = strlen_c(StrBro);
osal_memcpy((SerialApp_TxBuf + 1), StrBro, SerialApp_TxLen);
// Pre-pend sequence number to the Tx message.//发送序号
//SerialApp_TxBuf[0] = ++SerialApp_TxSeq;
StrBro = NULL;
}
if (SerialApp_TxLen)//长度有效
{
//广播不检查发送是否成功
AF_DataRequest(&LEDSApp_TxAddr,
(endPointDesc_t *)&SerialApp_epDesc,
SERIALAPP_CLUSTERID3, //用来处理广播消息
SerialApp_TxLen+1, SerialApp_TxBuf,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS);
SerialApp_TxLen = 0;
}
}
广播的数据来源有两个串口和通过指针StrBro指定。地址LEDSApp_TxAddr是在初始化的时候填充的,专门用于广播
//设置为广播模式
LEDSApp_TxAddr.endPoint = SERIALAPP_ENDPOINT; //端口,广播时需要配置
LEDSApp_TxAddr.addrMode = afAddrBroadcast;
//广播模式
LEDSApp_TxAddr.addr.shortAddr = NWK_BROADCAST_SHORTADDR; //广播地址
在这里我按照原来的代码在数据包中填上了序列号。最后由消息事件SERIALAPP_CLUSTERID3来处理。
case SERIALAPP_CLUSTERID3: //处理广播事件,可能需要应答
// Store the address for sending and retrying./存储的地址发送和重试。
//当同过广播获取节点信息时需要应答。拷贝源地址,为应答准备
osal_memcpy(&SerialApp_RxAddr, &(pkt->srcAddr), sizeof( afAddrType_t ));
// Transmit the data on the serial port./对串行端口传输数据。
//通过广播'a'命令可以获取网络中存在的节点的用户码
if(( ((pkt->cmd.DataLength-1) == 2) || ((pkt->cmd.DataLength-1) == 3) ) && (*(pkt->cmd.Data+2) == '\r') && (*(pkt->cmd.Data+1) == 'a'))
{ //获取用户码来的
Remote_TxLen = sizeof(SerialApp_user_ID);
osal_memcpy(Remote_TxBuf+1, &user_ID, Remote_TxLen);
Remote_TxBuf[Remote_TxLen+1] = '\n';
Remote_TxLen += 1;
osal_start_timerEx( SerialApp_TaskID, SERIALAPP_REMOTE_SHOW, osal_rand() & 0xff); //读取一个随机数作为延时
}
else //是广播数据
{
#ifndef USER_DEBUG
HalLedBlink (HAL_LED_1, 3, 5, 600); //LED_1以周期600ms ,5%的占空比连续闪烁3次
#endif //USER_DEBUG
}
#ifdef USER_DEBUG
HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) );
#endif
break;
如果广播的数据是’a’命令,就给对方返回自己的用户码,否则就把数据直接从串口输出。当然这只是简单的处理。使用随机数是为了避开同时发送。
四、点对点通信
点对点命令的实现如下
case 'p': //点对点
printz("input user_ID:ddggii, 6 byte!\n");
console.serialCB = console.search; //占用串口
commond = 0; //清除命令
break;
在应用层使用如下语句填充其函数指针
console.search = LEDSApp_EndSearch; //用于搜索节点的函数指针
所以点对点通信的入口函数是LEDSApp_EndSearch()
void LEDSApp_EndSearch(void) //搜索节点
{
search_t *search;
search = (search_t*)(SerialApp_TxBuf+1);
PTPSendCmd = 'F'; //不进行远程操作
if (!(SerialApp_TxLen = HalUARTRead(SERIAL_APP_PORT, (uint8*)&search->dat, SERIAL_APP_TX_MAX-sizeof(search_t)))) //没有数据
{
return; //结束运行
}
//串口调试助手把回车当成两个字符 '\t' '\n'
if(((SerialApp_TxLen == 2) || ((SerialApp_TxLen == 3))) && (search->dat.dat[1] == '\r') && (search->dat.dat[0] == 'q')) //如果是退出命令q 就退出广播
{
SerialApp_TxLen = 0; //没有数据
console.serialCB = console.console; //释放串口
osal_set_event(SerialApp_TaskID, SERIALAPP_MENU);//添加一个发送任务,打印菜单
return; //结束运行
}
if(SerialApp_TxLen != 6) //输入搜索的用户ID必须为6字节
{
HalUARTWrite(SERIAL_APP_PORT, Ser, strlen_c((char *)Ser));
while(SerialApp_TxLen) //清空串口
{
SerialApp_TxLen = HalUARTRead(SERIAL_APP_PORT, SerialApp_TxBuf+1,SERIAL_APP_TX_MAX );
}
return; //结束运行
}
SerialApp_TxLen += 2;
//在接收端暂未使用该地址
search->nwkAddr = NLME_GetShortAddr();
//SerialApp_TxBuf[0] = ++SerialApp_TxSeq; //序列号
if (SerialApp_TxLen)//长度有效
{
//不检测发送失败
AF_DataRequest(&LEDSApp_TxAddr,
(endPointDesc_t *)&SerialApp_epDesc,
SERIALAPP_CLUSTERID4, //用来处理广播消息
SerialApp_TxLen+1, SerialApp_TxBuf,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS);
SerialApp_TxLen = 0;
PTPTimerout = 'F'; //接收对方回复
osal_start_timerEx( SerialApp_TaskID, SERIALAPP_SEARCH, LINK_TIME_OUT); //等待返回对方短地址
}
}
这个函数实际上是发送了一条广播消息,其格式为
自己的短地址
搜索的用户码(6字节)
另外还设置了两个变量PTPSendCmd和PTPTimerout,分别用来设置是否远程(稍后会讲到)和搜索超时的。超时由事件SERIALAPP_SEARCH检测,该事件被触发时代表已经超时。另外与广播不同的是该消息由消息事件SERIALAPP_CLUSTERID4处理。
if ( events & SERIALAPP_SEARCH) //点对点传输搜索超时事件
{
PTPTimerout = 'T'; //超时,取消搜索事件
SerialApp_TxLen = 0; //串口需要接收数据必须清零
printz("Serach Time out!\n");
return ( events ^ SERIALAPP_SEARCH);
}
case SERIALAPP_CLUSTERID4: //处理广播事件,可能需要应答
// Store the address for sending and retrying./存储的地址发送和重试。
//当同过广播获取节点信息时需要应答。拷贝源地址,为应答准备
osal_memcpy(&SerialApp_RxAddr, &(pkt->srcAddr), sizeof( afAddrType_t ));
search = (search_t*)(pkt->cmd.Data+1);
//用户码匹配
if( (user_ID.district == search->dat.user.district ) &&
(user_ID.group == search->dat.user.group ) &&
(user_ID.identifier == search->dat.user.identifier))
{
search->nwkAddr = NLME_GetShortAddr();
AF_DataRequest(&SerialApp_RxAddr,
(endPointDesc_t *)&SerialApp_epDesc,
SERIALAPP_CLUSTERID5,
pkt->cmd.DataLength, pkt->cmd.Data,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS);
#ifdef USER_DEBUG
HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) );
#endif
}
else //是广播数据
{
#ifdef USER_DEBUG
HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) );
#endif
}
break;
对用户码进行匹配,匹配成功就把自己的用户码以单播的方式返回给对方,否则直接丢弃数据。对方接收到数据将有消息事件SERIALAPP_CLUSTERID5处理。
case SERIALAPP_CLUSTERID5: //被搜索节点返回信息,进行处理,不应答
if(PTPTimerout == 'F') //未超时
{
osal_stop_timerEx(SerialApp_TaskID, SERIALAPP_SEARCH); //取消定时器事件
#ifdef USER_DEBUG
// Transmit the data on the serial port./对串行端口传输数据。
HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) );
show_hex(pkt->cmd.Data+1, 2);
#endif //USER_DEBUG
//填充对方的地址信息
search = (search_t*)(pkt->cmd.Data+1);
SerialApp_TxAddr.addr.shortAddr = search->nwkAddr;
//对传输类型进行判断
if(PTPSendCmd == 'T') //命令
{
rem.cmd[REMOTE_TX].cmd = 'C'; //远程时该字节必须这样设置
rem.cmd[REMOTE_TX].nwkAddr = NLME_GetShortAddr();//填充自己的短地址
osal_memcpy(&rem.cmd[REMOTE_TX].user, &user_ID, sizeof( SerialApp_user_ID ));//填充用户ID
printz("authentication, 1 byte!\n");//提示输入认证码'C'
console.serialCB = LEDSApp_Cmd; //占用串口
}
else if(PTPSendCmd == 'F') //数据
{
printz("start send!\n");
console.serialCB = LEDSApp_PTP; //占用串口
}
else //出错
{
PTPSendCmd = 'F';
console.serialCB = console.console; //释放串口
}
}
else if(PTPTimerout == 'T') //超时
{
printz("Serach Time out!\n");
}
else //出错
{
PTPTimerout = 'F';
}
SerialApp_TxLen = 0; //串口需要接收数据必须清零
break;
这里首先检测是否超时,如超时则打印提示。然后取消超时事件,并获取对方短地址。由于我们是用点对点通信来传输数据的,所以最后将由函数LEDSApp_PTP()来占用串口。
static void LEDSApp_PTP(void) //点对点传输
{
PTPSendCmd = 'F'; //不进行远程操作
if(StrBro == NULL)
//从串口获取数据
{
if (!SerialApp_TxLen &&
(SerialApp_TxLen = HalUARTRead(SERIAL_APP_PORT, SerialApp_TxBuf+1, SERIAL_APP_TX_MAX)))
{//SerialApp_TxLen不为0时代表有数据等待发送
// Pre-pend sequence number to the Tx message.//发送序号
SerialApp_TxBuf[0] = ++SerialApp_TxSeq;
}
//串口调试助手把回车当成两个字符 '\t' '\n'
if(((SerialApp_TxLen == 2) || ((SerialApp_TxLen == 3))) && (SerialApp_TxBuf[2] == '\r') && (SerialApp_TxBuf[1] == 'q')) //如果是退出命令q 就退出广播
{
SerialApp_TxLen = 0; //没有数据
console.serialCB = console.console; //释放串口
osal_set_event(SerialApp_TaskID, SERIALAPP_MENU);//添加一个发送任务,打印菜单
return; //结束运行
}
}
else
{
SerialApp_TxLen = strlen_c(StrBro);
osal_memcpy((SerialApp_TxBuf + 1), StrBro, SerialApp_TxLen);
// Pre-pend sequence number to the Tx message.//发送序号
SerialApp_TxBuf[0] = ++SerialApp_TxSeq;
StrBro = NULL;
}
if (SerialApp_TxLen)//长度有效,因为取得了对方的地址,一下便回到了历程中原来的发送函数的形式
{
osal_stop_timerEx( SerialApp_TaskID, SERIALAPP_PTP); //取消已经存在的超时检测
if (afStatus_SUCCESS != AF_DataRequest(&SerialApp_TxAddr,
(endPointDesc_t *)&SerialApp_epDesc,
SERIALAPP_CLUSTERID1,
SerialApp_TxLen+1, SerialApp_TxBuf,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS))
{//发送失败,添加任务等待再次发送
osal_set_event(SerialApp_TaskID, SERIALAPP_SEND_EVT);
}
osal_start_timerEx( SerialApp_TaskID, SERIALAPP_PTP, LINK_TIME_OUT); //点对点传输使用应答
}
}
if ( events & SERIALAPP_SEND_EVT ) //对方忙,延时一段时间后再次发送
{
//SerialApp_Send();//发送数据,该函数已由自己编写的函数LEDSApp_PTP()代替
LEDSApp_PTP();
return ( events ^ SERIALAPP_SEND_EVT );
}
该函数使用的地址就是刚才设置的地址SerialApp_TxAddr。由于是要验证的,所以该函数需要检测是否发送失败。自然从串口读数据部分也与广播有所区别,需要检测是否有数据正在发送。当然这里也要设置超时事件SERIALAPP_PTP,主要是防止一直收不到数据时无法进行下一次数据的收发。这里设置由对方的消息事件SERIALAPP_CLUSTERID1进行处理。SERIALAPP_CLUSTERID1和SERIALAPP_CLUSTERID2都是工程中原来就用于点对点通信的,因此直接拿过来使用。在该事件最后会设置一个事件进行应答
osal_set_event( SerialApp_TaskID, SERIALAPP_RESP_EVT );
if ( events & SERIALAPP_RESP_EVT )
{
SerialApp_Resp();//AF发送应答
return ( events ^ SERIALAPP_RESP_EVT );
}
static void SerialApp_Resp(void)
{
if (afStatus_SUCCESS != AF_DataRequest(&SerialApp_RxAddr,
(endPointDesc_t *)&SerialApp_epDesc,
SERIALAPP_CLUSTERID2,
SERIAL_APP_RSP_CNT, SerialApp_RspBuf,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS))
{
osal_set_event(SerialApp_TaskID, SERIALAPP_RESP_EVT);
}
}
case SERIALAPP_CLUSTERID2:
if ((pkt->cmd.Data[1] == SerialApp_TxSeq) &&
((pkt->cmd.Data[0] == OTA_SUCCESS) || (pkt->cmd.Data[0] == OTA_DUP_MSG)))
{
SerialApp_TxLen = 0;
osal_stop_timerEx(SerialApp_TaskID, SERIALAPP_SEND_EVT);//当反馈信号回来时取消重发事件
printz("Send succeed!\n");//提示用户发送成功
}
else
{
// Re-start timeout according to delay sent from other device.
delay = BUILD_UINT16( pkt->cmd.Data[2], pkt->cmd.Data[3] );
//如果对方忙的话过一段时间后再继续发送数据。
osal_start_timerEx( SerialApp_TaskID, SERIALAPP_SEND_EVT, delay );
}
osal_stop_timerEx(SerialApp_TaskID, SERIALAPP_PTP);//接收到应答,取消超时事件
break;
当对方的应答为成功或者重复时取消重复发送,否则设置一段时间后重发,并在最后取消超时事件。这样就完成了一次点对点数据传输。过程如下:
发送方
接收方
LEDSApp_EndSearch(void) 收索节点
SERIALAPP_CLUSTERID4 信息匹配
SERIALAPP_CLUSTERID5 提取信息,设置LEDSApp_PTP()
此时已经获取到接受方地址,接下来就可以进行数据收发
LEDSApp_PTP(void) 发送数据
SERIALAPP_CLUSTERID1 数据处理
SerialApp_Resp(void) 应答
SERIALAPP_CLUSTERID2 处理应答
此时完成一次数据的收发
五、远程
远程弥补了控制台必须使被操作模块与电脑必须在一起的不足,支持通过网络中任一节点对网络中其他节点用户码的更改。远程是基于点对点通信实现的。
远程命令的实现如下
case 't':