2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
For BLE development in Delphi, drag a TBlueToothLe to the interface. Using this control, you can develop BLE, such as connecting a Bluetooth bracelet.
In the Demo that comes with Delphi, there is a BLEScanner program that can be used as a starting point for development.
If the above program is executed under Windows, after scanning the device, if you click on a device with the mouse, the interface may freeze and the program may not respond. Looking at the task management area, the program is indeed unresponsive and has crashed.
Clicking the mouse will scan the services of the selected device. Then, when the services of the device are found, the OnServicesDiscovered event of TBluetoothLE is triggered. In this event, multiple services of the device are read in a loop, and then for a certain service, its Character name is read in a loop. The system freezes when the Character is read in a loop.
I don't know why it crashes, but I found a solution, the code is as follows:
- procedure TForm6.BluetoothLE1ServicesDiscovered(const Sender: TObject; const AServiceList: TBluetoothGattServiceList);
- var
- ServiceIndex: Integer;
- Service: TBluetoothGattService;
- CharacteristicIndex: Integer;
- Characteristic: TBluetoothGattCharacteristic;
- begin
- //以下代码如果不包到 TTask.Run 里面(原本的代码没有),在 WINDOWS 底下,执行到 for
- //CharacteristicIndex := 0 to Service.Characteristics.Count 会界面冻结,而且单步跟踪也停止
- //了,没有往下执行。
- TTask.Run(
- procedure
- var
- ServiceIndex: Integer;
- CharacteristicIndex: Integer;
- begin
- if AServiceList.Count > 0 then
- begin
- for ServiceIndex := 0 to AServiceList.Count - 1 do
- begin
- Service := AServiceList[ServiceIndex];
-
- TThread.Synchronize(nil,
- procedure
- begin
- Listbox2.Items.Add((ServiceIndex + 1).ToString + ' - ' + Service.UUIDName + ' - ' + Service.UUID.ToString);
- end
- );
-
-
- //以下代码会导致死机,如果断点跟踪,直接就是停在 for 这一行,不会继续往下执行。
- for CharacteristicIndex := 0 to Service.Characteristics.Count - 1 do
- begin
- Characteristic := Service.Characteristics[CharacteristicIndex];
-
- TThread.Synchronize(nil,
- procedure
- begin
- Listbox2.Items.Add(' - ' + Characteristic.UUIDName + ' - ' + Characteristic.UUID.ToString);
- end
- );
-
- end;
-
- end;
- end
- else
- TThread.Synchronize(nil,
- procedure
- begin
- Listbox2.Items.Add('- Access not allowed or no service available');
- end
- );
-
- end
- );
-
- //Listbox1.Enabled := True;
- end;
In the above code, TTask.Run is added by me. TThread.Synchronize is also added by me. Remove TTask.Run and TThread.Synchronize and the remaining code is the original code of the Demo that comes with Delphi.
First, put the original code into TTask.Run, that is, put the code into a thread to execute, instead of letting the thread that originally triggered the OnServicesDiscovered event to execute. Possible reason: The thread that triggered OnServicesDiscovered cannot execute too many time-consuming tasks.
The code is executed in the thread. When data needs to be written to the interface controls, such as Listbox2.Items.Add, a thread synchronization is required. Therefore, TThread.Synchronize is added.
My development environment
The phenomenon may be different in different environments. Therefore, I would like to mention my development environment here:
Delphi 11 Community Edition;
Windows 11 Home;
The target program to be compiled and run is the Win32 version.
I haven't tested whether this demo will have the above problems on Android, but I believe that adding TTask.Run will also work better on Android.
The demo mentioned here, after installing Delphi, if it is installed by default, this demo program is in:
C:UsersPublicDocumentsEmbarcaderoStudio22.0SamplesObject PascalMulti-Device SamplesDevice Sensors and ServicesBluetoothBLEScanner
There is no problem in using Delphi to develop BLE programs, such as making a bracelet APP. However, it should be noted that it is best not to execute too much code in many events of the TBluetoothLE control. If there is complex business logic, it is best to put it in a separate thread to execute, and in the event method, just start the corresponding thread.
For Delphi, the newly added TTask.Run allows us to throw a lot of code into the thread for execution. The code writing method is much simpler than before when we had to create a thread class.