How to modify an existing BLECentral class into a singleton class? - ios

Hi I'm trying to make the BLE Central class into a Singleton class?
I'm running into a few crashes while trying to implement it.
Here is my code:
//This is the BLE Central Class
import Foundation
import UIKit
import CoreBluetooth
var txCharacteristic : CBCharacteristic?
var rxCharacteristic : CBCharacteristic?
var blePeripheral : CBPeripheral?
var characteristicASCIIValue = NSString()
class BLECentralViewController : UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDelegate, UITableViewDataSource{
//Data
var centralManager : CBCentralManager!
var RSSIs = [NSNumber]()
var data = NSMutableData()
var writeData: String = ""
var peripherals: [CBPeripheral] = []
var characteristicValue = [CBUUID: NSData]()
var timer = Timer()
var characteristics = [String : CBCharacteristic]()
//UI
#IBOutlet weak var baseTableView: UITableView!
#IBOutlet weak var refreshButton: UIBarButtonItem!
#IBAction func refreshAction(_ sender: AnyObject) {
disconnectFromDevice()
self.peripherals = []
self.RSSIs = []
self.baseTableView.reloadData()
startScan()
}
override func viewDidLoad() {
super.viewDidLoad()
self.baseTableView.delegate = self
self.baseTableView.dataSource = self
self.baseTableView.reloadData()
centralManager = CBCentralManager(delegate: self, queue: nil)
let backButton = UIBarButtonItem(title: "Disconnect", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backButton
}
override func viewDidAppear(_ animated: Bool) {
disconnectFromDevice()
super.viewDidAppear(animated)
refreshScanView()
print("View Cleared")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("Stop Scanning")
centralManager?.stopScan()
}
/*Okay, now that we have our CBCentalManager up and running, it's time to start searching for devices. You can do this by calling the "scanForPeripherals" method.*/
func startScan() {
peripherals = []
print("Now Scanning...")
self.timer.invalidate()
centralManager?.scanForPeripherals(withServices: [BLEService_UUID] , options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
Timer.scheduledTimer(timeInterval: 17, target: self, selector: #selector(self.cancelScan), userInfo: nil, repeats: false)
}
/*We also need to stop scanning at some point so we'll also create a function that calls "stopScan"*/
func cancelScan() {
self.centralManager?.stopScan()
print("Scan Stopped")
print("Number of Peripherals Found: \(peripherals.count)")
}
func refreshScanView() {
baseTableView.reloadData()
}
//-Terminate all Peripheral Connection
/*
Call this when things either go wrong, or you're done with the connection.
This cancels any subscriptions if there are any, or straight disconnects if not.
(didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved)
*/
func disconnectFromDevice () {
if blePeripheral != nil {
// We have a connection to the device but we are not subscribed to the Transfer Characteristic for some reason.
// Therefore, we will just disconnect from the peripheral
centralManager?.cancelPeripheralConnection(blePeripheral!)
}
}
func restoreCentralManager() {
//Restores Central Manager delegate if something went wrong
centralManager?.delegate = self
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,advertisementData: [String : Any], rssi RSSI: NSNumber) {
blePeripheral = peripheral
self.peripherals.append(peripheral)
self.RSSIs.append(RSSI)
peripheral.delegate = self
self.baseTableView.reloadData()
if blePeripheral == nil {
print("Found new pheripheral devices with services")
print("Peripheral name: \(String(describing: peripheral.name))")
print("**********************************")
print ("Advertisement Data : \(advertisementData)")
}
}
//Peripheral Connections: Connecting, Connected, Disconnected
//-Connection
func connectToDevice () {
centralManager?.connect(blePeripheral!, options: nil)
}
//-Connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("*****************************")
print("Connection complete")
print("Peripheral info: \(String(describing: blePeripheral))")
//Stop Scan- We don't need to scan once we've connected to a peripheral. We got what we came for.
centralManager?.stopScan()
print("Scan Stopped")
//Erase data that we might have
data.length = 0
//Discovery callback
peripheral.delegate = self
//Only look for services that matches transmit uuid
peripheral.discoverServices([BLEService_UUID])
//Once connected, move to new view controller to manager incoming and outgoing data
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let firstVC = storyboard.instantiateViewController(withIdentifier: "FirstViewController") as! FirstViewController
firstVC.peripheral = peripheral
navigationController?.pushViewController(firstVC, animated: true)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
if error != nil {
print("Failed to connect to peripheral")
return
}
}
func disconnectAllConnection() {
centralManager.cancelPeripheralConnection(blePeripheral!)
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let services = peripheral.services else {
return
}
//We need to discover the all characteristic
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
// bleService = service
}
print("Discovered Services: \(services)")
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let characteristics = service.characteristics else {
return
}
print("Found \(characteristics.count) characteristics!")
for characteristic in characteristics {
//looks for the right characteristic
if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Rx) {
rxCharacteristic = characteristic
//Once found, subscribe to the this particular characteristic...
peripheral.setNotifyValue(true, for: rxCharacteristic!)
// We can return after calling CBPeripheral.setNotifyValue because CBPeripheralDelegate's
// didUpdateNotificationStateForCharacteristic method will be called automatically
peripheral.readValue(for: characteristic)
print("Rx Characteristic: \(characteristic.uuid)")
}
if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Tx){
txCharacteristic = characteristic
print("Tx Characteristic: \(characteristic.uuid)")
}
peripheral.discoverDescriptors(for: characteristic)
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic == rxCharacteristic {
if let ASCIIstring = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue) {
characteristicASCIIValue = ASCIIstring
print("Value Recieved: \((characteristicASCIIValue as String))")
NotificationCenter.default.post(name:NSNotification.Name(rawValue: "Notify"), object: nil)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if error != nil {
print("\(error.debugDescription)")
return
}
if ((characteristic.descriptors) != nil) {
for x in characteristic.descriptors!{
let descript = x as CBDescriptor!
print("function name: DidDiscoverDescriptorForChar \(String(describing: descript?.description))")
print("Rx Value \(String(describing: rxCharacteristic?.value))")
print("Tx Value \(String(describing: txCharacteristic?.value))")
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if (error != nil) {
print("Error changing notification state:\(String(describing: error?.localizedDescription))")
} else {
print("Characteristic's value subscribed")
}
if (characteristic.isNotifying) {
print ("Subscribed. Notification has begun for: \(characteristic.uuid)")
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnected")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Message sent")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Succeeded!")
}
//Table View Functions
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.peripherals.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "BlueCell") as! PeripheralTableViewCell
let peripheral = self.peripherals[indexPath.row]
let RSSI = self.RSSIs[indexPath.row]
if peripheral.name == nil {
cell.peripheralLabel.text = "nil"
} else {
cell.peripheralLabel.text = peripheral.name
}
cell.rssiLabel.text = "RSSI: \(RSSI)"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
blePeripheral = peripherals[indexPath.row]
connectToDevice()
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
// We will just handle it the easy way here: if Bluetooth is on, proceed...start scan!
print("Bluetooth Enabled")
startScan()
} else {
//If Bluetooth is off, display a UI alert message saying "Bluetooth is not enable" and "Make sure that your bluetooth is turned on"
print("Bluetooth Disabled- Make sure your Bluetooth is turned on")
let alertVC = UIAlertController(title: "Bluetooth is not enabled", message: "Make sure that your bluetooth is turned on", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "ok", style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) -> Void in
self.dismiss(animated: true, completion: nil)
})
alertVC.addAction(action)
self.present(alertVC, animated: true, completion: nil)
}
}
}
My questions are:
How can I modify the BLECentral class to use as a singleton so I
can call from any view controller class to read and write data?
Can I simply make the first view controller as a singleton instead of the BLE central and read/write by calling this from other view controller class?
Or can I extend the first view controller class scope by using
extension?
I'm currently able to read/write data but peripheral doesn't seem to
be called properly sometimes, therefore gets disconnected? Any
suggestions/fixes?
Here is my FirstViewController class:
class FirstViewController: UIViewController, UIPeripheralManagerDelegate {
var peripheralManager: CBPeripheralManager?
var peripheral: CBPeripheral!
viewDidLoad(){
//I'm calling the blePeripheral from BLE class to the peripheral in the current class
peripheral = blePeripheral
}
//I have a button here to send some data and only when I receive the data I want to go to the next view controller
#IBAction func login(_sender: AnyObject) {
//This is my write code
let bytes : [UInt8] = [ 0x1A, 0x2B, 0x3C, 0x4D ]
let Transmitdata = NSData(bytes: bytes, length: bytes.count)
peripheral.writeValue(Transmitdata as Data, for: txCharacteristic!, type: CBCharacteristicWriteType.withoutResponse)
print("Data Sent",Transmitdata)
//Give time for data to be received fromdevice
sleep(1)
//let ReceiveData = rxCharacteristic?.value
if let ReceiveData = ReceiveData {
let ReceivedNoOfBytes = ReceiveData.count
var ReceivedByteArray = [UInt8](repeating: 0, count: ReceivedNoOfBytes)
(ReceiveData as NSData).getBytes(&ReceivedByteArray, length: ReceivedNoOfBytes)
print("Data Received ",ReceivedByteArray)
//checking if we received the right data?
if(ReceivedByteArray[0] == 10 && ReceivedByteArray[1] == 20 && ReceivedByteArray[2] == 30 && ReceivedByteArray[3] == 40){
performSegue(withIdentifier: "Second_View", sender: self)
}
}
}
And the SecondViewController class:
class SecondViewController: UIViewController{
var firstview: FirstViewController?
var peripheralManager: CBPeripheralManager?
var peripheral: CBPeripheral!
override func viewWillAppear(_animated: Bool){
let peripheral = firstview?.peripheral
let peripheralManager = firstview?.peripheralManager
}
//I have another button here to direct me to third view controller class
#IBAction func mainmenu(_sender: AnyObject){
//send some bytes
//receiver some bytes
//similar to the first view controller
If correct data is received
{
performSegue(withIdentifier: "Main_M", sender: self)
}
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?){
if segue.destination is Main_M
{
let gotoM = segue.destination as? Main_M
gotoM?.peripheral = firstview?.peripheral
}
}

Related

have to initiate a BLE peripheral every time i use it in Swift

with CBCentralManager i succesully scan multiple BLE UART devices and connect to them, de devices are stored in the array periphirals[], but when i want to send data to them one by one, only the last one connected i can send succesfully send data to, i solved it by calling blePeripheral?.discoverServices([ParticlePeripheral.BLEService_UUID])before writing data again, but i think this is not the right solution, can someone explain what i am doing wrong?
Below the code i use, the scanning and connecting start by didload
and startCyclus starts the first device, after the data recieved "didUpdateValueFor" is entered , getting the data and direct send data to the next peripheral
import Foundation
import UIKit
import CoreBluetooth
var txCharacteristic : CBCharacteristic?
var rxCharacteristic : CBCharacteristic?
var blePeripheral : CBPeripheral?
var characteristicASCIIValue = NSString()
var Running = false
var currentNode = 0;
var updateService = false
var maxNodes = Int()
class ViewController : UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDelegate{
//Data
var centralManager : CBCentralManager!
var RSSIs = [NSNumber]()
var data = NSMutableData()
var peripherals: [CBPeripheral] = []
var characteristicValue = [CBUUID: NSData]()
var timer = Timer()
var characteristics = [String : CBCharacteristic]()
var teller = 0
//UI
#IBOutlet weak var baseTableView: UITableView!
#IBOutlet weak var refreshButton: UIBarButtonItem!
#IBAction func naarRun(_ sender: Any) {
print("naarRun")
self.performSegue(withIdentifier:"naarRunView" , sender: self)
}
override func viewDidLoad() {
super.viewDidLoad()
centralManager = CBCentralManager(delegate: self, queue: nil)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
if (segue.identifier == "naarRunView") {
let vc = segue.destination as! ViewRun
vc.peripherals = peripherals
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
//print("View Cleared")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("Stop Scanning")
centralManager?.stopScan()
}
/*Okay, now that we have our CBCentalManager up and running, it's time to start searching for devices. You can do this by calling the "scanForPeripherals" method.*/
func startScan() {
peripherals = []
print("Now Scanning...")
self.timer.invalidate()
centralManager?.scanForPeripherals(withServices: [ParticlePeripheral.BLEService_UUID] , options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
Timer.scheduledTimer(withTimeInterval: 3, repeats: false) {_ in
self.cancelScan()
self.connectToAllDevices()
}
}
/*We also need to stop scanning at some point so we'll also create a function that calls "stopScan"*/
func cancelScan() {
self.centralManager?.stopScan()
print("Scan Stopped")
print("Number of Peripherals Found: \(peripherals.count)")
}
func disconnectFromDevice () {
if blePeripheral != nil {
// We have a connection to the device but we are not subscribed to the Transfer Characteristic for some reason.
// Therefore, we will just disconnect from the peripheral
centralManager?.cancelPeripheralConnection(blePeripheral!)
}
}
func restoreCentralManager() {
//Restores Central Manager delegate if something went wrong
centralManager?.delegate = self
}
/*
Called when the central manager discovers a peripheral while scanning. Also, once peripheral is connected, cancel scanning.
*/
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,advertisementData: [String : Any], rssi RSSI: NSNumber) {
blePeripheral = peripheral
teller+=1
self.peripherals.append(peripheral)
self.RSSIs.append(RSSI)
peripheral.delegate = self
//self.baseTableView.reloadData()
//if blePeripheral == nil {
print("Found new pheripheral devices with services")
print("Peripheral name: \(String(describing: peripheral.name))")
print("**********************************")
print ("Advertisement Data : \(advertisementData)")
//}
}
//Peripheral Connections: Connecting, Connected, Disconnected
//-Connection
func connectToDevice () {
centralManager?.connect(blePeripheral!, options: nil)
}
func connectToAllDevices(){
var seconds = 0.0
for per in peripherals
{
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
blePeripheral = per
print("Connecting naar " + (blePeripheral?.name!)!)
self.connectToDevice ()
}
seconds = seconds + 0.5;
}
}
/*
Invoked when a connection is successfully created with a peripheral.
This method is invoked when a call to connect(_:options:) is successful. You typically implement this method to set the peripheral’s delegate and to discover its services.
*/
//-Connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("*****************************")
print("Connection complete")
print("Peripheral info: \(String(describing: blePeripheral))")
//Erase data that we might have
data.length = 0
//Discovery callback
peripheral.delegate = self
//Only look for services that matches transmit uuid
peripheral.discoverServices([ParticlePeripheral.BLEService_UUID])
/*
//Once connected, move to new view controller to manager incoming and outgoing data
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let uartViewController = storyboard.instantiateViewController(withIdentifier: "UartModuleViewController") as! UartModuleViewController
uartViewController.peripheral = peripheral
navigationController?.pushViewController(uartViewController, animated: true)
*/
}
/*
Invoked when the central manager fails to create a connection with a peripheral.
*/
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
if error != nil {
print("Failed to connect to peripheral")
return
}
}
func disconnectAllConnection() {
centralManager.cancelPeripheralConnection(blePeripheral!)
}
/*
Invoked when you discover the peripheral’s available services.
This method is invoked when your app calls the discoverServices(_:) method. If the services of the peripheral are successfully discovered, you can access them through the peripheral’s services property. If successful, the error parameter is nil. If unsuccessful, the error parameter returns the cause of the failure.
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let services = peripheral.services else {
return
}
//We need to discover the all characteristic
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
// bleService = service
}
print("Discovered Services: \(services)")
}
/*
Invoked when you discover the characteristics of a specified service.
This method is invoked when your app calls the discoverCharacteristics(_:for:) method. If the characteristics of the specified service are successfully discovered, you can access them through the service's characteristics property. If successful, the error parameter is nil. If unsuccessful, the error parameter returns the cause of the failure.
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let characteristics = service.characteristics else {
return
}
print("Found \(characteristics.count) characteristics!")
for characteristic in characteristics {
//looks for the right characteristic
if characteristic.uuid.isEqual(ParticlePeripheral.BLE_Characteristic_uuid_Rx) {
rxCharacteristic = characteristic
//Once found, subscribe to the this particular characteristic...
peripheral.setNotifyValue(true, for: rxCharacteristic!)
// We can return after calling CBPeripheral.setNotifyValue because CBPeripheralDelegate's
// didUpdateNotificationStateForCharacteristic method will be called automatically
peripheral.readValue(for: characteristic)
print("Rx Characteristic: \(characteristic.uuid)")
}
if characteristic.uuid.isEqual(ParticlePeripheral.BLE_Characteristic_uuid_Tx){
txCharacteristic = characteristic
print("Tx Characteristic: \(characteristic.uuid)")
}
peripheral.discoverDescriptors(for: characteristic)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if error != nil {
print("\(error.debugDescription)")
return
}
guard let descriptors = characteristic.descriptors else { return }
descriptors.forEach { descript in
print("function name: DidDiscoverDescriptorForChar \(String(describing: descript.description))")
print("Rx Value \(String(describing: rxCharacteristic?.value))")
print("Tx Value \(String(describing: txCharacteristic?.value))")
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if (error != nil) {
print("Error changing notification state:\(String(describing: error?.localizedDescription))")
} else {
print("Characteristic's value subscribed")
}
if (characteristic.isNotifying) {
print ("Subscribed. Notification has begun for: \(characteristic.uuid)")
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnected")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Message sent")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Succeeded!")
}
// MARK: - Getting Values From Characteristic
/** After you've found a characteristic of a service that you are interested in, you can read the characteristic's value by calling the peripheral "readValueForCharacteristic" method within the "didDiscoverCharacteristicsFor service" delegate.
*/
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
guard characteristic == rxCharacteristic,
let characteristicValue = characteristic.value,
let ASCIIstring = NSString(data: characteristicValue,
encoding: String.Encoding.utf8.rawValue)
else { return }
characteristicASCIIValue = ASCIIstring
let ontvangen = String(characteristicASCIIValue)
let waarde = haalwaarde(recieved: ontvangen)
print("Value Recieved: " + String(characteristicASCIIValue) )
NotificationCenter.default.post(name:NSNotification.Name(rawValue: "Notify"), object: self)
if(updateService){updateService=false; return}
if(!waarde.isNumber){print("waarde is no number");return}
if(Running ){Vervolg()}
}
func haalNode(recieved:String)->String{
//nodenr
if(recieved.count<10){return "fout";}
let temp = recieved
let lengte = recieved.count;
let start = temp.index(temp.startIndex, offsetBy: 7)
let end = temp.index(temp.endIndex, offsetBy: -(lengte-8))
let range = start..<end
let nodeNr = String(temp[range])
//print("nodeNr=", nodeNr)
return nodeNr
}
func haalwaarde(recieved:String)->String{
//Reactietijd
if(recieved.count<10){return "fout"};
let temp = recieved
let lengte = recieved.count;
let start = temp.index(temp.startIndex, offsetBy: 1)
let end = temp.index(temp.endIndex, offsetBy: -(lengte-7))
let range = start..<end
let Reactietijd = String(temp[range])
//print("\nreactietijd=", Reactietijd)
return Reactietijd
}
func startCyclus(){
currentNode = 0
if maxNodes == 0 {return}
Running = true
blePeripheral = peripherals[0]
updateService = true
blePeripheral?.discoverServices([ParticlePeripheral.BLEService_UUID])
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.writeValue(data: "N 5000G55")
currentNode += 1
}
func Vervolg(){
print("vervolg")
if currentNode == maxNodes {Running = false;return}
blePeripheral = peripherals[currentNode]
updateService = true
blePeripheral?.discoverServices([ParticlePeripheral.BLEService_UUID])
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) {
self.writeValue(data: "N 5000G55")
currentNode += 1
}
}
// Write functions
func writeValue(data: String){
print("schrijfdata " + String(currentNode))
let valueString = (data as NSString).data(using: String.Encoding.utf8.rawValue)
//change the "data" to valueString
if let blePer = blePeripheral{
if let txCharacteristic = txCharacteristic {
blePer.writeValue(valueString!, for: txCharacteristic, type: CBCharacteristicWriteType.withoutResponse)
}
}
}
/*
Invoked when the central manager’s state is updated.
This is where we kick off the scan if Bluetooth is turned on.
*/
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
// We will just handle it the easy way here: if Bluetooth is on, proceed...start scan!
print("Bluetooth Enabled")
startScan()
} else {
//If Bluetooth is off, display a UI alert message saying "Bluetooth is not enable" and "Make sure that your bluetooth is turned on"
print("Bluetooth Disabled- Make sure your Bluetooth is turned on")
let alertVC = UIAlertController(title: "Bluetooth is not enabled", message: "Make sure that your bluetooth is turned on", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "ok", style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) -> Void in
self.dismiss(animated: true, completion: nil)
})
alertVC.addAction(action)
self.present(alertVC, animated: true, completion: nil)
}
}
}
extension String {
var isNumber: Bool {
let characters = CharacterSet.decimalDigits.inverted
return !self.isEmpty && rangeOfCharacter(from: characters) == nil
}
}
I think it's your logging is hiding what's really happening.
You reassign blePeripheral before each connection, but if any of them take longer than 0.5 seconds, by the time didConnect is called, the device that has connected won't be the one that's referred to by blePeripheral.
I would suggest removing blePeripheral entirely, and explicitly pass the CBPeripheral object into connectToDevice. Also, in didConnect, use the peripheral parameter that's passed in.

Use Bluetooth to control Arduino from IOS app

I've receive my arduino BLE module : SH-HC-08 I now how to use it regarding Android code. I also succeeded to communicate from an IOS app to my arduino by using an app from the app store. Now I would like to create my own app to control my arduino project.
I've been already trying a lot of tutorial available on the web but nothing work ...
But this one look like to be good : Tuto that I follow
To work my Arduino need to receive this value as string :
"0" -> Place the Servo in positon 0
"180" -> Place the Servo in position 180
Here is my arduino code :
in void setup()
bluetoothSerial.begin(9600);
Serial.begin(9600);
pinMode(LED_PIN, OUTPUT);
Serial.println("Prêt");
bluetoothSerial.setTimeout(300);
servo.attach(7, 0, 180);
servo.write(0);
in my void loop()
if(bluetoothSerial.available()){
c = bluetoothSerial.readString();
Serial.println(c);
if(c=="0"){
servo.write(0);
}
if(c=="180"){
servo.write(180);
}
}
By using the Appstore BLE communication app this works very well !
Now with my app nothing happens when I send "180" or "0" ...
My iOS Code :
In the mainViewController :
import UIKit
import CoreBluetooth
class MainViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {
var manager:CBCentralManager? = nil
var mainPeripheral:CBPeripheral? = nil
var mainCharacteristic:CBCharacteristic? = nil
let BLEService = "DFB0"
let BLECharacteristic = "DFB1"
#IBOutlet weak var recievedMessageText: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
manager = CBCentralManager(delegate: self, queue: nil);
customiseNavigationBar()
}
// ................... CustomiseNavigationBar() were here
let rightBarButton = UIBarButtonItem()
rightBarButton.customView = rightButton
self.navigationItem.rightBarButtonItem = rightBarButton
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "scan-segue") {
let scanController : ScanTableViewController = segue.destination as! ScanTableViewController
//set the manager's delegate to the scan view so it can call relevant connection methods
manager?.delegate = scanController
scanController.manager = manager
scanController.parentView = self
}
}
// MARK: Button Methods
#objc func scanButtonPressed() {
performSegue(withIdentifier: "scan-segue", sender: nil)
}
#objc func disconnectButtonPressed() {
//this will call didDisconnectPeripheral, but if any other apps are using the device it will not immediately disconnect
manager?.cancelPeripheralConnection(mainPeripheral!)
}
#IBAction func sendButtonPressed(_ sender: AnyObject) {
let helloWorld = "180"
let dataToSend = helloWorld.data(using: String.Encoding.utf8)
if (mainPeripheral != nil) {
mainPeripheral?.writeValue(dataToSend!, for: mainCharacteristic!, type: CBCharacteristicWriteType.withResponse)
print(dataToSend)
} else {
print("haven't discovered device yet")
}
}
// MARK: - CBCentralManagerDelegate Methods
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
mainPeripheral = nil
customiseNavigationBar()
print("Disconnected" + peripheral.name!)
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print(central.state)
}
// MARK: CBPeripheralDelegate Methods
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
for service in peripheral.services! {
print("Service found with UUID: " + service.uuid.uuidString)
//device information service
if (service.uuid.uuidString == "180A") {
peripheral.discoverCharacteristics(nil, for: service)
}
//GAP (Generic Access Profile) for Device Name
// This replaces the deprecated CBUUIDGenericAccessProfileString
if (service.uuid.uuidString == "1800") {
peripheral.discoverCharacteristics(nil, for: service)
}
//Bluno Service
if (service.uuid.uuidString == BLEService) {
peripheral.discoverCharacteristics(nil, for: service)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
//get device name
if (service.uuid.uuidString == "1800") {
for characteristic in service.characteristics! {
if (characteristic.uuid.uuidString == "2A00") {
peripheral.readValue(for: characteristic)
print("Found Device Name Characteristic")
}
}
}
if (service.uuid.uuidString == "180A") {
for characteristic in service.characteristics! {
if (characteristic.uuid.uuidString == "2A29") {
peripheral.readValue(for: characteristic)
print("Found a Device Manufacturer Name Characteristic")
mainCharacteristic = characteristic
} else if (characteristic.uuid.uuidString == "2A23") {
peripheral.readValue(for: characteristic)
print("Found System ID")
mainCharacteristic = characteristic
}
}
}
if (service.uuid.uuidString == BLEService) {
for characteristic in service.characteristics! {
if (characteristic.uuid.uuidString == BLECharacteristic) {
//we'll save the reference, we need it to write data
mainCharacteristic = characteristic
//Set Notify is useful to read incoming data async
peripheral.setNotifyValue(true, for: characteristic)
print("Found Bluno Data Characteristic")
}
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if (characteristic.uuid.uuidString == "2A00") {
//value for device name recieved
let deviceName = characteristic.value
print(deviceName ?? "No Device Name")
} else if (characteristic.uuid.uuidString == "2A29") {
//value for manufacturer name recieved
let manufacturerName = characteristic.value
print(manufacturerName ?? "No Manufacturer Name")
} else if (characteristic.uuid.uuidString == "2A23") {
//value for system ID recieved
let systemID = characteristic.value
print(systemID ?? "No System ID")
} else if (characteristic.uuid.uuidString == BLECharacteristic) {
//data recieved
if(characteristic.value != nil) {
let stringValue = String(data: characteristic.value!, encoding: String.Encoding.utf8)!
recievedMessageText.text = stringValue
}
}
}
}
And my ScanTableViewController :
import UIKit
import CoreBluetooth
class ScanTableViewController: UITableViewController, CBCentralManagerDelegate {
var peripherals:[CBPeripheral] = []
var manager:CBCentralManager? = nil
var parentView:MainViewController? = nil
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
scanBLEDevices()
}
// MARK: - Table view data source
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
// #warning Incomplete implementation, return the number of rows
return peripherals.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "scanTableCell", for: indexPath)
let peripheral = peripherals[indexPath.row]
cell.textLabel?.text = peripheral.name
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let peripheral = peripherals[indexPath.row]
manager?.connect(peripheral, options: nil)
}
// MARK: BLE Scanning
func scanBLEDevices() {
//manager?.scanForPeripherals(withServices: [CBUUID.init(string: parentView!.BLEService)], options: nil)
//if you pass nil in the first parameter, then scanForPeriperals will look for any devices.
manager?.scanForPeripherals(withServices: nil, options: nil)
//stop scanning after 3 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
self.stopScanForBLEDevices()
}
}
func stopScanForBLEDevices() {
manager?.stopScan()
}
// MARK: - CBCentralManagerDelegate Methods
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
if(!peripherals.contains(peripheral)) {
peripherals.append(peripheral)
}
self.tableView.reloadData()
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
print(central.state)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
//pass reference to connected peripheral to parent view
parentView?.mainPeripheral = peripheral
peripheral.delegate = parentView
peripheral.discoverServices(nil)
//peripheral.discoverCharacteristics(<#T##characteristicUUIDs: [CBUUID]?##[CBUUID]?#>, for: <#T##CBService#>)
//set the manager's delegate view to parent so it can call relevant disconnect methods
manager?.delegate = parentView
parentView?.customiseNavigationBar()
if let navController = self.navigationController {
navController.popViewController(animated: true)
}
print("Connected to " + peripheral.name!)
}
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
print(error!)
}
}
I'm sorry about put a lot of code it isn't so clean but I totally don't know where is the problem ...
Thanks a lot for your help !

How to disconnect already connected ble device

So my problem is when I segue to different storyboard my ble peripheral stay connected to phone:
code that I use to scan and connect ble peripheral:
import Foundation
import UIKit
import CoreBluetooth
var txCharacteristic : CBCharacteristic?
var rxCharacteristic : CBCharacteristic?
var blePeripheral : CBPeripheral?
var characteristicASCIIValue = NSString()
class BLECentralViewController : UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDelegate, UITableViewDataSource{
//Data
var centralManager : CBCentralManager!
var RSSIs = [NSNumber]()
var data = NSMutableData()
var writeData: String = ""
var peripherals: [CBPeripheral] = []
var characteristicValue = [CBUUID: NSData]()
var timer = Timer()
var characteristics = [String : CBCharacteristic]()
//UI
#IBOutlet weak var baseTableView: UITableView!
#IBOutlet weak var refreshButton: UIBarButtonItem!
#IBAction func refreshAction(_ sender: AnyObject) {
disconnectFromDevice()
self.peripherals = []
self.RSSIs = []
self.baseTableView.reloadData()
startScan()
}
override func viewDidLoad() {
super.viewDidLoad()
self.baseTableView.delegate = self
self.baseTableView.dataSource = self
self.baseTableView.reloadData()
/*Our key player in this app will be our CBCentralManager. CBCentralManager objects are used to manage discovered or connected remote peripheral devices (represented by CBPeripheral objects), including scanning for, discovering, and connecting to advertising peripherals.
*/
centralManager = CBCentralManager(delegate: self, queue: nil)
let backButton = UIBarButtonItem(title: "Disconnect", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backButton
}
override func viewDidAppear(_ animated: Bool) {
disconnectFromDevice()
super.viewDidAppear(animated)
refreshScanView()
print("View Cleared")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("Stop Scanning")
centralManager?.stopScan()
}
/*Okay, now that we have our CBCentalManager up and running, it's time to start searching for devices. You can do this by calling the "scanForPeripherals" method.*/
func startScan() {
peripherals = []
print("Now Scanning...")
self.timer.invalidate()
centralManager?.scanForPeripherals(withServices: nil , options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
Timer.scheduledTimer(timeInterval: 3, target: self, selector: #selector(self.cancelScan), userInfo: nil, repeats: false)
}
/*We also need to stop scanning at some point so we'll also create a function that calls "stopScan"*/
#objc func cancelScan() {
self.centralManager?.stopScan()
print("Scan Stopped")
print("Number of Peripherals Found: \(peripherals.count)")
}
func refreshScanView() {
baseTableView.reloadData()
}
//-Terminate all Peripheral Connection
/*
Call this when things either go wrong, or you're done with the connection.
This cancels any subscriptions if there are any, or straight disconnects if not.
(didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved)
*/
func disconnectFromDevice () {
if blePeripheral != nil {
// We have a connection to the device but we are not subscribed to the Transfer Characteristic for some reason.
// Therefore, we will just disconnect from the peripheral
centralManager?.cancelPeripheralConnection(blePeripheral!)
}
}
func restoreCentralManager() {
//Restores Central Manager delegate if something went wrong
centralManager?.delegate = self
}
/*
Called when the central manager discovers a peripheral while scanning. Also, once peripheral is connected, cancel scanning.
*/
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,advertisementData: [String : Any], rssi RSSI: NSNumber) {
blePeripheral = peripheral
self.peripherals.append(peripheral)
self.RSSIs.append(RSSI)
peripheral.delegate = self
self.baseTableView.reloadData()
if blePeripheral == nil {
print("Found new pheripheral devices with services")
print("Peripheral name: \(String(describing: peripheral.name))")
print("**********************************")
print ("Advertisement Data : \(advertisementData)")
}
}
//Peripheral Connections: Connecting, Connected, Disconnected
//-Connection
func connectToDevice () {
centralManager?.connect(blePeripheral!, options: nil)
print("Good luck")
print(blePeripheral!.discoverServices(nil))
print("Good luck")
}
/*
Invoked when a connection is successfully created with a peripheral.
This method is invoked when a call to connect(_:options:) is successful. You typically implement this method to set the peripheral’s delegate and to discover its services.
*/
//-Connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("*****************************")
print("Connection complete")
print("Peripheral info: \(String(describing: blePeripheral))")
//Stop Scan- We don't need to scan once we've connected to a peripheral. We got what we came for.
centralManager?.stopScan()
print("Scan Stopped")
//Erase data that we might have
data.length = 0
//Discovery callback
peripheral.delegate = self
//Only look for services that matches transmit uuid
peripheral.discoverServices([BLEService_UUID])
//Once connected, move to new view controller to manager incoming and outgoing data
let storyboard = UIStoryboard(name: "Main1", bundle: nil)
let uartViewController = storyboard.instantiateViewController(withIdentifier: "UartModuleViewController") as! UartModuleViewController
uartViewController.peripheral = peripheral
navigationController?.pushViewController(uartViewController, animated: true)
}
/*
Invoked when the central manager fails to create a connection with a peripheral.
*/
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
if error != nil {
print("Failed to connect to peripheral")
return
}
}
func disconnectAllConnection() {
centralManager.cancelPeripheralConnection(blePeripheral!)
}
/*
Invoked when you discover the peripheral’s available services.
This method is invoked when your app calls the discoverServices(_:) method. If the services of the peripheral are successfully discovered, you can access them through the peripheral’s services property. If successful, the error parameter is nil. If unsuccessful, the error parameter returns the cause of the failure.
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("*******************************************************AAA")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let services = peripheral.services else {
return
}
//We need to discover the all characteristic
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
print("god bless")
print(peripheral.discoverCharacteristics(nil, for: service))
print("god bless")
// bleService = service
}
print("Discovered Services: \(services)")
}
/*
Invoked when you discover the characteristics of a specified service.
This method is invoked when your app calls the discoverCharacteristics(_:for:) method. If the characteristics of the specified service are successfully discovered, you can access them through the service's characteristics property. If successful, the error parameter is nil. If unsuccessful, the error parameter returns the cause of the failure.
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let characteristics = service.characteristics else {
return
}
print("Found \(characteristics.count) characteristics!")
for characteristic in characteristics {
//looks for the right characteristic
if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Rx) {
rxCharacteristic = characteristic
//Once found, subscribe to the this particular characteristic...
peripheral.setNotifyValue(true, for: rxCharacteristic!)
// We can return after calling CBPeripheral.setNotifyValue because CBPeripheralDelegate's
// didUpdateNotificationStateForCharacteristic method will be called automatically
peripheral.readValue(for: characteristic)
print("Rx Characteristic: \(characteristic.uuid)")
}
if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Tx){
txCharacteristic = characteristic
print("Tx Characteristic: \(characteristic.uuid)")
}
peripheral.discoverDescriptors(for: characteristic)
}
}
// Getting Values From Characteristic
/*After you've found a characteristic of a service that you are interested in, you can read the characteristic's value by calling the peripheral "readValueForCharacteristic" method within the "didDiscoverCharacteristicsFor service" delegate.
*/
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic == rxCharacteristic {
if let ASCIIstring = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue) {
characteristicASCIIValue = ASCIIstring
print("Value Recieved: \((characteristicASCIIValue as String))")
NotificationCenter.default.post(name:NSNotification.Name(rawValue: "Notify"), object: nil)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if error != nil {
print("\(error.debugDescription)")
return
}
if ((characteristic.descriptors) != nil) {
for x in characteristic.descriptors!{
let descript = x as CBDescriptor?
print("function name: DidDiscoverDescriptorForChar \(String(describing: descript?.description))")
print("Rx Value \(String(describing: rxCharacteristic?.value))")
print("Tx Value \(String(describing: txCharacteristic?.value))")
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if (error != nil) {
print("Error changing notification state:\(String(describing: error?.localizedDescription))")
} else {
print("Characteristic's value subscribed")
}
if (characteristic.isNotifying) {
print ("Subscribed. Notification has begun for: \(characteristic.uuid)")
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnected")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Message sent")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Succeeded!")
}
//Table View Functions
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.peripherals.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//Connect to device where the peripheral is connected
let cell = tableView.dequeueReusableCell(withIdentifier: "BlueCell") as! PeripheralTableViewCell
let peripheral = self.peripherals[indexPath.row]
let RSSI = self.RSSIs[indexPath.row]
if peripheral.name == nil {
cell.peripheralLabel.text = "nil"
} else {
cell.peripheralLabel.text = peripheral.name
}
cell.rssiLabel.text = "RSSI: \(RSSI)"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
blePeripheral = peripherals[indexPath.row]
connectToDevice()
}
/*
Invoked when the central manager’s state is updated.
This is where we kick off the scan if Bluetooth is turned on.
*/
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
// We will just handle it the easy way here: if Bluetooth is on, proceed...start scan!
print("Bluetooth Enabled")
startScan()
} else {
//If Bluetooth is off, display a UI alert message saying "Bluetooth is not enable" and "Make sure that your bluetooth is turned on"
print("Bluetooth Disabled- Make sure your Bluetooth is turned on")
let alertVC = UIAlertController(title: "Bluetooth is not enabled", message: "Make sure that your bluetooth is turned on", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "ok", style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) -> Void in
self.dismiss(animated: true, completion: nil)
})
alertVC.addAction(action)
self.present(alertVC, animated: true, completion: nil)
}
}
}
and code when i sending data from another viewcontroller
import UIKit
import CoreBluetooth
class UartModuleViewController: UIViewController, CBPeripheralManagerDelegate, UITextViewDelegate, UITextFieldDelegate {
//UI
#IBOutlet weak var baseTextView: UITextView!
#IBOutlet weak var sendButton: UIButton!
#IBOutlet weak var inputTextField: UITextField!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var switchUI: UISwitch!
//Data
var centralManager : CBCentralManager!
var peripheralManager: CBPeripheralManager?
var peripheral: CBPeripheral!
private var consoleAsciiText:NSAttributedString? = NSAttributedString(string: "")
#IBAction func Discon(_ sender: Any) {
disconnectFromDevice()
print("Hello")
}
func disconnectFromDevice () {
// We have a connection to the device but we are not subscribed to the Transfer Characteristic for some reason.
// Therefore, we will just disconnect from the peripheral
centralManager?.cancelPeripheralConnection(blePeripheral!)
}
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.backBarButtonItem = UIBarButtonItem(title:"Back", style:.plain, target:nil, action:nil)
//Create and start the peripheral manager
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
//-Notification for updating the text view with incoming text
}
override func viewDidAppear(_ animated: Bool) {
}
override func viewDidDisappear(_ animated: Bool) {
// peripheralManager?.stopAdvertising()
// self.peripheralManager = nil
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
#IBAction func clickSendAction(_ sender: AnyObject) {
outgoingData()
}
#IBAction func S(_ sender: Any) {
sends()
}
#IBAction func sendd(_ sender: Any) {
sendd()
}
#IBAction func senda(_ sender: Any) {
senda()
}
#IBAction func sendt(_ sender: Any) {
sendt()
}
#IBAction func sendb(_ sender: Any) {
sendb()
}
func outgoingData () {
let inputText = "W"
writeValue(data: inputText)
}
func sends () {
let inputText = "S"
writeValue(data: inputText)
}
func sendd () {
let inputText = "D"
writeValue(data: inputText)
}
func senda () {
let inputText = "A"
writeValue(data: inputText)
}
func sendt () {
let inputText = "T"
writeValue(data: inputText)
}
func sendb () {
let inputText = "B"
writeValue(data: inputText)
}
// Write functions
func writeValue(data: String){
let valueString = (data as NSString).data(using: String.Encoding.utf8.rawValue)
//change the "data" to valueString
if let blePeripheral = blePeripheral{
if let txCharacteristic = txCharacteristic {
blePeripheral.writeValue(valueString!, for: txCharacteristic, type: CBCharacteristicWriteType.withoutResponse)
}
}
}
func writeCharacteristic(val: Int8){
var val = val
let ns = NSData(bytes: &val, length: MemoryLayout<Int8>.size)
blePeripheral!.writeValue(ns as Data, for: txCharacteristic!, type: CBCharacteristicWriteType.withResponse)
}
//MARK: UITextViewDelegate methods
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
if textView === baseTextView {
//tapping on consoleview dismisses keyboard
inputTextField.resignFirstResponder()
return false
}
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
scrollView.setContentOffset(CGPoint(x:0, y:250), animated: true)
}
func textFieldDidEndEditing(_ textField: UITextField) {
scrollView.setContentOffset(CGPoint(x:0, y:0), animated: true)
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
return
}
print("Peripheral manager is running")
}
//Check when someone subscribe to our characteristic, start sending the data
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
print("Device subscribe to characteristic")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
outgoingData()
return(true)
}
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
if let error = error {
print("\(error)")
return
}
}
}
How i can terminate all connections when i segue from second view controller ?
Thank you all so much
You can call your disconnect functions in
override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!)

How can we instantiate a BLE connected peripheral in every view controller swift class instead of a Singleton?

Hi I have a Swift app that I'm trying to learn.
Iam using Adafruit Basic Chat as a reference.
https://github.com/adafruit/Basic-Chat/tree/master/Basic%20Chat
How can I pass the connected peripheral to another view controller scene, without a singleton class?
I have gone through a lot of links but can someone tell me the simplest form of code to extend the peripheral scope to all my view controller activities?
I am able to read and write data using the following code but how can I clear the RX buffer after I have received the data as I sometimes find the rx data seems to overwrite the received bytes.
// BLECentralViewController
//
// BLECentralViewController.swift
// Basic Chat
//
// Created by Trevor Beaton on 11/29/16.
// Copyright © 2016 Vanguard Logic LLC. All rights reserved.
//
import Foundation
import UIKit
import CoreBluetooth
var txCharacteristic : CBCharacteristic?
var rxCharacteristic : CBCharacteristic?
var blePeripheral : CBPeripheral?
var characteristicASCIIValue = NSString()
class BLECentralViewController : UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate, UITableViewDelegate, UITableViewDataSource{
//Data
var centralManager : CBCentralManager!
var RSSIs = [NSNumber]()
var data = NSMutableData()
var writeData: String = ""
var peripherals: [CBPeripheral] = []
var characteristicValue = [CBUUID: NSData]()
var timer = Timer()
var characteristics = [String : CBCharacteristic]()
//UI
#IBOutlet weak var baseTableView: UITableView!
#IBOutlet weak var refreshButton: UIBarButtonItem!
#IBAction func refreshAction(_ sender: AnyObject) {
disconnectFromDevice()
self.peripherals = []
self.RSSIs = []
self.baseTableView.reloadData()
startScan()
}
override func viewDidLoad() {
super.viewDidLoad()
self.baseTableView.delegate = self
self.baseTableView.dataSource = self
self.baseTableView.reloadData()
/*Our key player in this app will be our CBCentralManager. CBCentralManager objects are used to manage discovered or connected remote peripheral devices (represented by CBPeripheral objects), including scanning for, discovering, and connecting to advertising peripherals.
*/
centralManager = CBCentralManager(delegate: self, queue: nil)
let backButton = UIBarButtonItem(title: "Disconnect", style: .plain, target: nil, action: nil)
navigationItem.backBarButtonItem = backButton
}
override func viewDidAppear(_ animated: Bool) {
disconnectFromDevice()
super.viewDidAppear(animated)
refreshScanView()
print("View Cleared")
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
print("Stop Scanning")
centralManager?.stopScan()
}
/*Okay, now that we have our CBCentalManager up and running, it's time to start searching for devices. You can do this by calling the "scanForPeripherals" method.*/
func startScan() {
peripherals = []
print("Now Scanning...")
self.timer.invalidate()
centralManager?.scanForPeripherals(withServices: [BLEService_UUID] , options: [CBCentralManagerScanOptionAllowDuplicatesKey:false])
Timer.scheduledTimer(timeInterval: 17, target: self, selector: #selector(self.cancelScan), userInfo: nil, repeats: false)
}
/*We also need to stop scanning at some point so we'll also create a function that calls "stopScan"*/
func cancelScan() {
self.centralManager?.stopScan()
print("Scan Stopped")
print("Number of Peripherals Found: \(peripherals.count)")
}
func refreshScanView() {
baseTableView.reloadData()
}
//-Terminate all Peripheral Connection
/*
Call this when things either go wrong, or you're done with the connection.
This cancels any subscriptions if there are any, or straight disconnects if not.
(didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved)
*/
func disconnectFromDevice () {
if blePeripheral != nil {
// We have a connection to the device but we are not subscribed to the Transfer Characteristic for some reason.
// Therefore, we will just disconnect from the peripheral
centralManager?.cancelPeripheralConnection(blePeripheral!)
}
}
func restoreCentralManager() {
//Restores Central Manager delegate if something went wrong
centralManager?.delegate = self
}
/*
Called when the central manager discovers a peripheral while scanning. Also, once peripheral is connected, cancel scanning.
*/
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,advertisementData: [String : Any], rssi RSSI: NSNumber) {
blePeripheral = peripheral
self.peripherals.append(peripheral)
self.RSSIs.append(RSSI)
peripheral.delegate = self
self.baseTableView.reloadData()
if blePeripheral == nil {
print("Found new pheripheral devices with services")
print("Peripheral name: \(String(describing: peripheral.name))")
print("**********************************")
print ("Advertisement Data : \(advertisementData)")
}
}
//Peripheral Connections: Connecting, Connected, Disconnected
//-Connection
func connectToDevice () {
centralManager?.connect(blePeripheral!, options: nil)
}
/*
Invoked when a connection is successfully created with a peripheral.
This method is invoked when a call to connect(_:options:) is successful. You typically implement this method to set the peripheral’s delegate and to discover its services.
*/
//-Connected
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("*****************************")
print("Connection complete")
print("Peripheral info: \(String(describing: blePeripheral))")
//Stop Scan- We don't need to scan once we've connected to a peripheral. We got what we came for.
centralManager?.stopScan()
print("Scan Stopped")
//Erase data that we might have
data.length = 0
//Discovery callback
peripheral.delegate = self
//Only look for services that matches transmit uuid
peripheral.discoverServices([BLEService_UUID])
//Once connected, move to new view controller to manager incoming and outgoing data
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let uartViewController = storyboard.instantiateViewController(withIdentifier: "UartModuleViewController") as! UartModuleViewController
uartViewController.peripheral = peripheral
navigationController?.pushViewController(uartViewController, animated: true)
}
/*
Invoked when the central manager fails to create a connection with a peripheral.
*/
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
if error != nil {
print("Failed to connect to peripheral")
return
}
}
func disconnectAllConnection() {
centralManager.cancelPeripheralConnection(blePeripheral!)
}
/*
Invoked when you discover the peripheral’s available services.
This method is invoked when your app calls the discoverServices(_:) method. If the services of the peripheral are successfully discovered, you can access them through the peripheral’s services property. If successful, the error parameter is nil. If unsuccessful, the error parameter returns the cause of the failure.
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let services = peripheral.services else {
return
}
//We need to discover the all characteristic
for service in services {
peripheral.discoverCharacteristics(nil, for: service)
// bleService = service
}
print("Discovered Services: \(services)")
}
/*
Invoked when you discover the characteristics of a specified service.
This method is invoked when your app calls the discoverCharacteristics(_:for:) method. If the characteristics of the specified service are successfully discovered, you can access them through the service's characteristics property. If successful, the error parameter is nil. If unsuccessful, the error parameter returns the cause of the failure.
*/
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
print("*******************************************************")
if ((error) != nil) {
print("Error discovering services: \(error!.localizedDescription)")
return
}
guard let characteristics = service.characteristics else {
return
}
print("Found \(characteristics.count) characteristics!")
for characteristic in characteristics {
//looks for the right characteristic
if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Rx) {
rxCharacteristic = characteristic
//Once found, subscribe to the this particular characteristic...
peripheral.setNotifyValue(true, for: rxCharacteristic!)
// We can return after calling CBPeripheral.setNotifyValue because CBPeripheralDelegate's
// didUpdateNotificationStateForCharacteristic method will be called automatically
peripheral.readValue(for: characteristic)
print("Rx Characteristic: \(characteristic.uuid)")
}
if characteristic.uuid.isEqual(BLE_Characteristic_uuid_Tx){
txCharacteristic = characteristic
print("Tx Characteristic: \(characteristic.uuid)")
}
peripheral.discoverDescriptors(for: characteristic)
}
}
// Getting Values From Characteristic
/*After you've found a characteristic of a service that you are interested in, you can read the characteristic's value by calling the peripheral "readValueForCharacteristic" method within the "didDiscoverCharacteristicsFor service" delegate.
*/
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
if characteristic == rxCharacteristic {
if let ASCIIstring = NSString(data: characteristic.value!, encoding: String.Encoding.utf8.rawValue) {
characteristicASCIIValue = ASCIIstring
print("Value Recieved: \((characteristicASCIIValue as String))")
NotificationCenter.default.post(name:NSNotification.Name(rawValue: "Notify"), object: nil)
}
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverDescriptorsFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if error != nil {
print("\(error.debugDescription)")
return
}
if ((characteristic.descriptors) != nil) {
for x in characteristic.descriptors!{
let descript = x as CBDescriptor!
print("function name: DidDiscoverDescriptorForChar \(String(describing: descript?.description))")
print("Rx Value \(String(describing: rxCharacteristic?.value))")
print("Tx Value \(String(describing: txCharacteristic?.value))")
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
print("*******************************************************")
if (error != nil) {
print("Error changing notification state:\(String(describing: error?.localizedDescription))")
} else {
print("Characteristic's value subscribed")
}
if (characteristic.isNotifying) {
print ("Subscribed. Notification has begun for: \(characteristic.uuid)")
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnected")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Message sent")
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor descriptor: CBDescriptor, error: Error?) {
guard error == nil else {
print("Error discovering services: error")
return
}
print("Succeeded!")
}
//Table View Functions
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.peripherals.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//Connect to device where the peripheral is connected
let cell = tableView.dequeueReusableCell(withIdentifier: "BlueCell") as! PeripheralTableViewCell
let peripheral = self.peripherals[indexPath.row]
let RSSI = self.RSSIs[indexPath.row]
if peripheral.name == nil {
cell.peripheralLabel.text = "nil"
} else {
cell.peripheralLabel.text = peripheral.name
}
cell.rssiLabel.text = "RSSI: \(RSSI)"
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
blePeripheral = peripherals[indexPath.row]
connectToDevice()
}
/*
Invoked when the central manager’s state is updated.
This is where we kick off the scan if Bluetooth is turned on.
*/
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == CBManagerState.poweredOn {
// We will just handle it the easy way here: if Bluetooth is on, proceed...start scan!
print("Bluetooth Enabled")
startScan()
} else {
//If Bluetooth is off, display a UI alert message saying "Bluetooth is not enable" and "Make sure that your bluetooth is turned on"
print("Bluetooth Disabled- Make sure your Bluetooth is turned on")
let alertVC = UIAlertController(title: "Bluetooth is not enabled", message: "Make sure that your bluetooth is turned on", preferredStyle: UIAlertControllerStyle.alert)
let action = UIAlertAction(title: "ok", style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) -> Void in
self.dismiss(animated: true, completion: nil)
})
alertVC.addAction(action)
self.present(alertVC, animated: true, completion: nil)
}
}
}
//UART SCENE
//
// UartModuleViewController.swift
// Basic Chat
//
// Created by Trevor Beaton on 12/4/16.
// Copyright © 2016 Vanguard Logic LLC. All rights reserved.
//
import UIKit
import CoreBluetooth
class UartModuleViewController: UIViewController, CBPeripheralManagerDelegate, UITextViewDelegate, UITextFieldDelegate {
//UI
#IBOutlet weak var baseTextView: UITextView!
#IBOutlet weak var sendButton: UIButton!
#IBOutlet weak var inputTextField: UITextField!
#IBOutlet weak var scrollView: UIScrollView!
#IBOutlet weak var switchUI: UISwitch!
//Data
var peripheralManager: CBPeripheralManager?
var peripheral: CBPeripheral!
private var consoleAsciiText:NSAttributedString? = NSAttributedString(string: "")
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.backBarButtonItem = UIBarButtonItem(title:"Back", style:.plain, target:nil, action:nil)
self.baseTextView.delegate = self
self.inputTextField.delegate = self
//Base text view setup
self.baseTextView.layer.borderWidth = 3.0
self.baseTextView.layer.borderColor = UIColor.blue.cgColor
self.baseTextView.layer.cornerRadius = 3.0
self.baseTextView.text = ""
//Input Text Field setup
self.inputTextField.layer.borderWidth = 2.0
self.inputTextField.layer.borderColor = UIColor.blue.cgColor
self.inputTextField.layer.cornerRadius = 3.0
//Create and start the peripheral manager
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
//-Notification for updating the text view with incoming text
updateIncomingData()
}
override func viewDidAppear(_ animated: Bool) {
self.baseTextView.text = ""
}
override func viewDidDisappear(_ animated: Bool) {
// peripheralManager?.stopAdvertising()
// self.peripheralManager = nil
super.viewDidDisappear(animated)
NotificationCenter.default.removeObserver(self)
}
func updateIncomingData () {
NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: "Notify"), object: nil , queue: nil){
notification in
let appendString = "\n"
let myFont = UIFont(name: "Helvetica Neue", size: 15.0)
let myAttributes2 = [NSFontAttributeName: myFont!, NSForegroundColorAttributeName: UIColor.red]
let attribString = NSAttributedString(string: "[Incoming]: " + (characteristicASCIIValue as String) + appendString, attributes: myAttributes2)
let newAsciiText = NSMutableAttributedString(attributedString: self.consoleAsciiText!)
self.baseTextView.attributedText = NSAttributedString(string: characteristicASCIIValue as String , attributes: myAttributes2)
newAsciiText.append(attribString)
self.consoleAsciiText = newAsciiText
self.baseTextView.attributedText = self.consoleAsciiText
}
}
#IBAction func clickSendAction(_ sender: AnyObject) {
outgoingData()
}
func outgoingData () {
let appendString = "\n"
let inputText = inputTextField.text
let myFont = UIFont(name: "Helvetica Neue", size: 15.0)
let myAttributes1 = [NSFontAttributeName: myFont!, NSForegroundColorAttributeName: UIColor.blue]
writeValue(data: inputText!)
let attribString = NSAttributedString(string: "[Outgoing]: " + inputText! + appendString, attributes: myAttributes1)
let newAsciiText = NSMutableAttributedString(attributedString: self.consoleAsciiText!)
newAsciiText.append(attribString)
consoleAsciiText = newAsciiText
baseTextView.attributedText = consoleAsciiText
//erase what's in the text field
inputTextField.text = ""
}
// Write functions
func writeValue(data: String){
let valueString = (data as NSString).data(using: String.Encoding.utf8.rawValue)
//change the "data" to valueString
if let blePeripheral = blePeripheral{
if let txCharacteristic = txCharacteristic {
blePeripheral.writeValue(valueString!, for: txCharacteristic, type: CBCharacteristicWriteType.withResponse)
}
}
}
func writeCharacteristic(val: Int8){
var val = val
let ns = NSData(bytes: &val, length: MemoryLayout<Int8>.size)
blePeripheral!.writeValue(ns as Data, for: txCharacteristic!, type: CBCharacteristicWriteType.withResponse)
}
//MARK: UITextViewDelegate methods
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
if textView === baseTextView {
//tapping on consoleview dismisses keyboard
inputTextField.resignFirstResponder()
return false
}
return true
}
func textFieldDidBeginEditing(_ textField: UITextField) {
scrollView.setContentOffset(CGPoint(x:0, y:250), animated: true)
}
func textFieldDidEndEditing(_ textField: UITextField) {
scrollView.setContentOffset(CGPoint(x:0, y:0), animated: true)
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if peripheral.state == .poweredOn {
return
}
print("Peripheral manager is running")
}
//Check when someone subscribe to our characteristic, start sending the data
func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
print("Device subscribe to characteristic")
}
//This on/off switch sends a value of 1 and 0 to the Arduino
//This can be used as a switch or any thing you'd like
#IBAction func switchAction(_ sender: Any) {
if switchUI.isOn {
print("On ")
writeCharacteristic(val: 1)
}
else
{
print("Off")
writeCharacteristic(val: 0)
print(writeCharacteristic)
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
textField.resignFirstResponder()
outgoingData()
return(true)
}
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
if let error = error {
print("\(error)")
return
}
}
}
The peripheral keeps disconnecting and starts scanning soon as I start a new view controller using performsegue method.
It would be really helpful if someone could shed some light?

