iOS與硬件通訊(socket,data拼接,發送指令,解析指令)


最近項目中用到了iPad驅動硬件來工作,也就是智能硬件的實現。下面簡單說下原理,詳細說下socket,wifi通信,數據處理接收,發送,以及數據解析代碼。

首先,來說下通信。因為硬件部件比較多,我們采取的是,iPad與主控板進行交換數據,主控板來與各硬件部件進行通信。看圖:

 

 
image.png

其中,主控與零部件間及時通訊,零部件實時把狀態上報給主控。當然,iPad與主控板也是及時通訊,主控需要每秒都上報給iPad各個硬件的當前狀態,以供iPad可以實時監控各零部件並且顯示不同的狀態,比如“ipad上實時顯示電冰箱的溫度”。后面這黑體加粗才是我們iOS端要做的任務。涉及到
1.與主控建立連接,
2.並保持長鏈接,實時接收解析主控發來的零部件狀態,
3.以及iPad給主控發指令來驅動硬件動作,比如“iPad發送指令讓電燈關閉”。

與主控建立連接,我們用到的是GCDAsyncSocket這個類,github地址https://github.com/robbiehanson/CocoaAsyncSocket

// Created by 王聰 // Copyright © 2018年 apple. All rights reserved. #import "GCDAsyncSocket.h" @property (nonatomic,strong) GCDAsyncSocket *clientSocket; @property (nonatomic,assign) BOOL connected; - (void)setSocketData { if (self.clientSocket && self.clientSocket.isConnected) { [self.clientSocket disconnect]; self.clientSocket = nil; } self.clientSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:dispatch_get_main_queue()]; NSError *error = nil; self.connected = [self.clientSocket connectToHost:@"你的地址" onPort:@"你的端口號" viaInterface:nil withTimeout:20 error:&error]; } 

連接成功之后會回調GCDAsyncSocketDelegate的連接成功的方法如下。

/** * Called when a socket connects and is ready for reading and writing. * The host parameter will be an IP address, not a DNS name. **/ - (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(uint16_t)port { NSLog(@"連接成功,連接主機信息 %@",sock); self.connected = YES; // 連接后,可讀取服務端的數據 [self.clientSocket readDataWithTimeout:-1 tag:1]; } 

相對的,斷開連接會調用如下回調

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err { NSLog(@"tcp連接斷開,%@",err); self.connected = NO; } 

連接成功了,下面讀取data

/** * Called when a socket has completed reading the requested data into memory. * Not called if there is an error. **/ - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag { [APPDELEGATE.clientSocket readDataWithTimeout:- 1 tag:1]; NSLog(@"接收到的數據%@",data); } 

接收到數據了,下面我們來發送指令控制硬件。
先來看下我們與主控約定的協議格式。

 

 
image.png
 
image.png

接下來看代碼怎么來發送這個協議數據到主控。

//發送數據的方法 - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag; 

那么我們就要構造出這個data,就可以實現發送數據到主控了。
下面介紹兩種生成data的方法。

//發送指令 + (void)sendData{ NSData *data = [SendDataOp returnSetData]; NSLog(@"發送數據Cmd_set%@----------", data.description); [APPDELEGATE.clientSocket writeData:data withTimeout:-1 tag:0]; } //構造data + (NSData *)returnSetData { //方法1,創建bytes數組 // Byte bytes[8] = {0x11,0xff,0x11,0xff,0x03,0x02,0x01,0x28};//40轉為26進制為0x28 // //想操作其中某位可以用下標找到並修改,比如想把最后一位"亮度"改為5 // bytes[7] = 0x05; // NSData *data = [[NSData alloc] initWithBytes:bytes length:sizeof(bytes)]; //方法2,直接拼接data NSMutableData *data = [NSMutableData data]; //表頭 char head1 = 0x11; [data appendBytes:&head1 length:1]; char head2 = 0xff; [data appendBytes:&head2 length:1]; char head3 = 0x11; [data appendBytes:&head3 length:1]; char head4 = 0xff; [data appendBytes:&head4 length:1]; //長度 char length = 0x03; [data appendBytes:&length length:1]; //燈泡號 char num = 0x02; [data appendBytes:&num length:1]; //命令字 char cmd = 0x01; [data appendBytes:&cmd length:1]; //燈泡的亮度 int lightness = 40; [data appendData:[mathUtil convertHexStrToData:[mathUtil ToHex:lightness]]];//這一步是把亮度40轉化為16進制字符串,然后16進制字符串轉化為NSData。下面粘上這一部分轉換的方法 //推薦方法2,直接可以調用方法轉為NSData,而方法1需要手動將40換算為28再拼上去。 return data; //即拼成了11 ff 11 ff 03 02 01 28 } 

10進制轉16進制

+(NSString *)ToHex:(long long int)tmpid { NSString *nLetterValue; NSString *str =@""; long long int ttmpig; for (int i =0; i<9; i++) { ttmpig=tmpid%16; tmpid=tmpid/16; switch (ttmpig) { case 10: nLetterValue =@"A";break; case 11: nLetterValue =@"B";break; case 12: nLetterValue =@"C";break; case 13: nLetterValue =@"D";break; case 14: nLetterValue =@"E";break; case 15: nLetterValue =@"F";break; default:nLetterValue=[[NSString alloc]initWithFormat:@"%lli",ttmpig]; } str = [nLetterValue stringByAppendingString:str]; if (tmpid == 0) { break; } } return str; } 

16進制轉為NSData

+ (NSData *)convertHexStrToData:(NSString *)str { if (!str || [str length] == 0) { return nil; } NSMutableData *hexData = [[NSMutableData alloc] initWithCapacity:20]; NSRange range; if ([str length] % 2 == 0) { range = NSMakeRange(0, 2); } else { range = NSMakeRange(0, 1); } for (NSInteger i = range.location; i < [str length]; i += 2) { unsigned int anInt; NSString *hexCharStr = [str substringWithRange:range]; NSScanner *scanner = [[NSScanner alloc] initWithString:hexCharStr]; [scanner scanHexInt:&anInt]; NSData *entity = [[NSData alloc] initWithBytes:&anInt length:1]; [hexData appendData:entity]; range.location += range.length; range.length = 2; } return hexData; } 

結束。謝謝看官!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM