色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

在嵌入式中使用設計模式的思想

嵌入式情報局 ? 來源:CSDN ? 2023-05-05 14:35 ? 次閱讀

1、嵌入式

嵌入式的標簽多為:低配,偏硬件,底層,資源緊張,代碼多以C語言匯編為主,代碼應用邏輯簡單。但隨著AIOT時代的到來,局面組件改變。芯片的性能資源逐漸提升,業務邏輯也逐漸變得復雜,相對于代碼的效率而言,代碼的復用可移植性要求越來越高,以獲得更短的項目周期 和更高的可維護性。下面是AIOT時代嵌入式設備的常見的軟件框架。

7344422e-eb0c-11ed-90ce-dac502259ad0.png

設計模式

設計模式的標簽:高級語言 ,高端,架構等。在AIOT時代,設計模式與嵌入式能擦出怎樣的火花?設計模式可描述為:對于某類相似的問題,經過前人的不斷嘗試,總結出了處理此類問題的公認的有效解決辦法。

嵌入式主要以C語言開發,且面向過程,而設計模式常見于高級語言(面向對象),目前市面上描述設計模式的書籍多數使用JAVA 語言,C語言能實現設計模式嗎?設計模式與語言無關,它是解決問題的方法,JAVA可以實現,C語言同樣可以實現。同樣的,JAVA程序員會遇到需要用模式來處理的問題,C程序員也可能遇見,因此設計模式是很有必要學習的。

模式陷阱:設計模式是針對具體的某些類問題的有效解決辦法,不是所有的問題都能匹配到對應的設計模式。因此,不能一味的追求設計模式,有時候簡單直接的處理反而更有效。有的問題沒有合適的模式,可以盡量滿足一些設計原則,如開閉原則(對擴展開放,對修改關閉)

2、觀察者模式

在對象之間定義一個一對多的依賴,當一個對象狀態改變的時候,所有依賴的對象都會自動收到通知。

735ad0c0-eb0c-11ed-90ce-dac502259ad0.png

實現

主題對象提供統一的注冊接口,以及注冊函數 。由觀察者本身實例化observer_intf 接口,然后使用注冊函數,添加到對應的主題列表中,主題狀態發生改變,依次通知列表中的所有對象。

structobserver_ops
{
void*(handle)(uint8_tevt);
};
structobserver_intf
{
structobserver_intf*next;
constchar*name;
void*condition;
conststructobserver_ops*ops;
}
intobserver_register(structtopical*top,structobserver_intf*observer);

當主題狀態發生改變,將通知到所有觀察者,觀察者本身也可以設置條件,是否選擇接收通知

structobserver_intfobserver_list;

voidXXXX_topical_evt(uint8_tevt)
{
structobserver_intf*cur_observer=observer_list.next;
uint8_t*condition=NULL;
while(cur_observer!=NULL)
{
condition=(uint8_t*)cur_observer->condition;
if(NULL==condition||(condition&&*condition))
{
if(cur_observer->ops->handle){
cur_observer->ops->handle(evt);
}
}
cur_observer=cur_observer->next;
}
}

實例:嵌入式裸機低功耗框架

設備功耗分布

7364c08a-eb0c-11ed-90ce-dac502259ad0.png

其中線路損耗,電源電路等軟件無法控制,故不討論。板載外設,如傳感器可能通過某條命令配置進入低功耗模式,又或者硬件上支持控制外設電源來控制功耗。片內外設,及芯片內部的外設,通過卸載相關驅動,關閉時鐘配置工作模式來控制功耗。

設備喚醒方式

當系統某個定時事件到來時,系統被主動喚醒處理事件

系統處于睡眠,被外部事件喚醒,如串口接收到一包數據,傳感器檢測到變化,通過引腳通知芯片

被動喚醒

主動喚醒

系統允許睡眠的條件

外設無正在收發的數據

緩存無需要處理的數據

應用層狀態處于空閑(無需要處理的事件)

基于觀察者模式的PM框架實現

PM組件提供的接口

