●通過ZigBee協(xié)議棧實現(xiàn)一個簡單的無線數(shù)據(jù)通信的時候怎么做绘沉?
①組網(wǎng):調(diào)用協(xié)議棧的組網(wǎng)函數(shù)、加入網(wǎng)絡(luò)函數(shù),實現(xiàn)網(wǎng)絡(luò)的建立與節(jié)點的加入米丘。
②發(fā)送:發(fā)送節(jié)點調(diào)用協(xié)議棧的無線數(shù)據(jù)發(fā)送函數(shù)赶撰,實現(xiàn)無線數(shù)據(jù)發(fā)送舌镶。
③接收:接收節(jié)點調(diào)用協(xié)議棧的無線數(shù)據(jù)接收函數(shù),實現(xiàn)無線數(shù)據(jù)接收豪娜。
●無線數(shù)據(jù)發(fā)送函數(shù)
AF_DataRequest(
&SampleApp_Periodic_DstAddr,?//發(fā)送目的地址+端點地址和傳送模式
&SampleApp_epDesc,?//源(答復(fù)或確認(rèn))終端的描述(比如操作系統(tǒng)中任務(wù)ID等)源EP
SAMPLEAPP_PERIODIC_CLUSTERID, //被Profile指定的有效的集群號
2, // 發(fā)送數(shù)據(jù)長度len
SendData, // 發(fā)送數(shù)據(jù)緩沖區(qū)
&SampleApp_TransID,?// 任務(wù)ID號
AF_DISCV_ROUTE,?// 有效位掩碼的發(fā)送選項
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )? //傳送跳數(shù)餐胀,通常設(shè)置為AF_DEFAULT_RADIUS
●osal_init_system(); 系統(tǒng)初始化函數(shù),我們關(guān)注其中的osalInitTask();
void osalInitTasks( void )
{
uint8 taskID = 0;?// 分配內(nèi)存瘤载,返回指向緩沖區(qū)的指針
tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);?// 設(shè)置所分配的內(nèi)存空間單元值為0
osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));// 任務(wù)優(yōu)先級由高向低依次排列否灾,高優(yōu)先級對應(yīng)taskID 的值反而小
macTaskInit( taskID++ );? //macTaskInit(0) ,用戶不需考慮
nwk_init( taskID++ );? ? //nwk_init(1)鸣奔,用戶不需考慮
Hal_Init( taskID++ );? ? //Hal_Init(2) 坟冲,用戶需考慮
#if defined( MT_TASK )
MT_TaskInit( taskID++ );
#endif
APS_Init( taskID++ );? ? ? //APS_Init(3) ,用戶不需考慮
#if defined ( ZIGBEE_FRAGMENTATION )
APSF_Init( taskID++ );
#endif
ZDApp_Init( taskID++ );? ? //ZDApp_Init(4) 溃蔫,用戶需考慮
#if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )
ZDNwkMgr_Init( taskID++ );
#endif
//用戶創(chuàng)建的任務(wù)
SampleApp_Init( taskID );? // SampleApp_Init _Init(5) 健提,用戶需考慮
}
●osal_start_system(); 運(yùn)行操作系統(tǒng)。關(guān)注osal_run_system();
void osal_run_system( void )
{
? uint8 idx = 0;
? osalTimeUpdate(); ?//掃描哪個事件被觸發(fā)伟叛,然后置相應(yīng)的標(biāo)志位
? Hal_ProcessPoll(); ?//輪詢TIMER 與UART
? do {
? ? if (tasksEvents[idx])? // Task is highest priority that is ready.
? ? {
? ? ? ?break; ?//得到待處理的最高優(yōu)先級任務(wù)索引號 idx
? ? }
? } while (++idx < tasksCnt);
if (idx < tasksCnt)
{
? uint16 events;
? halIntState_t intState;
? HAL_ENTER_CRITICAL_SECTION(intState); ?//進(jìn)入臨界區(qū)私痹,保護(hù)
? events = tasksEvents[idx]; ?//提取需要處理的任務(wù)中的事件
? tasksEvents[idx] = 0;? // 清除本次任務(wù)的事件
? HAL_EXIT_CRITICAL_SECTION(intState); ?//退出臨界區(qū)
? activeTaskID = idx; ?
? events = (tasksArr[idx])( idx, events );
? activeTaskID = TASK_NO_TASK;
? HAL_ENTER_CRITICAL_SECTION(intState);
? tasksEvents[idx] |= events;? // 保存為處理的事件 Add back unprocessed events to the current task.
? HAL_EXIT_CRITICAL_SECTION(intState); ?//退出臨界區(qū)
}
#if defined( POWER_SAVING )
? else? // Complete pass through all task events with no activity?
? {
? ? osal_pwrmgr_powerconserve();? // Put the processor/system into sleep
? }
#endif
/* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
? {
? ? osal_task_yield();
#endif
}
●SampleApp_Init(); 用戶應(yīng)用任務(wù)初始化函數(shù)。
void SampleApp_Init( uint8 task_id )
{
SampleApp_TaskID = task_id;? //osal分配的任務(wù)ID隨著用戶添加任務(wù)的增多而改變
SampleApp_NwkState = DEV_INIT;//設(shè)備狀態(tài)設(shè)定為ZDO層中定義的初始化狀態(tài)
SampleApp_TransID = 0;? ? ? ? //消息發(fā)送ID(多消息時有順序之分)
// Device hardware initialization can be added here or in main() (Zmain.c).
// If the hardware is application specific - add it here.
// If the hardware is other parts of the device add it in main().
#if defined ( BUILD_ALL_DEVICES )
// The "Demo" target is setup to have BUILD_ALL_DEVICES and HOLD_AUTO_START
// We are looking at a jumper (defined in SampleAppHw.c) to be jumpered
// together - if they are - we will start up a coordinator. Otherwise,
// the device will start as a router.
if ( readCoordinatorJumper() )
zgDeviceLogicalType = ZG_DEVICETYPE_COORDINATOR;
else
zgDeviceLogicalType = ZG_DEVICETYPE_ROUTER;
#endif // BUILD_ALL_DEVICES
//該段的意思是统刮,如果設(shè)置了HOLD_AUTO_START宏定義紊遵,將會在啟動芯片的時候會暫停啟動
//流程,只有外部觸發(fā)以后才會啟動芯片侥蒙。其實就是需要一個按鈕觸發(fā)它的啟動流程暗膜。
#if defined ( HOLD_AUTO_START )
// HOLD_AUTO_START is a compile option that will surpress ZDApp
//? from starting the device and wait for the application to
//? start the device.
ZDOInitDevice(0);
#endif
// Setup for the periodic message's destination address 設(shè)置發(fā)送數(shù)據(jù)的方式和目的地址尋址模式
// Broadcast to everyone 發(fā)送模式:廣播發(fā)送
SampleApp_Periodic_DstAddr.addrMode = (afAddrMode_t)AddrBroadcast;//廣播
SampleApp_Periodic_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; //指定端點號
SampleApp_Periodic_DstAddr.addr.shortAddr = 0xFFFF;//指定目的網(wǎng)絡(luò)地址為廣播地址
// Setup for the flash command's destination address - Group 1 組播發(fā)送
SampleApp_Flash_DstAddr.addrMode = (afAddrMode_t)afAddrGroup; //組尋址
SampleApp_Flash_DstAddr.endPoint = SAMPLEAPP_ENDPOINT; //指定端點號
SampleApp_Flash_DstAddr.addr.shortAddr = SAMPLEAPP_FLASH_GROUP;//組號0x0001
// Fill out the endpoint description. 定義本設(shè)備用來通信的APS層端點描述符
SampleApp_epDesc.endPoint = SAMPLEAPP_ENDPOINT; //指定端點號
SampleApp_epDesc.task_id = &SampleApp_TaskID;? //SampleApp 描述符的任務(wù)ID
SampleApp_epDesc.simpleDesc
= (SimpleDescriptionFormat_t *)&SampleApp_SimpleDesc;//SampleApp簡單描述符
SampleApp_epDesc.latencyReq = noLatencyReqs;? ? //延時策略
// Register the endpoint description with the AF
afRegister( &SampleApp_epDesc );? ? //向AF層登記描述符
// Register for all key events - This app will handle all key events
RegisterForKeys( SampleApp_TaskID ); // 登記所有的按鍵事件
// By default, all devices start out in Group 1
SampleApp_Group.ID = 0x0001;//組號
osal_memcpy( SampleApp_Group.name, "Group 1", 7? );//設(shè)定組名
aps_AddGroup( SAMPLEAPP_ENDPOINT, &SampleApp_Group );//把該組登記添加到APS中
#if defined ( LCD_SUPPORTED )
HalLcdWriteString( "SampleApp", HAL_LCD_LINE_1 ); //如果支持LCD,顯示提示信息
#endif
}
●SampleApp_ProcessEvent(); 用戶應(yīng)用任務(wù)的事件處理函數(shù)鞭衩。
uint16 SampleApp_ProcessEvent( uint8 task_id, uint16 events )
{
afIncomingMSGPacket_t *MSGpkt;
(void)task_id;? // Intentionally unreferenced parameter
if ( events & SYS_EVENT_MSG ) //接收系統(tǒng)消息再進(jìn)行判斷
{
//接收屬于本應(yīng)用任務(wù)SampleApp的消息学搜,以SampleApp_TaskID標(biāo)記
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
while ( MSGpkt )
{
switch ( MSGpkt->hdr.event )
{
// Received when a key is pressed
case KEY_CHANGE://按鍵事件
SampleApp_HandleKeys( ((keyChange_t *)MSGpkt)->state, ((keyChange_t *)MSGpkt)->keys );
break;
// Received when a messages is received (OTA) for this endpoint
case AF_INCOMING_MSG_CMD://接收數(shù)據(jù)事件,調(diào)用函數(shù)AF_DataRequest()接收數(shù)據(jù)
SampleApp_MessageMSGCB( MSGpkt );//調(diào)用回調(diào)函數(shù)對收到的數(shù)據(jù)進(jìn)行處理
break;
// Received whenever the device changes state in the network
case ZDO_STATE_CHANGE:
//只要網(wǎng)絡(luò)狀態(tài)發(fā)生改變娃善,就通過ZDO_STATE_CHANGE事件通知所有的任務(wù)。
//同時完成對協(xié)調(diào)器瑞佩,路由器聚磺,終端的設(shè)置
SampleApp_NwkState = (devStates_t)(MSGpkt->hdr.status);
//if ( (SampleApp_NwkState == DEV_ZB_COORD)//實驗中協(xié)調(diào)器只接收數(shù)據(jù)所以取消發(fā)送事件
if ( (SampleApp_NwkState == DEV_ROUTER) || (SampleApp_NwkState == DEV_END_DEVICE) )
{
// Start sending the periodic message in a regular interval.
//這個定時器只是為發(fā)送周期信息開啟的,設(shè)備啟動初始化后從這里開始
//觸發(fā)第一個周期信息的發(fā)送炬丸,然后周而復(fù)始下去
osal_start_timerEx( SampleApp_TaskID,
SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT );
}
else
{
// Device is no longer in the network
}
break;
default:
break;
}
// Release the memory 事件處理完了瘫寝,釋放消息占用的內(nèi)存
osal_msg_deallocate( (uint8 *)MSGpkt );
// Next - if one is available 指針指向下一個放在緩沖區(qū)的待處理的事件,
//返回while ( MSGpkt )重新處理事件稠炬,直到緩沖區(qū)沒有等待處理事件為止
MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( SampleApp_TaskID );
}
// return unprocessed events 返回未處理的事件
return (events ^ SYS_EVENT_MSG);
}
// Send a message out - This event is generated by a timer
//? (setup in SampleApp_Init()).
if ( events & SAMPLEAPP_SEND_PERIODIC_MSG_EVT )
{
// Send the periodic message 處理周期性事件焕阿,
//利用SampleApp_SendPeriodicMessage()處理完當(dāng)前的周期性事件,然后啟動定時器
//開啟下一個周期性事情首启,這樣一種循環(huán)下去捣鲸,也即是上面說的周期性事件了,
//可以做為傳感器定時采集闽坡、上傳任務(wù)
SampleApp_SendPeriodicMessage();
// Setup to send message again in normal period (+ a little jitter)
osal_start_timerEx( SampleApp_TaskID, SAMPLEAPP_SEND_PERIODIC_MSG_EVT,
(SAMPLEAPP_SEND_PERIODIC_MSG_TIMEOUT + (osal_rand() & 0x00FF)) );
// return unprocessed events 返回未處理的事件
return (events ^ SAMPLEAPP_SEND_PERIODIC_MSG_EVT);
}
// Discard unknown events
return 0;
}
● SampleApp_MessageMSGCB();分析接收數(shù)據(jù)函數(shù)。
void SampleApp_MessageMSGCB( afIncomingMSGPacket_t *pkt )
{
uint16 flashTime;
byte buf[3];
switch ( pkt->clusterId ) //判斷簇ID
{
case SAMPLEAPP_PERIODIC_CLUSTERID: //收到廣播數(shù)據(jù)
osal_memset(buf, 0 , 3);
osal_memcpy(buf, pkt->cmd.Data, 2); //復(fù)制數(shù)據(jù)到緩沖區(qū)中
if(buf[0]=='D' && buf[1]=='1')? ? ? //判斷收到的數(shù)據(jù)是否為"D1"
{
HalLedBlink(HAL_LED_1, 0, 50, 500);//如果是則Led1間隔500ms閃爍
#if defined(ZDO_COORDINATOR) //協(xié)調(diào)器收到"D1"后,返回"D1"給終端愁溜,讓終端Led1也閃爍
SampleApp_SendPeriodicMessage();
#endif
}
else
{
HalLedSet(HAL_LED_1, HAL_LED_MODE_ON);
}
break;
case SAMPLEAPP_FLASH_CLUSTERID: //收到組播數(shù)據(jù)
flashTime = BUILD_UINT16(pkt->cmd.Data[1], pkt->cmd.Data[2] );
HalLedBlink( HAL_LED_4, 4, 50, (flashTime / 4) );
break;
}
}
● SampleApp_MessageMSGCB();分析接收數(shù)據(jù)函數(shù)疾嗅。
void SampleApp_SendPeriodicMessage( void )
{
byte SendData[3]="D1";
// 調(diào)用AF_DataRequest將數(shù)據(jù)無線廣播出去
if( AF_DataRequest( &SampleApp_Periodic_DstAddr,//發(fā)送目的地址+端點地址和傳送模式
&SampleApp_epDesc,//源(答復(fù)或確認(rèn))終端的描述(比如操作系統(tǒng)中任務(wù)ID等)源EP
SAMPLEAPP_PERIODIC_CLUSTERID, //被Profile指定的有效的集群號
2,? ? ? // 發(fā)送數(shù)據(jù)長度
SendData,// 發(fā)送數(shù)據(jù)緩沖區(qū)
&SampleApp_TransID,? ? // 任務(wù)ID號
AF_DISCV_ROUTE,? ? ? // 有效位掩碼的發(fā)送選項
AF_DEFAULT_RADIUS ) == afStatus_SUCCESS )? //傳送跳數(shù),通常設(shè)置為AF_DEFAULT_RADIUS
{
}
else
{
HalLedSet(HAL_LED_1, HAL_LED_MODE_ON);
// Error occurred in request to send.
}
}