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

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

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

3天內不再提示

一個小而巧的自定義嵌入式軟件通信協議

嵌入式應用研究院 ? 來源:嵌入式大雜燴 ? 2023-04-21 09:16 ? 次閱讀

嵌入式開發中,常常會自定義一些協議格式,比如用于板與板之間的通信、客戶端與服務端之間的通信等。

自定義的協議格式可能有很多種,本篇文章我們來介紹一種很常用、實用、且靈活性很高的協議格式——ITLV格式。

什么是ITLV格式?

大家可能看到網絡上的很多文章用的是TLV(Tag、Length、Value)格式數據。實際中,可以根據實際需要進行修改。我們這里稍微改一下,實際上也是大同小異的。

我們這里的ITLV各字段的含義:

I:ID或Index,用于區分是什么數據。

T:Type,代表數據類型,如int、float等。

L:Length,表示數據的長度(Value的長度)。

V:Value,表示實際的數據。

其中,I、T、L是固定長度的,在制定具體的數據協議之前,需要評估好當前項目的數據會有多少、數據的最大長度是多少,考慮好后續數據擴展也可以保證協議通用。一般I設置為1~2字節,T設置為1字節,L設置為1~4字節。

下面我們制定一個格式:

5c798d4a-dfc4-11ed-bfe3-dac502259ad0.png

實際中,如果在物聯網系統中數據傳輸,我們用戶自定義的協議字段可能就只包含如上四個字段就可以了。比如我們公司的云平臺上的用戶數據格式用的就是類似ITLV這樣的格式。用戶在制定協議時的協議字段包含如上字段就可以了。

沒有包頭做一些數據區分,也沒有校驗字段,只包含如上字段就能保證數據可靠傳輸嗎?

因為端云通信采用MQTT,基于TCP,TCP的特點就是可靠的,網絡協議中會帶有校驗。并且,實際在傳輸用戶數據時,還會再用戶數據之前增加一些字段區分這就是用戶數據。所以,其實基于它的設備SDK來進行開發,操作的數據就是如上的數據。

但是,如果應用于板與板之間的通信,只包含如上字段自然是有風險的。我們至少還需要還要包頭、校驗字段。

實際中根據需要還可以增加其它字段,比如如果需要分包發送,還需要增加包號;如果多塊板之間進行通信,還需要增加發送數據目標地址等。

這里我們增加包頭與校驗字段:

5c9d0856-dfc4-11ed-bfe3-dac502259ad0.png

其中:

(1)Head固定為0x55、0xAA。

(2)Length為1字節,即Value最大為256B。

ITLV格式數據處理

下面以例子來演示ITLV格式數據的處理。

5cc51d28-dfc4-11ed-bfe3-dac502259ad0.png

下面我們以上面我們制定的協議編寫A板的組包、解析代碼。

1、設計相關數據結構

首先,我們創建一個協議格式結構體:

#pragmapack(1)
//協議格式
typedefstruct_protocol_format
{
uint16_thead;
uint8_tid;
uint8_ttype;
uint8_tlength;
uint8_tvalue[];
}protocol_format_t;

type字段的取值:

//TLV數據類型type
typedefenum_tlv_type
{
TLV_TYPE_UINT8,
TLV_TYPE_INT8,
TLV_TYPE_UINT16,
TLV_TYPE_INT16,
TLV_TYPE_UINT32,
TLV_TYPE_INT32,
TLV_TYPE_STRING,
TLV_TYPE_FLOAT,
TLV_TYPE_BYTE_ARR,//字節數組
}tlv_type_e;

下面設計我們的收、發數據結構,大致思路如下:

5ce42d3a-dfc4-11ed-bfe3-dac502259ad0.png

我們創建一個總的結構體,用于管理A板往B板發送及A板接受來自B板的數據:

//總的協議數據
typedefstruct_protocol_data
{
protocol_id_eid;
protocol_value_tvalue;
}protocol_data_t;

其中,成員id是一個枚舉:

左右滑動查看全部代碼>>>

//數據ID
typedefenum_protocol_id
{
//A板發往B板
PROTOCOL_ID_A_TO_B_BASE=0x00,
PROTOCOL_ID_A_TO_B_CTRL_CMD,
PROTOCOL_ID_A_TO_B_DATE_TIME,
PROTOCOL_ID_A_TO_B_END=0x7F,

//B板發往A板
PROTOCOL_ID_B_TO_A_BASE=0x80,
PROTOCOL_ID_B_TO_A_WORK_STATUS,
PROTOCOL_ID_B_TO_A_END=0xFF,
}protocol_id_e;

