简体   繁体   中英

Writing data to bluetooth peripheral fails

I have a program running on a Windows PC which sends/receives data over a COM port. The data is transmitted over Bluetooth via a HM10 Bluetooth module.

I'm able to discover the peripheral, connect to it, discover its services and characteristics all successfully. However my issue is with sending data. The central is my iPhone. The PC acts as the peripheral.

First my code.

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!")
            }
        }
    }

}

I'm supposed to send a byte array like this,

0x35 0x31 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00

to the peripheral and if the peripheral successfully receives it, I get this as a response,

0x43 0x41 0x4E 0x20 0x31 0x31 0x2F 0x35 0x30 0x30 0x0D 0x0A .

How it's supposed to look like.

在此处输入图片说明

This is what really happens.

在此处输入图片说明

在此处输入图片说明

在此处输入图片说明

Data packets are broken into pieces when transferred. Therefore I don't get the success response.

Weird part is sometimes, very rarely it actually works! The data gets sent properly (like shown in the very first image) and I receive the success response. But failures occur more often than not. Like 99% of the time.

I tried both ways, sending data as a byte array ( didTapSendBytesButton() ) and sending it as a string converted ( didTapSendStringButton() ). Both resulted in the same.

Also tested it with app called Bluetooth Serial . Same result.

I can't figure out why this is happening.

You are sending less than 20 bytes, so the Bluetooth data will be sent in a single transmission.

The problem is on your receiving side, or actually how you have structured your communications.

A serial port can only send or receive a single byte at a time, so even though iOS sends all of the bytes at once (this is a side-effect how how serial ports are emulated over GATT), Windows has to present them to the virtual COM port driver one at a time. Windows has buffering on COM ports so that bytes aren't lost if your program doesn't read fast enough, which is why you see more than one byte per "RX" but there is no concept of a "packet" in the COM driver, so it isn't aware of how many bytes were sent or that it should wait until all have been received and deliver them as one group.

The ultimate answer is that you need to modify your message so that it has some sort of delimiter (even a simple \\n) that lets the receiving program know that the end of a message has been received. It can then validate the message and respond appropriately.

Or, if you can't control the receiving program, and that program works with other sending code, then I suspect you have a problem with the data you are sending, because the fact that the serial bytes are split acros multiple RX calls is normal and the receiving program must have been written to handle this

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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