// Licensed under the Apache License, Version 2.0 // or the MIT license // , at your option. // All files in the project carrying such notice may not be copied, modified, or distributed // except according to those terms. use shared::basetsd::ULONG64; use shared::guiddef::{GUID, IsEqualGUID}; use shared::minwindef::{UCHAR, ULONG, USHORT}; use um::winnt::{BOOLEAN, HANDLE, PVOID}; DEFINE_GUID!{GUID_BLUETOOTHLE_DEVICE_INTERFACE, 0x781aee18, 0x7733, 0x4ce4, 0xad, 0xd0, 0x91, 0xf4, 0x1c, 0x67, 0xb5, 0x92} DEFINE_GUID!{GUID_BLUETOOTH_GATT_SERVICE_DEVICE_INTERFACE, 0x6e3bb679, 0x4372, 0x40c8, 0x9e, 0xaa, 0x45, 0x09, 0xdf, 0x26, 0x0c, 0xd8} DEFINE_GUID!{BTH_LE_ATT_BLUETOOTH_BASE_GUID, 0x00000000, 0x0000, 0x1000, 0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB} pub const BTH_LE_SERVICE_GAP: USHORT = 0x1800; pub const BTH_LE_SERVICE_GATT: USHORT = 0x1801; pub const BTH_LE_GATT_ATTRIBUTE_TYPE_PRIMARY_SERVICE: USHORT = 0x2800; pub const BTH_LE_GATT_ATTRIBUTE_TYPE_SECONDARY_SERVICE: USHORT = 0x2801; pub const BTH_LE_GATT_ATTRIBUTE_TYPE_INCLUDE: USHORT = 0x2802; pub const BTH_LE_GATT_ATTRIBUTE_TYPE_CHARACTERISTIC: USHORT = 0x2803; pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_EXTENDED_PROPERTIES: USHORT = 0x2900; pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_USER_DESCRIPTION: USHORT = 0x2901; pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_CLIENT_CONFIGURATION: USHORT = 0x2902; pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_SERVER_CONFIGURATION: USHORT = 0x2903; pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_FORMAT: USHORT = 0x2904; pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_AGGREGATE_FORMAT: USHORT = 0x2905; pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_DEVICE_NAME: USHORT = 0x2A00; pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_APPEARANCE: USHORT = 0x2A01; pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_PERIPHERAL_PRIVACY_FLAG: USHORT = 0x2A02; pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_RECONNECTION_ADDRESS: USHORT = 0x2A03; pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_PERIPHERAL_PREFERED_CONNECTION_PARAMETER: USHORT = 0x2A04; pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_SERVICE_CHANGED: USHORT = 0x2A05; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_OFFSET: u8 = 0x6; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_MASK: USHORT = 0x3ff; #[inline] pub fn BTH_LE_GAP_APPEARANCE_GET_CATEGORY(a: USHORT) -> USHORT { (a >> BTH_LE_GAP_APPEARANCE_CATEGORY_OFFSET) & BTH_LE_GAP_APPEARANCE_CATEGORY_MASK } #[inline] pub fn BTH_LE_GAP_APPEARANCE_SET_CATEGORY(a: &mut USHORT, c: USHORT) { *a = (*a & !BTH_LE_GAP_APPEARANCE_CATEGORY_MASK) | (c << BTH_LE_GAP_APPEARANCE_CATEGORY_OFFSET); } pub const BTH_LE_GAP_APPEARANCE_SUB_CATEGORY_MASK: USHORT = 0x3f; #[inline] pub fn BTH_LE_GAP_APPEARANCE_GET_SUB_CATEGORY(a: USHORT) -> UCHAR { (a & BTH_LE_GAP_APPEARANCE_SUB_CATEGORY_MASK) as u8 } #[inline] pub fn BTH_LE_GAP_APPEARANCE_SET_SUB_CATEGORY(a: &mut USHORT, s: UCHAR) { *a = (*a & !BTH_LE_GAP_APPEARANCE_SUB_CATEGORY_MASK) | (s as u16); } pub const BTH_LE_GAP_APPEARANCE_CATEGORY_UNCATEGORIZED: USHORT = 0x0000; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_PHONE: USHORT = 0x0001; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_COMPUTER: USHORT = 0x0002; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_WATCH: USHORT = 0x0003; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_CLOCK: USHORT = 0x0004; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_DISPLAY: USHORT = 0x0005; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_REMOTE_CONTROL: USHORT = 0x0006; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_EYE_GLASSES: USHORT = 0x0007; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_TAG: USHORT = 0x0008; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_KEYRING: USHORT = 0x0009; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_MEDIA_PLAYER: USHORT = 0x000a; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_BARCODE_SCANNER: USHORT = 0x000b; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_THERMOMETER: USHORT = 0x000c; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_HEART_RATE: USHORT = 0x000d; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_BLOOD_PRESSURE: USHORT = 0x000e; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_HID: USHORT = 0x000f; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_GLUCOSE_METER: USHORT = 0x0010; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_RUNNING_WALKING_SENSOR: USHORT = 0x0011; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_CYCLING: USHORT = 0x0012; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_PLUSE_OXIMETER: USHORT = 0x0031; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_WEIGHT_SCALE: USHORT = 0x0032; pub const BTH_LE_GAP_APPEARANCE_CATEGORY_OUTDOOR_SPORTS_ACTIVITY: USHORT = 0x0051; pub const BTH_LE_GAP_APPEARANCE_SUBCATEGORY_GENERIC: UCHAR = 0x00; pub const BTH_LE_GAP_APPEARANCE_WATCH_SUBCATEGORY_SPORTS_WATCH: UCHAR = 0x01; pub const BTH_LE_GAP_APPEARANCE_THERMOMETER_SUBCATEGORY_EAR: UCHAR = 0x01; pub const BTH_LE_GAP_APPEARANCE_HEART_RATE_SUBCATEGORY_HEART_RATE_BELT: UCHAR = 0x01; pub const BTH_LE_GAP_APPEARANCE_BLOOD_PRESSURE_SUBCATEGORY_ARM: UCHAR = 0x01; pub const BTH_LE_GAP_APPEARANCE_BLOOD_PRESSURE_SUBCATEGORY_WRIST: UCHAR = 0x02; pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_KEYBOARD: UCHAR = 0x01; pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_MOUSE: UCHAR = 0x02; pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_JOYSTICK: UCHAR = 0x03; pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_GAMEPAD: UCHAR = 0x04; pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_DIGITIZER_TABLET: UCHAR = 0x05; pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_CARD_READER: UCHAR = 0x06; pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_DIGITAL_PEN: UCHAR = 0x07; pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_BARCODE_SCANNER: UCHAR = 0x08; pub const BTH_LE_GAP_APPEARANCE_RUNNING_WALKING_SENSOR_SUBCATEGORY_IN_SHOE: UCHAR = 0x01; pub const BTH_LE_GAP_APPEARANCE_RUNNING_WALKING_SENSOR_SUBCATEGORY_ON_SHOE: UCHAR = 0x02; pub const BTH_LE_GAP_APPEARANCE_RUNNING_WALKING_SENSOR_SUBCATEGORY_ON_HIP: UCHAR = 0x03; pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_CYCLING_COMPUTER: UCHAR = 0x01; pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_SPEED_SENSOR: UCHAR = 0x02; pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_CADENCE_SENSOR: UCHAR = 0x03; pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_POWER_SENSOR: UCHAR = 0x04; pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_SPEED_AND_CADENCE_SENSOR: UCHAR = 0x05; pub const BTH_LE_GAP_APPEARANCE_PULSE_OXIMETER_SUBCATEGORY_FINGERTIP: UCHAR = 0x01; pub const BTH_LE_GAP_APPEARANCE_PULSE_OXIMETER_SUBCATEGORY_WRIST_WORN: UCHAR = 0x02; pub const BTH_LE_GAP_APPEARANCE_OUTDOOR_SPORTS_ACTIVITY_SUBCATEGORY_LOCATION_DISPLAY_DEVICE: UCHAR = 0x01; pub const BTH_LE_GAP_APPEARANCE_OUTDOOR_SPORTS_ACTIVITY_SUBCATEGORY_LOCATION_NAVIGATION_DISPLAY_DEVICE: UCHAR = 0x02; pub const BTH_LE_GAP_APPEARANCE_OUTDOOR_SPORTS_ACTIVITY_SUBCATEGORY_LOCATION_POD: UCHAR = 0x03; pub const BTH_LE_GAP_APPEARANCE_OUTDOOR_SPORTS_ACTIVITY_SUBCATEGORY_LOCATION_NAVIGATION_POD: UCHAR = 0x04; pub const BTH_LE_GATT_DEFAULT_MAX_INCLUDED_SERVICES_DEPTH: USHORT = 3; pub const BTH_LE_ATT_TRANSACTION_TIMEOUT: USHORT = 30; pub const BTH_LE_ATT_MAX_VALUE_SIZE: USHORT = 512; pub const BTH_LE_ATT_CID: USHORT = 0x0004; pub const BTHLEENUM_ATT_MTU_MIN: USHORT = 23; // #define BTHLEENUM_ATT_MTU_MAX (MAX_USHORT) pub const BTHLEENUM_ATT_MTU_DEFAULT: USHORT = BTHLEENUM_ATT_MTU_MIN; pub const BTHLEENUM_ATT_MTU_INITIAL_NEGOTIATION: USHORT = 525; pub const BTH_LE_ERROR_INVALID_HANDLE: USHORT = 0x01; pub const BTH_LE_ERROR_READ_NOT_PERMITTED: USHORT = 0x02; pub const BTH_LE_ERROR_WRITE_NOT_PERMITTED: USHORT = 0x03; pub const BTH_LE_ERROR_INVALID_PDU: USHORT = 0x04; pub const BTH_LE_ERROR_INSUFFICIENT_AUTHENTICATION: USHORT = 0x05; pub const BTH_LE_ERROR_REQUEST_NOT_SUPPORTED: USHORT = 0x06; pub const BTH_LE_ERROR_INVALID_OFFSET: USHORT = 0x07; pub const BTH_LE_ERROR_INSUFFICIENT_AUTHORIZATION: USHORT = 0x08; pub const BTH_LE_ERROR_PREPARE_QUEUE_FULL: USHORT = 0x09; pub const BTH_LE_ERROR_ATTRIBUTE_NOT_FOUND: USHORT = 0x0A; pub const BTH_LE_ERROR_ATTRIBUTE_NOT_LONG: USHORT = 0x0B; pub const BTH_LE_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE: USHORT = 0x0C; pub const BTH_LE_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH: USHORT = 0x0D; pub const BTH_LE_ERROR_UNLIKELY: USHORT = 0x0E; pub const BTH_LE_ERROR_INSUFFICIENT_ENCRYPTION: USHORT = 0x0F; pub const BTH_LE_ERROR_UNSUPPORTED_GROUP_TYPE: USHORT = 0x10; pub const BTH_LE_ERROR_INSUFFICIENT_RESOURCES: USHORT = 0x11; pub const BTH_LE_ERROR_UNKNOWN: USHORT = 0x1000; pub const BLUETOOTH_GATT_FLAG_NONE: ULONG = 0x00000000; pub const BLUETOOTH_GATT_FLAG_CONNECTION_ENCRYPTED: ULONG = 0x00000001; pub const BLUETOOTH_GATT_FLAG_CONNECTION_AUTHENTICATED: ULONG = 0x00000002; pub const BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE: ULONG = 0x00000004; pub const BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE: ULONG = 0x00000008; pub const BLUETOOTH_GATT_FLAG_SIGNED_WRITE: ULONG = 0x00000010; pub const BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE: ULONG = 0x00000020; pub const BLUETOOTH_GATT_FLAG_RETURN_ALL: ULONG = 0x00000040; pub const BLUETOOTH_GATT_FLAG_VALID_MASK: ULONG = BLUETOOTH_GATT_FLAG_NONE | BLUETOOTH_GATT_FLAG_CONNECTION_ENCRYPTED | BLUETOOTH_GATT_FLAG_CONNECTION_AUTHENTICATED | BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE | BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE | BLUETOOTH_GATT_FLAG_SIGNED_WRITE | BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE | BLUETOOTH_GATT_FLAG_RETURN_ALL; #[inline] pub fn IS_BLUETOOTH_GATT_FLAG_VALID(f: ULONG) -> bool { (f & !BLUETOOTH_GATT_FLAG_VALID_MASK) == 0 } pub type BLUETOOTH_GATT_EVENT_HANDLE = HANDLE; UNION!{union BTH_LE_UUID_value { [u32; 4], ShortUuid ShortUuid_mut: USHORT, LongUuid LongUuid_mut: GUID, }} STRUCT!{struct BTH_LE_UUID { IsShortUuid: BOOLEAN, Value: BTH_LE_UUID_value, }} pub type PBTH_LE_UUID = *mut BTH_LE_UUID; STRUCT!{struct BTH_LE_GATT_SERVICE { ServiceUuid: BTH_LE_UUID, AttributeHandle: USHORT, }} pub type PBTH_LE_GATT_SERVICE = *mut BTH_LE_GATT_SERVICE; ENUM!{enum BTH_LE_GATT_DESCRIPTOR_TYPE { CharacteristicExtendedProperties, CharacteristicUserDescription, ClientCharacteristicConfiguration, ServerCharacteristicConfiguration, CharacteristicFormat, CharacteristicAggregateFormat, CustomDescriptor, }} pub type PBTH_LE_GATT_DESCRIPTOR_TYPE = *mut BTH_LE_GATT_DESCRIPTOR_TYPE; STRUCT!{struct BTH_LE_GATT_CHARACTERISTIC { ServiceHandle: USHORT, CharacteristicUuid: BTH_LE_UUID, AttributeHandle: USHORT, CharacteristicValueHandle: USHORT, IsBroadcastable: BOOLEAN, IsReadable: BOOLEAN, IsWritable: BOOLEAN, IsWritableWithoutResponse: BOOLEAN, IsSignedWritable: BOOLEAN, IsNotifiable: BOOLEAN, IsIndicatable: BOOLEAN, HasExtendedProperties: BOOLEAN, }} pub type PBTH_LE_GATT_CHARACTERISTIC = *mut BTH_LE_GATT_CHARACTERISTIC; STRUCT!{struct BTH_LE_GATT_CHARACTERISTIC_VALUE { DataSize: ULONG, Data: [UCHAR; 1], }} pub type PBTH_LE_GATT_CHARACTERISTIC_VALUE = *mut BTH_LE_GATT_CHARACTERISTIC_VALUE; STRUCT!{struct BTH_LE_GATT_DESCRIPTOR { ServiceHandle: USHORT, CharacteristicHandle: USHORT, DescriptorType: BTH_LE_GATT_DESCRIPTOR_TYPE, DescriptorUuid: BTH_LE_UUID, AttributeHandle: USHORT, }} pub type PBTH_LE_GATT_DESCRIPTOR = *mut BTH_LE_GATT_DESCRIPTOR; STRUCT!{struct BTH_LE_GATT_DESCRIPTOR_VALUE_u_CharacteristicExtendedProperties { IsReliableWriteEnabled: BOOLEAN, IsAuxiliariesWritable: BOOLEAN, }} STRUCT!{struct BTH_LE_GATT_DESCRIPTOR_VALUE_u_ClientCharacteristicConfiguration { IsSubscribeToNotification: BOOLEAN, IsSubscribeToIndication: BOOLEAN, }} STRUCT!{struct BTH_LE_GATT_DESCRIPTOR_VALUE_u_ServerCharacteristicConfiguration { IsBroadcast: BOOLEAN, }} STRUCT!{struct BTH_LE_GATT_DESCRIPTOR_VALUE_u_CharacteristicFormat { Format: UCHAR, Exponent: UCHAR, Unit: BTH_LE_UUID, NameSpace: UCHAR, Description: BTH_LE_UUID, }} UNION!{union BTH_LE_GATT_DESCRIPTOR_VALUE_u { [u32; 12], CharacteristicExtendedProperties CharacteristicExtendedProperties_mut: BTH_LE_GATT_DESCRIPTOR_VALUE_u_CharacteristicExtendedProperties, ClientCharacteristicConfiguration ClientCharacteristicConfiguration_mut: BTH_LE_GATT_DESCRIPTOR_VALUE_u_ClientCharacteristicConfiguration, ServerCharacteristicConfiguration ServerCharacteristicConfiguration_mut: BTH_LE_GATT_DESCRIPTOR_VALUE_u_ServerCharacteristicConfiguration, CharacteristicFormat CharacteristicFormat_mut: BTH_LE_GATT_DESCRIPTOR_VALUE_u_CharacteristicFormat, }} STRUCT!{struct BTH_LE_GATT_DESCRIPTOR_VALUE { DescriptorType: BTH_LE_GATT_DESCRIPTOR_TYPE, DescriptorUuid: BTH_LE_UUID, u: BTH_LE_GATT_DESCRIPTOR_VALUE_u, DataSize: ULONG, Data: [UCHAR; 1], }} pub type PBTH_LE_GATT_DESCRIPTOR_VALUE = *mut BTH_LE_GATT_DESCRIPTOR_VALUE; ENUM!{enum BTH_LE_GATT_EVENT_TYPE { CharacteristicValueChangedEvent, }} FN!{stdcall PFNBLUETOOTH_GATT_EVENT_CALLBACK( EventType: BTH_LE_GATT_EVENT_TYPE, EventOutParameter: PVOID, Context: PVOID, ) -> ()} STRUCT!{struct BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION { NumCharacteristics: USHORT, Characteristics: [BTH_LE_GATT_CHARACTERISTIC; 1], }} pub type PBLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION = *mut BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION; STRUCT!{struct BLUETOOTH_GATT_VALUE_CHANGED_EVENT { ChangedAttributeHandle: USHORT, CharacteristicValueDataSize: usize, CharacteristicValue: PBTH_LE_GATT_CHARACTERISTIC_VALUE, }} pub type PBLUETOOTH_GATT_VALUE_CHANGED_EVENT = *mut BLUETOOTH_GATT_VALUE_CHANGED_EVENT; pub type BTH_LE_GATT_RELIABLE_WRITE_CONTEXT = ULONG64; pub type PBTH_LE_GATT_RELIABLE_WRITE_CONTEXT = *mut ULONG64; #[inline] pub fn IsBthLEUuidMatch(uuid1: &BTH_LE_UUID, uuid2: &BTH_LE_UUID) -> bool { fn is_bluetooth_le_uuid(uuid: &GUID) -> bool { uuid.Data2 == BTH_LE_ATT_BLUETOOTH_BASE_GUID.Data2 && uuid.Data3 == BTH_LE_ATT_BLUETOOTH_BASE_GUID.Data3 && uuid.Data4 == BTH_LE_ATT_BLUETOOTH_BASE_GUID.Data4 } unsafe { match (uuid1.IsShortUuid != 0, uuid2.IsShortUuid != 0) { (true, true) => uuid1.Value.ShortUuid() == uuid2.Value.ShortUuid(), (false, false) => IsEqualGUID(uuid1.Value.LongUuid(), uuid2.Value.LongUuid()), (true, false) => is_bluetooth_le_uuid(uuid2.Value.LongUuid()) && ((*uuid1.Value.ShortUuid()) as u32) == uuid2.Value.LongUuid().Data1, (false, true) => is_bluetooth_le_uuid(uuid1.Value.LongUuid()) && ((*uuid2.Value.ShortUuid()) as u32) == uuid1.Value.LongUuid().Data1, }} }