diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-08-05 20:58:04 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2024-08-05 21:07:42 +0200 |
| commit | 4f7ac1946a43379306aa432961fb97bba1139a6e (patch) | |
| tree | 2589e67baa770acf244dfdea355e16585d683d16 /examples | |
| parent | afc8e684dd16c3bc947b365ca293f0f37d95b342 (diff) | |
cyw43: add Bluetooth support.
Co-Authored-By: Brandon Ros <[email protected]>
Diffstat (limited to 'examples')
| -rw-r--r-- | examples/rp/Cargo.toml | 17 | ||||
| -rw-r--r-- | examples/rp/src/bin/bluetooth.rs | 148 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_ap_tcp_server.rs | 4 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_blinky.rs | 4 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_scan.rs | 4 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_tcp_server.rs | 8 | ||||
| -rw-r--r-- | examples/rp/src/bin/wifi_webrequest.rs | 4 |
7 files changed, 175 insertions, 14 deletions
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml index 4945f4bd2..2884ca85a 100644 --- a/examples/rp/Cargo.toml +++ b/examples/rp/Cargo.toml | |||
| @@ -16,8 +16,8 @@ embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defm | |||
| 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } | 16 | embassy-net-wiznet = { version = "0.1.0", path = "../../embassy-net-wiznet", features = ["defmt"] } |
| 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } | 17 | embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } |
| 18 | embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } | 18 | embassy-usb-logger = { version = "0.2.0", path = "../../embassy-usb-logger" } |
| 19 | cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs"] } | 19 | cyw43 = { version = "0.2.0", path = "../../cyw43", features = ["defmt", "firmware-logs", "bluetooth"] } |
| 20 | cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt", "overclock"] } | 20 | cyw43-pio = { version = "0.2.0", path = "../../cyw43-pio", features = ["defmt"] } |
| 21 | 21 | ||
| 22 | defmt = "0.3" | 22 | defmt = "0.3" |
| 23 | defmt-rtt = "0.4" | 23 | defmt-rtt = "0.4" |
| @@ -59,9 +59,22 @@ pio = "0.2.1" | |||
| 59 | rand = { version = "0.8.5", default-features = false } | 59 | rand = { version = "0.8.5", default-features = false } |
| 60 | embedded-sdmmc = "0.7.0" | 60 | embedded-sdmmc = "0.7.0" |
| 61 | 61 | ||
| 62 | bt-hci = { version = "0.1.0", default-features = false, features = ["defmt"] } | ||
| 63 | trouble-host = { version = "0.1.0", features = ["defmt", "gatt"] } | ||
| 64 | |||
| 62 | [profile.release] | 65 | [profile.release] |
| 63 | debug = 2 | 66 | debug = 2 |
| 64 | 67 | ||
| 65 | [profile.dev] | 68 | [profile.dev] |
| 66 | lto = true | 69 | lto = true |
| 67 | opt-level = "z" | 70 | opt-level = "z" |
| 71 | |||
| 72 | [patch.crates-io] | ||
| 73 | trouble-host = { git = "https://github.com/embassy-rs/trouble.git", rev = "4b8c0f499b34e46ca23a56e2d1640ede371722cf" } | ||
| 74 | bt-hci = { git = "https://github.com/alexmoon/bt-hci.git", rev = "b9cd5954f6bd89b535cad9c418e9fdf12812d7c3" } | ||
| 75 | embassy-executor = { path = "../../embassy-executor" } | ||
| 76 | embassy-sync = { path = "../../embassy-sync" } | ||
| 77 | embassy-futures = { path = "../../embassy-futures" } | ||
| 78 | embassy-time = { path = "../../embassy-time" } | ||
| 79 | embassy-time-driver = { path = "../../embassy-time-driver" } | ||
| 80 | embassy-embedded-hal = { path = "../../embassy-embedded-hal" } | ||
diff --git a/examples/rp/src/bin/bluetooth.rs b/examples/rp/src/bin/bluetooth.rs new file mode 100644 index 000000000..901521b60 --- /dev/null +++ b/examples/rp/src/bin/bluetooth.rs | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | //! This example test the RP Pico W on board LED. | ||
| 2 | //! | ||
| 3 | //! It does not work with the RP Pico board. See blinky.rs. | ||
| 4 | |||
| 5 | #![no_std] | ||
| 6 | #![no_main] | ||
| 7 | |||
| 8 | use bt_hci::controller::ExternalController; | ||
| 9 | use cyw43_pio::PioSpi; | ||
| 10 | use defmt::*; | ||
| 11 | use embassy_executor::Spawner; | ||
| 12 | use embassy_futures::join::join3; | ||
| 13 | use embassy_rp::bind_interrupts; | ||
| 14 | use embassy_rp::gpio::{Level, Output}; | ||
| 15 | use embassy_rp::peripherals::{DMA_CH0, PIO0}; | ||
| 16 | use embassy_rp::pio::{InterruptHandler, Pio}; | ||
| 17 | use embassy_sync::blocking_mutex::raw::NoopRawMutex; | ||
| 18 | use embassy_time::{Duration, Timer}; | ||
| 19 | use static_cell::StaticCell; | ||
| 20 | use trouble_host::advertise::{AdStructure, Advertisement, BR_EDR_NOT_SUPPORTED, LE_GENERAL_DISCOVERABLE}; | ||
| 21 | use trouble_host::attribute::{AttributeTable, CharacteristicProp, Service, Uuid}; | ||
| 22 | use trouble_host::gatt::GattEvent; | ||
| 23 | use trouble_host::{Address, BleHost, BleHostResources, PacketQos}; | ||
| 24 | use {defmt_rtt as _, embassy_time as _, panic_probe as _}; | ||
| 25 | |||
| 26 | bind_interrupts!(struct Irqs { | ||
| 27 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | ||
| 28 | }); | ||
| 29 | |||
| 30 | #[embassy_executor::task] | ||
| 31 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | ||
| 32 | runner.run().await | ||
| 33 | } | ||
| 34 | |||
| 35 | #[embassy_executor::main] | ||
| 36 | async fn main(spawner: Spawner) { | ||
| 37 | let p = embassy_rp::init(Default::default()); | ||
| 38 | let fw = include_bytes!("../../../../cyw43-firmware/43439A0.bin"); | ||
| 39 | let clm = include_bytes!("../../../../cyw43-firmware/43439A0_clm.bin"); | ||
| 40 | let btfw = include_bytes!("../../../../cyw43-firmware/43439A0_btfw.bin"); | ||
| 41 | |||
| 42 | // To make flashing faster for development, you may want to flash the firmwares independently | ||
| 43 | // at hardcoded addresses, instead of baking them into the program with `include_bytes!`: | ||
| 44 | // probe-rs download 43439A0.bin --format bin --chip RP2040 --base-address 0x10100000 | ||
| 45 | // probe-rs download 43439A0_clm.bin --format bin --chip RP2040 --base-address 0x10140000 | ||
| 46 | //let fw = unsafe { core::slice::from_raw_parts(0x10100000 as *const u8, 224190) }; | ||
| 47 | //let clm = unsafe { core::slice::from_raw_parts(0x10140000 as *const u8, 4752) }; | ||
| 48 | |||
| 49 | let pwr = Output::new(p.PIN_23, Level::Low); | ||
| 50 | let cs = Output::new(p.PIN_25, Level::High); | ||
| 51 | let mut pio = Pio::new(p.PIO0, Irqs); | ||
| 52 | let spi = PioSpi::new(&mut pio.common, pio.sm0, pio.irq0, cs, p.PIN_24, p.PIN_29, p.DMA_CH0); | ||
| 53 | |||
| 54 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | ||
| 55 | let state = STATE.init(cyw43::State::new()); | ||
| 56 | let (_net_device, bt_device, mut control, runner) = cyw43::new_with_bluetooth(state, pwr, spi, fw, btfw).await; | ||
| 57 | unwrap!(spawner.spawn(cyw43_task(runner))); | ||
| 58 | control.init(clm).await; | ||
| 59 | |||
| 60 | let controller: ExternalController<_, 10> = ExternalController::new(bt_device); | ||
| 61 | static HOST_RESOURCES: StaticCell<BleHostResources<4, 32, 27>> = StaticCell::new(); | ||
| 62 | let host_resources = HOST_RESOURCES.init(BleHostResources::new(PacketQos::None)); | ||
| 63 | |||
| 64 | let mut ble: BleHost<'_, _> = BleHost::new(controller, host_resources); | ||
| 65 | |||
| 66 | ble.set_random_address(Address::random([0xff, 0x9f, 0x1a, 0x05, 0xe4, 0xff])); | ||
| 67 | let mut table: AttributeTable<'_, NoopRawMutex, 10> = AttributeTable::new(); | ||
| 68 | |||
| 69 | // Generic Access Service (mandatory) | ||
| 70 | let id = b"Pico W Bluetooth"; | ||
| 71 | let appearance = [0x80, 0x07]; | ||
| 72 | let mut bat_level = [0; 1]; | ||
| 73 | let handle = { | ||
| 74 | let mut svc = table.add_service(Service::new(0x1800)); | ||
| 75 | let _ = svc.add_characteristic_ro(0x2a00, id); | ||
| 76 | let _ = svc.add_characteristic_ro(0x2a01, &appearance[..]); | ||
| 77 | svc.build(); | ||
| 78 | |||
| 79 | // Generic attribute service (mandatory) | ||
| 80 | table.add_service(Service::new(0x1801)); | ||
| 81 | |||
| 82 | // Battery service | ||
| 83 | let mut svc = table.add_service(Service::new(0x180f)); | ||
| 84 | |||
| 85 | svc.add_characteristic( | ||
| 86 | 0x2a19, | ||
| 87 | &[CharacteristicProp::Read, CharacteristicProp::Notify], | ||
| 88 | &mut bat_level, | ||
| 89 | ) | ||
| 90 | .build() | ||
| 91 | }; | ||
| 92 | |||
| 93 | let mut adv_data = [0; 31]; | ||
| 94 | AdStructure::encode_slice( | ||
| 95 | &[ | ||
| 96 | AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED), | ||
| 97 | AdStructure::ServiceUuids16(&[Uuid::Uuid16([0x0f, 0x18])]), | ||
| 98 | AdStructure::CompleteLocalName(b"Pico W Bluetooth"), | ||
| 99 | ], | ||
| 100 | &mut adv_data[..], | ||
| 101 | ) | ||
| 102 | .unwrap(); | ||
| 103 | |||
| 104 | let server = ble.gatt_server(&table); | ||
| 105 | |||
| 106 | info!("Starting advertising and GATT service"); | ||
| 107 | let _ = join3( | ||
| 108 | ble.run(), | ||
| 109 | async { | ||
| 110 | loop { | ||
| 111 | match server.next().await { | ||
| 112 | Ok(GattEvent::Write { handle, connection: _ }) => { | ||
| 113 | let _ = table.get(handle, |value| { | ||
| 114 | info!("Write event. Value written: {:?}", value); | ||
| 115 | }); | ||
| 116 | } | ||
| 117 | Ok(GattEvent::Read { .. }) => { | ||
| 118 | info!("Read event"); | ||
| 119 | } | ||
| 120 | Err(e) => { | ||
| 121 | error!("Error processing GATT events: {:?}", e); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | } | ||
| 125 | }, | ||
| 126 | async { | ||
| 127 | let mut advertiser = ble | ||
| 128 | .advertise( | ||
| 129 | &Default::default(), | ||
| 130 | Advertisement::ConnectableScannableUndirected { | ||
| 131 | adv_data: &adv_data[..], | ||
| 132 | scan_data: &[], | ||
| 133 | }, | ||
| 134 | ) | ||
| 135 | .await | ||
| 136 | .unwrap(); | ||
| 137 | let conn = advertiser.accept().await.unwrap(); | ||
| 138 | // Keep connection alive | ||
| 139 | let mut tick: u8 = 0; | ||
| 140 | loop { | ||
| 141 | Timer::after(Duration::from_secs(10)).await; | ||
| 142 | tick += 1; | ||
| 143 | server.notify(handle, &conn, &[tick]).await.unwrap(); | ||
| 144 | } | ||
| 145 | }, | ||
| 146 | ) | ||
| 147 | .await; | ||
| 148 | } | ||
diff --git a/examples/rp/src/bin/wifi_ap_tcp_server.rs b/examples/rp/src/bin/wifi_ap_tcp_server.rs index 4fc2690e3..b5fbd8e36 100644 --- a/examples/rp/src/bin/wifi_ap_tcp_server.rs +++ b/examples/rp/src/bin/wifi_ap_tcp_server.rs | |||
| @@ -28,7 +28,7 @@ bind_interrupts!(struct Irqs { | |||
| 28 | }); | 28 | }); |
| 29 | 29 | ||
| 30 | #[embassy_executor::task] | 30 | #[embassy_executor::task] |
| 31 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 31 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { |
| 32 | runner.run().await | 32 | runner.run().await |
| 33 | } | 33 | } |
| 34 | 34 | ||
| @@ -62,7 +62,7 @@ async fn main(spawner: Spawner) { | |||
| 62 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | 62 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); |
| 63 | let state = STATE.init(cyw43::State::new()); | 63 | let state = STATE.init(cyw43::State::new()); |
| 64 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 64 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 65 | unwrap!(spawner.spawn(wifi_task(runner))); | 65 | unwrap!(spawner.spawn(cyw43_task(runner))); |
| 66 | 66 | ||
| 67 | control.init(clm).await; | 67 | control.init(clm).await; |
| 68 | control | 68 | control |
diff --git a/examples/rp/src/bin/wifi_blinky.rs b/examples/rp/src/bin/wifi_blinky.rs index 471349639..04a61bbd5 100644 --- a/examples/rp/src/bin/wifi_blinky.rs +++ b/examples/rp/src/bin/wifi_blinky.rs | |||
| @@ -21,7 +21,7 @@ bind_interrupts!(struct Irqs { | |||
| 21 | }); | 21 | }); |
| 22 | 22 | ||
| 23 | #[embassy_executor::task] | 23 | #[embassy_executor::task] |
| 24 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 24 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { |
| 25 | runner.run().await | 25 | runner.run().await |
| 26 | } | 26 | } |
| 27 | 27 | ||
| @@ -46,7 +46,7 @@ async fn main(spawner: Spawner) { | |||
| 46 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | 46 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); |
| 47 | let state = STATE.init(cyw43::State::new()); | 47 | let state = STATE.init(cyw43::State::new()); |
| 48 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 48 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 49 | unwrap!(spawner.spawn(wifi_task(runner))); | 49 | unwrap!(spawner.spawn(cyw43_task(runner))); |
| 50 | 50 | ||
| 51 | control.init(clm).await; | 51 | control.init(clm).await; |
| 52 | control | 52 | control |
diff --git a/examples/rp/src/bin/wifi_scan.rs b/examples/rp/src/bin/wifi_scan.rs index 5f4c848a2..ab3529112 100644 --- a/examples/rp/src/bin/wifi_scan.rs +++ b/examples/rp/src/bin/wifi_scan.rs | |||
| @@ -23,7 +23,7 @@ bind_interrupts!(struct Irqs { | |||
| 23 | }); | 23 | }); |
| 24 | 24 | ||
| 25 | #[embassy_executor::task] | 25 | #[embassy_executor::task] |
| 26 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 26 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { |
| 27 | runner.run().await | 27 | runner.run().await |
| 28 | } | 28 | } |
| 29 | 29 | ||
| @@ -56,7 +56,7 @@ async fn main(spawner: Spawner) { | |||
| 56 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | 56 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); |
| 57 | let state = STATE.init(cyw43::State::new()); | 57 | let state = STATE.init(cyw43::State::new()); |
| 58 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 58 | let (_net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 59 | unwrap!(spawner.spawn(wifi_task(runner))); | 59 | unwrap!(spawner.spawn(cyw43_task(runner))); |
| 60 | 60 | ||
| 61 | control.init(clm).await; | 61 | control.init(clm).await; |
| 62 | control | 62 | control |
diff --git a/examples/rp/src/bin/wifi_tcp_server.rs b/examples/rp/src/bin/wifi_tcp_server.rs index 5575df677..87487cbe8 100644 --- a/examples/rp/src/bin/wifi_tcp_server.rs +++ b/examples/rp/src/bin/wifi_tcp_server.rs | |||
| @@ -27,11 +27,11 @@ bind_interrupts!(struct Irqs { | |||
| 27 | PIO0_IRQ_0 => InterruptHandler<PIO0>; | 27 | PIO0_IRQ_0 => InterruptHandler<PIO0>; |
| 28 | }); | 28 | }); |
| 29 | 29 | ||
| 30 | const WIFI_NETWORK: &str = "EmbassyTest"; | 30 | const WIFI_NETWORK: &str = "LadronDeWifi"; |
| 31 | const WIFI_PASSWORD: &str = "V8YxhKt5CdIAJFud"; | 31 | const WIFI_PASSWORD: &str = "MBfcaedHmyRFE4kaQ1O5SsY8"; |
| 32 | 32 | ||
| 33 | #[embassy_executor::task] | 33 | #[embassy_executor::task] |
| 34 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 34 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { |
| 35 | runner.run().await | 35 | runner.run().await |
| 36 | } | 36 | } |
| 37 | 37 | ||
| @@ -65,7 +65,7 @@ async fn main(spawner: Spawner) { | |||
| 65 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | 65 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); |
| 66 | let state = STATE.init(cyw43::State::new()); | 66 | let state = STATE.init(cyw43::State::new()); |
| 67 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 67 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 68 | unwrap!(spawner.spawn(wifi_task(runner))); | 68 | unwrap!(spawner.spawn(cyw43_task(runner))); |
| 69 | 69 | ||
| 70 | control.init(clm).await; | 70 | control.init(clm).await; |
| 71 | control | 71 | control |
diff --git a/examples/rp/src/bin/wifi_webrequest.rs b/examples/rp/src/bin/wifi_webrequest.rs index 70b6f0949..e32be6e45 100644 --- a/examples/rp/src/bin/wifi_webrequest.rs +++ b/examples/rp/src/bin/wifi_webrequest.rs | |||
| @@ -34,7 +34,7 @@ const WIFI_NETWORK: &str = "ssid"; // change to your network SSID | |||
| 34 | const WIFI_PASSWORD: &str = "pwd"; // change to your network password | 34 | const WIFI_PASSWORD: &str = "pwd"; // change to your network password |
| 35 | 35 | ||
| 36 | #[embassy_executor::task] | 36 | #[embassy_executor::task] |
| 37 | async fn wifi_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { | 37 | async fn cyw43_task(runner: cyw43::Runner<'static, Output<'static>, PioSpi<'static, PIO0, 0, DMA_CH0>>) -> ! { |
| 38 | runner.run().await | 38 | runner.run().await |
| 39 | } | 39 | } |
| 40 | 40 | ||
| @@ -67,7 +67,7 @@ async fn main(spawner: Spawner) { | |||
| 67 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); | 67 | static STATE: StaticCell<cyw43::State> = StaticCell::new(); |
| 68 | let state = STATE.init(cyw43::State::new()); | 68 | let state = STATE.init(cyw43::State::new()); |
| 69 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; | 69 | let (net_device, mut control, runner) = cyw43::new(state, pwr, spi, fw).await; |
| 70 | unwrap!(spawner.spawn(wifi_task(runner))); | 70 | unwrap!(spawner.spawn(cyw43_task(runner))); |
| 71 | 71 | ||
| 72 | control.init(clm).await; | 72 | control.init(clm).await; |
| 73 | control | 73 | control |
