在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

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

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

3天內不再提示

Ardupilot移植的深入細節分享

RTThread物聯網操作系統 ? 來源:驚覺嵌入式 ? 作者:驚覺嵌入式 ? 2021-04-30 16:14 ? 次閱讀

接Ardupilot移植經驗分享(2)

深入細節

是時候深入具體的HAL接口了。筆者并不打算一一講解所有的接口,而是挑選一些有代表性的來分析,主要的內容是:

分析HAL接口的含義,包括功能,入參及返回值的具體含義。

分析HAL_PX4的實現,看看有沒有可借鑒之處。

調度接口

AP_HAL::Scheduler提供了程序調度相關的接口。主要分為兩類:

延時函數

注冊回調

延時函數有3個,1個毫秒級延時,2個微秒級延時。這里的延時可不是死等,而是睡眠一段時間,在此期間讓出CPU的使用權以執行其他的線程。

virtual void delay(uint16_t ms) = 0;

virtual void delay_microseconds(uint16_t us) = 0;

virtual void delay_microseconds_boost(uint16_t us) { delay_microseconds(us); }

看似簡單的delay

大家可能會覺得,delay是最簡單的,delay_microseconds會比較復雜。因為通常來說,毫秒級延時是RTOS的基礎API,比如RT-Thread的rt_thread_mdelay。

rt_err_t rt_thread_mdelay(rt_int32_t ms);

不過Scheduler::delay除了簡單的睡眠延時,還多了一項任務。這就要先提到注冊回調接口中的一個:

typedef void(*Proc)(void);

virtual void register_delay_callback(AP_HAL::Proc, uint16_t min_time_ms) = 0;

這接口的功能是:注冊一個延時回調。當某個線程調用delay進行延時時,若延時的時間大于min_time_ms,則delay函數將會調用這個延時回調。

這延時回調的意義是,當你睡眠的時候,正好可以執行某一個指定的任務,不要浪費時間。你可能會想,RTOS的延時本就會讓出CPU,本就會讓別的線程得以執行,何必多此一舉呢?我們看看是誰注冊了這個回調。

其中之一是mavlink模塊。

hal.scheduler-》register_delay_callback(mavlink_delay_cb_static, 5);

7b10b000-a7f7-11eb-9728-12bb97331649.png

在這里插入圖片描述

注釋里面說明了原因,這是為了在長時間的初始化函數(setup)中能進行MAVLink交互。主要的MAVLink任務是在loop()中的AP_Scheduler調度系統中執行,就是紅圈部分(不過紅圈里面沒提到MAVLink,不要介意哈)。setup()是順序執行一系列的初始化函數,想在它里面去進行MAVLink任務,就靠這register_delay_callback了。

7b43b7ca-a7f7-11eb-9728-12bb97331649.png

我們再看看PX4的實現。延時的功能依賴于一個微秒級延時的接口delay_microseconds_semaphore,不過它每次只延時1000微秒,多余的時間會去執行延時回調。

7b7388a6-a7f7-11eb-9728-12bb97331649.png

微秒級延時delay_microseconds

筆者當初看到這接口時,有些頭疼。因為RT-Thread并沒有微秒級別的延時函數,再強調一遍,這不是死等,是要睡眠讓權的。

直接看PX4的實現:

void PX4Scheduler::delay_microseconds(uint16_t usec)

{

perf_begin(_perf_delay);

delay_microseconds_semaphore(usec);

perf_end(_perf_delay);

}

這是上節提到的delay_microseconds_semaphore的馬甲,脫了它:

7b82352c-a7f7-11eb-9728-12bb97331649.png

該函數使用hrt_call_after和信號量來完成微秒級睡眠的功能。hrt是High-resolution timer的縮寫,高精度定時器

調用hrt_call_after注冊一個定時器回調,定時時間是usec,單位微秒。回調函數是信號量發送函數sem_post,回調參數是信號量wait_semaphore。

使用sem_wait等待信號量wait_semaphore,此時當前線程會堵塞,進入睡眠狀態。

到達定時時間后,底層就執行這個回調,即sem_post(&wait_semaphore)。

sem_wait接收到了信號量wait_semaphore,該線程被喚醒。

結合時序圖來理解:

7bb9300e-a7f7-11eb-9728-12bb97331649.png

微秒級的延時函數,依賴于微秒級的定時回調,也就是hrt_call_after:

/**

* Call callout(arg) after delay has elapsed.

*

* If callout is NULL, this can be used to implement a timeout by testing the call

* with hrt_called()。

*/

__EXPORT extern void hrt_call_after(struct hrt_call *entry, hrt_abstime delay, hrt_callout callout, void *arg);

hrt_call_after屬于pixhawk底層的接口。筆者一度以為是Nuttx提供的功能,并且為RT-Thread沒有相應功能而煩惱。關于定時器,RT-Thread有類似的功能,那就是rt_timer,不過這是毫秒級的。

rt_timer_t rt_timer_create(const char *name,

void (*timeout)(void *parameter),

void *parameter,

rt_tick_t time,

rt_uint8_t flag)

可能你會想,一般單片機里面不是都有硬件定時器嗎?實現微秒級的定時功能很簡單啊。確實簡單,也不簡單。因為hrt_call_after提供的定時功能是要支持并發的,千言萬語不如一圖:

7bde807a-a7f7-11eb-9728-12bb97331649.png

至于pixhawk的實現以及筆者的移植,將專門出一篇文章來講解。

delay_microseconds_boost

這個同樣依賴于hrt_call_after,只是在睡眠的時候提高了優先級,以使得自己可在第一時間被喚醒。

注冊回調

virtual void register_timer_process(AP_HAL::MemberProc) = 0;

virtual void register_io_process(AP_HAL::MemberProc) = 0;

相對來說,這兩接口就簡單的多了。它們用于注冊在timer線程和io線程中運行的回調函數。

7c070de2-a7f7-11eb-9728-12bb97331649.png

注冊函數將回調指針加入到數組中。

7c17077e-a7f7-11eb-9728-12bb97331649.png

在相應線程中,定時的一一執行。

7c46c72a-a7f7-11eb-9728-12bb97331649.png

那么,這線程是怎么創建的呢?PX4Scheduler的初始化函數中,會創建許多線程。

void PX4Scheduler::init()

{

_main_task_pid = getpid();

// setup the timer thread - this will call tasks at 1kHz

pthread_attr_t thread_attr;

struct sched_param param;

pthread_attr_init(&thread_attr);

pthread_attr_setstacksize(&thread_attr, 2048);

param.sched_priority = APM_TIMER_PRIORITY;

(void)pthread_attr_setschedparam(&thread_attr, ?m);

pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);

pthread_create(&_timer_thread_ctx, &thread_attr, &PX4Scheduler::_timer_thread, this);

// the UART thread runs at a medium priority

pthread_attr_init(&thread_attr);

pthread_attr_setstacksize(&thread_attr, 2048);

param.sched_priority = APM_UART_PRIORITY;

(void)pthread_attr_setschedparam(&thread_attr, ?m);

pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);

pthread_create(&_uart_thread_ctx, &thread_attr, &PX4Scheduler::_uart_thread, this);

// the IO thread runs at lower priority

pthread_attr_init(&thread_attr);

pthread_attr_setstacksize(&thread_attr, 2048);

param.sched_priority = APM_IO_PRIORITY;

(void)pthread_attr_setschedparam(&thread_attr, ?m);

pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);

pthread_create(&_io_thread_ctx, &thread_attr, &PX4Scheduler::_io_thread, this);

// the storage thread runs at just above IO priority

pthread_attr_init(&thread_attr);

pthread_attr_setstacksize(&thread_attr, 1024);

param.sched_priority = APM_STORAGE_PRIORITY;

(void)pthread_attr_setschedparam(&thread_attr, ?m);

pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO);

pthread_create(&_storage_thread_ctx, &thread_attr, &PX4Scheduler::_storage_thread, this);

}

pthread_attr_init,pthread_create,這些是POSIX的線程接口,由Nuttx提供。POSIX 是 “Portable Operating System Interface”(可移植操作系統接口) 的縮寫,POSIX 是 IEEE Computer Society 為了提高不同操作系統的兼容性和應用程序的可移植性而制定的一套標準。

好消息是,RT-Thread從3.0版本開始提供POSIX接口。所以,當我們移植的時候,很多地方可以參考AP_HAL_PX4的代碼,甚至是直接復制它的代碼。

串口驅動

AP_HAL的串口驅動框架由4個類組成,層層分工明確。

