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
//! 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;

#[macro_use]
extern crate log;

#[macro_use]
extern crate nix;

#[cfg(target_os = "windows")]
extern crate winrt;

extern crate bytes;
#[macro_use] extern crate enum_primitive;
extern crate num;

#[macro_use]
extern crate nom;

#[macro_use]
extern crate bitflags;

extern crate failure;
#[macro_use]
extern crate failure_derive;

use std::result;
use std::time::Duration;

#[cfg(target_os = "linux")]
pub mod bluez;
#[cfg(target_os = "windows")]
pub mod winrtble;
pub mod api;

#[derive(Debug, Fail, Clone)]
pub enum Error {
    #[fail(display = "Permission denied")]
    PermissionDenied,

    #[fail(display = "Device not found")]
    DeviceNotFound,

    #[fail(display = "Not connected")]
    NotConnected,

    #[fail(display = "The operation is not supported: {}", _0)]
    NotSupported(String),

    #[fail(display = "Timed out after {:?}", _0)]
    TimedOut(Duration),

    #[fail(display = "{}", _0)]
    Other(String),
}

// Rumble Result type
pub type Result<T> = result::Result<T, Error>;