Jump to content
Viktor Akselrod
Message added by Viktor Akselrod,

Please be aware that these comments were copied here from another source and that the date and time shown for each comment may not be accurate.

  • Status: Fixed
  • Priority: Normal
  • Resolution: Fixed
  • Platform: Android
  • Affects version: 1.18.12.0

Delphi 12.3, компонент BluetoothLE1. Работаю с устройством по BLE.

1. Обнаруживаю доступные устройства, 2. Подключаюсь к сервисам устройства, 3. Получаю характеристики, 4. Подписываюсь на характеристику для чтения.

5. Пишу команду в характеристику для записи, ответ от устройства в событии "OnCharacteristicRead" не приходит.

 

Делал по стандартному FMX примеру "HeartRateMonitor". Работает.

Создал новый проект на FGX 1.18.11.0, разместил компонент BluetoothLE1. Устройство обнаруживается, сервисы, характеристики доступны,

подписка на характеристику для чтения проходит с результатом True. Но вот когда идёт передача от устройства, событие "OnCharacteristicRead" не срабатывает.

 

Подключены System.BluetoothSystem.Bluetooth.Components. Пробовал добавлять заголовочный файл Android.Api.Hardware.Bluetooth.

Что можно попробовать ещё, RTL, мосты?

FGX проект:

007.thumb.png.3ebabb6a45132281eaadb537bafebfe7.png

006.thumb.png.cbe1fbdf4a9a1e87c1cd52465339e2fd.png

unit Form.Main;

interface

{$SCOPEDENUMS ON}

uses
  System.Types, System.Classes, FGX.Forms, FGX.Forms.Types, FGX.Controls, FGX.Controls.Types, FGX.Layout, 
  FGX.Layout.Types, FGX.NavigationBar.Types, FGX.NavigationBar, FGX.DrawerLayout, FGX.StaticLabel,
  System.Bluetooth,
  System.Bluetooth.Components,
  System.Permissions,
  FGX.Button.Types, FGX.Button, FGX.Switch;

type
  TFormMain = class(TfgForm)
    fgDrawerLayout1: TfgDrawerLayout;
    fgNavigationBar: TfgNavigationBar;
    fgLabel2: TfgLabel;
    BluetoothLE1: TBluetoothLE;
    btDevices: TfgButton;
    loDevice: TfgLayout;
    loDeviceName: TfgLayout;
    lbDeviceName: TfgLabel;
    loDeviceSwitch: TfgLayout;
    fgSwitch: TfgSwitch;
    fgSend: TfgButton;
    procedure btDevicesTap(Sender: TObject);
    procedure BluetoothLE1EndDiscoverDevices(const Sender: TObject;
      const ADeviceList: TBluetoothLEDeviceList);
    procedure fgSendTap(Sender: TObject);
    procedure BluetoothLE1CharacteristicWrite(const Sender: TObject;
      const ACharacteristic: TBluetoothGattCharacteristic;
      AGattStatus: TBluetoothGattStatus);
    procedure BluetoothLE1CharacteristicRead(const Sender: TObject;
      const ACharacteristic: TBluetoothGattCharacteristic;
      AGattStatus: TBluetoothGattStatus);

  private const
    LOCATION_PERMISSION = 'android.permission.ACCESS_FINE_LOCATION';
    BLUETOOTH_SCAN_PERMISSION = 'android.permission.BLUETOOTH_SCAN';
    BLUETOOTH_CONNECT_PERMISSION = 'android.permission.BLUETOOTH_CONNECT';

  private
    { Private declarations }
    FBLEDevice: TBluetoothLEDevice;

    FGattService: TBluetoothGattService;
    FCharacteristic_UUID_RX: TBluetoothGattCharacteristic;
    FCharacteristic_UUID_TX: TBluetoothGattCharacteristic;

    procedure GetServiceAndCharacteristics;


  public
    { Public declarations }
  end;

const
  SERVICE_UUID : TGUID =           '{6E400001-B5A3-F393-E0A9-E50E24DCCA9E}';   { UUID для BLE }
  CHARACTERISTIC_UUID_TX : TGUID = '{6E400003-B5A3-F393-E0A9-E50E24DCCA9E}';
  CHARACTERISTIC_UUID_RX : TGUID = '{6E400002-B5A3-F393-E0A9-E50E24DCCA9E}';

var
  FormMain: TFormMain;

implementation

{$R *.xfm}

uses
  System.SysUtils, FGX.Application, FGX.Dialogs, FGX.Toasts, FGX.Log,
  Android.Api.Hardware.Bluetooth;

{******************************************************************************}

procedure TFormMain.btDevicesTap(Sender: TObject);
var
  Permissions: TArray<string>;
begin
  if TOSVersion.Check(12) then
    Permissions := [LOCATION_PERMISSION, BLUETOOTH_SCAN_PERMISSION, BLUETOOTH_CONNECT_PERMISSION]
  else
    Permissions := [LOCATION_PERMISSION];

  PermissionsService.RequestPermissions(Permissions,
    procedure(const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray) begin
      if ((Length(AGrantResults) = 3) and (AGrantResults[0] = TPermissionStatus.Granted)
                                      and (AGrantResults[1] = TPermissionStatus.Granted)
                                      and (AGrantResults[2] = TPermissionStatus.Granted)) or
         ((Length(AGrantResults) = 1) and (AGrantResults[0] = TPermissionStatus.Granted)) then
      BluetoothLE1.DiscoverDevices(2500)   { Запускаем поиск устройств }
      else
        TfgDialogs.ShowMessage('Cannot start BLE scan because not all required permissions have been granted!');
    end);
end;

{******************************************************************************}

procedure TFormMain.BluetoothLE1EndDiscoverDevices(const Sender: TObject;
  const ADeviceList: TBluetoothLEDeviceList);
var
  i: Integer;
begin
  for i := 0 to ADeviceList.Count - 1 do
    if Pos('CLMASTER', ADeviceList[i].DeviceName) > 0 then begin
      lbDeviceName.Text := ADeviceList[i].DeviceName;   { Отображаем Имя устройства }

      fgSwitch.Visible := True;

      FBLEDevice := BluetoothLE1.DiscoveredDevices[I];
      FBLEDevice.Connect;

      FBLEDevice.DiscoverServices;
      if BluetoothLE1.GetServices(FBLEDevice).Count = 0 then
        TfgToastFactory.Show('No services found!')
      else
        GetServiceAndCharacteristics;
    end;
end;

{******************************************************************************}

procedure TFormMain.GetServiceAndCharacteristics;
var
  i, j, k: Integer;
begin
  for i := 0 to FBLEDevice.Services.Count - 1 do begin
    fgNavigationBar.Title := FBLEDevice.Services[I].UUIDName + ' : ' + FBLEDevice.Services[I].UUID.ToString;
    for j := 0 to FBLEDevice.Services[I].Characteristics.Count - 1 do begin
      fgNavigationBar.Title := '--> ' + FBLEDevice.Services[I].Characteristics[J].UUIDName + ' : ' +
                      FBLEDevice.Services[I].Characteristics[J].UUID.ToString;
      for k := 0 to FBLEDevice.Services[I].Characteristics[J].Descriptors.Count - 1 do begin
        fgNavigationBar.Title := '----> ' + FBLEDevice.Services[I].Characteristics[J].Descriptors[K].UUIDName + ' : ' +
                      FBLEDevice.Services[I].Characteristics[J].Descriptors[K].UUID.ToString;
      end;
    end;
  end;

  FGattService := nil;
  FCharacteristic_UUID_RX := nil;
  FCharacteristic_UUID_TX := nil;

  FGattService := BluetoothLE1.GetService(FBLEDevice, SERVICE_UUID);
  if FGattService <> nil then begin
    FCharacteristic_UUID_TX := BluetoothLE1.GetCharacteristic(FGattService, CHARACTERISTIC_UUID_TX);
    FCharacteristic_UUID_RX := BluetoothLE1.GetCharacteristic(FGattService, CHARACTERISTIC_UUID_RX);

    fgSwitch.Enabled := True;
    fgSwitch.IsChecked := True;
  end
  else
    TfgToastFactory.Show('Service not found!');

  if FCharacteristic_UUID_TX <> nil then begin
    if BluetoothLE1.SubscribeToCharacteristic(FBLEDevice, FCharacteristic_UUID_TX) = True then
      fgNavigationBar.Title := 'Подписались UUID_TX'
  end;
