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

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

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

3天內不再提示

基于Linux的kfifo移植到STM32

汽車電子技術 ? 來源:物聯網IoT開發 ? 作者:杰杰 ? 2023-02-14 09:52 ? 次閱讀

基于Linux的kfifo移植到STM32(支持os的互斥訪問)

關于kfifo

kfifo是內核里面的一個First In First Out數據結構,它采用環形循環隊列的數據結構來實現;它提供一個無邊界的字節流服務,最重要的一點是,它使用并行無鎖編程技術,即當它用于只有一個入隊線程和一個出隊線程的場情時,兩個線程可以并發操作,而不需要任何加鎖行為,就可以保證kfifo的線程安全。

具體什么是環形緩沖區,請看我以前的文章

說明

關于kfifo的相關概念我不會介紹,有興趣可以看他的相關文檔,我只將其實現過程移植重寫,移植到適用stm32開發板上,并且按照我個人習慣重新命名, RingBuff ->意為環形緩沖區

往期關于環形緩沖區的文章:

杰杰帶你解讀【機智云】環形緩沖區源碼

STM32進階之串口環形緩沖區實現

RingBuff_t

環形緩沖區的結構體成員變量,具體含義看注釋。

buffer: 用于存放數據的緩存

size: buffer空間的大小

in, out: 和buffer一起構成一個循環隊列。 in指向buffer中隊頭,而且out指向buffer中的隊尾

typedef struct ringbuff 
{
    uint8_t *buffer;    /* 數據區域 */
    uint32_t size;      /* 環形緩沖區大小 */
    uint32_t in;        /* 數據入隊指針 (in % size) */
    uint32_t out;       /* 數據出隊指針 (out % size) */
#if USE_MUTEX
    MUTEX_T *mutex;       /* 支持rtos的互斥 */
#endif
}RingBuff_t ;

Create_RingBuff

創建一個環形緩沖區,為了適應后續對緩沖區入隊出隊的高效操作,環形緩沖區的大小應為2^n字節,

如果不是這個大小,則系統默認裁剪以對應緩沖區字節。

當然還可以優化,不過我目前并未做,思路如下:如果系統支持動態分配內存,則向上對齊,避免浪費內存空間,否則就按照我默認的向下對齊,當內存越大,對齊導致內存泄漏則會越多。對齊采用的函數是roundup_pow_of_two。如果系統支持互斥量,那么還將創建一個互斥量用來做互斥訪問,防止多線程同時使用導致數據丟失。

/************************************************************
  * @brief   Create_RingBuff
  * @param   rb:環形緩沖區句柄
  *          buffer:環形緩沖區的數據區域
  *          size:環形緩沖區的大小,緩沖區大小要為2^n
  * @return  err_t:ERR_OK表示創建成功,其他表示失敗
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    用于創建一個環形緩沖區
  ***********************************************************/
err_t Create_RingBuff(RingBuff_t* rb, 
                      uint8_t *buffer,
                      uint32_t size
                                )
{
    if((rb == NULL)||(buffer == NULL)||(size == 0))
    {
        PRINT_ERR("data is null!");
        return ERR_NULL;
    }

    PRINT_DEBUG("ringbuff size is %d!",size);
    /* 緩沖區大小必須為2^n字節,系統會強制轉換,
         否則可能會導致指針訪問非法地址。
         空間大小越大,強轉時丟失內存越多 */
    if(size&(size - 1))
    {
        size = roundup_pow_of_two(size);
        PRINT_DEBUG("change ringbuff size is %d!",size);
    }

    rb->buffer = buffer;
    rb->size = size;
    rb->in = rb->out = 0;
#if USE_MUTEX    
  /* 創建信號量不成功 */
  if(!create_mutex(rb->mutex))
  {
    PRINT_ERR("create mutex fail!");
    ASSERT(ASSERT_ERR);
    return ERR_NOK;
  }
#endif
    PRINT_DEBUG("create ringBuff ok!");
    return ERR_OK;
}

roundup_pow_of_two

/************************************************************
  * @brief   roundup_pow_of_two
  * @param   size:傳遞進來的數據長度
  * @return  size:返回處理之后的數據長度
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    用于處理數據,使數據長度必須為 2^n
    *                    如果不是,則轉換,丟棄多余部分,如
    *                    roundup_pow_of_two(66) -> 返回 64
  ***********************************************************/
static unsigned long roundup_pow_of_two(unsigned long x)
{
    return (1 << (fls(x-1)-1));             //向下對齊
  //return (1UL << fls(x - 1));            //向上對齊,用動態內存可用使用
}

Delete_RingBuff

刪除一個環形緩沖區,刪除之后,緩沖區真正存儲地址是不會被改變的(目前我是使用自定義數組做緩沖區的),但是刪除之后,就無法對緩沖區進行讀寫操作。并且如果支持os的話,創建的互斥量會被刪除。

/************************************************************
  * @brief   Delete_RingBuff
  * @param   rb:環形緩沖區句柄
  * @return  err_t:ERR_OK表示成功,其他表示失敗
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    刪除一個環形緩沖區
  ***********************************************************/
err_t Delete_RingBuff(RingBuff_t *rb)
{
    if(rb == NULL)
    {
        PRINT_ERR("ringbuff is null!");
        return ERR_NULL;
    }

    rb->buffer = NULL;
    rb->size = 0;
    rb->in = rb->out = 0;
#if USE_MUTEX    
  if(!deleta_mutex(rb->mutex))
  {
    PRINT_DEBUG("deleta mutex is fail!");
    return ERR_NOK;
  }
#endif
    return ERR_OK;
}

Write_RingBuff

向環形緩沖區寫入指定數據,支持線程互斥訪問。用戶想要寫入緩沖區的數據長度不一定是真正入隊的長度,在完成的時候還要看看返回值是否與用戶需要的長度一致~

這個函數很有意思,也是比較高效的入隊操作,將指定區域的數據拷貝到指定的緩沖區中,過程看注釋即可

/************************************************************
  * @brief   Write_RingBuff
  * @param   rb:環形緩沖區句柄
  * @param   wbuff:寫入的數據起始地址
  * @param   len:寫入數據的長度(字節)
  * @return  len:實際寫入數據的長度(字節)
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    這個函數會從buff空間拷貝len字節長度的數據到
             rb環形緩沖區中的空閑空間。
  ***********************************************************/
uint32_t Write_RingBuff(RingBuff_t *rb,
                        uint8_t *wbuff, 
                        uint32_t len)
{
  uint32_t l;
#if USE_MUTEX
  /* 請求互斥量,成功才能進行ringbuff的訪問 */
  if(!request_mutex(rb->mutex))
  {
    PRINT_DEBUG("request mutex fail!");
    return 0;
  }
  else  /* 獲取互斥量成功 */
  {
#endif
    len = min(len, rb->size - rb->in + rb->out);

    /* 第一部分的拷貝:從環形緩沖區寫入數據直至緩沖區最后一個地址 */
    l = min(len, rb->size - (rb->in & (rb->size - 1)));
    memcpy(rb->buffer + (rb->in & (rb->size - 1)), wbuff, l);

    /* 如果溢出則在緩沖區頭寫入剩余的部分
       如果沒溢出這句代碼相當于無效 */
    memcpy(rb->buffer, wbuff + l, len - l);

    rb->in += len;

    PRINT_DEBUG("write ringBuff len is %d!",len);
#if USE_MUTEX
  }
  /* 釋放互斥量 */
  release_mutex(rb->mutex);
#endif
  return len;
}

Read_RingBuff

讀取緩沖區數據到指定區域,用戶指定讀取長度,用戶想要讀取的長度不一定是真正讀取的長度,在讀取完成的時候還要看看返回值是否與用戶需要的長度一致~也支持多線程互斥訪問。

也是緩沖區出隊的高效操作。過程看代碼注釋即可

/************************************************************
  * @brief   Read_RingBuff
  * @param   rb:環形緩沖區句柄
  * @param   wbuff:讀取數據保存的起始地址
  * @param   len:想要讀取數據的長度(字節)
  * @return  len:實際讀取數據的長度(字節)
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    這個函數會從rb環形緩沖區中的數據區域拷貝len字節
             長度的數據到rbuff空間。
  ***********************************************************/
uint32_t Read_RingBuff(RingBuff_t *rb,
                       uint8_t *rbuff, 
                       uint32_t len)
{
  uint32_t l;
#if USE_MUTEX
  /* 請求互斥量,成功才能進行ringbuff的訪問 */
  if(!request_mutex(rb->mutex))
  {
    PRINT_DEBUG("request mutex fail!");
    return 0;
  }
  else
  {
#endif
    len = min(len, rb->in - rb->out);

    /* 第一部分的拷貝:從環形緩沖區讀取數據直至緩沖區最后一個 */
    l = min(len, rb->size - (rb->out & (rb->size - 1)));
    memcpy(rbuff, rb->buffer + (rb->out & (rb->size - 1)), l);

    /* 如果溢出則在緩沖區頭讀取剩余的部分
       如果沒溢出這句代碼相當于無效 */
    memcpy(rbuff + l, rb->buffer, len - l);

    rb->out += len;

    PRINT_DEBUG("read ringBuff len is %d!",len);
#if USE_MUTEX
  }
  /* 釋放互斥量 */
  release_mutex(rb->mutex);
#endif
  return len;
}

獲取緩沖區信息

這些就比較簡單了,看看緩沖區可讀可寫的數據有多少

/************************************************************
  * @brief   CanRead_RingBuff
    * @param   rb:環形緩沖區句柄
    * @return  uint32:可讀數據長度 0 / len
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    可讀數據長度
  ***********************************************************/
uint32_t CanRead_RingBuff(RingBuff_t *rb)
{
    if(NULL == rb)
    {
        PRINT_ERR("ringbuff is null!");
        return 0;
    }
    if(rb->in == rb->out)
        return 0;

    if(rb->in > rb->out)
        return (rb->in - rb->out);

    return (rb->size - (rb->out - rb->in));
}

/************************************************************
  * @brief   CanRead_RingBuff
    * @param   rb:環形緩沖區句柄
    * @return  uint32:可寫數據長度 0 / len
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    可寫數據長度
  ***********************************************************/
uint32_t CanWrite_RingBuff(RingBuff_t *rb)
{
    if(NULL == rb)
    {
        PRINT_ERR("ringbuff is null!");
        return 0;
    }

    return (rb->size - CanRead_RingBuff(rb));
}

附帶

這里的代碼我是用于測試的,隨便寫的

RingBuff_t ringbuff_handle;

    uint8_t rb[64];
    uint8_t res[64];
    Create_RingBuff(&ringbuff_handle, 
                                rb,
                                sizeof(rb));
            Write_RingBuff(&ringbuff_handle,
                     res, 
                     datapack.data_length);

            PRINT_DEBUG("CanRead_RingBuff = %d!",CanRead_RingBuff(&ringbuff_handle));
            PRINT_DEBUG("CanWrite_RingBuff = %d!",CanWrite_RingBuff(&ringbuff_handle));

            Read_RingBuff(&ringbuff_handle,
                     res, 
                     datapack.data_length);

支持多個os的互斥量操作

此處模仿了文件系統的互斥操作

#if USE_MUTEX
#define  MUTEX_TIMEOUT   1000     /* 超時時間 */
#define  MUTEX_T         mutex_t  /* 互斥量控制塊 */
#endif

/*********************************** mutex **************************************************/
#if USE_MUTEX
/************************************************************
  * @brief   create_mutex
  * @param   mutex:創建信號量句柄
  * @return  創建成功為1,0為不成功。
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    創建一個互斥量,用戶在os中互斥使用ringbuff,
  *          支持的os有rtt、win32、ucosFreeRTOSLiteOS
  ***********************************************************/
