-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathBluetoothcomponentthreaded.pas
1304 lines (1167 loc) · 48.8 KB
/
Bluetoothcomponentthreaded.pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
{*******************************************************}
{ }
{ CodeGear Delphi Runtime Library }
{ Copyright(c) 2016 Embarcadero Technologies, Inc. }
{ All rights reserved }
{ }
{*******************************************************}
unit BluetoothComponentThreaded;
interface
{$I DelphiDefs.inc}
{$IFDEF LT_10_2}
uses
System.Classes, System.SysUtils, System.Types, System.Bluetooth;
// We have Bluetooth Classic in all platforms except iOS
{$IF defined(MSWINDOWS) or (defined(MACOS) and not defined(IOS)) or defined(ANDROID)}
{$DEFINE BLUETOOTH_CLASSIC}
{$ENDIF}
type
{$IF defined(BLUETOOTH_CLASSIC)}
{TBluetooth}
[ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 or pidAndroid)]
/// <summary>
/// TBluetooth component provides access to the Classic Bluetooth framework functionality.
/// This framework let applications wirelessly connect to other Bluetooth devices, enabling point-to-point and multipoint wireless features
/// </summary>
TBluetooth = class(TComponent)
private
FEnabled: Boolean;
FOnDiscoverableEnd: TDiscoverableEndEvent;
FOnDiscoveryEnd: TDiscoveryEndEvent;
FOnRemoteRequestPair: TRemoteRequestPairEvent;
protected
/// <summary>
/// FBluetoothManager Var that provides access to bluetooth Manager
/// </summary>
FBluetoothManager: TBluetoothManager;
/// <summary>
/// FBluetoothManager Setup
/// </summary>
procedure Setup;
{TBluetoothManager}
function GetLastPairedDevices: TBluetoothDeviceList;
function GetCurrentManager: TBluetoothManager;
function GetCurrentAdapter: TBluetoothAdapter;
function GetSocketTimeout: Integer;
procedure SetSocketTimeout(Timeout: Integer);
function GetConnectionState: TBluetoothConnectionState;
/// <summary>
/// Fired when the Discoverable state ends
/// </summary>
procedure DoDiscoverableEnd(const Sender: TObject);
/// <summary>
/// fired when the DiscoverDevices(ATimeout: Integer) ends
/// </summary>
procedure DoDiscoveryEnd(const Sender: TObject; const ADeviceList: TBluetoothDeviceList);
/// <summary>
/// fired when a pairing request is received
/// </summary>
procedure DoRemoteRequestPair(const ADevice: TBluetoothDevice);
function GetStateConnected: Boolean;
function GetLastDiscoveredDevices: TBluetoothDeviceList;
function GetLastDiscoveredTimeStamp: TDateTime;
{TBluetoothAdapter}
function GetScanMode: TBluetoothScanMode;
/// <summary> SetEnabled processes the Bluetooth request of Enabled </summary>
procedure SetEnabled(AEnable: Boolean);
public
/// <summary>
/// Creates a new instance of the component
/// </summary>
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
{TBluetoothManager}
/// <summary>
/// Returns the current Manager
/// </summary>
property CurrentManager: TBluetoothManager read GetCurrentManager;
/// <summary>
/// Returns the current adapter (The local Bluetooth adapter, Bluetooth radio)
/// </summary>
property CurrentAdapter: TBluetoothAdapter read GetCurrentAdapter;
/// <summary>
/// Timeout used in the socket conections
/// </summary>
property SocketTimeout: Integer read GetSocketTimeout write SetSocketTimeout;
/// <summary>
/// Current adapter state (Connected or Disconnected)
/// </summary>
property ConnectionState: TBluetoothConnectionState read GetConnectionState;
/// <summary>
/// True when the current adapter is connected, False otherwise
/// </summary>
property StateConnected: Boolean read GetStateConnected;
/// <summary>
/// The current adapter performs a new discoverable devices scanning until a timeout
/// </summary>
procedure DiscoverDevices(ATimeout: Integer);
/// <summary>
/// The current adapter cancels the performance of DiscoverDevices
/// </summary>
procedure CancelDiscovery;
/// <summary>
/// Returns a list of last discovered devices
/// </summary>
property LastDiscoveredDevices: TBluetoothDeviceList read GetLastDiscoveredDevices;//FDiscoveredDevices;
/// <summary>
/// Returns a timestamp of last DiscoveredDevices performed
/// </summary>
property LastDiscoveredTimeStamp: TDateTime read GetLastDiscoveredTimeStamp;
/// <summary>
/// Enables the current adapter to be discoverable to other devices for a period of time
/// </summary>
procedure StartDiscoverable(Timeout: Integer);
/// <summary>
/// Returns a list of last paired devices
/// </summary>
property LastPairedDevices: TBluetoothDeviceList read GetLastPairedDevices;
{TBluetoothAdapter}
/// <summary>
/// The current adapter performs a pairing request to a passed device
/// </summary>
function Pair(const ADevice: TBluetoothDevice): Boolean;
/// <summary>
/// The current adapter performs an UnPairing request to a passed device
/// </summary>
function UnPair(const ADevice: TBluetoothDevice): Boolean;
/// <summary>
/// Query the current adapter for paired devices
/// </summary>
function PairedDevices: TBluetoothDeviceList; overload;
/// <summary>
/// Query the current adapter for paired devices filtered by service
/// </summary>
function PairedDevices(const AUUID: TBluetoothUUID): TBluetoothDeviceList; overload;
/// <summary>
/// Creates a server socket
/// </summary>
function CreateServerSocket(const AName: string; const AUUID: TGUID; Secure: Boolean): TBluetoothServerSocket;
/// <summary>
/// Current adapter scan mode state (None, Connectable, Discoverable)
/// </summary>
property ScanMode: TBluetoothScanMode read GetScanMode;
{TBluetoothDevice}
/// <summary>
/// Creates a client socket
/// </summary>
function CreateClientSocket(const ADevice: TBluetoothDevice; const AUUID: TGUID; Secure: Boolean): TBluetoothSocket;
/// <summary>
/// True when the passed device is paired to the current adapter, False otherwise
/// </summary>
function IsPaired(const ADevice: TBluetoothDevice): Boolean;
/// <summary>
/// Returns the passed device state (None, Paired, Connected)
/// </summary>
function State(const ADevice: TBluetoothDevice): TBluetoothDeviceState;
/// <summary>
/// Returns a list of the advertised services of the passed device
/// </summary>
function GetServices(const ADevice: TBluetoothDevice): TBluetoothServiceList;
/// <summary>
/// Returns the last list of the advertised services of the passed device
/// </summary>
function LastServiceList(const ADevice: TBluetoothDevice): TBluetoothServiceList;
published
/// <summary> Enable or Disable the Bluetooth component </summary>
property Enabled: Boolean read FEnabled write SetEnabled;
/// <summary>
/// OnDiscoveryEnd is fired when DiscoverDevices gets the timeout
/// </summary>
property OnDiscoveryEnd: TDiscoveryEndEvent read FOnDiscoveryEnd write FOnDiscoveryEnd;
/// <summary>
/// OnDiscoverableEnd is fired when the discoverable state gets the timeout
/// </summary>
property OnDiscoverableEnd: TDiscoverableEndEvent read FOnDiscoverableEnd write FOnDiscoverableEnd;
/// <summary>
/// OnRemoteRequestPair is fired when a remote device request for pairing
/// </summary>
property OnRemoteRequestPair: TRemoteRequestPairEvent read FOnRemoteRequestPair write FOnRemoteRequestPair;
end;
{$ENDIF}
{TBluetoothLEThreaded}
TBluetoothLEThreaded = class(TComponent)
private
//FOnDescriptorReadRequest: TGattDescriptorReadEvent;
//FOnDescriptorWriteRequest: TGattDescriptorWriteEvent;
FEnabled: Boolean;
FForceRefreshCachedDevices: Boolean;
FOnCharacteristicRead: TGattCharacteristicEvent;
FOnCharacteristicReadRequest: TGattCharacteristicReadEvent;
FOnCharacteristicWrite: TGattCharacteristicEvent;
FOnCharacteristicWriteRequest: TGattCharacteristicWriteEvent;
FOnCharacteristicSubscribed: TGattCharacteristicSubscriptionEvent;
FOnCharacteristicUnSubscribed: TGattCharacteristicSubscriptionEvent;
FOnConnectedDevice: TConnectLEDeviceEvent;
FOnDescriptorRead: TGattDescriptorEvent;
FOnDescriptorWrite: TGattDescriptorEvent;
FOnConnect: TNotifyEvent;
FOnDisconnect: TNotifyEvent;
FOnDisconnectDevice: TConnectLEDeviceEvent;
FOnDiscoverLEDevice: TDiscoverLEDeviceEvent;
FOnEndDiscoverDevices: TDiscoveryLEEndEvent;
FOnEndDiscoverServices: TDiscoverServicesEvent;
FOnServicesDiscovered: TDiscoverServicesEvent;
FOnReadRSSI: TGattDeviceRSSIEvent;
FOnReliableWriteCompleted: TGattOperationResultEvent;
FOnServiceAdded: TGattServiceEvent;
protected
FManager: TBluetoothLEManager;
FServer: TBluetoothGattServer;
/// <summary>
/// DoInternalDiscoverLEDevice is the procedure asocieted to OnDiscoverLeDevice event, internal job purpose
/// </summary>
procedure DoInternalDiscoverLEDevice(const Sender: TObject; const ADevice: TBluetoothLEDevice; Rssi: Integer; const ScanResponse: TScanResponse); overload;
procedure DoInternalDiscoveryEnd(const Sender: TObject; const ADeviceList: TBluetoothLEDeviceList); overload;
procedure Setup;
/// <summary>
/// This method set up the GattServer if supported by the device.
/// </summary>
procedure SetupGattServer;
/// <summary> procedure for the OnConnect Event </summary>
procedure DoConnect(Sender: TObject);
/// <summary> procedure for the OnDisconnect Event </summary>
procedure DoDisconnect(Sender: TObject);
procedure DoConnectedDevice(const Sender: TObject; const ADevice: TBluetoothLEDevice);
procedure DoDisconnectDevice(const Sender: TObject; const ADevice: TBluetoothLEDevice);
procedure DoOnCharacteristicRead(const Sender: TObject; const ACharacteristic: TBluetoothGattCharacteristic;
AGattStatus: TBluetoothGattStatus);
procedure DoOnCharacteristicReadRequest(const Sender: TObject; const ACharacteristic: TBluetoothGattCharacteristic;
var AGattStatus: TBluetoothGattStatus);
procedure DoOnCharacteristicWrite(const Sender: TObject; const ACharacteristic: TBluetoothGattCharacteristic;
AGattStatus: TBluetoothGattStatus);
procedure DoOnCharacteristicWriteRequest(const Sender: TObject; const ACharacteristic: TBluetoothGattCharacteristic;
var AGattStatus: TBluetoothGattStatus; const AValue: TByteDynArray);
/// <summary> procedure for the OnCharacteristicSubscribed Event </summary>
procedure DoOnCharacteristicSubscribed(const Sender: TObject; const AClientId: string;
const ACharacteristic: TBluetoothGattCharacteristic);
/// <summary> procedure for the OnCharacteristicUnSubscribed Event </summary>
procedure DoOnCharacteristicUnSubscribed(const Sender: TObject; const AClientId: string;
const ACharacteristic: TBluetoothGattCharacteristic);
procedure DoOnDescriptorRead(const Sender: TObject; const ADescriptor: TBluetoothGattDescriptor;
AGattStatus: TBluetoothGattStatus);
procedure DoOnDescriptorReadRequest(const Sender: TObject; const ADescriptor: TBluetoothGattDescriptor;
var AGattStatus: TBluetoothGattStatus);
procedure DoOnDescriptorWrite(const Sender: TObject; const ADescriptor: TBluetoothGattDescriptor;
AGattStatus: TBluetoothGattStatus);
procedure DoOnDescriptorWriteRequest(const Sender: TObject; const ADescriptor: TBluetoothGattDescriptor;
var AGattStatus: TBluetoothGattStatus; const AValue: TBytes);
procedure DoOnReadRSSI(const Sender: TObject; ARssiValue: Integer; AGattStatus: TBluetoothGattStatus);
procedure DoOnReliableWriteCompleted(const Sender: TObject; AGattStatus: TBluetoothGattStatus);
procedure DoServiceAdded(const Sender: TObject; const AService: TBluetoothGattService;
const AGattStatus: TBluetoothGattStatus);
/// <summary>
/// DoOnDiscoverLEDevice is the procedure associated to OnDiscoverLEDevice
/// </summary>
procedure DoOnDiscoverLEDevice(const Sender: TObject; const ADevice: TBluetoothLEDevice; Rssi: Integer; const ScanResponse: TScanResponse);
/// <summary>
/// DoOnServicesDiscovered is the procedure associated to OnServicesDiscovered
/// </summary>
procedure DoOnServicesDiscovered(const Sender: TObject; const AServiceList: TBluetoothGattServiceList);
procedure DoOnEndDiscoverDevices(const Sender: TObject; const ADeviceList: TBluetoothLEDeviceList);
/// <summary> SetEnabled processes the Bluetooth request of Enabled </summary>
procedure SetEnabled(AEnable: Boolean);
function GetSupportsGattClient: Boolean;
function GetSupportsGattServer: Boolean;
/// <summary> GetDiscoveredDevices process the property DiscoveredDevices </summary>
function GetDiscoveredDevices: TBluetoothLEDeviceList;
/// <summary> SetForceRefreshCachedDevices sets the property ForceRefreshCachedDevices </summary>
procedure SetForceRefreshCachedDevices(Value: Boolean);
public
//function AddDescriptor(const ACharacteristic: TBluetoothGattCharacteristic; const ADescriptor: TBluetoothGattDescriptor): Boolean;
//function CreateDescriptor(const ACharacteristic: TBluetoothGattCharacteristic; const AUUID: TBluetoothUUID): TBluetoothGattDescriptor;
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
function AddCharacteristic(const AService: TBluetoothGattService;
const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
function BeginReliableWrite(const ADevice: TBluetoothLEDevice): Boolean;
function CreateCharacteristic(const AService: TBluetoothGattService; const AUUID: TBluetoothUUID;
APropertyFlags: TBluetoothPropertyFlags; const ADescription: string): TBluetoothGattCharacteristic;
function CreateIncludedService(const AService: TBluetoothGattService; const AnUUID: TBluetoothUUID;
AType: TBluetoothServiceType): TBluetoothGattService;
function CreateService(const AnUUID: TBluetoothUUID; AType: TBluetoothServiceType): TBluetoothGattService;
function DiscoverServices(const ADevice: TBluetoothLEDevice): Boolean;
function ExecuteReliableWrite(const ADevice: TBluetoothLEDevice): Boolean;
function GetCharacteristic(const AService: TBluetoothGattService; const AUUID: TBluetoothUUID)
: TBluetoothGattCharacteristic;
function GetCharacteristics(const AService: TBluetoothGattService): TBluetoothGattCharacteristicList;
function GetConnectionState: TBluetoothConnectionState;
function GetCurrentAdapter: TBluetoothLEAdapter;
function GetCurrentManager: TBluetoothLEManager;
function GetDescriptors(const ACharacteristic: TBluetoothGattCharacteristic): TBluetoothGattDescriptorList;
function GetGattServer: TBluetoothGattServer;
function GetService(const ADevice: TBluetoothLEDevice; const AServiceID: TBluetoothUUID): TBluetoothGattService;
function GetServices(const ADevice: TBluetoothLEDevice): TBluetoothGattServiceList;
function ReadCharacteristic(const ADevice: TBluetoothLEDevice;
const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
function ReadDescriptor(const ADevice: TBluetoothLEDevice; const ADescriptor: TBluetoothGattDescriptor): Boolean;
function SubscribeToCharacteristic(const ADevice: TBluetoothLEDevice;
const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
function WriteCharacteristic(const ADevice: TBluetoothLEDevice;
const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
function WriteDescriptor(const ADevice: TBluetoothLEDevice; const ADescriptor: TBluetoothGattDescriptor): Boolean;
procedure AbortReliableWrite(const ADevice: TBluetoothLEDevice);
procedure CancelDiscovery;
procedure ClearServices;
function DiscoverDevices(ATimeout: Integer): Boolean; overload;
function DiscoverDevices(ATimeout: Integer; const AList: TBluetoothUUIDsList): Boolean; overload;
function DiscoverDevices(ATimeout: Integer; AList: array of TBluetoothUUID): Boolean; overload;
/// <summary> Starts a scan for Bluetooth LE devices that advertise data. ABluetoothLEScanFilterList is a List of Filters to perform scan
/// related operations for specific devices. </summary>
function DiscoverDevices(ATimeout: Cardinal; const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList): Boolean; overload;
function UnSubscribeToCharacteristic(const ADevice: TBluetoothLEDevice;
const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
procedure UpdateCharacteristicValue(const ACharacteristic: TBluetoothGattCharacteristic);
/// <summary>
/// RssiToDistance takes as a in-parameters the RSSI (Received signal strength indication)dBm,
/// the TxPower (Signal Strength at 1m distance)dBm and a Signal Propagation const, and
/// returns an approximation of the distance to a device in meters
/// </summary>
function RssiToDistance(ARssi, ATxPower: Integer; ASignalPropagationConst: Single): Double;
/// <summary>
/// ReadRemoteRSSI read the RSSI from a remote Device. This is an asynchronous operation,
/// once ReadRemoteRSSI is completed, the OnReadRSSI callback is triggered.
/// </summary>
function ReadRemoteRSSI(const ADevice: TBluetoothLEDevice): Boolean;
/// <summary> AddService Add the previously created Services and characteristics </summary>
function AddService(const AService: TBluetoothGattService): Boolean;
property ConnectionState: TBluetoothConnectionState read GetConnectionState;
property GattServer: TBluetoothGattServer read GetGattServer;
property CurrentAdapter: TBluetoothLEAdapter read GetCurrentAdapter;
property CurrentManager: TBluetoothLEManager read GetCurrentManager;
/// <summary> DiscoveredDevices returns the list of found devices </summary>
property DiscoveredDevices: TBluetoothLEDeviceList read GetDiscoveredDevices;
property SupportsGattClient: Boolean read GetSupportsGattClient;
property SupportsGattServer: Boolean read GetSupportsGattServer;
/// <summary> Setting to True, discovery process attemps to retrieve services from the actual device
/// instead of use the cached ones. This property only has effect in Android. Default is False </summary>
property ForceRefreshCachedDevices: Boolean read FForceRefreshCachedDevices write SetForceRefreshCachedDevices;
published
// property OnDescriptorReadRequest: TGattDescriptorReadEvent read FOnDescriptorReadRequest write FOnDescriptorReadRequest;
// property OnDescriptorWriteRequest: TGattDescriptorWriteEvent read FOnDescriptorWriteRequest write FOnDescriptorWriteRequest;
/// <summary> Enable or Disable the BluetoothLE component </summary>
property Enabled: Boolean read FEnabled write SetEnabled;
property OnCharacteristicRead: TGattCharacteristicEvent read FOnCharacteristicRead write FOnCharacteristicRead;
property OnCharacteristicReadRequest: TGattCharacteristicReadEvent read FOnCharacteristicReadRequest
write FOnCharacteristicReadRequest;
property OnCharacteristicWrite: TGattCharacteristicEvent read FOnCharacteristicWrite write FOnCharacteristicWrite;
property OnCharacteristicWriteRequest: TGattCharacteristicWriteEvent read FOnCharacteristicWriteRequest
write FOnCharacteristicWriteRequest;
/// <summary>
/// OnCharacteristicSubscribed is triggered when a remote device Subscribes to one of Gatt server Characteristic.
/// </summary>
property OnCharacteristicSubscribed: TGattCharacteristicSubscriptionEvent read FOnCharacteristicSubscribed
write FOnCharacteristicSubscribed;
/// <summary>
/// OnCharacteristicSubscribed is triggered when a remote device UnSubscribes to one of Gatt server Characteristic.
/// </summary>
property OnCharacteristicUnSubscribed: TGattCharacteristicSubscriptionEvent read FOnCharacteristicUnSubscribed
write FOnCharacteristicUnSubscribed;
/// <summary>
/// OnConnectDevice is triggered when a remote device connects to our Gatt server.
/// </summary>
property OnConnectedDevice: TConnectLEDeviceEvent read FOnConnectedDevice write FOnConnectedDevice;
property OnDescriptorRead: TGattDescriptorEvent read FOnDescriptorRead write FOnDescriptorRead;
property OnDescriptorWrite: TGattDescriptorEvent read FOnDescriptorWrite write FOnDescriptorWrite;
/// <summary>
/// OnConnect is triggered when we connect to a remote Gatt server device.
/// </summary>
property OnConnect: TNotifyEvent read FOnConnect write FOnConnect;
/// <summary>
/// OnDisconnect is triggered when we disconnect from a remote Gatt server device.
/// </summary>
property OnDisconnect: TNotifyEvent read FOnDisconnect write FOnDisconnect;
/// <summary>
/// OnDisconnectDevice is triggered when a remote device disconnects from our Gatt server.
/// </summary>
property OnDisconnectDevice: TConnectLEDeviceEvent read FOnDisconnectDevice write FOnDisconnectDevice;
/// <summary>
/// OnDiscoverLEDevice is fired each time a device is found
/// </summary>
property OnDiscoverLEDevice: TDiscoverLEDeviceEvent read FOnDiscoverLEDevice write FOnDiscoverLEDevice;
/// <summary>
/// OnServicesDiscovered is fired each time a device services are found
/// </summary>
property OnServicesDiscovered: TDiscoverServicesEvent read FOnServicesDiscovered write FOnServicesDiscovered;
property OnEndDiscoverDevices: TDiscoveryLEEndEvent read FOnEndDiscoverDevices write FOnEndDiscoverDevices;
/// <summary>
/// OnEndDiscoverServices property deprecated, use OnServicesDiscovered;
/// </summary>
property OnEndDiscoverServices: TDiscoverServicesEvent read FOnEndDiscoverServices write FOnEndDiscoverServices;
property OnReadRSSI: TGattDeviceRSSIEvent read FOnReadRSSI write FOnReadRSSI;
property OnReliableWriteCompleted: TGattOperationResultEvent read FOnReliableWriteCompleted
write FOnReliableWriteCompleted;
property OnServiceAdded: TGattServiceEvent read FOnServiceAdded write FOnServiceAdded;
end;
{$ENDIF}
implementation
{$IFDEF LT_10_2}
uses
System.Generics.Collections, System.NetConsts;
{$IF defined(BLUETOOTH_CLASSIC)}
{ TBluetooth }
function TBluetooth.GetCurrentManager: TBluetoothManager;
begin
Result := FBluetoothManager;
end;
function TBluetooth.GetConnectionState: TBluetoothConnectionState;
begin
if FBluetoothManager <> nil then
Result := FBluetoothManager.ConnectionState
else
Result := TBluetoothConnectionState.Disconnected;
end;
function TBluetooth.GetCurrentAdapter: TBluetoothAdapter;
begin
if FBluetoothManager <> nil then
Result := FBluetoothManager.CurrentAdapter
else
Result := nil;
end;
procedure TBluetooth.DiscoverDevices(ATimeout: Integer);
begin
if FBluetoothManager <> nil then
FBluetoothManager.StartDiscovery(ATimeout);
end;
procedure TBluetooth.DoDiscoverableEnd(const Sender: TObject);
begin
if FEnabled and Assigned(FOnDiscoverableEnd) then
if FEnabled and Assigned(FOnDiscoverableEnd) then
FOnDiscoverableEnd(Sender);
end;
procedure TBluetooth.DoDiscoveryEnd(const Sender: TObject; const ADeviceList: TBluetoothDeviceList);
begin
if FEnabled and Assigned(FOnDiscoveryEnd) then
if FEnabled and Assigned(FOnDiscoveryEnd) then
FOnDiscoveryEnd(Sender, ADeviceList);
end;
procedure TBluetooth.DoRemoteRequestPair(const ADevice: TBluetoothDevice);
begin
if FEnabled and Assigned(FOnRemoteRequestPair) then
if FEnabled and Assigned(FOnRemoteRequestPair) then
FOnRemoteRequestPair(ADevice);
end;
procedure TBluetooth.CancelDiscovery;
begin
if FBluetoothManager <> nil then
FBluetoothManager.CancelDiscovery;
end;
constructor TBluetooth.Create(AOwner: TComponent);
begin
inherited;
FEnabled := False;
end;
procedure TBluetooth.Setup;
begin
FBluetoothManager := TBluetoothManager.Current;
TBluetoothManager.Current.EnableBluetooth;
FBluetoothManager.OnDiscoverableEnd := DoDiscoverableEnd;
FBluetoothManager.OnDiscoveryEnd := DoDiscoveryEnd;
FBluetoothManager.OnRemoteRequestPair := DoRemoteRequestPair;
end;
destructor TBluetooth.destroy;
begin
inherited;
FBluetoothManager := nil;
end;
function TBluetooth.GetSocketTimeout: Integer;
begin
if FBluetoothManager <> nil then
Result := FBluetoothManager.SocketTimeout
else
Result := -1;
end;
procedure TBluetooth.SetSocketTimeout(Timeout: Integer);
begin
if FBluetoothManager <> nil then
FBluetoothManager.SocketTimeout := Timeout;
end;
procedure TBluetooth.StartDiscoverable(Timeout: Integer);
begin
if FBluetoothManager <> nil then
FBluetoothManager.StartDiscoverable(Timeout);
end;
function TBluetooth.GetStateConnected: Boolean;
begin
if (FBluetoothManager <> nil) and (FBluetoothManager.ConnectionState = TBluetoothConnectionState.Connected) then
Result := True
else
Result := False;
end;
function TBluetooth.GetLastDiscoveredDevices: TBluetoothDeviceList;
begin
if FBluetoothManager <> nil then
Result := FBluetoothManager.LastDiscoveredDevices
else
Result := nil;
end;
function TBluetooth.GetLastDiscoveredTimeStamp: TDateTime;
begin
if FBluetoothManager <> nil then
Result := FBluetoothManager.LastDiscoveredTimeStamp
else
Result := 0;
end;
function TBluetooth.GetLastPairedDevices: TBluetoothDeviceList;
begin
if FBluetoothManager <> nil then
Result := FBluetoothManager.LastPairedDevices
else
Result := nil;
end;
{TBluetooth-TBluetoothAdapter}
function TBluetooth.Pair(const ADevice: TBluetoothDevice): Boolean;
begin
Result := False;
if FBluetoothManager <> nil then
if ADevice <> nil then
Result := FBluetoothManager.CurrentAdapter.Pair(ADevice)
else
raise EBluetoothDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
function TBluetooth.UnPair(const ADevice: TBluetoothDevice): Boolean;
begin
Result := False;
if FBluetoothManager <> nil then
if ADevice <> nil then
Result := FBluetoothManager.CurrentAdapter.UnPair(ADevice)
else
raise EBluetoothDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
function TBluetooth.PairedDevices: TBluetoothDeviceList;
begin
if FBluetoothManager <> nil then
Result := FBluetoothManager.GetPairedDevices
else
Result := nil;
end;
function TBluetooth.PairedDevices(const AUUID: TBluetoothUUID): TBluetoothDeviceList;
var
LBSList: TBluetoothServiceList;
Device, Service: integer;
LExist: Boolean;
begin
Result := PairedDevices;
if Result <> nil then
for Device := Result.Count - 1 downto 0 do
begin
LExist := False;
LBSList := Result[Device].GetServices;
for Service := 0 to LBSList.Count - 1 do
if LBSList[Service].UUID = AUUID then
begin
LExist := True;
break;
end;
if not LExist then
Result.Delete(Device);
end;
end;
function TBluetooth.CreateServerSocket(const AName: string; const AUUID: TGUID;
Secure: Boolean): TBluetoothServerSocket;
begin
if FBluetoothManager <> nil then
Result := FBluetoothManager.CreateServerSocket(AName, AUUID, Secure)
else
Result := nil;
end;
function TBluetooth.GetScanMode: TBluetoothScanMode;
begin
if FBluetoothManager <> nil then
Result := FBluetoothManager.CurrentAdapter.ScanMode
else
Result := TBluetoothScanMode.None;
end;
procedure TBluetooth.SetEnabled(AEnable: Boolean);
begin
if not (csDesigning in ComponentState) then
begin
FEnabled := AEnable;
if FEnabled then
begin
if FBluetoothManager = nil then
Setup;
end
else
begin
if FBluetoothManager <> nil then
begin
CancelDiscovery;
FBluetoothManager.Free;
FBluetoothManager := nil;
end;
end
end else
FEnabled := AEnable;
end;
{TBluetooth-TBluetoothDevice}
function TBluetooth.CreateClientSocket(const ADevice: TBluetoothDevice; const AUUID: TGUID; Secure: Boolean): TBluetoothSocket;
begin
Result := nil;
if FEnabled then
if ADevice <> nil then
Result := ADevice.CreateClientSocket(AUUID, Secure)
else
raise EBluetoothDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
function TBluetooth.IsPaired(const ADevice: TBluetoothDevice): Boolean;
begin
Result := False;
if FEnabled then
if ADevice <> nil then
Result := ADevice.IsPaired
else
raise EBluetoothDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
function TBluetooth.State(const ADevice: TBluetoothDevice): TBluetoothDeviceState;
begin
Result := TBluetoothDeviceState.None;
if FEnabled then
if ADevice <> nil then
Result := ADevice.State
else
raise EBluetoothDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
function TBluetooth.GetServices(const ADevice: TBluetoothDevice): TBluetoothServiceList;
begin
Result := nil;
if FEnabled then
if ADevice <> nil then
Result := ADevice.GetServices
else
raise EBluetoothDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
function TBluetooth.LastServiceList(const ADevice: TBluetoothDevice): TBluetoothServiceList;
begin
Result := nil;
if FEnabled then
if ADevice <> nil then
Result := ADevice.LastServiceList
else
raise EBluetoothDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
{$ENDIF}
{ TBluetoothLEThreaded }
procedure TBluetoothLEThreaded.AbortReliableWrite(const ADevice: TBluetoothLEDevice);
begin
if FEnabled then
if (ADevice <> nil) then
ADevice.AbortReliableWrite
else
raise EBluetoothLEDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
function TBluetoothLEThreaded.AddCharacteristic(const AService: TBluetoothGattService;
const ACharacteristic: TBluetoothGattCharacteristic): Boolean;
begin
if GetGattServer <> nil then
Result := GetGattServer.AddCharacteristic(AService, ACharacteristic)
else
Result := False;
end;
//function TBluetoothLEThreaded.AddDescriptor(const ACharacteristic: TBluetoothGattCharacteristic;
// const ADescriptor: TBluetoothGattDescriptor): Boolean;
//begin
//
//end;
function TBluetoothLEThreaded.BeginReliableWrite(const ADevice: TBluetoothLEDevice): Boolean;
begin
Result := False;
if FEnabled then
if (ADevice <> nil) then
Result := ADevice.BeginReliableWrite
else
raise EBluetoothLEDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
procedure TBluetoothLEThreaded.CancelDiscovery;
begin
if FManager <> nil then
FManager.CancelDiscovery
end;
procedure TBluetoothLEThreaded.ClearServices;
begin
if GetGattServer <> nil then
GetGattServer.ClearServices;
end;
procedure TBluetoothLEThreaded.Setup;
begin
FManager := TBluetoothLEManager.CreateInstance;
FManager.ForceRefreshCachedDevices := FForceRefreshCachedDevices;
FManager.EnableBluetooth;
FManager.OnDiscoveryEnd := DoInternalDiscoveryEnd;
FManager.OnDiscoverLeDevice := DoInternalDiscoverLEDevice;
end;
procedure TBluetoothLEThreaded.SetupGattServer;
begin
if (FServer = nil) and SupportsGattServer then
begin
// May Gatt Server is not supported
FServer := FManager.GetGattServer;
FServer.OnConnectedDevice := DoConnectedDevice;
FServer.OnDisconnectDevice := DoDisconnectDevice;
FServer.OnCharacteristicRead := DoOnCharacteristicReadRequest;
FServer.OnCharacteristicWrite := DoOnCharacteristicWriteRequest;
FServer.OnClientSubscribed := DoOnCharacteristicSubscribed;
FServer.OnClientUnSubscribed := DoOnCharacteristicUnSubscribed;
//FServer.OnDescriptorRead := DoOnDescriptorReadRequest;
//FServer.OnDescriptorWrite := DoOnDescriptorWriteRequest;
FServer.OnServiceAdded := DoServiceAdded;
end;
end;
constructor TBluetoothLEThreaded.Create(AOwner: TComponent);
begin
FEnabled := False;
FForceRefreshCachedDevices := False;
inherited;
end;
function TBluetoothLEThreaded.CreateCharacteristic(const AService: TBluetoothGattService;
const AUuid: TBluetoothUUID; APropertyFlags: TBluetoothPropertyFlags;
const ADescription: string): TBluetoothGattCharacteristic;
begin
if GetGattServer <> nil then
Result := GetGattServer.CreateCharacteristic(AService, AUuid, APropertyFlags, ADescription)
else
Result := nil;
end;
//function TBluetoothLEThreaded.CreateDescriptor(const ACharacteristic: TBluetoothGattCharacteristic;
// const AUUID: TBluetoothUUID): TBluetoothGattDescriptor;
//begin
// Result := GetGattServer.CreateDescriptor(ACharacteristic, AUUID);
//end;
function TBluetoothLEThreaded.CreateIncludedService(const AService: TBluetoothGattService; const AnUUID: TBluetoothUUID;
AType: TBluetoothServiceType): TBluetoothGattService;
begin
if GetGattServer <> nil then
Result := GetGattServer.CreateIncludedService(AService, AnUUID, AType)
else
Result := nil;
end;
function TBluetoothLEThreaded.CreateService(const AnUUID: TBluetoothUUID; AType: TBluetoothServiceType): TBluetoothGattService;
begin
if GetGattServer <> nil then
Result := GetGattServer.CreateService(AnUUID, AType)
else
Result := nil;
end;
destructor TBluetoothLEThreaded.Destroy;
begin
FManager.Free;
inherited;
end;
function TBluetoothLEThreaded.DiscoverDevices(ATimeout: Integer): Boolean;
begin
if (FManager <> nil) and SupportsGattClient then
Result := FManager.StartDiscovery(ATimeout)
else
Result := False;
end;
function TBluetoothLEThreaded.DiscoverDevices(ATimeout: Integer; const AList: TBluetoothUUIDsList): Boolean;
begin
if (FManager <> nil) and SupportsGattClient then
Result := FManager.StartDiscovery(ATimeout, AList)
else
Result := False;
end;
function TBluetoothLEThreaded.DiscoverDevices(ATimeout: Cardinal; const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList): Boolean;
begin
if (FManager <> nil) and SupportsGattClient then
Result := FManager.StartDiscovery(ATimeout, ABluetoothLEScanFilterList)
else
Result := False;
end;
function TBluetoothLEThreaded.DiscoverDevices(ATimeout: Integer; AList: array of TBluetoothUUID): Boolean;
var
LList: TBluetoothUUIDsList;
Uuid: TBluetoothUUID;
begin
LList := TBluetoothUUIDsList.Create;
for Uuid in AList do
LList.Add(Uuid);
Result := DiscoverDevices(ATimeout, LList);
end;
function TBluetoothLEThreaded.DiscoverServices(const ADevice: TBluetoothLEDevice): Boolean;
begin
Result := False;
if FEnabled then
if (ADevice <> nil) then
Result := ADevice.DiscoverServices
else
raise EBluetoothLEDeviceException.Create(SBluetoothLENoDeviceAssigned);
end;
procedure TBluetoothLEThreaded.DoOnCharacteristicReadRequest(const Sender: TObject;
const ACharacteristic: TBluetoothGattCharacteristic; var AGattStatus: TBluetoothGattStatus);
begin
if FEnabled and Assigned(FOnCharacteristicReadRequest) then
FOnCharacteristicReadRequest(Sender, ACharacteristic, AGattStatus);
end;
procedure TBluetoothLEThreaded.DoOnCharacteristicRead(const Sender: TObject;
const ACharacteristic: TBluetoothGattCharacteristic; AGattStatus: TBluetoothGattStatus);
begin
if FEnabled and Assigned(FOnCharacteristicRead) then
if FEnabled and Assigned(FOnCharacteristicRead) then
FOnCharacteristicRead(Sender, ACharacteristic, AGattStatus);
end;
procedure TBluetoothLEThreaded.DoOnServicesDiscovered(const Sender: TObject; const AServiceList: TBluetoothGattServiceList);
begin
if FEnabled and Assigned(FOnServicesDiscovered) then
if FEnabled and Assigned(FOnServicesDiscovered) then
FOnServicesDiscovered(Sender, AServiceList);
if FEnabled and Assigned(FOnEndDiscoverServices) then
if FEnabled and Assigned(FOnEndDiscoverServices) then
FOnEndDiscoverServices(Sender, AServiceList);
end;
procedure TBluetoothLEThreaded.DoOnCharacteristicWriteRequest(const Sender: TObject;
const ACharacteristic: TBluetoothGattCharacteristic; var AGattStatus: TBluetoothGattStatus; const AValue: TByteDynArray);
begin
if FEnabled and Assigned(FOnCharacteristicWriteRequest) then
FOnCharacteristicWriteRequest(Sender, ACharacteristic, AGattStatus, AValue);
end;
procedure TBluetoothLEThreaded.DoOnCharacteristicSubscribed(const Sender: TObject; const AClientId: string;
const ACharacteristic: TBluetoothGattCharacteristic);
begin
if FEnabled and Assigned(FOnCharacteristicSubscribed) then
FOnCharacteristicSubscribed(Sender, AClientId, ACharacteristic);
end;
procedure TBluetoothLEThreaded.DoOnCharacteristicUnSubscribed(const Sender: TObject; const AClientId: string;
const ACharacteristic: TBluetoothGattCharacteristic);
begin
if FEnabled and Assigned(FOnCharacteristicUnSubscribed) then
FOnCharacteristicUnSubscribed(Sender, AClientId, ACharacteristic);
end;
procedure TBluetoothLEThreaded.DoOnCharacteristicWrite(const Sender: TObject;
const ACharacteristic: TBluetoothGattCharacteristic; AGattStatus: TBluetoothGattStatus);
begin
if FEnabled and Assigned(FOnCharacteristicWrite) then
if FEnabled and Assigned(FOnCharacteristicWrite) then
FOnCharacteristicWrite(Sender, ACharacteristic, AGattStatus);
end;
procedure TBluetoothLEThreaded.DoOnDescriptorReadRequest(const Sender: TObject; const ADescriptor: TBluetoothGattDescriptor;
var AGattStatus: TBluetoothGattStatus);
begin
// if FEnabled and Assigned(FOnDescriptorReadRequest) then
// TThread.Synchronize(nil, procedure begin
// if FEnabled and Assigned(FOnDescriptorReadRequest) then
// FOnDescriptorReadRequest(Sender, ADescriptor, AGattStatus);
// end);
end;
procedure TBluetoothLEThreaded.DoOnDescriptorRead(const Sender: TObject; const ADescriptor: TBluetoothGattDescriptor;
AGattStatus: TBluetoothGattStatus);
begin
if FEnabled and Assigned(FOnDescriptorRead) then
if FEnabled and Assigned(FOnDescriptorRead) then
FOnDescriptorRead(Sender, ADescriptor, AGattStatus);
end;
procedure TBluetoothLEThreaded.DoOnDescriptorWriteRequest(const Sender: TObject; const ADescriptor: TBluetoothGattDescriptor;
var AGattStatus: TBluetoothGattStatus; const AValue: TBytes);
begin
// if FEnabled and Assigned(FOnDescriptorWrite) then
// TThread.Synchronize(nil, procedure begin
// if FEnabled and Assigned(FOnDescriptorWrite) then
// FOnDescriptorWrite(Sender, ADescriptor, AGattStatus, AValue);
// end);
end;
procedure TBluetoothLEThreaded.DoOnDescriptorWrite(const Sender: TObject; const ADescriptor: TBluetoothGattDescriptor;
AGattStatus: TBluetoothGattStatus);
begin
if FEnabled and Assigned(FOnDescriptorWrite) then
if FEnabled and Assigned(FOnDescriptorWrite) then
FOnDescriptorWrite(Sender, ADescriptor, AGattStatus);
end;
procedure TBluetoothLEThreaded.DoOnDiscoverLEDevice(const Sender: TObject; const ADevice: TBluetoothLEDevice; Rssi: Integer; const ScanResponse: TScanResponse);
begin
if FEnabled and Assigned(FOnDiscoverLEDevice) then
if FEnabled and Assigned(FOnDiscoverLEDevice) then
FOnDiscoverLEDevice(Sender, ADevice, Rssi, ScanResponse);
end;
procedure TBluetoothLEThreaded.DoOnEndDiscoverDevices(const Sender: TObject; const ADeviceList: TBluetoothLEDeviceList);
begin
if FEnabled and Assigned(FOnEndDiscoverDevices) then
if FEnabled and Assigned(FOnEndDiscoverDevices) then
FOnEndDiscoverDevices(Sender, ADeviceList);
end;
procedure TBluetoothLEThreaded.DoOnReadRSSI(const Sender: TObject; ARssiValue: Integer; AGattStatus: TBluetoothGattStatus);
begin
if FEnabled and Assigned(FOnReadRSSI) then
if FEnabled and Assigned(FOnReadRSSI) then
FOnReadRSSI(Sender, ARssiValue, AGattStatus);
end;
procedure TBluetoothLEThreaded.DoOnReliableWriteCompleted(const Sender: TObject; AGattStatus: TBluetoothGattStatus);
begin
if FEnabled and Assigned(FOnReliableWriteCompleted) then
if FEnabled and Assigned(FOnReliableWriteCompleted) then
FOnReliableWriteCompleted(Sender, AGattStatus);
end;
procedure TBluetoothLEThreaded.DoConnect(Sender: TObject);
begin
if FEnabled and Assigned(FOnConnect) then
if FEnabled and Assigned(FOnConnect) then
FOnConnect(Sender);
end;