在线免费观看成年人视频-在线免费观看国产-在线免费观看国产精品-在线免费观看黄网站-在线免费观看精品

產(chǎn)品分類

當(dāng)前位置: 首頁 > 工業(yè)電氣產(chǎn)品 > 端子與連接器 > 線路板連接器 > FFC連接器

類型分類:
科普知識
數(shù)據(jù)分類:
FFC連接器

CC2640R2: TI BLE OAD(OTA)協(xié)議在Android和iOS上的APP流程和代碼解讀

發(fā)布日期:2022-04-28 點擊率:207

Other Parts Discussed in Post: CC2640

作者: TI 技術(shù)應(yīng)用工程師 張彥

CC2640 R2是一款面向 Bluetooth Smart 應(yīng)用的低功耗無線 MCU。該芯片運行TI的BLE協(xié)議棧,并支持OAD(Over the Air Download)空中固件升級功能,此空中固件升級功能就是利用Android或者iOS的產(chǎn)品對應(yīng)app通過BLE對CC2640R2的產(chǎn)品進行固件升級。同時,TI其實提供了Anroid和iOS的源碼對其支持:http://www.ti.com/tool/SENSORTAG-SW?keyMatch=sensortag&tisearch=Search-EN-Everything。這部分的源碼是基于TI的SensorTag硬件進行開發(fā)的,包含了很多內(nèi)容,對于客戶來說,基本上不適合直接拿去使用,但是其中的OAD部分代碼,卻是可以通用的。但是對于客戶的iOS或者Android app工程師來說,往往對BLE協(xié)議不熟,那就更不用說TI的OAD協(xié)議了,所以即使提供了源碼,客戶在這一部分開發(fā)起來還是很困難。本文就針對這一點,針對app開發(fā)過程中對OAD功能做一個流程和代碼解讀,用以幫助客戶更方便完成此功能開發(fā)。

首先,第一步是從上面的鏈接下載到最新的android和iOS源碼,上述鏈接最終會指引到github的下載地址。

有了源碼之后,我們就可以解讀了。

從app的角度上來看TI的OAD協(xié)議,大致是這樣的:

App連接上設(shè)備之后,就能發(fā)現(xiàn)OAD的service和characteristics(服務(wù)和特征值):

服務(wù)的UUID:0xFFC0,對應(yīng)的128bit UUID:

F000FFC0-0451-4000-B000-000000000000

服務(wù)下面有兩個主要特征值:(其他特征值可以暫且忽略)

OAD Image Identify,UUID:0xFFC1;OAD Image Block,UUID:0xFFC2,對應(yīng)的128bit UUID:

– OAD Image Identify F000FFC1-0451-4000-B000-000000000000,用于交互確認(rèn)固件版本信息。

– OAD Image Block       F000FFC2-0451-4000-B000-000000000000,用于傳送新的固件。

固件更新的所有操作都是對上面這兩個特征值進行操作。

用TI的SensorTag app可以看到:

用第三方app比如light blue也能看到,安卓手機的情況也是一樣。

 

在TI提供的示例代碼中,在Android中,客戶唯一要用到的文件其實就是FwUpdateActivity_CC26xx.java,所有的OAD流程基本全部都在這里。另外有一個相關(guān)的文件BluetoothLeService.java,這個是TI的SensorTag App封裝的BLE相關(guān)API接口集合,主要用于一些特征值的操作,比如write,read等,OAD用到的主要就是write,通過write來神奇地實現(xiàn)各種流程。在iOS源碼中,流程相關(guān)的主要是BLETIOAD2Profile.m(注意,另外一個BLETIOADProfile.m,這是針對舊版的CC254x的,和CC26xx略有不同,這里不做討論,有興趣可以自己去看),基本就在這里,另外對應(yīng)也有一個BLE相關(guān)接口集合BLEUtility.m。

第一步

從app來講,開始OAD的第一步就是先使能上面兩個特征值的notification功能。

