繁体   English   中英

将数据写入蓝牙外围设备失败

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM