美文网首页
BLE传输大数据

BLE传输大数据

作者: ashura_ | 来源:发表于2017-05-26 22:36 被阅读0次

背景

某智能硬件模拟程序,例如模拟插卡/拔卡/加热等事件, 采用的策略是使用模拟程序发送模拟命令,APP端解析之后,进行下一步业务逻辑。

问题

传输大一点的数据就会被截断,也就是说每次传输的数据包大小很小(测试是一次155个,但是ble上说是20个,appleDemo也是分包20个字节)。

模拟命令采用json格式,举例:

{
    "array": [
              1,
              2,
              3
              ],
    "boolean": true,
    "null": null,
    "number": 123,
    "object": {
        "a": "b",
        "c": "d",
        "e": "f"
    },
    "string": "Hello World"
}

结果明显被截断了:

2017-05-16 16:50:26.417340 GlucometerTestApp[65247:10879249] 收到特征更新通知...
2017-05-16 16:50:30.353523 GlucometerTestApp[65247:10879249] 读取到特征值:{

    "array": [

              1,

              2,

              3

              ],

    "boolean": true,

    "null": null,

    "number": 123,
2017-05-16 16:50:30.405110 GlucometerTestApp[65247:10879249] 读取到特征值:EOM
2017-05-16 16:50:30.430806 GlucometerTestApp[65247:10879249] didReceiveData:(null)

因为ble传输包大小限制,主流做法还有直接操作字节的方式。但是对要传输复杂数据明显用字节形式不够用。

解决方案

蓝牙肯定也可以传输较大的数据包,例如图片传输。应该采用那种方案呢?在Apple Documents里搜到一个叫BTLE的Demo。
具体的核心理论就是分包,也就是把一条命令分成多次来发送,而后最后组装一下即可。
分包示例图:

packge.png
如上图所示,模拟命令分成15个包传输过来,每个包大小固定位最大20个字符,第1-14包为模拟命令数据,第十五个包只发送了一个EOM字符串,接收端每接收到一个包则把这个数据追加到上一个包数据上,直到收到EOM标识,则把当前收到的所有数据进行解析,解析完成就可以进行下一步业务处理了。

Demo分包传输日志如下:

2017-05-16 17:03:44.832831 GlucometerTestApp[65291:10885464] 收到特征更新通知...
2017-05-16 17:03:57.853364 GlucometerTestApp[65291:10885464] 读取到特征值:{

    "array": [
2017-05-16 17:03:57.861861 GlucometerTestApp[65291:10885464] 读取到特征值:             1,
2017-05-16 17:03:57.869106 GlucometerTestApp[65291:10885464] 读取到特征值:           2,
2017-05-16 17:03:57.908184 GlucometerTestApp[65291:10885464] 读取到特征值:         3
2017-05-16 17:03:57.923027 GlucometerTestApp[65291:10885464] 读取到特征值:      ],

    "boole
2017-05-16 17:03:57.932465 GlucometerTestApp[65291:10885464] 读取到特征值:an": true,

    "nul
2017-05-16 17:03:57.939771 GlucometerTestApp[65291:10885464] 读取到特征值:l": null,

    "numb
2017-05-16 17:03:57.946587 GlucometerTestApp[65291:10885464] 读取到特征值:er": 123,

    "obje
2017-05-16 17:03:57.953552 GlucometerTestApp[65291:10885464] 读取到特征值:ct": {

        "a":
2017-05-16 17:03:57.959731 GlucometerTestApp[65291:10885464] 读取到特征值: "b",

        "c":
2017-05-16 17:03:57.965410 GlucometerTestApp[65291:10885464] 读取到特征值:"d",

        "e": "
2017-05-16 17:03:57.971610 GlucometerTestApp[65291:10885464] 读取到特征值:f"

    },

    "str
2017-05-16 17:03:57.977920 GlucometerTestApp[65291:10885464] 读取到特征值:ing": "Hello World"
2017-05-16 17:03:57.987575 GlucometerTestApp[65291:10885464] 读取到特征值:
}
2017-05-16 17:03:57.994471 GlucometerTestApp[65291:10885464] 读取到特征值:EOM
2017-05-16 17:03:58.001022 GlucometerTestApp[65291:10885464] didReceiveData:{
    array =     (
        1,
        2,
        3
    );
    boolean = 1;
    null = "<null>";
    number = 123;
    object =     {
        a = b;
        c = d;
        e = f;
    };
    string = "Hello World";
}

Central

Demo上的Central端截图

ScreenShot_20170516174707.png

收包关键代码:

