• 【iOS与EV3混合机器人编程一系列五个】iOS_WiFi_EV3_Library 解剖连接EV3


    在上一篇文章中。我们解说了怎样用开源码库CocoaAsyncSocket来实现iOS上的UDP和TCP数据通信。那么在本文中。我们将介绍在CocoaAsyncSocket的基础怎样使用UDP和TCP连接EV3的机制。


    之所以我们能够通过无线连接EV3,根本原因在于EV3的源码内建了一套无线连接通信的机制。
    这套机制是这种:
    1)EV3在连接到无线网络后,就不断地从3015port发送UDP数据。数据的格式例如以下:
    Serial-Number: 0016533f0c1e
    Port: 5555
    Name: EV3
    Protocol: EV3
    从这个UDP数据中,我们能够获取其ip地址,设备序列号两个关键数据。

    2)拥有了ip地址,我们就能够建立TCP连接连接到EV3,port为5555
    3)在连接上TCP后,我们就能够向EV3发送数据了,我们必须先发送一个解锁信息获取控制EV3的权限才干实现对EV3的有效控制,解锁信息格式为:
    GET /target?sn=SERIAL_NUMBER VMTP1.0 Protocol: EV3
    sn=相应设备的序列号。就是我们从UDP信息中获取的序列号
    4)解锁信息发送成功后。EV3会返回一条信息:”Accept:EV340”。假设我们收到了这条信息,就意味着我们已经解锁成功。如今我们就能够发送特定的EV3命令来控制EV3了。!

    连接EV3的奥秘就是上面这么几句话了。

    恭喜你,你已经知道Secret了!

    那么如今我们要通过详细的程序来实现它。


    在代码库中我们建立了一个类EV3WifiManager来管理EV3的连接和传输数据功能,并建立了EV3WifiBrowserViewController的视图控制器来作为EV3连接管理的界面。

    为了更好地存储管理EV3设备数据,我们还建立了EV3Device来存储EV3的信息。

    关于界面的设计本文就不谈了,仅谈谈实现连接的核心代码。


    == Step 1:连接UDP并接收数据 ==
    连接方法我们在上一篇文章已经讲了。本文不再谈。
    如今主要说明一下数据处理部分:
    - (void)udpSocket:(GCDAsyncUdpSocket *)sock didReceiveData:(NSData *)data
          fromAddress:(NSData *)address
    withFilterContext:(id)filterContext
    {
            // 1
            NSString *msg = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
            if (msg)
            {
            // 2
            NSString *serialNumber = [msg substringWithRange:NSMakeRange(14, 12)];
            
            NSString *host = [GCDAsyncUdpSocket hostFromAddress:address];
            
            EV3Device *device = [self.devices objectForKey:host];

            if (!device && host.length < 20) {
                
    // 3
                EV3Device *aDevice = [[EV3Device alloc] initWithSerialNumber:serialNumber address:host tag:self.devices.count isConnected:NO];
                
                
                
                // 4
                dispatch_queue_t tcpSocketQueue = dispatch_queue_create("com.manmanlai.tcpSocketQueue", DISPATCH_QUEUE_CONCURRENT);
                GCDAsyncSocket *tcpSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:tcpSocketQueue];
                
                aDevice.tcpSocket = tcpSocket;
                
                
                [self.devices setObject:aDevice forKey:aDevice.address];
                
                
                
                if ([self.delegate respondsToSelector:@selector(updateView)]) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [self.delegate updateView];
                    });
                }
            }
            
            }
            else
            {
            NSLog(@"Error converting received data into UTF-8 String");
            }
            // 5
            [self.udpSocket sendData:data toAddress:address withTimeout:-1 tag:0];
    }

    1、将获取的转化为字符串
    2、通过截取字符串来获取EV3设备的序列号,并通过hostFromAddress:获取特定连接的名称(每个连接都有一个host名称)作为EV3设备的key来存储EV3的信息。
    3、新建一个EV3Device实例来存储设备信息
    4、新建一个TCP socket用于连接EV3。
    5、将原UDP数据返回给EV3。(这一步省略也没有关系)

    == 连接TCP并解锁 ==
    TCP的连接这里不讲。不清楚的童鞋还请看上一篇文章。
    在实现中,我们在界面上显示了ip地址。点击后開始连接。
    一旦连接成功。我们就马上发送解锁数据。并马上接收数据。代码例如以下:

    - (void)connectTCPSocketWithDevice:(EV3Device *)device
    {
        
        GCDAsyncSocket *tcpSocket = device.tcpSocket;
        // connnect
        NSError *error = nil;
        if (![tcpSocket connectToHost:device.address
                                    onPort:5555
                                     error:&error])
        {
            NSLog(@"Error connecting: %@", error);
            
        } else {
            NSLog(@"Connected");
            // write data
            NSLog(@"writing...");
            NSString *unlockMsg = [NSString stringWithFormat:@"GET /target?sn=%@ VMTP1.0 Protocol: EV3",device.serialNumber];
            NSData *unlockData = [unlockMsg dataUsingEncoding:NSUTF8StringEncoding];
            [tcpSocket writeData:unlockData withTimeout:-1 tag:MESSAGE_UNLOCK];
            
            [tcpSocket readDataWithTimeout:-1 tag:MESSAGE_UNLOCK];
            
        }
        
        
    }

    读取到数据后。我们就着手进行数据处理,因为这个代码库要支持多机连接,因此我们在每个EV3Device中处理数据。这里大家要注意就是我们从EV3那边接收的不论什么数据包括port数据这是在这里进行处理。


    - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
    {
        NSString *host = sock.connectedHost;
        EV3Device *device = [self.devices objectForKey:host];
        
        [device handleReceivedData:data withTag:tag];        
    }

    这里我们仅仅看处理解锁数据的过程:
    case MESSAGE_UNLOCK:
            {
                NSString *httpResponse = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                NSString *response =[httpResponse substringToIndex:12];
                if ([response isEqualToString:@"Accept:EV340"]) {
                    self.isConnected = YES;
                    NSLog(@"ev3 connected");
                    
                    dispatch_async(dispatch_get_main_queue(), ^{
                        [self scanPorts];
                        [[NSNotificationCenter defaultCenter] postNotificationName:EV3DeviceConnectedNotification object:self];
                    });
                }
                    break;
            }

    须要注意的是我们发送的每一条数据都有特定的标签以便于区分。对于解锁数据的信息。其相应的标签是MESSAGE_UNLOCK。代码方面须要说明的不是非常多。核心就是推断接收到的信息是不是Accept:EV340,其余的代码就是直接发送命令让EV3返回port数据而且发送notification让界面更新。仅仅要接收到了信息。那么我们就已经成功连接而且能够控制EV3了。


    须要说明的是有一些情况局域网中无法发送TCP数据。导致尽管连接上了TCP,但无法发送解锁信息。一般我都是用Android手机做热点。iPhone热点连接问题确实值得大家一起好好研究!


    OK。那么大家能够看到,连接EV3并非一件非常困难的事。仅仅要通过上面几步。我们就能做到。


    在下一篇文章中,我们讲介绍怎样给EV3发送命令,怎样创建命令。

    敬请期待!


    【本文为原创文章,版权全部,转载请注明出处,谢谢。songrotek@qq.com


    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    方维分享系统模板修改,book_share_list.htm调用用户数据,$_FANWE['user']的数据
    方维分享系统修改会员的积分设置
    方维分享系统二次开发,tip.htm,修改调用的当前用户的信息
    方维分享系统模板修改,删除操作增加提示
    模拟器分辨率
    android自定义menu,PopUpWindow弹出菜单
    Android popupWindow响应back按键并关闭
    Android开发技巧:ViewStub惰性装载
    android动态全屏切换
    Android程序对不同手机屏幕分辨率自适应的总结
  • 原文地址:https://www.cnblogs.com/hrhguanli/p/4875384.html
Copyright © 2020-2023  润新知