petzval / btferret

Python and C Bluetooth Library
MIT License
126 stars 22 forks source link

Is it possible to increase MTU size? #10

Closed kahlenberg closed 8 months ago

kahlenberg commented 1 year ago

Hi, In file btlib.c the LEDATLEN is defined as 20. Does that mean the MTU size, right? I want to send and receive data up to 128 byte. Is it possible? If yes how? I changed LEDATLEN to 128, and in my nRF52840 firmware also, but it sends/receives still only 20 byte. I think in btlib.c lots of arraysizes are hardcoded with 20.

petzval commented 1 year ago

Change LEDATLEN to 128, and set SIZE=128 in the devices file LECHAR entry. The write_ctic code will then send a 128-byte packet. The only extra step that may be necessary is to tell the nRF that the MTU has changed from the default by calling the following function. Put it in btlib.c and call it immediately after connection with the node number of the nRF.

int setmtu(int node)
  {
  int ndevice;

  ndevice = devnp(node);
  if(ndevice < 0)
    return(0);

  mtuset[14] = (unsigned char)((LEDATLEN+3) & 0xFF);
  mtuset[15] = (unsigned char)(((LEDATLEN+3) >> 8) & 0xFF);
  sendhci(mtuset,ndevice);
  readhci(0,0,0,200,0);
  return(1);
  }

If you turn on verbose mode, you should see an opcode=03 reply from the nRF. The last two bytes are the MTU that the nRF will accept, and if they are 17 00 then LEDATLEN cannot be increased beyond 20 - they should be equal to the MTU you set on the nRF. I tried this between two Pis set up as client/server and the larger packet is transmitted OK.

kahlenberg commented 1 year ago

Thank you, I try it now, but the connection is always closed. Log after connection:

SEND LE connect to CO2 Sensor Module
  Set [10].. board address reversed 05..E0
< HCI OGF=08 OCF=0D
      0000  01 0D 20 19 60 00 60 00 - 00 01 05 C6 27 97 D0 E0
      0010  00 18 00 28 00 00 00 11 - 01 00 00 00 00
> Event 0F = 00 01 0D 20
      0000  04 0F 04 00 01 0D 20
> Event 3E = 01 00 40 00 00 01 05 C6 27 97...
      0000  04 3E 13 01 00 40 00 00 - 01 05 C6 27 97 D0 E0 27
      0010  00 00 00 11 01 00
Connect OK as LE client
Handle = 0040
  Set [1][2] handle 40 00
< L2CAP 0004 Opcode = 02
      0000  02 40 00 07 00 03 00 04 - 00 02 83 00
> L2CAP 0004 Opcode = 03
      0000  02 40 20 07 00 03 00 04 - 00 03 77 00
> Event 13 = 01 40 00 01 00
      0000  04 13 05 01 40 00 01 00
Reading LE services from CO2 Sensor Module..
SEND read UUID (opcode 08)
  Set [10][11] starting ctic handle 0001
  Set [14][15] UUID 2803
  Set [1][2] handle 40 00
< L2CAP 0004 Opcode = 08
      0000  02 40 00 0B 00 07 00 04 - 00 08 01 00 FF FF 03 28
SEND read UUID (opcode 08)
  Set [10][11] starting ctic handle 0002
  Set [14][15] UUID 2803
  Set [1][2] handle 40 00
< L2CAP 0004 Opcode = 08
      0000  02 40 00 0B 00 07 00 04 - 00 08 02 00 FF FF 03 28
> Event 13 = 01 40 00 02 00
      0000  04 13 05 01 40 00 02 00
> L2CAP 0004 Opcode = 09
      0000  02 40 20 30 00 2C 00 04 - 00 09 07 02 00 20 03 00
      0010  05 2A 05 00 0A 06 00 29 - 2B 07 00 02 08 00 2A 2B
      0020  0A 00 02 0B 00 00 2A 0C - 00 02 0D 00 01 2A 0E 00
      0030  02 0F 00 04 2A
SEND read UUID (opcode 08)
  Set [10][11] starting ctic handle 0010
  Set [14][15] UUID 2803
  Set [1][2] handle 40 00
< L2CAP 0004 Opcode = 08
      0000  02 40 00 0B 00 07 00 04 - 00 08 10 00 FF FF 03 28
