zephyrproject-rtos / zephyr

Primary Git Repository for the Zephyr Project. Zephyr is a new generation, scalable, optimized, secure RTOS for multiple hardware architectures.
https://docs.zephyrproject.org
Apache License 2.0
10.96k stars 6.67k forks source link

Bluetooth Module for CPP #55433

Open vChavezB opened 1 year ago

vChavezB commented 1 year ago

Introduction

Greetings Zephyr Team. This RFC proposes a BLE module for easier integration of Bluetooth GATT services and characteristics. I would like to hear your feedback and see if you would accept a proposal for C++ development.

Problem description

Currently adding GATT services and characteristics can be defined at compile time by using zephyr macros. This is however not type safe and straight forward. There are too many hidden details that make it cumbersome. Some examples:

  1. BLE indications and notifications API are not easy to use without manually tracking which attribute you defined . You need to count how many attributes in your GATT service are defined from the zephyr macros. For example if you defined the main service and then an indication service, you need to read the source code to know that the macro BT_GATT_SERVICE defines one attribute. When using the API you need to know the UUID or the attribute index define by the zephyr macro.
  2. There is no documentation on how to manually initialize the gatt attribute array for a service or characteristic. You need to read the source code to know for example that if you define a characteristic, the first gatt attribute needs to point the user_data member to a struct of bt_gatt_chrc.

Proposed change

A CPP zephyr module that initializes correctly the bt_gatt_attr struct for defining services and characteristics. The module would contain compile time declaration through templates (C++20) and dynamic declaration through normal C++ classes.

Detailed RFC

There is a need to either document how to initialize correctly the bt_gatt_attr struct. Unless you read the source code end users can not know how to define GATT attributes correctly. See for example this user which did not know how to use the API service define:

https://github.com/zephyrproject-rtos/zephyr/issues/20707

This proposal allows end users to use a CPP module which can be used at compile time or run time to define GATT attributes. It abstracts the complexity that is required to know how to declare GATT attributes. Currently the complexity is abstracted through Zephyr C Macros which are not type safe and are not thoroughly documented.

Proposed change (Detailed)

Templated class for C++ compile time definition of gatt attributes. The generated gatt attributes can then be used with the API bt_gatt_service_register. I attempted to declare the attributes directly in the linker section bt_gatt_service_static but my gcc compiler keeps mangling the c++ templated class instantiated attributes so I opted out of this option.

For run time, i propose a class that holds the attributes for services and characteristics. The end user can then can add characteristics to a service over a specified API for this module.

Dependencies

C++20 - I think that the latest standardization efforts for C++ allow better type safe code and optimizations at compile time.

Final notes

I am already developing this module and when I am back at the office I can link the current implementation and how this would look like. Its either necessary to document how attributes are initialized or a module that end users can utilize to develop GATT attributes for the zephyr API. I opt for a module that is typesafe and straightforward to use without the obfuscation that the zephyr macros have.

Alternatives

Document thoroughly how to define and initialize GATT services and characteristics.

vChavezB commented 1 year ago

As discussed before here is the proposed module for usage of the gatt attributes in the Zephyr OS 100 % compatible with C++.

https://github.com/vChavezB/ble_utils

It is a work in progress and I am open for discussion. The main trade off as always in this type of situations when you move from C to C++ is abstraction > performance.

In addition, I discarded the idea of using templates for generating a compiled time gatt attribute array. The main reason is that to my opinion the user interface was starting to get too complex really fast and didnt see any use cases that werent covered by this first proposal.