写数据到蓝牙外设失败
我有一个程序运行在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调用是正常的,并且必须写入接收程序来处理这个问题
您可以在这里引用iOS和Windows--您使用哪种发送数据?你想和哪个外设通话? – Carter
对不起,如果我不清楚。我会更新答案。 iOS设备充当中心。 PC作为外设。 – Isuru
您使用蓝牙串口应用程序进行了测试,并且具有相同的行为,是不是表示问题出现在接收端?您接收数据的代码是什么? – Carter