Print的功能,如其名稱,負責打印輸出。write系列為最底層的字節輸出接口,需要由具體的HAL平臺實現。print和println系列提供打印功能。所謂的打印,比如打印float,就是以字符格式輸出float。筆者只列了幾個print接口,實際上遠比這個多。

Stream定義了輸入接口,available返回接收緩存中的字節數,read用于讀取輸入。

BetterStream添加了格式化輸出的接口,即大家熟悉的printf系列。

UARTDriver引入了與串口相關的接口,begin用于配置波特率、輸入輸出緩存,set_flow_control和get_flow_control與流控相關。

7c5553ee-a7f7-11eb-9728-12bb97331649.png

在這里插入圖片描述

除了print系列函數由AP_HAL中的類實現,其他的功能,比如read, write, begin, flow_control,都要由具體的HAL平臺實現。PX4UARTDriver就是具體的實現類。

串口綁定

Ardupilot有6個串口,定義在AP_HAL::HAL之中。

AP_HAL::UARTDriver* uartA;

AP_HAL::UARTDriver* uartB;

AP_HAL::UARTDriver* uartC;

AP_HAL::UARTDriver* uartD;

AP_HAL::UARTDriver* uartE;

AP_HAL::UARTDriver* uartF;

PX4UARTDriver構造函數和set_device_path用于與具體的底層串口相綁定。HAL_PX4_Class.c中定義了綁定關系:

// 3 UART drivers, for GPS plus two mavlink-enabled devices

static PX4UARTDriver uartADriver(UARTA_DEFAULT_DEVICE, “APM_uartA”);

static PX4UARTDriver uartBDriver(UARTB_DEFAULT_DEVICE, “APM_uartB”);

static PX4UARTDriver uartCDriver(UARTC_DEFAULT_DEVICE, “APM_uartC”);

static PX4UARTDriver uartDDriver(UARTD_DEFAULT_DEVICE, “APM_uartD”);

static PX4UARTDriver uartEDriver(UARTE_DEFAULT_DEVICE, “APM_uartE”);

static PX4UARTDriver uartFDriver(UARTF_DEFAULT_DEVICE, “APM_uartF”);

read和write的實現

大家可能認為串口的讀寫是非常簡單的操作。其實不然,Ardupilot作為一個對實時要求很高的飛控程序,在應用層調用串口讀寫函數時,是不允許堵塞的。這需要一些額外的工作來實現。

PX4UARTDriver使用接收緩存和發送緩存來實現異步讀寫。

write是將數據寫入到發送緩存_writebuf之中。_writebuf是一個隊列,實質上是環形數組RingBuffer。

/*

write one byte to the buffer

*/

size_t PX4UARTDriver::write(uint8_t c)

{

if (_uart_owner_pid != getpid()){

return 0;

}

if (!_initialised) {

try_initialise();

return 0;

}

while (_writebuf.space() == 0) {

if (_nonblocking_writes) {

return 0;

}

hal.scheduler-》delay(1);

}

return _writebuf.write(&c, 1);

}

read從接收緩存中提取數據,若沒有則返回-1。

/*

read one byte from the read buffer

*/

int16_t PX4UARTDriver::read()

{

if (_uart_owner_pid != getpid()){

return -1;

}

if (!_initialised) {

try_initialise();

return -1;

}

uint8_t byte;

if (!_readbuf.read_byte(&byte)) {

return -1;

}

return byte;

}

將發送緩存的數據寫入串口和從串口接收數據以填充接收緩存的工作,在PX4UARTDriver::_timer_tick函數中實現。而所有串口的_timer_tick由一個統一的串口線程來調度。

void *PX4Scheduler::_uart_thread(void *arg)

{

PX4Scheduler *sched = (PX4Scheduler *)arg;

pthread_setname_np(pthread_self(), “apm_uart”);

while (!sched-》_hal_initialized) {

poll(nullptr, 0, 1);

}

while (!_px4_thread_should_exit) {

sched-》delay_microseconds_semaphore(1000);

// process any pending serial bytes

((PX4UARTDriver *)hal.uartA)-》_timer_tick();

((PX4UARTDriver *)hal.uartB)-》_timer_tick();

((PX4UARTDriver *)hal.uartC)-》_timer_tick();

((PX4UARTDriver *)hal.uartD)-》_timer_tick();

((PX4UARTDriver *)hal.uartE)-》_timer_tick();

((PX4UARTDriver *)hal.uartF)-》_timer_tick();

}

return nullptr;

}

