6

I've got a SWIFT application that have to send a value to my Arduino with Bluetooth LowEnergy module!

I've done correctly the search and connection parts but I'm not able to send and receive any data.

Here is my code to get a list of BLE devices available and put all this in a table view then after click in a cell the app provide to connect the device with them!

All this works perfectly but I don't know to send for example a "a" character from app to BLE and get back the answer from arduino to app!

    import UIKit
    import CoreBluetooth


class BluetoothList: UITableViewController,CBCentralManagerDelegate, CBPeripheralDelegate {

    var listValue = [Lista]()
    var Blue: CBCentralManager!
    var conn: CBPeripheral!
    var a: String!
    var char: CBCharacteristic!

    func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
        if (peripheral.name == a){
            self.conn = peripheral
            self.conn.delegate = self
            Blue.stopScan()
            Blue.connectPeripheral(self.conn, options: nil)
            self.performSegueWithIdentifier("ConnectionSegue", sender: nil)
        }
        else{
            listValue = [
                Lista(Name: peripheral.name!, RSS: RSSI.stringValue)
            ]
            self.tableView.reloadData()
        }
    }

    func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
        peripheral.delegate = self
        peripheral.discoverServices(nil)

    }

    func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
        if let servicePeripheral = peripheral.services! as [CBService]!{
            for service in servicePeripheral{
                peripheral.discoverCharacteristics(nil, forService: service)
            }
        }
    }

    func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
        if let characterArray = service.characteristics! as [CBCharacteristic]!{

            for cc in characterArray {
                if(cc.UUID.UUIDString == "FF05"){
                    print("OKOK")
                    peripheral.readValueForCharacteristic(cc)
                }
            }
        }
    }

    func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
        if (characteristic.UUID.UUIDString == "FF05"){

            let value = UnsafePointer<Int>((characteristic.value?.bytes.memory)!)
            print("\(value)")
        }
    }

    func centralManagerDidUpdateState(central: CBCentralManager){
        switch(central.state){
        case .PoweredOn:
            Blue.scanForPeripheralsWithServices(nil, options:nil)
            print("Bluetooth is powered ON")
        case .PoweredOff:
            print("Bluetooth is powered OFF")
        case .Resetting:
            print("Bluetooth is resetting")
        case .Unauthorized:
            print("Bluetooth is unauthorized")
        case .Unknown:
            print("Bluetooth is unknown")
        case .Unsupported:
            print("Bluetooth is not supported")
        }
    }

    override func viewDidLoad() {

        super.viewDidLoad()
        Blue = CBCentralManager(delegate: self, queue: nil)

    }

    override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
        let currentCell = tableView.cellForRowAtIndexPath(tableView.indexPathForSelectedRow!)! as UITableViewCell
        a = currentCell.textLabel?.text
        Blue = CBCentralManager(delegate: self, queue: nil)
    }

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        return 1
    }

    @IBAction func Reload_BTN(sender: AnyObject) {
        self.tableView.reloadData()
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.listValue.count
    }


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


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cella = self.tableView.dequeueReusableCellWithIdentifier("Cella", forIndexPath: indexPath)
        let Lista = self.listValue[indexPath.row]
        cella.textLabel?.text = Lista.Name
        cella.accessoryType = UITableViewCellAccessoryType.DisclosureIndicator
        return cella
    }
Kara
  • 6,115
  • 16
  • 50
  • 57
