• 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;
    }
    

    结束。谢谢看官!

  • 相关阅读:
    Epox 8RDA3G主板奇怪的问题
    Dreamweaver自动生成的垃圾代码
    于今天完成NGW作业
    C#中WebBrowser的使用
    解决FC3下默认浏览器无法出来的问题
    开了几个小时的会……
    HappyEO电子琴
    又一个周末
    FC2/FC3下无法使用Midi设备
    Blog正式易名“小生杂谈”
  • 原文地址:https://www.cnblogs.com/wangcongiOS/p/wangcong.html
Copyright © 2020-2023  润新知