//更新特征值后(调用readValueForCharacteristic:方法或者外围设备在订阅后更新特征值都会调用此代理方法)
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error) {
        NSLog(@"更新特征值时发生错误,错误信息:%@",error.localizedDescription);
        [self writeToLog:[NSString stringWithFormat:@"更新特征值时发生错误,错误信息:%@",error.localizedDescription]];
        return;
    }
    if (characteristic.value) {
        NSString *value=[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding];
        NSLog(@"读取到特征值:%@",value);
        [self writeToLog:[NSString stringWithFormat:@"读取到特征值:%@",value]];
            if ([value isEqualToString:@"EOM"]) {
                //处理数据
                [self.delegate didReceiveData:self.data complate:YES];
                
                //处理完毕,清空
                [self.data setLength:0];
            }
        else
        {
            [self.data appendData:characteristic.value];
            if(self.delegate)
            {
                [self.delegate didReceiveData:self.data complate:NO];
            }
        }
    }else{
        NSLog(@"未发现特征值.");
        [self writeToLog:@"未发现特征值."];
    }
}

Peripheral

Demo上的Peripheral端截图

ScreenShot_20170516174355.png

发包关键代码:

/** Sends the next amount of data to the connected central
 */
- (void)_sendData
{
    // First up, check if we're meant to be sending an EOM
    static BOOL sendingEOM = NO;
    
    if (sendingEOM) {
        
        // send it
        BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.characteristicM onSubscribedCentrals:nil];
        
        // Did it send?
        if (didSend) {
            
            // It did, so mark it as sent
            sendingEOM = NO;
            
            NSLog(@"Sent: EOM");
        }
        
        // It didn't send, so we'll exit and wait for peripheralManagerIsReadyToUpdateSubscribers to call sendData again
        return;
    }
    
    // We're not sending an EOM, so we're sending data
    
    // Is there any left to send?
    
    if (self.sendDataIndex >= self.dataToSend.length) {
        
        // No data left.  Do nothing
        return;
    }
    
    // There's data left, so send until the callback fails, or we're done.
    
    BOOL didSend = YES;
    
    while (didSend) {
        
        // Make the next chunk
        
        // Work out how big it should be
        NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex;
        
        // Can't be longer than 20 bytes
        if (amountToSend > NOTIFY_MTU) amountToSend = NOTIFY_MTU;
        
        // Copy out the data we want
        NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend];
        
        // Send it
        didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.characteristicM onSubscribedCentrals:nil];
        
        // If it didn't work, drop out and wait for the callback
        if (!didSend) {
            return;
        }
        
        NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding];
        NSLog(@"Sent: %@", stringFromData);
        
        // It did send, so update our index
        self.sendDataIndex += amountToSend;
        
        // Was it the last one?
        if (self.sendDataIndex >= self.dataToSend.length) {
            
            // It was - send an EOM
            
            // Set this so if the send fails, we'll send it next time
            sendingEOM = YES;
            
            // Send it
            BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.characteristicM onSubscribedCentrals:nil];
            
            if (eomSent) {
                // It sent, we're all done
                sendingEOM = NO;
                
                NSLog(@"Sent: EOM");
            }
            
            return;
        }
    }
}

Demo

具体直接运行Demo很直观的可以看到结果,本Demo能够展现出已收到。但是未处理未收到重发等,因为目前的产品无此业务需求。
DemoGit地址。

相关文章

  • 蓝牙4.0/4.1/4.2 BLE协议监控分析仪

    典型应用: - 抓取BLE蓝牙传输数据,分析数据传输协议; - 协助开发调试BLE相关软件,固件; - 实时捕获、...

  • BLE传输大数据

    背景 某智能硬件模拟程序,例如模拟插卡/拔卡/加热等事件, 采用的策略是使用模拟程序发送模拟命令,APP端解析之后...

  • BLE 链路层状态机

    BLE链路层 BLE链路层位于物理层之上,主要是控制无线电进行数据的传输,其功能主要包括: 数据报文的管理 广播、...

  • 蓝牙ble上传byte数据手机

    用蓝牙ble传输数据时,手机端要对接收到的数据进行处理,byte的数值空间为-128到+127; 所以如果传感...

  • sleep

    BLE的特点是超低功耗的无线传输设备,其空闲时可以进入睡眠模式,在需要传输数据时候进行唤醒,能进一步节省电量。 实...

  • 蓝牙

    1.蓝牙相关概念:GATT、ATT: 这两者都是BLE间小数据传输的协议规范,都是通用的。Characterist...

  • [转载]蓝牙4.0 BLE 数据传输(五)

    相信看了《蓝牙4.0 BLE 数据传输(四)》,大家应该知道怎么通过发送特征值来控制CC2540了,不说别的,就...

  • IMU通过BLE传输

  • 蓝牙低功耗概览

    常见用例---在临近设备间传输少量数据。 注意:当用户使用 BLE 与其他设备配对时,用户设备上的所有应用都可以访...

  • Android蓝牙4.0 Ble读写数据详解 -1

    Android蓝牙4.0 Ble读写数据详解 -1 Android蓝牙4.0 Ble读写数据详解 -2 因为最近公...

网友评论

      本文标题:BLE传输大数据

      本文链接:https://www.haomeiwen.com/subject/lhqffxtx.html