end;

{******************************************************************************}

procedure TFormMain.fgSendTap(Sender: TObject);
var
  LBytes : TArray<byte>;
begin
                                { $   C    I    R  }
  LBytes := TArray<byte>.Create($24, $43, $49, $52, $0D, $0A);

  BluetoothLE1.GetCharacteristic(FGattService, Characteristic_UUID_RX).SetValueAsString(TEncoding.ANSI.GetString(LBytes));
  FBLEDevice.WriteCharacteristic(BluetoothLE1.GetCharacteristic(FGattService, Characteristic_UUID_RX));
end;

{******************************************************************************}

procedure TFormMain.BluetoothLE1CharacteristicWrite(const Sender: TObject;
  const ACharacteristic: TBluetoothGattCharacteristic;
  AGattStatus: TBluetoothGattStatus);
begin
  if FBLEDevice.RequestMtu(517) = True then fgNavigationBar.Title := 'RequestMtu = 517';
end;

{******************************************************************************}

procedure TFormMain.BluetoothLE1CharacteristicRead(const Sender: TObject;
  const ACharacteristic: TBluetoothGattCharacteristic;
  AGattStatus: TBluetoothGattStatus);
begin
  fgNavigationBar.Title := 'Read!!!';
  if AGattStatus = TBluetoothGattStatus.Success then
    fgNavigationBar.Title := 'Read Success!!!';
end;

{******************************************************************************}

end.

 

Работающий пример на FMX:

008.thumb.png.0a3445c6d8b2fec2d632991e47610e49.png

009.thumb.png.7a5bb72d465bc9bdd7395dc5af3a9e27.png

photo_2025-04-06_21-04-01.thumb.jpg.f8ad7be9a55f80b0a95e0d8bf3243b15.jpg

 


Fix version: 1.18.13.0

User Feedback

Recommended Comments

В заголовочном файле Android.Api.Hardware.Bluetooth.pas посмотрел поиском:
1. GetServices - функция Есть.
2. GetCharacteristic - функция Есть.
3. WriteCharacteristic - функция Есть.
4. RequestMtu - функция Есть. 
5. SubscribeToCharacteristic - Нет !!!

Этой функцией подписываемся на характеристику. Может она не проходит вовне?

  • Administrators

Модуль Android.Api.Hardware.Bluetooth никаким образом не связан с реализацией блютуса в RTL. System.BluetoothSystem.Bluetooth.Components используют для своей реализации заголовочные файлы из RTL Android API.

Создал чистый FMX проект. Перенес код из FGX проекта в FMX. Ничего лишнего.

targetSdkVersion = 35, Uses Premitions те же. В FMX работает,

приходит событие "OnCharacteristicRead".

010.thumb.png.d270579c026ea1181d63bb60131e8166.pngphoto_2025-04-08_10-02-09.thumb.jpg.b84082178226cc85fa6731241af2a47a.jpg

Рабочий проект на FMX:

CL2_FMX.rar

unit MainForm;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs,
  FMX.Controls.Presentation, FMX.StdCtrls,
  System.Bluetooth,
  System.Bluetooth.Components,
  System.Permissions;

