{*******************************************************}
{ }
{ CodeGear Delphi Runtime Library }
{ Copyright(c) 2014-2022 Embarcadero Technologies, Inc. }
{ All rights reserved }
{ }
{*******************************************************}
unit System.Win.BluetoothWinRT;
interface
{$IF Defined(MSWINDOWS)}
uses
System.SysUtils, System.Bluetooth;
{$SCOPEDENUMS ON}
type
TPlatformWinRTBluetoothLEManager = class(TBluetoothLEManager)
public
class function GetBluetoothManager: TBluetoothLEManager; override;
end;
{$ENDIF}
implementation
{$IF Defined(MSWINDOWS)}
uses
Winapi.Windows, System.Types, System.Generics.Collections, System.SyncObjs, System.StrUtils, System.Classes,
WinApi.Bluetooth, WinApi.BluetoothLE, System.Win.Winrt, Winapi.winrt, Winapi.Foundation,
Winapi.Foundation.Collections, Winapi.Devices.Enumeration, Winapi.Devices, Winapi.Devices.Bluetooth,
Winapi.Devices.Bluetooth.Advertisement, Winapi.CommonTypes, Winapi.Storage.Streams, System.NetConsts, System.RTLConsts;
const
SBluetoothMACAddressFormat = '%0.2X:%0.2X:%0.2X:%0.2X:%0.2X:%0.2X'; // Do not translate
type
TAsyncOperation = class
private type
TCancelProcedure = reference to procedure;
TThreadTimer = class(TThread)
private
FTimeout: Cardinal;
FEvent: TEvent;
FOnTimer: TCancelProcedure;
procedure Cancel;
public
constructor Create(const ACancelProc: TCancelProcedure; Timeout: Cardinal); overload;
destructor Destroy; override;
procedure Execute; override;
end;
class function Wait(const AAsyncOp: T; var AsyncOpResult: T; ATimeout: Cardinal = INFINITE): AsyncStatus;
end;
TWinRTBluetoothLEManager = class(TPlatformWinRTBluetoothLEManager)
private
FLEAdapter: TBluetoothLEAdapter;
protected
function GetRadioAdapter: Boolean;
function GetConnectionState: TBluetoothConnectionState; override;
function DoGetAdapter: TBluetoothLEAdapter; override;
// LE Fucntionality
function DoGetGattServer: TBluetoothGattServer; override;
function DoGetSupportsGattClient: Boolean; override;
function DoGetSupportsGattServer: Boolean; override;
function DoEnableBluetooth: Boolean; override;
public
destructor Destroy; override;
end;
TWinRTBluetoothLEAdapter = class;
TBLEAdvertisementReceivedEventHandler = class(TInspectableObject,
TypedEventHandler_2__IBluetoothLEAdvertisementWatcher__IBluetoothLEAdvertisementReceivedEventArgs_Delegate_Base,
TypedEventHandler_2__IBluetoothLEAdvertisementWatcher__IBluetoothLEAdvertisementReceivedEventArgs)
private
[Weak] FAdapter: TWinRTBluetoothLEAdapter;
procedure Invoke(sender: IBluetoothLEAdvertisementWatcher; args: IBluetoothLEAdvertisementReceivedEventArgs); safecall;
public
constructor Create(const AAdapter: TWinRTBluetoothLEAdapter);
end;
TWinRTBluetoothLEAdapter = class(TBluetoothLEAdapter)
private type
TStopDiscoveryProc = procedure of object;
TDiscoverThreadTimer = class(TThread)
private
[Weak] FAdapter: TBluetoothLEAdapter;
FTimeout: Cardinal;
FOnTimer: TStopDiscoveryProc;
FEvent: TEvent;
procedure Cancel;
public
constructor Create(const AnAdapter: TBluetoothLEAdapter; const AStopDiscoveryProc: TStopDiscoveryProc; Timeout: Cardinal); overload;
destructor Destroy; override;
procedure Execute; override;
end;
private
FAdvertisementWatcher: IBluetoothLEAdvertisementWatcher;
FBLEAdvertisementReceivedDelegate: TypedEventHandler_2__IBluetoothLEAdvertisementWatcher__IBluetoothLEAdvertisementReceivedEventArgs;
FBLEAdvertisementReceivedDelegateERT: EventRegistrationToken;
FScannedLEDevices: TBluetoothLEDeviceDictionary;
FTimerThread: TDiscoverThreadTimer;
[Weak] FBluetoothLEScanFilterList: TBluetoothLEScanFilterList;
procedure GetBLEPairedDevices;
protected
FRadioInfo: TBluetoothRadioInfo;
function GetAdapterName: string; override;
procedure SetAdapterName(const Value: string); override;
function GetAddress: System.Bluetooth.TBluetoothMacAddress; override;
function DoStartDiscovery(Timeout: Cardinal; const AFilterUUIDList: TBluetoothUUIDsList = nil;
const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList = nil): Boolean; override;
function DoStartDiscoveryRaw(const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList = nil; Refresh: Boolean = True): Boolean; override;
procedure DoCancelDiscovery; override;
procedure DoDiscoveryEnd(const Sender: TObject; const ADeviceList: TBluetoothLEDeviceList); override;
function GetScanMode: TBluetoothScanMode; override;
function GetState: TBluetoothAdapterState; override;
procedure BLEAdvertisementReceived(const AAdvertisement: IBluetoothLEAdvertisement;
const AdvertisementType: BluetoothLEAdvertisementType; AAddress: UInt64; ARSSI: SmallInt; const ATimestamp: DateTime);
procedure StopDiscovery;
procedure DoDeviceDiscovered(const ADevice: System.Bluetooth.TBluetoothLEDevice; ANewDevice: Boolean;
const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList); override;
public
constructor Create(const AManager: TBluetoothLEManager; const ARadioInfo: TBluetoothRadioInfo);
destructor Destroy; override;
end;
TWinRTBluetoothLEAdvertiseData = class(TBluetoothLEAdvertiseData)
private
FDevice: System.Bluetooth.TBluetoothLEDevice;
protected
function DoAddServiceUUID(const AServiceUUID: TBluetoothUUID): Boolean; override;
procedure DoRemoveServiceUUID(const AServiceUUID: TBluetoothUUID); override;
procedure DoClearServiceUUIDs; override;
function DoAddServiceData(const AServiceUUID: TBluetoothUUID; const AData: TBytes): Boolean; override;
procedure DoRemoveServiceData(const AServiceUUID: TBluetoothUUID); override;
procedure DoClearServiceData; override;
function ContainsServiceUUID(const AServiceUUID: TBluetoothUUID): Boolean; override;
function GetServiceUUIDs: TArray; override;
function GetServiceData: TArray; override;
function GetDataForService(const AServiceUUID: TBluetoothUUID): TBytes; override;
procedure SetLocalName(const ALocalName: string); override;
function GetLocalName: string; override;
procedure SetTxPowerLevel(ATxPowerLevel: Integer); override;
function GetTxPowerLevel: Integer; override;
procedure SetManufacturerSpecificData(const AManufacturerSpecificData: TBytes); override;
function GetManufacturerSpecificData: TBytes; override;
public
constructor Create(const ADevice: System.Bluetooth.TBluetoothLEDevice);
end;
TWinRTBluetoothLEDevice = class;
TConnectionStatusChangeEventHandler = class(TInspectableObject,
TypedEventHandler_2__IBluetoothLEDevice__IInspectable_Delegate_Base,
TypedEventHandler_2__IBluetoothLEDevice__IInspectable)
private
[Weak] FDevice: TWinRTBluetoothLEDevice;
procedure Invoke(sender: IBluetoothLEDevice; args: IInspectable); safecall;
public
constructor Create(const ADevice: TWinRTBluetoothLEDevice);
end;
TWinRTBluetoothLEDevice = class(System.Bluetooth.TBluetoothLEDevice)
private
FClosed: Boolean;
FLEAdapter: TWinRTBluetoothLEAdapter;
FConnectionStatusChangeDelegate: TypedEventHandler_2__IBluetoothLEDevice__IInspectable;
procedure CheckInitialized;
procedure CheckAccessAcquired(const dev3 : IBluetoothLEDevice3);
procedure CheckNotClosed;
procedure SetLastRSSI(const ARSSI: SmallInt);
protected
FId: HSTRING;
FAddress: UInt64;
FBluetoothLEDevice: IBluetoothLEDevice;
FDeviceName: string;
FReliableWriteTransaction: GenericAttributeProfile_IGattReliableWriteTransaction;
m_asyncTmo : Integer;
function DoCreateAdvertiseData: TBluetoothLEAdvertiseData; override;
function GetAddress: TBluetoothMacAddress; override;
function GetDeviceName: string; override;
function GetBluetoothType: TBluetoothType; override;
function GetIdentifier: string; override;
function GetIsConnected: Boolean; override;
procedure DoAbortReliableWrite; override;
function DoBeginReliableWrite: Boolean; override;
function DoExecuteReliableWrite: Boolean; override;
function DoDiscoverServices: Boolean; override;
function DoReadCharacteristic(const ACharacteristic: TBluetoothGattCharacteristic): Boolean; override;
function DoReadDescriptor(const ADescriptor: TBluetoothGattDescriptor): Boolean; override;
function DoWriteCharacteristic(const ACharacteristic: TBluetoothGattCharacteristic): Boolean; override;
function DoWriteDescriptor(const ADescriptor: TBluetoothGattDescriptor): Boolean; override;
function DoReadRemoteRSSI: Boolean; override;
function DoSetCharacteristicNotification(const ACharacteristic: TBluetoothGattCharacteristic; Enable: Boolean): Boolean; override;
procedure ConnectionStatusChanged;
function DoDisconnect: Boolean; override;
function DoConnect: Boolean; override;
procedure CloseServices;
procedure SetScanned(AScanned: Boolean);
function GetScanned: Boolean;
public
class function AddressFromId(const AId: HSTRING): Int64;
property Scanned: Boolean read GetScanned write SetScanned;
constructor Create(const AId: HSTRING; const ALEAdapter: TWinRTBluetoothLEAdapter; AutoConnect: Boolean); overload;
constructor Create(const AAddress: UInt64; const ALEAdapter: TWinRTBluetoothLEAdapter; AutoConnect: Boolean); overload;
destructor Destroy; override;
end;
TWinRTBluetoothGattServer = class(TBluetoothGattServer)
private
FAdvertismentPublisher: IBluetoothLEAdvertisementPublisher;
protected
{ Service Management }
function DoCreateService(const AnUUID: TBluetoothUUID; AType: TBluetoothServiceType): TBluetoothGattService; override;
function DoCreateIncludedService(const AService: TBluetoothGattService; const AnUUID: TBluetoothUUID;
AType: TBluetoothServiceType): TBluetoothGattService; override;
{ Characteristic Management }
function DoCreateCharacteristic(const AService: TBluetoothGattService; const AnUUID: TBluetoothUUID;
const AProps: TBluetoothPropertyFlags; const ADescription: string = ''): TBluetoothGattCharacteristic; override;
{ Descriptor Management }
function DoCreateDescriptor(const ACharacteristic: TBluetoothGattCharacteristic; const AnUUID: TBluetoothUUID): TBluetoothGattDescriptor; override;
function DoCreateAdvertiseData: TBluetoothLEAdvertiseData; override;
{ Add the previously created Services and characteristics... }
function DoAddService(const AService: TBluetoothGattService): Boolean; override;
function DoAddCharacteristic(const AService: TBluetoothGattService; const ACharacteristic: TBluetoothGattCharacteristic): Boolean; override;
function DoGetServices: TBluetoothGattServiceList; override;
procedure DoClose; override;
procedure DoClearServices; override;
procedure DoCharacteristicReadRequest(const ADevice: System.Bluetooth.TBluetoothLEDevice; ARequestId: Integer; AnOffset: Integer;
const AGattCharacteristic: TBluetoothGattCharacteristic); override;
procedure DoCharacteristicWriteRequest(const ADevice: System.Bluetooth.TBluetoothLEDevice; ARequestId: Integer;
const AGattCharacteristic: TBluetoothGattCharacteristic; APreparedWrite: Boolean; AResponseNeeded: Boolean;
AnOffset: Integer; const AValue: TBytes); override;
procedure DoUpdateCharacteristicValue(const ACharacteristic: TBluetoothGattCharacteristic); override;
procedure DoServiceAdded(AStatus: TBluetoothGattStatus; const AService: TBluetoothGattService); override;
/// Advertises peripheral manager data
procedure DoStartAdvertising; override;
/// Stops advertising peripheral manager data
procedure DoStopAdvertising; override;
/// A Boolean value indicating whether the peripheral is currently advertising data
function DoIsAdvertising: Boolean; override;
public
constructor Create(const AManager: TBluetoothLEManager);
destructor Destroy; override;
end;
TWinRTBluetoothGattService = class(TBluetoothGattService)
private
FUUID: TGUID;
protected
[Weak] FDevice: TWinRTBluetoothLEDevice;
FGattService: GenericAttributeProfile_IGattDeviceService;
FType: TBluetoothServiceType;
procedure CheckAccessAcquired(const svc3 : GenericAttributeProfile_IGattDeviceService3);
function GetServiceUUID: TBluetoothUUID; override;
function GetServiceType: TBluetoothServiceType; override;
function DoGetCharacteristics: TBluetoothGattCharacteristicList; override;
function DoGetIncludedServices: TBluetoothGattServiceList; override;
function DoCreateCharacteristic(const AUuid: TBluetoothUUID; APropertyFlags: TBluetoothPropertyFlags;
const ADescription: string): TBluetoothGattCharacteristic; override;
function DoCreateIncludedService(const AnUUID: TBluetoothUUID; AType: TBluetoothServiceType): TBluetoothGattService; override;
// Add the previously created Services and characteristics...
function DoAddIncludedService(const AService: TBluetoothGattService): Boolean; override;
function DoAddCharacteristic(const ACharacteristic: TBluetoothGattCharacteristic): Boolean; override;
procedure CheckNotClosed;
procedure Close;
public
constructor Create(const ADevice: TWinRTBluetoothLEDevice; const AGattService: GenericAttributeProfile_IGattDeviceService;
AType: TBluetoothServiceType);
destructor Destroy; override;
end;
TWinRTBluetoothGattCharacteristic = class;
TGattValueChangedEventHandler = class(TInspectableObject,
TypedEventHandler_2__GenericAttributeProfile_IGattCharacteristic__GenericAttributeProfile_IGattValueChangedEventArgs_Delegate_Base,
TypedEventHandler_2__GenericAttributeProfile_IGattCharacteristic__GenericAttributeProfile_IGattValueChangedEventArgs)
private
[Weak] FGattCharacteristic: TWinRTBluetoothGattCharacteristic;
procedure Invoke(sender: GenericAttributeProfile_IGattCharacteristic; args: GenericAttributeProfile_IGattValueChangedEventArgs); safecall;
public
constructor Create(const AGattCharacteristic: TWinRTBluetoothGattCharacteristic);
end;
TWinRTBluetoothGattCharacteristic = class(TBluetoothGattCharacteristic)
private
FValue: TBytes;
FGattValueChanged: TypedEventHandler_2__GenericAttributeProfile_IGattCharacteristic__GenericAttributeProfile_IGattValueChangedEventArgs;
FGattValueChangedERT: EventRegistrationToken;
function UpdateValueFromDevice: TBluetoothGattStatus;
function SetValueToDevice: TBluetoothGattStatus;
protected
[Weak] FBluetoothGattService: TWinRTBluetoothGattService;
FGattCharacteristic: GenericAttributeProfile_IGattCharacteristic;
FValueChangeEventHandle: TBluetoothGattEventHandle;
function GetUUID: TBluetoothUUID; override;
function GetProperties: TBluetoothPropertyFlags; override;
function DoAddDescriptor(const ADescriptor: TBluetoothGattDescriptor): Boolean; override;
function DoGetDescriptors: TBluetoothGattDescriptorList; override;
function DoCreateDescriptor(const AUUID: TBluetoothUUID): TBluetoothGattDescriptor; override;
function DoGetValue: TBytes; override;
procedure DoSetValue(const AValue: TBytes); override;
procedure GattValueChangedEvent(const Args: GenericAttributeProfile_IGattValueChangedEventArgs);
function SetClientCharacteristicConfigurationDescriptor(
const ADescriptorValue: GenericAttributeProfile_GattClientCharacteristicConfigurationDescriptorValue): Boolean;
public
constructor Create(const AService: TWinRTBluetoothGattService; const AGattCharacteristic: GenericAttributeProfile_IGattCharacteristic);
destructor Destroy; override;
end;
TWinRTBluetoothGattDescriptor = class(TBluetoothGattDescriptor)
private
FValue: TBytes;
function UpdateValueFromDevice: TBluetoothGattStatus;
function SetValueToDevice: TBluetoothGattStatus;
protected
FGattDescriptor: GenericAttributeProfile_IGattDescriptor;
// Characteristic Extended Properties
function DoGetReliableWrite: Boolean; override;
function DoGetWritableAuxiliaries: Boolean; override;
// Characteristic User Description
function DoGetUserDescription: string; override;
procedure DoSetUserDescription(const Value: string); override;
// Client Characteristic Configuration
procedure DoSetNotification(const Value: Boolean); override;
function DoGetNotification: Boolean; override;
procedure DoSetIndication(const Value: Boolean); override;
function DoGetIndication: Boolean; override;
// Server Characteristic Configuration
function DoGetBroadcasts: Boolean; override;
procedure DoSetBroadcasts(const Value: Boolean); override;
//Characteristic Presentation Format
function DoGetFormat: TBluetoothGattFormatType; override;
function DoGetExponent: ShortInt; override;
function DoGetFormatUnit: TBluetoothUUID; override;
function DoGetValue: TBytes; override;
procedure DoSetValue(const AValue: TBytes); override;
function GetUUID: TBluetoothUUID; override;
public
constructor Create(const ACharacteristic: TWinRTBluetoothGattCharacteristic;
const AGattDescriptor: GenericAttributeProfile_IGattDescriptor);
end;
{Helper Functions}
function TBthLeUuidToUUID(const Uuid: TBthLeUuid): TBluetoothUUID; inline;
var
TempGuuid: TBluetoothUUID;
begin
if Uuid.IsShortUuid then
begin
TempGuuid := BTH_LE_ATT_BLUETOOTH_BASE_GUID;
Inc(TempGuuid.D1, Uuid.ShortUuid);
Result := TempGuuid;
end
else
Result := Uuid.LongUuid;
end;
function BLEUuidToString(Uuid: TBthLeUuid): string; inline;
begin
Result := TBthLeUuidToUUID(Uuid).ToString;
end;
function CheckOSVersionForGattClient: Boolean;
begin
Result := TOSVersion.Check(10);
end;
function CheckOSVersionForGattServer: Boolean;
begin
Result := TOSVersion.Check(10);
end;
function BthAddressToString(const AnAddress: TBluetoothAddress): string; inline;
begin
Result := Format(SBluetoothMACAddressFormat, [AnAddress.rgBytes[5], AnAddress.rgBytes[4],
AnAddress.rgBytes[3], AnAddress.rgBytes[2], AnAddress.rgBytes[1], AnAddress.rgBytes[0]]);
end;
function BytesFromIBuffer(const ABuffer: IBuffer): TBytes;
var
LReader: IDataReader;
LLength: Cardinal;
begin
LReader := TDataReader.Statics.FromBuffer(ABuffer);
LLength := LReader.UnconsumedBufferLength;
SetLength(Result, LLength);
if LLength > 0 then
LReader.ReadBytes(LLength, @Result[0]);
end;
function BytesToIBuffer(const ABytes: TBytes; AOffset: Integer = 0): IBuffer;
var
LWriter: IDataWriter;
LNumBytes: Integer;
begin
LWriter := TDataWriter.Create;
LNumBytes := Length(ABytes) - AOffset;
if LNumBytes > 0 then
LWriter.WriteBytes(LNumBytes, @ABytes[AOffset]);
Result := LWriter.DetachBuffer;
end;
{ TPlatformBluetoothLEManager }
class function TPlatformWinRTBluetoothLEManager.GetBluetoothManager: TBluetoothLEManager;
begin
Result := TWinRTBluetoothLEManager.Create;
end;
{ TWinBluetoothLEManager }
function TWinRTBluetoothLEManager.DoGetGattServer: TBluetoothGattServer;
begin
Result := TWinRTBluetoothGattServer.Create(Self);
end;
function TWinRTBluetoothLEManager.DoGetAdapter: TBluetoothLEAdapter;
begin
if not GetRadioAdapter then
FLEAdapter := nil;
Result := FLEAdapter;
end;
function TWinRTBluetoothLEManager.DoGetSupportsGattClient: Boolean;
begin
Result := CheckOSVersionForGattClient;
end;
function TWinRTBluetoothLEManager.DoGetSupportsGattServer: Boolean;
begin
Result := CheckOSVersionForGattServer;
end;
function TWinRTBluetoothLEManager.GetConnectionState: TBluetoothConnectionState;
begin
if GetRadioAdapter then
Result := TBluetoothConnectionState.Connected
else
Result := TBluetoothConnectionState.Disconnected;
end;
function TWinRTBluetoothLEManager.GetRadioAdapter: Boolean;
var
btfrp: TBlueToothFindRadioParams;
hRadio: THandle;
hFind: HBLUETOOTH_RADIO_FIND;
LRadioInfo: TBluetoothRadioInfo;
begin
FillChar(btfrp, SizeOf(btfrp), 0);
btfrp.dwSize := SizeOf(btfrp);
hFind := BluetoothFindFirstRadio(btfrp, hRadio);
if hFind <> 0 then
begin
Result := True;
if FLEAdapter = nil then
begin
LRadioInfo.dwSize := SizeOf(TBluetoothRadioInfo);
BluetoothGetRadioInfo(hRadio, LRadioInfo);
FLEAdapter := TWinRTBluetoothLEAdapter.Create(Self, LRadioInfo);
end;
BluetoothFindRadioClose(hFind);
end
else
Result := False;
end;
destructor TWinRTBluetoothLEManager.Destroy;
begin
if FLEAdapter <> nil then
begin
TWinRTBluetoothLEAdapter(FLEAdapter).StopDiscovery;
FLEAdapter.Free;
end;
inherited;
end;
function TWinRTBluetoothLEManager.DoEnableBluetooth: Boolean;
begin
Result := False;
end;
{ TWinRTBluetoothLEAdapter.TThreadTimer }
procedure TWinRTBluetoothLEAdapter.TDiscoverThreadTimer.Cancel;
begin
Terminate;
FEvent.SetEvent;
FOnTimer := nil;
end;
constructor TWinRTBluetoothLEAdapter.TDiscoverThreadTimer.Create(const AnAdapter: TBluetoothLEAdapter;
const AStopDiscoveryProc: TStopDiscoveryProc; Timeout: Cardinal);
begin
inherited Create(True);
FAdapter := AnAdapter;
FOnTimer := AStopDiscoveryProc;
FTimeout := Timeout;
FEvent := TEvent.Create;
FreeOnTerminate := True;
end;
destructor TWinRTBluetoothLEAdapter.TDiscoverThreadTimer.Destroy;
begin
FEvent.Free;
inherited;
end;
procedure TWinRTBluetoothLEAdapter.TDiscoverThreadTimer.Execute;
begin
inherited;
FEvent.WaitFor(FTimeout);
if (not Terminated) and Assigned(FOnTimer) then
begin
try
FOnTimer;
except
if Assigned(System.Classes.ApplicationHandleException) then
System.Classes.ApplicationHandleException(Self)
else
raise;
end;
end;
end;
{ TWinBluetoothLEAdapter }
procedure TWinRTBluetoothLEAdapter.BLEAdvertisementReceived(const AAdvertisement: IBluetoothLEAdvertisement;
const AdvertisementType: BluetoothLEAdvertisementType; AAddress: UInt64; ARSSI: SmallInt;
const ATimestamp: DateTime);
var
LId: string;
LDevice: System.Bluetooth.TBluetoothLEDevice;
I: Integer;
LSection: IBluetoothLEAdvertisementDataSection;
LDataBytes: TBytes;
LNew: Boolean;
begin
LId := Format('%.12x', [AAddress]);
LNew := False;
LDevice := TWinRTBluetoothLEManager.GetDeviceInList(LId, FManager.AllDiscoveredDevices);
if LDevice = nil then
begin
LNew := True;
LDevice := TWinRTBluetoothLEDevice.Create(AAddress, Self, True);
end;
if AAdvertisement.DataSections.Size > 0 then
for I := 0 to AAdvertisement.DataSections.Size - 1 do
begin
LSection := AAdvertisement.DataSections.GetAt(I);
LDataBytes := BytesFromIBuffer(LSection.Data);
if LDevice.AdvertisedData = nil then
TWinRTBluetoothLEDevice(LDevice).FAdvertisedData := TScanResponse.Create;
LDevice.AdvertisedData.AddOrSetValue(TScanResponseKey(LSection.DataType), LDataBytes);
if AAdvertisement.LocalName <> 0 then
begin
TWinRTBluetoothLEDevice(LDevice).FDeviceName := AAdvertisement.LocalName.ToString;
TWinRTBluetoothLEAdvertiseData(LDevice.ScannedAdvertiseData).FLocalName := AAdvertisement.LocalName.ToString;
end;
end;
if AAdvertisement.ServiceUuids.Size > 0 then
for I := 0 to AAdvertisement.ServiceUuids.Size - 1 do
if not TWinRTBluetoothLEAdvertiseData(LDevice.ScannedAdvertiseData).FServiceUUIDs.Contains(AAdvertisement.ServiceUuids.GetAt(I)) then
TWinRTBluetoothLEAdvertiseData(LDevice.ScannedAdvertiseData).FServiceUUIDs.Add(AAdvertisement.ServiceUuids.GetAt(I));
(LDevice as TWinRTBluetoothLEDevice).SetLastRSSI(ARSSI);
DoDeviceDiscovered(LDevice, LNew, nil);
end;
constructor TWinRTBluetoothLEAdapter.Create(const AManager: TBluetoothLEManager; const ARadioInfo: TBluetoothRadioInfo);
begin
inherited Create(AManager);
FScannedLEDevices := TBluetoothLEDeviceDictionary.Create;
FRadioInfo := ARadioInfo;
FBLEAdvertisementReceivedDelegate := TBLEAdvertisementReceivedEventHandler.Create(Self);
FAdvertisementWatcher := TBluetoothLEAdvertisementWatcher.Create;
FBLEAdvertisementReceivedDelegateERT := FAdvertisementWatcher.add_Received(FBLEAdvertisementReceivedDelegate);
FAdvertisementWatcher.ScanningMode := BluetoothLEScanningMode.Active;
end;
destructor TWinRTBluetoothLEAdapter.Destroy;
begin
StopDiscovery;
if FBLEAdvertisementReceivedDelegateERT.Value <> 0 then
FAdvertisementWatcher.remove_Received(FBLEAdvertisementReceivedDelegateERT);
FBLEAdvertisementReceivedDelegate := nil;
FAdvertisementWatcher := nil;
FScannedLEDevices.Free;
inherited;
end;
procedure TWinRTBluetoothLEAdapter.GetBLEPairedDevices;
var
LDeviceInformationCollectionAsyncOp: IAsyncOperation_1__IVectorView_1__IDeviceInformation;
LBLEDevicesFound: IVectorView_1__IDeviceInformation;
LWinBluetoothLEDevice: TWinRTBluetoothLEDevice;
I: Integer;
begin
for I := 0 to FManager.AllDiscoveredDevices.Count - 1 do
TWinRTBluetoothLEDevice(FManager.AllDiscoveredDevices[I]).FPaired := False;
if TAsyncOperation.Wait(
TDeviceInformation.Statics.FindAllAsync(TBluetoothLEDevice.Statics.GetDeviceSelector),
LDeviceInformationCollectionAsyncOp) = AsyncStatus.Completed then
begin
LBLEDevicesFound := LDeviceInformationCollectionAsyncOp.GetResults;
if LBLEDevicesFound.Size > 0 then
for I := 0 to LBLEDevicesFound.Size - 1 do
begin
LWinBluetoothLEDevice := TWinRTBluetoothLEDevice(TWinRTBluetoothLEManager.GetDeviceInList
(Format('%.12x', [TWinRTBluetoothLEDevice.AddressFromId(LBLEDevicesFound.GetAt(I).Id)]), FManager.AllDiscoveredDevices));
if LWinBluetoothLEDevice = nil then
begin
LWinBluetoothLEDevice := TWinRTBluetoothLEDevice.Create(LBLEDevicesFound.GetAt(I).Id, Self, False);
LWinBluetoothLEDevice := TWinRTBluetoothLEDevice(
TWinRTBluetoothLEManager.AddDeviceToList(
System.Bluetooth.TBluetoothLEDevice(LWinBluetoothLEDevice),
FManager.AllDiscoveredDevices
)
);
end;
LWinBluetoothLEDevice.FPaired := True;
end;
end;
end;
function TWinRTBluetoothLEAdapter.DoStartDiscovery(Timeout: Cardinal; const AFilterUUIDList: TBluetoothUUIDsList;
const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList): Boolean;
var
I: Integer;
begin
GetBLEPairedDevices;
FScannedLEDevices.Clear;
FBluetoothLEScanFilterList := ABluetoothLEScanFilterList;
FAdvertisementWatcher.AdvertisementFilter.Advertisement.ServiceUuids.Clear;
if AFilterUUIDList <> nil then
for I := 0 to AFilterUUIDList.Count - 1 do
FAdvertisementWatcher.AdvertisementFilter.Advertisement.ServiceUuids.Append(AFilterUUIDList[I]);
FAdvertisementWatcher.Start;
FTimerThread := TDiscoverThreadTimer.Create(Self, DoCancelDiscovery, Timeout);
FTimerThread.Start;
Result := True;
end;
function TWinRTBluetoothLEAdapter.DoStartDiscoveryRaw(const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList;
Refresh: Boolean): Boolean;
begin
FScannedLEDevices.Clear;
FBluetoothLEScanFilterList := ABluetoothLEScanFilterList;
FAdvertisementWatcher.Start;
Result := True;
end;
function TWinRTBluetoothLEAdapter.GetAdapterName: string;
begin
Result := FRadioInfo.szName;
end;
function TWinRTBluetoothLEAdapter.GetAddress: System.Bluetooth.TBluetoothMacAddress;
var
LAddress: TBluetoothAddress;
begin
Result := '00:00:00:00:00:00'; // Do not translate
LAddress := FRadioInfo.address;
if LAddress.ullLong <> BLUETOOTH_NULL_ADDRESS.ullLong then
Result := BthAddressToString(LAddress);
end;
function TWinRTBluetoothLEAdapter.GetScanMode: TBluetoothScanMode;
begin
Result := Default(TBluetoothScanMode);
end;
function TWinRTBluetoothLEAdapter.GetState: TBluetoothAdapterState;
begin
Result := Default(TBluetoothAdapterState);
end;
procedure TWinRTBluetoothLEAdapter.SetAdapterName(const Value: string);
begin
raise EBluetoothAdapterException.CreateRes(@SBluetoothNotImplemented);
end;
procedure TWinRTBluetoothLEAdapter.StopDiscovery;
begin
if Assigned(FTimerThread) then
begin
FTimerThread.Cancel;
FTimerThread := nil;
end;
if FAdvertisementWatcher.Status = BluetoothLEAdvertisementWatcherStatus.Started then
begin
FAdvertisementWatcher.Stop;
end;
end;
procedure TWinRTBluetoothLEAdapter.DoCancelDiscovery;
begin
StopDiscovery;
DoDiscoveryEnd(Self, nil);
end;
procedure TWinRTBluetoothLEAdapter.DoDeviceDiscovered(
const ADevice: System.Bluetooth.TBluetoothLEDevice; ANewDevice: Boolean;
const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList);
var
LDiscovered: Boolean;
begin
LDiscovered := True;
if (not ADevice.Scanned) then
begin
if (FBluetoothLEScanFilterList <> nil) then
LDiscovered := DoDeviceOvercomesFilters(ADevice, FBluetoothLEScanFilterList);
if ANewDevice then
TWinRTBluetoothLEManager.AddDeviceToList(ADevice, FManager.AllDiscoveredDevices);
if LDiscovered then
begin
//if TWinRTBluetoothLEDevice(ADevice).Paired then // Need to be thought
TWinRTBluetoothLEManager.AddDeviceToList(ADevice, FManager.LastDiscoveredDevices);
TWinRTBluetoothLEDevice(ADevice).Scanned := True;
end;
end;
if LDiscovered then
DoDiscoverDevice(Self, ADevice, ADevice.LastRSSI, ADevice.AdvertisedData);
end;
procedure TWinRTBluetoothLEAdapter.DoDiscoveryEnd(const Sender: TObject; const ADeviceList: TBluetoothLEDeviceList);
begin
inherited DoDiscoveryEnd(Sender, nil);
end;
{ TWinBluetoothGattClient }
procedure TWinRTBluetoothLEDevice.CheckNotClosed;
begin
if FClosed then
raise EBluetoothServiceException.CreateRes(@SBluetoothLEDeviceDisconnectedExplicity);
end;
procedure TWinRTBluetoothLEDevice.CloseServices;
var
LService: TBluetoothGattService;
begin
for LService in FServices do
(LService as TWinRTBluetoothGattService).Close;
end;
procedure TWinRTBluetoothLEDevice.ConnectionStatusChanged;
var
LConnected: Boolean;
begin
LConnected := GetIsConnected;
if LConnected and Assigned(OnConnect) then
OnConnect(Self)
else
if (not LConnected) and Assigned(OnDisconnect) then
OnDisconnect(Self);
end;
constructor TWinRTBluetoothLEDevice.Create(const AAddress: UInt64; const ALEAdapter: TWinRTBluetoothLEAdapter;
AutoConnect: Boolean);
begin
inherited Create(AutoConnect);
FId := 0;
FAddress := AAddress;
FLEAdapter := ALEAdapter;
FClosed := true;
m_asyncTmo := 5000;
end;
constructor TWinRTBluetoothLEDevice.Create(const AId: HSTRING; const ALEAdapter: TWinRTBluetoothLEAdapter;
AutoConnect: Boolean);
begin
inherited Create(AutoConnect);
FId := AId;
FAddress := AddressFromId(AId);
FLEAdapter := ALEAdapter;
FClosed := true;
m_asyncTmo := 5000;
end;
destructor TWinRTBluetoothLEDevice.Destroy;
begin
FReliableWriteTransaction := nil;
DoDisconnect;
inherited;
end;
procedure TWinRTBluetoothLEDevice.DoAbortReliableWrite;
begin
FReliableWriteTransaction := nil;
end;
function TWinRTBluetoothLEDevice.DoBeginReliableWrite: Boolean;
begin
FReliableWriteTransaction := TGenericAttributeProfile_GattReliableWriteTransaction.Create;
Result := True;
end;
function TWinRTBluetoothLEDevice.DoDiscoverServices: Boolean;
var
I: Integer;
LGattService: GenericAttributeProfile_IGattDeviceService;
dev3 : IBluetoothLEDevice3;
res3 : IAsyncOperation_1__GenericAttributeProfile_IGattDeviceServicesResult;
serviceRes : GenericAttributeProfile_IGattDeviceServicesResult;
LGattServices: IVectorView_1__GenericAttributeProfile_IGattDeviceService;
begin
Result := True;
FServices.Clear;
CheckInitialized;
if FId = 0 then
begin
if
not Supports(
FBluetoothLEDevice,
IBluetoothLEDevice3,
dev3
)
then
raise EBluetoothDeviceException.CreateRes(@SBluetoothLEDeviceNotPaired);
CheckAccessAcquired(dev3);
var asyncStat := TAsyncOperation.Wait(
dev3.GetGattServicesAsync(BluetoothCacheMode.Uncached),
res3,
m_asyncTmo
);
if asyncStat = AsyncStatus.Completed then
begin
var ioStat := res3.GetResults.Status;
if GenericAttributeProfile_GattCommunicationStatus.Success = ioStat then
begin
serviceRes := res3.GetResults;
LGattServices := serviceRes.Services;
for I := 0 to LGattServices.Size - 1 do
begin
LGattService := LGattServices.GetAt(I);
FServices.Add(TWinRTBluetoothGattService.Create(Self, LGattService, TBluetoothServiceType.Primary));
end;
end;
end;
end
else
begin
if FBluetoothLEDevice.GattServices.Size > 0 then
for I := 0 to FBluetoothLEDevice.GattServices.Size - 1 do
begin
LGattService := FBluetoothLEDevice.GattServices.GetAt(I);
FServices.Add(TWinRTBluetoothGattService.Create(Self, LGattService, TBluetoothServiceType.Primary));
end;
end;
DoOnServicesDiscovered(Self, FServices);
end;
function TWinRTBluetoothLEDevice.DoExecuteReliableWrite: Boolean;
var
LWriteValueAsync: IAsyncOperation_1__GenericAttributeProfile_GattCommunicationStatus;
begin
CheckNotClosed;
if FReliableWriteTransaction <> nil then
begin
if TAsyncOperation.Wait(
FReliableWriteTransaction.CommitAsync, LWriteValueAsync) = AsyncStatus.Completed then
Result := LWriteValueAsync.GetResults = GenericAttributeProfile_GattCommunicationStatus.Success
else
Result := False;
FReliableWriteTransaction := nil;
end
else
Result := False;
end;
function TWinRTBluetoothLEDevice.DoReadCharacteristic(const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
begin
CheckNotClosed;
TThread.CreateAnonymousThread(procedure
begin
DoOnCharacteristicRead(ACharacteristic, TWinRTBluetoothGattCharacteristic(ACharacteristic).UpdateValueFromDevice);
end).Start;
Result := True;
end;
function TWinRTBluetoothLEDevice.DoReadDescriptor(const ADescriptor: TBluetoothGattDescriptor): Boolean;
begin
CheckNotClosed;
TThread.CreateAnonymousThread(procedure
begin
DoOnDescriptorRead(ADescriptor, TWinRTBluetoothGattDescriptor(ADescriptor).UpdateValueFromDevice);
end).Start;
Result := True;
end;
function TWinRTBluetoothLEDevice.DoReadRemoteRSSI: Boolean;
begin
{ Not supported on windows }
Result := False;
end;
function TWinRTBluetoothLEDevice.DoConnect: Boolean;
begin
{ Not supported on windows }
Result := False;
end;
function TWinRTBluetoothLEDevice.DoCreateAdvertiseData: TBluetoothLEAdvertiseData;
begin
Result := TWinRTBluetoothLEAdvertiseData.Create(Self);
end;
function TWinRTBluetoothLEDevice.DoSetCharacteristicNotification(const ACharacteristic: TBluetoothGattCharacteristic;
Enable: Boolean): Boolean;
var
LDescriptorValue: GenericAttributeProfile_GattClientCharacteristicConfigurationDescriptorValue;
begin
CheckNotClosed;
if TBluetoothProperty.Notify in ACharacteristic.Properties then
LDescriptorValue := GenericAttributeProfile_GattClientCharacteristicConfigurationDescriptorValue.Notify
else
if TBluetoothProperty.Indicate in ACharacteristic.Properties then
LDescriptorValue := GenericAttributeProfile_GattClientCharacteristicConfigurationDescriptorValue.Indicate
else
Exit(False);
if not Enable then
LDescriptorValue := GenericAttributeProfile_GattClientCharacteristicConfigurationDescriptorValue.None;
Result := TWinRTBluetoothGattCharacteristic(ACharacteristic).SetClientCharacteristicConfigurationDescriptor(LDescriptorValue);
end;
function TWinRTBluetoothLEDevice.DoWriteCharacteristic(const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
begin
CheckNotClosed;
TThread.CreateAnonymousThread(procedure
begin
DoOnCharacteristicWrite(ACharacteristic, TWinRTBluetoothGattCharacteristic(ACharacteristic).SetValueToDevice);
end).Start;
Result := True;
end;
function TWinRTBluetoothLEDevice.DoWriteDescriptor(const ADescriptor: TBluetoothGattDescriptor): Boolean;
begin
CheckNotClosed;
TThread.CreateAnonymousThread(procedure
begin
DoOnDescriptorWrite(ADescriptor, TWinRTBluetoothGattDescriptor(ADescriptor).SetValueToDevice);
end).Start;
Result := True;
end;
function TWinRTBluetoothLEDevice.GetAddress: TBluetoothMacAddress;
begin
Result := Format('%.12x', [FAddress]).ToUpper;
Result.Insert(2,':');
Result.Insert(5,':');
Result.Insert(8,':');
Result.Insert(11,':');
Result.Insert(14,':');
end;
function TWinRTBluetoothLEDevice.GetBluetoothType: TBluetoothType;
begin
Result := TBluetoothType.LE;
end;
function TWinRTBluetoothLEDevice.GetDeviceName: string;
begin
CheckInitialized;
Result := FDeviceName;
end;
function TWinRTBluetoothLEDevice.GetIdentifier: string;
begin
Result := Format('%.12x', [FAddress]);
end;
function TWinRTBluetoothLEDevice.GetIsConnected: Boolean;
begin
if Assigned(FBluetoothLEDevice) then
Result := FBluetoothLEDevice.ConnectionStatus = BluetoothConnectionStatus.Connected
else
Result := False;
end;
function TWinRTBluetoothLEDevice.GetScanned: Boolean;
begin
Result := FScanned;
end;
procedure TWinRTBluetoothLEDevice.SetLastRSSI(const ARSSI: SmallInt);
begin
FLastRSSI := ARSSI;
end;
procedure TWinRTBluetoothLEDevice.SetScanned(AScanned: Boolean);
begin
FScanned := AScanned;
end;
class function TWinRTBluetoothLEDevice.AddressFromId(const AId: HSTRING): Int64;
var
LTemp: string;
LDevPos: Integer;
begin
LTemp := AId.ToString;
LDevPos := LTemp.ToUpper.IndexOf('#DEV_'); // Do not translate
if LDevPos <> -1 then
LTemp := LTemp.Substring(LDevPos + 5, 12)
else
LTemp := ReplaceStr(RightStr(LTemp, 17), ':', '');
Result := StrToInt64('$' + LTemp);
end;
procedure TWinRTBluetoothLEDevice.CheckInitialized;
var
LBLEDeviceAsyncOp: IAsyncOperation_1__IBluetoothLEDevice;
dev3 : IBluetoothLEDevice3;
res3 : IAsyncOperation_1__GenericAttributeProfile_IGattDeviceServicesResult;
begin
if not Assigned(FBluetoothLEDevice) or FClosed then
begin
if FId = 0 then
begin
if TAsyncOperation.Wait(
TBluetoothLEDevice.Statics.FromBluetoothAddressAsync(FAddress), LBLEDeviceAsyncOp) = AsyncStatus.Completed then
begin
FBluetoothLEDevice := LBLEDeviceAsyncOp.GetResults;
FClosed := False;
if Assigned(FBluetoothLEDevice) then
begin
if DeviceName.IsEmpty then
FDeviceName := FBluetoothLEDevice.Name.ToString;
FId := FBluetoothLEDevice.DeviceId;
FConnectionStatusChangeDelegate := TConnectionStatusChangeEventHandler.Create(Self);
FBluetoothLEDevice.add_ConnectionStatusChanged(FConnectionStatusChangeDelegate);
end;
end;
end
else
if
TAsyncOperation.Wait(
TBluetoothLEDevice.Statics.FromIdAsync(FId),
LBLEDeviceAsyncOp
) = AsyncStatus.Completed
then begin
FBluetoothLEDevice := LBLEDeviceAsyncOp.GetResults;
FClosed := False;
if DeviceName.IsEmpty then
FDeviceName := FBluetoothLEDevice.Name.ToString;
FConnectionStatusChangeDelegate := TConnectionStatusChangeEventHandler.Create(Self);
FBluetoothLEDevice.add_ConnectionStatusChanged(FConnectionStatusChangeDelegate);
end;
if
Supports(
FBluetoothLEDevice,
IBluetoothLEDevice3,
dev3
)
then
CheckAccessAcquired(dev3);
end;
end;
procedure TWinRTBluetoothLEDevice.CheckAccessAcquired(const dev3 : IBluetoothLEDevice3);
begin
Assert(Assigned(dev3));
var accRes : IAsyncOperation_1__DeviceAccessStatus;
if
(
TAsyncOperation.Wait(
dev3.RequestAccessAsync,
accRes,
m_asyncTmo
) <> AsyncStatus.Completed
) or
(DeviceAccessStatus.Allowed <> accRes.GetResults)
then
raise EBluetoothDeviceException.Create('Access to BLE device is not granted!');
end;
function TWinRTBluetoothLEDevice.DoDisconnect: Boolean;
var
LBLEClosable: IClosable;
begin
if
(not FClosed) and
Assigned(FBluetoothLEDevice) and
(FBluetoothLEDevice.QueryInterface(IClosable, LBLEClosable) = 0)
then begin
CloseServices;
LBLEClosable.Close;
FClosed := True;
Result := True;
end else
Result := False;
end;
{ TWinBluetoothGattCharacteristic }
constructor TWinRTBluetoothGattCharacteristic.Create(const AService: TWinRTBluetoothGattService;
const AGattCharacteristic: GenericAttributeProfile_IGattCharacteristic);
begin
inherited Create(AService);
FBluetoothGattService := AService;
FGattCharacteristic := AGattCharacteristic;
if (TBluetoothProperty.Notify in Properties) or (TBluetoothProperty.Indicate in Properties) then
FGattValueChanged := TGattValueChangedEventHandler.Create(Self);
end;
destructor TWinRTBluetoothGattCharacteristic.Destroy;
begin
if FGattValueChangedERT.Value <> 0 then
FGattCharacteristic.remove_ValueChanged(FGattValueChangedERT);
FDescriptors.Clear();
inherited;
end;
function TWinRTBluetoothGattCharacteristic.DoAddDescriptor(const ADescriptor: TBluetoothGattDescriptor): Boolean;
begin
Result := False;
end;
function TWinRTBluetoothGattCharacteristic.DoCreateDescriptor(const AUUID: TBluetoothUUID): TBluetoothGattDescriptor;
begin
raise EBluetoothLECharacteristicException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattCharacteristic.DoGetDescriptors: TBluetoothGattDescriptorList;
var
LGattDescriptors: IVectorView_1__GenericAttributeProfile_IGattDescriptor;
I: Integer;
characteristic3 : GenericAttributeProfile_IGattCharacteristic3;
descriptorRes3 : IAsyncOperation_1__GenericAttributeProfile_IGattDescriptorsResult;
descrRes : GenericAttributeProfile_IGattDescriptorsResult;
begin
FDescriptors.Clear;
{ if Supports(FGattCharacteristic, GenericAttributeProfile_IGattCharacteristic3, characteristic3) then
begin
if TAsyncOperation.Wait(
characteristic3.GetDescriptorsAsync(BluetoothCacheMode.Uncached), descriptorRes3) = AsyncStatus.Completed then
begin
descrRes := descriptorRes3.GetResults;
LGattDescriptors := descrRes.Descriptors;
for I := 0 to LGattDescriptors.Size - 1 do
FDescriptors.Add(TWinRTBluetoothGattDescriptor.Create(Self, LGattDescriptors.GetAt(I)));
end;
end
else}
begin
var chx2 := FGattCharacteristic as GenericAttributeProfile_IGattCharacteristic2;
LGattDescriptors := chx2.GetAllDescriptors;
if LGattDescriptors.Size > 0 then
for I := 0 to LGattDescriptors.Size - 1 do
begin
var dcr := TWinRTBluetoothGattDescriptor.Create(
Self,
LGattDescriptors.GetAt(I)
);
Assert(Assigned(dcr));
FDescriptors.Add(dcr);
end;
end;
Result := FDescriptors;
end;
function TWinRTBluetoothGattCharacteristic.DoGetValue: TBytes;
begin
Result := FValue;
end;
procedure TWinRTBluetoothGattCharacteristic.DoSetValue(const AValue: TBytes);
begin
FValue := AValue;
end;
procedure TWinRTBluetoothGattCharacteristic.GattValueChangedEvent(const Args: GenericAttributeProfile_IGattValueChangedEventArgs);
begin
FValue := BytesFromIBuffer(Args.CharacteristicValue);
TWinRTBluetoothGattService(FService).FDevice.DoOnCharacteristicRead(Self, TBluetoothGattStatus.Success);
end;
function TWinRTBluetoothGattCharacteristic.GetProperties: TBluetoothPropertyFlags;
function HasProperty(const Props: GenericAttributeProfile_GattCharacteristicProperties;
const AProperty: GenericAttributeProfile_GattCharacteristicProperties): Boolean;
begin
Result := (Ord(Props) and Ord(AProperty) = Ord(AProperty));
end;
var
LProps: GenericAttributeProfile_GattCharacteristicProperties;
begin
Result := [];
LProps := FGattCharacteristic.CharacteristicProperties;
if HasProperty(LProps, GenericAttributeProfile_GattCharacteristicProperties.Broadcast) then
Include(Result, TBluetoothProperty.Broadcast);
if HasProperty(LProps, GenericAttributeProfile_GattCharacteristicProperties.Read) then
Include(Result, TBluetoothProperty.Read);
if HasProperty(LProps, GenericAttributeProfile_GattCharacteristicProperties.Write) then
Include(Result, TBluetoothProperty.Write);
if HasProperty(LProps, GenericAttributeProfile_GattCharacteristicProperties.WriteWithoutResponse) then
Include(Result, TBluetoothProperty.WriteNoResponse);
if HasProperty(LProps, GenericAttributeProfile_GattCharacteristicProperties.AuthenticatedSignedWrites) then
Include(Result, TBluetoothProperty.SignedWrite);
if HasProperty(LProps, GenericAttributeProfile_GattCharacteristicProperties.Notify) then
Include(Result, TBluetoothProperty.Notify);
if HasProperty(LProps, GenericAttributeProfile_GattCharacteristicProperties.Indicate) then
Include(Result, TBluetoothProperty.Indicate);
end;
function TWinRTBluetoothGattCharacteristic.GetUUID: TBluetoothUUID;
begin
Result := FGattCharacteristic.Uuid;
end;
function TWinRTBluetoothGattCharacteristic.SetClientCharacteristicConfigurationDescriptor(
const ADescriptorValue: GenericAttributeProfile_GattClientCharacteristicConfigurationDescriptorValue): Boolean;
var
LWriteDescValueAsync: IAsyncOperation_1__GenericAttributeProfile_GattCommunicationStatus;
begin
Result := False;
if ADescriptorValue = GenericAttributeProfile_GattClientCharacteristicConfigurationDescriptorValue.None then
begin
if FGattValueChangedERT.Value <> 0 then
begin
FGattCharacteristic.remove_ValueChanged(FGattValueChangedERT);
FGattValueChangedERT.Value := 0;
end;
end
else
if (TBluetoothProperty.Notify in Properties) or (TBluetoothProperty.Indicate in Properties) then
begin
if FGattValueChangedERT.Value <> 0 then
FGattCharacteristic.remove_ValueChanged(FGattValueChangedERT);
FGattValueChangedERT := FGattCharacteristic.add_ValueChanged(FGattValueChanged);
end;
if TAsyncOperation.Wait(
FGattCharacteristic.WriteClientCharacteristicConfigurationDescriptorAsync(ADescriptorValue),
LWriteDescValueAsync) = AsyncStatus.Completed then
Result := LWriteDescValueAsync.GetResults = GenericAttributeProfile_GattCommunicationStatus.Success;
end;
function TWinRTBluetoothGattCharacteristic.SetValueToDevice: TBluetoothGattStatus;
var
LWriteValueAsync: IAsyncOperation_1__GenericAttributeProfile_GattCommunicationStatus;
LWriteOption: GenericAttributeProfile_GattWriteOption;
begin
Result := TBluetoothGattStatus.Failure;
if FBluetoothGattService.FDevice.FReliableWriteTransaction <> nil then
begin
FBluetoothGattService.FDevice.FReliableWriteTransaction.WriteValue(FGattCharacteristic, BytesToIBuffer(FValue));
Result := TBluetoothGattStatus.Success;
end
else
begin
if TBluetoothProperty.WriteNoResponse in Properties then
LWriteOption := GenericAttributeProfile_GattWriteOption.WriteWithoutResponse
else
LWriteOption := GenericAttributeProfile_GattWriteOption.WriteWithResponse;
if TAsyncOperation.Wait(
FGattCharacteristic.WriteValueAsync(BytesToIBuffer(FValue), LWriteOption),
LWriteValueAsync) = AsyncStatus.Completed then
if LWriteValueAsync.GetResults = GenericAttributeProfile_GattCommunicationStatus.Success then
Result := TBluetoothGattStatus.Success;
end;
end;
function TWinRTBluetoothGattCharacteristic.UpdateValueFromDevice: TBluetoothGattStatus;
var
LGattReadValueAsyncOp: IAsyncOperation_1__GenericAttributeProfile_IGattReadResult;
LReadResult: GenericAttributeProfile_IGattReadResult;
begin
Result := TBluetoothGattStatus.Failure;
if TAsyncOperation.Wait(
FGattCharacteristic.ReadValueAsync(BluetoothCacheMode.Uncached),
LGattReadValueAsyncOp) = AsyncStatus.Completed then
begin
LReadResult := LGattReadValueAsyncOp.GetResults;
if LReadResult.Status = GenericAttributeProfile_GattCommunicationStatus.Success then
begin
FValue := BytesFromIBuffer(LReadResult.Value);
Result := TBluetoothGattStatus.Success;
end;
end;
end;
{ TWinBluetoothGattService }
procedure TWinRTBluetoothGattService.CheckNotClosed;
begin
if FDevice.FClosed then
raise EBluetoothServiceException.CreateRes(@SBluetoothLEDeviceDisconnectedExplicity);
end;
procedure TWinRTBluetoothGattService.Close;
var
LGattServiceClosable: IClosable;
begin
if (FGattService <> nil) and (FGattService.QueryInterface(IClosable, LGattServiceClosable) = 0) then
begin
LGattServiceClosable.Close;
FGattService := nil;
end;
end;
constructor TWinRTBluetoothGattService.Create(const ADevice: TWinRTBluetoothLEDevice;
const AGattService: GenericAttributeProfile_IGattDeviceService; AType: TBluetoothServiceType);
begin
inherited Create;
FDevice := ADevice;
FGattService := AGattService;
FUUID := FGattService.Uuid;
FType := AType;
end;
destructor TWinRTBluetoothGattService.Destroy;
begin
Close;
inherited;
end;
procedure TWinRTBluetoothGattService.CheckAccessAcquired(const svc3 : GenericAttributeProfile_IGattDeviceService3);
begin
Assert(Assigned(svc3));
var accRes : IAsyncOperation_1__DeviceAccessStatus;
if
(
TAsyncOperation.Wait(
svc3.RequestAccessAsync,
accRes,
FDevice.m_asyncTmo
) <> AsyncStatus.Completed
) or
(DeviceAccessStatus.Allowed <> accRes.GetResults)
then
raise EBluetoothDeviceException.Create('Access to BLE device service is not granted!');
end;
function TWinRTBluetoothGattService.DoGetCharacteristics: TBluetoothGattCharacteristicList;
var
I: Integer;
service3 : GenericAttributeProfile_IGattDeviceService3;
LGattCharacteristics: IVectorView_1__GenericAttributeProfile_IGattCharacteristic;
res3 : IAsyncOperation_1__GenericAttributeProfile_IGattCharacteristicsResult;
charactersRes : GenericAttributeProfile_IGattCharacteristicsResult;
characteristic : GenericAttributeProfile_IGattCharacteristic;
begin
CheckNotClosed;
FCharacteristics.Clear;
{
if
Supports(
FGattService,
GenericAttributeProfile_IGattDeviceService3,
service3
)
then begin
CheckAccessAcquired(service3);
var asyncStat := TAsyncOperation.Wait(
service3.GetCharacteristicsAsync(
BluetoothCacheMode.Uncached
),
res3,
5000
);
if asyncStat = AsyncStatus.Completed then
begin
charactersRes := res3.GetResults;
LGattCharacteristics := charactersRes.Characteristics;
for I := LGattCharacteristics.Size - 1 downto 0 do
begin
characteristic := LGattCharacteristics.GetAt(I);
FCharacteristics.Add(TWinRTBluetoothGattCharacteristic.Create(Self, characteristic));
end;
end;
end
else }
begin
LGattCharacteristics := (FGattService as GenericAttributeProfile_IGattDeviceService2).GetAllCharacteristics;
if LGattCharacteristics.Size > 0 then
for I := 0 to LGattCharacteristics.Size - 1 do
FCharacteristics.Add(TWinRTBluetoothGattCharacteristic.Create(Self, LGattCharacteristics.GetAt(I)));
end;
Result := FCharacteristics;
end;
function TWinRTBluetoothGattService.DoGetIncludedServices: TBluetoothGattServiceList;
var
I: Integer;
LGattServices: IVectorView_1__GenericAttributeProfile_IGattDeviceService;
begin
CheckNotClosed;
FIncludedServices.Clear;
LGattServices := (FGattService as GenericAttributeProfile_IGattDeviceService2).GetAllIncludedServices;
if LGattServices.Size > 0 then
for I := 0 to LGattServices.Size - 1 do
FIncludedServices.Add(TWinRTBluetoothGattService.Create(FDevice, LGattServices.GetAt(I), TBluetoothServiceType.Primary));
Result := FIncludedServices;
end;
function TWinRTBluetoothGattService.DoAddIncludedService(const AService: TBluetoothGattService): Boolean;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattService.DoAddCharacteristic(const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattService.DoCreateCharacteristic(const AUuid: TBluetoothUUID; APropertyFlags: TBluetoothPropertyFlags;
const ADescription: string): TBluetoothGattCharacteristic;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattService.DoCreateIncludedService(const AnUUID: TBluetoothUUID; AType: TBluetoothServiceType): TBluetoothGattService;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattService.GetServiceType: TBluetoothServiceType;
begin
Result := FType;
end;
function TWinRTBluetoothGattService.GetServiceUUID: TBluetoothUUID;
begin
Result := FUUID;
end;
{ TWinBluetoothGattDescriptor }
constructor TWinRTBluetoothGattDescriptor.Create(const ACharacteristic: TWinRTBluetoothGattCharacteristic;
const AGattDescriptor: GenericAttributeProfile_IGattDescriptor);
begin
inherited Create(ACharacteristic);
FGattDescriptor := AGattDescriptor;
end;
function TWinRTBluetoothGattDescriptor.DoGetBroadcasts: Boolean;
begin
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.ServerCharacteristicConfiguration then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
Result := TBluetoothProperty.Broadcast in FCharacteristic.Properties;
end;
function TWinRTBluetoothGattDescriptor.DoGetExponent: ShortInt;
begin
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.CharacteristicPresentationFormat then
raise EBluetoothLEDescriptorException.Create(SBluetoothDescriptorTypeError);
Result := ShortInt(Value[1]);
end;
function TWinRTBluetoothGattDescriptor.DoGetFormat: TBluetoothGattFormatType;
begin
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.CharacteristicPresentationFormat then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
Result := TBluetoothGattFormatType(Value[0]);
end;
function TWinRTBluetoothGattDescriptor.DoGetFormatUnit: TBluetoothUUID;
var
LValue: Word;
begin
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.CharacteristicPresentationFormat then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
if Length(FValue) < 4 then
LValue := 0
else
LValue := FValue[2] or (FValue[3] shl 8);
Result := System.Bluetooth.TBluetoothUUIDHelper.GetBluetoothUUID(LValue);
end;
function TWinRTBluetoothGattDescriptor.DoGetIndication: Boolean;
begin
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.ClientCharacteristicConfiguration then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
Result := TBluetoothProperty.Indicate in FCharacteristic.Properties;
end;
function TWinRTBluetoothGattDescriptor.DoGetNotification: Boolean;
begin
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.ClientCharacteristicConfiguration then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
Result := TBluetoothProperty.Notify in FCharacteristic.Properties;
end;
function TWinRTBluetoothGattDescriptor.DoGetReliableWrite: Boolean;
const
LProp = GenericAttributeProfile_GattCharacteristicProperties.ReliableWrites;
var
LProps: GenericAttributeProfile_GattCharacteristicProperties;
begin
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.CharacteristicExtendedProperties then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
LProps := TWinRTBluetoothGattCharacteristic(FCharacteristic).FGattCharacteristic.CharacteristicProperties;
Result := Ord(LProps) and Ord(LProp) = Ord(LProp);
end;
function TWinRTBluetoothGattDescriptor.DoGetUserDescription: string;
begin
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.CharacteristicUserDescription then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
Result := TEncoding.Unicode.GetString(FValue);
end;
function TWinRTBluetoothGattDescriptor.DoGetValue: TBytes;
begin
Result := FValue;
end;
function TWinRTBluetoothGattDescriptor.DoGetWritableAuxiliaries: Boolean;
const
LProp = GenericAttributeProfile_GattCharacteristicProperties.ReliableWrites;
var
LProps: GenericAttributeProfile_GattCharacteristicProperties;
begin
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.CharacteristicExtendedProperties then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
LProps := TWinRTBluetoothGattCharacteristic(FCharacteristic).FGattCharacteristic.CharacteristicProperties;
Result := Ord(LProps) and Ord(LProp) = Ord(LProp);
end;
procedure TWinRTBluetoothGattDescriptor.DoSetBroadcasts(const Value: Boolean);
var
B: TBytes;
begin
if not (TBluetoothProperty.Broadcast in FCharacteristic.Properties) then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
if Value then
B := [$01, $00]
else
B := [$00, $00];
SetValue(B);
end;
procedure TWinRTBluetoothGattDescriptor.DoSetIndication(const Value: Boolean);
var
B: TBytes;
begin
inherited;
if not (TBluetoothProperty.Indicate in FCharacteristic.Properties) then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
if Value then
B := [$02, $00]
else
B := [$00, $00];
SetValue(B);
end;
procedure TWinRTBluetoothGattDescriptor.DoSetNotification(const Value: Boolean);
var
B: TBytes;
begin
inherited;
if not (TBluetoothProperty.Notify in FCharacteristic.Properties) then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
if Value then
B := [$01, $00]
else
B := [$00, $00];
SetValue(B);
end;
procedure TWinRTBluetoothGattDescriptor.DoSetUserDescription(const Value: string);
begin
inherited;
if UUID <> TGenericAttributeProfile_GattDescriptorUuids.Statics.CharacteristicUserDescription then
raise EBluetoothLEDescriptorException.CreateRes(@SBluetoothDescriptorTypeError);
DoSetValue(TEncoding.Unicode.GetBytes(Value));
end;
procedure TWinRTBluetoothGattDescriptor.DoSetValue(const AValue: TBytes);
begin
FValue := AValue;
end;
function TWinRTBluetoothGattDescriptor.GetUUID: TBluetoothUUID;
begin
Result := FGattDescriptor.Uuid;
end;
function TWinRTBluetoothGattDescriptor.SetValueToDevice: TBluetoothGattStatus;
var
LWriteValueAsync: IAsyncOperation_1__GenericAttributeProfile_GattCommunicationStatus;
begin
Result := TBluetoothGattStatus.Failure;
if (TAsyncOperation.Wait(
FGattDescriptor.WriteValueAsync(BytesToIBuffer(FValue)), LWriteValueAsync) = AsyncStatus.Completed) and
(LWriteValueAsync.GetResults = GenericAttributeProfile_GattCommunicationStatus.Success) then
Result := TBluetoothGattStatus.Success;
end;
function TWinRTBluetoothGattDescriptor.UpdateValueFromDevice: TBluetoothGattStatus;
var
LGattReadValueAsyncOp: IAsyncOperation_1__GenericAttributeProfile_IGattReadResult;
LReadResult: GenericAttributeProfile_IGattReadResult;
begin
Result := TBluetoothGattStatus.Success;
if TAsyncOperation.Wait(
FGattDescriptor.ReadValueAsync(BluetoothCacheMode.Uncached),
LGattReadValueAsyncOp) = AsyncStatus.Completed then
begin
LReadResult := LGattReadValueAsyncOp.GetResults;
if LReadResult.Status = GenericAttributeProfile_GattCommunicationStatus.Success then
FValue := BytesFromIBuffer(LReadResult.Value)
else
Result := TBluetoothGattStatus.Failure;
end;
end;
{ TConnectionStatusChangeEventHandler }
constructor TConnectionStatusChangeEventHandler.Create(const ADevice: TWinRTBluetoothLEDevice);
begin
inherited Create;
FDevice := ADevice;
end;
procedure TConnectionStatusChangeEventHandler.Invoke(sender: IBluetoothLEDevice; args: IInspectable);
begin
FDevice.ConnectionStatusChanged;
end;
{ TGattValueChangedEventHandler }
constructor TGattValueChangedEventHandler.Create(const AGattCharacteristic: TWinRTBluetoothGattCharacteristic);
begin
inherited Create;
FGattCharacteristic := AGattCharacteristic;
end;
procedure TGattValueChangedEventHandler.Invoke(sender: GenericAttributeProfile_IGattCharacteristic;
args: GenericAttributeProfile_IGattValueChangedEventArgs);
begin
FGattCharacteristic.GattValueChangedEvent(args);
end;
{ TAsyncOperation }
class function TAsyncOperation.Wait(const AAsyncOp: T; var AsyncOpResult: T; ATimeout: Cardinal): AsyncStatus;
var
LAsyncInfo: IAsyncInfo;
LTimer: TThreadTimer;
begin
if AAsyncOp.QueryInterface(IAsyncInfo, LAsyncInfo) <> 0 then
raise Exception.CreateRes(@SNoAsyncInfo);
LTimer := TThreadTimer.Create(
procedure
begin
LAsyncInfo.Cancel;
end,
ATimeout);
LTimer.Start;
while LAsyncInfo.Status = AsyncStatus.Started do
TThread.Yield;
LTimer.Free;
AsyncOpResult := AAsyncOp;
Result := LAsyncInfo.Status;
end;
{ TAsyncOperation.TThreadTimer }
procedure TAsyncOperation.TThreadTimer.Cancel;
begin
Terminate;
FEvent.SetEvent;
FOnTimer := nil;
end;
constructor TAsyncOperation.TThreadTimer.Create(const ACancelProc: TCancelProcedure; Timeout: Cardinal);
begin
inherited Create(True);
FOnTimer := ACancelProc;
FTimeout := Timeout;
FEvent := TEvent.Create;
end;
destructor TAsyncOperation.TThreadTimer.Destroy;
begin
Cancel;
FEvent.Free;
inherited;
end;
procedure TAsyncOperation.TThreadTimer.Execute;
begin
inherited;
FEvent.WaitFor(FTimeout);
if not Terminated and Assigned(FOnTimer) then
FOnTimer;
end;
{ TBLEAdvertisementReceivedEventHandler }
constructor TBLEAdvertisementReceivedEventHandler.Create(const AAdapter: TWinRTBluetoothLEAdapter);
begin
inherited Create;
FAdapter := AAdapter;
end;
procedure TBLEAdvertisementReceivedEventHandler.Invoke(sender: IBluetoothLEAdvertisementWatcher;
args: IBluetoothLEAdvertisementReceivedEventArgs);
begin
FAdapter.BLEAdvertisementReceived(args.Advertisement, args.AdvertisementType, args.BluetoothAddress,
args.RawSignalStrengthInDBm, args.Timestamp);
end;
{ TWinRTBluetoothLEAdvertiseData }
function TWinRTBluetoothLEAdvertiseData.ContainsServiceUUID(const AServiceUUID: TBluetoothUUID): Boolean;
begin
Result := FServiceUUIDs.Contains(AServiceUUID);
end;
constructor TWinRTBluetoothLEAdvertiseData.Create(const ADevice: System.Bluetooth.TBluetoothLEDevice);
begin
inherited Create;
FDevice := ADevice;
end;
function TWinRTBluetoothLEAdvertiseData.DoAddServiceData(const AServiceUUID: TBluetoothUUID;
const AData: TBytes): Boolean;
begin
// Not supported in Windows
Result := False;
end;
function TWinRTBluetoothLEAdvertiseData.DoAddServiceUUID(const AServiceUUID: TBluetoothUUID): Boolean;
begin
// Not supported in Windows
Result := False;
end;
procedure TWinRTBluetoothLEAdvertiseData.DoClearServiceData;
begin
inherited;
// Not supported in Windows
end;
procedure TWinRTBluetoothLEAdvertiseData.DoClearServiceUUIDs;
begin
inherited;
// Not supported in Windows
end;
procedure TWinRTBluetoothLEAdvertiseData.DoRemoveServiceData(const AServiceUUID: TBluetoothUUID);
begin
inherited;
// Not supported in Windows
end;
procedure TWinRTBluetoothLEAdvertiseData.DoRemoveServiceUUID(const AServiceUUID: TBluetoothUUID);
begin
inherited;
// Not supported in Windows
end;
function TWinRTBluetoothLEAdvertiseData.GetDataForService(const AServiceUUID: TBluetoothUUID): TBytes;
begin
if Length(GetServiceData) > 0 then
FServiceData.TryGetValue(AServiceUUID, Result)
else
Result := nil;
end;
function TWinRTBluetoothLEAdvertiseData.GetLocalName: string;
begin
Result := FLocalName;
end;
function TWinRTBluetoothLEAdvertiseData.GetManufacturerSpecificData: TBytes;
begin
if (FDevice <> nil) and (FDevice.AdvertisedData <> nil) then
if FDevice.AdvertisedData.ContainsKey(TScanResponseKey.ManufacturerSpecificData) then
FManufacturerSpecificData := FDevice.AdvertisedData.Items[TScanResponseKey.ManufacturerSpecificData];
Result := FManufacturerSpecificData;
end;
function TWinRTBluetoothLEAdvertiseData.GetServiceData: TArray;
var
LData: TBytes;
LServiceTBytes: TBytes;
LServiceUUID: TGUID;
LSize: Integer;
LServiceData: TPair<TBluetoothUUID,TBytes>;
begin
if (FDevice <> nil) and (FDevice.AdvertisedData <> nil) then
if FDevice.AdvertisedData.ContainsKey(TScanResponseKey.ServiceData) then
begin
LData := FDevice.AdvertisedData.Items[TScanResponseKey.ServiceData];
LServiceUUID := System.Bluetooth.TBluetoothUUIDHelper.GetBluetoothUUID(PWord(@LData[0])^);
LSize := Length(LData) - 2;
SetLength(LServiceTBytes, LSize);
Move(LData[2], LServiceTBytes[0], LSize);
FServiceData.AddOrSetValue(LServiceUUID, LServiceTBytes);
end;
// Prepared to be an array, but it will just own one element for now.
SetLength(Result, FServiceData.count);
LSize := 0;
for LServiceData in FServiceData do
begin
Result[LSize].create(LServiceData);;
Inc(LSize);
end;
end;
function TWinRTBluetoothLEAdvertiseData.GetServiceUUIDs: TArray;
begin
Result := FServiceUUIDs.ToArray;
end;
function TWinRTBluetoothLEAdvertiseData.GetTxPowerLevel: Integer;
begin
if (FDevice <> nil) and (FDevice.AdvertisedData <> nil) then
if FDevice.AdvertisedData.ContainsKey(TScanResponseKey.TxPowerLevel) then
FTxPowerLevel := ShortInt(FDevice.AdvertisedData.Items[TScanResponseKey.TxPowerLevel]);
Result := FTxPowerLevel;
end;
procedure TWinRTBluetoothLEAdvertiseData.SetLocalName(const ALocalName: string);
begin
inherited;
// Not supported in Windows
end;
procedure TWinRTBluetoothLEAdvertiseData.SetManufacturerSpecificData(const AManufacturerSpecificData: TBytes);
begin
inherited;
FManufacturerSpecificData := AManufacturerSpecificData;
end;
procedure TWinRTBluetoothLEAdvertiseData.SetTxPowerLevel(ATxPowerLevel: Integer);
begin
inherited;
// Not supported in Windows
end;
{ TWinRTBluetoothGattServer }
constructor TWinRTBluetoothGattServer.Create(const AManager: TBluetoothLEManager);
begin
inherited;
FAdvertismentPublisher := TBluetoothLEAdvertisementPublisher.Create;
end;
destructor TWinRTBluetoothGattServer.Destroy;
begin
if IsAdvertising then
StopAdvertising;
inherited;
end;
function TWinRTBluetoothGattServer.DoAddCharacteristic(const AService: TBluetoothGattService;
const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattServer.DoAddService(const AService: TBluetoothGattService): Boolean;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
procedure TWinRTBluetoothGattServer.DoClearServices;
begin
inherited;
// Not implemented
end;
procedure TWinRTBluetoothGattServer.DoClose;
begin
inherited;
// Not implemented
end;
function TWinRTBluetoothGattServer.DoCreateAdvertiseData: TBluetoothLEAdvertiseData;
begin
Result := TWinRTBluetoothLEAdvertiseData.Create(nil);
end;
function TWinRTBluetoothGattServer.DoCreateCharacteristic(const AService: TBluetoothGattService;
const AnUUID: TBluetoothUUID; const AProps: TBluetoothPropertyFlags;
const ADescription: string): TBluetoothGattCharacteristic;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattServer.DoCreateDescriptor(const ACharacteristic: TBluetoothGattCharacteristic;
const AnUUID: TBluetoothUUID): TBluetoothGattDescriptor;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattServer.DoCreateIncludedService(const AService: TBluetoothGattService;
const AnUUID: TBluetoothUUID; AType: TBluetoothServiceType): TBluetoothGattService;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattServer.DoCreateService(const AnUUID: TBluetoothUUID;
AType: TBluetoothServiceType): TBluetoothGattService;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattServer.DoGetServices: TBluetoothGattServiceList;
begin
raise EBluetoothServiceException.CreateRes(@SBluetoothNotImplemented);
end;
function TWinRTBluetoothGattServer.DoIsAdvertising: Boolean;
begin
Result := FAdvertismentPublisher.Status = BluetoothLEAdvertisementPublisherStatus.Started
end;
procedure TWinRTBluetoothGattServer.DoCharacteristicReadRequest(const ADevice: System.Bluetooth.TBluetoothLEDevice; ARequestId: Integer;
AnOffset: Integer; const AGattCharacteristic: TBluetoothGattCharacteristic);
begin
// Not implemented
end;
procedure TWinRTBluetoothGattServer.DoCharacteristicWriteRequest(const ADevice: System.Bluetooth.TBluetoothLEDevice; ARequestId: Integer;
const AGattCharacteristic: TBluetoothGattCharacteristic; APreparedWrite: Boolean; AResponseNeeded: Boolean;
AnOffset: Integer; const AValue: TBytes);
begin
// Not implemented
end;
procedure TWinRTBluetoothGattServer.DoUpdateCharacteristicValue(const ACharacteristic: TBluetoothGattCharacteristic);
begin
// Not implemented
end;
procedure TWinRTBluetoothGattServer.DoServiceAdded(AStatus: TBluetoothGattStatus; const AService: TBluetoothGattService);
begin
// Not implemented
end;
procedure TWinRTBluetoothGattServer.DoStartAdvertising;
var
LManufacturerData: IBluetoothLEManufacturerData;
LRawManufacturerData: TBytes;
LCompanyID: Word;
begin
inherited;
if IsAdvertising then
StopAdvertising;
LRawManufacturerData := AdvertiseData.ManufacturerSpecificData;
FAdvertismentPublisher.Advertisement.ManufacturerData.Clear;
if Length(LRawManufacturerData) >= 2 then
begin
LManufacturerData := TBluetoothLEManufacturerData.Create;
Move(LRawManufacturerData[0], LCompanyId, SizeOf(Word));
LManufacturerData.CompanyId := LCompanyID;
if Length(LRawManufacturerData) >= 3 then
LManufacturerData.Data := BytesToIBuffer(LRawManufacturerData, 2);
FAdvertismentPublisher.Advertisement.ManufacturerData.Append(LManufacturerData);
FAdvertismentPublisher.Start;
end
else
raise EBluetoothLEAdvertiseDataException.CreateRes(@SBluetoothLEAdvertisementEmpty);
end;
procedure TWinRTBluetoothGattServer.DoStopAdvertising;
begin
if IsAdvertising then
FAdvertismentPublisher.Stop;
end;
{$ENDIF}
end.
Delphi 11.2 BLE for Windows RT
- Информация о материале
- Автор: Vsevolod V Gromov
- Категория: Resources
- Просмотров: 183
A quick fixup for Embarcadero BLE runtime, at least allowing to work with Windows 8+ BLE subsystem without deadlocks