0

I'm trying to implement an app for transfer some strings between ble devices (for now one device act as central and the other one as pheripheral) but without success.

This is how my peripheral (server) is set up. Characteristic build

fun buildCharacteristic(
    characteristicUUID: UUID,
): BluetoothGattCharacteristic {

    var properties = BluetoothGattCharacteristic.PROPERTY_READ or
                     BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE or 
                     BluetoothGattCharacteristic.PROPERTY_NOTIFY

    var permission = BluetoothGattCharacteristic.PERMISSION_READ or
                     BluetoothGattCharacteristic.PERMISSION_WRITE

    var characteristic = BluetoothGattCharacteristic(
                             characteristicUUID, 
                             properties, 
                             permission
                         )

    return characteristic

}

service build

fun buildService(
    serviceUUID: UUID,
    serviceType: Int,
    characteristics: List<BluetoothGattCharacteristic>
) {
    bluetoothGattService = BluetoothGattService(
                               serviceUUID, 
                               BluetoothGattService.SERVICE_TYPE_PRIMARY
                           )
    for (characteristic in characteristics) {
        bluetoothGattService.addCharacteristic(characteristic)
    }
}

and this is how i start ble server (i omit implementation of callbacks)

 fun startServer(
    bleAdapter: BluetoothAdapter,
    btManager: BluetoothManager,
    context: Context
) {
    bleAdvertiser = bleAdapter.bluetoothLeAdvertiser

    bleGattServer = btManager.openGattServer(context, gattServerCallback)
    bleGattServer.addService(bluetoothGattService)

    var settings = AdvertiseSettings.Builder().apply {
            setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
            setConnectable(true)
            setTimeout(0)
            setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH)
        }

    var data = AdvertiseData.Builder().apply {
            setIncludeDeviceName(true)
    }

    bleAdvertiser.startAdvertising(settings.build(), data.build(), advertiseCallback)
}

On central (client) side, when onScanResult is triggered, i try to connect with device:

fun connectToDevice(device: BluetoothDevice) {
    device.connectGatt(
        context,
        false,
        createGattCallback()
    )
}

where createGattCallback() is a function return a BluetoothGattCallback object. Inside this callback, when onConnectionStateChange is called, i call service discover, and when service is discovered i try do write data to peripheral

override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
    super.onServicesDiscovered(gatt, status)
    if (gatt?.services != null) {
        var serviceFound = false
        for (service in gatt.services) {
            if (service.uuid == Consts.SERVICE_UUID) {
                serviceFound = true
                var bluetoothGattCharacteristic =    service.getCharacteristic(Consts.CHARACTERISTIC_UUID)

                writeCharacteristic(
                    gatt, 
                    bluetoothGattCharacteristic
                )

             }
         }
         if (!serviceFound) {
             gatt.disconnect()
         }
     }
}


fun writeCharacteristic(
    gatt: BluetoothGatt, 
    characteristic: BluetoothGattCharacteristic
) {

    var toSendString = "A random string for testing purpose only"
    var toSendByteArray = toSendString.toByteArray(Charsets.UTF_8)

    val chunkSize = 18
    val numberOfPackets = ceil(
        (toSendByteArray.size).toDouble() / chunkSize.toDouble()
    )

    for (i in 0 until numberOfPackets.toInt()) {
        var startIndex = i * chunkSize
        var endIndex = if (startIndex + chunkSize <= toSendByteArray.size) {
            startIndex + chunkSize
        } else {
            toSendByteArray.size
        }

        var packet = toSendByteArray.copyOfRange(startIndex, endIndex)
        characteristic.value = packet
        gatt.writeCharacteristic(characteristic)
        Thread.sleep(250)
    }
}

My code seems not workin, on peripheral i don't receive entire string, but only the first 18 bytes. Where i'm wrong?

giozh
  • 9,868
  • 30
  • 102
  • 183

1 Answers1

0

You need to wait for onCharacteristicWrite before you can send the next value. See Android BLE BluetoothGatt.writeDescriptor() return sometimes false. And your sleep won't solve anything.

Emil
  • 16,784
  • 2
  • 41
  • 52
  • Yes, after a night of tests (and coffee) i've noticed that :D so when central onCharacteristicWrite is triggered, i send next packet – giozh Aug 28 '19 at 08:13