zigbee 组网(三)(转载)
(2013-08-04 20:32:33)
第三个功能:实现两个节点间的串口通信
“串口终端1”的数据,如何被“节点 1”所接收,并且发送出去的?
串口数据是由哪层来负责的呢?--HAL。
。 。恩,猜对了。但这个肯定不是靠猜的,其中的过程
的同学可以用 ctrl +)
,Hal_ProcessPoll ==> HalUARTPoll ==>
HalUARTPollDMA
这个
HalUARTPollDMA 函数里最后有这样一句话:dmaCfg.uartCB(HAL_UART_DMA-1,
evt); 对dmaCfg.uartCB 这个函数进行了调用,ctrl
/ 搜索这个 dmaCfg.uartCB,发现 SerialApp_Init
函数有两句话:
uartConfig.callBackFunc
=
SerialApp_CallBack;
HalUARTOpen (SERIAL_APP_PORT,
&uartConfig);
“串口终端1”的数据,如何被“节点 1”所接收,并且发送出去的?
就不讲了。
让我们从主循环 (osal_start_system) 的Hal_ProcessPoll函数找下去 (用source
insight
此处将 dmaCfg.uartCB
这个函数注册成为 SerialApp_CallBack, 也就是说
SerialApp_CallBack函数每次循环中被调用一次,对串口的内容进行查询,如果 DMA
中接收到了数据,则调用HalUARTRead,将 DMA 数据读至数据 buffer 并通过 AF_DataRequest
函数发送出去,注意:出去的信息的 CLUSTERID(信息簇ID)号为
SERIALAPP_CLUSTERID1。 总结一下这个过程:
串口数据==>DMA接收==>主循环中通过SerialApp_CallBack 查询==>从
DMA获取并发送到空中。
具体流程如下:
具体流程如下:
void
SerialApp_Init( uint8 task_id )
{
......
uartConfig.configured
= TRUE;
//
2x30 don't care - see uart driver.
uartConfig.baudRate
=
SERIAL_APP_BAUD;
uartConfig.flowControl
= TRUE;
uartConfig.flowControlThreshold
= SERIAL_APP_THRESH; // 2x30 don't care - see
uart driver.
uartConfig.rx.maxBufSize
= SERIAL_APP_RX_SZ;
//
2x30 don't care - see uart driver.
uartConfig.tx.maxBufSize
= SERIAL_APP_TX_SZ;
//
2x30 don't care - see uart driver.
uartConfig.idleTimeout
= SERIAL_APP_IDLE;
// 2x30 don't care - see
uart driver.
uartConfig.intEnable
= TRUE;
// 2x30 don't care - see
uart driver.
uartConfig.callBackFunc
= SerialApp_CallBack;
//调用SerialApp_CallBack函数,对串口内容进行查询
HalUARTOpen
(SERIAL_APP_PORT, &uartConfig);
......
}
(void)port;
if ((event
& (HAL_UART_RX_FULL | HAL_UART_RX_ABOUT_FULL |
HAL_UART_RX_TIMEOUT)) &&
(SerialApp_TxLen <
SERIAL_APP_TX_MAX))
!SerialApp_TxLen)
{
SerialApp_Send();
//调用串口发送函数,将从串口接受到的数据,发送出去
}
......
}
static
void SerialApp_CallBack(uint8 port, uint8 event)
{
//如果 DMA 中接收到了数据
#if
SERIAL_APP_LOOPBACK
#else
#endif
}
if
(SerialApp_TxLen < SERIAL_APP_TX_MAX)
{
SerialApp_TxLen += HalUARTRead(SERIAL_APP_PORT,
SerialApp_TxBuf+SerialApp_TxLen+1,
SERIAL_APP_TX_MAX-SerialApp_TxLen);
}
if
(SerialApp_TxLen)
{
(void)SerialApp_TxAddr;
if (HalUARTWrite(SERIAL_APP_PORT,
SerialApp_TxBuf+1, SerialApp_TxLen))
{
SerialApp_TxLen =
0;
}
else
{
osal_set_event(SerialApp_TaskID,
SERIALAPP_SEND_EVT);
}
}
if
(!SerialApp_TxLen &&
(SerialApp_TxLen =
HalUARTRead(SERIAL_APP_PORT, SerialApp_TxBuf+1,
SERIAL_APP_TX_MAX)))
{
// Pre-pend sequence number to the Tx
message.
SerialApp_TxBuf[0] =
++SerialApp_TxSeq;
}
if
(SerialApp_TxLen)
{
if (afStatus_SUCCESS
!= AF_DataRequest(&SerialApp_TxAddr,
//通过AF_DataRequest()函数,将数据从空中发送出去
(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);
//如果数据没有发送成功,重新发送
}
}
static
void SerialApp_Send(void)
{
#if
SERIAL_APP_LOOPBACK
//初始化时,SERIAL_APP_LOOPBACK=false
,所以不执行if这个预编译,转到else去执行
#else
#endif
}
UINT16
SerialApp_ProcessEvent( uint8 task_id, UINT16 events )
{
if ( events & SERIALAPP_SEND_EVT )
//当数据没有发送成功时
{
SerialApp_Send();
return (
events ^ SERIALAPP_SEND_EVT );
}
}
节点2 在收到空中的信号后,如何传递给与其相连的串口终端?
}
节点2 在收到空中的信号后,如何传递给与其相连的串口终端?
节点 2
从空中捕获到信号后, 在应用层上首先收到信息的就是 SerialApp_ProcessEvent 这个函数了,它收到一个
AF_INCOMING_MSG_CMD 的事件,并通知 SerialApp_ProcessMSGCmd,执行以下代码
:
{
switch ( MSGpkt->hdr.event
)
{
......
case AF_INCOMING_MSG_CMD:
//在这个实验中,使用串口通讯时,触发的事件,从空中捕获到信号。
SerialApp_ProcessMSGCmd(
MSGpkt ); //处理这个消息
break;
......
}
}
}
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:
//节点一发送过来的信息的 CLUSTERID(信息簇ID)号为
SERIALAPP_CLUSTERID1
// Store the address for
sending and retrying.
osal_memcpy(&SerialApp_RxAddr,
&(pkt->srcAddr), sizeof( afAddrType_t ));
seqnb = pkt->cmd.Data[0];
//
Keep message if not a repeat packet
if ( (seqnb > SerialApp_RxSeq) ||
// Normal
((seqnb
< 0x80 ) && ( SerialApp_RxSeq > 0x80)) ) //
Wrap-around
{
// Transmit the data on the
serial port.
if
( HalUARTWrite(
SERIAL_APP_PORT, pkt->cmd.Data+1, (pkt->cmd.DataLength-1) ) )
//通过串口发送数据到PC机
{
// Save for
next incoming message
SerialApp_RxSeq = seqnb;
stat =
OTA_SUCCESS;
}
else
{
stat =
OTA_SER_BUSY;
}
}
else
{
stat =
OTA_DUP_MSG;
}
// Select approproiate OTA flow-control
delay.
delay = (stat == OTA_SER_BUSY) ?
SERIALAPP_NAK_DELAY : SERIALAPP_ACK_DELAY;
// Build & send OTA response
message.
SerialApp_RspBuf[0] = stat;
SerialApp_RspBuf[1] = seqnb;
SerialApp_RspBuf[2] = LO_UINT16( delay
);
SerialApp_RspBuf[3] = HI_UINT16( delay
);
osal_set_event(
SerialApp_TaskID, SERIALAPP_RESP_EVT );
//受到数据后,向节点1发送一个响应事件,跳到SerialApp_ProcessEvent()
osal_stop_timerEx(SerialApp_TaskID,
SERIALAPP_RESP_EVT);
break;
......
}
}
节点1,接收到来自节点2的response。
{
switch ( MSGpkt->hdr.event
)
{
......
case AF_INCOMING_MSG_CMD:
//在这个实验中,使用串口通讯时,触发的事件,从空中捕获到信号。
SerialApp_ProcessMSGCmd(
MSGpkt ); //处理这个消息
break;
......
}
}
}
SERIALAPP_CLUSTERID2代表接收到发送成功的response,取消自动重发,如果不,自动重发。
UINT16
SerialApp_ProcessEvent( uint8 task_id, UINT16 events )
//当有事件传递到应用层的时候,执行此处
{
......
while (
(MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(
SerialApp_TaskID )) )
}
void
SerialApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt
) //对从空中捕获到的信号进行处理
{
......
}
UINT16
SerialApp_ProcessEvent( uint8 task_id, UINT16 events )
{
......
if ( events
& SERIALAPP_RESP_EVT )
//串口响应事件,表示成功接受来自节点1的数据,
{
SerialApp_Resp();
//向节点1发送
成功接受的response
return ( events ^ SERIALAPP_RESP_EVT
);
}
......
}
if
(afStatus_SUCCESS != AF_DataRequest(&SerialApp_RxAddr,
//通过AF_DataRequest函数,讲接收成功响应从空中发送出去
(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);
//如果发送失败,重新发送
}
......
......
static
void SerialApp_Resp(void)
{
}
节点1,接收到来自节点2的response。
UINT16
SerialApp_ProcessEvent( uint8 task_id, UINT16 events
)
{
......
while (
(MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(
SerialApp_TaskID )) )
}
SERIALAPP_CLUSTERID2代表接收到发送成功的response,取消自动重发,如果不,自动重发。
void
SerialApp_ProcessMSGCmd( afIncomingMSGPacket_t *pkt
)
{
......
// A
response to a received serial data block.
case
SERIALAPP_CLUSTERID2:
//SerialWsn_CLUSTERID2代表接收到发送成功的response
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);
//当收到发送成功的response,停止自动从发
}
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 ); //没有收到成功的response,自动重发
}
break;
default:
break;
}