Thread 1 : signal SIGABRT unrecognized selector

I am currently creating a Bluetooth chat application with Xcode 8 that allows two devices to connect to each other via Bluetooth and send and receive messages to one another. Below is the code for this.
import UIKit
import CoreBluetooth
class ViewController: UIViewController, CBPeripheralManagerDelegate, CBCentralManagerDelegate, CBPeripheralDelegate {
let messageUUID = CBUUID(string: "053D6600-821E-46A7-AC25-43A81D948E8B")
let inputUUID = CBUUID(string: "49A79D26-5323-4374-81EA-29B099AF85C8")
let otherUUID = CBUUID(string: "053D6600-821E-46A7-AC25-43A81D948E87")
var peripheralManager: CBPeripheralManager!
var characteritic: CBMutableCharacteristic!
var getDataPeripheralCharacteristic: CBMutableCharacteristic!
var service: CBMutableService!
var outputData:String = ""
var centralManager: CBCentralManager!
var connectingPeripheral: CBPeripheral?
var centralWriteCharacteristic: CBCharacteristic!
#IBOutlet weak var inputLabel: UITextField!
#IBOutlet weak var outputLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func centralMode(sender: AnyObject) {
centralManager = CBCentralManager(delegate: self, queue: nil)
peripheralManager = nil
}
#IBAction func peripheralMode(sender: AnyObject) {
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
centralManager = nil
}
func peripheralManager(peripheral: CBPeripheralManager, didAddService service: CBService, error: NSError?) {
peripheral.stopAdvertising()
let identifier = Bundle.main.bundleIdentifier!
let manufacturerData = identifier.data(using: String.Encoding.utf8, allowLossyConversion: false)
let dataToBeAdvertised:[String: Any] = [
CBAdvertisementDataLocalNameKey : "Sample peripheral",
CBAdvertisementDataManufacturerDataKey : manufacturerData as Any,
CBAdvertisementDataServiceUUIDsKey : [messageUUID, inputUUID],
]
peripheralManager.startAdvertising(dataToBeAdvertised)
}
#IBAction func sendData(_ sender: UIButton) {
if (peripheralManager != nil) {
let passed = peripheralManager.updateValue(inputLabel.text!.data(using: String.Encoding.utf8)!, for: characteritic!, onSubscribedCentrals: nil)
if passed == false {
print("error couldn't send data")
}
}
if (centralManager != nil) {
if (connectingPeripheral != nil) {
connectingPeripheral?.writeValue(inputLabel.text!.data(using: String.Encoding.utf8)!, for: centralWriteCharacteristic, type: CBCharacteristicWriteType.withResponse)
}
}
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
if (peripheral.state == .poweredOn) {
characteritic = CBMutableCharacteristic(type: messageUUID, properties: CBCharacteristicProperties.notify, value: nil, permissions: CBAttributePermissions.readable)
getDataPeripheralCharacteristic = CBMutableCharacteristic(type: inputUUID, properties:
CBCharacteristicProperties.write, value: nil, permissions: CBAttributePermissions.writeable)
service = CBMutableService(type: otherUUID, primary: true)
service.characteristics = [characteritic!, getDataPeripheralCharacteristic!]
peripheralManager!.add(service)
}
}
func peripheralManager(peripheral: CBPeripheralManager, didReceiveWriteRequests requests: [CBATTRequest]) {
for request in requests {
if (request.characteristic.uuid.uuidString == inputUUID.uuidString) {
outputData = String(data: request.value!, encoding: String.Encoding.utf8)!
outputLabel.text = outputData
}
}
}
func peripheralManager(peripheral: CBPeripheralManager, didReceiveReadRequest request: CBATTRequest) {
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
centralManager.scanForPeripherals(withServices: nil, options: nil)
//search for peripheral device
}
}
//when peripheral is discovered, this method is called
private func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
self.centralManager.stopScan();
self.connectingPeripheral = peripheral;
peripheral.delegate = self;
centralManager.connect(peripheral, options: nil)
}
//if connection request from central is succesfull, this method is called
func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) {
peripheral.delegate = self;
peripheral.discoverServices(nil)
}
//if central discovers services, this method is called
private func peripheral(peripheral: CBPeripheral, didDiscoverServices error: NSError?) {
for service: CBService in peripheral.services! {
peripheral.discoverCharacteristics(nil, for: service)
}
}
private func peripheral(peripheral: CBPeripheral, didDiscoverCharacteristicsForService service: CBService, error: NSError?) {
if (service.uuid.uuidString == otherUUID.uuidString) {
guard let characteristics = service.characteristics else {
return
}
for characteristic in characteristics {
if characteristic.uuid.uuidString == messageUUID.uuidString {
peripheral.setNotifyValue(true, for: characteristic)
} else if characteristic.uuid.uuidString == inputUUID.uuidString {
centralWriteCharacteristic = characteristic
}
}
}
}
private func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
if error != nil {
print("Error reading characteristics");
}
if (characteristic.uuid == messageUUID) {
outputData = String(data: characteristic.value!, encoding: String.Encoding.utf8)!
print(outputData)
outputLabel.text = outputData
}
}
}
The Thread 1 signal SIGABRT error is produced when I click either central mode or peripheral mode but not when I click send data. I have done some research online and the general solution to this error is to check the connections for the buttons and make sure there is only one connection and it is the correct one. I have done this but it still has not fixed the error. Below are images of the connections for these buttons.
central mode button
peripheral mode button

Resources