Technology Sharing

A problem with using Delphi for Bluetooth BLE development

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

concept

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.

question

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.

Cause Analysis

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:

  1. procedure TForm6.BluetoothLE1ServicesDiscovered(const Sender: TObject; const AServiceList: TBluetoothGattServiceList);
  2. var
  3. ServiceIndex: Integer;
  4. Service: TBluetoothGattService;
  5. CharacteristicIndex: Integer;
  6. Characteristic: TBluetoothGattCharacteristic;
  7. begin
  8. //以下代码如果不包到 TTask.Run 里面(原本的代码没有),在 WINDOWS 底下,执行到 for
  9. //CharacteristicIndex := 0 to Service.Characteristics.Count 会界面冻结,而且单步跟踪也停止
  10. //了,没有往下执行。
  11. TTask.Run(
  12. procedure
  13. var
  14. ServiceIndex: Integer;
  15. CharacteristicIndex: Integer;
  16. begin
  17. if AServiceList.Count > 0 then
  18. begin
  19. for ServiceIndex := 0 to AServiceList.Count - 1 do
  20. begin
  21. Service := AServiceList[ServiceIndex];
  22. TThread.Synchronize(nil,
  23. procedure
  24. begin
  25. Listbox2.Items.Add((ServiceIndex + 1).ToString + ' - ' + Service.UUIDName + ' - ' + Service.UUID.ToString);
  26. end
  27. );
  28. //以下代码会导致死机,如果断点跟踪,直接就是停在 for 这一行,不会继续往下执行。
  29. for CharacteristicIndex := 0 to Service.Characteristics.Count - 1 do
  30. begin
  31. Characteristic := Service.Characteristics[CharacteristicIndex];
  32. TThread.Synchronize(nil,
  33. procedure
  34. begin
  35. Listbox2.Items.Add(' - ' + Characteristic.UUIDName + ' - ' + Characteristic.UUID.ToString);
  36. end
  37. );
  38. end;
  39. end;
  40. end
  41. else
  42. TThread.Synchronize(nil,
  43. procedure
  44. begin
  45. Listbox2.Items.Add('- Access not allowed or no service available');
  46. end
  47. );
  48. end
  49. );
  50. //Listbox1.Enabled := True;
  51. end;

Code Explanation

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.

Location of the Demo program

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

in conclusion

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.