br-ble 0.2.0

This is an Bluetooth
Documentation
use std::collections::HashMap;
use std::time::Instant;
use json::{JsonValue, object};
#[cfg(target_os = "windows")]
use windows::Devices::Bluetooth::BluetoothLEDevice;
#[cfg(target_os = "windows")]
use windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristic;
#[cfg(target_os = "windows")]
use windows::Devices::Bluetooth::GenericAttributeProfile::GattCharacteristicProperties;
#[cfg(target_os = "macos")]
use crate::mac::central::{AdvertisementData, CentralManager};
#[cfg(target_os = "macos")]
use crate::mac::central::peripheral::Peripheral;

/// 蓝牙设备
#[derive(Clone)]
pub struct Device {
    /// 设备名称
    pub name: String,
    /// 设备id
    pub id: String,
    /// 设备信号
    pub rssi: i32,
    /// 服务列表
    pub characteristic: HashMap<String, Characteristic>,
    /// 发现
    pub discover: bool,
    /// 连接
    pub connect: bool,
    /// 禁用
    pub disable: bool,

    pub last_seen:Instant,
    /// 环境类型
    pub types: Types,
}
impl Device {
    #[cfg(target_os = "macos")]
    pub fn new(id: String, name: String, rssi: i32, manager: CentralManager, peripheral: Peripheral, advertisement_data: AdvertisementData) -> Self {
        Self {
            name,
            id,
            rssi,
            characteristic: Default::default(),
            discover: false,
            connect: false,
            disable: false,
            last_seen: Instant::now(),
            types: Types::Mac(manager, peripheral, Box::new(advertisement_data)),
        }
    }
    #[cfg(target_os = "windows")]
    pub fn new(id: String, name: String, rssi: i32, manager: CentralManager, peripheral: BluetoothLEDevice, advertisement_data: AdvertisementData) -> Self {
        Self {
            name,
            id,
            rssi,
            characteristic: Default::default(),
            discover: false,
            connect: false,
            disable: false,
            last_seen: Instant::now(),
            types: Types::Win(manager, peripheral, advertisement_data),
        }
    }
    /// 关闭连接
    pub fn disconnect(&mut self) -> bool {
        match self.clone().types {
            #[cfg(target_os = "macos")]
            Types::Mac(manager, peripheral, _advertisement_data) => {
                manager.cancel_connect(&peripheral);
                true
            }
            #[cfg(target_os = "windows")]
            Types::Win(manager, peripheral,_advertisement_data) => {
                manager.disconnect(peripheral);
                true
            }
            Types::None => { false }
        }
    }
    /// 开启连接
    pub fn connect(&mut self) -> bool {
        match self.clone().types {
            #[cfg(target_os = "macos")]
            Types::Mac(manager, peripheral, _advertisement_data) => {
                manager.connect(&peripheral);
                true
            }
            #[cfg(target_os = "windows")]
            Types::Win(manager, peripheral,_advertisement_data) => {
                manager.connect(peripheral);
                true
            }
            Types::None => false
        }
    }
    /// 订阅
    pub fn subscribe(&mut self, characteristic: Characteristic) -> bool {
        match self.clone().types {
            #[cfg(target_os = "macos")]
            Types::Mac(_, peripheral, _) => {
                peripheral.subscribe(&characteristic.characteristic);
                true
            }
            #[cfg(target_os = "windows")]
            Types::Win(manager, peripheral, _advertisement_data) => {
                manager.subscribe(peripheral, characteristic);
                true
            }
            _ => false
        }
    }
    pub fn json(&mut self) -> JsonValue {
        object! {
            name:self.name.clone(),
            id:self.id.clone(),
            rssi:self.rssi,
            discover: self.discover,
            connect: self.connect,
            disable:self.disable,
        }
    }
}
#[derive(Clone)]
pub enum Types {
    #[cfg(target_os = "macos")]
    Mac(CentralManager, Peripheral, Box<AdvertisementData>),
    #[cfg(target_os = "windows")]
    Win(CentralManager, BluetoothLEDevice, AdvertisementData),
    None,
}

#[cfg(target_os = "macos")]
use crate::mac::central::characteristic::Characteristic as Char;
#[cfg(target_os = "windows")]
use crate::win::central::{AdvertisementData, CentralManager};

/// 特征
#[derive(Clone)]
pub struct Characteristic {
    /// 特征UUID
    pub uuid: String,
    pub properties: Properties,
    #[cfg(target_os = "macos")]
    characteristic: Char,
    #[cfg(target_os = "windows")]
    pub characteristic: GattCharacteristicProperties,
    #[cfg(target_os = "windows")]
    pub gatt_characteristic: GattCharacteristic,
    /// 是否订阅
    pub is_subscribe: Option<bool>,
}

impl Characteristic {
    #[cfg(target_os = "macos")]
    pub fn default(characteristic: Char) -> Characteristic {
        Self {
            uuid: characteristic.id().to_string(),
            properties: Properties::form(format!("{:?}", characteristic.properties())),
            characteristic,
            is_subscribe: None,
        }
    }
    #[cfg(target_os = "windows")]
    pub fn default(uuid: String, characteristic: GattCharacteristicProperties, gatt_characteristic: GattCharacteristic) -> Characteristic {
        Self {
            uuid,
            properties: Properties::form(characteristic.0),
            characteristic,
            gatt_characteristic,
            is_subscribe: None,
        }
    }
}
/// 属性标志
#[derive(Debug, Clone)]
pub struct Properties {
    /// 可读
    pub read: bool,
    /// 可写
    pub write: bool,
    /// 通知
    pub notify: bool,
    /// 发送指示
    pub indicate: bool,
    /// 无响应写入
    pub write_without_response: bool,
    /// 认证签名写入
    pub authenticated_signed_writes: bool,
    /// 指示特征具有扩展的属性
    pub extended_properties: bool,
    /// 支持可靠写入
    pub reliable_write: bool,
    /// 支持可写辅助属性
    pub writable_auxiliaries: bool,
    /// 允许特征值进行广播
    pub broadcast: bool,
}

impl Properties {
    const BROADCAST: u16 = 0b00000001;
    const READ: u16 = 0b00000010;
    const WRITE_WITHOUT_RESPONSE: u16 = 0b00000100;
    const WRITE: u16 = 0b00001000;
    const NOTIFY: u16 = 0b00010000;
    const INDICATE: u16 = 0b00100000;
    const AUTHENTICATED_SIGNED_WRITES: u16 = 0b01000000;
    const EXTENDED_PROPERTIES: u16 = 0b10000000;
    const RELIABLE_WRITE: u16 = 0b000100000000;
    const WRITABLE_AUXILIARIES: u16 = 0b001000000000;

    #[cfg(target_os = "macos")]
    pub fn form(text: String) -> Properties {
        let text = text.trim_start_matches("Properties(BitFlagsDebug(BitFlags<Property>(");
        let text = text.split(",").collect::<Vec<&str>>()[0];
        let text = text.trim_start_matches("0b");
        let raw_value = u16::from_str_radix(text, 2).map_err(|e| e.to_string()).unwrap();
        let is_read = (Properties::READ & raw_value) == Properties::READ;
        let is_write = (Properties::WRITE & raw_value) == Properties::WRITE;
        let is_notify = (Properties::NOTIFY & raw_value) == Properties::NOTIFY;
        let is_indicate = (Properties::INDICATE & raw_value) == Properties::INDICATE;
        let is_write_without_response = (Properties::WRITE_WITHOUT_RESPONSE & raw_value) == Properties::WRITE_WITHOUT_RESPONSE;
        let is_authenticated_signed_writes = (Properties::AUTHENTICATED_SIGNED_WRITES & raw_value) == Properties::AUTHENTICATED_SIGNED_WRITES;
        let is_extended_properties = (Properties::EXTENDED_PROPERTIES & raw_value) == Properties::EXTENDED_PROPERTIES;
        let is_reliable_write = (Properties::RELIABLE_WRITE & raw_value) == Properties::RELIABLE_WRITE;
        let is_writable_auxiliaries = (Properties::WRITABLE_AUXILIARIES & raw_value) == Properties::WRITABLE_AUXILIARIES;
        let is_broadcast = (Properties::BROADCAST & raw_value) == Properties::BROADCAST;
        Self {
            read: is_read,
            write: is_write,
            notify: is_notify,
            indicate: is_indicate,
            write_without_response: is_write_without_response,
            authenticated_signed_writes: is_authenticated_signed_writes,
            extended_properties: is_extended_properties,
            reliable_write: is_reliable_write,
            writable_auxiliaries: is_writable_auxiliaries,
            broadcast: is_broadcast,
        }
    }
    #[cfg(target_os = "windows")]
    pub fn form(properties: u32) -> Properties {
        let is_read = (properties & GattCharacteristicProperties::Read.0) != 0;
        let is_write = (properties & GattCharacteristicProperties::Write.0) != 0;
        let is_notify = (properties & GattCharacteristicProperties::Notify.0) != 0;
        let is_indicate = (properties & GattCharacteristicProperties::Indicate.0) != 0;
        let is_write_without_response = (properties & GattCharacteristicProperties::WriteWithoutResponse.0) != 0;
        let is_authenticated_signed_writes = (properties & GattCharacteristicProperties::AuthenticatedSignedWrites.0) != 0;
        let is_extended_properties = (properties & GattCharacteristicProperties::ExtendedProperties.0) != 0;
        let is_reliable_write = (properties & GattCharacteristicProperties::ReliableWrites.0) != 0;
        let is_writable_auxiliaries = (properties & GattCharacteristicProperties::WritableAuxiliaries.0) != 0;
        let is_broadcast = (properties & GattCharacteristicProperties::Broadcast.0) != 0;
        Self {
            read: is_read,
            write: is_write,
            notify: is_notify,
            indicate: is_indicate,
            write_without_response: is_write_without_response,
            authenticated_signed_writes: is_authenticated_signed_writes,
            extended_properties: is_extended_properties,
            reliable_write: is_reliable_write,
            writable_auxiliaries: is_writable_auxiliaries,
            broadcast: is_broadcast,
        }
    }
}