structpm
{
structpm*next;
constchar*name;
void(*init)(void);
void(*deinit(void);
void*condition;
};
staticstructpmpm_list;
staticuint8_tpm_num;
staticuint8_tpm_status;

intpm_register(conststructpm*pm,constchar*name)
{
structpm*cur_pm=&pm_list;
while(cur_pm->next)
{
cur_pm=cur_pm->next;
}
cur_pm->next=pm;
pm->next=NULL;
pm->name=name;
pm_num++;
}

voidpm_loop(void)
{
uint32_tpm_condition=0;
structpm*cur_pm=pm_list.next;
staticuint8_tcnt;

/*checkallcondition*/
while(cur_pm)
{
if(cur_pm->condition){
pm_condition|=*((uint32_t*)(cur_pm->condition));
}
cur_pm=cur_pm->next;
}
if(pm_condition==0)
{
cnt++;
if(cnt>=5)
{
pm_status=READY_SLEEP;
}
}
else
{
cnt=0;
}
if(pm_status==READY_SLEEP)
{
cur_pm=pm_list.next;
while(cur_pm)
{
if(cur_pm->deinit){
cur_pm->deinit();
}
cur_pm=cur_pm->next;
}
pm_status=SLEEP;
ENTER_SLEEP_MODE();
}
/*sleep--->wakeup*/
if(pm_status==SLEEP)
{
pm_status=NORMAL;
cur_pm=pm_list.next;
while(cur_pm)
{
if(cur_pm->init){
cur_pm->init();
}
cur_pm=cur_pm->next;
}
}
}

外設使用PM接口

structuart_dev
{
...
structpmpm;
uint32_tpm_condition;
};
structuart_devuart1;

voidhal_uart1_init(void);
voidhal_uart1_deinit(void);

voiduart_init(void)
{
uart1.pm.init=hal_uart1_init;
uart1.pm.deinit=hal_uart1_deinit;
uart1.pm.condition=&uart1.pm_condition;
pm_register(&uart1.pm,"uart1");
}
/*接下來串口驅動檢查緩存,發送,接收是否空閑或者忙碌,給uart1.pm_condition賦值*/

結論

PM 電源管理可以單獨形成模塊,當功耗外設增加時,只需實現接口,注冊即可

通過定義段導出操作,可以更加簡化應用層或外設的注冊邏輯

方便調試,可以很方便打印出系統當前為滿足睡眠條件的模塊

通過條件字段劃分,應該可以實現系統部分睡眠

3、責任鏈模式

在現實生活中,一個事件(任務)需要經過多個對象處理是很常見的場景。如報銷流程,公司員工報銷, 首先員工整理報銷單,核對報銷金額,有誤則繼續核對整理,直到無誤,將報銷單遞交到財務,財務部門進行核對,核對無誤后,判斷金額數量,若小于一定金額,則財務部門可直接審批,若金額超過范圍,則報銷單流傳到總經理,得到批準后,整個任務才算結束。類似的情景還有很多,如配置一個WIFI模塊,通過AT指令,要想模塊正確連入WIFI , 需要按一定的順序依次發送配置指令 , 如設置設置模式 ,設置 需要連接的WIFI名,密碼,每發送一條配置指令,模塊都將返回配置結果,而發送者需要判斷結果的正確性,再選擇是否發送下一條指令或者進行重傳。

總結起來是,一系列任務需要嚴格按照時間線依次處理的順序邏輯,如下圖所示:

736e1fd6-eb0c-11ed-90ce-dac502259ad0.png

在存在系統的情況下,此類邏輯可以很容易的用阻塞延時來實現,實現如下:

voidprocess_task(void)
{
task1_process();
msleep(1000);

task2_process();
mq_recv(&param,1000);

task3_process();
while(mq_recv(¶m,1000)!=OK)
{
if(retry)
{
task3_process();
--try;
}
}
}

在裸機的情況下,為了保證系統的實時性,無法使用阻塞延時,一般使用定時事件配合狀態機來實現:

voidprocess_task(void)
{
switch(task_state)
{
casetask1:
task1_process();
set_timeout(1000);break;
casetask2:
task1_process();
set_timeout(1000);break;
casetask3:
task1_process();
set_timeout(1000)break;
default:break;
}
}
/*定時器超時回調*/
voidtimeout_cb(void)
{
if(task_state==task1)
{
task_state=task2;
process_task();
}
else//task2andtask3
{
if(retry)
{
retry--;
process_task();
}
}
}
/*任務的應答回調*/
voidtask_ans_cb(void*param)
{
if(task==task2)
{
task_state=task3;
process_task();
}
}

和系統實現相比,裸機的實現更加復雜,為了避免阻塞,只能通過狀態和定時器來實現順序延時的邏輯,可以看到,實現過程相當分散,對于單個任務的處理分散到了3個函數中處理,這樣導致的后果是:修改,移植的不便。而實際的應用中,類似的邏輯相當多,如果按照上面的方法去實現,將會導致應用程序的強耦合

實現

可以發現,上面的情景有以下特點:

任務按順序執行,只有當前任務執行完了(有結論,成功或者失敗)才允許執行下一個任務

前一個任務的執行結果會影響到下一個任務的執行情況

任務有一些特性,如超時時間,延時時間,重試次數

通過以上信息,我們可以抽象出這樣一個模型:任務作為節點, 每一個任務節點有其屬性:如超時,延時,重試,參數,處理方法,執行結果。當需要按照順序執行一系列任務時,依次將任務節點串成一條鏈,啟動鏈運行,則從任務鏈的第一個節點開始運行,運行的結果可以是 OK , BUSY ,ERROR 。若是OK, 表示節點已處理,從任務鏈中刪除,ERROR 表示運行出錯,任務鏈將停止運行,進行錯誤回調,可以有用戶決定是否繼續運行下去。BUSY表示任務鏈處于等待應答,或者等待延時的情況。當整條任務鏈上的節點都執行完,進行成功回調。

7375cd1c-eb0c-11ed-90ce-dac502259ad0.png

node數據結構定義

/*shadownodeapitypeforreq_chainsrc*/
typedefstructshadow_resp_chain_node
{
uint16_ttimeout;
uint16_tduration;
uint8_tinit_retry;
uint8_tparam_type;
uint16_tretry;
/*usedinmpool*/
structshadow_resp_chain_node*mp_prev;
structshadow_resp_chain_node*mp_next;

/*usedresp_chain*/
structshadow_resp_chain_node*next;

node_resp_handle_fphandle;
void*param;
}shadow_resp_chain_node_t;

node內存池

使用內存池的必要性:實際情況下,同一時間,責任鏈的條數,以及單條鏈的節點數比較有限,但種類是相當多的。比如一個支持AT指令的模塊,可能支持幾十條AT指令,但執行一個配置操作,可能就只會使用3-5條指令,若全部靜態定義節點,將會消耗大量內存資源。因此動態分配是必要的。

73822544-eb0c-11ed-90ce-dac502259ad0.png

初始化node內存池,內存池內所有節點都將添加到free_list。當申請節點時,會取出第一個空閑節點,加入到used_list , 并且接入到責任鏈。當責任鏈某一個節點執行完,將會被自動回收(從責任鏈中刪除,并從used_list中刪除,然后添加到free_list)

職責鏈數據結構定義

typedefstructresp_chain
{
boolenable;//enble==true責任鏈啟動
boolis_ans;//收到應答,與void*param共同組成應答信號

uint8_tstate;
constchar*name;
void*param;
TimerEvent_ttimer;
booltimer_is_running;
shadow_resp_chain_node_tnode;//節點鏈
void(*resp_done)(void*result);//執行結果回調
}resp_chain_t;

職責鏈初始化

voidresp_chain_init(resp_chain_t*chain,constchar*name,
void(*callback)(void*result))
{
RESP_ASSERT(chain);
/*onlyinitonetime*/
resp_chain_mpool_init();

chain->enable=false;
chain->is_ans=false;
chain->resp_done=callback;
chain->name=name;

chain->state=RESP_STATUS_IDLE;
chain->node.next=NULL;
chain->param=NULL;

TimerInit(&chain->timer,NULL);
}

職責鏈添加節點

intresp_chain_node_add(resp_chain_t*chain,
node_resp_handle_fphandle,void*param)
{
RESP_ASSERT(chain);
BoardDisableIrq();
shadow_resp_chain_node_t*node=chain_node_malloc();
if(node==NULL)
{
BoardEnableIrq();
RESP_LOG("nodemallocerror,nofreenode");
return-2;
}
/*初始化節點,并加入責任鏈*/
shadow_resp_chain_node_t*l=&chain->node;
while(l->next!=NULL)
{
l=l->next;
}
l->next=node;
node->next=NULL;
node->handle=handle;
node->param=param;
node->timeout=RESP_CHIAN_NODE_DEFAULT_TIMEOUT;
node->duration=RESP_CHIAN_NODE_DEFAULT_DURATION;
node->init_retry=RESP_CHIAN_NODE_DEFAULT_RETRY;
node->retry=(node->init_retry==0)?0:(node->init_retry-1);
BoardEnableIrq();
return0;
}

職責鏈的啟動

voidresp_chain_start(resp_chain_t*chain)
{
RESP_ASSERT(chain);
chain->enable=true;
}

職責鏈的應答

voidresp_chain_set_ans(resp_chain_t*chain,void*param)
{
RESP_ASSERT(chain);
if(chain->enable)
{
chain->is_ans=true;
if(param!=NULL)
chain->param=param;
else
{
chain->param="NOPARAM";
}
}
}

職責鏈的運行

intresp_chain_run(resp_chain_t*chain)
{
RESP_ASSERT(chain);
if(chain->enable)
{
shadow_resp_chain_node_t*cur_node=chain->node.next;
/*maybeansoccurinhandle,socannotchangestatedirectwhenanscomming*/
if(chain->is_ans)
{
chain->is_ans=false;
chain->state=RESP_STATUS_ANS;
}

switch(chain->state)
{
caseRESP_STATUS_IDLE:
{
if(cur_node)
{
uint16_tretry=cur_node->init_retry;
if(cur_node->handle)
{
cur_node->param_type=RESP_PARAM_INPUT;
chain->state=cur_node->handle((resp_chain_node_t*)cur_node,cur_node->param);
}
else
{
RESP_LOG("nodehandleisnull,gotonextnode");
chain->state=RESP_STATUS_OK;
}
if(retry!=cur_node->init_retry)
{
cur_node->retry=cur_node->init_retry>0?(cur_node->init_retry-1):0;
}
}
else
{
if(chain->resp_done)
{
chain->resp_done((void*)RESP_RESULT_OK);
}
chain->enable=0;
chain->state=RESP_STATUS_IDLE;
TimerStop(&chain->timer);
chain->timer_is_running=false;
}
break;
}
caseRESP_STATUS_DELAY:
{
if(chain->timer_is_running==false)
{
chain->timer_is_running=true;
TimerSetValueStart(&chain->timer,cur_node->duration);
}
if(TimerGetFlag(&chain->timer)==true)
{
chain->state=RESP_STATUS_OK;
chain->timer_is_running=false;
}
break;
}
caseRESP_STATUS_BUSY:
{
/*waitingforansortimeout*/
if(chain->timer_is_running==false)
{
chain->timer_is_running=true;
TimerSetValueStart(&chain->timer,cur_node->timeout);
}
if(TimerGetFlag(&chain->timer)==true)
{
chain->state=RESP_STATUS_TIMEOUT;
chain->timer_is_running=false;
}
break;
}
caseRESP_STATUS_ANS:
{
/*alreadygottheans,puttheparambacktotherequesthandle*/
TimerStop(&chain->timer);
chain->timer_is_running=false;
if(cur_node->handle)
{
cur_node->param_type=RESP_PARAM_ANS;
chain->state=cur_node->handle((resp_chain_node_t*)cur_node,chain->param);
}
else
{
RESP_LOG("nodehandleisnull,gotonextnode");
chain->state=RESP_STATUS_OK;
}
break;
}
caseRESP_STATUS_TIMEOUT:
{
if(cur_node->retry)
{
cur_node->retry--;
/*retrytorequestuntilcntis0*/
chain->state=RESP_STATUS_IDLE;
}
else
{
chain->state=RESP_STATUS_ERROR;
}
break;
}
caseRESP_STATUS_ERROR:
{
if(chain->resp_done)
{
chain->resp_done((void*)RESP_RESULT_ERROR);
}
chain->enable=0;
chain->state=RESP_STATUS_IDLE;
TimerStop(&chain->timer);
chain->timer_is_running=false;
cur_node->retry=cur_node->init_retry>0?(cur_node->init_retry-1):0;
chain_node_free_all(chain);
break;
}
caseRESP_STATUS_OK:
{
/*getthenextnode*/
cur_node->retry=cur_node->init_retry>0?(cur_node->init_retry-1):0;
chain_node_free(cur_node);
chain->node.next=chain->node.next->next;
chain->state=RESP_STATUS_IDLE;
break;
}
default:
break;
}
}
returnchain->enable;
}

測試用例

定義并初始化責任鏈

voidchain_test_init(void)
{
resp_chain_init(&test_req_chain,"testrequest",test_req_callback);
}

定義運行函數,在主循環中調用

voidchain_test_run(void)
{
resp_chain_run(&test_req_chain);
}

測試節點添加并啟動觸發函數

voidchain_test_tigger(void)
{
resp_chain_node_add(&test_req_chain,node1_req,NULL);
resp_chain_node_add(&test_req_chain,node2_req,NULL);
resp_chain_node_add(&test_req_chain,node3_req,NULL);
resp_chain_start(&test_req_chain);
}

分別實現節點請求函數

/*延時1s后執行下一個節點*/
intnode1_req(resp_chain_node_t*cfg,void*param)
{
cfg->duration=1000;
RESP_LOG("node1senddirectrequest:delay:%dms",cfg->duration);
returnRESP_STATUS_DELAY;
}
/*超時時間1S,重傳次數5次*/
intnode2_req(resp_chain_node_t*cfg,void*param)
{
staticuint8_tcnt;
if(param==NULL)
{
cfg->init_retry=5;
cfg->timeout=1000;
RESP_LOG("node2sendrequestmaxretry:%d,waitingforans...");
returnRESP_STATUS_BUSY;
}
RESP_LOG("node2getans:%d",(int)param);
returnRESP_STATUS_OK;
}
/*非異步請求*/
intnode3_req(resp_chain_node_t*cfg,void*param)
{
RESP_LOG("node4senddirectrequest");
returnRESP_STATUS_OK;
}

voidans_callback(void*param)
{
resp_chain_set_ans(&test_req_chain,param);
}

結論

實現了裸機處理 順序延時任務

較大程度的簡化了應用程的實現,用戶只需要實現響應的處理函數 , 調用接口添加,即可按時間要求執行

參數為空,表明為請求 ,否則為應答。(在某些場合,請求可能也帶參數,如接下來所說的LAP協議,此時需要通過判斷參數的類型)






審核編輯:劉清

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 嵌入式
    +關注

    關注

    5087

    文章

    19148

    瀏覽量

    306158
  • 電源管理
    +關注

    關注

    115

    文章

    6185

    瀏覽量

    144635
  • JAVA
    +關注

    關注

    19

    文章

    2972

    瀏覽量

    104864
  • C語言
    +關注

    關注

    180

    文章

    7608

    瀏覽量

    137135

原文標題:在嵌入式中使用設計模式的思想

文章出處:【微信號:嵌入式情報局,微信公眾號:嵌入式情報局】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    深入了解嵌入式編程

    能從PC機器編程去看嵌入式問題,那是第一步;學會用嵌入式編程思想,那是第二步;用PC的思想嵌入式思想
    的頭像 發表于 10-18 09:56 ?3678次閱讀

    如何在嵌入式系統設計中使用UML技術

    嵌入式系統設計是一個軟、硬件結合的協同設計(Hardware/Software Co-design),需要不同技術背景的人共同開發。 本文將重點討論如何在嵌入式系統設計中使用 UML 技術,并用車載 GPS 終端項目作為實例來具
    發表于 04-14 08:02 ?3911次閱讀
    如何在<b class='flag-5'>嵌入式</b>系統設計<b class='flag-5'>中使</b>用UML技術

    嵌入式軟件設計之思想與方法

    本帖最后由 lee_st 于 2018-2-24 17:16 編輯 嵌入式軟件設計之思想與方法
    發表于 02-24 17:15

    怎么利用分層思想進行嵌入式項目設計

    利用分層思想進行嵌入式項目設計,你試過嗎?
    發表于 05-22 10:16

    嵌入式開發必須掌握的設計思想?

    嵌入式開發重要的2個設計思想
    發表于 03-09 07:02

    嵌入式設備中使用JavaScript

    只聽說過匯編,c做嵌入式,從不曾想JAVAScript也牛到涉入硬件領域了,原本對他的思維定格就是一個瀏覽器腳本??磥碚鎽四蔷湓挕挥邢氩坏?,沒有做不到’話不多說看看這些大佬的帖子嵌入式設備
    發表于 11-08 06:14

    嵌入式系統硬件抽象層的設計思想簡析

    嵌入式系統硬件抽象層(HAL & BSP)的設計思想1 前言1.1 層次化思想1.2 模塊化思想1.3 對象化思想2 板級支持包(BSP)3
    發表于 02-11 07:49

    嵌入式系統教學模式研究

    嵌入式系統教學模式研究  回顧從單片機教學到現在的嵌入式系統教學20余年的發展,介紹嵌入式系統教學流行的微處理器和嵌入式操作系統
    發表于 03-29 15:08 ?1545次閱讀

    基于AVR單片機的嵌入式“瘦服務器”系統設計思想

    基于AVR單片機的嵌入式“瘦服務器”系統設計思想 根據國內嵌入式設備的研究形勢和產業發展規模,提出了基于AVR單片機(ATmega103)的嵌入式 “瘦
    發表于 05-04 22:10 ?929次閱讀
    基于AVR單片機的<b class='flag-5'>嵌入式</b>“瘦服務器”系統設計<b class='flag-5'>思想</b>

    嵌入式系統中使用FPGA時的常見問題及對策

    電子發燒友網核心提示 :嵌入式系統中使用FPGA時會經常出現以下常見問題,如在嵌入式設計中,怎樣使用FPGA、
    發表于 10-17 13:38 ?1051次閱讀

    如何在嵌入式Linux中使用GPIO

    了解如何在嵌入式Linux中使用GPIO,特別強調Zynq-7000系列。 我們介紹了基本的用戶和內核空間GPIO使用情況,以及GPIO,GPIO密鑰和GPIO LED上的bit-banged I / O.
    的頭像 發表于 11-26 07:02 ?4085次閱讀

    C嵌入式編程設計模式

    C嵌入式編程設計模式1 嵌入式系統有何特殊之處 11 嵌入式設計的約束 12 嵌入式工具 13 OSRTOS還是沒有操作系統 14
    發表于 11-03 15:36 ?17次下載
    C<b class='flag-5'>嵌入式</b>編程設計<b class='flag-5'>模式</b>

    嵌入式系統系列叢書-時間觸發嵌入式系統設計模式

    嵌入式系統系列叢書-時間觸發嵌入式系統設計模式
    發表于 12-13 11:30 ?0次下載

    嵌入式思想與PC思想結合

    能從PC機器編程去看嵌入式問題,那是第一步。
    的頭像 發表于 05-10 10:42 ?619次閱讀
    <b class='flag-5'>嵌入式</b><b class='flag-5'>思想</b>與PC<b class='flag-5'>思想</b>結合

    如何在嵌入式中使用設計模式思想?

    設計模式的標簽:高級語言 ,高端,架構等。AIOT時代,設計模式嵌入式能擦出怎樣的火花?設計模式可描述為:對于某類相似的問題,經過前人的
    的頭像 發表于 08-09 16:15 ?671次閱讀
    如何在<b class='flag-5'>嵌入式</b><b class='flag-5'>中使</b>用設計<b class='flag-5'>模式</b>的<b class='flag-5'>思想</b>?
    主站蜘蛛池模板: 国产乱人偷精品视频A人人澡| 在线天天看片视频免费观看| 午夜福利32集云播| TIMI1TV天美传媒在线观看| 久久怡红院国产精品| 亚洲看片网站| 国产精品视频大全| 同桌别揉我奶了嗯啊| 闺蜜扒开我尿口使劲揉| 日本精品在线观看视频| www精品一区二区三区四区| 欧美成 人 网 站 免费| AV国产乱码一区二区三视频| 免费看欧美xxx片| 97蜜桃网123| 女子初尝黑人巨嗷嗷叫| NANANA在线观看高清影院| 人和拘一级毛片| 囯产精品久久久久免费蜜桃| 无码人妻99久久密AV| 国内精品日本久久久久影院| 夜夜穞狠狠穞| 免费。色婬网站| 产传媒61国产免费| 色综合久久天天影视网| 国产伦精品一区二区三区| 亚洲色偷偷偷网站色偷一区人人藻| 久久99热狠狠色AV蜜臀| 中文亚洲大香伊蕉不卡一区| 女子叉开腿让男子桶免费软件 | 欧美人成在线观看ccc36| 被高跟鞋调教丨vk| 午夜福利影院私人爽爽| 好大太快了快插穿子宫了| 最新 国产 精品 精品 视频| 欧美特黄99久久毛片免费| 国产精品视频成人| 97成人免费视频| 偷拍 拍自 欧美色区| 久久精品美女久久| 成人天堂资源WWW在线|