包含著A->B、B->A的ID,因為ID是用1個字節標識,收、發的ID各預留一半,新增的ID在各自的BASE ID及END ID之間添加。

成員value是一個聯合體,用于管理A->B、B->A的value數據:

左右滑動查看全部代碼>>>

//所有協議數據value值
typedefunion_protocol_value
{
protocol_value_a_to_b_ta_to_b_value;
protocol_value_b_to_a_tb_to_a_value;
}protocol_value_t;

a_to_b_value及b_to_a_value也是聯合體,用于管理更細分的數據:

左右滑動查看全部代碼>>>

//A板發往B板的數據value值
typedefunion_protocol_value_a_to_b
{
protocol_data_ctrl_cmd_tctrl_cmd;
protocol_data_time_tdate_time;
}protocol_value_a_to_b_t;

//B板發往A板的數據value值
typedefunion_protocol_value_b_to_a
{
protocol_data_work_status_twork_status;
}protocol_value_b_to_a_t;

更細分的數據:

左右滑動查看全部代碼>>>

//控制命令
typedefenum_ctrl_cmd
{
CTRL_CMD_LED_ON,
CTRL_CMD_LED_OFF
}ctrl_cmd_e;

typedefstruct_protocol_data_ctrl_cmd
{
ctrl_cmd_ecmd;
}protocol_data_ctrl_cmd_t;

//時間數據
typedefstruct_protocol_data_time
{
intyear;
intmon;
intmday;
inthour;
intmin;
intsec;
}protocol_data_time_t;

//工作狀態
typedefenum_work_status
{
WORK_STATUS_NORMAL,
WORK_STATUS_ERROR
}work_status_e;

typedefstruct_protocol_data_work_status
{
work_status_estatus;
}protocol_data_work_status_t;

明確了我們需要進行交互的數據的類型之后,解析來我們就可以根據它們的特點來編寫組包、解析函數了。

2、組包

大致思路如下:

5d11d35c-dfc4-11ed-bfe3-dac502259ad0.png

組包函數:

左右滑動查看全部代碼>>>

intprotocol_data_packet(uint8_t*buf,uint16_tlen,protocol_data_t*protocol_data)
{
intret=-1;
intvalue_len=0;
intoffset=0;
protocol_format_t*p_protocol_format=NULL;

if(!buf||!protocol_data||lenid)
{
casePROTOCOL_ID_A_TO_B_CTRL_CMD:
{
printf("PROTOCOL_ID_A_TO_B_CTRL_CMD
");
value_len=sizeof(protocol_data->value.a_to_b_value.ctrl_cmd);
printf("protocol_format.length=%d
",value_len);
break;
}
casePROTOCOL_ID_A_TO_B_DATE_TIME:
{
printf("PROTOCOL_ID_A_TO_B_DATE_TIME
");
value_len=sizeof(protocol_data->value.a_to_b_value.date_time);
printf("value_len=%d
",value_len);
break;
}

default:
break;
}

//為協議格式數據申請內存
p_protocol_format=(protocol_format_t*)malloc(sizeof(protocol_format_t)+value_len);
if(NULL==p_protocol_format)
{
printf("mallocerror
");
returnret;
}

//填充協議數據各字段
p_protocol_format->head=PROTOCOL_HEAD;
p_protocol_format->id=protocol_data->id;
p_protocol_format->type=TLV_TYPE_BYTE_ARR;
p_protocol_format->length=value_len;
if(p_protocol_format->length<=?PROTOCOL_VALUE_MAX_LEN)
????{
????????memcpy(p_protocol_format->value,&protocol_data->value.a_to_b_value,p_protocol_format->length);
}
else
{
printf("protocol_format.length>PROTOCOL_VALUE_MAX_LEN
");
}

//計算校驗值
uint32_tcrc_data_len=sizeof(protocol_format_t)+value_len;
uint16_tcrc16=crc16_x25_check((uint8_t*)p_protocol_format,crc_data_len);
printf("crc16=%#x
",crc16);

//struct->buf
memcpy(buf,p_protocol_format,crc_data_len);
offset+=crc_data_len;
memcpy(buf+offset,&crc16,sizeof(uint16_t));
offset+=sizeof(uint16_t);

//釋放內存
free(p_protocol_format);
p_protocol_format=NULL;

returnoffset;
}

3、解包

大致思路如下:

5d4000ba-dfc4-11ed-bfe3-dac502259ad0.png

解包函數:

左右滑動查看全部代碼>>>

//解包函數
voidprotocol_data_parse(protocol_data_t*protocol_data,uint8_t*buf,uint16_tlen)
{
protocol_format_t*p_protocol_format=NULL;

if(!buf||!protocol_data||lenstruct
memcpy(p_protocol_format,buf,sizeof(protocol_format_t)+value_len);
printf("protocol_data->id=%#x
",p_protocol_format->id);

//通過數據ID來解析各對應的數據
switch(p_protocol_format->id)
{
casePROTOCOL_ID_B_TO_A_WORK_STATUS:
{
printf("PROTOCOL_ID_B_TO_A_WORK_STATUS
");
uint8_twork_status_len=sizeof(protocol_data->value.b_to_a_value.work_status);
if(p_protocol_format->length==work_status_len)
{
memcpy(&protocol_data->value.b_to_a_value.work_status,p_protocol_format->value,p_protocol_format->length);
}
else
{
printf("p_protocol_format->lengtherror
");
}
break;
}

default:
break;
}

//釋放內存
free(p_protocol_format);
p_protocol_format=NULL;
}

4、CRC16校驗

CRC16分很多種:CRC16-X25、CRC16-MODBUS、CRC16-XMODEM等。

這里我們使用CRC16-X25:

staticconstunsignedshortcrc16_table[256]=
{
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78
};

uint16_tcrc16_x25_check(uint8_t*data,uint32_tlength)
{
unsignedshortcrc_reg=0xFFFF;

while(length--)
{
crc_reg=(crc_reg>>8)^crc16_table[(crc_reg^*data++)&0xff];
}

return(uint16_t)(~crc_reg)&0xFFFF;
}

5、測試代碼

下面我們編寫組包、解包測試代碼:

組包控制命令數據,并把組包之后的發送緩沖區中的數據打印出來。

組包時間數據,并把組包之后的發送緩沖區中的數據打印出來。

從一個模擬的工作狀態接受緩沖區數據中解析工作狀態數據并打印出來。

測試代碼如:

左右滑動查看全部代碼>>>

//微信公眾號:嵌入式大雜燴
#include
#include
#include"protocol_tlv.h"

intmain(intarc,char*argv[])
{
staticuint8_tsend_buf[PROTOCOL_MAX_LEN]={0};
protocol_data_tprotocol_data_send={0};
intsend_len=0;

printf("
==============================testpacket===========================================
");
//模擬組包發送控制命令
bzero(send_buf,sizeof(send_buf));
bzero(&protocol_data_send,sizeof(protocol_data_t));
protocol_data_send.id=PROTOCOL_ID_A_TO_B_CTRL_CMD;
protocol_data_send.value.a_to_b_value.ctrl_cmd.cmd=CTRL_CMD_LED_OFF;
send_len=protocol_data_packet(send_buf,PROTOCOL_MAX_LEN,&protocol_data_send);
printf("sendctrldata=");
print_hex_data_frame(send_buf,send_len);

//模擬組包發送時間數據
bzero(send_buf,sizeof(send_buf));
bzero(&protocol_data_send,sizeof(protocol_data_t));
protocol_data_send.id=PROTOCOL_ID_A_TO_B_DATE_TIME;
protocol_data_send.value.a_to_b_value.date_time.year=2022;
protocol_data_send.value.a_to_b_value.date_time.mon=8;
protocol_data_send.value.a_to_b_value.date_time.mday=20;
protocol_data_send.value.a_to_b_value.date_time.hour=8;
protocol_data_send.value.a_to_b_value.date_time.min=8;
protocol_data_send.value.a_to_b_value.date_time.sec=8;
send_len=protocol_data_packet(send_buf,PROTOCOL_MAX_LEN,&protocol_data_send);
printf("senddate_timedata=");
print_hex_data_frame(send_buf,send_len);

printf("
==============================testparse===========================================
");
//模擬解析工作狀態數據
uint8_twork_status_buf[11]={0x55,0xAA,0x81,0x08,0x04,0x01,0x00,0x00,0x00,0xf2,0x88};
protocol_data_tprotocol_data_recv={0};

uint16_tcalc_crc16=crc16_x25_check(work_status_buf,sizeof(work_status_buf)-2);
uint16_trecv_crc16=(uint16_t)(work_status_buf[10]<

編譯、運行:

5d6af7de-dfc4-11ed-bfe3-dac502259ad0.png

對照著我們制定的協議,數據完全正確!

ITLV格式的其它用法

ITLV格式具有很強的靈活性,我們這里使用的數據類型Type為字節數組,其實使用字符串類型也很常用,比如為了協議具備更強的可讀性、方便調試,可以在Value字段里再封裝一層JSON格式數據。其實我覺得Type的選項只保留字節數組及字符串就夠用了,可以滿足所有情況。

當然,可能有些數據長度總是定長的,也可以用其它定長的類型。比如數據都是一些定長的類型,那么L字段也可以省略掉。實際中,比較通用的做法就是:全用字節數組或者全用字符串。別混著用,代碼可能會很混亂。

審核編輯:湯梓紅

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

    關注

    28

    文章

    911

    瀏覽量

    40379
  • TCP
    TCP
    +關注

    關注

    8

    文章

    1377

    瀏覽量

    79186
  • 函數
    +關注

    關注

    3

    文章

    4345

    瀏覽量

    62867
  • 嵌入式軟件
    +關注

    關注

    4

    文章

    240

    瀏覽量

    26688
  • MQTT
    +關注

    關注

    5

    文章

    653

    瀏覽量

    22622

原文標題:一個小而巧的自定義嵌入式軟件通信協議

文章出處:【微信號:嵌入式應用研究院,微信公眾號:嵌入式應用研究院】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    【LabVIEW串口通信】串行通信協議的可配置轉換問題

    本帖最后由 fantek 于 2013-12-31 18:26 編輯 目前存在的問題:主機( 計算機,PLC等)通過串口連接兩臺或多臺通信協議樣的儀器設備,而這些設備都是自定義協議
    發表于 09-29 02:26

    使用自定義協議的USART

    是提供在AT32微控制器上創建IAP應用程序的般準則。AT32微控制器可以運行用戶特定的固件來對微控制器中嵌入的閃存執行IAP。此功能可以使用產品可用和支持的任何通信接口。使用自定義
    發表于 01-14 06:14

    使用51單片機完成簡單的串口通信協議

    轉載自:自定義串口通信協議的實現weixin_33885253 2017-01-18 21:11:00 1926收藏 4 文章標簽: 嵌入式 c/c++ java版權使用51單片機完成
    發表于 01-19 07:30

    嵌入式開發中自定義協議的解析與組包相關案例分享

    1、嵌入式開發中自定義協議的解析與組包  在嵌入式產品開發中,經常會遇到兩設備之間的通信、設備
    發表于 10-27 17:01

    SOPC中自定義外設和自定義指令性能分析

    SOPC中自定義外設和自定義指令性能分析 NiosII是建立在FPGA上的嵌入式軟核處理器,靈活性很強。作為體現NiosII靈活性精髓
    發表于 03-29 15:12 ?1629次閱讀
    SOPC中<b class='flag-5'>自定義</b>外設和<b class='flag-5'>自定義</b>指令性能分析

    基于嵌入式網關的socket編程及通信協議

    基于嵌入式網關的socket編程及通信協議
    發表于 08-31 14:59 ?6次下載
    基于<b class='flag-5'>嵌入式</b>網關的socket編程及<b class='flag-5'>通信協議</b>

    基于嵌入式中央處理單元(CPU)的自定義指令

    Arm啟用了用于嵌入式中央處理單元(CPU)的自定義指令,以在不斷變化的世界中為芯片制造商提供更大的靈活性。新的自定義說明將使那些獲得Arm架構許可并設計自己的芯片的合作伙伴能夠將其片上系統(SoC)產品與
    發表于 10-09 14:19 ?913次閱讀

    嵌入式的CPU自定義指令有什么特點

    Arm的自定義指令最早將在2020年上半年在ArmCortex?M33CPU中開展,新的和現有的被許可人將無需支付額外費用,因此SoC設計人員可以為嵌入式和互聯網添加自己的指令不會
    的頭像 發表于 02-05 17:32 ?2875次閱讀

    如何實現自定義串口通信協議

    些初學者總覺得通信協議很復雜的知識,把它想的很高深,導致不知道該怎么學。 同時,偶爾有讀者問關于串口自定義
    的頭像 發表于 06-01 10:01 ?4584次閱讀

    自定義串口通信協議

    原題敘述有若干個溫度采集器,每個溫度采集器可實現8路溫度的測量。試設計通信協議,用于溫度采集器與上位計算機的串行通信協議,可實現溫度采集數據上傳、上位機控制每路溫度測量通的開啟功能
    發表于 12-02 14:21 ?18次下載
    <b class='flag-5'>自定義</b>串口<b class='flag-5'>通信協議</b>

    C#與STM32自定義通信協議

    C#與STM32自定義通信協議功能:1.可通過C#上位機對多臺STM32下位機進行控制2.自定義上位機與下位機通信協議
    發表于 12-24 18:59 ?37次下載
    C#與STM32<b class='flag-5'>自定義</b><b class='flag-5'>通信協議</b>

    嵌入式開發中自定義協議的解析與組包

    嵌入式產品開發中,經常會遇到兩設備之間的通信、設備與服務器的通信、設備和上位機的通信等,很多時候通信
    發表于 01-25 11:14 ?5次下載
    <b class='flag-5'>嵌入式</b>開發中<b class='flag-5'>自定義</b><b class='flag-5'>協議</b>的解析與組包

    拓普微智能液晶顯示模塊HMI自定義通信協議

    隨著工業技術的發展,HMI(人機界面)的應用領域愈加廣泛。通過拓普微的智能液晶顯示模塊實現的自定義通信協議能在定程度上維護企業的數據隱秘性,提升產品功能的多樣性,并且能夠解決企業通信協議
    的頭像 發表于 12-09 14:01 ?1267次閱讀
    拓普微智能液晶顯示模塊HMI<b class='flag-5'>自定義</b><b class='flag-5'>通信協議</b>

    智能液晶顯示模塊HMI自定義通信協議分析

    隨著工業技術的發展,HMI(人機界面)的應用領域愈加廣泛。通過拓普微的智能液晶顯示模塊實現的自定義通信協議能在定程度上維護企業的數據隱秘性,提升產品功能的多樣性,并且能夠解決企業通信協議
    的頭像 發表于 07-30 14:46 ?1366次閱讀
    智能液晶顯示模塊HMI<b class='flag-5'>自定義</b><b class='flag-5'>通信協議</b>分析

    幾種常見嵌入式設備通信協議

    幾種常見嵌入式設備通信協議
    的頭像 發表于 09-18 16:43 ?1719次閱讀
    幾種常見<b class='flag-5'>嵌入式</b>設備<b class='flag-5'>通信協議</b>
    主站蜘蛛池模板: 无人区在线日本高清免费| 国产短视频精品区| 欧美极限变态扩张video| 川师 最美老师| 夜夜艹日日干| 日韩AV爽爽爽久久久久久| 狠狠色丁香婷婷久久综合五月| 97人妻精品全国免费视频| 神马影院午夜伦理限级| 美国色情三级欧美三级纸匠情挑| 国产精品99久久久久久AV色戒 | 97在线视频免费观看97| 67194成网页发布在线观看| 亚洲激情一区| 欧美特级特黄a大片免费| 久久视频这有精品63在线国产| 国产精品999| 国产成人8x视频一区二区| 9久爱午夜视频| 野花日本免费完整版高清版动漫| 亚洲AV日韩AV欧美在线观看网 | 欧美特级特黄a大片免费| 欧美日韩中文国产一区发布| 欧美性黑吊xxx| 日本一区不卡在线播放视频免费| 久久一本岛在免费线观看2020| 成年视频xxxxxx在线| 7723日本高清完整版在线观看| 最美白虎逼| 亚洲中文字幕一二三四区苍井空 | 99精品久久久久久久| 伊人热人久久中文字幕| 亚洲qvod图片区电影| 视频成人永久免费看| 小短文H啪纯肉公交车| 天天狠狠弄夜夜狠狠躁·太爽了| 男女免费观看在线爽爽爽视频| 精品网站一区二区三区网站| 国产精品一区二区20P| 成人毛片一区二区三区| 国产成人免费不卡在线观看|