SWIFT - BLE communications
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
}
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.