簡單來說就是調(diào)用android或者iOS提供的現(xiàn)有API,分分鐘完成。(藍(lán)牙協(xié)議上來說就是往這兩個特征值的CCC句柄上寫01:00,我們這里盡量不討論具體藍(lán)牙協(xié)議,從簡考慮,有興趣的人可以自己去研究一下)。

對應(yīng)到代碼里,
Android在FwUpdateActivity_CC26xx.java中,新的固件文件裝載到手機內(nèi)存后:public void onLoad(View v)中調(diào)用:

 

mLeService.setCharacteristicNotification(mCharIdentify, true);

mLeService.setCharacteristicNotification(mCharBlock, true);

實際上可以根據(jù)客戶真實代碼在適當(dāng)位置加上面兩個函數(shù)就行,這樣第一步其實就完成了。

*更多說明:

上面兩個函數(shù),其實就是BluetoothLeService.java中的API,最終追蹤下去的話是調(diào)用Android SDK 的BLE API來使能notification:

mBluetoothGatt.setCharacteristicNotification(request.characteristic, request.notifyenable)

其實我們也可以直接調(diào)用這個來實現(xiàn)上面的功能。

iOS在BLETIOAD2Profile.m里的-(void) configureProfile 函數(shù)里調(diào)用:

CBUUID *sUUID = [CBUUID UUIDWithString:TI_OAD_SERVICE];

CBUUID *cUUID = [CBUUID UUIDWithString:TI_OAD_IMAGE_NOTIFY];

[BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:YES];

cUUID = [CBUUID UUIDWithString:TI_OAD_IMAGE_BLOCK_REQUEST];

if (self.notifications)[BLEUtility setNotificationForCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID enable:YES];

 

注意,iOS代碼里面OAD Image Identify和OAD Image Block對應(yīng)的是TI_OAD_IMAGE_NOTIFY和TI_OAD_IMAGE_BLOCK_REQUEST。同樣,在iOS里適當(dāng)位置調(diào)用這個函數(shù)就行。

*更多說明:

對于iOS TI給出的源碼,是BLEUtility.m中封裝了Apple的BLE API來使能notification:

- (void)setNotifyValue:(BOOL)enabled forCharacteristic:(CBCharacteristic *)characteristic;

一樣,我們也可以直接調(diào)用這個來實現(xiàn)上面的功能。

空中sniffer抓包看的話,就能看到這兩個使能notification的流程:

 

第二步

 

從app角度來講,第二步就是要把新固件的版本信息從手機傳送到外設(shè)上,讓外設(shè)進行判斷是否要升級。

這一步就要用到OAD Image Identify,這個特征值在整個OAD過程中只會用到一次,就是在這里。

  • App這邊先從獲得到的新固件里把固件的image header (16個字節(jié)) 讀出來,image header就是固件的二進制文件的開始16個字節(jié),很容易獲取到。


體現(xiàn)在代碼里,

Android:還是在FwUpdateActivity_CC26xx.java中,在打開新固件文件的時候:

private boolean loadFile(String filepath, boolean isAsset) {

 

順便創(chuàng)建要發(fā)送的16個字節(jié)image header結(jié)構(gòu):

mFileImgHdr = new ImgHdr(mFileBuffer,readLen);

這個構(gòu)造函數(shù)就會把image header部分給組織好放到16字節(jié)的一個buffer中去,用以接下來發(fā)送給設(shè)備。這個類的定義也在FwUpdateActivity_CC26xx.java中:

private class ImgHdr {
   ……


   ImgHdr(byte[] buf, int fileLen) {
       this.len = (fileLen / (16 / 4));
       this.ver = 0;
       this.uid[0] = this.uid[1] = this.uid[2] = this.uid[3] = 'E';
       this.addr = 0;
       this.imgType = 1; //EFL_OAD_IMG_TYPE_APP
      
this.crc0 = calcImageCRC((int)0,buf);
       crc1 = (short)0xFFFF;
       ……
   }

可以看到構(gòu)造函數(shù)里面,雖然有讀取到的實際固件文件的image header作為輸入?yún)?shù),但我們實際的代碼里面為了演示,只是寫死了一些內(nèi)容。這里可以根據(jù)實際情況修改一下,根據(jù)前面提到的16字節(jié)header的順序來就行,比如:

