nrf-softdevice 0.1.0

Rust interface to nRF SoftDevice
Documentation
use crate::ble::SecurityMode;
use crate::raw;

// Missing:
// - Characteristic presentation format

#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct AttributeMetadata {
    pub read: SecurityMode,
    pub write: SecurityMode,
    pub variable_len: bool,
    pub deferred_read: bool,
    pub deferred_write: bool,
}

impl AttributeMetadata {
    pub fn with_security(security: SecurityMode) -> Self {
        AttributeMetadata {
            read: security,
            write: security,
            ..Default::default()
        }
    }

    pub fn read_security(mut self, security: SecurityMode) -> Self {
        self.read = security;
        self
    }

    pub fn write_security(mut self, security: SecurityMode) -> Self {
        self.write = security;
        self
    }

    pub(crate) fn into_raw(self) -> raw::ble_gatts_attr_md_t {
        self.into_raw_inner(raw::BLE_GATTS_VLOC_STACK as u8)
    }

    #[cfg(feature = "alloc")]
    pub(crate) fn into_raw_user(self) -> raw::ble_gatts_attr_md_t {
        self.into_raw_inner(raw::BLE_GATTS_VLOC_USER as u8)
    }

    fn into_raw_inner(self, vloc: u8) -> raw::ble_gatts_attr_md_t {
        raw::ble_gatts_attr_md_t {
            read_perm: self.read.into_raw(),
            write_perm: self.write.into_raw(),
            _bitfield_1: raw::ble_gatts_attr_md_t::new_bitfield_1(
                self.variable_len.into(),
                vloc,
                self.deferred_read.into(),
                self.deferred_write.into(),
            ),
        }
    }
}

#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Attribute<T: AsRef<[u8]>> {
    pub metadata: AttributeMetadata,
    pub value: T,
    pub max_len: u16,
}

impl<T: AsRef<[u8]>> Attribute<T> {
    pub fn new(value: T) -> Self {
        let max_len = unwrap!(value.as_ref().len().try_into());
        Attribute {
            max_len,
            value,
            metadata: Default::default(),
        }
    }

    pub fn security(mut self, security: SecurityMode) -> Self {
        self.metadata.read = security;
        self.metadata.write = security;
        self
    }

    pub fn read_security(mut self, security: SecurityMode) -> Self {
        self.metadata.read = security;
        self
    }

    pub fn write_security(mut self, security: SecurityMode) -> Self {
        self.metadata.write = security;
        self
    }

    pub fn variable_len(mut self, max_len: u16) -> Self {
        self.max_len = max_len;
        self.metadata.variable_len = true;
        self
    }

    pub fn deferred(mut self) -> Self {
        self.metadata.deferred_read = true;
        self.metadata.deferred_write = true;
        self
    }

    pub fn deferred_read(mut self) -> Self {
        self.metadata.deferred_read = true;
        self
    }

    pub fn deferred_write(mut self) -> Self {
        self.metadata.deferred_write = true;
        self
    }
}

#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct UserDescription {
    pub metadata: Option<AttributeMetadata>,
    pub value: &'static [u8],
    pub max_len: u16,
}

#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Properties {
    pub broadcast: bool,
    pub read: bool,
    pub write_without_response: bool,
    pub write: bool,
    pub notify: bool,
    pub indicate: bool,
    pub signed_write: bool,
    pub queued_write: bool,
    pub write_user_description: bool,
}

impl Properties {
    pub const fn new() -> Self {
        Self {
            broadcast: false,
            read: false,
            write_without_response: false,
            write: false,
            notify: false,
            indicate: false,
            signed_write: false,
            queued_write: false,
            write_user_description: false,
        }
    }

    pub const fn broadcast(mut self) -> Self {
        self.broadcast = true;
        self
    }

    pub const fn read(mut self) -> Self {
        self.read = true;
        self
    }

    pub const fn write_without_response(mut self) -> Self {
        self.write_without_response = true;
        self
    }

    pub const fn write(mut self) -> Self {
        self.write = true;
        self
    }

    pub const fn notify(mut self) -> Self {
        self.notify = true;
        self
    }

    pub const fn indicate(mut self) -> Self {
        self.indicate = true;
        self
    }

    pub const fn signed_write(mut self) -> Self {
        self.signed_write = true;
        self
    }

    pub const fn queued_write(mut self) -> Self {
        self.queued_write = true;
        self
    }

    pub const fn write_user_description(mut self) -> Self {
        self.write_user_description = true;
        self
    }

    pub(crate) fn into_raw(self) -> (raw::ble_gatt_char_props_t, raw::ble_gatt_char_ext_props_t) {
        (
            raw::ble_gatt_char_props_t {
                _bitfield_1: raw::ble_gatt_char_props_t::new_bitfield_1(
                    self.broadcast.into(),
                    self.read.into(),
                    self.write_without_response.into(),
                    self.write.into(),
                    self.notify.into(),
                    self.indicate.into(),
                    self.signed_write.into(),
                ),
            },
            raw::ble_gatt_char_ext_props_t {
                _bitfield_1: raw::ble_gatt_char_ext_props_t::new_bitfield_1(
                    self.queued_write.into(),
                    self.write_user_description.into(),
                ),
            },
        )
    }
}

#[derive(Default, Debug, PartialEq, Eq, Clone)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub struct Metadata {
    pub properties: Properties,
    pub user_description: Option<UserDescription>,
    pub cccd: Option<AttributeMetadata>,
    pub sccd: Option<AttributeMetadata>,
}

impl Metadata {
    pub fn new(properties: Properties) -> Self {
        let cccd = if properties.indicate || properties.notify {
            Some(AttributeMetadata::default())
        } else {
            None
        };

        let sccd = if properties.broadcast {
            Some(AttributeMetadata::default())
        } else {
            None
        };

        Metadata {
            properties,
            cccd,
            sccd,
            ..Default::default()
        }
    }

    pub fn with_security(properties: Properties, write_security: SecurityMode) -> Self {
        let cccd = if properties.indicate || properties.notify {
            Some(AttributeMetadata::default().write_security(write_security))
        } else {
            None
        };

        let sccd = if properties.broadcast {
            Some(AttributeMetadata::default().write_security(write_security))
        } else {
            None
        };

        Metadata {
            properties,
            cccd,
            sccd,
            ..Default::default()
        }
    }
}