I am able to send data upto 20 bytes by connecting to an external BLE device. How do I send data greater than 20 bytes. I have read that we have to either fragment the data or split characteristic to required parts. If I assume my data is 32 bytes, could you tell me changes I need to make in my code to get this working? Following are the required snippets from my code:
public boolean send(byte[] data) {
if (mBluetoothGatt == null || mBluetoothGattService == null) {
Log.w(TAG, "BluetoothGatt not initialized");
return false;
}
BluetoothGattCharacteristic characteristic =
mBluetoothGattService.getCharacteristic(UUID_SEND);
if (characteristic == null) {
Log.w(TAG, "Send characteristic not found");
return false;
}
characteristic.setValue(data);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
return mBluetoothGatt.writeCharacteristic(characteristic);
}
This is the code I used for sending the data. The "send" function is used in the following onclick event.
sendValueButton = (Button) findViewById(R.id.sendValue);
sendValueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = dataEdit.getText().toString();
yableeService.send(text.getBytes());
}
});
When the String text
is greater than 20 bytes then only the first 20 bytes are received. How to rectify this?
To test sending multiple characteristics I tried this:
sendValueButton = (Button) findViewById(R.id.sendValue);
sendValueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = "Test1";
yableeService.send(text.getBytes());
text = "Test2";
yableeService.send(text.getBytes());
text = "Test3";
yableeService.send(text.getBytes());
}
});
But I only received "Test3" i.e. the last characteristic. What mistake did I commit? I am new to BLE so please ignore any naiveness
Edit:
After accepting answer for anyone who views this later.
There are two ways to accomplish this.
1. Split up your data and write in a loop as the selected answer does.
2. Split up your data and write using callback i.e. onCharacterisitcWrite()
. This will save you from errors if there were any during writing.
But most important between the writes use a Thread.sleep(200)
if you are only writing and not waiting for a response from the firmware. This will ensure that all of your data reaches. Without the sleep
I was always getting the last packet. If you notice the accepted answer he has also used sleep
in between.
You are correct that the BLE specification doesn't allow write operations to exceed 20 bytes. If you can't subdivide your payload over multiple characteristics (which is logically going to be easier to maintain), then your chunking mechanism is the other approach.
However, realize that the BLE stack hates when you try to queue up multiple operations. Each read/write is asynchronous, which the result coming via the
onCharacteristicRead()
oronCharacteristicWrite()
callback on theBluetoothGattCallback
instance. The code you've written attempts to send three characteristic write operations on top of each other, without waiting for the callback in between. Your code will need to follow a path more like:You need to request a MTU update. This is the maximum transmission unit. As it is now, BLE accepts up to 512 bytes in a single packet. However, without requesting this MTU update, your device will not send a packet over 23 bytes (currently).
Using your BluetoothGatt object call requestMtu()
Here is a link to the developer's page
BluetoothGattCallback will receive the onMtuChanged() event as shown below. Upon a successful MTU update, you can send the data as one packet. Here is a link to this developer page.
I typically call requestMtu() after connecting to the characteristic that I wish to write to. Good Luck.
This is the example of implementation using chunk method, but without using Thread.sleep , i found it is better and efficient for my application to send more than 20 bit data.
The packets will be send after
onCharacteristicWrite()
triggered. i just found out this method will be triggered automatically after peripheral device(BluetoothGattServer)
sends asendResponse()
method.firstly we have to transform the packet data into chunk with this function:
after our data ready, so i put my iteration on this function:
BLE allow you transfer maximum is 20 bytes.
If you want send more 20 bytes, you should define array byte[] include how many packet you want.
Example worked fine if you want send < 160 characters (160 bytes).
p/s : Let edit followed as u want. Not followed me exactly.
Actually, when we are using BLE, mobile side and firmware side need set up the Key (ex. 0x03 ...) to define the connection gate among both sides.
The idea is :
When we still continue transfer packets, not is the last one. The gate is
byte[1] = 0x01
.If we send the last one, The gate is
byte[1] = 0x00
.The data contruction (20 bytes):
1 -
Byte 1
- Define theGate ID
: ex. Message gate IDbyte[0] = 0x03
.2 -
Byte 2
- Define therecognization
: Is the last packet0x00
or continue sending packets0x01
.3 -
Byte 3
(Should be 18 bytes after minusByte 1
&Byte 2
) - Attach the message content in here.Should understand my logic before reading the code in below please.
Below is example about send Message with many packets, each packet : byte[20].
You can actually trigger a BLE Long write if the device on the other end supports it.
You can do this by setting the write type to be BluetoothGattCharacteristic.WRITE_TYPE_DEFAULT
In this case you can send more than 20 bytes.
If you want to send large sets of data over BLE, then your best bet is to use two characteristics, one to send the bulk of your data and the other to send the last segment. This way you don't need to set the response to WRITE_NO_RESPONSE and use the callback to send the next segment all the way until you get to the last segment, at which point you will write that to the second characteristic which will let the device know that you are done writing the data and that it can concatenate all the data together to form one large data packet.