type
  TForm1 = class(TForm)
    Label1: TLabel;
    btDevices: TButton;
    btSend: TButton;
    lbDeviceName: TLabel;
    BluetoothLE1: TBluetoothLE;
    procedure btDevicesClick(Sender: TObject);
    procedure BluetoothLE1EndDiscoverDevices(const Sender: TObject;
      const ADeviceList: TBluetoothLEDeviceList);
    procedure btSendClick(Sender: TObject);
    procedure BluetoothLE1CharacteristicWrite(const Sender: TObject;
      const ACharacteristic: TBluetoothGattCharacteristic;
      AGattStatus: TBluetoothGattStatus);
    procedure BluetoothLE1CharacteristicRead(const Sender: TObject;
      const ACharacteristic: TBluetoothGattCharacteristic;
      AGattStatus: TBluetoothGattStatus);

  private const
    LOCATION_PERMISSION = 'android.permission.ACCESS_FINE_LOCATION';
    BLUETOOTH_SCAN_PERMISSION = 'android.permission.BLUETOOTH_SCAN';
    BLUETOOTH_CONNECT_PERMISSION = 'android.permission.BLUETOOTH_CONNECT';

  private
    { Private declarations }
    FBLEDevice: TBluetoothLEDevice;

    FGattService: TBluetoothGattService;
    FCharacteristic_UUID_RX: TBluetoothGattCharacteristic;
    FCharacteristic_UUID_TX: TBluetoothGattCharacteristic;

    procedure GetServiceAndCharacteristics;

  public
    { Public declarations }
  end;


const
  SERVICE_UUID : TGUID =           '{6E400001-B5A3-F393-E0A9-E50E24DCCA9E}';   { UUID для BLE }
  CHARACTERISTIC_UUID_TX : TGUID = '{6E400003-B5A3-F393-E0A9-E50E24DCCA9E}';
  CHARACTERISTIC_UUID_RX : TGUID = '{6E400002-B5A3-F393-E0A9-E50E24DCCA9E}';

var
  Form1: TForm1;

implementation

{$R *.fmx}

{******************************************************************************}

procedure TForm1.btDevicesClick(Sender: TObject);
var
  Permissions: TArray<string>;
begin
  if TOSVersion.Check(12) then
    Permissions := [LOCATION_PERMISSION, BLUETOOTH_SCAN_PERMISSION, BLUETOOTH_CONNECT_PERMISSION]
  else
    Permissions := [LOCATION_PERMISSION];

  PermissionsService.RequestPermissions(Permissions,
    procedure(const APermissions: TClassicStringDynArray; const AGrantResults: TClassicPermissionStatusDynArray) begin
      if ((Length(AGrantResults) = 3) and (AGrantResults[0] = TPermissionStatus.Granted)
                                      and (AGrantResults[1] = TPermissionStatus.Granted)
                                      and (AGrantResults[2] = TPermissionStatus.Granted)) or
         ((Length(AGrantResults) = 1) and (AGrantResults[0] = TPermissionStatus.Granted)) then
      BluetoothLE1.DiscoverDevices(2500)   { Запускаем поиск устройств }
      else
        Label1.Text := 'Cannot start BLE scan because not all required permissions have been granted!';
    end);
end;

{******************************************************************************}

procedure TForm1.BluetoothLE1EndDiscoverDevices(const Sender: TObject;
  const ADeviceList: TBluetoothLEDeviceList);
var
  i: Integer;
begin
  for i := 0 to ADeviceList.Count - 1 do
    if Pos('CLMASTER', ADeviceList[i].DeviceName) > 0 then begin
      lbDeviceName.Text := ADeviceList[i].DeviceName;   { Отображаем Имя устройства }

      FBLEDevice := BluetoothLE1.DiscoveredDevices[I];
      FBLEDevice.Connect;

      FBLEDevice.DiscoverServices;
      if BluetoothLE1.GetServices(FBLEDevice).Count = 0 then
        Label1.Text := 'No services found!'
      else
        GetServiceAndCharacteristics;
    end;
end;

