基於SPP協議,通過iphone藍芽與經過蘋果MFI授權認證的硬體通訊,傳輸圖片
阿新 • • 發佈:2019-02-02
因為公司產品需要,要寫一個demo,演示iphone與硬體通過藍芽通訊,傳輸資料包,折騰好久,終於折騰了出來了。分享一下實現的過程。
首先,要拿到蘋果公司的MFI認證,然後要定義至少一種命令協議,讓配件支援,Apple 並不負責提供協議的註冊機制,製造商必須自己決定支援哪些協議,為了防止命名衝
突,協議的名字是反向的 DNS 字串,類似com.apple.myProtocol
。
定義好協議後,要在工程中宣告協議,在Info.plist的UISupportedExternalAccessoryProtocols鍵中宣告。
工程裡要新增ExternalAccessory 框架。
通過EAAccessoryManager獲取配件列表,通過EAAccessory與配件建立連線,就可以建立一個EASession回話,與配件進行通訊
。
詳細程式碼參照官方EADemo例項,裡面實現的很清楚。
我的任務是將圖片讀進去,提取它的raw資料,但由於圖片是96x96畫素,就是說raw資料大小有96x96x4個bit,大約40k,輸出到配件後要進行寫入,速度太慢,所以將raw數
據經過處理,去掉透明度,RGB分別取5位,6位,5位,這樣大約剩20k,即使這樣也要將每個資料包分段傳送,每段256個位元組,傳送資料前,加上一個檔案頭,每一段加上一個
段頭,每一段傳送之後等待硬體響應,響應之後才能傳送下一段,1s之內沒有接受響應則終止傳送。部分程式碼如下:
- UIImage *img=[UIImage imageNamed:myFilePath];//myFilePath點陣圖片路徑
- CGImageRef cgimage=img.CGImage;
- CFDataRef dataref=CGDataProviderCopyData(CGImageGetDataProvider(cgimage));//獲取圖片cfdata資料
-
int cgdatalength=CFDataGetLength(dataref);
- UInt8 *pixelByteData=(UInt8 *)malloc(cgdatalength);
- CFDataGetBytes(dataref, CFRangeMake(0,cgdatalength),pixelByteData);
- int eachgroupnum=256;//每一段資料大小為256bit
- int groumpcount=cgdatalength/(eachgroupnum*2);//分段總數
- NSMutableData *data1 = [NSMutableData data];
- const char *buf = [self.ID UTF8String];//將命令頭處理為位元組流
- if (buf)
- {
- uint32_t len = strlen(buf);
- char singleNumberString[3] = {'\0', '\0', '\0'};
- uint32_t singleNumber = 0;
- for(uint32_t i = 0 ; i <len; i+=2)
- {
- if ( ((i+1) <len) && isxdigit(buf[i]) && (isxdigit(buf[i+1])) )
- {
- singleNumberString[0] = buf[i];
- singleNumberString[1] = buf[i + 1];
- sscanf(singleNumberString, "%x", &singleNumber);
- uint8_t tmp = (uint8_t)(singleNumber & 0x000000FF);
- [data1 appendBytes:(void *)(&tmp) length:1];
- }
- else
- {
- break;
- }
- }
- }
- [data1 appendBytes:(void *)(&groumpcount) length:1];//將分段總數新增到位元組流中
- [[EADSessionController sharedController] writeData:data1];//傳送檔案頭
- //將圖片位元組流資料分成groumpcount分,每個畫素點去掉透明體,3位元組RGB處理成2位元組,讀入位元組流緩衝區
- NSMutableData *datas = [NSMutableData data];
- UInt16 temp=0;
- for(int i=0;i<groumpcount;i++)
- {
- [datas appendBytes:(void *)(&i) length:1];//段首編號部分
- [datas appendBytes:(void *)(&groumpcount) length:1];//段首編號分段總數部分
- for(int j=eachgroupnum*i*2;j<eachgroupnum*(i+1)*2;j=j+4)
- {
- temp=pixelByteData[j+2];
- temp+=pixelByteData[j+1]*32;
- temp+=pixelByteData[j]*2048;
- uint8_t tmp1 = (uint8_t)(temp & 0x0000FF00);
- uint8_t tmp2 = (uint8_t)(temp & 0x000000FF);
- [datas appendBytes:(void *)(&tmp1) length:1];
- [datas appendBytes:(void *)(&tmp2) length:1];
- }
- if (i==0) {
- [[EADSessionController sharedController] writeData:datas];//第一段資料直接傳送
- }
- else{
- if(readdatabuf==0xff0000){//readdatabuf為硬體響應發回的資料,當以一段資料成功接受後,給應用發回0xff0000,且readdatabuf值儲存最後 一次硬體響應
- [[EADSessionController sharedController] writeData:datas];//傳送下一段資料
- readdatabuf=0;//清空上一次接受的資料
- [datas setData:nil];//清空上一次傳送的資料
- continue;//結束本次迴圈
- }
- [self performSelector:@selector(laterwritedata:) withObject:datas afterDelay:1];
- if(temp==NO)
- {
- break;//1s之內沒有收到硬體的響應,跳出迴圈,終止傳送
- }
- }
- readdatabuf=0;//清空上一次接受的資料
- [datas setData:nil];//清空上一次傳送的資料
- }
- -(void) laterwritedata:(NSMutableData *)data
- {
- if(readdatabuf==0xff0000){
- temps=YES;//temp位YES,表示已得到響應,可以進行下一段的傳送
- [[EADSessionController sharedController] writeData:data];
- }
- else
- {
- temps=NO;
- }
- }