1

I am working on transmitting the contents of a byte array from an Android mobile app to an MCU. I am able to successfully transfer the data byte by byte (multiple packets) but I am unable to successfully send the array as a whole (as one packet). It should be noted that the data will be transmitted via a GATT profile and that the array is successfully passed to this portion of the code.

    public void writeCustomUsernameCharacteristic(byte[] byteArray) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("00002a37-0000-1000-8000-00805f9b34fb"));

        if (mCustomService == null) {
            Log.w(TAG, "Custom BLE Service not found");
            return;
        }
        mBluetoothGatt.requestMtu(244); 

        for (int i = 0; i < credentials.length; i++) {
            individualBytes = byteArray[i];

            BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb")); 
            mWriteCharacteristic.setValue(individualBytes, BluetoothGattCharacteristic.FORMAT_UINT8, 0);  
            mBluetoothGatt.writeCharacteristic(mWriteCharacteristic);

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                System.out.println("got interrupted!");
            }
            if (mBluetoothGatt.writeCharacteristic(mWriteCharacteristic) == false) {
                Log.w(TAG, "Failed to write characteristic");
            }
        }
    }

However, if I try to set the value to the byte array itself I am unable to send the information. It should be noted that there are no errors being reported on the app side and the MCU side isn't reporting any packets being received.

public void writeCustomUsernameCharacteristic(byte[] byteArray) {
        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(TAG, "BluetoothAdapter not initialized");
            return;
        }
        BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("4880c12c-fdcb-4077-8920-a450d7f9b907"));

        if (mCustomService == null) {
            Log.w(TAG, "Custom BLE Service not found");
            return;
        }
        mBluetoothGatt.requestMtu(244);

        BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString("fec26ec4-6d71-4442-9f81-55bc21d658d6"));
        mWriteCharacteristic.setValue(byteArray);
        mWriteCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
        mBluetoothGatt.writeCharacteristic(mWriteCharacteristic);
    }

Could anyone provide on any suggestions on how to transmit this byte array in on packet? Thanks in advance.

In response to the possible duplicate. It appears that the link is referencing code I have already attempted in the second block. The problem is that the mBluetoothGatt.writeCharacteristic(mWriteCharacteristic); is not sending the packets to the MCU.

public void writeCustomUsernameCharacteristic(byte[] byteArray) {
            if (mBluetoothAdapter == null || mBluetoothGatt == null) {
                Log.w(TAG, "BluetoothAdapter not initialized");
                return;
            }
            BluetoothGattService mCustomService = mBluetoothGatt.getService(UUID.fromString("4880c12c-fdcb-4077-8920-a450d7f9b907"));

            if (mCustomService == null) {
                Log.w(TAG, "Custom BLE Service not found");
                return;
            }
            mBluetoothGatt.requestMtu(244);

            BluetoothGattCharacteristic mWriteCharacteristic = mCustomService.getCharacteristic(UUID.fromString("fec26ec4-6d71-4442-9f81-55bc21d658d6"));
            mWriteCharacteristic.setValue(byteArray);
            mWriteCharacteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT);
            mBluetoothGatt.writeCharacteristic(mWriteCharacteristic);

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                System.out.println("got interrupted!");
            }
  • 1
    Possible duplicate of [Android BLE, read and write characteristics](https://stackoverflow.com/questions/24008249/android-ble-read-and-write-characteristics) – Chisko Jul 03 '18 at 18:26
  • @Chisko I don't believe this is a duplicate as I am already implementing the gatt.writeCharacteristic() to no avail unless I missed something when examining the link. Was there something in particular that you were referencing? – LostandConfused Jul 03 '18 at 18:57

2 Answers2

1

You can only have one outstanding GATT request at a time. You need to wait for the onMtuChanged callback before you can perform a write. Then you need to wait for the onCharacteristicWrite callback before you perform another write.

See my answer at Android BLE BluetoothGatt.writeDescriptor() return sometimes false for a more thorough explanation.

Emil
  • 16,784
  • 2
  • 41
  • 52
  • Although this seems to be something that I should account for in my code I'm not sure as to whether or not this is the actual issue that is preventing my code from sending the information as a single packet. I believe this due to the fact that I have verified that the MTU has successfully changed and I have been able to successfully transmit the data as multiple packets. Any idea why it wouldn't be able to send the data as a single packet? – LostandConfused Jul 09 '18 at 12:11
  • Can you please update your question so that the code follows the requirements I mentioned? – Emil Jul 09 '18 at 13:56
  • Sorry I have a pretty busy schedule today/tomorrow and will update my code when I have time. However, it appears that even if I remove requestMtu(244) and account for it on the MCU side that I am still unable to write the byteArray to the characeristic unless it is the individual elements. Do you still believe that the only error is that the GATT server is still processing another task? Thanks for the help and I'll add the wait functionality as soon as possible – LostandConfused Jul 09 '18 at 20:27
  • What is the length of the byte array you try to write? – Emil Jul 09 '18 at 21:56
  • I was able to fix the issue (see above). Thank you for all of your help! – LostandConfused Jul 10 '18 at 12:58
  • Adding a delay as the last thing in the code shouldn't solve anything. And using delays between gatt operations instead of properly waiting for the callback is also a bad idea since you can't know how long time it will take for the operation to complete. For example, if the BLE link quality is bad the packet will take longer to send. – Emil Jul 10 '18 at 13:48
0

If you can send byte by byte and the device accepts the MTU it is as simple as this:

mCustomService.writeCharacteristic(mWriteCharacteristic,byteArray );

or

mBluetoothGatt.writeCharacteristic(mWriteCharacteristic,byteArray);

To check if there is a MTU-size problem send a small (<20bytes) byte array.

GrooverFromHolland
  • 971
  • 1
  • 11
  • 18