embassy-rs / embassy

Modern embedded framework, using Rust and async.
https://embassy.dev
Apache License 2.0
4.81k stars 654 forks source link

cyw43: Bluetooth support #1516

Open segfaultsourcery opened 1 year ago

segfaultsourcery commented 1 year ago

Are there plans to support bluetooth as well? As far as I understand, the CYW43439 chip on the Pico W supports it.

Meigs2 commented 11 months ago

Bluetooth would be nice!

I took a look at the driver we use currently for the cyw43 and it doesn't seem like it supports bluetooth, but that's just a cursory search through the repo.

Meigs2 commented 11 months ago

Well actually, it seems like the driver does have a structure for some bluetooth stuff:

https://infineon.github.io/wifi-host-driver/html/structwhd__btwt__config__params__t.html

brandonros commented 11 months ago

https://github.com/raspberrypi/pico-sdk/releases/tag/1.5.1 looks like it was "added"/made official around here

I think what we'd need to translate/implement is here:

https://github.com/raspberrypi/pico-sdk/tree/master/src/rp2_common/pico_btstack https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_cyw43_driver/include/pico/btstack_cyw43.h

Not sure if a new .bin/different .bin would be needed here: https://github.com/embassy-rs/embassy/tree/main/cyw43-firmware

One concern I see is, that just gets the rp2040 / cyw43 in a state where you can now speak btstack to it, something else that isn't implement in Rust https://github.com/bluekitchen/btstack

Not sure if it'd be easier to write btstack-sys bindings?

edit:

looks like this is of interest https://github.com/raspberrypi/pico-sdk/commit/c8ccefb9726b89d35d230d194d6977705908ffe7

Dirbaio commented 11 months ago

The meat for sending/receiving HCI packets over SPI is here https://github.com/raspberrypi/pico-sdk/tree/master/src/rp2_common/pico_cyw43_driver/cybt_shared_bus

The issue is that will get us only "send/receive HCI packets to the bluetooth controller". We then need a bluetooth host stack on top of that. (the host stack is what implements the higher layers of BLE, like L2CAP, ATT, GATT...).

Pico-sdk is using BTStack as the host stack. It is proprietary, requires licensing to use. RPi and BlueKitchen (the company behind BTStack) have entered some agreement to license BTStack for free on Pico W-based hardware only.

This license does NOT cover other hardware, and we're in the same situation for other hardware: STM32WB[^1] and nRF52/53[^2]'s controller blobs also speak HCI, we also need a host stack for them.

[^1]: they have some kind of higher-level vendor-specific commands for higher-layer protocols. I dunno how complete they are or how nice they're to use compared to a real BLE host stack. [^2]: the "old" softdevice (what's implemented in nrf-softdevice) does have implementations for higher-layer protocols, but it's in "maintenance mode" according to Nordic, doesn'd support nRF53 nor newer Bluetooth features. The newer "softdevice controller" blob is HCI only.

So I think the Embassy project should focus its efforts in getting some bluetooth stack that's freely usable for all hardware we support, not BTstack. There's Bluedroid, NimBLE (C, but I believe the Espressif folks have worked in Rust bindings?) or write one from scratch in Rust, which is a giant undertaking, bleps is one attempt at it.

So, I will take PRs for exposing raw HCI in cyw43, or for integrating some FOSS bluetooth stacks. I will NOT accept PRs working towards integrating BTStack. (if raw HCI is exposed, nothing prevents someone from doing that on their own, of course)

Meigs2 commented 11 months ago

I found this project which looks like has setup cbindgen FFI for NimBLE: https://github.com/benbrittain/apache-nimble-sys

Whether or not this is what we need is another question.

brandonros commented 10 months ago

@Dirbaio I beat the snot out of pico-sdk by littering it hardcore with a bunch of custom uart_printf as well as turning on some debug flags and I got basically how the C pico-sdk library does "bluetooth HCI init" https://gist.github.com/brandonros/b4b952ee97049def55e073e0d8a2f75d

