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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
//! Bluetooth mesh element.

use dbus::{
    arg::{ArgType, RefArg, Variant},
    nonblock::{Proxy, SyncConnection},
};
use dbus_crossroads::{Crossroads, IfaceBuilder, IfaceToken};
use futures::{Stream, StreamExt};
use std::{
    collections::HashMap,
    fmt,
    pin::Pin,
    sync::{Arc, Weak},
    task::{Context, Poll},
};
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;

use crate::{
    mesh::{ReqError, PATH, SERVICE_NAME, TIMEOUT},
    method_call, Error, ErrorKind, Result, SessionInner,
};

pub(crate) const ELEMENT_INTERFACE: &str = "org.bluez.mesh.Element1";

pub(crate) type ElementConfig = HashMap<String, Variant<Box<dyn RefArg + 'static>>>;
pub(crate) type ElementConfigs = HashMap<usize, HashMap<u16, ElementConfig>>;

/// Interface to a Bluetooth mesh element interface.
#[derive(Debug, Clone, Default)]
pub struct Element {
    /// Location descriptor as defined in the GATT Bluetooth Namespace
    /// Descriptors section of the Bluetooth SIG Assigned Numbers.
    pub location: Option<u16>,
    /// Element SIG models.
    pub models: Vec<Model>,
    /// Vendor models.
    pub vendor_models: Vec<VendorModel>,
    /// Control handle for element once it has been registered.
    pub control_handle: ElementControlHandle,
    #[doc(hidden)]
    pub _non_exhaustive: (),
}

/// SIG model information.
#[derive(Debug, Clone)]
pub struct Model {
    /// SIG model identifier.
    pub id: u16,
    /// Indicates whether the model supports publication mechanism.
    ///
    /// By default this is true.
    pub publish: bool,
    /// Indicates whether the model supports subscription mechanism.
    ///
    /// By default this is true.
    pub subscribe: bool,
    #[doc(hidden)]
    pub _non_exhaustive: (),
}

impl Model {
    /// Creates a new model with the specified SIG model identifier.
    pub fn new(id: u16) -> Self {
        Self { id, ..Default::default() }
    }

    fn as_tuple(&self) -> (u16, HashMap<String, Variant<Box<dyn RefArg>>>) {
        let mut opts: HashMap<String, Variant<Box<dyn RefArg>>> = HashMap::new();
        opts.insert("Publish".to_string(), Variant(Box::new(self.publish)));
        opts.insert("Subscribe".to_string(), Variant(Box::new(self.subscribe)));
        (self.id, opts)
    }
}

impl Default for Model {
    fn default() -> Self {
        Self { id: 0, publish: true, subscribe: true, _non_exhaustive: Default::default() }
    }
}

/// Vendor model information.
#[derive(Debug, Clone)]
pub struct VendorModel {
    /// Company id.
    pub vendor: u16,
    /// Vendor-assigned model identifier.
    pub id: u16,
    /// Indicates whether the model supports publication mechanism.
    ///
    /// By default this is true.
    pub publish: bool,
    /// Indicates whether the model supports subscription mechanism.
    ///
    /// By default this is true.
    pub subscribe: bool,
    #[doc(hidden)]
    pub _non_exhaustive: (),
}

impl VendorModel {
    /// Creates a new model with the vendor and model identifiers.
    pub fn new(vendor: u16, id: u16) -> Self {
        Self { vendor, id, ..Default::default() }
    }

    #[allow(clippy::type_complexity)]
    fn as_tuple(&self) -> (u16, u16, HashMap<String, Variant<Box<dyn RefArg>>>) {
        let mut opts: HashMap<String, Variant<Box<dyn RefArg>>> = HashMap::new();
        opts.insert("Publish".to_string(), Variant(Box::new(self.publish)));
        opts.insert("Subscribe".to_string(), Variant(Box::new(self.subscribe)));
        (self.vendor, self.id, opts)
    }
}

impl Default for VendorModel {
    fn default() -> Self {
        Self { vendor: 0, id: 0, publish: true, subscribe: true, _non_exhaustive: Default::default() }
    }
}

/// An element exposed over D-Bus to bluez.
pub(crate) struct RegisteredElement {
    inner: Arc<SessionInner>,
    element: Element,
    index: usize,
}

