Hello I have an ESP-32H2 which I successfully tested basically with the example Attribute Server with the GATT Profile (including some embassy), but I seem to be unable to define a new Service after initial flash. I use espflash but i explicitly use it with --no-skip so it should erase and reflash every time.
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
#![feature(async_closure)]
// BLE Example
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_backtrace as _;
use esp_hal::{
clock::ClockControl, embassy, gpio::IO, peripherals::*, prelude::*, rng::Rng, timer::TimerGroup,
};
use esp_println::println;
use esp_wifi::{ble::controller::asynch::BleConnector, initialize, EspWifiInitFor};
pub type BootButton = esp_hal::gpio::Gpio9<esp_hal::gpio::Input<esp_hal::gpio::PullDown>>;
pub const SOC_NAME: &str = "ESP32-H2";
#[main]
async fn main(_spawner: Spawner) -> ! {
#[cfg(feature = "log")]
esp_println::logger::init_logger(log::LevelFilter::Info);
let peripherals = Peripherals::take();
let system = peripherals.SYSTEM.split();
let clocks = ClockControl::max(system.clock_control).freeze();
#[cfg(target_arch = "xtensa")]
let timer = hal::timer::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0;
#[cfg(target_arch = "riscv32")]
let timer = esp_hal::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0;
let init = initialize(
EspWifiInitFor::Ble,
timer,
Rng::new(peripherals.RNG),
system.radio_clock_control,
&clocks,
)
.unwrap();
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let button = io.pins.gpio9.into_pull_down_input();
// Async requires the GPIO interrupt to wake futures
esp_hal::interrupt::enable(
esp_hal::peripherals::Interrupt::GPIO,
esp_hal::interrupt::Priority::Priority1,
)
.unwrap();
let timer_group0 = TimerGroup::new_async(peripherals.TIMG0, &clocks);
embassy::init(&clocks, timer_group0);
let mut bluetooth = peripherals.BT;
let connector = BleConnector::new(&init, &mut bluetooth);
let mut ble = Ble::new(connector, esp_wifi::current_millis);
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(SOC_NAME),
])
.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);
};
// usefull referece https://github.com/bjoernQ/esp32c3-ble-hid/blob/main/src/main.rs#L229-L284
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();
}
}
Now I wanted to change the Server with the gatt macro to this:
gatt!([
service {
uuid: "00001812-0000-1000-8000-00805f9b34fb",
characteristics: [
characteristic {
name: "read_datastore",
uuid: "00002a4a-0000-1000-8000-00805f9b34fb",
read: sync_events_read,
},
characteristic {
name: "write_datastore",
uuid: "00002a4b-0000-1000-8000-00805f9b34fb",
write: sync_events_write,
},
characteristic {
name: "my_characteristic",
uuid: "00002a4c-0000-1000-8000-00805f9b34fb",
notify: true,
read: rf3,
write: wf3,
},
],
},
// Battery LVL, also see PDF for assigned number
// https://forums.developer.apple.com/forums/thread/77866
service {
uuid: "180F", // Battery Service UUID (16-bit)
characteristics: [characteristic {
uuid: "2A19", // Battery Level Characteristic UUID (16-bit)
read: read_battery_lvl
}]
},
]);
but it seems the Service including the characteristics never changes from the original first flashed profile. I tested this as I have a second esp32h2 and this one cannot change from these characteristics back to the example ones.
I do flash with the command "espflash flash --monitor --no-skip" and my .cargo/config.toml looks like this:
[target.riscv32imac-unknown-none-elf]
runner = "espflash flash --monitor --no-skip"
rustflags = [
# "-C",
# "link-arg=-Tlinkall.x",
"-C",
"link-arg=-Trom_functions.x",
"-C",
"force-frame-pointers",
]
[env]
ESP_LOGLEVEL = "INFO"
# ESP_LOGLEVEL = "DEBUG"
[build]
rustflags = [
#required for WIFI
# "-C",
# "link-arg=-Tlinkall.x",
"-C",
"link-arg=-Trom_functions.x",
# Required to obtain backtraces (e.g. when using the "esp-backtrace" crate.)
# NOTE: May negatively impact performance of produced code
"-C",
"force-frame-pointers",
]
target = "riscv32imac-unknown-none-elf"
[unstable]
build-std = ["core"]
I also included my whole example project for reproducibility. Some guidance would be much appreciated.
esph2_example.zip