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
//! Rumble is a Bluetooth Low Energy (BLE) central module library for Rust.
//! Currently only Linux (with the BlueZ bluetooth library) is supported, although
//! other operating systems may be supported in the future. Rumble interfaces with
//! BlueZ using its socket interface rather than DBus. This offers much more control
//! and reliability over the DBus interface, and does not require running BlueZ in
//! experimental mode for BLE.
//!
//! As of version 0.2, the API is becoming more stable and the library itself more
//! useful. You should still expect to encounter bugs, limitations, and odd behaviors.
//! Pull requests (and wireshark traces) welcome!
//!
//! ## Usage
//!
//! An example of how to use the library to control some BLE smart lights:
//!
//! ```rust,no_run
//! extern crate rumble;
//! extern crate rand;
//!
//! use std::thread;
//! use std::time::Duration;
//! use rand::{Rng, thread_rng};
//! use rumble::bluez::manager::Manager;
//! use rumble::api::{UUID, Central, Peripheral};
//!
//! pub fn main() {
//! let manager = Manager::new().unwrap();
//!
//! // get the first bluetooth adapter
//! let adapters = manager.adapters().unwrap();
//! let mut adapter = adapters.into_iter().nth(0).unwrap();
//!
//! // reset the adapter -- clears out any errant state
//! adapter = manager.down(&adapter).unwrap();
//! adapter = manager.up(&adapter).unwrap();
//!
//! // connect to the adapter
//! let central = adapter.connect().unwrap();
//!
//! // start scanning for devices
//! central.start_scan().unwrap();
//! // instead of waiting, you can use central.on_event to be notified of
//! // new devices
//! thread::sleep(Duration::from_secs(2));
//!
//! // find the device we're interested in
//! let light = central.peripherals().into_iter()
//! .find(|p| p.properties().local_name.iter()
//! .any(|name| name.contains("LEDBlue"))).unwrap();
//!
//! // connect to the device
//! light.connect().unwrap();
//!
//! // discover characteristics
//! light.discover_characteristics().unwrap();
//!
//! // find the characteristic we want
//! let chars = light.characteristics();
//! let cmd_char = chars.iter().find(|c| c.uuid == UUID::B16(0xFFE9)).unwrap();
//!
//! // dance party
//! let mut rng = thread_rng();
//! for _ in 0..20 {
//! let color_cmd = vec![0x56, rng.gen(), rng.gen(), rng.gen(), 0x00, 0xF0, 0xAA];
//! light.command(&cmd_char, &color_cmd).unwrap();
//! thread::sleep(Duration::from_millis(200));
//! }
//! }
//! ```
extern crate libc;
extern crate log;
extern crate nix;
extern crate bytes;
extern crate enum_primitive;
extern crate num;
extern crate nom;
extern crate bitflags;
extern crate failure;
extern crate failure_derive;
use result;
use Duration;
// Rumble Result type
pub type Result<T> = Result;