iOS swift在写蓝牙中心和蓝牙外设demo时的发现和说明

ios 同时被 2 个专栏收录
419 篇文章 0 订阅
174 篇文章 0 订阅

两个demo在下面的博客中查看:

iOS swift 蓝牙详解(蓝牙中心demo,蓝牙外设demo(可替代mac蓝牙串口调试工具),蓝牙中心框架,gif演示)

文章目录

在这里插入图片描述
在这里插入图片描述

1.CBCentral CBPeripheral程序员不能自己创建,只能由系统创建,然后程序员在代理方法中获取

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI;
- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic;

1.2 maximumUpdateValueLength(CBCentral)蓝牙中心最多一包能收多少个字节,苹果APP作为蓝牙中心是182

在这里插入图片描述
亲测:
外设发:
在这里插入图片描述
蓝牙中心收:只能收182个,应该是发的时候就被截断了
在这里插入图片描述

2.iphone手机app作为蓝牙外设,不发数据,60~70s后会自动和蓝牙中心断开,需要发心跳包才不会断开

在这里插入图片描述

3.writeValue.withResponse和writeValue.withoutResponse

3.1 writeValue.withResponse

    print(backStr)
    printXY("写", obj: self, line: #line)
    self.peripheral?.writeValue(data, for: self.characteristic!, type: .withResponse)
       func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
        print(#function)
        print(error)
    }

打印(外设那边没有回复):
23
19:44:49.887 XYCharacteristicVC 29 写
peripheral(_:didWriteValueFor:error:)
Optional(Error Domain=CBATTErrorDomain Code=241 “Unknown ATT error.” UserInfo={NSLocalizedDescription=Unknown ATT error.})

如果外设那边回了success, print(error)的结果为nil

3.2 writeValue.withoutResponse

    print(backStr)   printXY(self.peripheral?.canSendWriteWithoutResponse, obj: self, line: #line)
    printXY("写无回复", obj: self, line: #line)
    self.peripheral?.writeValue(data, for: self.characteristic!, type: .withoutResponse)

    func peripheralIsReady(toSendWriteWithoutResponse peripheral: CBPeripheral) {
        print(peripheral.canSendWriteWithoutResponse)
        print(#function)
    }

打印:
67
19:45:11.491 XYCharacteristicVC 48 Optional(true)
19:45:11.492 XYCharacteristicVC 49 写无回复
true
peripheralIsReady(toSendWriteWithoutResponse:)

peripheralIsReady(toSendWriteWithoutResponse:)方法始终会被调用

参考:
iOS蓝牙的使用

4.必须执行read和notify的方法,代理方法被调用后,characteristic.value才有数据,否则为nil

read和notify方法:

 open func readValue(for characteristic: CBCharacteristic)

 open func setNotifyValue(_ enabled: Bool, for characteristic: CBCharacteristic)

CBPeripheralDelegate代理方法:

- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error;

5.最多一包可以给外设发(写)多少个字节peripheral.maximumWriteValueLength.

CBPeripheral

open func maximumWriteValueLength(for type: CBCharacteristicWriteType) -> Int

5.1 苹果app作为蓝牙外设 .withResponse: 512, .withoutResponse: 182

当用苹果app作为蓝牙外设时,写可以发512个字节,写无回复可以发182个字节,如下图:
在这里插入图片描述

5.2 我这的一个蓝牙串口作为蓝牙外设 .withResponse: 512, .withoutResponse: 20

在这里插入图片描述
在这里插入图片描述

5.2 1 .withResponse分包发大量数据时打印截图如下:

在这里插入图片描述

5.3 maximumWriteValueLength,canSendWriteWithoutResponse,peripheralIsReady

5.3.1 用我这的蓝牙串口meek实测的发现(我的蓝牙串口应该是有点问题)

发现1

如下图,写无回复前,canSendWriteWithoutResponse的值为true,之后为false,之后peripheralIsReady代理方法被调用canSendWriteWithoutResponse的值又变为true.

如果,写的data的数据长度超过了maximumWriteValueLength:20,则peripheralIsReady代理方法不会被调用。发下一包数据前canSendWriteWithoutResponse的值还是为false. 发一包小于20的数据后会恢复正常
在这里插入图片描述
在这里插入图片描述

发现2

下面两张蓝牙串口收到数据的图,结合5.3.1的两张截图。当发的数据是120时虽然远远超过了maximumWriteValueLength:20,但还是可以收到,而且是分包接收,每包最大长度为32。

当长度为180时,串口这边就收不到了。但再发一包小于20的数据,通讯可以恢复正常:发数据前canSendWriteWithoutResponse的值为true,发完后peripheralIsReady代理方法会被调用。

长度为480个的时候,蓝牙串口直接失效。和app断开,而且搜不到了。要拔了重插。如下面的图3

图1
在这里插入图片描述
图2
在这里插入图片描述
图3
在这里插入图片描述

发现3

这个蓝牙串口peripheral.maximumWriteValueLength(for: .withResponse)为512. 但是我一包发480个数据,串口还是直接会挂掉。这应该是蓝牙串口的问题

5.3.2 用写无回复writeWithoutResponse分包发大量数据时,打印结果如下截图

在这里插入图片描述

6.从5中得到的启示:.withResponse类似TCP,可靠传输,速度慢,每包写完都有回应,每包传的数据大。.withoutResponse类似UDP,不可靠传输,每包传完没有回应,传输速度快,每包传的数据小

TCP与UDP,gif演示,一看就懂(无比形象)

7. 蓝牙外设特征属性为.read

7.1 给read特征赋一个固定的值

1.permissions只能为.readable. 不能为[.readable, .writable]

 //'Characteristics with cached values must be read-only' 
 let read = CBMutableCharacteristic(type: characteristicReadUUID, properties: .read, value: Data(bytes: [9, 10, 11]), permissions: .readable)

2.赋值后就不能改变,蓝牙中心read时,下面的代理方法不会被调用

func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
        print(#function)
    }

7.2 动态赋值

1.value参数赋值为nil,permissions参数可以赋值为[.readable, .writable]

 let read = CBMutableCharacteristic(type: characteristicReadUUID, properties: [.read,.write, value: nil, permissions: [.readable, .writable])

2.当蓝牙中心读数据时下面的代理方法会被调用,request.value就是蓝牙中的读到的值

    func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
        print(#function)
        print(request)
        request.value = Data([2,3,4])  //蓝牙中心read到的值
        peripheral.respond(to: request, withResult: .success)
    }

参考博客:
蓝牙BLE: ATT和GATT的概念
RxSwift 封装 CoreBluetooth(三) 连接
RxSwift 封装 CoreBluetooth(四) 外设接口设计及实现

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值