看過前面高清大圖的,應該對這個有印象:

7c61c5b6-a7f7-11eb-9728-12bb97331649.png

SPI和I2C驅動

我們再看兩個驅動,SPI驅動和I2C驅動。這兩個驅動有很多共同之處:

都有總線的概念,一條總線掛接許多設備。

都有主從概念,每次傳輸由主機發起,由從機應答。

正是由于它們非常相似,Ardupilot提取出它們的共同之處,抽象成一個基類AP_HAL::Device。下圖是Device的類圖,并非包含其所有內容,僅列出了一些重要的元素。

7c6e6f3c-a7f7-11eb-9728-12bb97331649.png

在這里插入圖片描述

UML圖示說明

上圖為UML類圖。前面提到類圖的語法,這里做一點補充。

變量和函數左邊有顏色的符號表示訪問權限,綠色圓圈是public,黃色菱形是protected。

斜體函數為純虛函數,需要由子類實現。

transfer

Ardupilot的I2C和SPI驅動主要是用于與傳感器通信,所以Device類提供了兩個常用的接口:read_register和write_register,并且實現了它們。當然,這是基于transfer接口實現的,而transfer交由子類來實現,畢竟SPI和I2C的實現是不同的。

/*

* Core transfer function. This does a single bus transaction which

* sends send_len bytes and receives recv_len bytes back from the slave.

*

* Return: true on a successful transfer, false on failure.

*/

virtual bool transfer(const uint8_t *send, uint32_t send_len,

uint8_t *recv, uint32_t recv_len) = 0;

對于I2C來說,transfer實現的是先寫后讀。而對于SPI來說,transfer內部是同時讀寫。

SPIDevice和I2CDevice

7c8186d0-a7f7-11eb-9728-12bb97331649.png

它們添加了自身獨有的接口。

SPIDevice添加了全雙工的傳輸接口transfer_fullduplex,與transfer接口所不同之處在于發送和接收緩存的長度一致。

I2CDevice中,set_address用于設置地址,set_split_transfers指定在先寫后讀的中間是否傳輸停止位。

Periodic Callback

Device的功能遠不只是為SPI和I2C定義了統一的transfer接口。最重要的,是實現了應用層訪問總線的串行化。SPI和I2C都是由一條總線掛接許多設備,無論是SPI或I2C,都不允許在同一時刻訪問多個設備。因此,Device提供了get_semaphore接口,以鎖定總線。當然,這并不算是串行化,真正的串行化,是通過register_periodic_callback來實現。

virtual PeriodicHandle register_periodic_callback(uint32_t period_usec, PeriodicCb) = 0;

各傳感器驅動通過register_periodic_callback注冊定時回調,在回調之中訪問對應的傳感器。同一總線的所有定時回調是在同一個線程中被執行的,這就是串行化。

7d495e94-a7f7-11eb-9728-12bb97331649.png

PX4在實現時,使用DeviceBus實現這個串行化的功能,其會為每一條總線創建一個線程。

7d9b24d6-a7f7-11eb-9728-12bb97331649.png

其內部實現,無非是創建線程,將回調添加到一個鏈表之中。在函數中,POSIX接口的調用清晰可見。筆者的意思是,可以直接拿來用啦。

7db1b5d4-a7f7-11eb-9728-12bb97331649.png

Manager

應用層通過Device來訪問I2C和SPI設備,那么Device對象是哪來的呢?由I2CDeviceManager和SPIDeviceManager提供,而這兩個Manager的實例可通過HAL引用訪問。

7df3cc9e-a7f7-11eb-9728-12bb97331649.png

小結

SPI和I2C傳輸的具體實現,沒啥好說的。最值得說的,是Ardupilot抽象出了Device基類,為應用層提供串行化的訪問功能。而這串行化,是靠創建線程和回調鏈表來實現。

是時候放一張高清大圖了:

7e8275b6-a7f7-11eb-9728-12bb97331649.png

總結

到目前為止,我們看了調度接口,串口驅動,SPI和I2C驅動。調度接口中的微秒級延時接口非常關鍵,因為很多地方使用了它,并且它的實現有些困難。至于串口、SPI等驅動接口,只要我們理清了它們的層級關系,明確了各接口的作用,移植時不會有什么大問題。并且,這些驅動接口的實現,很多地方可以參考PX4的實現,甚至是直接復制過來用。

原文標題:Ardupilot移植經驗分享(3)

文章出處:【微信公眾號:RTThread物聯網操作系統】歡迎添加關注!文章轉載請注明出處。

責任編輯:haq

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

    關注

    12

    文章

    1844

    瀏覽量

    85408
  • 串口
    +關注

    關注

    14

    文章

    1557

    瀏覽量

    76735

原文標題:Ardupilot移植經驗分享(3)

文章出處:【微信號:RTThread,微信公眾號:RTThread物聯網操作系統】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    臺積電分享 2nm 工藝深入細節:功耗降低 35% 或性能提升15%!

    來源:IEEE 臺積電在本月早些時候于IEEE國際電子器件會議(IEDM)上公布了其N2(2nm級)制程的更多細節。該新一代工藝節點承諾實現24%至35%的功耗降低或15%的性能提升(在相同電壓
    的頭像 發表于 12-16 09:57 ?245次閱讀
    臺積電分享 2nm 工藝<b class='flag-5'>深入</b><b class='flag-5'>細節</b>:功耗降低 35% 或性能提升15%!

    移植Mediapipe LLM Demo到Kotlin Multiplatform

    在今年的廈門和廣州 Google I/O Extended 上,我分享了《On-Device Model 集成 (KMP) 與用例》。本文是當時 Demo 的深入細節分析,同時也是后面幾篇同類型文章的開頭。
    的頭像 發表于 12-05 16:29 ?321次閱讀
    <b class='flag-5'>移植</b>Mediapipe LLM Demo到Kotlin Multiplatform

    多平臺FPGA工程快速移植與構建

    作為一名FPGA工程師,經常需要在多個FPGA設備之間移植項目,核心的問題是IP的管理和移植,今天通過安裝和使用 FuseSoC 在多個 AMD FPGA 之間移植一個簡單的項目。從 AMD Spartan 7 更改為 AMD
    的頭像 發表于 11-20 16:12 ?1005次閱讀
    多平臺FPGA工程快速<b class='flag-5'>移植</b>與構建

    深入解析Zephyr RTOS的技術細節

    ,Zephyr OS在嵌入式開發中的知名度逐漸增加,新的微控制器和開發板都支持Zephyr。本文將深入討論Zephyr RTOS的技術細節
    的頭像 發表于 10-22 16:47 ?631次閱讀
    <b class='flag-5'>深入</b>解析Zephyr RTOS的技術<b class='flag-5'>細節</b>

    Nordic-RT-Thread5.1.0移植筆記

    Nordic-RT-Thread5.1.0移植筆記
    的頭像 發表于 10-16 08:09 ?525次閱讀
    Nordic-RT-Thread5.1.0<b class='flag-5'>移植</b>筆記

    基于機智云移植STM32L496G代碼移植

    前言最近我拿到了STM32L496AGMCU,發現其擴展版可以連接ESP-01S。我想嘗試將開發板連接到我們的機智云上,并根據機智云提供的文檔進行程序移植。STM32CubeMX移植機智云自動生成
    的頭像 發表于 09-20 08:05 ?473次閱讀
    基于機智云<b class='flag-5'>移植</b>STM32L496G代碼<b class='flag-5'>移植</b>

    【GD32 MCU 移植教程】9、從 STM32F10x 系列移植到 GD32F30x 系列

    對比、外設及性能對比以及從 STM32F10x 移植到 GD32F30x 的移植步驟,旨在讓開發者能夠快速從STM32F10x 移植到 GD32F30x,縮短研發周
    的頭像 發表于 09-07 09:57 ?891次閱讀
    【GD32 MCU <b class='flag-5'>移植</b>教程】9、從 STM32F10x 系列<b class='flag-5'>移植</b>到 GD32F30x 系列

    LED顯示屏的換幀頻率與刷新頻率:技術細節與市場發展

    在當今數字化時代,LED顯示屏已成為信息傳遞和廣告宣傳的重要工具。然而,對于普通消費者來說,LED顯示屏背后的技術細節可能仍然是一個謎。今天,我們將深入探討LED顯示屏中的兩個關鍵概念:換幀頻率和刷新頻率,以及它們之間的關系,帶領大家了解這些技術如何影響我們的視覺體驗。
    的頭像 發表于 06-23 02:22 ?748次閱讀
    LED顯示屏的換幀頻率與刷新頻率:技術<b class='flag-5'>細節</b>與市場發展

    CC2500和CC1101移植說明

    主要通過如何移植移植注意、關于芯片配置、如何生成導出配置四大步驟來說明CC2500和CC1101移植
    的頭像 發表于 06-15 14:32 ?644次閱讀
    CC2500和CC1101<b class='flag-5'>移植</b>說明

    如何移植FFmpeg

    的全方位解決方案,深入掌握FFmpeg已成為每一位多媒體開發工程師的必修課。今天就跟各位小伙伴分享一篇共創社的學習筆記,探討一下如何移植FFmpeg。配置交叉編譯環
    的頭像 發表于 06-07 15:28 ?1711次閱讀
    如何<b class='flag-5'>移植</b>FFmpeg

    深入了解目標檢測深度學習算法的技術細節

    本文將討論目標檢測的基本方法(窮盡搜索、R-CNN、FastR-CNN和FasterR-CNN),并嘗試理解每個模型的技術細節。為了讓經驗水平各不相同的讀者都能夠理解,文章不會使用任何公式來進行講解
    的頭像 發表于 04-30 08:27 ?365次閱讀
    <b class='flag-5'>深入</b>了解目標檢測深度學習算法的技術<b class='flag-5'>細節</b>

    細節控必備!東芝“顯微屏”電視Z700NF,打造專精細節的“顯微屏”電視

    對音畫細節的打磨,旨在解決用戶的觀影痛點,提供極致還原的細節視聽享受。 1300nits Mini LED?亮度突破,細節盡現 用戶在觀看電視時,常因亮度不足而錯失畫面的細微之處。東芝電視Z700NF采用1300nits Min
    的頭像 發表于 04-19 13:31 ?356次閱讀

    鴻蒙開發實戰:基于【Markwon】移植和開發

    本項目是基于開源項目**Markwon**進行適用harmonyos的移植和開發的。
    的頭像 發表于 03-25 16:27 ?851次閱讀
    鴻蒙開發實戰:基于【Markwon】<b class='flag-5'>移植</b>和開發

    鴻蒙ArkUI【開發移植Carbon】

    本項目是基于開源項目[Carbon]?進行harmonyos化的移植和開發的。
    的頭像 發表于 03-25 15:41 ?539次閱讀
    鴻蒙ArkUI【開發<b class='flag-5'>移植</b>Carbon】

    【鴻蒙】標準系統移植指南

    標準系統移植指南 本文描述了移植一塊開發板的通用步驟,和具體芯片相關的詳細移植過程無法在此一一列舉。后續社區還會陸續發布開發板移植的實例供開發者參考。 定義開發板 本文以
    的頭像 發表于 02-27 14:36 ?963次閱讀
    【鴻蒙】標準系統<b class='flag-5'>移植</b>指南
    主站蜘蛛池模板: 亚洲精品久久久久午夜| 天天操天天碰| 主人扒开腿揉捏花蒂调教cfh| 久久天天操| 九色九色九色在线综合888| 国产香蕉在线视频| 色综合视频| 尤物久久99热国产综合| 久久国产精品夜色| 国产激烈床戏无遮挡观看| 久久a毛片| 国产色视频在线| 亚洲 欧美 校园| 黄色午夜剧场| 4438x全国免费| 在线天堂视频| 特黄色片| 久青草国产手机在线视频 | 国产一区二区三区美女图片| 色人人| 男女爱爱福利| 欧美18videosex性欧美1819| 色噜噜在线视频| 精品伊人久久大香线蕉网站| 一级特黄特色的免费大片视频| free 欧美| 成人一二| www.婷婷| 欧美大黄| 67pao强力打造| 亚洲成网777777国产精品| 女人张开腿给男人桶爽免费| 成人看片免费无限观看视频| 人人干干人人| 国产综合免费视频| 日本边添边爱边摸边做边爱| 日本aaaaa特黄毛片| 性欧美性free| 激情丁香婷婷| 色网站在线观看| 一区二区三区高清视频在线观看 |