D.Tibe
  • 73
  • 1
  • 1
  • 7
  • 1
    You need to know which characteristic your arduino uses to receive data and then you simply write the bytes to that characteristic. – Paulw11 Mar 04 '16 at 11:10
  • So, how can I find it? – D.Tibe Mar 04 '16 at 12:00
  • If you are able to edit my code where it's wrong I will be too happy because I know that I've to know the characteristic of my BLE module and I know that I could put it into a CBCharacteristic variable (or something like this) but I don't know where can I get this type of value!! Thanks a lot – D.Tibe Mar 04 '16 at 12:02
  • 1
    You need to refer to the documentation for your BLE device in order to find out its characteristics. You can discover characteristics once you connect to the device but you need to know the a characteristic UUID you are looking for – Paulw11 Mar 04 '16 at 12:20
  • So, I've to read the documentation and find the characterist but where I have to put them? I continue to don't understand what type of steps I've to do in order so... For example if I understand (please correct me if I wrong) : I've to see the characteristics of my BLE and the question is: which type of characteristics I've to get and where I've to put them? I don't understand your answer sorry but if u want I can give you mor information about my problem if you ask me! For example my BLE device is a HM-10 BLE module – D.Tibe Mar 04 '16 at 13:30
  • From my answer here you can see the characteristic identifier: http://stackoverflow.com/questions/27633216/hm10-ble-change-characteristic-value-at-command-arduino. In your `didDiscoverCharwcteristicsFofService` you look for that value in the `cc.UUID.UUIDString`. When you find it, store `self.char=cc` now you can write data to `self.char` to send data to your device, – Paulw11 Mar 04 '16 at 21:32
  • Sorry for late! But... I've seen and re-seen your answer but i don't know how to get that value. So for example i've wrote AT+CHAR and i've got 0xFFE1 so, in the for cycle i've to write cc.UUID.UUIDString == "FFE1" or what? What i've to do for get the right value? – D.Tibe Mar 06 '16 at 15:00
  • Ok, i've got this print in the 'didDiscoverCharwcteristicsFofService' function and the result is that! – D.Tibe Mar 06 '16 at 15:13

1 Answers1

7

The following code is for Swift 3 (XCode 8 Beta 6). It's an example using the standard UUIDs for serial ports like the ones on some commercial modules. So the declarations for the service and characteristics should look like this:

private let UuidSerialService = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E"
private let UuidTx =            "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
private let UuidRx =            "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"

And then your delegate's method for the didDiscoverCharacteristic can be something like this:

public func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?)
{
    if let characteristics = service.characteristics {
        for characteristic in characteristics {
            // Tx:
            if characteristic.uuid == CBUUID(string: UuidTx) {
                print("Tx char found: \(characteristic.uuid)")
                txCharacteristic = characteristic
            }

            // Rx:
            if characteristic.uuid == CBUUID(string: UuidRx) {
                rxCharacteristic = characteristic
                if let rxCharacteristic = rxCharacteristic {
                    print("Rx char found: \(characteristic.uuid)")
                    serialPortPeripheral?.setNotifyValue(true, for: rxCharacteristic)
                }
            }
        }
    }
}

For writing to the Tx, something like the following works, where value is an [UInt8]:

let data = NSData(bytes: value, length: value.count)
serialPortPeripheral?.writeValue(data as Data, for: txCharacteristic, type: CBCharacteristicWriteType.withResponse)

Reading?

public func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    let rxData = characteristic.value
    if let rxData = rxData {
        let numberOfBytes = rxData.count
        var rxByteArray = [UInt8](repeating: 0, count: numberOfBytes)
        (rxData as NSData).getBytes(&rxByteArray, length: numberOfBytes)
        print(rxByteArray)
    }
}

Finally, if you don't know or you are not sure about the services and characteristics of your BLE device, you can look for a free iOS app called "LightBlue". It will discover a device and if you connect to it, it will list all services and characteristics. Just be aware that obvoiusly your app will not be able to access the BLE hardware while LightBlue is connected to your device.

nbloqs
  • 3,152
  • 1
  • 28
  • 49
  • What exactly is `serialPortPeripheral` it's used but the declaration or type isn't shown – Ben Sullivan Feb 20 '23 at 10:58
  • It is a wrapper added there to show that you can have your own classes on top of the Bluetooth layer. It is just an example of something that makes usage of the peripheral(...) functions. – nbloqs Feb 21 '23 at 09:25