一、什麼是透傳
透傳的基本概念:
透傳就是透明傳輸的簡稱。那麼什麼是透明傳輸呢?顧名思義,透明傳輸就是指在傳輸過程中,對外界完全透明,不需要關係傳輸過程以及傳輸協議,終目的是要把傳輸的內容原封不動的傳遞給被接收端,發送和接收的內容完全一致。這就相當於把信息直接扔給你想要傳輸的人,只需要扔(也就是傳輸)這一個步驟,不需要其他的內容安排。
二、ZigBee無線透傳的流程
發送和接收數據的流程:
發送數據:
填充並註冊端點描述符 配置發送模式及目的地址 AF_DataRe quest()發送數據
接收數據:
填充並註冊端點描述符 處理系統事件 SYS_EVENT_MSG 中的AF_INCOMING _MSG_CMD 消息獲得消息包中的無線數據
三、功能需求
1、協調器獲取PC機通過串口發來的數據,並且廣播給終端,終端收到數據後打印在串口調試工具
2、終端獲取PC機通過串口發來的數據,並且單播給協調器,協調器收到數據後打印到串口調試器上
四、具體操作
1、首先在我們的工程模板SampleApp.c內添加我們的頭文件
#include "mt_uart.h"
#include "string,h"
#include "MT.h" //新的頭文件,我們要輪詢串口任務裏的事件,這些事件包含在這個頭文件中
2、串口初始化,串口打印、波特率的設置以及關閉流控
void SampleApp_Init( uint8 task_id )
{
SampleApp_TaskID = task_id;
SampleApp_NwkState = DEV_INIT;
SampleApp_TransID = 0;
MT_UartInit ();
//這次要添加一個串口任務註冊,只有註冊了串口任務,我們纔可以去檢測串口任務裏的某一個事件
MT_UartRegisterTaskID(task_id); //mt_uart.h 117行
HalUARTWrite ( 0, "uart0 is ok\n", strlen("uart0 is ok\n"));
#if !defined( MT_UART_DEFAULT_OVERFLOW )
#define MT_UART_DEFAULT_OVERFLOW FALSE
#endif
#if !defined MT_UART_DEFAULT_BAUDRATE
#define MT_UART_DEFAULT_BAUDRATE HAL_UART_BR_115200
#endif
3、協調器和終端配置
//協調器以廣播的形式發送給終端
SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;
SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;
//終端以單播的方式發送給協調器
SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)Addr16Bit; //單播形式
SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT;
SampleApp_Flash_DstAddr.addr.shortAddr = 0x0000; //協調器地址
再往下的端口描述符無需改動,組播相關代碼註釋掉
4、進入事件輪詢函數
檢測到網絡狀態改變之後,我們不再需要週期性的發送數據,只在有串口數據到來的時候發送數據
先看一下串口數據的格式
typedef struct
{
osal_event_hdr_t hdr;//數據頭
uint8 *msg; //指針,指向一個數組,數組的第一個元素是數據長度,後邊的纔是真正的數據
} mtOSALSerialData_t;
我們需要在事件輪詢中加入一個新的情況 有串口數據到達
case CMD_SERIAL_MSG://代表有串口數據的到達
SerialData_Analysis(((mtOSALSerialData_t *)MSGpkt)->msg);
break;
5、串口消息到達之後,我們通過調用下面的函數將其發送出去
void SerialData_Analysis(uint8 *msg)
{
if(zgDeviceLogicalType == ZG_DEVICETYPE_COORDINATOR)
{
AF_DataRequest( &SampleApp_Periodic_DstAddr, &SampleApp_epDesc,
SAMPLEAPP_PERIODIC_CLUSTERID,
*msg,
msg+1,
&SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
}
else if(zgDeviceLogicalType == ZG_DEVICETYPE_ENDDEVICE )
{
AF_DataRequest( &SampleApp_Flash_DstAddr, &SampleApp_epDesc,
SAMPLEAPP_FLASH_CLUSTERID,
*msg,
msg+1,
&SampleApp_TransID,
AF_DISCV_ROUTE,
AF_DEFAULT_RADIUS );
}
}
6、接收到的數據處理
那麼數據發送出去之後,我們就要接收數據後的處理
事件輪詢:有新的無線消息到達
調用 SampleAPP_MessageMSGCB(MSGpkt)
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
uint16 flashTime;
switch ( pkt->clusterId )
{
case SAMPLEAPP_PERIODIC_CLUSTERID:
HalUARTWrite ( 0, pkt->cmd.Data, pkt->cmd.DataLength );
break;
case SAMPLEAPP_FLASH_CLUSTERID:
HalUARTWrite ( 0, pkt->cmd.Data, pkt->cmd.DataLength );
break;
}
}
7、 最後,有一個問題,我們設置的事件輪詢中,case CMD_SERIAL_MSG:這一事件並沒有真正觸發。
那爲什麼不能觸發呢?
我們來看 mt_uart.c文件:
我們在進行串口初始化的時候,我們可以看到協議棧是利用一個結構體,對結構體的成員變量的一個賦值,在串口初始化中,有一個回調函數
只要執行了串口初始化函數,就要去執行這一個回調函數
而回調函數內纔是真正觸發我們設立的,有串口數據到達這一事件的。
但我們剛剛的代碼,並沒有觸發這一事件
沒有觸發的原因如下:
協議棧對串口數據的封裝有着明確的格式要求,如果我們沒有按照這個格式來傳送數據,那麼我們的串口數據是收不到,事件是觸發不了的
8、爲了簡便,我們也可以對回調函數進行一個處理,使其能夠發送我們未封裝的串口數據。
函數如下:
void MT_UartProcessZToolData ( uint8 port, uint8 event )
{
uint8 ch,len = 0;
uint8 uartData[128]; //定義一個數據暫存數組
uint8 i;
(void)event; //
while(Hal_UART_RxBufLen(port)) //只要檢測到串口緩存區有數據
{
HalUARTRead(port,&ch,1);//就把數據一個一個的傳輸給ch變量
uartData[len+1] = ch; //再把ch的數據傳給數組
len++;
}
if(len)
{
uartData[0] = len; //第一個元素設爲數據長度
pMsg = (mtOSALSerialData_t *)osal_msg_allocate(sizeof(mtOSALSerialData_t)+len+1);
//爲串口數據包分配內存
}
if(pMsg)
{
pMsg->hdr.event = CMD_SERIAL_MSG; //設置串口數據到達事件
pMsg->msg=(uint8*)(pMsg+1); //把數據定位到結構體數據部分
for(i=0;i<=len;i++)
pMsg->msg[i]=uartData[i]; //再把暫存區數據放入串口數據中
osal_msg_send(App_TaskID,(byte*)pMsg); //把數據包發往消息隊列
}
osal_msg_deallocate((uint8*)pMsg); //分配的內存用完後記得刪除,以免內存溢出
}