> L2CAP 0004 Opcode = 09
      0000  02 40 20 45 00 41 00 04 - 00 09 15 11 00 12 12 00
      0010  48 FC 85 75 90 C7 93 92 - 2D 48 9B E1 02 00 EA E9
      0020  14 00 04 15 00 48 FC 85 - 75 90 C7 93 92 2D 48 9B
      0030  E1 03 00 EA E9 16 00 04 - 17 00 48 FC 85 75 90 C7
      0040  93 92 2D 48 9B E1 04 00 - EA E9
SEND read UUID (opcode 08)
  Set [10][11] starting ctic handle 0018
  Set [14][15] UUID 2803
  Set [1][2] handle 40 00
< L2CAP 0004 Opcode = 08
      0000  02 40 00 0B 00 07 00 04 - 00 08 18 00 FF FF 03 28
> Event 13 = 01 40 00 02 00
      0000  04 13 05 01 40 00 02 00
> L2CAP 0004 Opcode = 01
   Error 0A = Attribute Not Found
      0000  02 40 20 09 00 05 00 04 - 00 01 08 18 00 0A

Characteristics saved to device info
   ctic
   index       LE Characteristics
     0  Service Changed      ? byte Permit 20 i   Handle=0003 UUID=2A05
     1  Client Supported Features          1 byte Permit 0A rwa Handle=0006 UUID=2B29
     2  Database Hash        16 byte Permit 02 r   Handle=0008 UUID=2B2A
     3  Name                 17 byte Permit 02 r   Handle=000B UUID=2A00
     4  Appearance           2 byte Permit 02 r   Handle=000D UUID=2A01
     5  Pref Connection Parameters         8 byte Permit 02 r   Handle=000F UUID=2A04
     6  E9EA0002E19B482D9293C7907585FC48   128 byte Permit 12 rn  Handle=0012
            UUID=E9EA0002E19B482D9293C7907585FC48
     7  E9EA0003E19B482D9293C7907585FC48   ? byte Permit 04 w   Handle=0015
            UUID=E9EA0003E19B482D9293C7907585FC48
     8  E9EA0004E19B482D9293C7907585FC48   ? byte Permit 04 w   Handle=0017
            UUID=E9EA0004E19B482D9293C7907585FC48
Write CO2 Sensor Module E9EA0003E19B482D9293C7907585FC48 = 00 00 48 44
SEND write LE characteristic
  Set [3][4] [5][6] packet lengths
  Set [9] opcode 52
  Set [10][11] characteristic handle 0015
  Set [12].. 04 data bytes
  Set [1][2] handle 40 00
< L2CAP 0004 Opcode = 52
      0000  02 40 00 0B 00 07 00 04 - 00 52 15 00 00 00 48 44
Write CO2 Sensor Module E9EA0004E19B482D9293C7907585FC48 = 00
SEND write LE characteristic
  Set [3][4] [5][6] packet lengths
  Set [9] opcode 52
  Set [10][11] characteristic handle 0017
  Set [12].. 01 data bytes
  Set [1][2] handle 40 00
< L2CAP 0004 Opcode = 52
      0000  02 40 00 08 00 04 00 04 - 00 52 17 00 00
read index: 6, write index: 7, ctrldata index: 8 data: 0
Read LE characteristic
  Set [10][11] handle 0012
  Set [1][2] handle 40 00
< L2CAP 0004 Opcode = 0A
      0000  02 40 00 07 00 03 00 04 - 00 0A 12 00
> Event 13 = 01 40 00 02 00
      0000  04 13 05 01 40 00 02 00
> L2CAP 0004 Opcode = 0B
      0000  02 40 20 45 00 41 00 04 - 00 0B 42 42 42 42 42 42
      0010  42 42 42 42 42 42 42 42 - 42 42 42 42 42 42 42 42
      0020  42 42 42 42 42 42 42 42 - 42 42 42 42 42 42 42 42
      0030  42 42 42 42 42 42 42 42 - 42 42 42 42 42 42 42 42
      0040  42 42 42 42 42 42 42 42 - 42 42
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

Disconnecting everything and exit..
< HCI OGF=08 OCF=0A
      0000  01 0A 20 01 00
> Event 13 = 01 40 00 01 00
      0000  04 13 05 01 40 00 01 00
