BLE RFCOMM substitute

I'm looking for the best practices (and possibly some sample swift code) to communicate with a custom BLE peripheral in a request-response protocol, where the iOS device is the central.
So far my best understanding is that I'll have to implement a custom GATT profile/service.
But both BLE and iOS development is new to me. Could anyone give extra directions?

It depends, but a flexible approach might look like this. I'll focus on your protocol here—the rest is in the Core Bluetooth docs.

  • The peripheral publishes an app-specific service, most likely on a UUID that you generated randomly.
  • Underneath that service it publishes a read/notify characteristic, which will provide an asynchronous response to requests (a different random UUID).
  • The peripheral also publishes a writeable characteristic for requests.
  • When the central connects, it discovers both characteristics, subscribes to the "result" characteristic, and writes to the "request" characteristic when it needs to.

These writes and notifications have a small binary data payload of your choice. Typically iOS devices will let you do ~185 bytes at a time so if your requests and responses are short you can insert them directly. If they're bigger you'll have a bit more work to split them up.

Possible simplifications if your app allows it:

  • If requests can be completed instantly, the central could write a request and then immediately read a response from a second characteristic, without messing about with notifications.
  • If you have a small fixed variety of requests, you can add a characteristic for each one. Then you know what type of request it is already without parsing the data.
  • If your requests don't need any parameters or data payload, simply trying to read a specific characteristic can be treated as a request. If the peripheral can provide the response synchronously, it can calculate and return it immediately. This is a very simple workflow to implement.

Thanks a lot thombles! I was thinking about something like this. What caught my attention is that you say we have to split messages that are too "large". With my old RFCOMM implementation the average packet size was 340 bytes, so I'm a bit disappointed. Is this something unavoidable? And if yes, am I going to need something like this:

loop until the whole message is sent:
    central sends several bytes of the message to a characteristic
    peripheral reads it and writes a checksum to another characteristic 
    if crc failure:
       restart transmission
BLE RFCOMM substitute
 
 
Q