static err_t create_mutex(MUTEX_T *mutex)
{
  err_t ret = 0;

//    *mutex = rt_mutex_create("test_mux",RT_IPC_FLAG_PRIO); /* rtt */
//    ret = (err_t)(*mutex != RT_NULL);

//    *mutex = CreateMutex(NULL, FALSE, NULL);        /* Win32 */
//    ret = (err_t)(*mutex != INVALID_HANDLE_VALUE);

//    *mutex = OSMutexCreate(0, &err);        /* uC/OS-II */
//    ret = (err_t)(err == OS_NO_ERR);

//    *mutex = xSemaphoreCreateMutex();   /* FreeRTOS */
//    ret = (err_t)(*mutex != NULL);

//  ret = LOS_MuxCreate(&mutex);  /* LiteOS */
//    ret = (err_t)(ret != LOS_OK);
  return ret;
}
/************************************************************
  * @brief   deleta_mutex
  * @param   mutex:互斥量句柄
  * @return  NULL
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    刪除一個互斥量,支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  ***********************************************************/
static err_t deleta_mutex(MUTEX_T *mutex)
{
    err_t ret;

//    ret = rt_mutex_delete(mutex);   /* rtt */

//    ret = CloseHandle(mutex);   /* Win32 */

//    OSMutexDel(mutex, OS_DEL_ALWAYS, &err); /* uC/OS-II */
//    ret = (err_t)(err == OS_NO_ERR);

//  vSemaphoreDelete(mutex);        /* FreeRTOS */
//    ret = 1;

//  ret = LOS_MuxDelete(&mutex);  /* LiteOS */
//    ret = (err_t)(ret != LOS_OK);

    return ret;
}
/************************************************************
  * @brief   request_mutex
  * @param   mutex:互斥量句柄
  * @return  NULL
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    請求一個互斥量,得到互斥量的線程才允許進行訪問緩沖區
  *          支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  ***********************************************************/
static err_t request_mutex(MUTEX_T *mutex)
{
    err_t ret;

//    ret = (err_t)(rt_mutex_take(mutex, MUTEX_TIMEOUT) == RT_EOK);/* rtt */

//    ret = (err_t)(WaitForSingleObject(mutex, MUTEX_TIMEOUT) == WAIT_OBJECT_0);  /* Win32 */

//    OSMutexPend(mutex, MUTEX_TIMEOUT, &err));       /* uC/OS-II */
//    ret = (err_t)(err == OS_NO_ERR);

//    ret = (err_t)(xSemaphoreTake(mutex, MUTEX_TIMEOUT) == pdTRUE);  /* FreeRTOS */

//  ret = (err_t)(LOS_MuxPend(mutex,MUTEX_TIMEOUT) == LOS_OK);          /* LiteOS */

    return ret;
}
/************************************************************
  * @brief   release_mutex
  * @param   mutex:互斥量句柄
  * @return  NULL
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    釋放互斥量,當線程使用完資源必須釋放互斥量
  *          支持的os有rtt、win32、ucos、FreeRTOS、LiteOS
  ***********************************************************/
static void release_mutex(MUTEX_T *mutex)
{
//    rt_mutex_release(mutex);/* rtt */

//    ReleaseMutex(mutex);        /* Win32 */

//    OSMutexPost(mutex);     /* uC/OS-II */

//    xSemaphoreGive(mutex);  /* FreeRTOS */

//  LOS_MuxPost(mutex);   /* LiteOS */
}
#endif
/*********************************** mutex **************************************************/

debug.h

最后送一份debug的簡便操作源碼,因為前文很多時候會調用

PRINT_ERR

PRINT_DEBUG

#ifndef _DEBUG_H
#define _DEBUG_H
/************************************************************
  * @brief   debug.h
  * @author  jiejie
  * @github  https://github.com/jiejieTop
  * @date    2018-xx-xx
  * @version v1.0
  * @note    此文件用于打印日志信息
  ***********************************************************/
/**
* @name Debug print 
* @{
*/
#define PRINT_DEBUG_ENABLE        1       /* 打印調試信息 */
#define PRINT_ERR_ENABLE            1   /* 打印錯誤信息 */
#define PRINT_INFO_ENABLE            0       /* 打印個人信息 */


