RKTK API Docs RKTK Home Repo

rktk_drivers_nrf/softdevice/ble/services/
device_information.rs

1use nrf_softdevice::{
2    ble::{
3        gatt_server::{
4            builder::ServiceBuilder,
5            characteristic::{Attribute, Metadata, Properties},
6            CharacteristicHandles, RegisterError,
7        },
8        Uuid,
9    },
10    Softdevice,
11};
12
13use super::super::constant::{
14    DEVICE_INFORMATION, FIRMWARE_REVISION, HARDWARE_REVISION, MANUFACTURER_NAME, MODEL_NUMBER,
15    PNP_ID, SERIAL_NUMBER, SOFTWARE_REVISION,
16};
17
18#[repr(u8)]
19#[derive(Clone, Copy)]
20#[allow(dead_code)]
21pub enum VidSource {
22    BluetoothSIG = 1,
23    UsbIF = 2,
24}
25
26#[repr(C, packed)]
27#[derive(Clone, Copy)]
28pub struct PnPID {
29    pub vid_source: VidSource,
30    pub vendor_id: u16,
31    pub product_id: u16,
32    pub product_version: u16,
33}
34
35#[derive(Debug, Default)]
36pub struct DeviceInformation {
37    pub manufacturer_name: Option<&'static str>,
38    pub model_number: Option<&'static str>,
39    pub serial_number: Option<&'static str>,
40    pub hw_rev: Option<&'static str>,
41    pub fw_rev: Option<&'static str>,
42    pub sw_rev: Option<&'static str>,
43}
44
45pub struct DeviceInformationService {}
46
47impl DeviceInformationService {
48    pub fn new(
49        sd: &mut Softdevice,
50        pnp_id: &PnPID,
51        info: DeviceInformation,
52    ) -> Result<Self, RegisterError> {
53        let mut sb = ServiceBuilder::new(sd, DEVICE_INFORMATION)?;
54
55        Self::add_pnp_characteristic(&mut sb, pnp_id)?;
56        Self::add_opt_str_characteristic(&mut sb, MANUFACTURER_NAME, info.manufacturer_name)?;
57        Self::add_opt_str_characteristic(&mut sb, MODEL_NUMBER, info.model_number)?;
58        Self::add_opt_str_characteristic(&mut sb, SERIAL_NUMBER, info.serial_number)?;
59        Self::add_opt_str_characteristic(&mut sb, HARDWARE_REVISION, info.hw_rev)?;
60        Self::add_opt_str_characteristic(&mut sb, FIRMWARE_REVISION, info.fw_rev)?;
61        Self::add_opt_str_characteristic(&mut sb, SOFTWARE_REVISION, info.sw_rev)?;
62
63        let _service_handle = sb.build();
64
65        Ok(DeviceInformationService {})
66    }
67
68    fn add_opt_str_characteristic(
69        sb: &mut ServiceBuilder,
70        uuid: Uuid,
71        val: Option<&'static str>,
72    ) -> Result<Option<CharacteristicHandles>, RegisterError> {
73        if let Some(val) = val {
74            let attr = Attribute::new(val);
75            let md = Metadata::new(Properties::new().read());
76            Ok(Some(sb.add_characteristic(uuid, attr, md)?.build()))
77        } else {
78            Ok(None)
79        }
80    }
81
82    fn add_pnp_characteristic(
83        sb: &mut ServiceBuilder,
84        pnp_id: &PnPID,
85    ) -> Result<CharacteristicHandles, RegisterError> {
86        // SAFETY: `PnPID` is `repr(C, packed)` so viewing it as an immutable slice of bytes is safe.
87        let val = unsafe {
88            core::slice::from_raw_parts(
89                pnp_id as *const _ as *const u8,
90                core::mem::size_of::<PnPID>(),
91            )
92        };
93
94        let attr = Attribute::new(val);
95        let md = Metadata::new(Properties::new().read());
96        Ok(sb.add_characteristic(PNP_ID, attr, md)?.build())
97    }
98}