private class ImgHdr {
   ……


   ImgHdr(byte[] buf, int fileLen) {
       this.len = (fileLen / (16 / 4));
       this.ver = buf[5];

       this.ver = (this.ver << 8) | buf[4];
       this.uid[0] = buf[8];this.uid[1] = buf[9];

       this.uid[2] = buf[10]; this.uid[3] = buf[11];
       this.addr = buf[13];

       this.addr = (this.addr << 8) | buf[12];
       this.imgType = buf[14];//EFL_OAD_IMG_TYPE_APP
      
this.crc0 = calcImageCRC((int)0,buf);
       crc1 = (short)0xFFFF;
       ……
   }

這樣就基本能拿到實際的真實數(shù)據(jù)了。

 

iOS:就很簡單了,直接把新固件文件開始的16字節(jié)header復(fù)制到代碼里就可以了,還是在BLETIOAD2Profile.m里,在-(void) uploadImage 函數(shù)中:

   img_hdr_t2 imgHeader;

  

uint32_t pages = ((uint32_t)self.imageFile.length / 4096);

//做個CRC校驗,放到image header中去,同時把image header的16字節(jié)內(nèi)容補完整。

[self calcImageInfo:0 pages:pages imageHeader:&imgHeader buf:imageFileData];

  

      memcpy(requestData, &imgHeader, 16);

需要注意的是iOS給的源碼里面,image header內(nèi)容的補充是在crc校驗函數(shù)里面一并完成的:-(void) calcImageInfo里:

imageHeader buf:(uint8_t *)buf {

   imageHeader->len = (pages * FLASH_PAGE_SIZE) / (OAD_BLOCK_SIZE / FLASH_WORD_SIZE);

   imageHeader->ver = 0;

   imageHeader->uid[0] = imageHeader->uid[1] = imageHeader->uid[2] = imageHeader->uid[3] = 'E';

   imageHeader->addr = (firstpage * FLASH_PAGE_SIZE) / (OAD_BLOCK_SIZE / FLASH_WORD_SIZE);

   imageHeader->imgType = EFL_OAD_IMG_TYPE_APP;

   imageHeader->res[0] = 0xff;

   imageHeader->crc0 = [self calcImageCRC:firstpage imageHeader:imageHeader buf:buf];

   imageHeader->crc1 = 0xffff;

}

這樣iOS這里也得到完整的image header信息了。

 

  • 接下來app將通過OAD Image Identify這個特征值首先把前面得到的新的固件的版本信息發(fā)送給設(shè)備(CC2640R2),這個版本信息包含在前面得到的image header的16個字節(jié)buffer里,把這個發(fā)出去給設(shè)備就行了。

體現(xiàn)在代碼里,

Android,還是在FwUpdateActivity_CC26xx.java中,開始流程函數(shù):

private void startProgramming() {

 

獲取image identify(其實就是image header):

mCharIdentify.setValue(mFileImgHdr.getRequest());

 

并通過BLE的write characteristic動作從app發(fā)送到設(shè)備端:

mLeService.writeCharacteristic(mCharIdentify);

 

*更多說明:

上面write characteristic函數(shù)其實就是BluetoothLeService.java中的API,最終追蹤下去的話是調(diào)用Android SDK 的BLE API來進行BLE的write command操作:

mBluetoothGatt.writeCharacteristic(request.characteristic);

其實我們也可以直接調(diào)用這個來實現(xiàn)上面的功能。

iOS代碼中,在BLETIOAD2Profile.m里,還是在-(void) uploadImage 函數(shù)里:
CBUUID *cUUID = [CBUUID UUIDWithString:TI_OAD_IMAGE_NOTIFY];

[BLEUtility writeNoResponseCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:requestData length:16]];

通過 write characteristic來把image header發(fā)送到設(shè)備端。

*更多說明:

這個的write函數(shù),其實也是在BLEUtility.m里面封裝了Apple的BLE標(biāo)準(zhǔn)API:

- (void)writevalue:(NSData *)data forCharacteristic:(CBCharacteristic *)characteristic type:(CBCharacteristicWriteType)type;

我們也可以直接調(diào)用這個來實現(xiàn)上面的功能。

空中sniffer抓包能看到write command發(fā)送image header:

 

 

