Compartilhamento de tecnologia

Um problema ao usar Delphi para desenvolvimento Bluetooth BLE

2024-07-12

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

conceito

Para desenvolvimento BLE em Delphi, arraste um TBlueToothLe para a interface e use este controle para desenvolver BLE, como conectar uma pulseira Bluetooth.

Existe um programa BLEScanner na Demo que acompanha o Delphi, que pode ser usado como ponto de partida para o desenvolvimento.

pergunta

Se o programa acima for executado no Windows, após a verificação do dispositivo, se o mouse clicar em um dispositivo, a interface poderá congelar e o programa não responderá. Olhando para a área de gerenciamento de tarefas, é verdade que o programa não responde e travou.

Análise de causa

Clique com o mouse para verificar os serviços do dispositivo selecionado. Então, quando os serviços do dispositivo são descobertos, o evento OnServicesDiscovered do TBluetoothLE é acionado. Nesse caso, vários serviços do dispositivo são lidos em loop e, para um determinado serviço, seu nome de caractere é lido em loop. A falha é onde o loop lê Character.

Por que caiu, eu não sei. Mas encontrei uma solução, o código é o seguinte:

  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;

Explicação do código

No código acima, TTask.Run foi adicionado por mim. TThread.Synchronize também foi adicionado por mim. Remova TTask.Run e TThread.Synchronize e o código restante é o código original do Demo que vem com o Delphi.

Primeiro, coloque o código original em TTask.Run, o que significa colocar esses códigos em um thread para execução. Em vez de deixar o thread que originalmente gerou o evento OnServicesDiscovered ser executado. Razão possível: o thread que acionou OnServicesDiscovered não pode executar muitas tarefas demoradas.

O código é executado no thread. Quando você precisa gravar dados no controle de interface, como o código Listbox2.Items.Add, você precisa realizar a sincronização do thread. Então adicione TThread.Synchronize.

meu ambiente de desenvolvimento

Em ambientes diferentes, os fenômenos podem ser diferentes. Portanto, aqui está meu ambiente de desenvolvimento:

Delphi 11 Edição Comunitária;

Windows 11 Home Edition;

O programa alvo a ser compilado e executado é a versão Win32.

Não há teste se esta demonstração terá os problemas acima no Android. Mas acredito que no Android será melhor adicionar TTask.Run.

Localização do programa de demonstração

O Demo mencionado aqui, após a instalação do Delphi, se estiver instalado por padrão, o programa Demo é:

C:UsuáriosPúblicoDocumentosEmbarcaderoStudio22.0AmostrasObject PascalAmostras de vários dispositivosSensores e serviços de dispositivosBluetoothBLEScanner

para concluir

Não há problema em usar Delphi para desenvolver programas BLE, como fazer um APP de pulseira. Porém, deve-se observar que em muitos eventos do controle TBluetoothLE, é melhor não executar muito código. Se houver uma lógica de negócios complexa, é melhor executá-la em um thread separado. No método de evento, basta iniciar o thread correspondente.

Para Delphi, o recém-adicionado TTask.Run nos permite colocar muito código na execução do thread. O método de escrita de código é muito mais simples do que antes, quando tínhamos que criar uma classe de thread.