While studying BLE on ESP32, I came to the conclusion that it was more "involved" than it needed to be and could potentially be simplified through encapsulation as a set of objects. In the ESP32 environment, the obvious choice for objects is C++. This video illustrates one possible implementation of a set of C++ classes that encapsulate and simplify BLE on the ESP32.
https://www.youtube.com/watch?v=2_vlF_02VXk
This is still very much a work in progress and its direction will be governed by community interest. The source of the classes can be found here:
https://github.com/nkolban/esp32-snippe ... /cpp_utils
I'm working on writing these up in more detail (a programmer's guide) but the relative priority of that work will be related to community needs and interest.
Comment and direction for BLE C++ classes (and other classes in general) very welcome.
Additional related videos:
* ESP32 - BLE Client - https://www.youtube.com/watch?v=UgI7WRr5cgE
[Video]: Bluetooth BLE and C++ classes
[Video]: Bluetooth BLE and C++ classes
Last edited by kolban on Sat Jul 29, 2017 7:26 pm, edited 2 times in total.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32
Re: [Video]: Bleutooth BLE and C++ classes
Great work Neil. I was thinking that the BLE interface could do to be a bit simpler myself. The use of C++ classes looks like a good way to go. Wonder why Espressif didn't do it like that in the API.
Looks like it'll make building BLE peripherals much easier.
Looks like it'll make building BLE peripherals much easier.
Steve.
Re: [Video]: Bleutooth BLE and C++ classes
Excellent work! Very nice, clear video. Have you thought about how you are going to handle notifications?
My current ESP32 app is all C for now. Perhaps I'll look at your library implementation for examples...
Robin
My current ESP32 app is all C for now. Perhaps I'll look at your library implementation for examples...
Robin
Re: [Video]: Bleutooth BLE and C++ classes
Robin,
In an Object Oriented language, there are commonly two choices for asynchronous callbacks. The first is subclassing. Imagine we have a call called Foo:
class Foo {
virtual void myCallback() {
// do nothing
}
}
In our story, this could be the BLECharacteristic class. Now imagine that we want handle read requests from the peer, me might code:
class MyFoo: public Foo {
void myCallback() {
// do something
}
}
In this case, MyFoo is a subclass of Foo. This means that it behaves exactly like Foo ... except where we have over-ridden same named functions (eg. myCallback). In this case when the internals of Foo invoke the callback, what will be called is your own implementation.
A second common choice is supplying a callback function. For example, in C we can code:
void myCallback();
Foo myFoo;
myFoo.setCallback(myCallback)
The "myFoo" instance would expose a "callback setter" that would take as input a function pointer. The instance of "myFoo" would then save (in its own instance state) the reference to the function. When a callback is needed, it would check that a function pointer reference is present, and then invoke it.
In a C++ flavor of the world, instead of supply a single function to the setCallback() invocation, we could supply a reference to a class that provides an abstract implementation of multiple callbacks.
Some of these are a matter of taste as opposed to "correctness" of design. My current taste is that of modeling an abstract callback class and then subclassing that for my own implementations.
In an Object Oriented language, there are commonly two choices for asynchronous callbacks. The first is subclassing. Imagine we have a call called Foo:
class Foo {
virtual void myCallback() {
// do nothing
}
}
In our story, this could be the BLECharacteristic class. Now imagine that we want handle read requests from the peer, me might code:
class MyFoo: public Foo {
void myCallback() {
// do something
}
}
In this case, MyFoo is a subclass of Foo. This means that it behaves exactly like Foo ... except where we have over-ridden same named functions (eg. myCallback). In this case when the internals of Foo invoke the callback, what will be called is your own implementation.
A second common choice is supplying a callback function. For example, in C we can code:
void myCallback();
Foo myFoo;
myFoo.setCallback(myCallback)
The "myFoo" instance would expose a "callback setter" that would take as input a function pointer. The instance of "myFoo" would then save (in its own instance state) the reference to the function. When a callback is needed, it would check that a function pointer reference is present, and then invoke it.
In a C++ flavor of the world, instead of supply a single function to the setCallback() invocation, we could supply a reference to a class that provides an abstract implementation of multiple callbacks.
Some of these are a matter of taste as opposed to "correctness" of design. My current taste is that of modeling an abstract callback class and then subclassing that for my own implementations.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32
Re: [Video]: Bleutooth BLE and C++ classes
@Shcreasey,
Thank you sir. From my basic understanding, C and C++ will likely have the same (similar) execution characteristics. What that means is that if I wrote an app in C but then compiled it using the C++ compiler, the execution pattern should be the same (similar). If I utilize the basic features of the C++ language (eg. class construction, new operator etc) then again, the pattern should be similar to me having written in C and used "malloc" and "free" to allocate state storage data. Where some deviation might occur is if one started to use the Standard Template Library (STL) available to C++. Here you start to take advantage of capabilities that are C++ exclusive with pros and cons. The pros being that you suddenly have increased richness of function and the cons being that the size of your compiled executable will grow. You are trading off "low level architecture access" for "higher level design/models".
Given that ESP-IDF *must* be as close to the metal as possible, I have no concern with the ESP-IDF itself being implemented (as much as possible) in C. One must realize that from a C++ environment, we can 100% access all the capabilities exposed by C. This means that any arbitrary ESP-IDF exposed function (eg. esp_xyz) can be called from either C or C++ in exactly the same manner. If we choose, we can then encapsulate the ESP-IDF functions in higher level models as C++ classes. However, the reverse wouldn't be true. If the ESP-IDF used C++ as its own (and exclusive) exposed framework, that would prevent access from exclusively native C applications.
Thank you sir. From my basic understanding, C and C++ will likely have the same (similar) execution characteristics. What that means is that if I wrote an app in C but then compiled it using the C++ compiler, the execution pattern should be the same (similar). If I utilize the basic features of the C++ language (eg. class construction, new operator etc) then again, the pattern should be similar to me having written in C and used "malloc" and "free" to allocate state storage data. Where some deviation might occur is if one started to use the Standard Template Library (STL) available to C++. Here you start to take advantage of capabilities that are C++ exclusive with pros and cons. The pros being that you suddenly have increased richness of function and the cons being that the size of your compiled executable will grow. You are trading off "low level architecture access" for "higher level design/models".
Given that ESP-IDF *must* be as close to the metal as possible, I have no concern with the ESP-IDF itself being implemented (as much as possible) in C. One must realize that from a C++ environment, we can 100% access all the capabilities exposed by C. This means that any arbitrary ESP-IDF exposed function (eg. esp_xyz) can be called from either C or C++ in exactly the same manner. If we choose, we can then encapsulate the ESP-IDF functions in higher level models as C++ classes. However, the reverse wouldn't be true. If the ESP-IDF used C++ as its own (and exclusive) exposed framework, that would prevent access from exclusively native C applications.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32
Re: [Video]: Bleutooth BLE and C++ classes
Lol, I'm quite familiar with OO programming given that most of my code is written in C++ or Java. I was asking about how you might handle BLE notification (since it didn't look like your classes were currently handling them).
Robin
Robin
Re: [Video]: Bleutooth BLE and C++ classes
Sorry Robin, my mind overloaded the use of the word "Notification". In the solution so far, a BLECharacteristic object models a BLE Characteristic. It is the value of the characteristic that, when it changes, may wish to be indicated to the clients that would then receive the corresponding notification that it has changed. As such, the BLECharacteristic class has a method on it called indicate(). When that is invoked, it causes the current value of the characteristic to be indicated resulting in the corresponding notification of the connected client.
Does this sound like a reasonable choice?
Does this sound like a reasonable choice?
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32
Re: [Video]: Bleutooth BLE and C++ classes
Hi Neil,
I believe indications and notifications are two slightly different things. Both automatically inform the client/central device of a change to the peripheral/server characteristic but they differ in the acknowledgement:
Indication (requiring an acknowledgement from the client/central device)
notification (not requiring an acknowledgement from the client/central device)
Steve.
I believe indications and notifications are two slightly different things. Both automatically inform the client/central device of a change to the peripheral/server characteristic but they differ in the acknowledgement:
Indication (requiring an acknowledgement from the client/central device)
notification (not requiring an acknowledgement from the client/central device)
Steve.
Steve.
Re: [Video]: Bleutooth BLE and C++ classes
Thanks Steve,
See the following:
http://esp-idf.readthedocs.io/en/latest ... P7uint8_tb
That's a great catch. Right now the BLECharacteristic class has a method called indicate that calls esp_ble_gatts_send_indicate with the need_confirm parameter set to false. From the docs, this looks to then be a "Notify". I'll change the indicate() method to pass true and create a second method called notify() that passes false.
A HUGE thank you kind sir.
See the following:
http://esp-idf.readthedocs.io/en/latest ... P7uint8_tb
That's a great catch. Right now the BLECharacteristic class has a method called indicate that calls esp_ble_gatts_send_indicate with the need_confirm parameter set to false. From the docs, this looks to then be a "Notify". I'll change the indicate() method to pass true and create a second method called notify() that passes false.
A HUGE thank you kind sir.
Free book on ESP32 available here: https://leanpub.com/kolban-ESP32
Re: [Video]: Bleutooth BLE and C++ classes
I have a mobile bluetooth client connecting to the ESP32 and turning on/off a led on GPIO 5 successfully. Now, I want to send a notification should a variable change on the ESP32. If found in components/bt/bluedroid/api/include/esp_gatts_api.h:
I tried it and it works well. The "need_confirm" parameter determines whether a notification or indication is sent.
Robin
Code: Select all
esp_err_t esp_ble_gatts_send_indicate(esp_gatt_if_t gatts_if, uint16_t conn_id, uint16_t attr_handle,
uint16_t value_len, uint8_t *value, bool need_confirm);
Robin
Who is online
Users browsing this forum: forrest and 79 guests