기술나눔

Bluetooth BLE 개발에 Delphi를 사용하는 문제

2024-07-12

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

개념

Delphi에서 BLE 개발을 위해 TBlueToothLe를 인터페이스로 드래그하고 이 컨트롤을 사용하여 블루투스 팔찌 연결과 같은 BLE를 개발합니다.

Delphi와 함께 제공되는 데모에는 개발의 출발점으로 사용할 수 있는 BLEScanner 프로그램이 있습니다.

질문

Windows에서 위 프로그램을 실행한 경우 장치를 스캔한 후 장치를 마우스로 클릭하면 인터페이스가 정지되고 프로그램이 응답하지 않을 수 있습니다. 작업 관리 영역을 살펴보면 프로그램이 응답하지 않고 충돌이 난 것이 사실입니다.

원인 분석

마우스를 클릭하면 선택한 장치의 서비스를 검색할 수 있습니다. 그런 다음 장치의 서비스가 검색되면 TBluetoothLE의 OnServicesDiscovered 이벤트가 트리거됩니다. 이 이벤트는 장치의 여러 서비스를 루프에서 읽은 후 특정 서비스에 대해 해당 캐릭터 이름을 루프에서 읽습니다. 충돌은 루프가 문자를 읽는 곳입니다.

왜 추락했는지 모르겠습니다. 그러나 해결책을 찾았습니다. 코드는 다음과 같습니다.

  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;

코드 설명

위 코드에서는 제가 TTask.Run을 추가했습니다. TThread.Synchronize도 제가 추가했습니다. TTask.Run 및 TThread.Synchronize를 제거하면 나머지 코드는 Delphi와 함께 제공되는 데모의 원본 코드입니다.

먼저 원본 코드를 TTask.Run에 넣습니다. 이는 실행을 위해 이러한 코드를 스레드에 넣는 것을 의미합니다. 원래 OnServicesDiscovered 이벤트를 발생시킨 스레드가 실행되도록 하는 대신. 가능한 이유: OnServicesDiscovered를 트리거한 스레드는 시간이 많이 걸리는 작업을 너무 많이 수행할 수 없습니다.

코드는 스레드에서 실행됩니다. Listbox2.Items.Add 코드와 같이 인터페이스 컨트롤에 데이터를 써야 하는 경우 스레드 동기화를 수행해야 합니다. 따라서 TThread.Synchronize를 추가하세요.

내 개발 환경

다른 환경에서는 현상이 다를 수 있습니다. 따라서 내 개발 환경은 다음과 같습니다.

델파이 11 커뮤니티 에디션;

윈도우 11 홈 에디션;

컴파일하고 실행할 대상 프로그램은 Win32 버전입니다.

이 데모가 Android에서 위의 문제를 가질지 여부는 테스트되지 않습니다. 하지만 Android에서는 TTask.Run을 추가하는 것이 더 나을 것이라고 생각합니다.

데모 프로그램 위치

여기에 언급된 데모는 델파이를 설치한 후 기본으로 설치된다면 데모 프로그램은 다음과 같습니다.

C:UsersPublicDocumentsEmbarcaderoStudio22.0SamplesObject PascalMulti-Device SamplesDevice Sensors and ServicesBluetoothBLEScanner

결론적으로

팔찌 APP 제작 등 BLE 프로그램 개발에 델파이를 활용하는데는 문제가 없습니다. 그러나 TBluetoothLE 컨트롤의 많은 이벤트에서는 너무 많은 코드를 실행하지 않는 것이 가장 좋습니다. 복잡한 비즈니스 로직이 있는 경우에는 별도의 스레드에서 실행하는 것이 가장 좋습니다. 이벤트 메서드에서는 해당 스레드를 시작하면 됩니다.

Delphi의 경우 새로 추가된 TTask.Run을 사용하면 스레드 실행에 많은 코드를 넣을 수 있습니다. 코드 작성 방법은 스레드 클래스를 생성해야 했던 이전보다 훨씬 간단합니다.