2017-02-03 6 views
0

J'essaie d'envoyer des données de mon iPhone à un appareil Bluetooth qui est connecté à un Arduino. Je sais que le périphérique bluetooth fonctionne bien car j'ai utilisé l'application nRF connect et j'ai envoyé des données à partir de là vers le bluetooth que l'Arduino a lu.Les données Swift 3 ne sont pas envoyées vers l'appareil Bluetooth depuis l'application iPhone

Je pense que la façon dont mon application est organisée crée des problèmes. En l'état, il y a trois contrôleurs de vue.

Le premier contrôleur de vue est un écran de page d'accueil qui en contient peu. Vous pouvez connecter le deuxième et un troisième contrôleur de vue depuis la page d'accueil. Le second contrôleur de vue est un écran de connexion du Bluetooth Le contrôleur troisième vue est un écran d'action avec des boutons

Le second contrôleur de vue est une vue de table avec une option de numérisation pour rechercher les périphériques Bluetooth disponibles. J'utilise ce code:

import UIKit 
import CoreBluetooth 

class ViewController: UIViewController, CBCentralManagerDelegate, UITableViewDataSource, UITableViewDelegate 
{ 

//MARK: Variables 
    //central manager 
    var manager: CBCentralManager? 

    //peripheral manager 
    var peripheral: CBPeripheral? 

    //HM-10 service code 
    let HMServiceCode = CBUUID(string: "0xFFE0") 

    //HM-10 characteristic code 
    let HMCharactersticCode = CBUUID(string: "0xFFE1") 

    //array to store the peripherals 
    var peripheralArray:[(peripheral: CBPeripheral, RSSI: Float)] = [] 

    //for timing..obvs 
    var timer: Timer! 

//MARK: IBOutlets 
    //if cancel is pressed go back to homepage 
    @IBAction func cancelButton(_ sender: Any) 
    { 
     performSegue(withIdentifier: "segueBackwards", sender: nil) 
    } 

    //this is for the tableview so that you can reference it 
    @IBOutlet var tableView: UITableView! 

    //allow for disabling the scanning button whilst scanning 
    @IBOutlet var scanningButton: UIBarButtonItem! 

    //loads the centralmanager delegate in here 
    override func viewDidLoad() 
    { 
     manager = CBCentralManager(delegate: self, queue: nil) 
     tableView.delegate = self 
     tableView.dataSource = self 
     super.viewDidLoad() 
     if(peripheral != nil) 
      { 
       disconnectPeripheral() 
      } 
    } 

    //nothing 
    override func didReceiveMemoryWarning() 
    { 
     super.didReceiveMemoryWarning() 
    } 

//MARK: cancel any preexisting connection - this still needs to be done 
    func disconnectPeripheral() 
    { 
     manager?.cancelPeripheralConnection(peripheral!) 
    } 

//MARK: Bluetooth central 

    //required centralmanager component. Text for what power state currently is 
    func centralManagerDidUpdateState(_ central: CBCentralManager) 
    { 
     var consoleMsg = "" 
     switch (central.state) 
     { 
     case.poweredOff: 
      consoleMsg = "BLE is Powered Off" 
      scanningButton.isEnabled = false 
      alert() 

     case.poweredOn: 
      consoleMsg = "BLE is Powered On" 
      scanningButton.isEnabled = true 

     case.resetting: 
      consoleMsg = "BLE is resetting" 

     case.unknown: 
      consoleMsg = "BLE is in an unknown state" 

     case.unsupported: 
      consoleMsg = "This device is not supported by BLE" 

     case.unauthorized: 
      consoleMsg = "BLE is not authorised" 
     } 
     print("\(consoleMsg)") 
    } 

//MARK: Alert if Bluetooth is not turned on 
    func alert() 
    { 
     //main header 
     let title = "Bluetooth Power" 

     //the little debrief below the main title 
     let message = "Please turn on Bluetooth to use this app" 

     //text in the text box 
     let text = "OK" 

     //this says what the title and message is 
     let alert = UIAlertController(title: title, message: message , preferredStyle: UIAlertControllerStyle.alert) 

     //add button for the answer 
     let okayButton = UIAlertAction(title: text, style: UIAlertActionStyle.cancel, handler: nil) 
     alert.addAction(okayButton) 

     //show the alert 
     present(alert, animated: true, completion: nil) 
     print("said ok on button to turning on bluetooth") 
    } 

//MARK: Connection to bluetooth 
    //once scanned this will say what has been discovered - add to peripheralArray 
    func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) 
    { 
     for existing in peripheralArray 
     { 
      if existing.peripheral.identifier == peripheral.identifier {return} 
     } 
     //adding peripheral to the array 
     let theRSSI = RSSI.floatValue 
     peripheralArray.append(peripheral: peripheral, RSSI: theRSSI) 
     peripheralArray.sort { $0.RSSI < $1.RSSI } 
     print("discovered peripheral") 
     tableView.reloadData() 
     print("There are \(peripheralArray.count) peripherals in the array") 
    } 

    //create a link/connection to the peripheral 
    func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) 
    { 
     peripheral.discoverServices(nil) //may need to remove this not sure it does much 
     print("connected to peripheral") 
    } 

    //disconnect from the peripheral 
    func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) 
    { 
     print("disconnected from peripheral") 
     stopScanning() 
    } 

    //if it failed to connect to a peripheral will tell us (although not why) 
    func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) 
    { 
     print("failed to connect to peripheral") 
     stopScanning() 
    } 

//MARK: scanning 
    //press scan button to initiate scanning sequence 
    @IBAction func scanButton(_ sender: Any) 
    { 
     startTimer() 
    } 

    //start scanning for 5 seconds 
    func startTimer() 
    { 
     //after 5 seconds this goes to the stop scanning routine 
     timer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(ViewController.stopScanning), userInfo: nil, repeats: true) 
     print("Start Scan") 
     manager?.scanForPeripherals(withServices: [HMServiceCode], options: nil) 
     scanningButton.isEnabled = false 
    } 
    //stop the scanning and re-enable the scan button so you can do it again 
    func stopScanning() 
    { 
     timer?.invalidate() 
     print("timer stopped") 
     manager?.stopScan() 
     print("Scan Stopped") 
     print("array items are: \(peripheralArray)") 
     print("peripheral items are: \(peripheral)") 
     print("manager items are: \(manager)") 

     scanningButton.isEnabled = true 

    } 

//MARK: Table View 
    //number of sections the table will have 
    func numberOfSections(in tableView: UITableView) -> Int 
    { 
     return 1 
    } 

    //number of rows each section of the table will have 
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
    { 
     return peripheralArray.count 
    } 

    //the way the data will be displayed in each row for the sections 
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
    { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) 
     let BluetoothNaming = peripheralArray[indexPath.row].peripheral.name 
     cell.textLabel?.text = BluetoothNaming 

     return cell 
    } 

    //what happens when we select an item from the bluetooth list 
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    { 
     //tableView.deselectRow(at: indexPath, animated: true) 
     stopScanning() 
     peripheral = peripheralArray[(indexPath as NSIndexPath).row].peripheral 
     print ("connecting to peripheral called \(peripheral)") 

     //store the name of the connected peripeheral 
     let connectedPeripheral = peripheral 
     manager?.connect(connectedPeripheral!, options: nil) 
     performSegue(withIdentifier: "segueBackwards", sender: nil) 
    } 

//MARK: change label name 
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    { 
     if segue.identifier == "segueBackwards" 
     { 
      if let indexPath = self.tableView.indexPathForSelectedRow 
      { 
       //storing the name of the peripheral and then saving to send to Homepage 
       let peripheral = peripheralArray[indexPath.row].peripheral.name 
       let vc = segue.destination as! HomepageViewController 
       vc.selectedName = peripheral 

       //this is to unselect the row in the table 
       tableView.deselectRow(at: indexPath, animated: true) 
      } 
     } 
    } 

//MARK: end 
} 

Dans l'ensemble la deuxième page, je peux me connecter à un périphérique Bluetooth. Je retourne ensuite à l'écran d'accueil. De là, je vais ensuite au contrôleur troisième vue qui est de contrôler les actions pour mon application. Je l'ai réglé de sorte que vous cliquez sur un bouton, puis cela vous permet d'envoyer des données au bluetooth. Cependant, pour une raison quelconque, je ne peux pas envoyer de données. le clic sur le bouton fonctionne, mais les données ne sont pas envoyées.

Voici mon code pour le contrôleur troisième vue:

