summaryrefslogtreecommitdiff
path: root/nrf-softdevice/src/ble/gatt_traits.rs
blob: 2b27f8fff3fb0a5b4ef1ffc00486f8416da629d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use core::convert::TryInto;
use core::{mem, slice};

use heapless::{String, Vec};

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum FromGattError {
    InvalidLength,
    InvalidCharacter,
}

pub trait FixedGattValue: Sized {
    const SIZE: usize;

    // Converts from gatt bytes.
    // Must panic if and only if data.len != Self::SIZE
    fn from_gatt(data: &[u8]) -> Self;

    // Converts to gatt bytes.
    // Must return a slice of len Self::SIZE
    fn to_gatt(&self) -> &[u8];
}

pub trait GattValue: Sized {
    const MIN_SIZE: usize;
    const MAX_SIZE: usize;

    // Converts from gatt bytes.
    // Must panic if and only if data.len not in MIN_SIZE..=MAX_SIZE
    fn from_gatt(data: &[u8]) -> Self;

    // Converts to gatt bytes.
    // Must return a slice of len in MIN_SIZE..=MAX_SIZE
    fn to_gatt(&self) -> &[u8];
}

impl<T: FixedGattValue> GattValue for T {
    const MIN_SIZE: usize = Self::SIZE;
    const MAX_SIZE: usize = Self::SIZE;

    fn from_gatt(data: &[u8]) -> Self {
        <Self as FixedGattValue>::from_gatt(data)
    }

    fn to_gatt(&self) -> &[u8] {
        <Self as FixedGattValue>::to_gatt(self)
    }
}

pub unsafe trait Primitive: Copy {}
unsafe impl Primitive for u8 {}
unsafe impl Primitive for u16 {}
unsafe impl Primitive for u32 {}
unsafe impl Primitive for u64 {}
unsafe impl Primitive for i8 {}
unsafe impl Primitive for i16 {}
unsafe impl Primitive for i32 {}
unsafe impl Primitive for i64 {}
unsafe impl Primitive for f32 {}
unsafe impl Primitive for f64 {}

impl<T: Primitive> FixedGattValue for T {
    const SIZE: usize = mem::size_of::<Self>();

    fn from_gatt(data: &[u8]) -> Self {
        if data.len() != Self::SIZE {
            panic!("Bad len")
        }
        unsafe { *(data.as_ptr() as *const Self) }
    }

    fn to_gatt(&self) -> &[u8] {
        unsafe { slice::from_raw_parts(self as *const Self as *const u8, Self::SIZE) }
    }
}

impl FixedGattValue for bool {
    const SIZE: usize = 1;

    fn from_gatt(data: &[u8]) -> Self {
        data != [0x00]
    }

    fn to_gatt(&self) -> &[u8] {
        match self {
            true => &[0x01],
            false => &[0x00],
        }
    }
}

impl<const N: usize> GattValue for Vec<u8, N> {
    const MIN_SIZE: usize = 0;
    const MAX_SIZE: usize = N;

    fn from_gatt(data: &[u8]) -> Self {
        unwrap!(Self::from_slice(data))
    }

    fn to_gatt(&self) -> &[u8] {
        &self
    }
}

impl<const N: usize> GattValue for [u8; N] {
    const MIN_SIZE: usize = 0;
    const MAX_SIZE: usize = N;

    fn from_gatt(data: &[u8]) -> Self {
        unwrap!(data.try_into())
    }

    fn to_gatt(&self) -> &[u8] {
        self.as_slice()
    }
}

impl<const N: usize> GattValue for String<N> {
    const MIN_SIZE: usize = 0;
    const MAX_SIZE: usize = N;

    fn from_gatt(data: &[u8]) -> Self {
        String::from(unwrap!(
            core::str::from_utf8(data).map_err(|_| FromGattError::InvalidCharacter)
        ))
    }

    fn to_gatt(&self) -> &[u8] {
        self.as_ref()
    }
}