  • 最后,設(shè)備收到image header之后,會進行和自己本身的固件版本號進行比較。如果發(fā)現(xiàn)image header中的版本號沒有自己的版本號新,那么就直接以notification (這里notification是在前面第一步使能)的形式在OAD Image Identify上回復(fù)自己的版本號給手機,表示拒絕此次固件升級,此次升級就此結(jié)束。

空中sniffer抓包,其中標(biāo)黃的部分就是設(shè)備回復(fù)自身版本號,表示拒絕此次固件升級:

 

如果發(fā)現(xiàn)image header中的版本號確實比自己本身的固件版本號要新,那么就同意這次固件更新,會在OAD Image Block這個特征值的notification (這里notification是在前面第一步使能)上回復(fù)0x0000,表示準(zhǔn)備接受序列號第0個固件內(nèi)容包。注意實在OAD Image Block這個特征值上,不是OAD Image Identify這個特征值上,OAD Image Identify這個特征值的使命在前面已經(jīng)完成,后面不會再使用。

從sniffer看就會看到0x0000從外設(shè)發(fā)回手機:

總結(jié)下來第二步,就是app要在OAD Image Identify特征值上發(fā)送新固件的image header到設(shè)備端,然后設(shè)備端進行判斷是否要接收新的固件進行升級,如果要升級,則在OAD Image Block特征值上向手機回復(fù)0x0000,不然回復(fù)自己目前的固件版本號表示拒絕更新。總結(jié)起來就是下面的兩個流程圖:


第三步

這一步從app來講就是按照順序發(fā)送固件內(nèi)容了。

手機在OAD Image Block特征值上收到0x0000之后就代表設(shè)備端愿意接收新固件,并且意思是對方準(zhǔn)備好接收第0個固件包。每個固件包的內(nèi)容長度是16個字節(jié),并且需要在頭部放上兩個字節(jié)的序列號,序列號從0x0000開始累加,一直到最后一個固件包。

*注意這個序列號是小端在前的,所以后面是0x0100,0x0200,0x0300,0x0400,…,0xFF00,0x0001,0x0101,0x0201,…這樣累加上去。

從空中sniffer上看,很容易就能看到整個流程的交互:

首先是手機發(fā)送第0包的固件內(nèi)容,通過BLE的Write方式在OAD Image Block特征值上發(fā)送,固件block內(nèi)容是16個字節(jié),注意下圖標(biāo)黃的頭兩個字節(jié),是固件包序列號,第0包是0x0000,所以包的總長是16+2=18個字節(jié)。

那么設(shè)備收到APP發(fā)送過去的第0包固件后,回復(fù)請求下一個固件包,通過Notification的方式在OAD Image Block特征值上回復(fù)0x0100:

APP收到設(shè)備發(fā)回的0x0100,就知道對方已經(jīng)等待接收下一包固件,于是就發(fā)送下一包0x0100的固件包,以此類推,一直到固件發(fā)送結(jié)束。

具體到代碼里,

在Android中,就是在programBlock()函數(shù)里,這里我們只關(guān)注核心部分:

private void programBlock() {
  

   省略前面邏輯相關(guān)代碼,工程里面很容易看懂。
       // Prepare block

   首先自然是包序列號,buffer的頭兩個字節(jié):
      
mOadBuffer[0] = Conversion.loUint16(mProgInfo.iBlocks);
       mOadBuffer[1] = Conversion.hiUint16(mProgInfo.iBlocks);
       然后是16個字節(jié)的固件block包內(nèi)容:

   System.arraycopy(mFileBuffer, mProgInfo.iBytes, mOadBuffer, 2, OAD_BLOCK_SIZE);

       // Send block

   接著把這18個字節(jié)通過write方式在OAD Image Block特征值上發(fā)送:
      
mCharBlock.setValue(mOadBuffer);
       boolean success = mLeService.writeCharacteristicNonBlock(mCharBlock);
       如果發(fā)送成功,那么就順移相關(guān)的包序列號還有固件文件中的位移標(biāo)志:
      
if (success) {
           // Update stats
          
packetsSent++;
           mProgInfo.iBlocks++;
           mProgInfo.iBytes += OAD_BLOCK_SIZE;
           mProgressBar.setProgress((mProgInfo.iBlocks * 100) / mProgInfo.nBlocks);

       如果最后一個固件block成功完成,那么就恭喜,OAD順利成功!
           if (mProgInfo.iBlocks == mProgInfo.nBlocks) {
               …
               b.setTitle("Programming finished");
               b.setPositiveButton("OK",null);

               alertDialog d = b.create();
               d.show();
               mProgramming = false;
              mLog.append("Programming finished at block " + (mProgInfo.iBlocks + 1) + "");
           }
       } else {
           mProgramming = false;
           msg = "GATT writeCharacteristic failed";
       }
      
  

}

*更多說明:

上面boolean success = mLeService.writeCharacteristicNonBlock(mCharBlock);這個函數(shù),其實就是BluetoothLeService.java中的API,最終追蹤下去的話是調(diào)用Android SDK 的BLE API來實現(xiàn)的:mBluetoothGatt.writeCharacteristic(request.characteristic);

 

iOS的代碼里,體現(xiàn)在BLETIOAD2Profile.m里的-(void) sendonePacket 函數(shù),只看核心部分,和Android很像的,因為流程一樣:

-(void) sendonePacket {

            …

            …

   //Prepare Block

   首先自然是包序列號,buffer的頭兩個字節(jié):

   uint8_t requestData[2 + OAD_BLOCK_SIZE];

  

   requestData[0] = LO_UINT16(self.iBlocks);

   requestData[1] = HI_UINT16(self.iBlocks);

   然后是16個字節(jié)的固件block包內(nèi)容:

   memcpy(&requestData[2] , &imageFileData[self.iBytes], OAD_BLOCK_SIZE);

  

   CBUUID *sUUID = [CBUUID UUIDWithString:TI_OAD_SERVICE];

   CBUUID *cUUID = [CBUUID UUIDWithString:TI_OAD_IMAGE_BLOCK_REQUEST];

   接著把這18個字節(jié)通過write方式在OAD Image Block特征值上發(fā)送:

[BLEUtility writeNoResponseCharacteristic:self.d.p sCBUUID:sUUID cCBUUID:cUUID data:[NSData dataWithBytes:requestData length:2 + OAD_BLOCK_SIZE]];

   如果發(fā)送成功,那么就順移相關(guān)的包序列號還有固件文件中的位移標(biāo)志:

   dataWithBytes:requestData length:2 + OAD_BLOCK_SIZE]);

   self.sndDataCount ++;

   self.iBlocks++;

   self.iBytes += OAD_BLOCK_SIZE;

   self.sentPackets++;

   如果最后一個固件block成功完成,那么就恭喜,OAD順利成功!

   if(self.iBlocks == self.nBlocks) {

       self.inProgramming = NO;

       [self.oadDelegate didFinishUploading];

       return;

   }