import UIKit 
    import CoreBluetooth 

    class SelectionViewController: UIViewController, CBPeripheralDelegate 
    { 

    //MARK: Variables 
     var mainPeripheral: CBPeripheral? 
     let UuidSerialService = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" 
     let UuidTx =   "6E400002-B5A3-F393-E0A9-E50E24DCCA9E" 
     let UuidRx =   "6E400003-B5A3-F393-E0A9-E50E24DCCA9E" 
     let txCharacteristicUUID = "0000ffe0-0000-1000-8000-00805f9b34fb" 
     let txServiceUUID =   "0000ffe1-0000-1000-8000-00805f9b34fb" 

     /// Whether to write to the HM10 with or without response. 
     /// Legit HM10 modules (from JNHuaMao) require 'Write without Response', 
     /// while fake modules (e.g. from Bolutek) require 'Write with Response'. 
     var writeType: CBCharacteristicWriteType = .withoutResponse 
     var writeCharacteristic: CBCharacteristic? 

    //MARK: IBOutlets 

     @IBOutlet var whiteButtonControl: UIButton! 

     @IBAction func doneButton(_ sender: Any) 
     { 
      performSegue(withIdentifier: "segueControltoHome", sender: nil) 
     } 

    //MARK: preset buttons 
     @IBAction func whiteButton(_ sender: Any) 
     { 
      let value : UInt8 = 75 
      let data = Data([value]) 
      mainPeripheral?.writeValue(data, for: writeCharacteristic!, type: writeType) 
      print("Button pressed") 
     } 

//MARK: Peripheral Control 
    func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) 
    { 
     var consoleMsg = "" 
     switch (peripheral.state) 
     { 
     case.poweredOff: 
      consoleMsg = "Peripheral is Powered Off" 

     case.poweredOn: 
      consoleMsg = "Peripheral is Powered On" 

     case.resetting: 
      consoleMsg = "Peripheral is resetting" 

     case.unknown: 
      consoleMsg = "Peripheral is in an unknown state" 

     case.unsupported: 
      consoleMsg = "This device is not supported by Peripheral" 

     case.unauthorized: 
      consoleMsg = "Peripheral is not authorised" 
     } 
     print("\(consoleMsg)") 
    } 

    func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) 
    { 
     // discover the 0xFFE1 characteristic for all services (though there should only be one) 
     for service in peripheral.services! 
     { 
      peripheral.discoverCharacteristics([CBUUID(string: "FFE1")], for: service) 
     } 
    } 

    func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) 
    { 
     // check whether the characteristic we're looking for (0xFFE1) is present - just to be sure 
     print("reading this part") 
     for characteristic in service.characteristics! 

     { 
      if characteristic.uuid == CBUUID(string: "FFE1") 
      { 
       // subscribe to this value (so we'll get notified when there is serial data for us..) 
       peripheral.setNotifyValue(true, for: characteristic) 
       print ("subscribed to this value") 

       // keep a reference to this characteristic so we can write to it 
       writeCharacteristic = characteristic 
       print("characteristic is fine") 
      } 
     } 
    } 

Je pense qu'une partie du problème est que le service périphérique et caractéristique ne se connectent pas au centre? Est-ce que ça sonne bien? Au moment où je cherche à envoyer la valeur 75 à la bluetooth que l'Arduino peut alors lire. Est-ce que j'ai fait quelque chose de mal avec le délégué périphérique? Que dois-je faire pour qu'il soit en mesure d'envoyer des données

grâce

+1

Utilisez un Singleton pour gérer votre partie Bluetooth. Ensuite, tout ViewController y aura accès. – Larme

+0

une chance que vous pourriez développer à ce sujet? –

Répondre

0

@Larme est exact. Créez une classe singleton pour gérer toutes les actions Core Bluetooth. Ensuite, créez une instance de ce singleton où vous voulez.

J'ai créé un exemple de classe singleton avec les fonctionnalités Core Bluetooth ici, https://github.com/alextarrago/bletest.

+0

Salut Alex, merci pour le lien githb. Je suis relativement nouveau pour Swift, que ferais-je avec le singleton? Comment pourrais-je intégrer cela à mon travail? –

+0

Utilisez simplement la classe Singleton pour créer toutes les méthodes et actions que vous souhaitez effectuer sur vos périphériques BLE. Créez ensuite une instance de cette classe singleton sur chaque classe dont vous avez besoin. Évidemment, vous devez créer un protocole (ou similaire) pour communiquer entre le singleton et vos autres contrôleurs. –

+0

Ok, je vais essayer de faire ça. créer le singleton avec tous les trucs basés sur BLE que je veux faire. puis créez cette instance dans tous les ** contrôleurs de vue **, n'est-ce pas? Je devrai rechercher des protocoles, parce que je ne suis pas si familier avec eux. Une indication? –

0

Votre characterictics UUID est erroné

if characteristic.uuid == CBUUID(string: "FFE1") 

caractéristique = FFFE0

changement this ->if characteristic.uuid == CBUUID(string: "FFE0")

+0

Je l'ai trié maintenant, mais ce n'était pas le problème. –