本帖最后由 神经火光 于 2012-8-17 11:33 编辑
最近在使用SerailAPP 实现星形网,使用其串口通信功能,希望实现多对一的功能,愿望是好的,实现起来确实遇到写问题!
实现点对点通信很方便,实现多对一却遇到了阻碍,不是不能加入网络,而是,加入网络后无法实现数据传输。问题是,在很长一
段时间内只能有一个在通信,当然也会有两个一起通信的时候。
主要问题在与,SerailApp 帮我们实现串口无线收发的同时,也在串口程序中加入了 序列号,防止数据重发重收,具体如下:
首先,是串口接受,然后无线发送的程序(EndDevice):
static void SerialApp_SendData( uint8 *buf, uint8 len )
{
afStatus_t stat;
// Pre-pend sequence number to the start of the Rx buffer.
*buf = ++SerialApp_SeqTx;
otaBuf = buf;
otaLen = len+1;
stat = AF_DataRequest( &SerialApp_DstAddr,
(endPointDesc_t *)&SerialApp_epDesc,
SERIALAPP_CLUSTERID1,
otaLen, otaBuf,
&SerialApp_MsgID, 0, AF_DEFAULT_RADIUS );
if ( (stat == afStatus_SUCCESS) || (stat == afStatus_MEM_FAIL) )
{
osal_start_timerEx( SerialApp_TaskID, SERIALAPP_MSG_RTRY_EVT,
SERIALAPP_MSG_RTRY_TIMEOUT );
rtryCnt = SERIALAPP_MAX_RETRIES;
}
else
{
FREE_OTABUF();
}
}
可以看到,在
// Pre-pend sequence number to the start of the Rx buffer.
*buf = ++SerialApp_SeqTx;
处为buf 加了一个序列号,这个序列号会在协调器接受之后进行判断
Coordinator 处处理程序:
void SerialApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt )
{
uint8 stat;
uint8 seqnb;
uint8 delay;
switch ( pkt->clusterId )
{
// A message with a serial data block to be transmitted on the serial port.
case SERIALAPP_CLUSTERID1:
seqnb = pkt->cmd.Data[0];
// Keep message if not a repeat packet,控制是不是同一个包应该由硬件自己控制得把
if ( (seqnb > SerialApp_SeqRx) || // Normal
((seqnb < 0x80 ) && ( SerialApp_SeqRx > 0x80)) ) // Wrap-around
{
// Transmit the data on the serial port.
if ( HalUARTWrite( SERIAL_APP_PORT, pkt->cmd.Data+1,
(pkt->cmd.DataLength-1) ) )
{
// Save for next incoming message
SerialApp_SeqRx = seqnb;
stat = OTA_SUCCESS;
}
else
{
stat = OTA_SER_BUSY;
}
}
……
……
……
}
可以看到,条件判断语句:
if ( (seqnb > SerialApp_SeqRx) || // Normal
((seqnb < 0x80 ) && ( SerialApp_SeqRx > 0x80)) ) // Wrap-around
这里,就是问题的关键所在,其一,seqnb 没有针对不同的终端定义不同的Seqnb,所以当不同的终端发数据的时候,协调器会
接受 seqnb 符合条件判断的那个,并发送给串口。所以多个终端发送数据时,只有一个能被协调器接收数据并串口发送。其
二,seqnb对与多个终端时,只要终端发来的序列好满足条件。seqnb都会为之改变。那么seqnb永远都是最新最大的值。
举个例子,比如在点对点的情况下,终端给协调器发送数据,seqnb从0x20开始,一段时间后,这个时候seqnb 假设等于 0x36
,那么关闭终端,再打开终端,则终端发给协调器的序列号从0x20开始,在在0x20~0x36 直接的数据,协调器都不会串口显
示。
这里通过 SerialApp_SeqRx 来判断是否接受数据,它的定义如下:
static uint8 SerialApp_SeqRx;
static uint8 SerialApp_SeqTx;
初始化在SerailApp_Init() 中,如下:
void SerialApp_Init( uint8 task_id )
{
halUARTCfg_t uartConfig;
SerialApp_MsgID = 0x00;
SerialApp_SeqRx = 0xC3;
SerialApp_TaskID = task_id;
……………………………………
}
一开始: SerialApp_SeqRx = 0xC3;
修改的方法,有两种,第一,要么将SerialApp_seqrx 设计为结构体,其中,加上网络地址,然后在条件判断中,对网络地址同
样进行判断,这样,就可以分别避免多对一造成的seqrx的问题。同时,加上flag标志,用于判断终端是否是重新加入网络。
第二,最简单,就是直接把条件判断去掉,即不使用seqrx 的信息,只需要在Coordinator中屏蔽条件判断即可。因为zigbee协议
栈自己会有硬件实现数据包是否重复判断,所以,我们不用去操心!
|