0

I am trying to send data (image) between 2 devices (both iPhones). This code is for the CBPeripheralManager that advertises:

func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {

    switch peripheral.state {
    case .unknown:
        print("central.state is .unknown")
    case .resetting:
        print("central.state is .resetting")
    case .unsupported:
        print("central.state is .unsupported")
    case .unauthorized:
        print("central.state is .unauthorized")
    case .poweredOff:
        print("central.state is .poweredOff")
    case .poweredOn:
        print("central.state is .poweredOn")
      updateAdvertisingData()
    }
}

func updateAdvertisingData() {

    if (cameraPeripheralManager.isAdvertising) {
        cameraPeripheralManager.stopAdvertising()
    }
    let advertisementData = String(format: "%@", "advertisementData")

            char = CBMutableCharacteristic(type: CHAR_UUID, properties: [.notify], value: nil, permissions: [.readable])
            myRoei = CBMutableService(type: RX_UUID, primary: true)
            myRoei.characteristics = [char]
            cameraPeripheralManager.add(myRoei)
            cameraPeripheralManager.startAdvertising([CBAdvertisementDataServiceUUIDsKey:[RX_UUID], CBAdvertisementDataLocalNameKey: advertisementData])
}
   func peripheralManager(_ peripheral: CBPeripheralManager, central: CBCentral, didSubscribeTo characteristic: CBCharacteristic) {
    print("didSubscribeTo")
            if let img = UIImage(named: "maiden") {
                let data = UIImagePNGRepresentation(img)
            self.sendData(data: data!)
            }
}

func sendData(data: Data){

    data.withUnsafeBytes { (u8Ptr: UnsafePointer<UInt8>) in
        let mutRawPointer = UnsafeMutableRawPointer(mutating: u8Ptr)
        let uploadChunkSize = 20
        let totalSize = data.count
        var offset = 0
        while offset < totalSize {
            let chunkSize = offset + uploadChunkSize > totalSize ? totalSize - offset : uploadChunkSize
            let chunk = Data(bytesNoCopy: mutRawPointer+offset, count: chunkSize, deallocator: Data.Deallocator.none)
            offset += chunkSize
            print("The offset is: + \(offset)")
            print("Total size is: + \(totalSize)")
           cameraPeripheralManager.updateValue(chunk, for: char, onSubscribedCentrals: nil)
        }
    }
}

In the CBCentralManager I am using didUpdateValueFor characteristic and the it is always nil.

func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    print(characteristic.value as Any)
    switch characteristic.uuid {
    case CHAR_UUID:
        print("Char value: \(String(describing: characteristic.value))")
    case RX_UUID: break
    //
    default:
        print("Unhandled Characteristic UUID: \(characteristic.uuid)")
    }
}

What am I doing wrong?

ironRoei
  • 2,049
  • 24
  • 45
  • First of all..BLE -> by meaning it is low energy bluetooth and by documentation( it depends on your characteristic, but mostly) it is only 20 bytes array. So to send image over BLE will take time..and nobody suggests to send image over BLE. But I am not saying that it's impossible...but look at OTA data transfer example, make CRC for your chuck. peripheral.writeValue instead of update should be use: let data: NSData = "5213005".dataUsingEncoding(NSUTF8StringEncoding)! peripheral.writeValue(data, forCharacteristic: characteristicx, type: CBCharacteristicWriteType.WithoutResponse) – Jevgenij Kononov Mar 26 '18 at 08:11
  • In your case cameraPeripheralManager.writeValue(..your code..) CRC will check that your chunk is correct, otherwise you are in danger of miss sending your data...BLE really sensitive.. – Jevgenij Kononov Mar 26 '18 at 08:13
  • @JevgenijKononov thanks for the response! Yes i know that BLE not meant to do so yet i wanna check how long it will take to transfer image. I didnt understand your suggestion. First of all the cameraPeripheralManager dosent have a writeValue method. Second how i control the chunks of data? – ironRoei Mar 26 '18 at 08:26
  • Well I suppose that you are using wrong IOS library, check this out: https://developer.apple.com/documentation/corebluetooth/cbperipheral . You need discover your BLE device, then connect, then go through all services then choise characteristic and fire your data to that characteristic. It sound like a pain but it is not it is quite straight forward. – Jevgenij Kononov Mar 26 '18 at 08:35
  • To control chucks, write and check -> response or notify your sending device that send data was correctly acknowledged. Something like: Characteristic maximum payload 20bytes: so use 18 bytes for your data and 2 for CRC16 check. So 18+2 = 20 bytes. Where 18 is your data and 2 crc data. And then you received data on the second device you have 20 bytes array, divide for 2 parts again 18 and 2 -> check crc16 of 18 and compare with 2 part – Jevgenij Kononov Mar 26 '18 at 08:39
  • That for your crc16 example. The best website for checking crc16. https://www.lammertbies.nl/comm/info/crc-calculation.html You need to create that crc16 function by your self or try to find implementation on stack. – Jevgenij Kononov Mar 26 '18 at 08:43
  • @JevgenijKononov i am using the right library. i think you misunderstood my question. I am talking about the advertising side. There is a big difference between peripheralManager and CBPeripheral. – ironRoei Mar 26 '18 at 08:48
  • What kind of device you would like to use for advertising side? Iphone or another BLE device like ble121lr? – Jevgenij Kononov Mar 26 '18 at 08:52
  • i am using iphone. ass you can see in the code above ,it advertises ok and i connect it from the other device, the only problem is the update value method – ironRoei Mar 26 '18 at 08:56
  • By Idea...you should have gatt file for your device(BLE device in which you describe your characteristic behavior. something like that.. Battery status ABCD and then on that BLE local device you can update by special attribute write command – Jevgenij Kononov Mar 26 '18 at 08:57
  • myCharacteristic = [[CBMutableCharacteristic alloc] initWithType:myCharacteristicUUID properties:CBCharacteristicPropertyRead | CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable]; add flag write. that probably will solve your problem. Do not forget about permission flag write – Jevgenij Kononov Mar 26 '18 at 09:00
  • check this out: https://developer.apple.com/library/content/documentation/NetworkingInternetWeb/Conceptual/CoreBluetooth_concepts/BestPracticesForSettingUpYourIOSDeviceAsAPeripheral/BestPracticesForSettingUpYourIOSDeviceAsAPeripheral.html#//apple_ref/doc/uid/TP40013257-CH5-SW1 – Jevgenij Kononov Mar 26 '18 at 09:02
  • @JevgenijKononov did it already: char = CBMutableCharacteristic(type: CHAR_UUID, properties: [.notify], value: nil, permissions: [.readable]) See my code – ironRoei Mar 26 '18 at 09:13
  • But you haven't put write flag. Notify that another thing, it is background task which notify device B about changes in Device A characteristic. So try set write flag – Jevgenij Kononov Mar 26 '18 at 09:46
  • https://www.cloudcity.io/blog/2016/09/14/zero-to-ble-on-ios--part-three/ – Jevgenij Kononov Mar 26 '18 at 09:51
  • @JevgenijKononov again you are wrong. the notify flag should do that and the article is about peripheralManager and not about peripheral. – ironRoei Mar 26 '18 at 09:57
  • I am not saying that I am right:) I just tried help. That is what you looking for. https://github.com/0x7fffffff/Core-Bluetooth-Transfer-Demo/blob/master/Bluetooth/BTLEPeripheralViewController.swift – Jevgenij Kononov Mar 26 '18 at 10:34
  • @JevgenijKononov it is all good man :) so what you gave me is ok but my problem is with notify... i mange to update the value just the first time – ironRoei Mar 26 '18 at 11:00

0 Answers0