iOS与硬件通讯(socket,data拼接,发送指令,解析指令)

最近项目中用到了iPad驱动硬件来工作,也就是智能硬件的实现。下面简单说下原理,详细说下socket,wifi通信,数据处理接收,发送,以及数据解析代码。
首先,来说下通信。因为硬件部件比较多,我们采取的是,iPad与主控板进行交换数据,主控板来与各硬件部件进行通信。看图:
iOS与硬件通讯(socket,data拼接,发送指令,解析指令)
文章图片

其中,主控与零部件间及时通讯,零部件实时把状态上报给主控。
当然,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); }

接收到数据了,下面我们来发送指令控制硬件。
先来看下我们与主控约定的协议格式。
iOS与硬件通讯(socket,data拼接,发送指令,解析指令)
文章图片

iOS与硬件通讯(socket,data拼接,发送指令,解析指令)
文章图片

接下来看代码怎么来发送这个协议数据到主控。
//发送数据的方法 - (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag;

那么我们就要构造出这个data,就可以实现发送数据到主控了。
下面介绍两种生成data的方法。
//发送指令 + (void)sendData{ NSData *data = https://www.it610.com/article/[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 =https://www.it610.com/article/@"A"; break; case 11:nLetterValue =https://www.it610.com/article/@"B"; break; case 12:nLetterValue =https://www.it610.com/article/@"C"; break; case 13:nLetterValue =https://www.it610.com/article/@"D"; break; case 14:nLetterValue =https://www.it610.com/article/@"E"; break; case 15:nLetterValue =https://www.it610.com/article/@"F"; break; default:nLetterValue=https://www.it610.com/article/[[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; }

【iOS与硬件通讯(socket,data拼接,发送指令,解析指令)】结束。谢谢看官!
Created by 王聪

    推荐阅读