I am creating an app for BLE connection for iOS. I can connect to the peripheral from central (iPhone6: iOS12.9) and send commands with I am able to send commands with writevalue.
https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518949-setnotifyvalue
In the above setNotifyValue, there is a description that seems to be accepted by indicate. The following methods of didUpdateValueFor do not return.
/// When changing the characteristic
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/1518708-peripheral
If you know how to implement receiving data in indicate, please let me know.
The sample code is shown below. I'm still working on it, so there may be some garbage code, sorry.
// ViewController.swift
import UIKit
import CoreBluetooth
import os
class ViewController: UIViewController {
/// https://qiita.com/eKushida/items/def628e0eff6c106d467
var serviceUUID : CBUUID!
var characteristicUUID : CBUUID!
var responseCharacteristicUUID : CBUUID!
var centralManager: CBCentralManager!
var peripheral: CBPeripheral!
var writeCharacteristic: CBCharacteristic!
var responsCharacteristic: CBCharacteristic!
var data = Data()
@IBOutlet weak var dispLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
setup()
dispLabel.text = "Startup"
}
/// Initialize the central manager and UUID
private func setup() {
// Create an object representing the UUID.
self.serviceUUID = CBUUID(string: "XXXXX0000-XXXX-XXXX-XXXX-XXXXXXXXXX")
self.characteristicUUID = CBUUID(string: "XXXX2001-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
self.responseCharacteristicUUID = CBUUID(string: "XXXX2000-XXXX-XXXX-XXXX-XXXXXXXXXXXX")
}
/// Pairing process
@IBAction func scan(_ sender: UIButton) {
print("Pairing process")
dispLabel.text = "Pairing process pressed"
self.centralManager = CBCentralManager(delegate: self, queue: nil)
}
/// Communication connection
@IBAction func connect(_ sender: UIButton) {
print("Communication connection")
/// https://qiita.com/MashMorgan/items/32500f158cb08d565786
/// https://knkomko.hatenablog.com/entry/2019/07/16/013443
let message = "**COMMAND**"
let command = message + "\r"
let writeData = Data(command.utf8)
print("writeData:" + String(data: writeData, encoding: .utf8)!)
peripheral.writeValue(writeData, for: writeCharacteristic, type: CBCharacteristicWriteType.withResponse)
}
}
//MARK : - CBCentralManagerDelegate
extension ViewController: CBCentralManagerDelegate {
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
//wait for power on and scan
case CBManagerState.poweredOn:
let services: [CBUUID] = [serviceUUID] ///serviceUUID
centralManager.scanForPeripherals(withServices: nil, options: nil)
// centralManager.scanForPeripherals(withServices: services, options: nil)
print("isScanning:" + String(centralManager.isScanning))
default:
break
}
}
/// Called when a peripheral is discovered
func centralManager(_ central: CBCentralManager,
didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any],
rssi RSSI: NSNumber) {
self.peripheral = peripheral
print("peripheral.name:" + String(peripheral.name ? "") + " peripheral.id:" + peripheral.identifier.uuidString)
if "XXXXXXX" == peripheral.name {
//start connection
self.centralManager.connect(self.peripheral, options: nil)
//peripheral is found, stop scanning
centralManager.stopScan()
}
}
/// called when connected
func centralManager(_ central: CBCentralManager,
didConnect peripheral: CBPeripheral) {
print("Connection successful serviceUUID:" + serviceUUID.uuidString)
peripheral.delegate = self
peripheral.discoverServices([serviceUUID])
dispLabel.text = "Peripheral connection successful"
}
/// Called when the connection fails
func centralManager(_ central: CBCentralManager,
didFailToConnect peripheral: CBPeripheral,
error: Error?) {
print("Connection failed")
}
/// When disconnected
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
print("Disconnection: \(String(describing: error))")
}
}
//MARK : - CBPeripheralDelegate
extension ViewController: CBPeripheralDelegate {
/// Called when the characteristic is found
func peripheral(_ peripheral: CBPeripheral,
DidDiscoverCharacteristicsFor service: CBService,
error: Error?) {
if error ! = nil {
print(error.debugDescription)
return
}
guard let serviceCharacteristics = service.characteristics else {
// error handling
return
}
// Processing by characteristic
for characreristic in serviceCharacteristics {
if characreristic.uuid == characteristicUUID
{
// keep the characteristic for writing data
self.writeCharacteristic = characreristic
print("Write characreristic / UUID:" + characreristic.uuid.uuidString)
print("Write characreristic / properties: \(self.writeCharacteristic.properties)")
continue
}
if characreristic.uuid == responseCharacteristicUUID {
peripheral.setNotifyValue(true, for: characreristic)
self.responsesCharacteristic = characreristic
print("Responses characreristic / UUID:" + characreristic.uuid.uuidString)
print("Responses characreristic / properties: \(self.responsesCharacteristic.properties)")
continue
}
print("Other characreristic / UUID:" + characreristic.uuid.uuidString)
}
}
func peripheral(_ peripheral: CBPeripheral, didDiscoverIncludedServicesFor: CBService, error: Error?){
print("peripheral didDiscoverIncludedServicesFor")
}
/// When writing data to the characteristic (called when sending a command)
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
print("peripheral didWriteValueFor")
guard error == nil else {
print("Error when writing characteristic data: \(String(describing: error))")
// failure handling
return
}
print(characteristic.value)
}
func peripheral(peripheral: CBPeripheral,
didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic,
error: NSError?)
{
print("peripheral didUpdateNotificationStateForCharacteristic")
if let error = error {
print("Notify state update failed.... .error: \(error)")
} else {
print("Notify state update succeeded! isNotifying: \(characteristic.isNotifying)")
}
}
func peripheral(peripheral: CBPeripheral,
didUpdateValueForCharacteristic characteristic: CBCharacteristic,
error: NSError?)
{
print("peripheral didUpdateValueForCharacteristic")
if let error = error {
print("Data update notification error: \(error)")
return
}
print("Data update! value: \(characteristic.value)")
}
/// When changing the characteristic
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
print("peripheral didUpdateValueFor")
guard error == nil else {
print("Error getting/changing characteristic value: \(String(describing: error))")
// failure handling
return
}
guard let data = characteristic.value else {
print("characteristic.value")
// failure process
return
}
// data will be passed to us
print(data)
}
}
I have example iOS projects (Central & Peripheral) which send/receive indications: https://github.com/alexanderlavrushko/BLEProof-collection
setNotifyValue
here is called similarly as you do, it should be fine.
I suggest to check the way how the characteristic is created and updated on the Peripheral side, iOS example link.
Also there is a great iOS application LightBlue which can simulate a BLE device, see this guide: