btleplug 0.5.1

A Cross-Platform Rust Bluetooth Low Energy (BLE) GATT library.
Documentation
// btleplug Source Code File
//
// Copyright 2020 Nonpolynomial Labs LLC. All rights reserved.
//
// Licensed under the BSD 3-Clause license. See LICENSE file in the project root
// for full license information.
//
// Some portions of this file are taken and/or modified from Rumble
// (https://github.com/mwylde/rumble), using a dual MIT/Apache License under the
// following copyright:
//
// Copyright (c) 2014 The Rust Project Developers

use std::{iter::Take, mem, slice::Iter, sync::Mutex};

use libc::{self, AF_BLUETOOTH, SOCK_RAW};
use nix::sys::ioctl::ioctl_param_type;

use crate::{
    bluez::{
        adapter::{Adapter, ConnectedAdapter},
        constants::*,
        ioctl,
        util::handle_error,
    },
    Result,
};

#[derive(Debug, Copy)]
#[repr(C)]
pub struct HCIDevReq {
    pub dev_id: u16,
    pub dev_opt: u32,
}

impl Clone for HCIDevReq {
    fn clone(&self) -> Self {
        *self
    }
}

impl Default for HCIDevReq {
    fn default() -> Self {
        HCIDevReq {
            dev_id: 0,
            dev_opt: 0,
        }
    }
}

#[derive(Copy)]
#[repr(C)]
pub struct HCIDevListReq {
    dev_num: u16,
    dev_reqs: [HCIDevReq; 16],
}

impl HCIDevListReq {
    pub fn iter(&self) -> Take<Iter<HCIDevReq>> {
        self.dev_reqs.iter().take(self.dev_num as usize)
    }
}

impl Clone for HCIDevListReq {
    fn clone(&self) -> Self {
        *self
    }
}

impl Default for HCIDevListReq {
    fn default() -> Self {
        HCIDevListReq {
            dev_num: 16u16,
            dev_reqs: unsafe { mem::zeroed() },
        }
    }
}

/// This struct is the interface into BlueZ. It can be used to list, manage, and connect to bluetooth
/// adapters.
pub struct Manager {
    ctl_fd: Mutex<i32>,
}

impl Manager {
    /// Constructs a new manager to communicate with the BlueZ system. Only one Manager should be
    /// created by your application.
    pub fn new() -> Result<Manager> {
        let fd = handle_error(unsafe { libc::socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI) })?;
        Ok(Manager {
            ctl_fd: Mutex::new(fd),
        })
    }

    /// Returns the list of adapters available on the system.
    pub fn adapters(&self) -> Result<Vec<Adapter>> {
        let mut result: Vec<Adapter> = vec![];

        let ctl = self.ctl_fd.lock().unwrap();

        let mut dev_list = HCIDevListReq::default();

        unsafe {
            ioctl::hci_get_dev_list(*ctl, &mut dev_list)?;
        }

        for dev_req in dev_list.iter() {
            let adapter = Adapter::from_dev_id(*ctl, dev_req.dev_id)?;
            result.push(adapter);
        }

        Ok(result)
    }

    /// Updates the state of an adapter.
    pub fn update(&self, adapter: &Adapter) -> Result<Adapter> {
        let ctl = self.ctl_fd.lock().unwrap();
        Adapter::from_dev_id(*ctl, adapter.dev_id)
    }

    /// Disables an adapter.
    pub fn down(&self, adapter: &Adapter) -> Result<Adapter> {
        let ctl = self.ctl_fd.lock().unwrap();
        unsafe { ioctl::hci_dev_down(*ctl, adapter.dev_id as ioctl_param_type)? };
        Adapter::from_dev_id(*ctl, adapter.dev_id)
    }

    /// Enables an adapater.
    pub fn up(&self, adapter: &Adapter) -> Result<Adapter> {
        let ctl = self.ctl_fd.lock().unwrap();
        unsafe {
            ioctl::hci_dev_up(*ctl, adapter.dev_id as ioctl_param_type)?;
        }
        Adapter::from_dev_id(*ctl, adapter.dev_id)
    }

    /// Establishes a connection to an adapter. Returns a `ConnectedAdapter`, which is the
    /// [`Central`](../../api/trait.Central.html) implementation for BlueZ.
    pub fn connect(&self, adapter: &Adapter) -> Result<ConnectedAdapter> {
        ConnectedAdapter::new(adapter)
    }
}