流程和Android完全一樣,我連注釋都直接復(fù)制過來了J。

 

 

這樣就是完整的OAD流程了。總結(jié)就是分三步走:使能OAD Image Identify和OAD Image Block 的notification,在OAD Image Identify上發(fā)送新固件版本(image header)進行確認(rèn),最后在OAD Image Block上按順序把固件發(fā)送完,結(jié)束。

 

 

 

下一篇: PLC、DCS、FCS三大控

上一篇: 在AM335X平臺上運行ub

推薦產(chǎn)品

更多
欧美最猛黑人XXXⅩ猛男视频| 噜噜狠狠色综合久色AⅤ网址| 久久久久久亚洲精品无码| 老师上课跳D突然被开到最大视频| 欧美另类VIDEOSSEXO潮| 牲欲强的熟妇农村老妇女视频| 五十熟妇日本熟妇久久| 亚洲午夜无码毛片Av| AV成人午夜无码一区二区| 高清国语自产拍免费视频| 激情综合亚洲色婷婷五月APP| 蜜芽国产尤物AV尤物在线看| 三级日本高清完整版热播| 亚洲大尺度专区无码| 99久久精品费精品国产一区二区| 丰满熟妇人妻中文字幕| 精品卡一卡二卡3卡高清乱码| 浓精喷进老师黑色丝袜| 偷看娇妻在别人胯下沦陷小说| 亚洲精品天堂成人片AV在线播放| CHINESE中年熟妇FREE| 国产裸体XXXX视频在线播放| 乱人伦人妻中文字幕无码| 沈陽43歲熟女高潮視頻| 亚洲一区在线观看XXX| 成人国内精品久久久久影院VR| 国产中国男男GayGay| 欧美丰满熟妇XX猛交| 无人区卡一卡二入口| 18禁真人床震无遮挡免费| 国产成人精品一区二区秒播 | 99精品国产再热久久无毒不卡| 国产成人无码区免费A∨视频网站 国产成人无码免费视频在线 | 无码国产成人午夜电影在线观看| 夜夜躁婷婷AV蜜桃妖精视频| 国产999精品成人网站| 鲁鲁网亚洲站内射污| 天天狠天天透天天爱综合| 一区二区三区国产精华护肤品| 丰满女教师中文字幕5| 久久永久免费人妻精品我不卡 | 成人无码专区免费播放三区| 久久精品爆乳熟妇AV-区| 色噜噜人体337P人体| 怡红院亚洲第一综合久久| 国产成人无码免费看片软件| 女刑警被两个黑人挺进| 亚洲AV优女天堂熟女| 成人无码区免费A∨视频| 久久亚洲色WWW成人网址| 无码日韩人妻AV一区二区三区| AV鲁丝一区鲁丝二区鲁丝三区| 极限少妇人妻无石久久电影网| 日韩人妻潮喷中文在线视频| 曰本无码人妻丰满熟妇啪| 国产强伦姧在线看无码| 人妻丰满熟妇无码AV| 一二三四在线观看免费高清视频| 国产精品未满十八禁止观看| 人妻少妇精品无码专区APP| 亚洲一区二区三区中文字幕在线| 国产精品国产三级国产专不| 欧美性一区二区三区| 亚洲欧美国产精品专区久久| 国产成人精品免费久久久久| 欧美成人在线视频| 亚洲中文字幕日产乱码小说| 国产无遮挡又爽又黄大胸免费| 日日狠狠久久8888偷偷色| 2023国精产品一二三四区| 国产女人天天春夜夜春| 西西大胆无码视频免费| 18禁自慰网址进入| 国产日韩欧美亚欧在线| 久久亚洲日韩看片无码| 欧精国精产品一区| 人妻尝试又大又粗久久| 影音先锋亚洲AV少妇熟女| 国产无遮挡无码视频在线观看不卡 | 永久免费的AV在线网无码| 国内精品久久久久久久影视| 特黄AAAAAAAAA毛片免费| ZOOM与人性ZOOM视频| 裸睡时一自慰不小心就滑进去啦| 亚洲国产精品无码久久久蜜芽| 国产精品久久久久乳精品爆| 日韩AV一区二区三区| CHINA中国人CHINESE| 麻花豆传媒剧国产MV免费天美| 亚洲AV日韩AV永久无码电影| 99精产国品一二三产区区别在线 | 欧产日产国产精品| 越看越湿的啪啪的小说免费| 久久国产色欲AV38| 亚洲成A人一区二区三区| 国产毛片毛多水多的特级毛片| 少妇人妻中文字幕| 粗大的内捧猛烈进出动态图| 欧洲AV无码放荡人妇网站| 55夜色66夜色国产精品视频| 久欠精品国国产99国产精2| 亚洲色偷偷AV男人的天堂| 加勒比色综合久久久久久久久| 性色AⅤ一区二区三区天美传媒| 国产精华最好的产品有哪些| 十八禁无码免费网站| 帝王怀孕肚腹圆隆憋尿| 日韩一卡2卡3卡4卡| 成人观看免费毛片爽| 日本久久三级电影院| 爸爸缓慢有力送女儿的句子| 成熟妇女性成熟满足视频| 日本大片免A费观看视频| おやすみせくよ晚安免费影院| 欧美日韩在线视频一区| √天堂网WWW最新版| 蜜芽亚洲AV无码精品国产| 主人地下室惩罚骚奴的法律后果 | 任你躁X7X7X7X7在线观看| 薄荷奶糖(1V2)笔趣| 人与畜禽共性关系的重要性有哪些| А√天堂中文最新版在线种子| 人妻美妇疯狂迎合系列视频| 成人国产精品一区二区免费看| 日韩乱码人妻无码超清蜜桃| 俄罗斯大荫蒂女人毛茸茸| 少妇无码人妻一区二区三区| 国产成人拍精品视频午夜网站| 天干天干夜天干天天爽| 国产精品扒开腿做爽爽爽日本无码 | 不知火舞蹈三个小孩海边X| 色综合色天天久久婷婷基地| 国产产无码乱码精品久久鸭| 午夜美女裸体福利视频| 含羞草实验室隐藏路径2023| 亚洲乱码无码永久不卡在线| 久久久久久精品免费免费WEI| 在教室伦流澡到高潮H强圩| 女人ASS人体下部PICS| JAPANESE五十路熟妇| 搡老女人911熟妇老熟女| 国产精品久久久久AV| 亚精区在二线三线区别99| 精品久久久久久中文字幕大豆网| 欧美野外疯狂做受XXXX高潮| 苍井空一区二区三区在线观看| 天天躁夜夜躁很很躁| 国精品产露脸偷拍视频| 亚洲最大综合久久网成人| 逆徒每天都想着欺师犯上| 成年无码动漫AV片在线尤物| 我是你亲妈呀你爸知道死你| 狠狠躁夜夜躁人妻蜜臂AV| 曰本A级毛片无卡免费视频| 欧美最猛黑人XXXⅩ猛男无码| 公粗挺进了我的密道在线观看 | AV男人在线东京天堂| 日产精品卡2卡三卡乱码网址| 国产成人无码一区二区三区 | 少妇无码AV无码专区线Y| 国产亚洲日韩在线三区| 又湿又紧又大又爽又A视频| 欧洲美熟女乱又伦AV曰曰| 给丰满少妇按摩到高潮| 亚洲爆乳成AV人在线视菜奈实| 噜噜狠狠色综合久色AⅤ网址| 斑马视频电影免费观看| 午夜男女爽爽影院_性夜影院 | 又嫩又硬又黄又爽的视频| 欧洲PAYPAL网站WWW| 国产精品无码不卡一区二区三区| 亚洲精品无码专区在线观看| 女人扒下裤让男人桶到爽| 丰满的少妇XXXXX人妻| 亚洲精品TV久久久久久久久| 欧美巨大XXXX做受中文字幕| 贵阳40多岁熟女高潮呻吟| 亚洲国产精品无码久久久| 欧美激情内射喷水高潮| 国产乱码一区二区三区| 在办公室里揉弄小雪好爽| 日韩一卡2卡3卡4卡| 精品无码无人网站免费视频| WWW国产精品内射老熟女| 亚洲AⅤ国产成人AV片妓女| 男男GAy作爱免费观看| 国产精品久久高潮呻吟无码| 影音先锋新男人AV资源站| 思思久久99热只有频精品66| 久久精品女人天堂AV麻| 成人片黄网站色多多WWW| 亚洲精品国产成人AV| 人妻无码一区二区在线影院| 狠狠爱天天综合色欲网| JULIA绝顶快感高潮在线| 亚洲AV无码一期二期三期少妇| 欧美亚洲一区二区三区| 加勒比久久综合久久鬼色88| 播放片高清MV在线观看| 亚洲色精品VR一区二区三区|