0

I created my custom peripheral to write data to peripheral and tried to write data from my central. when write value function is executed i am getting request is not supported error. Here is my code.Hope you understand my problem. Looking for the solution to fix. Thanks in advance.

connectedPeripheral?.writeValue(data, for: characteristic, type: .withResponse)

Setup up my custom BLEPeripheral and startAdvertising in Peripheral

// MARK: CBPeripheralManagerDelegate

func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
    if peripheral.state == .poweredOn {
        setup()
    } else {
        print("peripheral is not available: \(peripheral.state.rawValue)")
    }
}

func peripheralManager(_ peripheral: CBPeripheralManager, didAdd service: CBService, error: Error?) {
    if let error = error {
        print("Could not add service: \(error.localizedDescription)")
    } else {
        print("peripheral added service. Start advertising")
        let advertisementData: [String: Any] = [
            CBAdvertisementDataServiceUUIDsKey: [CBUUID(string: BLEIdentifiers.serviceIdentifier)],
            CBAdvertisementDataLocalNameKey: "BLE Sensor"  // This key will not be transmitted when app is backgrounded
        ]
        manager.startAdvertising(advertisementData)
    }
}

func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?) {
    if let error = error {
        print("Could not start advertising: \(error.localizedDescription)")
    } else {
        print("peripheral started advertising")
    }
}

func peripheralManager(_ peripheral: CBPeripheralManager, didReceiveRead request: CBATTRequest) {
    print("Did receive read request: \(request)")
    if !request.characteristic.uuid.isEqual(characteristic.uuid) {
        peripheral.respond(to: request, withResult: .requestNotSupported)
    } else {
        guard let value = characteristic.value else {
            peripheral.respond(to: request, withResult: .invalidAttributeValueLength)
            return
        }
        if request.offset > value.count {
            peripheral.respond(to: request, withResult: .invalidOffset)
        } else {
            request.value = value.subdata(in: request.offset..<value.count-request.offset)
            peripheral.respond(to: request, withResult: .success)
        }
    }
    
}
func setup() {
    let characteristicUUID = CBUUID(string: BLEIdentifiers.characteristicIdentifier)
    
    characteristic = CBMutableCharacteristic(type: characteristicUUID, properties: [.read, .write,.notify], value: nil, permissions: [.readable,.writeable])

    let descriptor = CBMutableDescriptor(type: CBUUID(string: CBUUIDCharacteristicUserDescriptionString), value: "BLESensor prototype")
    characteristic.descriptors = [descriptor]
    
    let serviceUUID = CBUUID(string: BLEIdentifiers.serviceIdentifier)
    let service = CBMutableService(type: serviceUUID, primary: true)
    
    service.characteristics = [characteristic]
    manager.add(service)
}

Writing data to Peripheral in Central

func writeDataToPeripheral(data: Data){
     if let characteristics =  ctService?.characteristics {
         for characteristic in characteristics {
             if characteristic.uuid == CBUUID(string: BLEIdentifiers.characteristicIdentifier) {
                 if characteristic.properties.contains(.write) {
                    connectedPeripheral?.writeValue(data, for: characteristic, type: .withResponse)
                 }
             }
         }
     }
 }

func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
         guard error == nil else {
            print("Error discovering didWriteValueFor: error", error.debugDescription)
            //Getting Error Domain=CBATTErrorDomain Code=6 "The request is not supported."
             return
         }
         print("Message sent")
     }

func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    if let error = error {
        print("peripheral failed to discover services: \(error.localizedDescription)")
    } else {
        peripheral.services?.forEach({ (service) in
            print("service discovered: \(service)")
            peripheral.discoverCharacteristics([CBUUID(string: BLEIdentifiers.characteristicIdentifier)], for: service)
        })
    }
}

func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    if let error = error {
        print("NSA A peripheral failed to discover characteristics: \(error.localizedDescription)")
    } else {
        ctService = service
        service.characteristics?.forEach({ (characteristic) in
            print("NSA A characteristic discovered: \(characteristic)")
            if characteristic.uuid == CBUUID(string: BLEIdentifiers.characteristicIdentifier)  {
                // keep a reference to this characteristic so we can write to it
                writeCharacteristic = characteristic
            }
            if characteristic.properties.contains(.read) {
                peripheral.readValue(for: characteristic)
            }
            peripheral.discoverDescriptors(for: characteristic)
        })
    }
}
Ahil
  • 57
  • 2
  • 11
  • Check the properties of the characteristic to confirm that writing with response is supported. It may only support writing without a response. – Paulw11 Aug 30 '20 at 07:03
  • @Paulw11 Thanks for the reply. I am already setting permission and properties to write. characteristic = CBMutableCharacteristic(type: characteristicUUID, properties: [.read, .write], value: nil, permissions: [.readable,.writeable]). Still why i am getting request is not supported error. can you please help? – Ahil Aug 30 '20 at 07:59
  • Because you have made it write, not write with response and you are trying to write with response. – Paulw11 Aug 30 '20 at 08:25
  • @Paulw11 Yes but there is no "write with response" available in CBCharacteristicProperties struct. Only write and writeWithoutResponse is available related to writing properties. Then how can we achieve write with response? – Ahil Aug 30 '20 at 08:44
  • Pleas [edit] your question to show the code where you set up and publish your service – Paulw11 Aug 30 '20 at 08:47
  • The characteristic setup is fine, and write with response should be enabled. However, I don't see where you go through the process of service/characteristic discovery? CoreBluetooth requires that you first discover the characteristic you want to write to, you cannot just use an ID, even if you know it upfront. – Adis Aug 30 '20 at 08:48
  • @Paulw11 Updated the code.Can you please check now? – Ahil Aug 30 '20 at 09:09
  • @Adis I Updated the code. I am getting ctService in didDiscoverCharacteristicsFor service and writing value in Connected Peripheral.can you please check what i am doing wrong? – Ahil Aug 30 '20 at 09:13
  • Why don't you use your `writeCharacteristic` property in `writeDataToPeripheral`? – Paulw11 Aug 30 '20 at 09:55
  • @Paulw11 Thanks for helping out me. I tried that also. if writeCharacteristic.properties.contains(.write) { connectedPeripheral?.writeValue(data, for: writeCharacteristic, type: .withResponse) } Still cannot be able to write – Ahil Aug 30 '20 at 10:33
  • What if you try without the `.withResponse`? – Paulw11 Aug 30 '20 at 10:34
  • @Paulw11 If i use .withoutResponse i am not getting any error. But i am not sure write is successfull or failure. connectedPeripheral?.writeValue(data, for: writeCharacteristic, type: .withoutResponse) – Ahil Aug 30 '20 at 10:39
  • Well, from your code it seems that the peripheral is set up to support write with response, but based on the error you are getting that isn't the case. What if you make seperate read and write characteristics rather than a single read/write characteristic? – Paulw11 Aug 30 '20 at 10:47
  • @Paulw11 Sorry I didn't understand what you mean? Can you please help on this? – Ahil Aug 30 '20 at 10:53
  • I think I see the problem. Have you implemented [`didRecieveWrite`](https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393315-peripheralmanager) in your peripheral manager delegate? – Paulw11 Aug 30 '20 at 10:58
  • @Paulw11 Yes!!! Finally found the problem. Thanks a lot for helping me. Have a nice days :D – Ahil Aug 30 '20 at 11:18

1 Answers1

2

In order to support writes, you must implement the didReceiveWrite method in your CBPeripheralManagerDelegate.

Since you don't have this method, you get a "not supported" response to your write request.

Paulw11
  • 108,386
  • 14
  • 159
  • 186