[英]Writing data to bluetooth peripheral fails
我有一个在Windows PC上运行的程序,该程序通过COM端口发送/接收数据。 数据通过HM10蓝牙模块通过蓝牙传输。
我能够发现外围设备,与其连接,成功发现其服务和特性。 但是我的问题是发送数据。 中央是我的iPhone。 PC作为外围设备。
首先是我的代码。
import CoreBluetooth
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var peripheralNameLabel: UILabel!
@IBOutlet weak var noOfServicesLabel: UILabel!
@IBOutlet weak var sendBytesButton: UIButton!
@IBOutlet weak var sendStringButton: UIButton!
@IBOutlet weak var responseTextView: UITextView!
private let serviceUUID = CBUUID(string: "FFE0")
private var characteristicUUID = CBUUID(string: "FFE1")
private var manager: CBCentralManager!
private var peripheral: CBPeripheral!
private var characteristic: CBCharacteristic!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil)
}
@IBAction func didTapSendBytesButton(sender: UIButton) {
let bytes: [UInt8] = [0x35, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
let data = NSData(bytes: bytes, length: bytes.count)
peripheral.writeValue(data, forCharacteristic: characteristic, type: .WithResponse)
}
@IBAction func didTapSendStringButton(sender: UIButton) {
let string = "5100000000"
if let data = string.dataUsingEncoding(NSUTF8StringEncoding) {
peripheral.writeValue(data, forCharacteristic: characteristic, type: .WithResponse)
} else {
sendStringButton.enabled = false
sendStringButton.setTitle("😟", forState: .Normal)
}
}
}
extension ViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(central: CBCentralManager) {
print(#function)
switch central.state {
case .Unsupported:
print("Unsupported")
case .Unauthorized:
print("Unauthorized")
case .PoweredOn:
print("Powered On")
navigationItem.title = "Connecting..."
central.scanForPeripheralsWithServices([serviceUUID], options: nil)
case .Resetting:
print("Resetting")
case .PoweredOff:
print("Powered Off")
case .Unknown:
print("Unknown")
}
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print(#function)
print("Discovered \(peripheral.name) at \(RSSI)")
peripheralNameLabel.text = peripheral.name
if peripheral.name == nil || peripheral.name == "" {
return
}
if self.peripheral == nil || self.peripheral.state == .Disconnected {
self.peripheral = peripheral
central.connectPeripheral(peripheral, options: nil)
central.stopScan()
}
}
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
print(#function)
navigationItem.title = "Connected!"
sendBytesButton.enabled = true
sendStringButton.enabled = true
peripheral.delegate = self
peripheral.discoverServices([serviceUUID])
}
func centralManager(central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: NSError?) {
self.peripheral = nil
central.scanForPeripheralsWithServices(nil, options: nil)
}
func centralManager(central: CBCentralManager, didFailToConnectPeripheral peripheral: CBPeripheral, error: NSError?) {
print(#function)
self.peripheral = nil
}
}
extension ViewController: CBPeripheralDelegate {
func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
print(#function)
guard let services = peripheral.services else {
return
}
noOfServicesLabel.text = "\(services.count)"
for service in services {
print(service.UUID)
if service.UUID == serviceUUID {
peripheral.discoverCharacteristics(nil, forService: service)
}
}
}
func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
print(#function)
guard let characteristics = service.characteristics else {
return
}
for characteristic in characteristics {
print("characteristic: \(characteristic.UUID)")
if characteristic.UUID == characteristicUUID {
self.characteristic = characteristic
peripheral.setNotifyValue(true, forCharacteristic: characteristic)
}
}
}
func peripheral(peripheral: CBPeripheral, didWriteValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
print(#function)
print(error)
}
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
print(#function)
if characteristic.UUID == characteristicUUID {
print("Got reply from: \(characteristic.UUID)")
if let data = characteristic.value, let string = String(data: data, encoding: NSUTF8StringEncoding) {
responseTextView.text = string
} else {
print("No response!")
}
}
}
}
我应该发送这样的字节数组,
0x35 0x31 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
到外围设备,如果外围设备成功接收到它,我得到响应
0x43 0x41 0x4E 0x20 0x31 0x31 0x2F 0x35 0x30 0x30 0x0D 0x0A
。
它应该是什么样子。
这是真正发生的情况。
数据包在传输时被分成几部分。 因此,我没有得到成功的回应。
有时候,很奇怪的部分实际上很少起作用! 数据被正确发送(如第一幅图所示),我收到成功响应。 但是失败的发生往往多于失败。 大概有99%的时间。
我尝试了两种方式,将数据作为字节数组( didTapSendBytesButton()
)发送并作为转换后的字符串( didTapSendStringButton()
)发送。 两者导致了相同的结果。
还使用名为Bluetooth Serial的应用程序对其进行了测试。 结果相同。
我不知道为什么会这样。
您发送的字节数少于20个,因此蓝牙数据将在一次传输中发送。
问题出在您的接收方,或者实际上是您如何构建通信。
串行端口一次只能发送或接收一个字节,因此,即使iOS一次发送所有字节(这是如何通过GATT模拟串行端口的副作用),Windows也必须将它们呈现给虚拟COM端口驱动程序一次一个。 Windows在COM端口上有缓冲,因此,如果您的程序读取速度不够快,字节不会丢失,这就是为什么您在每个“ RX”中看到多个字节,但COM驱动程序中没有“数据包”的概念,因此它不知道发送了多少字节,或者它应该等待直到收到所有字节并将它们作为一组传递。
最终的答案是,您需要修改您的消息,使其具有某种分隔符(甚至是简单的\\ n),以便接收程序知道已接收到消息的结尾。 然后,它可以验证消息并做出适当响应。
或者,如果您无法控制接收程序,并且该程序可以与其他发送代码一起使用,那么我怀疑您正在发送的数据有问题,因为串行字节被拆分为多个RX调用是正常的并且必须已编写接收程序来处理此问题
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.