This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

BLE design — best practice, many or few characteristics?

Hello!  We are designing an iPad app that will occasionally connect to our device over BLE. The app is kind of a maintenance/service app that will query various information from the device, for example:

  • state
  • battery level
  • firmware version
  • configuration table
  • event log
  • activity log

and send a few items like

  • various commands such as reset to factory defaults
  • a firmware upgrade

My teammate has proposed setting up a set of BLE characteristics on the device that publish most of the above individually; a characteristic for state, battery, version, config data, event data, activity data, and a pair of RX/TX channels for streaming data. Generally speaking, a lot of characteristics, each dedicated to a specific type of data.

My inclination is to just set up the RX/TX, and do everything over that one serial channel with a framed message system: "[B2234][S7][C3,27]" tells us the battery level is 2234, the state is 7, and config parameter 3 is 27. Maybe we have a second RX/TX dedicated to binary data, no framing.

So I was hoping you could help us settle this debate. Both of us have a little experience but we aren't experts at BLE.

The advantages/disadvantages of the many-characteristic approach, he says:

  • PRO more transparent/explicit what is being passed
  • PRO don't have to write any parsing code, data is not fettered with framing data
  • CON if you want to transmit something else we need to add a whole new characteristic instead of adding a new framed command, which is more coding
  • CON I'm not sure if this is true, but if we add a new characteristic to the device, do we break compatibility with the App?

The advantages/disadvantages of the single Rx/TX are:

  • PRO very versatile, if we want to add a command or change the timeliness or pattern of data transmission for a certain data item, we are just modifying C code, not redoing the set of characteristics
  • PRO compatibility is a non-issue, any new commands not supported yet by the other side are just ignored or NACKed
  • CON as mentioned, you have to write parsing code for the framed data
  • CON I think RX/TX over BLE is awkward, in that you have to "batch" up your stream to the size of the characteristic. We'd have to be careful to not lose data.

So I consider the versatility (since we will probably change our dataset a lot) of the single RX/TX to be the winning factor, and he considers the explicit transparency of the many-characteristics approach to be the winner.

I also feel like there are factors we don't know about due to inexperience. Are there costs of additional characteristics, or are they cheap? What are the compatibility issues if the two sides don't match on the characteristics.

So which approach do you guys like?

Parents
  • Hi

    If you don't need compatibility with third-party software, I would use one characteristic approach. As you said, you can easy change your command set in a new firmware version. If you add a new characteristic every time, you should somehow force the host to rescan all characteristics (or rescan with every connection, that slows connection process). Of course, you need some layer to handle fragmentation and command acknowledge, but this is one-time development effort.
    One CON I can see that you cannot debug your commands with standard tool like nRF connect, maybe you'll need to write some tool to send and receive commands.
    Just one thing from my experience - make a separate characteristic for firmware update and configure it first in the list, this will save you from a big headache one day :)

Reply
  • Hi

    If you don't need compatibility with third-party software, I would use one characteristic approach. As you said, you can easy change your command set in a new firmware version. If you add a new characteristic every time, you should somehow force the host to rescan all characteristics (or rescan with every connection, that slows connection process). Of course, you need some layer to handle fragmentation and command acknowledge, but this is one-time development effort.
    One CON I can see that you cannot debug your commands with standard tool like nRF connect, maybe you'll need to write some tool to send and receive commands.
    Just one thing from my experience - make a separate characteristic for firmware update and configure it first in the list, this will save you from a big headache one day :)

Children
  • Thanks Dmitry for the good thoughts!  One question, I was thinking of a separate RX/TX for binary data, such as firmware hex file, that wouldn't have framing detection (ie we wouldn't have to switch parsing modes between framed ASCII and raw on one channel).  Is his why you say make a different characteristic, or some other reason?  And why configure it first?

  • I prefer to send everything in binary, you may consider ascii more convenient.

    Firmware update should work in any firmware version under any circumstances, it's better to isolate that code in a separate module and do not touch once it has been tested. If you use a bootloader for firmware update, this characteristic can be shared between app and bootloader without need for device rebonding or other dirty hacks. That's why to place it first - maybe you will decide to add more characteristics in the future.

Related