#if PRINT_DEBUG_ENABLE
#define PRINT_DEBUG(fmt, args...)      do{(printf("\\n[DEBUG] >> "), printf(fmt, ##args));}while(0)     
#else
#define PRINT_DEBUG(fmt, args...)         
#endif

#if PRINT_ERR_ENABLE
#define PRINT_ERR(fmt, args...)      do{(printf("\\n[ERR] >> "), printf(fmt, ##args));}while(0)     
#else
#define PRINT_ERR(fmt, args...)           
#endif

#if PRINT_INFO_ENABLE
#define PRINT_INFO(fmt, args...)      do{(printf("\\n[INFO] >> "), printf(fmt, ##args));}while(0)     
#else
#define PRINT_INFO(fmt, args...)           
#endif

/**@} */

//針對不同的編譯器調用不同的stdint.h文件
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
    #include 
#endif

/* 斷言 Assert */
#define AssertCalled(char,int)     printf("\\nError:%s,%d\\r\\n",char,int)
#define ASSERT(x)   if((x)==0)  AssertCalled(__FILE__,__LINE__)

typedef enum 
{
    ASSERT_ERR = 0,                             /* 錯誤 */
    ASSERT_SUCCESS = !ASSERT_ERR    /* 正確 */
} Assert_ErrorStatus;

typedef enum 
{
    FALSE = 0,      /* 假 */
    TRUE = !FALSE   /* 真 */
}ResultStatus;

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

    關注

    3

    文章

    1410

    瀏覽量

    41117
  • 編程技術
    +關注

    關注

    0

    文章

    40

    瀏覽量

    10598
  • 數據結構
    +關注

    關注

    3

    文章

    573

    瀏覽量

    40606
