hbldh / bleak

A cross platform Bluetooth Low Energy Client for Python using asyncio
MIT License
1.6k stars 280 forks source link

Set MTU Feature #168

Closed farzadpanahi closed 2 years ago

farzadpanahi commented 4 years ago

Question

I need to set the MTU manually for a connection. I was looking at the source code and did not see any implementation for that. Is this by design or it can be potentially added as a feature?

farzadpanahi commented 4 years ago

@hbldh if you can give me a hint where this possibly should be implemented I can go ahead and code it.

I am looking at this -> https://github.com/hadess/bluez/blob/master/doc/gatt-api.txt

My understanding is that we can negotiate MTU when calling ReadValue and WriteValue methods using the mtu in the "options"? Is this correct?

I can't find where you are sending "options" to dbus api.

dlech commented 4 years ago

Have you seen issue #97?

farzadpanahi commented 4 years ago

I have seen that. I thought it is related to Windows backend. Is it not?

hbldh commented 4 years ago

It is not possible in Windows, no. It might be possible in BlueZ according to that documentation you linked to.

I will not look at this in the foreseeable future I am afraid. I have no usecase for it though and no device to test it on and I am swamped with other (paid) work and cannot guarantee doing anything with this project for quite some time. I will still address PRs to develop branch occasionally, so if you desire these changes you have to do the legwork yourselves.

savar commented 3 years ago

One thing to mention: on Linux it won't be always using the max, so even if it is not doing anything on Windows (see the flutter_blue plugin) it makes sense to: 1) have a method to requestMtu which is simply ignored on windows (which is fine, because requesting is not equal getting so no one can expect it to be X .. you can ask for X but it will probably Y anyways) 2) having a way to get the actual MTU to know what size of packets we can send

hbldh commented 3 years ago

@savar The BlueZ MTU handling has been implemented in the feature/linux-mtu branch if you want to test it out. You specify your desired mtu in read, write and notify methods. You can send that in on Windows as well and it will be ignored.

There is no way of getting current MTU value from any API, so that will not be available.

dlech commented 3 years ago

It might be possible to get the MTU on macOS with https://developer.apple.com/documentation/corebluetooth/cbperipheral/1620312-maximumwritevaluelengthfortype and on Windows with https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.genericattributeprofile.gattsession.maxpdusize?view=winrt-19041.

savar commented 3 years ago

So.. as for the ATT specification an ATT MTU can only be negotiated once per connection (https://www.bluetooth.com/specifications/bluetooth-core-specification/) see 3.4.2.1 (but it also says that the ATT_MTU value is per ATT bearer value which I have no idea what this actually means, see 3.2.8 Exchanging MTU size).

From what I saw otherwise it is actually possible (on Android) to do the request actively.. while on iOS this is done anyways by the system at connection time.

I checked based on https://stackoverflow.com/questions/50255842/ble-lower-mtu-value-sizebig-difference-after-mtu-exchange that the bluez stack even though not exposing this possibility (to ask for the mtu) is also requesting a quite high one

< ACL data: handle 3585 flags 0x00 dlen 7
    ATT: MTU req (0x02)
      client rx mtu 517
> HCI Event: Number of Completed Packets (0x13) plen 5
    handle 3585 packets 1
> HCI Event: Number of Completed Packets (0x13) plen 5
    handle 3585 packets 1
> ACL data: handle 3585 flags 0x02 dlen 7
    ATT: MTU resp (0x03)
      server rx mtu 247

so as this is similar to the Windows behavior (and probably to the macOSX behavior: TODO check) the most important part is actually to get the MTU possible. Otherwise I don't know if I break something if I send more data than possible within one packet.

I don't see that the linux-mtu branch is giving me this information (mtu size) as you pointed out.

hbldh commented 3 years ago

I don't see that the linux-mtu branch is giving me this information (mtu size) as you pointed out.

No, it doesn't, and I pointed that out in my reply. I thought that it was not possible to find out, but as @dlech states, there might be some hope on the Windows and macOS backends. But if there is no way of negotiating it, the only value of beaing able to read hte current MTU value is to make certain that you do not send too much data? Can this not be found by simply experimenting with payload sizes?

I have never read the ATT specifications and I probably never will. I look at the APIs available and use what is available there. Whether it is according to specs or not, I do not know.

denravonska commented 3 years ago

Any chance this will be included in a release any time soon?

hbldh commented 3 years ago

@denravonska Nothing has been implemented for mtu, except the BlueZ part mentioned above. However, that does not seem to work so it will not make it into master branch. So the answer is no, I am afraid.

Feel free to try to add the functionality if you need it!

dlech commented 3 years ago

If "this" is setting the requested MTU, then this is only possible AFAIK on Android (which Bleak doesn't support) and on Linux with raw HCI packets which requires elevated privileges and circumvents BlueZ, so not likely to happen any time soon. If "this" is getting the already negotiated MTU then it may be possible on Windows and Mac but BlueZ would require a new API added upstream to work without the need for raw HCI packets and elevated privileges.

denravonska commented 3 years ago

"This" being the ability to setting the MTU. I'm currently migrating from pygattt, which wraps gatttool, to bleak but I cannot get notifications working. Seeing as we send packets of ~168 bytes my initial gut feeling was that it's the MTU that's the problem. However, it seems like I can send large packets just fine and they show up on the peripheral, so I think my problem is elsewhere.

Edit: Just did some bluetoothd debugging and the MTU is definitely not my issue. MTU exchange complete, with MTU: 512.

mjonescae commented 3 years ago

I added to client.py -- for Windows 10,

def get_mtu(self):
    return self._session.MaxPduSize

it works.

dlech commented 2 years ago

Closing as won't fix since setting the MTU is only possible on Android.