简体   繁体   中英

xamarin bluetooth data receive delay

I have my xamarin app running on android. It connects to a custom device through bluetooth using SPP. The App issues commands and the device responds with about 260 bytes.

My problem is that there appears to be a large delay between data being sent by the device and that data being available to my app through the socket. This results in the throughput of the connection being very low.

Scope image here: https://imgur.com/a/gBPaWHJ

In the image, the yellow trace is the data being sent to the device, the blue is the response. As you can see, the device responds immediately after the command is sent. I have measured the peroid from the start of a command to the end of the response to be 12ms.

In the code, I measured the time between the app receiving the last byte of a response to the the sending of the next command. The time was always 0 or 1ms. This is not what the scope is telling me, there is a clear 92ms period between the end of a response and the sending of the next command.

I also measured the time between the line of code that sends data, and the first byte of the response being received, it always takes 50 to 80ms. This here is the problem.

I have been through my code and there are no delays or timers that prevent a command being sent. If it has received a full resonse, it will send a request for data straight away.

I have a System.Threading.Thread which loops around handling the sending and receiving of data. I have timed this loop and it always takes less than 3ms to complete (mostly it is 0ms). This shows there is no delay in my loop causing this. I wouldnt expect any delay as we're only talking about 260 bytes of data to read and process.

Is there something in Xamarin Android that might cause a delay between data arriving at the tablet over bluetooth and data being available to my app. Perhaps something is only updating the BluetoothSocket every 100ms? I want those empty gaps on my scope to be gone.

In general, the factors that affect Bluetooth transmission are as follows: Connection Interval / number of frames sent per Connection Event / length of each frame of data , and an operation type (not considered at this time).

According to the optimal value supported by the Android protocol, you can set the Connection Interval to 7.5ms , and the data size of each frame is 20 bytes .

If you need to send 260 bytes of data, then the time required for the calculation is 97.5ms . Sometimes it may involve fluctuations in the stability of the Bluetooth connection, which takes about 100ms .

  1. why is it limited to 20 bytes?

The core spec defines the default MTU of the ATT to be 23 bytes. After removing one byte of the ATT opcode and the ATT handle2 bytes, the remaining 20 bytes are reserved for the GATT. Considering that some Bluetooth smart devices are weak and don't dare to use memory space too much, the core spec requires that each device must support an MTU of 23. At the beginning of the connection between the two devices, everyone is like a new friend, I don't know the other party's fine, so strictly follow the routine, that is, send up to 20 bytes at a time, which is the most insurance.

  1. How to break through 20?

Since the maximum length of the ATT is 512 bytes, it is sufficient to change the MTU of the transmitted ATT. On Android (API 21), the interface for changing the ATT MTU is:

public boolean requestMtu (int mtu)
#Added in API level 21
#Request an MTU size used for a given connection.
#When performing a write request operation (write without response), the data sent is truncated to the MTU size. This function may be used to request a larger MTU size to be able to send more data at once.
#A onMtuChanged(BluetoothGatt, int, int) callback will indicate whether this operation was successful.
#Requires BLUETOOTH permission.
#Returns true, if the new MTU value has been requested successfully

If your peripheral application changes the MTU and succeeds, then this callback will also be called.

@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
    super.onMtuChanged(gatt, mtu, status);

    if (status == BluetoothGatt.GATT_SUCCESS) {
        this.supportedMTU = mtu;//local var to record MTU size
    }
}

After that, you can happily send the length of the supportedMTU data.

So this is actually not related to xamarin, this is just a limitation imposed by Android.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM