I have a question about android 4.4 Bluetooth Low Energy.
I have a BLE dongle with UART Rx pin. I can send bytes data from Rx-pin to BLE dongle, and BLE dongle will send the data to bluetooth host device by indication.
So I have a Rx characteristic value it's property is indication.
I send about 80 bytes data to Rx characteristic, but i only get 20 bytes by once callback function onCharacteristicChanged.
But I use iPad mini to indicate this characteristic value, it receives 4 packets one of 20 bytes data and it seems right.
How can I do to receive 80 bytes data like iOS in Android callback function ?
Try negotiating a bigger GATT MTU. The default is 23 bytes.
The (G)ATT protocol takes up 3 bytes for the header per Notification / Indication.
So 20 - 3 = 20 bytes left by default.
On iOS 8, the maximum MTU that iOS will allow is 158 bytes.
I'm not sure about what Android allows.
I had exactly the same problem - 20 bytes it is a limitation applied to both indications and notifications. It is defined in the Spec, however I am yet to find it.
If your characteristic is not using either indications or notifications then this constraint doesn't apply and all your data will be sent in chunks of MTU-5 see section section 3.4.6.1 of the BT4.0 spec.
The data is sent in chunks of 20 bytes each. So if you want to receive all 80 bytes, then divide the data in 20 byte chunks and send it in a loop. Refer to Android: Sending data >20 bytes by BLE for clarification.
Remember to add Thread.sleep(200) in the loop so that the characteristic is not overwritten.
Related
I understand that in Android, the MTU for writing data to a Characterisitc is around 23 bytes (3 bytes used so you have around 20 bytes free) and that you can request a higher MTU (up to 512) to allow you to write/send larger data packets to a bluetooth device.
However, do you also need to do this when reading data from a characterisitic?
Both Reading and Notification updates?
If say, I have a characteristic that sends data in 123 byte chunks, but I only ever have to send at most 2 bytes to it, do I need to negotiate a large MTU?
I can recommend you to read the ATT and GATT chapters in the Bluetooth Core standard. Those explain the protocol.
By default Android does not negotiate a larger MTU than the default (23 bytes). You can do that yourself though by calling the requestMtu function.
Android automatically under the hood uses "Write Long Characteristic Values" and "Read Long Characteristic Values" when the MTU is not big enough when reading/writing values in order to transfer the whole value. However these procedures are very inefficient since they require multiple roundtrips. The read operation also is not atomic.
Notifications and Indications don't have any "Long" variant with multiple roundtrips, so these will be truncated to fit the MTU.
We have some android devices which have BT stack 4.0 and 4.1. As per theory, 4.0 and 4.1 support data transfer of only 23 (20 +3) bytes. While BT stack 4.2 and 5.0 support data transfer upto 251 bytes MTU.
But in our app, we requested MTU size of 64 bytes and its working fine. We are able to send and receive data of this size. We are able to send 500-700 packets continuously of 64 bytes.
Does any body has idea why it is working differently? or is it just a few android devices which are working this way?
We want to eliminate devices which won't support our application.
You are confused with the terms here. Per the spec all BLE versions since Bluetooth 4.0 have maximum possible MTU of 64 kilobyte, even though Android limits it to 517 for GATT.
The new feature that was added in BLE 4.2 was the "LE Data Packet Length Extension" which is an enhancement of the Link Layer that increases the maximum packet length over the air from 27 bytes to 251 bytes that does not affect the host layer in any way. If the host sends a packet that is bigger than what the link layer can handle, it is automatically fragmented by the sender stack and reassembled at the receiver.
So your Android app will work the same regardless of the link layer capabilities. The only concern you should have is whether the remote application supports your desired MTU of 64.
UPDATE
Bluetooth Core v4.0 specification Volume 6 Part B section 2.4:
The LLID field has two different values for start and continuation fragment.
10b = LL Data PDU: Start of an L2CAP message or a complete L2CAP message with no fragmentation.
01b = LL Data PDU: Continuation fragment of an L2CAP message, or an Empty PDU.
The feature of continuing an earlier packet is important when the host packet is larger than the link layer can handle (normally 27 or 251 bytes with LE Data Length Extension). That is how you can get an MTU of for example 517 when the packets over the air are never longer than 27 bytes.
See Bluetooth Core specification Volume 3 Part A section 7.2 for more info about L2CAP fragmentation and recombination.
I am trying to write a 120 byte data through ble to raspberrypi from my android app(I increased the MTU to the required limit). But all I am able to transfer is first 20 bytes. When I tried to search on the internet, I see that android limits the size to 20 byte for ble transfers and I will have to send multiple 20 byte packets.
But why I tried to end the same data from nrfConnect android app, I see that the data is being transferred without any issue. Can you help me understand how nrfConnect is able to do it with you writing it as packets?
Through the data is getting truncated, i am getting GATT_SUCCESS response from raspberrypi
Just as info, I am able to send 52 bytes to our custom board with nrf52 chip from the same app
Looks like android takes care of writing more than 20 bytes of data.
Below are the two cases that I had:
Case 1:
Android app trying to write data to custom program running in nrf52 chip.
Size of data : 50 bytes.
After increase the BLE MTU on the chip side, the write was successful without any changes from app side.(gatt.writeCharacteristic(characteristic))
Case 2:
Android app trying to write data to ble program running in raspberrypi 3
Size of data 120 bytes.
Issue:Even after increasing the BLE MTU in raspberry pi, when trying to write the data only 20 bytes are received, with successful write response.
Solution: After using gatt.requestMtu(120) and calling the write character in onMtuChanged() callback, was able to send the entire data.
If I want to transfer a lot of data (e.g. 1 MB file) over BLE, what's the best way to do it?
I control both sides of the connection, but the client side is iOS/Android so only has access to GATT. I can't do anything with L2CAP.
I also can't wait for Bluetooth 4.1, 6LoWPAN, Connection-Oriented-Channels or anything like that.
I would assume the answer is to have one "request" characteristic that you write a data request to ("Give me 3000 bytes starting at byte 0"), and a "data out" characteristic that sends lots of 20 byte notifications (the maximum characteristic size) containing the data.
Is there a better way?
Yes we are using the approach you have mentioned.
Request data with the last index number(First time the index is 0)
The server send you with data with index no.Store the index no for subsequent format
continue Step 1 and 2 till the time server sends end of data-probably with index -1 or something.
Make sure you transfer the data you required in the most space efficient format.See if you can zip the files and transfer it.
You can update connection interval to small value with smallest 6*1.25 ms in remote BLE device.
Actually, BLE is designed for Low energy, small packet, low data rate.
L2cap data will be transmitted in different data channel with frequency hop. Packets TX/RX happen within each connection interval and max number of packets TX/RX in an event is restricted by specification, finally implemented by manufacture. So we can change connection interval as small as possible to increase data rate.
Refer BT 4.0 spec Vol 2, 7.8.18 LE Connection Update Command.
Try to negotiate a larger MTU than the default.
Then each notification can be larger. Even though it will be fragmented by the L2CAP layer, you will get a slightly larger throughput since the packet header will be smaller.
I'm working on an Android Bluetooth project to send and receive data from a custom made hardware. I used Bluetooth Chat Sample in SDK as basis.
I am sending data from one device to another (LG Nexus 4). All is ok until I reach a length of 1004 bytes (it is the audio data). At that point it splits it into 2 messages of 990 and 14 bytes in most of cases. but is strange sometimes its sending 1004 without splitting (approx. 4 times in 100).
I am sending this packet of 1004 bytes, in which there is 4 bytes is my header and rest of 1000 bytes is actual data which I want to use as per command in header, now if packets are splitting as per above mentioned way than I cannot handle the flow.
So, please let me know why packets are splitting in such way and how can I stop this splitting or, if I cannot do this, than please suggest me any alternative way to do this.
Thanks.
Data sent via Bluetooth socket is abstracted as a stream. Here the transport layer is broken into packets, where packet has a maximum size of almost 1KB(1000 bytes). So you can devise a mechanism in which you can send the message length info in the header, then on receiving side you will have to make subsequent read() calls; each returning data for one packet.