收藏 人收藏

    評論

    相關推薦
    熱點推薦

    Linux系統移植開發篇2:燒寫linux鏡像

    本文章為《STM32MP157 Linux系統移植開發篇》系列中的一篇,筆者使用的開發平臺為華清遠見FS-MP1A開發板(STM32MP157開發板)。
    發表于 09-29 16:00 ?3444次閱讀
    <b class='flag-5'>Linux</b>系統<b class='flag-5'>移植</b>開發篇2:燒寫<b class='flag-5'>linux</b>鏡像

    stm32移植linux方法

    stm32移植linux方法,推薦分享一個朋友的人工智能教程,零基礎!通俗易懂!希望你也加入人工智能的隊伍中來!Ⅰ、概述該文寫針對初學μC/OS的朋友,基于以下平臺來一步一步
    發表于 08-09 09:17

    移植Linux晶心平臺

    鑒于越來越多使用者將Linux移植晶心平臺(Andes Embedded)上(AndesCore N12或N10),本文的目的在協助使用者快速、有效率的將Linux
    發表于 04-11 10:10 ?1015次閱讀
    <b class='flag-5'>移植</b><b class='flag-5'>Linux</b><b class='flag-5'>到</b>晶心平臺

    STM32_UCOS移植

    STM32 UCOS移植 STM32 UCOS移植 STM32 UCOS移植
    發表于 07-13 17:31 ?30次下載

    如何將SQLite移植linux的方法程序說明概述

    本文檔的主要內容詳細介紹的是如何將SQLite移植linux的方法程序說明概述
    發表于 07-20 08:00 ?0次下載

    實操經驗分享——在STM32移植Linux

    剛從硬件跳槽為嵌軟時,沒有任何一絲的準備。一入職,領導就交代了一項特難的任務——在stm32移植linux!
    的頭像 發表于 09-17 17:01 ?1.3w次閱讀

    GD32移植STM32開發平臺

    GD32移植STM32開發平臺
    發表于 12-02 14:51 ?28次下載
    GD32<b class='flag-5'>移植</b><b class='flag-5'>到</b><b class='flag-5'>STM32</b>開發平臺

    RT-Thread系統移植STM32f103

    RT-Thread系統移植STM32f103
    發表于 12-09 12:51 ?26次下載
    RT-Thread系統<b class='flag-5'>移植</b><b class='flag-5'>到</b><b class='flag-5'>STM32</b>f103

    AN5293 STM32F7系列移植STM32H7系列

    AN5293 STM32F7系列移植STM32H7系列
    發表于 11-21 17:06 ?1次下載
    AN5293 <b class='flag-5'>STM32</b>F7系列<b class='flag-5'>移植</b><b class='flag-5'>到</b><b class='flag-5'>STM32</b>H7系列

    AN3422_從STM32F1移植STM32L1的應用手冊

    AN3422_從STM32F1移植STM32L1的應用手冊
    發表于 11-21 17:06 ?4次下載
    AN3422_從<b class='flag-5'>STM32</b>F1<b class='flag-5'>移植</b><b class='flag-5'>到</b><b class='flag-5'>STM32</b>L1的應用手冊

    AN3427_從STM32F1移植STM32F2的應用手冊

    AN3427_從STM32F1移植STM32F2的應用手冊
    發表于 11-21 17:06 ?10次下載
    AN3427_從<b class='flag-5'>STM32</b>F1<b class='flag-5'>移植</b><b class='flag-5'>到</b><b class='flag-5'>STM32</b>F2的應用手冊

    AN4904_從STM32F1STM32F4的軟件移植

    AN4904_從STM32F1STM32F4的軟件移植
    發表于 11-21 17:06 ?5次下載
    AN4904_從<b class='flag-5'>STM32</b>F1<b class='flag-5'>到</b><b class='flag-5'>STM32</b>F4的軟件<b class='flag-5'>移植</b>

    AN4617_從STM32F0STM32L0的軟件移植

    AN4617_從STM32F0STM32L0的軟件移植
    發表于 11-21 17:06 ?5次下載
    AN4617_從<b class='flag-5'>STM32</b>F0<b class='flag-5'>到</b><b class='flag-5'>STM32</b>L0的軟件<b class='flag-5'>移植</b>

    AN4936_從STM32F7STM32H7的軟件移植

    AN4936_從STM32F7STM32H7的軟件移植
    發表于 11-21 17:06 ?5次下載
    AN4936_從<b class='flag-5'>STM32</b>F7<b class='flag-5'>到</b><b class='flag-5'>STM32</b>H7的軟件<b class='flag-5'>移植</b>

    Linux驅動移植 Linux系統架構優點

    系統移植 linux 驅動移植 移植是說同樣的一個 linux 操作系統,我們可以跑到不同的硬件上面,我們把操作系統
    的頭像 發表于 07-27 17:06 ?1082次閱讀
    <b class='flag-5'>Linux</b>驅動<b class='flag-5'>移植</b> <b class='flag-5'>Linux</b>系統架構優點
    主站蜘蛛池模板: 在线成人免费观看国产精品 | 久久精品香蕉视频 | 中文字幕一区二区三区四区五区人 | 人人搞人人爽 | 成人欧美一区二区三区的电影 | 日本欧洲亚洲一区在线观看 | 乱码一区二区三区完整视频 | 操操干干 | 午夜视频福利在线观看 | 四虎国产精品免费久久影院 | 久久久久久人精品免费费看 | 又黄又爽的成人免费网站 | 能直接看黄的网站 | 午夜色网站| 成人99国产精品一级毛片 | 4438x色| 欧美大狠狠大臿蕉香蕉大视频 | 影音先锋在线亚洲精品推荐 | 在线观看黄的网站 | 美女被草视频在线观看 | 东京加勒比| 国内露脸夫妇交换精品 | 亚洲国产香蕉视频欧美 | 亚洲免费观看视频 | 中文字幕不卡一区 | 国产精品7m凸凹视频分类大全 | 亚洲视频你懂的 | 国产免费播放一区二区三区 | 欧美福利片在线观看 | 亚洲人毛茸茸bbxx | 午夜精品一区二区三区在线视 | 成人国产精品一级毛片视频 | 日韩精品无码一区二区三区 | 国产精品亚洲一区二区三区在线播放 | 日本三级强在线观看 | 黄视频免费在线观看 | 久久久久久久国产视频 | 免费能直接在线观看黄的视频 | 国产亚洲精品久久午夜 | 人成网站在线观看 | 在线观看视频播放 |