Skip to content
This repository has been archived by the owner on Sep 6, 2023. It is now read-only.

Commit

Permalink
Merge branch 'release/0.3.4'
Browse files Browse the repository at this point in the history
  • Loading branch information
persello committed Nov 20, 2022
2 parents 42c1c00 + 3015b2d commit 1bd16e2
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 85 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "bluedroid"
version = "0.3.3"
version = "0.3.4"
edition = "2021"
license = "MIT"
description = "A wrapper for the ESP32 Bluedroid Bluetooth stack."
Expand Down
18 changes: 8 additions & 10 deletions examples/server.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,21 @@
use std::sync::RwLock;
use std::sync::{RwLock, Arc};

use bluedroid::{
gatt_server::{Characteristic, Profile, Service, GLOBAL_GATT_SERVER},
utilities::{AttributePermissions, BleUuid, CharacteristicProperties},
};

use lazy_static::lazy_static;
use log::info;

lazy_static! {
static ref VALUE: RwLock<Vec<u8>> = RwLock::new("Initial value.".as_bytes().to_vec());
}

fn main() {
esp_idf_sys::link_patches();
esp_idf_svc::log::EspLogger::initialize_default();

info!("Logger initialised.");

let char_value_write: Arc<RwLock<Vec<u8>>> = 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",
Expand Down Expand Up @@ -61,13 +59,13 @@ fn main() {
.name("Writable Characteristic")
.permissions(AttributePermissions::new().read().write())
.properties(CharacteristicProperties::new().read().write())
.on_read(|_param| {
.on_read(move |_param| {
info!("Read from writable characteristic.");
return VALUE.read().unwrap().clone();
return char_value_read.read().unwrap().clone();
})
.on_write(|value, _param| {
.on_write(move |value, _param| {
info!("Wrote to writable characteristic: {:?}", value);
*VALUE.write().unwrap() = value;
*char_value_write.write().unwrap() = value;
})
.show_name()
.build();
Expand Down
38 changes: 30 additions & 8 deletions src/gatt_server/characteristic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,17 @@ use std::{
sync::{Arc, RwLock},
};

type WriteCallback = dyn Fn(Vec<u8>, esp_ble_gatts_cb_param_t_gatts_write_evt_param) + Send + Sync;

/// Represents a GATT characteristic.
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct Characteristic {
/// The name of the characteristic, for debugging purposes.
name: Option<String>,
/// The characteristic identifier.
pub(crate) uuid: BleUuid,
/// The function to be called when a write happens. This functions receives the written value in the first parameter, a `Vec<u8>`.
pub(crate) write_callback: Option<fn(Vec<u8>, esp_ble_gatts_cb_param_t_gatts_write_evt_param)>,
pub(crate) write_callback: Option<Arc<WriteCallback>>,
/// A list of descriptors for this characteristic.
pub(crate) descriptors: Vec<Arc<RwLock<Descriptor>>>,
/// The handle that the Bluetooth stack assigned to this characteristic.
Expand Down Expand Up @@ -104,9 +106,9 @@ impl Characteristic {
/// # Notes
///
/// The callback will be called from the Bluetooth stack's context, so it must not block.
pub fn on_read(
pub fn on_read<C: Fn(esp_ble_gatts_cb_param_t_gatts_read_evt_param) -> Vec<u8> + Send + Sync + 'static>(
&mut self,
callback: fn(esp_ble_gatts_cb_param_t_gatts_read_evt_param) -> Vec<u8>,
callback: C,
) -> &mut Self {
if !self.properties.read || !self.permissions.read_access {
warn!(
Expand All @@ -117,7 +119,7 @@ impl Characteristic {
return self;
}

self.control = AttributeControl::ResponseByApp(callback);
self.control = AttributeControl::ResponseByApp(Arc::new(callback));
self.internal_control = self.control.clone().into();

self
Expand All @@ -130,7 +132,7 @@ impl Characteristic {
/// It is up to the library user to decode the data into a meaningful format.
pub fn on_write(
&mut self,
callback: fn(Vec<u8>, esp_ble_gatts_cb_param_t_gatts_write_evt_param),
callback: impl Fn(Vec<u8>, esp_ble_gatts_cb_param_t_gatts_write_evt_param) + Send + Sync + 'static,
) -> &mut Self {
if !((self.properties.write || self.properties.write_without_response)
&& self.permissions.write_access)
Expand All @@ -143,7 +145,7 @@ impl Characteristic {
return self;
}

self.write_callback = Some(callback);
self.write_callback = Some(Arc::new(callback));
self
}

Expand Down Expand Up @@ -298,7 +300,7 @@ impl Characteristic {
.iter()
.find(|desc| desc.read().unwrap().uuid == BleUuid::Uuid16(0x2902))
{
if let AttributeControl::ResponseByApp(callback) = cccd.read().unwrap().control {
if let AttributeControl::ResponseByApp(callback) = &cccd.read().unwrap().control {
let value = callback(param);

return Some((
Expand All @@ -324,3 +326,23 @@ impl std::fmt::Display for Characteristic {
)
}
}

impl std::fmt::Debug for Characteristic {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
// Debug representation of a characteristic.
f.debug_struct("Characteristic")
.field("name", &self.name)
.field("uuid", &self.uuid)
.field("write_callback", &self.write_callback.is_some())
.field("descriptors", &self.descriptors)
.field("attribute_handle", &self.attribute_handle)
.field("service_handle", &self.service_handle)
.field("permissions", &self.permissions)
.field("properties", &self.properties)
.field("control", &self.control)
.field("internal_value", &self.internal_value)
.field("max_value_length", &self.max_value_length)
.field("internal_control", &self.internal_control)
.finish()
}
}
58 changes: 30 additions & 28 deletions src/gatt_server/custom_attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use lazy_static::lazy_static;
use log::debug;

lazy_static! {
static ref STORAGE: Mutex<EspNvsStorage> = Mutex::new(
static ref STORAGE: Arc<Mutex<EspNvsStorage>> = Arc::new(Mutex::new(
EspNvsStorage::new_default(
Arc::new(
EspDefaultNvs::new()
Expand All @@ -22,7 +22,7 @@ lazy_static! {
true
)
.expect("Cannot create a new NVS storage. Did you declare an NVS partition?")
);
));
}

impl Descriptor {
Expand Down Expand Up @@ -53,36 +53,38 @@ impl Descriptor {
Self::new(BleUuid::from_uuid16(0x2902))
.name("Client Characteristic Configuration")
.permissions(AttributePermissions::new().read().write())
.on_read(|param| {
let storage = STORAGE.lock().unwrap();
.on_read(
|param: esp_idf_sys::esp_ble_gatts_cb_param_t_gatts_read_evt_param| {
let storage = STORAGE.lock().unwrap();

// Get the descriptor handle.
// Get the descriptor handle.

// TODO: Find the characteristic that contains the handle.
// WARNING: Using the handle is incredibly stupid as the NVS is not erased across flashes.
// TODO: Find the characteristic that contains the handle.
// WARNING: Using the handle is incredibly stupid as the NVS is not erased across flashes.

// Create a key from the connection address.
let key = format!(
"{:02X}{:02X}{:02X}{:02X}-{:04X}",
/* param.bda[1], */ param.bda[2],
param.bda[3],
param.bda[4],
param.bda[5],
param.handle
);
// Create a key from the connection address.
let key = format!(
"{:02X}{:02X}{:02X}{:02X}-{:04X}",
/* param.bda[1], */ param.bda[2],
param.bda[3],
param.bda[4],
param.bda[5],
param.handle
);

// Prepare buffer and read correct CCCD value from non-volatile storage.
let mut buf: [u8; 2] = [0; 2];
if let Some(value) = storage.get_raw(&key, &mut buf).unwrap() {
debug!("Read CCCD value: {:?} for key {}.", value, key);
value.0.to_vec()
} else {
debug!("No CCCD value found for key {}.", key);
vec![0, 0]
}
})
.on_write(|value, param| {
let mut storage = STORAGE.lock().unwrap();
// Prepare buffer and read correct CCCD value from non-volatile storage.
let mut buf: [u8; 2] = [0; 2];
if let Some(value) = storage.get_raw(&key, &mut buf).unwrap() {
debug!("Read CCCD value: {:?} for key {}.", value, key);
value.0.to_vec()
} else {
debug!("No CCCD value found for key {}.", key);
vec![0, 0]
}
},
)
.on_write(|value, param| {
let mut storage = STORAGE.lock().unwrap();

// Create a key from the connection address.
let key = format!(
Expand Down
6 changes: 3 additions & 3 deletions src/gatt_server/descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ impl Descriptor {
}

/// Sets the read callback for the [`Descriptor`].
pub fn on_read(
pub fn on_read<C: Fn(esp_ble_gatts_cb_param_t_gatts_read_evt_param) -> Vec<u8> + Send + Sync + 'static>(
&mut self,
callback: fn(esp_ble_gatts_cb_param_t_gatts_read_evt_param) -> Vec<u8>,
callback: C,
) -> &mut Self {
if !self.permissions.read_access {
warn!(
Expand All @@ -69,7 +69,7 @@ impl Descriptor {
return self;
}

self.control = AttributeControl::ResponseByApp(callback);
self.control = AttributeControl::ResponseByApp(Arc::new(callback));
self.internal_control = self.control.clone().into();

self
Expand Down
Loading

0 comments on commit 1bd16e2

Please sign in to comment.