Victor Sergienko
Victor Sergienko

Reputation: 13495

How do I send a long notification with Bluez, example?

I need to send a long (let's say 10Kb) notification from Bluez 5.37 on my Linux device to a mobile phone.

My implementation is based on src/shared/gatt-server.c.

I cannot find an example of this in Bluez. src/shared/gatt-server.c, bt_gatt_server_send_notification() is strictly trimming the packet to MTU-1 and discards the rest. I must need an output queue for this, like in gatt-client.c. bt_gatt_client_read_long_value() looks like an example of what I need, but for long characteristic reads.

  1. Is there a way to send a long notification compatible with majority of Bluetooth 4.0 Android phones? It requires a bit of collaboration on the phone side - sending a ATT_READ_BLOB_REQUESTS, AFAIS.
  2. Or is there a generic packetization library that will work over 20-byte-sized packets?
  3. Another way I can think of is to create another characteristic, use Notification messages for short messages and, er, notifications that "Hey, there's a long message, read it from that characteristic".

Which way is better? Does an example of any of the three ways exist?

Upvotes: 1

Views: 2039

Answers (2)

Victor Sergienko
Victor Sergienko

Reputation: 13495

I'm not entitled to disclose the code, but here's the basic idea of what I did. I use a tools/bgatt-server.c as an base for my peripheral.

To send a long message:

  • Save the notification_buffer being sent and the notification_position in the server's fields;
  • Implement a bt_gatt_server_send_notification_with_callback() function in gatt-server.c. It should do the same as bt_gatt_server_send_notification() but have extra void *user_data and bt_gatt_server_destroy_func_t destroy arguments, and pass them to bt_att_send(). This will enqueue the next invocation of destroy callback when the bluez output queue becomes free.
  • Implement a bt_gatt_server_destroy_func_t that calculates the next chunk to be sent from server's notification_buffer and notification_position fields, send them with bt_gatt_server_send_notification_with_callback() and passes server as user_data and itself as the destroy callback.

To reassemble the message on receiving end:

  • I split the long message with my own packetizer/depacketizer.
  • I use a header: 1 byte - packet's messageId and 2 bytes for packetId - this way, one can have messages up to 17*65536 bytes length. Plus, this leaves the opportunity to re-request a packet for reliable delivery in the future.

Upvotes: 2

Cambsukguy
Cambsukguy

Reputation: 11

I do this for Bluez:

PRLOG("Send Notify, %d bytes\n", send_len);
do {
  if (RPService.valid) {
    send_res = bt_gatt_server_send_notification (pCharac->server->gatt, pCharac->handle,
                                                     pTx, mMIN(send_len, mBLE_TRANSFER_SIZE));
  } else {
    break;
  }
  if (send_res) {
    pTx += mBLE_TRANSFER_SIZE;
    send_len -= mBLE_TRANSFER_SIZE;
  } else {
    PRLOG("  Notify write failed...wait\n");
    usleep(mTX_WAIT);
  }
} while (send_len > 0);

Upvotes: 1

Related Questions