use std::mem::ManuallyDrop;
use std::thread::sleep;
use std::time::Duration;
use futures_core::Stream;
use tracing::{error, warn};
use windows::Devices::Bluetooth::GenericAttributeProfile::{GattCharacteristic, GattClientCharacteristicConfigurationDescriptorValue, GattCommunicationStatus, GattValueChangedEventArgs, GattWriteResult};
use windows::Foundation::TypedEventHandler;
use windows_future::{AsyncOperationCompletedHandler,IAsyncOperation};
use windows::Storage::Streams::DataReader;
use windows::core::{Error, HSTRING, Ref};
use futures_lite::StreamExt;
use log::info;
use windows::Devices::Bluetooth::{BluetoothConnectionStatus, BluetoothLEDevice};
use windows::Devices::Enumeration::{DeviceInformation, DeviceInformationKind, DeviceInformationPairing, DevicePairingKinds, DevicePairingRequestedEventArgs, DevicePairingResult};
pub fn pair(id: HSTRING) {
loop {
let device_info: DeviceInformation = DeviceInformation::CreateFromIdAsync(&id).unwrap().get().unwrap();
let pairing_info: DeviceInformationPairing = device_info.Pairing().unwrap();
info!("pair state: {}", pairing_info.IsPaired().ok().unwrap());
info!("pair can: {}", pairing_info.CanPair().ok().unwrap());
if pairing_info.IsPaired().unwrap() {
info!("already paired !");
break;
}
let protection_level = pairing_info.ProtectionLevel().ok().unwrap();
info!("pair protection_level: {:?}", pairing_info.ProtectionLevel().ok().unwrap());
let custom_pairing = pairing_info.Custom().unwrap();
let pairing_kinds_supported = DevicePairingKinds::None
| DevicePairingKinds::ConfirmOnly
| DevicePairingKinds::DisplayPin
| DevicePairingKinds::ProvidePin
| DevicePairingKinds::ConfirmPinMatch
| DevicePairingKinds::ProvidePasswordCredential
| DevicePairingKinds::ProvideAddress;
let pairing_requested_token = custom_pairing.PairingRequested(&TypedEventHandler::new(
move |_sender, args: Ref<'_, DevicePairingRequestedEventArgs>| {
let args = args.unwrap();
args.Accept()?;
println!(">>>>>>>> kind: {:?}", pairing_kinds_supported);
Ok(())
}
)).ok().unwrap();
println!("======= kind: {:?}, level: {:?}", pairing_kinds_supported, protection_level);
let pairing_result_operation: IAsyncOperation<DevicePairingResult> = custom_pairing.PairWithProtectionLevelAsync(pairing_kinds_supported, protection_level).unwrap();
let _pairing_result: DevicePairingResult = pairing_result_operation.get().unwrap();
custom_pairing.RemovePairingRequested(pairing_requested_token).unwrap();
let device_info: DeviceInformation = DeviceInformation::CreateFromIdAsync(&id).unwrap().get().unwrap();
let pairing_info: DeviceInformationPairing = device_info.Pairing().unwrap();
if pairing_info.IsPaired().unwrap() {
break;
} else {
info!("sleep");
sleep(Duration::from_secs(5));
}
info!("****pair state: {}", pairing_info.IsPaired().ok().unwrap());
}
}
pub fn connected_device() -> Result<Vec<String>, ()> {
let aqs_filter = match BluetoothLEDevice::GetDeviceSelectorFromConnectionStatus(BluetoothConnectionStatus::Connected) {
Ok(e) => {
e
}
Err(_) => {
return Err(());
}
};
let device_info_collection =
match DeviceInformation::FindAllAsyncWithKindAqsFilterAndAdditionalProperties(
&aqs_filter, None, DeviceInformationKind::AssociationEndpoint) {
Ok(e) => {
e
}
Err(_) => {
return Err(());
}
};
let devices_list = match device_info_collection.get() {
Ok(e) => {
e
}
Err(_) => {
return Err(());
}
};
let mut device_ids = Vec::new();
for device_info in devices_list {
if let Ok(device_id) = device_info.Id() {
device_ids.push(device_id.to_string().split("-").last().unwrap().to_string());
}
}
Ok(device_ids)
}
pub fn unpair(id: HSTRING) {
loop {
let device_info: DeviceInformation = DeviceInformation::CreateFromIdAsync(&id).unwrap().get().unwrap();
let pairing_info: DeviceInformationPairing = device_info.Pairing().unwrap();
info!("before unpair state: {}", pairing_info.IsPaired().ok().unwrap());
if !pairing_info.IsPaired().unwrap() {
break;
}
let _unpair_res = pairing_info.UnpairAsync().unwrap().get().ok().unwrap();
let device_info: DeviceInformation = DeviceInformation::CreateFromIdAsync(&id).unwrap().get().unwrap();
let pairing_info: DeviceInformationPairing = device_info.Pairing().unwrap();
info!("after unpair state: {}", pairing_info.IsPaired().ok().unwrap());
if !pairing_info.IsPaired().unwrap() {
break;
} else {
info!("sleep");
sleep(Duration::from_secs(5));
}
info!("****pair state: {}", pairing_info.IsPaired().ok().unwrap());
}
}
pub fn subscribe(characteristic: &GattCharacteristic) -> Result<impl Stream<Item=Result<Vec<u8>, Error>> + Send + Unpin + '_, Error> {
let (mut sender, receiver) = futures_channel::mpsc::channel(16);
let token = characteristic.ValueChanged(&TypedEventHandler::new(
move |_characteristic, event_args: Ref<'_, GattValueChangedEventArgs>| {
let event_args = event_args
.as_ref()
.expect("GattValueChangedEventArgs was null in ValueChanged handler");
fn get_value(event_args: &GattValueChangedEventArgs) -> Result<Vec<u8>, Error> {
let buf = event_args.CharacteristicValue()?;
let len = buf.Length()?;
let mut data: Vec<u8> = vec![0; len as usize];
let reader = DataReader::FromBuffer(&buf)?;
reader.ReadBytes(data.as_mut_slice())?;
Ok(data)
}
if let Err(err) = sender.try_send(get_value(event_args)) {
error!("Error sending characteristic value changed notification: {:?}", err);
}
Ok(())
},
));
let guard = defer(move || {
if let Err(err) = characteristic.RemoveValueChanged(token.unwrap()) {
warn!("Error removing value change event handler: {:?}", err);
}
});
let res = characteristic
.WriteClientCharacteristicConfigurationDescriptorWithResultAsync(GattClientCharacteristicConfigurationDescriptorValue::Notify)?.get()?;
check_communication_status(res.Status()?)?;
let guard = defer(move || {
let _guard = guard;
let res = characteristic
.WriteClientCharacteristicConfigurationDescriptorWithResultAsync(
GattClientCharacteristicConfigurationDescriptorValue::Notify,
)
.and_then(|op| {
op.SetCompleted(&AsyncOperationCompletedHandler::new(move |op, _status| {
fn check_status(res: Result<GattWriteResult, Error>) -> Result<(), Error> {
let res = res?;
check_communication_status(
res.Status()?,
)
}
if let Err(err) = check_status(op.as_ref().unwrap().GetResults()) {
warn!("Error disabling characteristic notifications {:?}", err);
}
Ok(())
}))
});
if let Err(err) = res {
warn!("Error disabling characteristic notifications: {:?}", err);
}
});
Ok(receiver.map(move |x| {
let _guard = &guard;
x
}))
}
struct CommunicationError(GattCommunicationStatus);
impl std::fmt::Debug for CommunicationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "CommunicationError({})", self)
}
}
impl std::fmt::Display for CommunicationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let str = match self.0 {
GattCommunicationStatus::Success => "success",
GattCommunicationStatus::AccessDenied => "access denied",
GattCommunicationStatus::Unreachable => "unreachable",
GattCommunicationStatus::ProtocolError => "protocol error",
_ => return write!(f, "unknown ({})", self.0.0),
};
f.write_str(str)
}
}
pub(super) fn check_communication_status(
status: GattCommunicationStatus,
) -> Result<(), Error> {
match status {
GattCommunicationStatus::Success => Ok(()),
GattCommunicationStatus::Unreachable => Err(Error::new(windows::core::HRESULT(0x8007048Fu32 as i32), "Device is unreachable")), GattCommunicationStatus::ProtocolError => Err(Error::new(windows::core::HRESULT(0x8007044Du32 as i32), "Protocol error occurred")), GattCommunicationStatus::AccessDenied => Err(Error::new(windows::core::HRESULT(0x80070005u32 as i32), "Access denied")), _ => Err(Error::new(windows::core::HRESULT(0x80004005u32 as i32), "Unhandled communication status")), }
}
pub struct ScopeGuard<F: FnOnce()> {
dropfn: ManuallyDrop<F>,
}
impl<F: FnOnce()> Drop for ScopeGuard<F> {
fn drop(&mut self) {
let dropfn = unsafe { ManuallyDrop::take(&mut self.dropfn) };
dropfn();
}
}
pub fn defer<F: FnOnce()>(dropfn: F) -> ScopeGuard<F> {
ScopeGuard {
dropfn: ManuallyDrop::new(dropfn),
}
}