use std::sync::{Arc, RwLock}; use bluedroid::{ gatt_server::{Characteristic, Profile, Service, GLOBAL_GATT_SERVER}, utilities::{AttributePermissions, BleUuid, CharacteristicProperties}, }; use esp_idf_sys::{esp_get_free_heap_size, esp_get_free_internal_heap_size}; use log::info; fn main() { esp_idf_sys::link_patches(); esp_idf_svc::log::EspLogger::initialize_default(); info!("Logger initialised."); let char_value_write: Arc>> = Arc::new(RwLock::new("Initial value".as_bytes().to_vec())); let char_value_read = char_value_write.clone(); // A static characteristic. let static_characteristic = Characteristic::new(BleUuid::from_uuid128_string( "d4e0e0d0-1a2b-11e9-ab14-d663bd873d93", )) .name("Static Characteristic") .permissions(AttributePermissions::new().read()) .max_value_length(20) .properties(CharacteristicProperties::new().read()) .show_name() .set_value("Hello, world!".as_bytes().to_vec()) .build(); // A characteristic that notifies every second. let notifying_characteristic = Characteristic::new(BleUuid::from_uuid128_string( "a3c87500-8ed3-4bdf-8a39-a01bebede295", )) .name("Notifying Characteristic") .permissions(AttributePermissions::new().read()) .properties(CharacteristicProperties::new().read().notify()) .max_value_length(20) .show_name() .set_value("Initial value.".as_bytes().to_vec()) .build(); // A characteristic that notifies every second. let indicating_characteristic = Characteristic::new(BleUuid::from_uuid128_string( "c41d6f80-1a2c-11e9-ab14-d663bd873d93", )) .name("Indicating Characteristic") .permissions(AttributePermissions::new().read()) .properties(CharacteristicProperties::new().read().indicate()) .max_value_length(20) .show_name() .set_value("Initial value.".as_bytes().to_vec()) .build(); // A writable characteristic. let writable_characteristic = Characteristic::new(BleUuid::from_uuid128_string( "3c9a3f00-8ed3-4bdf-8a39-a01bebede295", )) .name("Writable Characteristic") .permissions(AttributePermissions::new().read().write()) .properties(CharacteristicProperties::new().read().write()) .on_read(move |_param| { info!("Read from writable characteristic."); return char_value_read.read().unwrap().clone(); }) .on_write(move |value, _param| { info!("Wrote to writable characteristic: {:?}", value); *char_value_write.write().unwrap() = value; }) .show_name() .build(); let service = Service::new(BleUuid::from_uuid128_string( "fafafafa-fafa-fafa-fafa-fafafafafafa", // far better, run run run run, run run run away... )) .name("Example Service") .primary() .characteristic(&static_characteristic) .characteristic(¬ifying_characteristic) .characteristic(&indicating_characteristic) .characteristic(&writable_characteristic) .build(); let profile = Profile::new(0x0001) .name("Default Profile") .service(&service) .build(); GLOBAL_GATT_SERVER .lock() .unwrap() .profile(profile) .device_name("ESP32-GATT-Server") .appearance(bluedroid::utilities::Appearance::WristWornPulseOximeter) .advertise_service(&service) .start(); std::thread::spawn(move || { let mut counter = 0; loop { counter += 1; notifying_characteristic .write() .unwrap() .set_value(format!("Counter: {counter}").as_bytes().to_vec()); indicating_characteristic .write() .unwrap() .set_value(format!("Counter: {counter}").as_bytes().to_vec()); std::thread::sleep(std::time::Duration::from_secs(1)); } }); std::thread::spawn(|| loop { std::thread::sleep(std::time::Duration::from_millis(500)); unsafe { let x = esp_get_free_heap_size(); let y = esp_get_free_internal_heap_size(); info!("Free heap: {} bytes, free internal heap: {} bytes", x, y); } }); loop { info!("Main loop."); std::thread::sleep(std::time::Duration::from_secs(10)); } }