{******************************************************************************}

procedure TForm1.GetServiceAndCharacteristics;
var
  i, j, k: Integer;
begin
  for i := 0 to FBLEDevice.Services.Count - 1 do begin
    Label1.Text := FBLEDevice.Services[I].UUIDName + ' : ' + FBLEDevice.Services[I].UUID.ToString;
    for j := 0 to FBLEDevice.Services[I].Characteristics.Count - 1 do begin
      Label1.Text := '--> ' + FBLEDevice.Services[I].Characteristics[J].UUIDName + ' : ' +
                      FBLEDevice.Services[I].Characteristics[J].UUID.ToString;
      for k := 0 to FBLEDevice.Services[I].Characteristics[J].Descriptors.Count - 1 do begin
        Label1.Text := '----> ' + FBLEDevice.Services[I].Characteristics[J].Descriptors[K].UUIDName + ' : ' +
                      FBLEDevice.Services[I].Characteristics[J].Descriptors[K].UUID.ToString;
      end;
    end;
  end;

  FGattService := nil;
  FCharacteristic_UUID_RX := nil;
  FCharacteristic_UUID_TX := nil;

  FGattService := BluetoothLE1.GetService(FBLEDevice, SERVICE_UUID);
  if FGattService <> nil then begin
    FCharacteristic_UUID_TX := BluetoothLE1.GetCharacteristic(FGattService, CHARACTERISTIC_UUID_TX);
    FCharacteristic_UUID_RX := BluetoothLE1.GetCharacteristic(FGattService, CHARACTERISTIC_UUID_RX);
  end
  else
    Label1.Text := 'Service not found!';

  if FCharacteristic_UUID_TX <> nil then begin
    if BluetoothLE1.SubscribeToCharacteristic(FBLEDevice, FCharacteristic_UUID_TX) = True then
      Label1.Text := 'Подписались UUID_TX';
  end;
end;

{******************************************************************************}

procedure TForm1.btSendClick(Sender: TObject);
var
  LBytes : TArray<byte>;
begin
                                { $   C    I    R  }
  LBytes := TArray<byte>.Create($24, $43, $49, $52, $0D, $0A);

  BluetoothLE1.GetCharacteristic(FGattService, Characteristic_UUID_RX).SetValueAsString(TEncoding.ANSI.GetString(LBytes));
  FBLEDevice.WriteCharacteristic(BluetoothLE1.GetCharacteristic(FGattService, Characteristic_UUID_RX));
end;

{******************************************************************************}

procedure TForm1.BluetoothLE1CharacteristicWrite(const Sender: TObject;
  const ACharacteristic: TBluetoothGattCharacteristic;
  AGattStatus: TBluetoothGattStatus);
begin
  if FBLEDevice.RequestMtu(517) = True then Label1.Text := 'RequestMtu = 517';
end;

{******************************************************************************}

procedure TForm1.BluetoothLE1CharacteristicRead(const Sender: TObject;
  const ACharacteristic: TBluetoothGattCharacteristic;
  AGattStatus: TBluetoothGattStatus);
begin
  Label1.Text := 'Read!!!';
  if AGattStatus = TBluetoothGattStatus.Success then
    Label1.Text := 'Read Success!!!';
end;

{******************************************************************************}

end.

 

Еще раз создал чистый проект на FGX, без тем, ключей. Перенес код из FMX.

Не работает, не возвращается событие "OnCharacteristicRead".

CL2_Test.rar

  • Administrators

Добрый день,

2 hours ago, Александр Клопоцкий said:

Еще раз создал чистый проект на FGX, без тем, ключей. Перенес код из FMX.

Не работает, не возвращается событие "OnCharacteristicRead".

Это очень хорошее и полезное наблюдение! Попробуйте обновить java часть FGX Native и проверить еще раз (Файлы только для 12.3).

{app} - место установки FGX Native.

Create an account or sign in to comment

Recently Browsing 0

  • No registered users viewing this page.