impl RegisteredElement {
    pub(crate) fn new(inner: Arc<SessionInner>, root_path: String, element: Element, index: usize) -> Self {
        *element.control_handle.element_ref.lock().unwrap() = Some(ElementRefInner { root_path, index });
        Self { inner, element, index }
    }

    fn proxy(&self) -> Proxy<'_, &SyncConnection> {
        Proxy::new(SERVICE_NAME, PATH, TIMEOUT, &*self.inner.connection)
    }

    dbus_interface!();
    dbus_default_interface!(ELEMENT_INTERFACE);

    pub(crate) fn register_interface(cr: &mut Crossroads) -> IfaceToken<Arc<Self>> {
        cr.register(ELEMENT_INTERFACE, |ib: &mut IfaceBuilder<Arc<Self>>| {
            ib.method_with_cr_async(
                "MessageReceived",
                ("source", "key_index", "destination", "data"),
                (),
                |ctx,
                 cr,
                 (source, key_index, destination, data): (
                    u16,
                    u16,
                    Variant<Box<dyn RefArg + 'static>>,
                    Vec<u8>,
                )| {
                    method_call(ctx, cr, move |reg: Arc<Self>| async move {
                        log::trace!(
                            "Message received for element {:?}: source={:?} key_index={:?} dest={:?} data={:?}",
                            reg.index,
                            source,
                            key_index,
                            destination,
                            data
                        );

                        let destination = match destination.0.arg_type() {
                            ArgType::Array => {
                                let args = dbus::arg::cast::<Vec<u8>>(&destination.0).ok_or(ReqError::Failed)?;
                                if args.len() < 2 {
                                    return Err(ReqError::Failed.into());
                                }
                                u16::from_be_bytes([args[0], args[1]])
                            }
                            ArgType::UInt16 => *dbus::arg::cast::<u16>(&destination.0).ok_or(ReqError::Failed)?,
                            _ => return Err(ReqError::Failed.into()),
                        };

                        let msg = ReceivedMessage {
                            key_index,
                            source,
                            destination,
                            data,
                        };
                        reg.element.control_handle
                            .event_tx
                            .send(ElementEvent::MessageReceived(msg))
                            .await
                            .map_err(|_| ReqError::Failed)?;

                        Ok(())
                    })
                },
            );

            ib.method_with_cr_async(
                "DevKeyMessageReceived",
                ("source", "remote", "net_index", "data"),
                (),
                |ctx,
                 cr,
                 (source, remote, net_index, data): (
                    u16,
                    bool,
                    u16,
                    Vec<u8>,
                )| {
                    method_call(ctx, cr, move |reg: Arc<Self>| async move {
                        log::trace!(
                            "Dev Key Message received for element {:?}: source={:?} net_index={:?} remote={:?} data={:?}",
                            reg.index,
                            source,
                            net_index,
                            remote,
                            data
                        );

                        let msg = ReceivedDevKeyMessage {
                            source,
                            remote,
                            net_index,
                            data,
                        };
                        reg.element.control_handle
                            .event_tx
                            .send(ElementEvent::DevKeyMessageReceived(msg))
                            .await
                            .map_err(|_| ReqError::Failed)?;

                        Ok(())
                    })
                },
            );

            cr_property!(ib, "Index", reg => {
                Some(reg.index as u8)
            });

            cr_property!(ib, "Models", reg => {
                Some(reg.element.models.iter().map(|m| m.as_tuple()).collect::<Vec<_>>())
            });

            cr_property!(ib, "VendorModels", reg => {
                Some(reg.element.vendor_models.iter().map(|m| m.as_tuple()).collect::<Vec<_>>())
            });

            cr_property!(ib, "Location", reg => {
                reg.element.location
            });
        })
    }
}

/// A reference to a registered element.
#[derive(Clone)]
pub struct ElementRef(Weak<std::sync::Mutex<Option<ElementRefInner>>>);

impl ElementRef {
    /// Element index.
    ///
    /// `None` if the element is currently not registered.
    pub fn index(&self) -> Option<usize> {
        self.0.upgrade().and_then(|m| m.lock().unwrap().as_ref().map(|i| i.index))
    }

    /// Element D-Bus path.
    pub(crate) fn path(&self) -> Result<dbus::Path<'static>> {
        self.0
            .upgrade()
            .and_then(|m| m.lock().unwrap().as_ref().map(|i| i.path()))
            .ok_or_else(|| Error::new(ErrorKind::MeshElementUnpublished))
    }
}

impl fmt::Debug for ElementRef {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ElementRef").field("index", &self.index()).finish()
    }
}

struct ElementRefInner {
    root_path: String,
    index: usize,
}

impl ElementRefInner {
    /// Element D-Bus path.
    fn path(&self) -> dbus::Path<'static> {
        let element_path = format!("{}/ele{}", &self.root_path, self.index);
        dbus::Path::new(element_path).unwrap()
    }
}

/// An object to control an element and receive events once it has been registered.
///
/// Use [element_control] to obtain controller and associated handle.
pub struct ElementControl {
    event_rx: ReceiverStream<ElementEvent>,
    element_ref: ElementRef,
}

impl fmt::Debug for ElementControl {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ElementControl").finish()
    }
}

impl ElementControl {
    /// Returns a reference to the registered element.
    pub fn element_ref(&self) -> ElementRef {
        self.element_ref.clone()
    }
}

impl Stream for ElementControl {
    type Item = ElementEvent;
    fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
        Pin::into_inner(self).event_rx.poll_next_unpin(cx)
    }
}

/// A handle to store inside a element definition to make it controllable
/// once it has been registered.
///
/// Use [element_control] to obtain controller and associated handle.
#[derive(Clone)]
pub struct ElementControlHandle {
    event_tx: mpsc::Sender<ElementEvent>,
    element_ref: Arc<std::sync::Mutex<Option<ElementRefInner>>>,
}

impl Default for ElementControlHandle {
    fn default() -> Self {
        Self { event_tx: mpsc::channel(1).0, element_ref: Arc::new(std::sync::Mutex::new(None)) }
    }
}

impl fmt::Debug for ElementControlHandle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.debug_struct("ElementControlHandle").finish()
    }
}

/// Creates a [ElementControl] and its associated [ElementControlHandle].
///
/// Keep the [ElementControl] and store the [ElementControlHandle] in [Element::control_handle].
pub fn element_control() -> (ElementControl, ElementControlHandle) {
    let (event_tx, event_rx) = mpsc::channel(128);
    let inner = Arc::new(std::sync::Mutex::new(None));
    (
        ElementControl {
            event_rx: ReceiverStream::new(event_rx),
            element_ref: ElementRef(Arc::downgrade(&inner)),
        },
        ElementControlHandle { event_tx, element_ref: inner },
    )
}

/// Bluetooth mesh element events received by the application.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum ElementEvent {
    /// A message arrived addressed to the application element.
    MessageReceived(ReceivedMessage),
    /// A message arrived addressed to the application element,
    /// which was sent with the remote node's device key.
    DevKeyMessageReceived(ReceivedDevKeyMessage),
}

/// A message addressed to the application element.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct ReceivedMessage {
    /// Index of application key used to decode the incoming message.
    ///
    /// The same key_index should
    /// be used by the application when sending a response to this
    /// message (in case a response is expected).
    pub key_index: u16,
    /// Unicast address of the remote node-element that sent the message.
    pub source: u16,
    /// The destination address of the received message.
    pub destination: u16,
    /// Incoming message.
    pub data: Vec<u8>,
}

/// Message originated by a local model encoded with the device key of the remote node.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct ReceivedDevKeyMessage {
    /// Unicast address of the remote node-element that sent the message.
    pub source: u16,
    /// Device key remote origin.
    ///
    /// The remote parameter if true indicates that the device key
    /// used to decrypt the message was from the sender.
    /// False indicates that the local nodes device key was used, and the
    /// message has permissions to modify local states.
    pub remote: bool,
    /// Subnet message was received on.
    ///
    /// The net_index parameter indicates what subnet the message was
    /// received on, and if a response is required, the same subnet
    /// must be used to send the response.
    pub net_index: u16,
    /// Incoming message.
    pub data: Vec<u8>,
}