esp-idf-svc icon indicating copy to clipboard operation
esp-idf-svc copied to clipboard

BLE support missing

Open monacoprinsen opened this issue 3 years ago • 24 comments

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.

monacoprinsen avatar Feb 25 '22 21:02 monacoprinsen

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.

jessebraham avatar Mar 01 '22 17:03 jessebraham

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.

lherman-cs avatar Aug 29 '22 15:08 lherman-cs

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.

ivmarkov avatar Aug 30 '22 03:08 ivmarkov

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.

wassup- avatar Mar 04 '23 09:03 wassup-

If it's useful to you, I created a bluedroid wrapper: https://github.com/persello/bluedroid.

persello avatar Mar 04 '23 15:03 persello

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.

ivmarkov avatar Sep 21 '23 15:09 ivmarkov

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).

thedevleon avatar Sep 29 '23 18:09 thedevleon

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 avatar Oct 12 '23 11:10 FrigoEU

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

thedevleon avatar Oct 12 '23 12:10 thedevleon

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?

FrigoEU avatar Oct 12 '23 12:10 FrigoEU

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.

ivmarkov avatar Oct 12 '23 12:10 ivmarkov

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.

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!

FrigoEU avatar Oct 12 '23 12:10 FrigoEU

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.

ivmarkov avatar Oct 12 '23 12:10 ivmarkov

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.

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.

ivmarkov avatar Oct 12 '23 13:10 ivmarkov

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.

FrigoEU avatar Oct 12 '23 13:10 FrigoEU

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.

ivmarkov avatar Oct 12 '23 14:10 ivmarkov

Oh and remove this completely:

#[panic_handler]
#[allow(dead_code)]
fn panic(info: &core::panic::PanicInfo) -> ! {
  ::log::error!("{:?}", info);
  unsafe { esp_idf_sys::abort() }
}

ivmarkov avatar Oct 12 '23 14:10 ivmarkov

@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.

jasta avatar Oct 12 '23 19:10 jasta

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;
    }
}

LarryMerino avatar Oct 13 '23 07:10 LarryMerino

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

FrigoEU avatar Oct 13 '23 08:10 FrigoEU

What is preventing adding 'esp32-nimble' to 'esp-idf-svc' and closing this issue?

vaknin avatar Jan 30 '24 18:01 vaknin

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?

ivmarkov avatar Jan 30 '24 18:01 ivmarkov

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.

Vollbrecht avatar Jan 30 '24 18:01 Vollbrecht

@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.

taks avatar Jan 31 '24 01:01 taks