I have been analizing the Bluetooth snoop file on several Android devices, where the Android device is the Central (Client) and the peer device is the Peripheral (Server).
When performing a Write Command (WC) (sending data from Android to Peripheral), besides the WC sent packet, wireshark identifies an HCI event labeled as Number of Completed Packets.
As HCI messages are exchanged between Host and Controller of the same device, do these events take up a packet slot on the Connection Interval(CI) ? Because while I'm able to send 3 packets/CI using Notifications, only 1 packets/CI is being sent when using Write Command.
You can send multiple Write Without Response packets (called Write Command on the ATT layer) in a single connection event. The bluetooth controller has a buffer where it enqueues outgoing packets (called ACL data packets). You can see the size of this queue in the snoop log by looking for LE Read Buffer Size. When bluetooth is started, the host reads this value will keep track of the currently available space in some counter variable. When it sends a packet to the device (for example a Write Command), the counter is decreased by one. When the host receives a Number of Completed Packets event (which means that the packet has been sent out over the air), it increases the counter. As long as this counter remains positive after you issue a Write Without Response, your GATT onCharacteristicWrite callback will be called so you can immediately enqueue another Write Without Response packet. When the next connection event occurs, it sends multiple packets that are enqueued.
If you still can't achieve throughput higher than one packet per connection event, make sure you have set up the characteristic to use the WRITE_TYPE_NO_RESPONSE.
Related
I am new to the BLE development. I want to send some large amount of data over a BLE connection with maximum throughput.
I have a GATT server, which is running on Linux, and a client which is running as an app on Android. I have created a custom characteristic with the maximum allowed size(512 bytes). I am requesting it from the app with a read operation. Every time I receive a call for reading on the server side I change it's value until I am finished with all the data(I know this isn't the best way but that's not the problem for now).
As for the connection parameters using android's requestConnectionPriority(CONNECTION_PRIORITY_HIGH) i can see that they are trying to negotiate a connection interval of 7.5ms but for some reason, it changes to 15ms and it remains there. Maybe my phone doesn't support it but I don't think so.
The next thing and the main problem is the MTU. Using hcidump, I can see that they are starting to negotiate the MTU as I can see an MTU Request from the client with a value of 517(by default) and a server Response with the same value. But when I trigger the data exchange I can see(using Wireshark) that the packets are containing only 32 bytes of payload. I don't know if it's a restriction with my Bluetooth adapter.
An MTU packet can consist of many radio packets and the 32byte radio packet payload is probably a restriction in your bluetooth adapter. No phone supports 7.5ms connection intervals at this point in time. You should also enable Data Length Extention if your phone and device supports it. This will allow you to transmit multiple MTUs throughout the connection event.
Which one is the actual confirmation callBack which tells that the data has been successfully delivered to the remote BLE Device from the Android Phone? onCharacteristicWrite() or onCharacteristicChanged() or something else.
The data I am writing is with the BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE.
When you use BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE there is no confirmation of successful delivery at all. When you get the onCharacteristicWrite callback it only means the packet has been buffered and the Bluetooth stack has place to accept another packet.
I have a question regarding the bluetooth LE protocol.
I have an Android Device and a peripheral device.
Looking at the transmission with a sniffer and wireshark there is +/- every 40ms an empty PDU message. As I understood the protocol this means the connection interval those device chose is 40ms.
For testing I am using a simple "UART" application where the android device enables the notification on an antribute of the peripheral device and gets notified whenever the attribute changes.
Now, if I "send" multiple 20 byte packets through this setup, wireshark shows me, that those value notifications are just about 7-10 ms apart. Each Notification contains 20 Bytes
Does that mean, that the connection interval does not apply for notifications and that each notification can hold max. 20 Bytes?
Thanks & Greetings!
There is one connection event per connection interval. In each connection event multiple packets can be sent directly after each other. When no side has anything left to send, the connection event is closed and next exchange will occur at the next connection interval point. So yes, many notifications can be sent in one connection interval.
I'm using VpnService to capture packets and after capturing them I want to send them to their destination. Now, the capturing aspect works. I got the protocol, Source IP / Destination IP and the Source Port / Destination Port from the packets.
I was thinking about creating a socket with these parameters. VpnService has actually a method protect() which protects the socket and the traffic will not be forwarded through VPN.
I don't have muche experience with sockets. But the other day I read a comment here saying I only send the actual data through the socket and not the IP or TCP header? But since TCP uses a 3-way-handshake (correct me if i'm wrong) the first packets wouldn't have any data, just a SYN - flag.
Does that mean this method doesn't work or can i send a packet with the header through the socket?
Yes, we can send data via sockets and dont have to worry about Transport-layer or IP layer headers. Depending upon the socket type (SOCK_STREAM or SOCK_DGRAM), the underlying layer (and the stack for behavior) adds TCP or UDP header on top of application data. Lastly, before sending it out, the IP layer would add IP header. But, if your design requires, you can always "encapsulate" your entire packet with IP/TCP/Data as a data and send it to the other end. When the other end receives the packet, the application layer would receive data which would actually be the original IP/TCP/Data.
Edit
You should explore 2 more questions: a) how would we maintain the packet boundary and (b) what about MTU size. The first one needs to be thought about since TCP does not bother about packet boundary, so it is possible that when you read data on the receiver, it would not start with the header -- one quick solution would be to check if you are hitting the header and then read the length of the packet and continue to read till you have read that much data. The second one is if your packet is already the size of MTU, then adding 2 additional headers would throw it beyond MTU and hence, would likely be fragmented. If you are worried about performance, then this may not be a good thing.
I am working on Android project which communicates over TCP/IP. Communication works on specific protocol - this protocol is message oriented.
android device sends message to server via socket
server sends answer message to android device
It is not problem but I have a few parlous questions.
I don't have any idea how to solve connection interrupts (wifi, edge, change wifi to edge over open socket, ...) and connection timeouts? If android device sends 1 message and in this moment are connection problems - then android device sends different message (other request) - it is guaranteed that answers will be delivered in correct sequence?
I tried set timeout for socket object but it didn't work. I dont know why but if I set timeout to 5 seconds and I turned off the server before I sent message - it took more than 5 second before she came exciption.
I didn't found any articles on internet about this problems.
Thank you very much.
For TCP sockets the way you can get timeouts is by using select() or poll(),in Android you have to use SocketChannel() (java.nio) class to deal with non-blocking sockets. They both can query a socket for a specific period (10 or 20 seconds for example) and can tell you if it is writeable (you can use send()) or readable (there is data to be read recv()). Also the select() command will tell you if the socket has an error, most probably a broken connection. When you get such an error (except an interrupted signal, this one should be ignored and reissue the select), all you can do is close the socket and reopen a new one with the server, there is no way, as far as I know, to recover a broken connection, although, if you've implemented in the protocol, you can resume where you left off when the socket was broken. I don't know how you've implemented the protocol, but most of them will required a positive ACK (acknowledge) from the receiver before going on with another message. Also, when establishing a connection the client should specified if it a brand new connection or a broken one and act accordingly.
The idea is:
The sender sends a header specifying the command to process and the length of the data it's going to send after the header, the receiver receives the header and the data, once it process it, it sends a response ACK packet to the sender with a positive value to acknowledge the message, optionally with some data in case it's necessary. If after a reasonable period of time you don't receive the ACK packet then you may resend the same data again until you receive the positive ACK.
There could be the situation where the client sends a message, the server receives it and processes it, but when the server sends the positive ACK packet the connections breaks and the client never receives the packet, so it will resend the same message again once the connections is reestablished. To avoid this situation, it's necessary to send a message ID (an int which increments for every message sent) in the header to identity it.
I know it sounds difficult and it's in fact. If the connection is on the same network (intranet) it works nicely but, when the communication is on the internet, you may face a lot of problems and situations which you can't control, so it's necessary a well defined protocol where you can recover from broken connections and the transactions/messages won't be duplicated.