0

I want two BLE devices to connect to each other, and exchange data bi-directionally.
These devices are exactly equivalent - this is basically a serial cable between two peers.
There is not one 'store of data', or hierarchy between the two.

Both ends basically transmit data to each other (there is no polling for 'read' data), and no acknowledgement is required.

BLE documentation refers to the Characteristic Properties as:

  • A Client can send data to the server with 'write'
  • A Server uses a 'notify' characteristic (which the Client subscribes to)

So basically I have just one question:

Can I just have one Characteristic, with two properties

  • 'Notify' (writing to Client) and
  • 'Write' (writing to Server)

That the Peripheral advertises, and this will enable two-way write behavior?

DefenestrationDay
  • 3,712
  • 2
  • 33
  • 61

1 Answers1

3

First a few things to make everything clear, in case somebody wonders:

BLE has the concept of Central and Peripheral. Peripherals advertise their presence. Centrals scan and discover peripherals which they then connect to. Once the connection is created, these link layer roles do not really matter in terms of GATT and L2CAP Connection oriented channels, which are both used to transfer data.

Every device (including centrals) supporting connections over BLE must have a GATT server. While it is far more common that the peripheral only uses the GATT server role, it can act as GATT client. Centrals can also act as GATT servers. Furthermore, the both GATT roles can be supported simultaneously. Both sides can for example expose an identical GATT server characteristic with the write property. Not sure if this is a common approach though.

Now, back to your question. You can definitely have one characteristic both having the "write" and "notify" capabilities. When you write, I would suggest using "Write without response" since that has better throughput than "Write with response", since it does not require an acknowledgement between every write. Over the link layer, all kinds of packets are still sent "reliably", meaning there will be no packet drops unless the whole connection drops.

I would however suggest you to have one characteristic per direction. The reason is that some Bluetooth stacks can not in a thread-safe way both send and receive data on one single characteristic, due to the API design structure. In particular, Android's API has one method to set data on a characteristic and another method to send the current data of a characteristic. If a notification arrives in between these calls (where the bluetooth stack internally assigns the new data to the characteristic), the write operation will send the data that was just notified, instead of the intended data.

You could also check out L2CAP Connection oriented channels (introduced in Bluetooth v4.2) which is a good way to transfer raw data byte packets, when the GATT structure is not appropriate.

Emil
  • 16,784
  • 2
  • 41
  • 52
  • You are absolutely right except "Write Without Response". This method does not guarantee data delivering and there are lot of device that works incorrectly if you use "Write Without Response". Data may be lost or even sequence may be wrong. You always should check your devices requirements before using Write Without Response/Write With Response. – Mike Petrichenko Feb 02 '23 at 14:29
  • Good point. Many bluetooth stacks though implement Write without response in a completely reliable way without packet drops, if you follow the flow control requirements for that stack. See for example https://stackoverflow.com/questions/43741849/oncharacteristicwrite-and-onnotificationsent-are-being-called-too-fast-how-to/43744888#43744888 how to do that on Android when sending data. When receiving data, Android never drops any packets. For iOS, always wait for https://developer.apple.com/documentation/corebluetooth/cbperipheraldelegate/2874034-peripheralisready before sending the next write. – Emil Feb 02 '23 at 14:44
  • It does not matter what Android and Apple do. The only matter is what Bluetooth Core specification says. There are not only Android and Apple in the world: ESP32, TI, STM, many other with own stack and own implementation with tons of bugs. Bluetooth Core specs says that Write Without Response does not guarantee data delivering, so any developer must develop his code as data may not be delivered. – Mike Petrichenko Feb 02 '23 at 18:00