Closed monacoprinsen closed 2 months ago
We discussed this briefly today in the community meeting.
Unfortunately, none of our current maintainers seems to have much or any experience with Bluetooth. Given the complexity of the protocol this makes defining traits incredibly difficult, if not impossible. We really need somebody with expertise to do this properly, so that's our first blocking point.
One potential option is to try and find examples of Bluetooth stacks written in Rust for other platforms. I'm not really sure what is out there, or if there has been any serious work done for this at all. However, if we were able to find some implementation(s) we would at least have some inspiration as to how our API might look.
If there are any further updates on this topic I will share them here, but it's unfortunately looking like one or more community members will need to tackle this on their own, otherwise there will likely be quite the wait.
How about continuing Rubble's work,https://github.com/jonas-schievink/rubble? The project seems to be outdated, it only supports Bluetooth 4.2 and NRF MCUs only, but it's designed to be hardware-independent.
At the very least, I think we can learn from their project structure and flow.
Rubble is not seeing a lot of development lately so I'm skeptical that it can be used in any shape or form.
There are actually some sample wrappers of the ESP-IDF BT stacks implemented by community members in the meantime. We are only waiting for them to find some time to publish those.
I think it would be handy to list some of these sample wrappers. The only one that I could find is https://github.com/pyaillet/esp-idf-ble.
If it's useful to you, I created a bluedroid wrapper: https://github.com/persello/bluedroid.
I have updated the title of the bug to indicate that this issue is now about BLE.
Classic BT (esp32 only, of course) is in the meantime supported, under the experimental
flag, in mainline, and will be released soon. Not all protocols are implemented, but they can be - incrementally, when the need arises. and the overall framework how to implement those is in the meantime in place.
As for BLE - at least the Bluedroid APIs can also be easily mapped as they should follow the same approach as the Classic BT. And will share the same underlying driver (BtDriver
). There is even a commented out code that is midway into implementing BLE on top of Bluedroid.
As for BLE - at least the Bluedroid APIs can also be easily mapped as they should follow the same approach as the Classic BT. And will share the same underlying driver (
BtDriver
). There is even a commented out code that is midway into implementing BLE on top of Bluedroid.
Hi ivmarkov, just found this thread after searching for BLE support on the esp32-c3 in Rust. Can you elaborate a bit on what needs to be done and how I could get a first example running? You mentioned some commented out code, I guess you mean this? https://github.com/esp-rs/esp-idf-svc/blob/master/src/bt/ble/gatt/server.rs#L265
I have also tried to compile bluedroid with the latest cargo packages and esp-idf v5.1 in the meantime (https://github.com/thedevleon/bluedroid/tree/upgrade), but it fails with a lot of errors regarding pthreads (same error messages as here: https://github.com/esp-rs/esp-idf-hal/issues/289).
I'd also be very interested to know how to get started with BLE using this library, or what still needs doing.
I've managed to get a simple BLE GATT server working using the following library https://github.com/pyaillet/esp-idf-ble, but I'd much rather use this "official" well maintained libary. Thanks for all the work on it!
I'd also be very interested to know how to get started with BLE using this library, or what still needs doing.
I've managed to get a simple BLE GATT server working using the following library https://github.com/pyaillet/esp-idf-ble, but I'd much rather use this "official" well maintained libary. Thanks for all the work on it!
In the meantime, I have found this library, which works very well and covers all my needs: https://lib.rs/crates/esp32-nimble
I'd also be very interested to know how to get started with BLE using this library, or what still needs doing. I've managed to get a simple BLE GATT server working using the following library https://github.com/pyaillet/esp-idf-ble, but I'd much rather use this "official" well maintained libary. Thanks for all the work on it!
In the meantime, I have found this library, which works very well and covers all my needs: https://lib.rs/crates/esp32-nimble
I've actually also tried to use this library, but failed to get it working since the rest of my project is using the standard library. As far as I understand the esp32-nimble crate works only in an no-std environment?
I've actually also tried to use this library, but failed to get it working since the rest of my project is using the standard library. As far as I understand the esp32-nimble crate works only in an no-std environment?
No, completely the opposite. esp32-nimble
seems to require ESP IDF and it does depend on esp-idf-svc
and friends.
I've actually also tried to use this library, but failed to get it working since the rest of my project is using the standard library. As far as I understand the esp32-nimble crate works only in an no-std environment?
No, completely the opposite.
esp32-nimble
seems to require ESP IDF and it does depend onesp-idf-svc
and friends.
That's what I thought when I first found it! But when I looked through the examples (eg: https://github.com/taks/esp32-nimble/blob/develop/examples/ble_server.rs) it says #![no_std] and that made me terribly confused. I also just tried the code in my project verbatim (apart from the no_std annotation mentioned above) and couldn't get it working, so I chalked it up to the std <> no_std divide. I'm probably making a big reasoning error somewhere, but can't figure out where!
I'd also be very interested to know how to get started with BLE using this library, or what still needs doing.
I've managed to get a simple BLE GATT server working using the following library https://github.com/pyaillet/esp-idf-ble, but I'd much rather use this "official" well maintained libary. Thanks for all the work on it!
@FrigoEU @thedevleon There are not yet "official" bindings for BLE, yet what is there is pretty close: you need to uncomment this line and then work on the ble
module by making it compile and then fix all possible bugs.
The ble
module is based on BlueDroid though, not on NimBLE. We might have NimBLE
implementation in future as well, but I have no time for that, so somebody has to pick it up. Perhaps by taking the esp32-nimble
project, adjusting it to work on top of esp-idf-svc
's BtDriver
, removing as many allocations as possible (we don't usually need those), and making the API similar (or identical) to the one via which BlueDroid BLE is exposed. As in getting rid of all the Lazy
/ OnceCell
stuff by following the singleton pattern used for BtDriver
and for the ClassicBT servers (Gap, A2dp, Avrc and so on).
If you are just starting with embedded, this is not an easy task. In the meantime, just use esp32-nimble
.
@jasta is anyway working on BLE traits, and I think he has a working implementation on top of NimBLE for the esp32.
@taks might be interested in contributing his lib into esp-idf-svc
as well.
I've actually also tried to use this library, but failed to get it working since the rest of my project is using the standard library. As far as I understand the esp32-nimble crate works only in an no-std environment?
No, completely the opposite.
esp32-nimble
seems to require ESP IDF and it does depend onesp-idf-svc
and friends.That's what I thought when I first found it! But when I looked through the examples (eg: https://github.com/taks/esp32-nimble/blob/develop/examples/ble_server.rs) it says #![no_std] and that made me terribly confused. I also just tried the code in my project verbatim (apart from the no_std annotation mentioned above) and couldn't get it working, so I chalked it up to the std <> no_std divide. I'm probably making a big reasoning error somewhere, but can't figure out where!
That's because most of the esp-rs
folks are constantly branding the ESP IDF
(esp-idf-*
) crates as the "STD" crates, which - to the community - often means "STD"-only, while what it actually means is that these crates CAN be used, and DO support "STD" as well, but don't mandate it. In contrast, the baremetal (esp-hal
) crates DO NOT support "std" simply because - unlike the esp-idf-*
crates - they do not "implement" the STD threads, sockets etc. Not that the esp-idf-*
crates "implement" sockets and threads themselves. Actually ESP IDF itself does, by providing a POSIX API, which Rust STD library upstream can map and use directly (well, almost directly - we had to upstream a few changes to upstream Rust STD library so that it maps ESP IDF cleanly back in time.)
Regardless, esp-idf-*
crates can also be compiled and used with no_std
as well, and also with or without alloc
(though without alloc
a lot of functionality is missing). Because in general, no_std
is a strict subset of STD, not a negation of it.
And @taks probably did his crate no_std
simply because "why not". And he was right. Why not - using no_std
makes you think what APIs you really need - and - moreover, when you really need alloc
. Especially useful for libraries. That's also why the esp-idf-*
crates are no_std
-compatible as well. Even if 99.9% of the community (in their "apps", not libraries) uses them with STD, as STD gives them threads, sockets and whatnot which are otherwise difficult.
That really clarifies a lot. Thank you so much! I'll read this again tomorrow until it's engrained in my brain :).
In the meantime, I'll see why esp32-nimble wasn't working for me.
That really clarifies a lot. Thank you so much! I'll read this again tomorrow until it's engrained in my brain :).
In the meantime, I'll see why esp32-nimble wasn't working for me.
Just take this example again, paste it in a esp-idf-template
-generated project with "STD enabled", remove all #[]
annotations, and try to compile. It should work fine then.
Oh and remove this completely:
#[panic_handler]
#[allow(dead_code)]
fn panic(info: &core::panic::PanicInfo) -> ! {
::log::error!("{:?}", info);
unsafe { esp_idf_sys::abort() }
}
@jasta is anyway working on BLE traits, and I think he has a working implementation on top of NimBLE for the esp32. @taks might be interested in contributing his lib into
esp-idf-svc
as well.
I haven't implemented ble-peripheral
for esp32 yet (I implemented bluer-ble-peripheral for the host first because it's way easier to test), but based on your feedback and seeing some potentially thorny gotchas I'm going to start looking at that now. I don't anticipate this work will take me more than a few weeks to settle and publish to crates.io.
That really clarifies a lot. Thank you so much! I'll read this again tomorrow until it's engrained in my brain :).
In the meantime, I'll see why esp32-nimble wasn't working for me.
Here I leave you the basic example using the esp-idf (STD) crate.
It works for esp32-c3 but I have not tested it for esp32. Be careful because they recently updated the crate to version 0.2.1 and it does not work for me with this new version, it works for me with version 0.2.0
I use this library but keep in mind that if you are going to use it with iPhone, there are some things that don't quite go well for me with the bounding issue
https://github.com/taks/esp32-nimble/issues/24
I hope this helps you.
use esp_idf_sys as _; // If using the `binstart` feature of `esp-idf-sys`, always keep this module imported
use log::*;
use esp32_nimble::{uuid128, BLEDevice, NimbleProperties};
fn main() {
// It is necessary to call this function once. Otherwise some patches to the runtime
// implemented by esp-idf-sys might not link properly. See https://github.com/esp-rs/esp-idf-template/issues/71
esp_idf_sys::link_patches();
// Bind the log crate to the ESP Logging facilities
esp_idf_svc::log::EspLogger::initialize_default();
info!("Hello, world!");
let ble_device = BLEDevice::take();
let server = ble_device.get_server();
server.on_connect(|server, desc| {
info!("Client connected");
server
.update_conn_params(desc.conn_handle, 24, 48, 0, 60)
.unwrap();
::log::info!("Multi-connect support: start advertising");
ble_device.get_advertising().start().unwrap();
});
let service = server.create_service(uuid128!("fafafafa-fafa-fafa-fafa-fafafafafafa"));
// A static characteristic.
let static_characteristic = service.lock().create_characteristic(
uuid128!("d4e0e0d0-1a2b-11e9-ab14-d663bd873d93"),
NimbleProperties::READ,
);
static_characteristic
.lock()
.set_value("Hello, world!".as_bytes());
// A characteristic that notifies every second.
let notifying_characteristic = service.lock().create_characteristic(
uuid128!("a3c87500-8ed3-4bdf-8a39-a01bebede295"),
NimbleProperties::READ | NimbleProperties::NOTIFY,
);
notifying_characteristic.lock().set_value(b"Initial value.");
// A writable characteristic.
let writable_characteristic = service.lock().create_characteristic(
uuid128!("3c9a3f00-8ed3-4bdf-8a39-a01bebede295"),
NimbleProperties::READ | NimbleProperties::WRITE,
);
writable_characteristic
.lock()
.on_read(move |_, _| {
::log::info!("Read from writable characteristic.");
})
.on_write(move |args| {
::log::info!("Wrote to writable characteristic: {:?}", args.recv_data);
});
let ble_advertising = ble_device.get_advertising();
ble_advertising
.name("ESP32-C3")
.add_service_uuid(uuid128!("68f41eac-ee28-11ec-8ea0-0242ac120002"));
ble_advertising.start().unwrap();
let mut counter = 0;
loop {
esp_idf_hal::delay::FreeRtos::delay_ms(1000);
notifying_characteristic
.lock()
.set_value(format!("Counter: {counter}").as_bytes())
.notify();
counter += 1;
}
}
Hey Larry,
Thanks a lot for your time!
In the meantime I also managed to get esp32-nimble working on my project. However, I did have to downgrade to version 1.4. Both 2.0 and 2.1 didn't work well for me. See https://github.com/taks/esp32-nimble/issues/29
What is preventing adding 'esp32-nimble' to 'esp-idf-svc' and closing this issue?
What is preventing adding 'esp32-nimble' to 'esp-idf-svc' and closing this issue?
@taks Any interest in contributing your library and merging it/adjusting it with what is already available here?
What is preventing adding 'esp32-nimble' to 'esp-idf-svc' and closing this issue?
ble alone is a huge thing by itself, and the development is still pretty much underway, so a lot of breaking things. esp-idf-svc is also not finished in that sense, but i think it make sense for ergonomic reasons to have them separated until they settled down a bit.
But i think we can try to promote esp-nimble more inside esp-idf-* eco system so the discoverability is better for interested users.
@taks Any interest in contributing your library and merging it/adjusting it with what is already available here?
Currently, 'esp32-nimble' has some bad code and I frequently modify it. (includes breaking changes) I'm interested in merging into 'esp-idf-svc', but merging requires more modifications.
As @Vollbrecht mentioned, I think it's better to develop them separately until they settled down a bit.
Is there any gatt client library available? Nimble has some bugs that are still unresolved and cannot be used
Is there any gatt client library available? Nimble has some bugs that are still unresolved and cannot be used
Gatt "client" library specifically, or gatt server/peripheral, which is in 99% what you need in the MCU?
There are now also Bluedroid bindings in the esp-idf-svc
itself, so you can try these. Here's an example. You need to pass the experimental
feature to esp-idf-svc
for these though.
Is there any gatt client library available? Nimble has some bugs that are still unresolved and cannot be used
Gatt "client" library specifically, or gatt server/peripheral, which is in 99% what you need in the MCU?
There are now also Bluedroid bindings in the
esp-idf-svc
itself, so you can try these. Here's an example. You need to pass theexperimental
feature toesp-idf-svc
for these though.
ble controller
Is there any gatt client library available? Nimble has some bugs that are still unresolved and cannot be used
Gatt "client" library specifically, or gatt server/peripheral, which is in 99% what you need in the MCU? There are now also Bluedroid bindings in the
esp-idf-svc
itself, so you can try these. Here's an example. You need to pass theexperimental
feature toesp-idf-svc
for these though.ble controller
You always need a BLE controller and there is one. But after that, your device has to assume either the role of a gatt server/peripheral or a gatt client. Or both (which is rare).
Oh well. You have the example and the exposed APIs in esp-idf-svc
so I guess you can see for yourself whether what is there would suit your needs or not. :)
Closing since the Bluedroid bindings are available since the last release of esp-idf-svc
.
I am trying to use the esp32 Wifi+Bluetooth module. Although the wifi functionality is working I did not find any way of getting the Bluetooth to work using Rust.
It would be great to have this option as well since many IoT projects require Bluetooth support.