2016-08-14 2 views
0

J'ai un programme exécuté sur un PC Windows qui envoie/reçoit des données via un port COM. Les données sont transmises via Bluetooth via un module Bluetooth HM10.Ecriture de données dans un périphérique Bluetooth bloqué

Je suis capable de découvrir le périphérique, de s'y connecter, de découvrir ses services et ses caractéristiques avec succès. Cependant, mon problème est avec l'envoi de données. Le central est mon iPhone. Le PC agit en tant que périphérique.

D'abord mon 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!") 
      } 
     } 
    } 

} 

Je suis censé envoyer un tableau d'octets comme celui-ci,

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

au périphérique et si le périphérique reçoit avec succès, je reçois cela comme une réponse,

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

Comment c'est censé ressembler.

enter image description here

C'est ce qui se passe vraiment.

enter image description here

enter image description here

enter image description here

Les paquets de données sont mises en pièces lors de son transfert. Par conséquent, je ne reçois pas la réponse de succès.

Une partie étrange est parfois, très rarement cela fonctionne réellement! Les données sont envoyées correctement (comme montré dans la toute première image) et je reçois la réponse de succès. Mais les échecs surviennent le plus souvent. Comme 99% du temps.

J'ai essayé dans les deux sens, en envoyant des données sous la forme d'un tableau d'octets (didTapSendBytesButton()) et en l'envoyant sous la forme d'une chaîne convertie (didTapSendStringButton()). Les deux ont abouti à la même chose.

Également testé avec l'application appelée Bluetooth Serial. Même résultat

Je n'arrive pas à comprendre pourquoi cela se produit.

+0

Vous référencez ici iOS et Windows ici, lesquels utilisez-vous pour envoyer les données? A quel périphérique es-tu en train de parler? – Carter

+0

Désolé si je n'étais pas clair à ce sujet. Je vais mettre à jour la réponse. L'appareil iOS agit comme le central. Le PC agit en tant que périphérique. – Isuru

+0

Vous avez testé avec l'application Bluetooth Serial et avez eu le même comportement, cela ne signifie-t-il pas que le problème se produit du côté du récepteur? Quel est votre code pour recevoir les données? – Carter

Répondre

1

Vous envoyez moins de 20 octets, donc les données Bluetooth seront envoyées en une seule transmission.

Le problème se situe du côté de la réception ou de la manière dont vous avez structuré vos communications. Un port série ne peut envoyer ou recevoir qu'un seul octet à la fois. Même si iOS envoie tous les octets en même temps (effet secondaire sur l'émulation des ports série sur le GATT), Windows doit présentez-les au pilote de port COM virtuel un à la fois. Windows a un tampon sur les ports COM afin que les octets ne soient pas perdus si votre programme ne lit pas assez vite, ce qui explique pourquoi vous voyez plus d'un octet par "RX" mais il n'y a pas de "paquet" dans le pilote COM , donc il ne sait pas combien d'octets ont été envoyés ou qu'il devrait attendre jusqu'à ce que tous aient été reçus et les livrer comme un groupe.La réponse ultime est que vous devez modifier votre message afin qu'il ait un certain type de délimiteur (même un \ n simple) qui indique au programme de réception que la fin d'un message a été reçue. Il peut ensuite valider le message et répondre de manière appropriée. Ou, si vous ne pouvez pas contrôler le programme de réception, et que ce programme fonctionne avec d'autres codes d'envoi, je suppose que vous avez un problème avec les données que vous envoyez, parce que les octets série sont divisés en plusieurs acros Les appels RX sont normaux et le programme de réception doit avoir été écrit pour gérer ceci

+0

Merci pour la réponse détaillée, Paul. On m'a dit que le programme fonctionnant sous Windows recherche 10 octets pendant environ 100ms et obtient le délai d'attente. Cela pourrait-il avoir un effet sur cela? – Isuru

+0

Peut-être, mais encore une fois le problème serait avec le pilote com virtuel sur le PC, pas le code iOS ou le périphérique BLE. 100 ms devraient être suffisamment de temps pour livrer 10 octets à 9600 bps – Paulw11