日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

zstack流程梳理与串口事件详解及zigbee调试助手实现细节

發布時間:2023/12/20 编程问答 61 豆豆
生活随笔 收集整理的這篇文章主要介紹了 zstack流程梳理与串口事件详解及zigbee调试助手实现细节 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

聲明:本文撰寫時間為2019年6月,能力有限,有錯誤歡迎批評指正

首先先梳理一遍zstack的流程

協議棧的文件包層次結構:

  • App:應用層目錄,這是用戶創建各種不同工程的區域,在這個目錄中包含了應用層的內容和這個項目的主要內容,在協議中一般是以操作系統的任務實現的。

  • HAL:硬件層目錄,包含有與硬件相關的配置和驅動及操作函數

  • MAC:MAC層目錄,包含了MAC層的參數配置文件及其MAC的LIB庫的函數接口文件

  • MT:實現通過串口可控制各層,并與各層進行直接交互

  • NWK:網絡層目錄,包含網絡層配置參數文件網絡層庫的函數接口文件及APS層庫的函數接口

  • OSAL:協議棧的操作系統

  • Profile:AF(Applicationframework應用框架)層目錄

  • Security:安全層目錄,包含安全層處理函數,比如加密函數等

  • Services:地址處理函數目錄,包括地址模式的定義及地址處理函數

  • Tools: 工程配置目錄,包括空間劃分及Z-Stack相關配置信息

  • ZDO:ZDO目錄

  • ZMac:MAC層目錄,包括MAC層參數配置及MAC層LIB庫函數回調處理函數

  • ZMain:主函數目錄,包括入口函數及硬件配置文件

  • Output:輸出文件目錄,由IAR IDE自動生成

一些名詞

英文中文含義備注
EndPoint端點是協議棧應用層的入口,即入口地址,也可以理解應用對象(Application Object)存在的地方,它是為實現一個設備描述而定義的一組群集端點0 :用于整個ZigBee設備的配置和管理,附屬在端點0的對象被稱為ZigBee設備對象(ZD0)
端點255:用于向所有的端點進行廣播
端點241~254:保留端點
其他端點:映射應用對象,并使得應用程序可以跟ZigBee堆棧其他層進行通信。
Cluster一個具體的應用(例如智能家居系統)有大量細節上的小規范例如電燈的控制:開燈、關燈等)這個規范即成為簇
COORDINATOR協調器協調器是整個網絡的核心,它最主要的作用是啟動網絡,其方法是其方法是選擇一個相對空閑的信道,形成一個PANID
Router路由器路由器的主要功能是提供接力作用,能擴展信號的傳輸范圍,因此一般情況下應該一直處于活動狀態,不應休眠。終端設備可以睡眠也可以喚醒,因此可以用電池來供電。
Channel信道2.4GHz的射頻頻段被分為16個獨立的信道。每一個設備都有一個默認的信道集(DEFAULT_CHANLIST)。協調器掃描自己的默認信道并選擇噪聲最小的信道作為自己所建的網絡信道。設備節點和路由器也要掃描默認信道集并選擇信道上已經存在的網絡加入。
PANID網絡編號PANID指網絡編號,用于區分不同的網絡設備,PANID值與ZDAPP_CONFIG_PAN_ID的值設定有關。如果協調器的ZDAPP_CONFIG_PAN_ID設置為0xFFFF,則協調器將產生一個隨機的PANID,如果路由器和終端節點的ZDAPP_CONFIG_PAN_ID設置為0xFFFF,路由器和終端節點將會在自己默認信道上隨機的選擇一個網絡加入,網絡協調器的PANID即為自己的PANID。如果協調器的ZDAPP_CONFIG_PAN_ID設置為非0xFFFF值,則協調器根據自己的網絡長地址(IEEE地址)或ZDAPP_CONFIG_PAN_ID隨機產生PANID的值。不同的是如果路由器和終端節點的ZDAPP_CONFIG_PAN_ID 的值設置為非0xFFFF,則會以ZDAPP_CONFIG_PAN_ID值作為PANID。如果協調器的值設為小于等于0x3FFF的有效值,協調器就會以這個特定的PANID值建立網絡,但是如果在默認信道上已經有了該PANID值的網絡存在,則協調器會繼續搜尋其它的PANID,直到找到不沖突的網絡為止,這樣就可能產生一個問題如果協調器在默認信道上發生PANID沖突而更換PANID,終端節點并不知道協調器已經更換了PANID,還會繼續加入到PANID為ZDAPP_CONFIG_PAN_ID值的網絡中

在main函數中:

int main( void ) {// Turn off interrupts//關閉中斷osal_int_disable( INTS_ALL );//初始化硬件// Initialization for board related stuff such as LEDsHAL_BOARD_INIT();// Make sure supply voltage ishigh enough to run//電壓檢測,確保芯片能正常工作的電壓zmain_vdd_check();// Initialize board I/O//初始化板載I/OInitBoard( OB_COLD );// Initialze HAL drivers//初始化硬件驅動HalDriverInit();// Initialize NV System//初始化NV系統osal_nv_init( NULL );// Initialize the MAC//初始化MACZMacInit();// Determine the extended address//確定擴展地址(64位IEEE/物理地址)zmain_ext_addr(); #if defined ZCL_KEY_ESTABLISH// Initialize the Certicom certificate information.// 初始化CERT認證系統zmain_cert_init(); #endif// Initialize basic NVitems//初始化基本NV條目zgInit(); #ifndef NONWK//Since the AF isn't a task, call it's initialization routine//如果task里沒有AF任務,需要在此調用他的初始化函數afInit(); #endif// Initialize the operating system//初始化操作系統osal_init_system();...}

其中的osal_init_system便是操作系統的初始化,里面包含了os中各個app以及os各組成部分的初始化方法的調用,比如:初始化內存,堆棧等,其中對app的初始化函數為osalInitTasks();

uint8 osal_init_system( void ) {// Initialize the Memory Allocation System//初始化內存分配系統osal_mem_init();// Initialize the message queue//初始化消息隊列 任務之間的通信靠的就是消息隊列osal_qHead = NULL;// Initialize the timers//初始化定時器osalTimerInit();// Initialize the Power Management System//初始化電源管理系統osal_pwrmgr_init();//osal_mem_alloc()該函數是OSAL中的內存管理函數,是一個存儲分配函數,返回指向一個緩存的指針,參數是被分配緩存的大小,其tasksCnt的定義如下const uint8tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );tasksEvents指向被分配的內存空間,這里注意tasksArr[]函數指針數組的聯系是一一對應的。tasksEvents就是指向第一個被分配的任務的內存空間tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);//把申請的內存空間全部設置為0,tasksCnt任務數 * 單個任務占的內存空間(4byte)osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));// Initialize the system tasks.//初始化系統任務,重點關注osalInitTasks();// Setup efficient search for the first free block of heap.//設置有效的查找堆上的第一個空閑塊osal_mem_kick();return ( SUCCESS ); }

任務初始化函數-------osalInitTasks();

void osalInitTasks( void ) {uint8 taskID = 0;//下面就是Z-Stack協議棧中,從MAC層到ZDO層的初始化函數,其中的參數都是任務的ID,不過ID號是依次遞增的macTaskInit(taskID++ ); //mac_ID = 0nwk_init( taskID++ ); //nwk_ID = 1Hal_Init( taskID++ ); //Hal_ID = 2 #if defined( MT_TASK )MT_TaskInit( taskID++ );//mt_ID = 3 #endifAPS_Init( taskID++ ); //APS_ID =4 #if defined ( ZIGBEE_FRAGMENTATION )APSF_Init(taskID++ ); //ZDO_ID =5 #endifZDApp_Init( taskID++ ); ;//ZDO_ID =6 #if defined ( ZIGBEE_FREQ_AGILITY ) ||defined ( ZIGBEE_PANID_CONFLICT )ZDNwkMgr_Init( taskID++ ); //ZDO_ID =7 #endif //協議棧工程下如果選擇Coordinator或EndDevice或Router工程則只會進入這個 #if defined(SAPP_ZSTACK)sapp_taskInitProcess();//ZDO_ID =8 #endif //協議棧工程下如果選擇Deemo工程則只會進入這個 #if defined(SAPP_ZSTACK_DEMO)// 任務建立實驗范例代碼// 啟動定時器osal_start_timerEx(taskID, 0x0001, 1000);//ZDO_ID =8 #endif }

追蹤到sapp_taskInitProcess,這里便是app的初始化函數了,在這個協議棧中,app只有一個,但這個app是一個管理很多小功能的APP,所有的小功能被放在functionlist里統一管理

void sapp_taskInitProcess(void) {#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;elsezgDeviceLogicalType = ZG_DEVICETYPE_ROUTER; #endif // BUILD_ALL_DEVICES#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// 構造功能列表funcTableBuffer = createFuncTable(funcCount);funcTableBuffer->ft_type = 0x01;funcTableBuffer->ft_count = funcCount;int i;for(i = 0; i < funcCount; i++){funcTableBuffer->ft_list[i].type = funcList[i].function.type;funcTableBuffer->ft_list[i].id = funcList[i].function.id;funcTableBuffer->ft_list[i].cycle = funcList[i].function.cycle;}controlTaskId = tasksCnt - 2;functionTaskId = tasksCnt - 1;HalIOInit(functionTaskId);createEndPoint(&controlEndPointInfo, &controlTaskId, CONTROL_ENDPOINT);for(i = 0; i < funcCount; i++){struct ep_info_t *ep = &funcList[i];createEndPoint(ep, &functionTaskId, i + 1);if(ep->res_available)(*ep->res_available)(ep, ResInit, NULL);} //這里選擇是否注冊串口事件 #if defined(ZDO_COORDINATOR)// || defined(RTR_NWK) // RegisterForKeys( SampleApp_TaskID );MT_UartRegisterTaskID(controlTaskId); #endif }

好了所有的初始化任務完成了,現在回到main中,再經過幾個初始化后就進入osal_start_system開始正式啟動OS了

...// Initialize the operating system//初始化操作系統osal_init_system();// Allow interrupts//使能中斷osal_int_enable( INTS_ALL );// Final board initialization//最終板載初始化InitBoard( OB_READY );// Display informationabout this device//顯示設備信息zmain_dev_info();/*Display the device info on the LCD *///添加LCD液晶屏的支持 #ifdef LCD_SUPPORTEDzmain_lcd_init(); #endif #ifdef WDT_IN_PM1/*If WDT is used, this is a good place to enable it. *///看門狗的初始化設置WatchDogEnable( WDTIMX ); #endifosal_start_system(); // No Return from here沒有返回,即進入操作系統return 0; // Shouldn't get here.//不會運行到這

進入osal_start_system發現這里有個死循環,也就是為什么main函數不return的原因

void osal_start_system( void ) { #if !defined ( ZBIT ) && !defined (UBIT )for(;;) // 一直循環,是“輪詢”中的輪,即不斷循環執行 #endif{osal_run_system();} }

進入osal_run_system中,osal_start_system函數是ZigBee協議棧的靈魂,實現的方法是不斷查詢事件表,如果有事情發生就調用相應的事件處理函數。

void osal_run_system( void ) {uint8 idx = 0;osalTimeUpdate();Hal_ProcessPoll();do {if (tasksEvents[idx]) // 這里就是“輪詢”中的詢,即不斷查詢,而且這個查詢是有優先級順序的{break;//如果有事件發生則跳出循環}} while (++idx < tasksCnt);//判斷是主動跳出循環還是全部判斷完跳出的循環if (idx < tasksCnt){uint16 events;halIntState_t intState;HAL_ENTER_CRITICAL_SECTION(intState);events = tasksEvents[idx];tasksEvents[idx] = 0; // 清除事件標志HAL_EXIT_CRITICAL_SECTION(intState);activeTaskID = idx;events = (tasksArr[idx])( idx, events );//調用相應的事件處理函數,tasksArr[]是一個函數指針數組,每一個元素都是函數指針activeTaskID = TASK_NO_TASK;HAL_ENTER_CRITICAL_SECTION(intState);tasksEvents[idx] |= events; // 如果沒有處理完可以再次設置標志HAL_EXIT_CRITICAL_SECTION(intState);} #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 }

這里可以去看我們的taskArr里有什么了

// 任務列表 const pTaskEventHandlerFn tasksArr[] = {macEventLoop,nwk_event_loop,Hal_ProcessEvent, #if defined( MT_TASK )MT_ProcessEvent, #endifAPS_event_loop, #if defined ( ZIGBEE_FRAGMENTATION )APSF_ProcessEvent, #endifZDApp_event_loop, #if defined ( ZIGBEE_FREQ_AGILITY ) || defined ( ZIGBEE_PANID_CONFLICT )ZDNwkMgr_event_loop, #endif #if defined(SAPP_ZSTACK)//重點,這兩個便是我們自己定義的事件處理函數sapp_controlEpProcess,sapp_functionEpProcess, #endif #if defined(SAPP_ZSTACK_DEMO)// Deemo工程對應的事件處理函數Hello_ProcessEvent, #endif }; //學習一下這里sizeof的用法,之后會經常用到 const uint8 tasksCnt = sizeof(tasksArr)/sizeof(tasksArr[0]);

這里的taskArr(包含系統級任務如macEventLoop等和用戶app如sapp_functionEpProcess)非常像我們平常使用的操作系統里的任務管理器里的任務(圖中包含了系統自帶應用如windowServer何kernel_task等,也包括了用戶app如QQ),對于我們的OS來說,多個網絡應用是通過端口號(圖中如果有一份數據包發給QQ則會發送給0.0.0.0:1194)來區分的,而對于OSAL來說,接收到一份數據包決定將數據包發送給哪個app則是通過數據包中指定的EndPoint決定的。

比如這一份數據包,就會被發送到EndPoint為0x01的task里。


進入第一個app的處理函數sapp_controlEpProcess,這里主要是為了配合zigbee調試助手使用,原來是讓協調器接收PC中的ZigBee調試助手里發送的命令幀,以及解析命令幀里命令,01對應發送functionlist,02對應發送拓撲信息,03對應發送function的數據?關于zigbee調試助手的原理在最后面會講一下。

uint16 sapp_controlEpProcess(uint8 task_id, uint16 events) {afIncomingMSGPacket_t *MSGpkt;//如果是系統事件if ( events & SYS_EVENT_MSG ){//message要通過osal_msg_send發送也要對應通過osal_msg_receive接收MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(task_id);while ( MSGpkt ){//HalUARTWrite(0, &MSGpkt->hdr.event,1);switch ( MSGpkt->hdr.event ){ #if defined(ZDO_COORDINATOR)//如果是串口事件case CMD_SERIAL_MSG:uartMsgProcesser((uint8 *)MSGpkt);HalLedBlink( HAL_LED_1, 2, 50, 90 );break; #endif#if ! defined(ZDO_COORDINATOR) && defined(RTR_NWK)//如果是串口事件case CMD_SERIAL_MSG:uartMsgProcesser1((uint8 *)MSGpkt);HalLedBlink( HAL_LED_1, 2, 50, 90 );break; #endif// Received when a messages is received (OTA) for this endpoint//如果收到了無線數據包case AF_INCOMING_MSG_CMD:{// TODO: QueryProfile or QueryTopo//先判斷是不是跟自己一個clusterswitch(MSGpkt->clusterId){case SAPP_PERIODIC_CLUSTERID:switch(MSGpkt->cmd.Data[0]){case 0x01:// CtrlQueryProfile//這個也是配合zigbee調試助手使用的,目的是顯示functionlist里有幾個functionSendData(CONTROL_ENDPOINT, funcTableBuffer->ft_data, MSGpkt->srcAddr.addr.shortAddr, MSGpkt->srcAddr.endPoint, sizeof(FUNCTABLE) + funcCount * sizeof(FUNCINFO));break;case 0x02:// CtrlQueryTopo//如果是查詢拓撲信息的命令幀則把自己的拓撲數據發送給源地址(也就是協調器)這個是配合zigbee調試助手顯示拓撲結構功能使用的,原理在之后會講SendData(CONTROL_ENDPOINT, (unsigned char *)&topoBuffer, MSGpkt->srcAddr.addr.shortAddr, MSGpkt->srcAddr.endPoint, sizeof(TOPOINFO));break;case 0x03:// CtrlQuerySpecialFunction//也是配合zigbee調試助手使用的,應該是發送function里的數據{uint8 i;for(i = 0; i < funcTableBuffer->ft_count; i++){if((funcTableBuffer->ft_list[i].type == MSGpkt->cmd.Data[1])&& (funcTableBuffer->ft_list[i].id == MSGpkt->cmd.Data[2])){// 0x03, EndPoint, rCycleuint8 specialFunc[3] = { 0x03, i + 1, funcTableBuffer->ft_list[i].cycle };SendData(CONTROL_ENDPOINT, specialFunc, MSGpkt->srcAddr.addr.shortAddr, MSGpkt->srcAddr.endPoint, sizeof(specialFunc));break;}}}break;default:{int i;for(i = 0; i < funcCount; i++){struct ep_info_t *ep = &funcList[i];if(ep->res_available) (*ep->res_available)(ep, ResControlPkg, MSGpkt);//執行對應的資源可用函數}}break;}HalLedBlink( HAL_LED_2, 1, 50, 250 );break;}break;}// Received whenever the device changes state in the network//如果是網絡狀態改變信息case ZDO_STATE_CHANGE:{devStates_t st = (devStates_t)(MSGpkt->hdr.status);if ( (st == DEV_ZB_COORD)|| (st == DEV_ROUTER)|| (st == DEV_END_DEVICE) ){ // topoBuffer->type = 0x02;//改變自己存儲的拓撲結構數據memcpy(topoBuffer.IEEE, NLME_GetExtAddr(), 8); #if !defined(ZDO_COORDINATOR)topoBuffer.PAddr = NLME_GetCoordShortAddr(); #elsetopoBuffer.PAddr = 0xFFFF; #endifosal_memcpy(&topoBuffer.panid, &_NIB.nwkPanId, sizeof(uint16));osal_memcpy(&topoBuffer.channel, &_NIB.nwkLogicalChannel, sizeof(uint8));//向協調器發送拓撲信息SendData(CONTROL_ENDPOINT, (unsigned char *)&topoBuffer, 0x0000, TRANSFER_ENDPOINT, sizeof(TOPOINFO));HalLedBlink( HAL_LED_2, 4, 50, 250 );}}break;default:break;}// Release the memoryosal_msg_deallocate( (uint8 *)MSGpkt );// Next - if one is availableMSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( task_id );}// return unprocessed eventsreturn (events ^ SYS_EVENT_MSG);}// 定時器時間到, 遍歷所有端點看是否有userTimerif(events & SAPP_SEND_PERIODIC_MSG_EVT){int i;uint8 hasUserTimer = 0;for(i = 0; i < funcCount; i++){struct ep_info_t *ep = &funcList[i];if(ep->userTimer && ep->res_available){hasUserTimer = 1;ep->userTimer = ep->userTimer - 1;if(ep->userTimer <= 1){ep->userTimer = 0;(*ep->res_available)(ep, ResUserTimer, NULL);//執行對應的超時函數}}}if(hasUserTimer){// 重新啟動定時器osal_start_timerEx(task_id, SAPP_SEND_PERIODIC_MSG_EVT, 1000);}else{isUserTimerRunning = 0;osal_stop_timerEx(task_id, SAPP_SEND_PERIODIC_MSG_EVT);}// return unprocessed eventsreturn (events ^ SAPP_SEND_PERIODIC_MSG_EVT);}// Discard unknown eventsreturn 0; }

最后進入sapp_functionEpProcess看看,這里主要是根據事件執行的functionlist里對應的定義的那些函數

uint16 sapp_functionEpProcess(uint8 task_id, uint16 events) {afIncomingMSGPacket_t *MSGpkt;if(events & SYS_EVENT_MSG){MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( task_id );while ( MSGpkt ){switch ( MSGpkt->hdr.event ){// 接收到數據包case AF_INCOMING_MSG_CMD:{switch ( MSGpkt->clusterId ){case SAPP_PERIODIC_CLUSTERID:if(MSGpkt->endPoint <= funcCount){struct ep_info_t *ep = &funcList[MSGpkt->endPoint - 1];if(ep->incoming_data)(*ep->incoming_data)(ep, MSGpkt->srcAddr.addr.shortAddr, MSGpkt->srcAddr.endPoint, &MSGpkt->cmd);//執行對應的incoming處理函數HalLedBlink( HAL_LED_2, 1, 50, 250 );}break;}}break;case ZDO_STATE_CHANGE:{curNwkState = (devStates_t)(MSGpkt->hdr.status);if ( (curNwkState == DEV_ZB_COORD)|| (curNwkState == DEV_ROUTER)|| (curNwkState == DEV_END_DEVICE) ){int i;int hasTimeOut = 0;for(i = 0; i < funcCount; i++){struct ep_info_t *ep = &funcList[i];if(ep->nwk_stat_change)(*ep->nwk_stat_change)(ep);// 重置端點計數器if(ep->time_out && ep->function.cycle){ep->timerTick = ep->function.cycle;hasTimeOut = 1;}}if(hasTimeOut){// 加入網絡成功,啟動定時器,為各個端點提供定時osal_start_timerEx(task_id,SAPP_SEND_PERIODIC_MSG_EVT,1000);}}elseosal_stop_timerEx(task_id, SAPP_SEND_PERIODIC_MSG_EVT);}break;//IO事件case IOPORT_INT_EVENT:{OSALIOIntData_t* IOIntData;IOIntData =(OSALIOIntData_t*)MSGpkt;if(IOIntData->endPoint <= funcCount){struct ep_info_t *ep = &funcList[IOIntData->endPoint - 1];if(ep->res_available)(*ep->res_available)(ep, ResIOInt, IOIntData->arg);//執行對應的資源可用處理函數}}break; #if defined(HAL_IRDEC) && (HAL_IRDEC == TRUE)case IRDEC_INT_EVENT: //{OSALIRDecIntData_t* TimerIntData = (OSALIRDecIntData_t*)MSGpkt;if(TimerIntData->endPoint <= funcCount){struct ep_info_t *ep = &funcList[TimerIntData->endPoint - 1];if(ep->res_available)(*ep->res_available)(ep, ResTimerInt, TimerIntData->data);}}break; #endifdefault:break;}// Release the memoryosal_msg_deallocate( (uint8 *)MSGpkt );// Next - if one is availableMSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive( task_id );}// return unprocessed eventsreturn (events ^ SYS_EVENT_MSG);}// 定時器時間到, 遍歷所有端點看是否有需要調用time_outif(events & SAPP_SEND_PERIODIC_MSG_EVT){int i;for(i = 0; i < funcCount; i++){struct ep_info_t *ep = &funcList[i];if(ep->time_out && ep->function.cycle){// 端點需要周期執行ep->timerTick = ep->timerTick - 1;if(ep->timerTick == 0){// 定時時間到,執行time_out函數(*ep->time_out)(ep);ep->timerTick = ep->function.cycle;}} #if 0if(ep->userTimer && ep->res_available){ep->userTimer = ep->userTimer - 1;if(ep->userTimer <= 1){(*ep->res_available)(ep, ResUserTimer, NULL);ep->userTimer = 0;}} #endif}// 重新啟動定時器osal_start_timerEx(task_id, SAPP_SEND_PERIODIC_MSG_EVT, 1000);// return unprocessed eventsreturn (events ^ SAPP_SEND_PERIODIC_MSG_EVT);}// Discard unknown eventsreturn 0; }

Zigbee 串口事件

UART(通用串口)是由zigbee協議棧中的MT層主管的,因此要在預編譯選項中添加上ZTOOL_P1或ZAPP_P1和MT_TASK

相關的文件有:

  • MT_UART.c
  • MT_UART.h

略過硬件層的一些關于串口的初始化后,我們又回到了OSAL的初始化函數,在這里面有個非常重要的函數MT_TaskInit,這里面是對MT層的一系列設置。

void osalInitTasks( void ) {uint8 taskID = 0;//下面就是Z-Stack協議棧中,從MAC層到ZDO層的初始化函數,其中的參數都是任務的ID,不過ID號是依次遞增的macTaskInit(taskID++ ); //mac_ID = 0nwk_init( taskID++ ); //nwk_ID = 1Hal_Init( taskID++ ); //Hal_ID = 2 #if defined( MT_TASK )MT_TaskInit( taskID++ );//mt_ID = 3...

追蹤進去后:

void MT_TaskInit(uint8 task_id) {MT_TaskID = task_id;/* Initialize the Serial port *///初始化UartMT_UartInit();/* Register taskID - Do this after UartInit() because it will reset the taskID *///注冊事件MT_UartRegisterTaskID(task_id);osal_set_event(task_id, MT_SECONDARY_INIT_EVENT); }

其中的UartInit中

void MT_UartInit () {halUARTCfg_t uartConfig;/* Initialize APP ID */App_TaskID = 0;/* UART Configuration *///設置為已配置uartConfig.configured = TRUE;//設置為默認波特率115200uartConfig.baudRate = MT_UART_DEFAULT_BAUDRATE;//設置是否采用流控及流控設置uartConfig.flowControl = MT_UART_DEFAULT_OVERFLOW;uartConfig.flowControlThreshold = MT_UART_DEFAULT_THRESHOLD;//設置最大發送緩沖區長度128uartConfig.rx.maxBufSize = MT_UART_DEFAULT_MAX_RX_BUFF;//設置最大接收緩沖區長度128uartConfig.tx.maxBufSize = MT_UART_DEFAULT_MAX_TX_BUFF;//設置超時時間uartConfig.idleTimeout = MT_UART_DEFAULT_IDLE_TIMEOUT;uartConfig.intEnable = TRUE; #if defined (ZTOOL_P1) || defined (ZTOOL_P2)//重要:設置串口回調函數uartConfig.callBackFunc = MT_UartProcessZToolData1; #elif defined (ZAPP_P1) || defined (ZAPP_P2)uartConfig.callBackFunc = MT_UartProcessZAppData; #elseuartConfig.callBackFunc = NULL; #endif/* Start UART */ #if defined (MT_UART_DEFAULT_PORT)//開啟UARTHalUARTOpen (MT_UART_DEFAULT_PORT, &uartConfig); #else/* Silence IAR compiler warning */(void)uartConfig; #endif/* Initialize for ZApp */ #if defined (ZAPP_P1) || defined (ZAPP_P2)/* Default max bytes that ZAPP can take */MT_UartMaxZAppBufLen = 1;MT_UartZAppRxStatus = MT_UART_ZAPP_RX_READY; #endif}

追蹤這個回調函數發現這個是我自己寫的回調函數,自己添加新的回調函數時要在MT_UART.h里面聲明

//自定義的串口接收回調函數 void MT_UartProcessZToolData1 ( uint8 port, uint8 event ) {uint8 flag = 0,i,j = 0; //flag判斷有沒有數據,j記錄數據長度uint8 buf[128]; //緩沖128(void)event;while(Hal_UART_RxBufLen(port)) //檢測串口數據是否完成{HalUARTRead(port,&buf[j],1);//數據接收到bufj++;flag = 1;}if(flag == 1) //有數據時{//分配內存,結構體+內容+長度pMsg = (mtOSALSerialData_t *)osal_msg_allocate( sizeof( mtOSALSerialData_t )+j+1);pMsg->hdr.event = CMD_SERIAL_MSG;//事件類型選擇為CMD_SERIAL_MSGpMsg->msg = (uint8*)(pMsg+1); //把數據定位到結構體pMsg->msg [0]= j; //記錄數據長度for(i=0;i<j;i++)pMsg->msg [i+1]= buf[i];osal_msg_send( App_TaskID, (byte *)pMsg ); // 登記任務并發往上層osal_msg_deallocate ( (uint8 *)pMsg ); // 釋放內存} }//原本的回調函數,在后面講zigbee調試助手原理的時候會講到,暫時不用管 void MT_UartProcessZToolData ( uint8 port, uint8 event ) {uint8 ch;uint8 bytesInRxBuffer;(void)event; // Intentionally unreferenced parameterwhile (Hal_UART_RxBufLen(port)){HalUARTRead (port, &ch, 1);switch(state){...}

注意串口事件也要在這里注冊才行

void sapp_taskInitProcess(void) {... //這里選擇是否注冊串口事件 #if defined(ZDO_COORDINATOR)// || defined(RTR_NWK) // RegisterForKeys( SampleApp_TaskID );MT_UartRegisterTaskID(controlTaskId); #endif }

這樣我們回到sapp_controlEpProcess函數中,就可以對串口事件進行處理了,在這里路由器和協調器的處理函數是不同的

uint16 sapp_controlEpProcess(uint8 task_id, uint16 events) {afIncomingMSGPacket_t *MSGpkt;if ( events & SYS_EVENT_MSG ){//HalLedBlink( HAL_LED_1, 2, 50, 90 );MSGpkt = (afIncomingMSGPacket_t *)osal_msg_receive(task_id);while ( MSGpkt ){//HalUARTWrite(0, &MSGpkt->hdr.event,1);switch ( MSGpkt->hdr.event ){ #if defined(ZDO_COORDINATOR)case CMD_SERIAL_MSG:uartMsgProcesser((uint8 *)MSGpkt);HalLedBlink( HAL_LED_1, 2, 50, 90 );break; #endif#if ! defined(ZDO_COORDINATOR) && defined(RTR_NWK)case CMD_SERIAL_MSG:uartMsgProcesser1((uint8 *)MSGpkt);HalLedBlink( HAL_LED_1, 2, 50, 90 );break; #endif

Zigbee調試助手原理

  • 解析的思路
  • 注意到在CMD_SERIAL_MSG事件中有讓LED1閃兩下的代碼,實際現象中是當點擊ZigBee調試助手的打開端口按鈕時,LED1和LED2都閃,而且經過一段固定的時間后也會都閃,而控制LED1閃是在發送無線數據包出現的。
  • case CMD_SERIAL_MSG:uartMsgProcesser((uint8 *)MSGpkt);HalLedBlink( HAL_LED_1, 2, 50, 90 );break;
  • 注意到在這個case里還有一句uartMsgProcesser,追蹤進去發現這個函數的功能是將受到的數據包進行解析,然后把數據包里的數據按照數據包里的地址發送出去,并且這個數據包里還有一個cmd和一個cmdEndPoint的幀控制域,只有當這兩個控制域分別為0x0018和0xF1時才會觸發發送數據包的函數,由此我們可以推測,PC通過串口發來了一串具有特定格式的數據包,協調器對數據包進行解析,然后把數據包里的數據發送到數據包里的目的地址。
  • static uint8 uartMsgProcesser(uint8 *msg) {mtOSALSerialData_t *pMsg = (mtOSALSerialData_t *)msg;mtUserSerialMsg_t *pMsgBody = (mtUserSerialMsg_t *)pMsg->msg;if ( (curNwkState != DEV_ZB_COORD)&& (curNwkState != DEV_ROUTER)&& (curNwkState != DEV_END_DEVICE) )return 1;switch(pMsgBody->cmd){case 0x0018:{switch(pMsgBody->cmdEndPoint){case 0xF1:{// 轉發數據SendData(TRANSFER_ENDPOINT, pMsgBody->data,pMsgBody->addr, pMsgBody->endPoint,pMsgBody->len - 6);}break;}}break;}return 1;
  • 那么這個數據包長什么樣子呢,我們追蹤到MT層中的串口回調函數,終于發現了官方對于這個數據包的格式定義,SOP(Start Of Packet我猜的)根據抓包的結果,發現一直是0x02,至于是什么含義在后面會講到;我們繼續看這個函數,發現他完成了對一個數據包的解析和FSC校驗。
  • #if defined (ZTOOL_P1) || defined (ZTOOL_P2) /**************************************************************************************************** @fn MT_UartProcessZToolData** @brief | SOP | CMD |Data Length| cmdEP | Address | EndPoint | Data | FSC |* | 1 | 2 | 1 | 2 | 2 | 1 | 1 ~119 | 1 |** Parses the data and determine either is SPI or just simply serial data* then send the data to correct place (MT or APP)** @param port - UART port* event - Event that causes the callback*** @return None***************************************************************************************************/ void MT_UartProcessZToolData ( uint8 port, uint8 event ) {uint8 ch;uint8 bytesInRxBuffer;(void)event; // Intentionally unreferenced parameterwhile (Hal_UART_RxBufLen(port)){//讀數據緩沖區HalUARTRead (port, &ch, 1);//判斷幀域類型switch(state){//如果是SOP控制域case SOP_STATE://如果是MT層的UART的SOPif(ch == MT_UART_SOF)state = LEN_STATE;break;//如果是長度控制域case LEN_STATE:if(ch < 7){// 不合法的長度state = SOP_STATE;// 直接丟棄了break;}//合法后開始構建一個數據包pMsg = (mtOSALSerialData_t *)osal_msg_allocate(sizeof(mtOSALSerialData_t) +ch + 3);//SOP+LEN+FSCtempDataLen = 0;/* Allocate memory for the data */ // pMsg = (mtOSALSerialData_t *)osal_msg_allocate(sizeof(mtOSALSerialData_t) + sizeof(mtUserSerialMsg_t) + // ch - 5);if (pMsg){/* Fill up what we can *///把能填的都填上,這里的事件類型CMD_SERIAL_MSG就是我們在處理函數里判斷的事件類型pMsg->hdr.event = CMD_SERIAL_MSG;pMsg->msg = (uint8*)(pMsg + 1);pMsgContent = (mtUserSerialMsg_t *)pMsg->msg;pMsgContent->sop = MT_UART_SOF;pMsgContent->len = ch;state = DATA_STATE;}else{pMsgContent = NULL;state = SOP_STATE;return;}break;//如果是數據域case DATA_STATE:pMsgContent->dataBody[tempDataLen++] = ch;/* Check number of bytes left in the Rx buffer */bytesInRxBuffer = Hal_UART_RxBufLen(port);/* If the remain of the data is there, read them all, otherwise, just read enough *///讀到數據域結束if (bytesInRxBuffer <= pMsgContent->len - tempDataLen){HalUARTRead (port, &pMsgContent->dataBody[tempDataLen], bytesInRxBuffer);tempDataLen += bytesInRxBuffer;}else{HalUARTRead (port, &pMsgContent->dataBody[tempDataLen], pMsgContent->len - tempDataLen);tempDataLen += (pMsgContent->len - tempDataLen);}/* If number of bytes read is equal to data length, time to move on to FCS */if ( tempDataLen == pMsgContent->len )state = FCS_STATE;break;//進行幀校驗 case FCS_STATE:/* Make sure it's correct */{pMsgContent->fsc = ch;uint8 fcs = MT_UartCalcFCS(0, &pMsgContent->len, 1);fcs = MT_UartCalcFCS(fcs, pMsgContent->dataBody, pMsgContent->len);if(fcs == ch)//如果對了那就把數據包發送給應用層osal_msg_send(App_TaskID, (byte *)pMsg);elseosal_msg_deallocate((uint8 *)pMsg);}/* Reset the state, send or discard the buffers at this point */state = SOP_STATE;break;default:break;}} }
  • 這里也就解釋里為什么我們要重寫他的串口回調函數,因為我們在串口調試助手里發送的數據包在這個回調函數看來是不合法的都被丟棄了,而且也是因為我們不想做這么麻煩的數據包,不過壞處也是有的,就是由于沒有幀校驗位,導致很多數據包的內容都出錯了,因此最好保留一位校驗位,如果可以的話可以自己實現一個漢明碼校驗,這樣就不用重發數據了。

  • 接下來繼續觀察實驗現象,發現zigbee調試助手打開后只有一個協調器節點,等待一會(大概十秒)后才突然出現子節點,同時接收LED燈閃爍,子節點的發送LED燈閃爍,這時整個流程就很清晰了:

  • zigbee調試助手周期性地發送一個特定格式的串口數據包給協調器

  • 協調器接收到后對數據包進行解析發送給應用層并觸發CMD事件

  • 在CMD的事件處理函數中向廣播地址(包括協調器)發送命令幀

  • 所有設備接收到命令幀后在處理函數里立即向協調器發送拓撲信息包

  • 協調器接收到拓撲信息包后將報文通過串口寫給電腦

  • 電腦中的zigbee調試助手分析拓撲信息包中的節點父子關系繪制圖像

  • 下面我們驗證一下整個流程。步驟123在上面已經介紹了。

  • 步驟5的實現源碼在functionlist中協調器的接收到數據包的處理函數里:

  • void CoordinatorIncomingRoutine(struct ep_info_t *ep, uint16 addr, uint8 endPoint, afMSGCommandFormat_t *msg) {if(msg->DataLength > 0){mtUserSerialMsg_t *pMsg = osal_mem_alloc(sizeof(mtUserSerialMsg_t) + msg->DataLength - 1);//在這里可以看到,為什么SOP一直是0x02,因為這里的MT_UART_SOP就是0x02,也就是串口事件規定的SOPpMsg->sop = MT_UART_SOF;//長度pMsg->len = msg->DataLength + 6;//命令位pMsg->cmd = 0x0018;//處理命令的endpointpMsg->cmdEndPoint = 0xF1;//網絡地址pMsg->addr = addr;//endpointpMsg->endPoint = endPoint;//數據區memcpy(pMsg->data, msg->Data, msg->DataLength);//幀校驗pMsg->fsc = MT_UartCalcFCS(0, &pMsg->len, 1);pMsg->fsc = MT_UartCalcFCS(pMsg->fsc, pMsg->dataBody, pMsg->len);//將整個數據包通過串口寫給電腦HalUARTWrite(HAL_UART_PORT_0, &pMsg->sop, sizeof(mtUserSerialMsg_t) - 2 + msg->DataLength);HalUARTWrite(HAL_UART_PORT_0, &pMsg->fsc, 1);//不釋放會死機osal_mem_free(pMsg);} }
  • 通過并聯一個USB轉TTL的小工具,連接傳感器安裝孔中的P0.2(TXD),和P0.3(RXD)截獲了協調器向PC發送的數據包:
  • 可以看到最后一行是一個終端節點發送的一個數據,數據的內容是字符串"Z-Stack for SAPP",他在zigbee調試助手中如下圖所示(這個圖是后來補的并不完全一致,當時的實驗情況與此圖類似)

    注意打開某個節點時可能會出現多個傳感器標簽0,1,2等,對應的就是ENDPORT。

  • 這樣Ubiqua之類的軟件實現原理也明白了,通過抓取所有的數據包,利用數據包中目的地址、源地址、PANID等信息分析出節點的父子層級,最終把拓撲圖繪制出來。
  • 最后總結的zigbee調試助手繪制拓撲圖及遠程控制實現內部原理

  • zigbee調試助手周期性地發送一個特定格式的串口數據包給協調器

  • 協調器接收到后對數據包進行解析發送給應用層并觸發CMD事件

  • 在CMD的事件處理函數中向廣播地址(包括協調器)發送命令幀

  • 所有設備接收到命令幀后在處理函數里立即向協調器發送拓撲信息包

  • 協調器接收到拓撲信息包后將報文通過串口寫給電腦

  • 電腦中的zigbee調試助手分析拓撲信息包中的節點父子關系繪制圖像

  • 總結

    以上是生活随笔為你收集整理的zstack流程梳理与串口事件详解及zigbee调试助手实现细节的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    中国成人一区 | 四虎在线观看视频 | 久草视频手机在线 | 精品视频久久 | 成人免费网站视频 | 日韩一区二区三区免费视频 | 亚洲精品视频免费在线 | 国产精品v欧美精品v日韩 | 91精品啪在线观看国产 | 久久久蜜桃一区二区 | 亚洲女欲精品久久久久久久18 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 久久99久久99精品 | 久久精品美女视频网站 | 蜜臀av在线一区二区三区 | 亚洲精品xxx | 国产小视频免费观看 | 中文字幕av免费在线观看 | 手机在线欧美 | 国产精品24小时在线观看 | 亚洲精品中文字幕在线观看 | 精品成人a区在线观看 | 亚洲欧美乱综合图片区小说区 | 在线三级播放 | 日日碰狠狠添天天爽超碰97久久 | 91久久丝袜国产露脸动漫 | 日韩高清不卡一区二区三区 | a级片网站 | 亚洲一二区精品 | 国产一区黄色 | 国产福利在线免费观看 | 亚洲精品国产第一综合99久久 | 国产精品av一区二区 | 四季av综合网站 | 久久久高清视频 | 99久久精品无免国产免费 | 国产精品久久久久久久久久了 | 日本韩国精品在线 | 亚洲精品成人在线 | 亚洲免费av在线 | 人人模人人爽 | 久久精品在线视频 | 超碰在线97免费 | 欧美性成人 | 三日本三级少妇三级99 | 麻豆视频免费版 | 最近中文字幕完整高清 | 久久免费观看少妇a级毛片 久久久久成人免费 | 天天摸夜夜添 | 精品一区在线看 | 在线视频18在线视频4k | av网站手机在线观看 | 精品日韩在线 | 国产原创在线观看 | 玖草影院 | 天天干 夜夜操 | www.狠狠色 | 在线观看免费黄视频 | 国产精品久久久久久影院 | www五月 | 天天干,天天操 | 欧美激情视频一区二区三区免费 | 色综合天天| 国产福利一区二区三区视频 | 久久久久网址 | 福利电影一区二区 | 69中文字幕 | 日本成人a | 日韩欧美一区二区三区免费观看 | 在线免费黄网站 | av大全在线 | 亚洲成av人片 | 久久久96 | 人人爽人人爽人人 | 久久99久久99精品免费看小说 | 日韩国产精品久久久久久亚洲 | 久久久穴 | 日韩欧美观看 | 免费中文字幕视频 | 在线亚洲高清视频 | 色噜噜在线观看视频 | 欧美日韩中文在线观看 | 色婷婷视频在线观看 | 在线激情小视频 | 久久影院中文字幕 | 欧美黑人性猛交 | 精品国产伦一区二区三区观看方式 | 国语自产偷拍精品视频偷 | 99精品视频免费观看 | 久草精品视频 | 国产黄色在线网站 | www.国产在线观看 | 国产成人福利在线 | 国产精品ⅴa有声小说 | 欧美男女爱爱视频 | 99久久婷婷国产一区二区三区 | a电影在线观看 | 亚洲一区二区高潮无套美女 | 国产精品久久久久一区二区三区共 | 99久久99久久 | 另类五月激情 | 国内精品久久久久久久久久清纯 | 免费视频国产 | 精品亚洲免费 | 成年人在线视频观看 | 日本韩国精品一区二区在线观看 | 婷婷成人综合 | 亚洲国产精品影院 | 亚洲精品高清在线观看 | 色综合久久66| 九九精品久久 | 中文字幕资源在线观看 | 91精品国产自产在线观看 | 婷婷免费视频 | 人人草人 | 激情影音 | 久热爱| 久久五月精品 | 日韩黄色免费 | 国产91精品欧美 | 99久久99久久免费精品蜜臀 | 色综合小说 | 婷婷久月 | 91人人爽久久涩噜噜噜 | 国产三级精品三级在线观看 | 91久久国产自产拍夜夜嗨 | 久久久久国产精品免费网站 | 三级黄色在线 | 精品亚洲免费视频 | www.五月天婷婷 | www久 | 97视频在线免费播放 | 亚洲国内在线 | 婷婷国产一区二区三区 | 久久久久9999亚洲精品 | 久久99热久久99精品 | 在线观看一级片 | www.黄色小说.com | 国产精品大全 | 午夜婷婷网 | 国产二区av | 免费成人在线观看视频 | 久久热首页 | 国产精品综合av一区二区国产馆 | 成人久久18免费网站 | h动漫中文字幕 | 久久激情视频 | 欧美一级电影在线观看 | 亚洲人av免费网站 | 黄色h在线观看 | 国产免费专区 | 精品一区 在线 | 国产精品18久久久久久久久久久久 | 日韩一片| 久久99深爱久久99精品 | 久久久久久久久影视 | 亚洲美女在线国产 | 亚州精品天堂中文字幕 | 日本乱码在线 | 国产精品久久久久久久久久东京 | 久久久亚洲精品 | 精品1区2区 | 午夜丰满寂寞少妇精品 | 九九99 | 天天做天天射 | 开心色激情网 | 国产精品入口传媒 | 国产成人免费网站 | 久草在线一免费新视频 | 日韩在线二区 | 最新高清无码专区 | 国内精品久久久久影院一蜜桃 | 日韩国产精品一区 | 久久久久久久久久电影 | 天天做日日做天天爽视频免费 | 久久成人午夜视频 | 高清中文字幕av | 超碰在线人人草 | 日韩av在线免费看 | 波多野结依在线观看 | 久久婷婷丁香 | 日韩欧美一区二区在线观看 | 2022久久国产露脸精品国产 | 久久精品a | 97超碰人人网 | 国产在线国偷精品产拍 | 九九免费在线视频 | 成年人视频免费在线播放 | 亚洲成av人片在线观看香蕉 | 玖玖视频免费在线 | 国产在线永久 | 日本99热| 五月天天天操 | 国产精品v欧美精品v日韩 | 激情影院在线 | 中文字幕资源在线观看 | 丁香六月婷婷综合 | 国产成人1区 | www.com.黄 | 亚洲精品视频久久 | 色天堂在线视频 | 玖玖视频免费在线 | 天天爽夜夜爽精品视频婷婷 | 国产精品日韩 | 激情视频免费在线观看 | 一区二区三区高清 | 97日日碰人人模人人澡分享吧 | 久久精品麻豆 | 国产免费作爱视频 | 久草精品视频在线看网站免费 | 婷婷久月 | 国产黄a三级三级 | av在线一二三区 | 国产精品美女久久久久久久久 | 最新日韩视频在线观看 | 黄色网址中文字幕 | 精品99视频| 中午字幕在线观看 | 国产一区免费观看 | 亚洲精品乱码久久久久久高潮 | 久久成人午夜 | 成人毛片在线视频 | 国产精品成人久久 | 91精品免费视频 | 免费在线播放 | 91在线欧美| 国产精品久久久久一区二区国产 | .国产精品成人自产拍在线观看6 | 深爱激情久久 | 国产色视频一区二区三区qq号 | 亚洲高清视频一区二区三区 | 国产亚洲精品久久 | av免费网站观看 | 天天插狠狠干 | 亚洲视频一区二区三区在线观看 | 韩日电影在线免费看 | 久久丁香 | 中文字幕电影网 | 天天拍天天色 | 久久黄网站 | 91综合视频在线观看 | 欧美国产日韩激情 | 91在线免费播放视频 | 久久综合五月天婷婷伊人 | 免费在线观看91 | 三级av网站 | 国产高清专区 | 中文字幕免费高清av | 在线中文字幕一区二区 | 久草免费在线视频观看 | 中文字幕免费国产精品 | 999视频在线观看 | 久久国产精品久久久 | 五月婷婷在线视频观看 | 狠狠色丁香婷婷综合久小说久 | 亚洲精品中文字幕视频 | 51久久成人国产精品麻豆 | 欧美精品一二三 | 911国产在线观看 | 国产精品嫩草影视久久久 | 亚洲国产免费网站 | 国产精品不卡在线观看 | 国产美女在线免费观看 | 精品一区二区在线看 | 国产高清中文字幕 | 欧美孕妇与黑人孕交 | 国产视频69 | av播放在线 | 久久午夜视频 | 日日日操 | 国产精品日韩 | 日韩激情av在线 | 久久精品福利 | 永久黄网站色视频免费观看w | 国产精品久久久视频 | 亚洲精品欧美精品 | 亚洲狠狠丁香婷婷综合久久久 | 国产视频在线观看免费 | 免费观看视频的网站 | 免费情缘 | 激情在线网站 | 五月天堂网 | 亚洲日本va午夜在线电影 | 精品欧美在线视频 | 黄色软件大全网站 | 婷婷激情五月综合 | 婷婷精品国产欧美精品亚洲人人爽 | 激情黄色av | 国产精品久久婷婷六月丁香 | 综合网伊人 | 国产成人一区二区啪在线观看 | 国产亚洲婷婷免费 | 最近高清中文字幕 | 国产一区精品在线 | 久久久片 | 超碰97网站 | 国产福利久久 | 国产精品久久一区二区三区不卡 | av在线免费网 | 亚洲欧美日本一区二区三区 | 在线黄色国产 | 91理论片午午伦夜理片久久 | 免费在线视频一区二区 | 在线免费试看 | 不卡av在线播放 | 午夜久久成人 | 欧美精品久久久久久久久久 | 亚洲精品tv久久久久久久久久 | 欧美狠狠色 | 国产精品无av码在线观看 | 91精品国产九九九久久久亚洲 | 色在线免费观看 | 亚洲高清在线 | 99精品久久精品一区二区 | 日韩在线视频线视频免费网站 | 日日操日日干 | 五月婷婷操 | a视频在线观看 | 国产99免费 | 国产精品一区二区美女视频免费看 | 亚洲区精品视频 | 久久国产色 | 一区二区三区在线看 | 亚洲视频每日更新 | 91资源在线 | 97成人精品视频在线观看 | h动漫中文字幕 | 日韩特级毛片 | 精品字幕 | 国产高清一区二区 | 在线免费色视频 | 超碰人人国产 | 亚洲一级久久 | av先锋影音少妇 | 成人av一级片 | 国产精品久久久久婷婷 | 成人性生交大片免费观看网站 | 99久久99久国产黄毛片 | 欧美一级高清片 | 精品福利在线 | 国产剧在线观看片 | 欧美视频在线二区 | 国产精品毛片久久久久久久 | 日本在线观看一区二区三区 | 国产精品久久久久久久久久了 | 99热在线国产 | 综合网伊人 | 最新色站| 夜色.com| 成年人在线看片 | 蜜桃视频日韩 | 久久久五月天 | 免费色婷婷 | 婷婷精品国产一区二区三区日韩 | 免费看三级| 91成人免费观看视频 | www.久久久.com | 啪啪av在线 | 成人性生活大片 | 日韩在线观看你懂的 | 狠狠操操网 | 91色亚洲 | 黄色三级网站 | 国产亚洲一区二区三区 | 黄色在线免费观看网站 | 69久久99精品久久久久婷婷 | 一区二区三区在线观看免费 | 国产高清av免费在线观看 | 日韩色综合网 | 深爱开心激情网 | 99久久99久久免费精品蜜臀 | 成人免费视频在线观看 | 国产伦精品一区二区三区高清 | av黄色在线观看 | 久久九九精品久久 | 免费在线观看av网址 | 国产精品高潮呻吟久久av无 | 狠狠色丁香婷婷综合橹88 | 免费视频你懂的 | 一级片免费视频 | 99精品欧美一区二区 | 亚州精品在线视频 | 国产精品久久久久久麻豆一区 | 亚洲高清国产视频 | 色99视频| 一区二区网 | 私人av | 午夜av片 | 国产a视频免费观看 | 国产香蕉久久精品综合网 | 午夜在线看片 | 探花系列在线 | 美女黄频在线观看 | avcom在线 | 国产色婷婷在线 | 激情久久一区二区三区 | 国产成a人亚洲精v品在线观看 | 日韩电影在线观看一区二区三区 | 黄色毛片网站在线观看 | 久久伦理视频 | 婷婷播播网 | 在线看国产精品 | 日日夜夜精品免费观看 | 中文字幕 欧美性 | 在线成人一区二区 | 久久精品美女视频网站 | 欧美一区二区伦理片 | 国内外成人免费在线视频 | 九九精品久久久 | 久久久色 | 超碰免费在线公开 | 久久精品视频免费 | 在线免费高清一区二区三区 | 欧美一级日韩三级 | 精品a视频| 91av电影在线观看 | 国产精品久久一区二区三区不卡 | 国产精品第 | 国精产品永久999 | 婷婷综合五月天 | 国产精品丝袜久久久久久久不卡 | 亚洲天堂精品 | 在线不卡视频 | 免费福利视频导航 | 97成人在线 | 99综合电影在线视频 | 国产精品久久久久久久婷婷 | 日韩精品免费一区二区在线观看 | 精品在线观看一区二区 | 久久久久久久久久久久久久免费看 | 9999在线观看| 天天操天天是 | 久久久亚洲影院 | 黄色精品免费 | 日韩素人在线观看 | 婷婷成人在线 | 免费在线观看国产精品 | 在线观看免费高清视频大全追剧 | 99久久er热在这里只有精品66 | 天天干一干 | 亚洲激情综合 | 夜夜高潮夜夜爽国产伦精品 | 免费观看av网站 | 色婷婷av一区二 | a极黄色片| 超碰人人草人人 | 亚洲va欧洲va国产va不卡 | 久福利 | 黄色软件网站在线观看 | 91成人在线观看喷潮 | 操操爽| 91最新国产 | 国产精品久久久久一区 | 国产精品视频免费看 | 韩国av免费看 | 成人国产亚洲 | 在线天堂8√| 激情五月婷婷激情 | 久久视频国产精品免费视频在线 | 草免费视频 | 亚洲日本一区二区在线 | www亚洲国产 | 成人h视频在线播放 | 高清中文字幕 | 夜夜干夜夜 | 日韩在线网址 | 久久精品视频2 | 在线观看91网站 | 992tv又爽又黄的免费视频 | 亚洲精品女| 一二三区在线 | 久久资源在线 | 中文字幕在线观看国产 | 狠狠干 狠狠操 | 国产精品一区二区三区四 | 精品久操 | 久久国产色 | 成人av网页 | 九九国产精品视频 | 色精品视频 | 国产精品美女久久久久久 | 96精品高清视频在线观看软件特色 | 久久尤物电影视频在线观看 | 国产精品久久久久国产精品日日 | 视频在线观看99 | 国产一区二区日本 | 久久三级毛片 | 91视频在线免费下载 | 97视频在线观看成人 | 在线三级av | 在线观看日本高清mv视频 | 日日操日日操 | 中文字幕区 | 成人一区不卡 | 久久久这里有精品 | 一区二区三区四区五区六区 | 伊人资源视频在线 | 欧美狠狠色 | 一区二区三区精品在线 | 日韩高清一 | 精品日韩中文字幕 | 久久桃花网 | 欧美一级片免费观看 | 久久99国产精品二区护士 | 亚洲色视频 | 欧美日韩精 | 亚洲精品视频在线免费播放 | 中文av网| 久久久www成人免费精品 | 久久天天操| 亚洲精品久久激情国产片 | 91中文在线 | 久久免费福利视频 | 少妇bbb搡bbbb搡bbbb′ | 在线观看mv的中文字幕网站 | 国产高清免费 | 久久精品中文 | 九九99 | 人成午夜视频 | 久久任你操 | 麻豆久久精品 | 国产a级片免费观看 | 成人福利在线观看 | 日日碰夜夜爽 | 久久精品国产亚洲精品2020 | av久久久 | 在线免费三级 | 视频国产 | 国产精品二区三区 | 国产小视频在线免费观看视频 | 日av免费| 日本3级在线观看 | 中文字幕在线中文 | 免费看片网页 | 亚洲综合视频网 | 欧美在线视频第一页 | 国产在线看 | 岛国精品一区二区 | 国产精品涩涩屋www在线观看 | 五月婷婷久久丁香 | 色资源中文字幕 | 国产精品99久久久精品免费观看 | 伊人导航 | 999久久精品 | 婷婷丁香av| 99自拍视频在线观看 | 国产福利免费在线观看 | 欧美日韩国产在线精品 | 国产精品18久久久久vr手机版特色 | 91国内在线视频 | 91久久久久久久一区二区 | 久久夜色精品亚洲噜噜国4 午夜视频在线观看欧美 | 免费观看91视频 | 国产精品久久久久久久久久99 | 久久婷亚洲五月一区天天躁 | 在线观看免费视频 | 国产日本在线观看 | 欧美日韩视频在线观看一区二区 | 黄色在线网站噜噜噜 | 国产精品亚洲片夜色在线 | 97在线观看免费视频 | 狠狠狠狠狠色综合 | 天天干.com | 91久久国产自产拍夜夜嗨 | 夜夜躁日日躁 | 在线观看精品一区 | 亚洲四虎影院 | 午夜久久网 | 久久综合九色综合欧美就去吻 | 免费观看mv大片高清 | 99精彩视频 | 国产精品美女视频网站 | 18av在线视频| 久久玖 | 国产亚洲精品成人av久久ww | 美女视频又黄又免费 | 日韩二区三区在线 | av福利资源 | 一区二三国产 | 91av九色| 激情深爱.com | 日本爱爱免费视频 | 亚洲电影成人 | 久久九九久久 | 四虎永久精品在线 | 免费看wwwwwwwwwww的视频 久久久久久99精品 91中文字幕视频 | 黄色片免费看 | 婷婷色网视频在线播放 | 亚洲乱亚洲乱妇 | 在线观看资源 | 亚洲乱码在线 | 国产精品久久久久久久久蜜臀 | 日日干天天干 | 很黄很色很污的网站 | 久操操 | 亚洲精品无 | 色视频在线免费观看 | 国产高清视频免费 | 91人人揉日日捏人人看 | 玖草影院| 欧美日韩精品电影 | 午夜性福利 | 黄色a在线观看 | 日韩三级一区 | 国产福利一区在线观看 | 麻豆视频免费网站 | 国产成人久久av免费高清密臂 | 激情综合五月网 | 欧美精品一区二区在线播放 | 亚洲精品国偷拍自产在线观看蜜桃 | 日韩系列在线 | 亚洲区二区 | 五月婷婷丁香网 | 亚洲一级二级 | 亚洲 欧美 变态 国产 另类 | 中文在线中文a | 日韩,精品电影 | 成人av影视在线 | 国产精品美女视频 | 永久免费av在线播放 | 国际av在线 | 在线看欧美| 西西4444www大胆视频 | 国产亚洲在线观看 | 国产一区影院 | 人人爱夜夜操 | 国产精品九九视频 | 美女久久视频 | 99视频| 国产亚洲精品成人av久久ww | 国产成人精品一区二区三区福利 | www免费 | a亚洲视频| 久草在线 | 午夜精品久久久久久久久久久久 | 天天干天天草天天爽 | 免费网站黄 | 96久久| 最近免费中文字幕大全高清10 | 久久久精华网 | 久草在线手机视频 | 一二三区视频在线 | 伊在线视频 | 欧美成人xxx | 免费视频成人 | 国产在线a不卡 | 开心色插 | 免费看毛片网站 | 久久久久久久久久久成人 | 大荫蒂欧美视频另类xxxx | 婷婷激情在线观看 | av天天草 | 成年美女黄网站色大片免费看 | 四虎在线影视 | 精品国产一二三四区 | 免费看国产视频 | 99久久精品国产亚洲 | 亚洲午夜精品一区二区三区电影院 | 在线观看黄色 | 国产精品久久99综合免费观看尤物 | 四虎影视久久久 | 色免费在线 | 精品国产诱惑 | 干天天| 成年人黄色大全 | 国产亚洲精品久久久久久久久久久久 | 亚洲一级片在线观看 | 成年人免费在线观看网站 | 国内精品视频一区二区三区八戒 | 国产香蕉久久 | 极品美女被弄高潮视频网站 | 色婷婷 亚洲 | 999视频网站 | 欧美精品视 | 国产精品免费观看国产网曝瓜 | 国产黄色免费在线观看 | 亚洲一级影院 | www.久久成人 | 视频二区在线视频 | 香蕉视频日本 | 精品黄色在线 | 综合五月 | 国产黄视频在线观看 | 欧美在线日韩在线 | 成人国产精品久久久久久亚洲 | 特级毛片在线免费观看 | 午夜丰满寂寞少妇精品 | 狠狠色丁婷婷日日 | 欧美黄色高清 | 500部大龄熟乱视频 欧美日本三级 | 久久性生活片 | 欧美乱大交 | 欧美xxxxx在线视频 | 国内精品久久天天躁人人爽 | 亚洲小视频在线观看 | 九色精品免费永久在线 | 91桃色视频| 最新黄色av网址 | 黄色成人在线观看 | 91麻豆看国产在线紧急地址 | 九九热国产视频 | 在线观看视频你懂的 | 手机在线免费av | www.com.黄| 999热视频| 国产成人精品一区二区在线观看 | 免费高清在线观看成人 | 久热久草在线 | 久99久在线视频 | 国产精品永久在线观看 | 久久激情婷婷 | 久久精品久久精品久久 | 伊人网av| 国产免费观看av | 国产一区二区三区高清播放 | 在线看国产视频 | www夜夜操com | 国产精品va在线观看入 | 国产精品久久一区二区三区, | 国产精品麻豆一区二区三区 | 蜜臀av一区二区 | 中文字幕在线观看完整版 | 中文字幕高清免费日韩视频在线 | 国产专区第一页 | 国产精品v a免费视频 | 亚洲精品日韩在线观看 | 国产中的精品av小宝探花 | 日韩毛片一区 | 人人盈棋牌 | 麻豆精品视频在线观看免费 | 99精品免费在线 | 天天操天天玩 | 美女av电影| 国产精品理论片在线播放 | 超碰在线99 | 欧美日韩不卡一区二区三区 | 国产一区二区中文字幕 | 啪啪精品 | 亚洲精品xxxx | 久久伊人五月天 | 韩日av一区二区 | 亚洲成a人片在线www | 制服丝袜天堂 | 天躁狠狠躁| 夜添久久精品亚洲国产精品 | 超碰在线1 | 国产中文在线观看 | av色影院| 中文国产在线观看 | 亚洲黄色在线免费观看 | 国产区久久 | 国产精品一区二区精品视频免费看 | 国产精品区免费视频 | 99视频在线精品国自产拍免费观看 | 人人草在线观看 | 亚洲精品在线国产 | 中文字幕有码在线播放 | 久久国产手机看片 | 999久久久久久久久久久 | 久久精品久久99精品久久 | 亚洲综合小说 | 最近中文字幕高清字幕在线视频 | 国产精品久久久久毛片大屁完整版 | 黄网站app在线观看免费视频 | 97人人艹| 国产精品第72页 | 欧美日韩一区二区三区在线免费观看 | 日韩视频在线不卡 | 高清国产一区 | 在线v片免费观看视频 | 欧美激情综合五月色丁香小说 | 国产高清日韩欧美 | 在线观看精品国产 | 亚洲激情 在线 | 国产在线97 | 精品电影一区 | 日韩区欠美精品av视频 | 91视频免费观看 | 91麻豆国产| 亚洲国产播放 | 国产在线一区二区 | 韩日三级在线 | av中文国产 | 成人av亚洲 | 久久久久久久福利 | 黄视频网站大全 | av免费在线播放 | 午夜精品三区 | 久久久久免费看 | 色丁香色婷婷 | 在线日韩av | 超碰97人 | 国产成人一区二 | 欧美日韩不卡一区二区三区 | 开心激情网五月天 | 五月天婷婷免费视频 | 婷婷色在线播放 | 日本久热 | 毛片网站免费 | 九九热在线观看 | 91系列在线观看 | 特级西西444www高清大视频 | 亚洲激情校园春色 | 国产一区高清在线 | 久久久久久国产精品亚洲78 | 欧美激情综合五月色丁香小说 | 国产一区在线免费观看 | av片在线观看 | www夜夜操com| 中文字幕 国产专区 | 五月婷婷六月丁香在线观看 | 激情欧美一区二区免费视频 | 婷婷丁香av| 岛国一区在线 | 涩涩网站免费 | 精品麻豆入口免费 | 精品999| 狠狠干天天射 | 一级黄色大片在线观看 | 日韩一区二区免费视频 | 国产手机av | 亚洲精品天天 | 欧美成人日韩 | 在线免费中文字幕 | 国产 日韩 在线 亚洲 字幕 中文 | 色噜噜噜| 在线播放视频一区 | 久久这里 | 日韩欧美视频二区 | 狠狠操导航 | 丝袜av网站 | 日韩剧| 国产高清区| 中文免费观看 | 又大又硬又黄又爽视频在线观看 | 国产美女精品视频免费观看 | 欧美日韩国产二区三区 | 中文字幕色播 | 国产精品网在线观看 | 欧美福利久久 | 久久免费一级片 | 97免费中文视频在线观看 | 亚洲视频六区 | 黄色亚洲| 成人小视频免费在线观看 | 色婷婷99| 久久免费一级片 | 日韩精品一二三 | 91伊人久久大香线蕉蜜芽人口 | 亚洲精品1234区 | 9999精品免费视频 | 精品主播网红福利资源观看 | 人人网人人爽 | 天天爽天天摸 | 久久久久五月天 | 午夜精品婷婷 | 又色又爽又黄高潮的免费视频 | 亚洲伊人第一页 | 国产精品99久久久久久武松影视 | 九九热免费在线视频 | 色婷婷五 | 最近中文字幕在线 | 国产精品久久久久一区二区三区共 | 国产 日韩 欧美 自拍 | 99久久精品免费看国产四区 | 精品国模一区二区 | 美女视频久久久 | 久久99国产精品二区护士 | 99免费在线播放99久久免费 | 免费色黄 | 成人在线免费视频 | 成人av网站在线观看 | 中文字幕在线免费看线人 | 四虎www com | 在线免费av网 | 久久手机免费观看 | 一区二区三区日韩精品 | 天天干,天天操,天天射 | 日韩中文字幕亚洲一区二区va在线 | 中文字幕在线观看免费观看 | 日韩视频在线观看免费 | 久草视频在线看 | 天天干天天干天天干 | 最近最新最好看中文视频 | 日韩在线三级 | 亚洲乱码精品久久久久 | 午夜国产一区二区三区四区 | 欧美精品中文在线免费观看 | 婷婷九九| 国产视频亚洲视频 | 亚洲成a人片77777kkkk1在线观看 | 婷婷激情综合 | 在线观看国产麻豆 | 人人爱爱人人 | 欧美激情视频在线免费观看 | 久久久久国产免费免费 | 国产精品福利视频 | 激情五月开心 | 国产在线精品一区二区 | 精品一区二三区 | 免费网站看v片在线a | 91亚·色| 99精品视频观看 | 亚洲精品乱码久久久久久蜜桃欧美 | 亚洲视频在线观看 | 日韩视频一区二区三区在线播放免费观看 | 在线观看免费高清视频大全追剧 | 日韩高清网站 | 91人人人| 免费三级大片 | 亚洲国内精品在线 | 日韩视频免费 | 国产福利av | 色丁香色婷婷 | 日本精品视频在线观看 | 日韩欧美高清免费 | 亚洲天天看 | 91av在线精品 | a爱爱视频| 欧美性成人 | 国产综合精品一区二区三区 | 色99中文字幕| 婷婷色中文字幕 | 97超视频 | 99re8这里有精品热视频免费 | 日产乱码一二三区别免费 | 性色av免费在线观看 | 97成人精品视频在线播放 | 五月婷婷一区二区三区 | 99久久精品日本一区二区免费 | 美女一区网站 | 岛国精品一区二区 | 丁香婷婷激情啪啪 | 国内少妇自拍视频一区 | 国产精品久久久久久久久久久久午夜 | 免费看片网页 | 久久99久久精品 | 国产精品中文在线 | 成年人黄色大全 | 欧美整片sss | 97超碰人人在线 | 亚洲另类视频在线 | 香蕉视频久久 | 国产成人av网址 | 午夜精品久久久久久久99无限制 | 日韩视频一区二区三区在线播放免费观看 | 射射射综合网 | 人人超在线公开视频 | 99久久精品电影 | 午夜影院一级 | 国产麻豆精品免费视频 | 狠狠色香婷婷久久亚洲精品 | 日韩欧美在线中文字幕 | 精品国产电影一区二区 | 天天综合网入口 | 天天干com | 久久精品国产99国产 | 日韩a在线播放 | 亚洲天堂毛片 | 国产免费不卡 | 我要看黄色一级片 | 久草在线视频首页 | 亚洲无吗天堂 | 视频 国产区| 国产视频久久久久 | 欧美亚洲精品一区 | 五月婷婷激情 | 日本精品在线 | 久久www免费视频 | 久久av观看| 国产免费三级在线观看 | 免费视频黄 | 久久精品99国产精品亚洲最刺激 | 精品96久久久久久中文字幕无 | 性色av免费看 | 国产精品av一区二区 | 国产伦精品一区二区三区… | 亚洲国产中文字幕 | 亚洲精品美女久久久久 | 久久久久久久久久久影视 | 少妇高潮流白浆在线观看 | 99视频在线免费 | 精品综合久久久 | 久草在线久| 免费影视大全推荐 | 欧美日韩在线播放一区 | 波多野结衣在线中文字幕 | 欧美日韩一区二区三区在线免费观看 | 精品999在线观看 | 国产黄色片在线 | 综合婷婷丁香 | 国产亚洲精品综合一区91 | 狠狠干网| 欧美日韩国产在线 | 国模精品在线 | 波多野结衣视频在线 | 久久中文字幕导航 | 精品天堂av |