mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-29 21:30:39 +00:00

* Add a timer-driven task * Spawn another timer * Log * foo * Do not access current time on each schedule * Update generic queue * Minimize alarm priorities * Point to github with patches * Fix build without any queue impl selected * Remove explicit generic-queue features * Define cfgs, fix calling something uninitialized * Clean up RefCell+generic queue * Fix arg order * Feature * Fix single integrated-timer queue * Fix next expiration when arming * Add note * Adjust impl to latest changes * Local patch * Refactor the refactor refactor * Track the timer item's owner * Clear owner on dequeue * Clean up * Point at the right branch * Fix panic message * Hide private function * Remove integrated-timer references * Point at upstream embassy * Configure via esp-config * Document, clean up, fix * Hack * Remove patches * Update config separator, test the complex variant * Undo esp-config hack * Remove trouble example, update edge-net * Update test deps * Document * Update bt-hci. * Fix generic queue * Fix panic message * Fix UB * Fix rebase * Resolve UB * Avoid mutable reference in interrupt executor --------- Co-authored-by: Dario Nieuwenhuis <dirbaio@dirbaio.net>
188 lines
5.9 KiB
Rust
188 lines
5.9 KiB
Rust
//! Embassy BLE Example
|
|
//!
|
|
//! - starts Bluetooth advertising
|
|
//! - offers one service with three characteristics (one is read/write, one is write only, one is read/write/notify)
|
|
//! - pressing the boot-button on a dev-board will send a notification if it is subscribed
|
|
|
|
//% FEATURES: embassy esp-wifi esp-wifi/ble esp-hal/unstable
|
|
//% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 esp32h2
|
|
|
|
#![no_std]
|
|
#![no_main]
|
|
|
|
use core::cell::RefCell;
|
|
|
|
use bleps::{
|
|
ad_structure::{
|
|
create_advertising_data,
|
|
AdStructure,
|
|
BR_EDR_NOT_SUPPORTED,
|
|
LE_GENERAL_DISCOVERABLE,
|
|
},
|
|
async_attribute_server::AttributeServer,
|
|
asynch::Ble,
|
|
attribute_server::NotificationData,
|
|
gatt,
|
|
};
|
|
use embassy_executor::Spawner;
|
|
use esp_alloc as _;
|
|
use esp_backtrace as _;
|
|
use esp_hal::{
|
|
clock::CpuClock,
|
|
gpio::{Input, Pull},
|
|
rng::Rng,
|
|
time,
|
|
timer::timg::TimerGroup,
|
|
};
|
|
use esp_println::println;
|
|
use esp_wifi::{ble::controller::BleConnector, init, EspWifiController};
|
|
|
|
// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html
|
|
macro_rules! mk_static {
|
|
($t:ty,$val:expr) => {{
|
|
static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
|
|
#[deny(unused_attributes)]
|
|
let x = STATIC_CELL.uninit().write(($val));
|
|
x
|
|
}};
|
|
}
|
|
|
|
#[esp_hal_embassy::main]
|
|
async fn main(_spawner: Spawner) -> ! {
|
|
esp_println::logger::init_logger_from_env();
|
|
let config = esp_hal::Config::default().with_cpu_clock(CpuClock::max());
|
|
let peripherals = esp_hal::init(config);
|
|
|
|
esp_alloc::heap_allocator!(72 * 1024);
|
|
|
|
let timg0 = TimerGroup::new(peripherals.TIMG0);
|
|
|
|
let init = &*mk_static!(
|
|
EspWifiController<'static>,
|
|
init(
|
|
timg0.timer0,
|
|
Rng::new(peripherals.RNG),
|
|
peripherals.RADIO_CLK,
|
|
)
|
|
.unwrap()
|
|
);
|
|
|
|
cfg_if::cfg_if! {
|
|
if #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] {
|
|
let button = Input::new(peripherals.GPIO0, Pull::Down);
|
|
} else {
|
|
let button = Input::new(peripherals.GPIO9, Pull::Down);
|
|
}
|
|
}
|
|
|
|
cfg_if::cfg_if! {
|
|
if #[cfg(feature = "esp32")] {
|
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
|
esp_hal_embassy::init(timg1.timer0);
|
|
} else {
|
|
use esp_hal::timer::systimer::SystemTimer;
|
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
|
esp_hal_embassy::init(systimer.alarm0);
|
|
}
|
|
}
|
|
|
|
let mut bluetooth = peripherals.BT;
|
|
|
|
let connector = BleConnector::new(&init, &mut bluetooth);
|
|
|
|
let now = || time::now().duration_since_epoch().to_millis();
|
|
let mut ble = Ble::new(connector, now);
|
|
println!("Connector created");
|
|
|
|
let pin_ref = RefCell::new(button);
|
|
let pin_ref = &pin_ref;
|
|
|
|
loop {
|
|
println!("{:?}", ble.init().await);
|
|
println!("{:?}", ble.cmd_set_le_advertising_parameters().await);
|
|
println!(
|
|
"{:?}",
|
|
ble.cmd_set_le_advertising_data(
|
|
create_advertising_data(&[
|
|
AdStructure::Flags(LE_GENERAL_DISCOVERABLE | BR_EDR_NOT_SUPPORTED),
|
|
AdStructure::ServiceUuids16(&[Uuid::Uuid16(0x1809)]),
|
|
AdStructure::CompleteLocalName(esp_hal::chip!()),
|
|
])
|
|
.unwrap()
|
|
)
|
|
.await
|
|
);
|
|
println!("{:?}", ble.cmd_set_le_advertise_enable(true).await);
|
|
|
|
println!("started advertising");
|
|
|
|
let mut rf = |_offset: usize, data: &mut [u8]| {
|
|
data[..20].copy_from_slice(&b"Hello Bare-Metal BLE"[..]);
|
|
17
|
|
};
|
|
let mut wf = |offset: usize, data: &[u8]| {
|
|
println!("RECEIVED: {} {:?}", offset, data);
|
|
};
|
|
|
|
let mut wf2 = |offset: usize, data: &[u8]| {
|
|
println!("RECEIVED: {} {:?}", offset, data);
|
|
};
|
|
|
|
let mut rf3 = |_offset: usize, data: &mut [u8]| {
|
|
data[..5].copy_from_slice(&b"Hola!"[..]);
|
|
5
|
|
};
|
|
let mut wf3 = |offset: usize, data: &[u8]| {
|
|
println!("RECEIVED: Offset {}, data {:?}", offset, data);
|
|
};
|
|
|
|
gatt!([service {
|
|
uuid: "937312e0-2354-11eb-9f10-fbc30a62cf38",
|
|
characteristics: [
|
|
characteristic {
|
|
uuid: "937312e0-2354-11eb-9f10-fbc30a62cf38",
|
|
read: rf,
|
|
write: wf,
|
|
},
|
|
characteristic {
|
|
uuid: "957312e0-2354-11eb-9f10-fbc30a62cf38",
|
|
write: wf2,
|
|
},
|
|
characteristic {
|
|
name: "my_characteristic",
|
|
uuid: "987312e0-2354-11eb-9f10-fbc30a62cf38",
|
|
notify: true,
|
|
read: rf3,
|
|
write: wf3,
|
|
},
|
|
],
|
|
},]);
|
|
|
|
let mut rng = bleps::no_rng::NoRng;
|
|
let mut srv = AttributeServer::new(&mut ble, &mut gatt_attributes, &mut rng);
|
|
|
|
let counter = RefCell::new(0u8);
|
|
let counter = &counter;
|
|
|
|
let mut notifier = || {
|
|
// TODO how to check if notifications are enabled for the characteristic?
|
|
// maybe pass something into the closure which just can query the characteristic
|
|
// value probably passing in the attribute server won't work?
|
|
|
|
async {
|
|
pin_ref.borrow_mut().wait_for_rising_edge().await;
|
|
let mut data = [0u8; 13];
|
|
data.copy_from_slice(b"Notification0");
|
|
{
|
|
let mut counter = counter.borrow_mut();
|
|
data[data.len() - 1] += *counter;
|
|
*counter = (*counter + 1) % 10;
|
|
}
|
|
NotificationData::new(my_characteristic_handle, &data)
|
|
}
|
|
};
|
|
|
|
srv.run(&mut notifier).await.unwrap();
|
|
}
|
|
}
|