> L2CAP 0005 ? =  12 02 08 00 18 00 28 00 00 00 2A...
      0000  02 40 20 10 00 0C 00 05 - 00 12 02 08 00 18 00 28
      0010  00 00 00 2A 00
> Event 0E = 01 0A 20 0C
      0000  04 0E 04 01 0A 20 0C
SEND Close connection
  Set [4][5] handle 40 00
< HCI OGF=01 OCF=06
      0000  01 06 04 03 40 00 13
> Event 0F = 00 01 06 04
      0000  04 0F 04 00 01 06 04
CO2 Sensor Module has disconnected
> Event 05 = 00 40 00 16
      0000  04 05 04 00 40 00 16
GOT Disconnected OK (Event 05)
HCI closed

And I receive a warning from nRF: <wrn> bt_att: Ignoring unexpected request

kahlenberg commented 1 year ago

Second question: Is there any callback for client? My nRF works as bt-server and I connect to it with Raspberry Pi using btferret library. When I reset the server (nRF), I want to be informed for disconnect event. Is it possible? Thanks.

petzval commented 1 year ago

The characteristic scan is finding the 128-byte entry correctly, and is reading the 64 bytes that the nRF has chosen to send, so this seems to be working OK. It looks like the 128 length might be coming from the devices.txt file, in which case an extra step may be needed. With my nRF52840 I have found that a data length command must be sent for the Pi to see a 128-byte entry correctly, so the modified version of setmtu is now:

int setmtu(int node)
  {
  int ndevice;
  static unsigned char setdatlen[16] = {10,0,S2_HAND,0,1,0x22,0x20,6,0x40,0,0x1B,0,0,2};

  ndevice = devnp(node);
  if(ndevice < 0)
    return(0);

  mtuset[14] = (unsigned char)((LEDATLEN+3) & 0xFF);
  mtuset[15] = (unsigned char)(((LEDATLEN+3) >> 8) & 0xFF);
  sendhci(mtuset,ndevice);

  setdatlen[10] = (unsigned char)((LEDATLEN+3) & 0xFF);
  setdatlen[11] = (unsigned char)(((LEDATLEN+3) >> 8) & 0xFF);
  sendhci(setdatlen,ndevice);

  readhci(0,0,0,200,0);
  return(1);
  }

Test this by temporarily removing the characteristic from devices.txt. On my system, the old version of setmtu results in a reported size of 22 bytes when a services scan is run, but the new version sees and reads/writes 128 bytes.

In the original btferret.c code, the "Disconnecting everything.." message only appears because btlink() has terminated, so the cause of the disconnect is in btlink().

If the readhci() function is running, it will see a disconnect (line 5403 in btlib.c). But readhci does not run in the background, so a disconnect can only be seen by polling. The read_notify function can be used for this because it just runs readhci for the specified time. If a disconnect happens when readhci is not running, the info will be saved in a buffer and readhci will see it when it does run, so for example:

read_notify(50);    // run readhci for 50ms - it will see any past or current disconnects
if(device_connected(node) == NO_CONN)
  printf("Device disconnected\n");

OR just call readhci directly

readhci(0,0,0,50,0);    // 50ms time out
petzval commented 1 year ago

The ability to increase the characteristic size beyond 20 for the local and remote devices looks so useful that I will incorporate the MTU-setting functions into btlib so they will run automatically. Hope to release this new version within a week.

kahlenberg commented 1 year ago

Thank you. Can you please share also the configuration of nRF board? Somehow I couldn't set the mtu, I have always 20 Byte. If I want to have 128 byte MTU, I should write a number less then 128. I don't rememeber exactly. CONFIG_BT_L2CAP_TX_MTU=119

petzval commented 1 year ago

The MTU needs to be data length + 3. The new version 7 sets the MTU to whatever value the nRF requests, and can now read/write 128 byte characteristics set up by nRF Connect Desktop/Low Energy/Server Setup option which seems to always request the maximum MTU of 251. I have not written nRF code to set the MTU.

ashoksharma842 commented 8 months ago

// ATT_MTU data cannot be more than 244 //line#43

define LEDATLEN 244

while the spec BLUETOOTH SPECIFICATION Version 5.0 | Vol 3, Part F specifies (on page 2178).

The maximum length of an attribute value shall be 512 octets.

Can I set LEDATLEN to 512? Or did I misunderstood something?