In the name of replicating it for our uses in Rust:

I am a little confused on one thing. I could be wrong but I think the current order of operations on how we split cyw43 init between runner and control makes this hard to implement? Or am I mistaken? I don't really have bus to be able to do bp_read / bp_write to write the Bluetooth firmware in the control context, and I need the clm loaded first, which means I can't do it from runner

The order of operations seems to be (from C land, redacted logs from the gist comments):

cyw43_ll_bus_init
cyw43_spi_init
cyw43_spi_gpio_setup
cyw43_spi_reset
chip_up
...
backplane ready
ALP is set
...
cyw43_clm_load start
...
cyw43_btbus_init
cybt_fw_download

The really painful part about cybt_fw_download is it isn't one continuous .bin we can flash into memory. It's a custom format where it's a bunch of non-4 aligned writes size wise + address wise, so we have to read what is in memory, blend that together with what we want to write, and upload it.

I'll keep hitting on it, just wanted to know if you had any easy guidance to make this a bit less painful. :D

I am with you, we will target bleps, all we need is to implement

use bleps::HciConnection;
impl HciConnection for Cyw43HciConnection {
    fn read(&self) -> Option<u8> {
        panic!("TODO")
    }

    fn write(&self, data: u8) {
        panic!("TODO")
    }

    fn millis(&self) -> u64 {
        panic!("TODO")
    }
}
Dirbaio commented 10 months ago

I saw your PR, pretty excited to see progress on this! :star_struck:

and I need the clm loaded first

are you sure that's needed? Intuitively I'd say the wifi CLM doesn't affect Bluetooth at all. (the cyw43 is more like a bluetooth chip and a wifi chip glued together, each has its own core with different firmware and RAM). If you try initializing BT without loading the CLM it probably works anyway.

If that's not the case, it could be workarounded by putting the bus in an async Mutex so it can be used from both runner and control, but I'd really really like to avoid that.

brandonros commented 10 months ago

Are you sure the cyw43 Bluetooth core isn't the same as the WLAN core?

Dirbaio commented 10 months ago

they aren't, the datasheet has some details, plus the fact that there's two firmwares.

brandonros commented 10 months ago

Could you check https://github.com/georgerobotics/cyw43-driver/blob/main/src/cyw43_ll.c and tell me where you see the additional Bluetooth core? Based on my logs, I do not see anything about any additional cores being brought up/reset but maybe I missed it. I only see device_core_is_up(self, CORE_WLAN_ARM);

Or sorry, it'd probably be here https://github.com/raspberrypi/pico-sdk/blob/master/src/rp2_common/pico_cyw43_driver/cybt_shared_bus/cybt_shared_bus.c#L112

I am working on writing Rust to be able to read/write the needed parsed Bluetooth firmware padded correctly from https://github.com/georgerobotics/cyw43-driver/blob/main/firmware/cyw43_btfw_43439.h, will PR it

Dirbaio commented 10 months ago

the datasheet literally says there's 2 cores.

I think the bluetooth core starts on its own. In a more standard setup (ie not Pico's weird bluetooth-over-SPI) you talk to it via the bluetooth UART, which works even if you haven't initialized the wifi part. That'd explain why there's no code to explicitly start the BT core. It seems the wifi backplane has a window into BT stuff, so the Pico W is (ab?)using that to do bluetooth over SPI.

johnbchron commented 5 months ago

Any movement on this? It would be awesome to have BLE on the Pico W.

mikkelens commented 2 months ago

1820 was the latest PR for this, but was unfortunately closed 3 weeks ago. My guess is that no maintainer is actively prioritizing it at the moment. I hope it gets picked back up before long, since it's been 8 months since it was actively worked on and embassy has progressed a lot since then.

Dirbaio commented 2 months ago

See #2865 for latest status. Help is needed to finish it, contributors welcome!