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
//! Types for LE advertisements

use byteorder::{ByteOrder, LittleEndian};

use super::CommonDataType;

/// LE Advertisement Type
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
pub enum Advertisement<'a> {
    /// Complete local name of the device.
    CompleteLocalName(&'a str),
    /// Service data with 16-bit UUID.
    ///
    /// The first parameter is the UUID, the second parameter is the payload.
    ///
    /// The payload may be up to 27 bytes for legacy advertising mode.
    ServiceData16BitUuid(u16, &'a [u8]),
    /// Service data with 32-bit UUID
    ///
    /// The first parameter is the UUID, the second parameter is the payload.
    ///
    /// The payload may be up to 25 bytes for legacy advertising mode.
    ServiceData32BitUuid(u32, &'a [u8]),
    /// Service data with 128-bit UUID
    ///
    /// The first parameter is the UUID, the second parameter is the payload.
    ///
    /// The payload may be up to 13 bytes for legacy advertising mode.
    ServiceData128BitUuid(u128, &'a [u8]),
    /// Manufacturer-specific data
    ///
    /// The first parameter is the manufacturer ID, the second parameter is the
    /// payload.
    ///
    /// The payload may be up to 27 bytes for legacy advertising mode.
    ManufacturerSpecificData(u16, &'a [u8]),
}

impl Advertisement<'_> {
    /// Gets the length of the advertisement payload, in bytes.
    ///
    /// This includes the length byte itself.
    #[allow(clippy::len_without_is_empty)]
    pub fn len(&self) -> usize {
        use Advertisement::*;
        2 + match self {
            CompleteLocalName(n) => n.len(),
            ServiceData16BitUuid(_, b) | ManufacturerSpecificData(_, b) => 2 + b.len(),
            ServiceData32BitUuid(_, b) => 4 + b.len(),
            ServiceData128BitUuid(_, b) => 16 + b.len(),
        }
    }

    /// Gets the [CommonDataType] for this advertisement.
    const fn get_type(&self) -> CommonDataType {
        use Advertisement::*;
        match self {
            CompleteLocalName(_) => CommonDataType::CompleteLocalName,
            ServiceData16BitUuid(_, _) => CommonDataType::ServiceData16BitUuid,
            ServiceData32BitUuid(_, _) => CommonDataType::ServiceData32BitUuid,
            ServiceData128BitUuid(_, _) => CommonDataType::ServiceData128BitUuid,
            ManufacturerSpecificData(_, _) => CommonDataType::ManufacturerSpecificData,
        }
    }

    /// Serialize the advertisement into the given buffer, and return the number
    /// of bytes written.
    ///
    /// The maximum length of advertisements in legacy mode is 31 bytes.
    ///
    /// `bytes` must be at least [Self::len()] bytes.
    pub fn copy_into_slice(&self, bytes: &mut [u8]) -> usize {
        use Advertisement::*;
        let len = self.len();
        // Don't count the length byte.
        bytes[0] = (len - 1) as u8;
        bytes[1] = self.get_type() as u8;
        match self {
            CompleteLocalName(n) => {
                bytes[2..2 + n.len()].copy_from_slice(n.as_bytes());
            }
            ServiceData16BitUuid(u, b) | ManufacturerSpecificData(u, b) => {
                LittleEndian::write_u16(&mut bytes[2..], *u);
                bytes[4..4 + b.len()].copy_from_slice(b);
            }
            ServiceData32BitUuid(u, b) => {
                LittleEndian::write_u32(&mut bytes[2..], *u);
                bytes[6..6 + b.len()].copy_from_slice(b);
            }
            ServiceData128BitUuid(u, b) => {
                LittleEndian::write_u128(&mut bytes[2..], *u);
                bytes[18..18 + b.len()].copy_from_slice(b);
            }
        }
        len
    }
}