Delphi蓝牙LE心率档案访问

Delphi蓝牙LE心率档案访问,delphi,bluetooth-lowenergy,Delphi,Bluetooth Lowenergy,我正在跟踪Delphi测试项目,从实现 心率服务。所以一个完美的适合测试项目的人 不幸的是,在发现服务时 蓝牙1.DiscoverServices(adev) 引发一个异常,该设备需要配对。 此外,如果我不发出该命令,蓝牙LE设备的服务阵列将为空 (仅填写广告列表) 所以。。。我不能配对这个设备,而且据我所知,我不需要在BT LE中进行配对- 那么,为什么会出现这种例外情况?我如何才能获得其他情况下的服务 此外,永远不会调用OnEndDiscoverDevices-只有在取消发现过程时才会调用该

我正在跟踪Delphi测试项目,从实现 心率服务。所以一个完美的适合测试项目的人

不幸的是,在发现服务时 蓝牙1.DiscoverServices(adev) 引发一个异常,该设备需要配对。 此外,如果我不发出该命令,蓝牙LE设备的服务阵列将为空 (仅填写广告列表)

所以。。。我不能配对这个设备,而且据我所知,我不需要在BT LE中进行配对- 那么,为什么会出现这种例外情况?我如何才能获得其他情况下的服务

此外,永远不会调用OnEndDiscoverDevices-只有在取消发现过程时才会调用该事件

以下是完整的代码:

unit ufrmBTLETest;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.Bluetooth, Vcl.StdCtrls,
  System.Bluetooth.Components, Vcl.ComCtrls, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    BTLE: TBluetoothLE;
    memLog: TMemo;
    tvDevices: TTreeView;
    timCancel: TTimer;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure BTLEDiscoverLEDevice(const Sender: TObject;
      const ADevice: TBluetoothLEDevice; Rssi: Integer;
      const ScanResponse: TScanResponse);
    procedure BTLEServicesDiscovered(const Sender: TObject;
      const AServiceList: TBluetoothGattServiceList);
    procedure BTLEServiceAdded(const Sender: TObject;
      const AService: TBluetoothGattService;
      const AGattStatus: TBluetoothGattStatus);
    procedure BTLEEndDiscoverDevices(const Sender: TObject;
      const ADeviceList: TBluetoothLEDeviceList);
    procedure BTLEEndDiscoverServices(const Sender: TObject;
      const AServiceList: TBluetoothGattServiceList);
    procedure timCancelTimer(Sender: TObject);
    procedure tvDevicesClick(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

uses
  System.StrUtils, System.Generics.Collections;

{$R *.dfm}

const HRSERVICE: TBluetoothUUID = '{0000180D-0000-1000-8000-00805F9B34FB}';
      HRMEASUREMENT_CHARACTERISTIC: TBluetoothUUID  = '{00002A37-0000-1000-8000-00805F9B34FB}';


function bytesToStr( aval : TBytes ) : string;
var i : integer;
begin
     for i := 0 to Length(aval) do
         Result := Result + IntToHex(aval[i], 2);
end;

procedure TForm1.BTLEDiscoverLEDevice(const Sender: TObject;
  const ADevice: TBluetoothLEDevice; Rssi: Integer;
  const ScanResponse: TScanResponse);
var
  i: Integer;
  arr : TArray<TPair<TScanResponseKey, TBytes>>;

begin
     memLog.Lines.Add('Discovered: ' + ADevice.Identifier);
     memLog.Lines.Add('Name: ' + ADevice.DeviceName);

     arr := scanResponse.ToArray;
     for i := 0 to Length(arr) - 1 do
     begin
          memLog.Lines.Add(Format('Resp %d, %d, %s',[i, Integer(arr[i].Key), BytesToSTr( arr[i].Value )]));
     end;
end;

procedure TForm1.BTLEEndDiscoverDevices(const Sender: TObject;
  const ADeviceList: TBluetoothLEDeviceList);
var i, j: Integer;
    ti : TTreeNode;
    aDev : TBluetoothLEDevice;
    ser : TBluetoothGattService;
begin
     for i := 0 to ADeviceList.Count - 1 do
     begin
          aDev := ADeviceList[i];
          if true then //aDev.DeviceName = 'medilogHR' then
          begin
               ti := tvDevices.Items.AddChild(nil, ifthen( aDev.DeviceName = '', aDev.Identifier, aDev.DeviceName));
          end;
     end;
end;

procedure TForm1.BTLEEndDiscoverServices(const Sender: TObject;
  const AServiceList: TBluetoothGattServiceList);
begin
     memLog.Lines.Add('Services ended:' + AServiceList.Count.ToString);
end;

procedure TForm1.BTLEServiceAdded(const Sender: TObject;
  const AService: TBluetoothGattService;
  const AGattStatus: TBluetoothGattStatus);
begin
     memlog.Lines.Add('Service added: ' + AService.UUIDName);
     memLog.Lines.Add('Gatt: ' + IntToStr(Integer(agattStatus)));
end;

procedure TForm1.BTLEServicesDiscovered(const Sender: TObject;
  const AServiceList: TBluetoothGattServiceList);
begin
     memLog.Lines.Add('Service Discovered');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
     tvDevices.Items.Clear;
     timCancel.Interval := 18000;
     if BTLE.DiscoverDevices(timCancel.Interval, [HRSERVICE]) then 
        timCancel.Enabled := True;
end;

procedure TForm1.Button2Click(Sender: TObject);
const
  HeartRateService: TGUID = '{0000180D-0000-1000-8000-00805F9B34FB}';
var
  ABLEAdvertisedDataFilter: TBluetoothLEScanFilter;
  ABLEAdvertisedDataFilterList: TBluetoothLEScanFilterList;
begin
  ABLEAdvertisedDataFilter:= TBluetoothLEScanFilter.Create;
  ABLEAdvertisedDataFilterList:= TBluetoothLEScanFilterList.Create;
  ABLEAdvertisedDataFilter.ServiceUUID:= HeartRateService; 
  ABLEAdvertisedDataFilterList.Add(ABLEAdvertisedDataFilter);

  timCancel.Interval := 18000;
  btle.CurrentManager.StartDiscovery(18000,ABLEAdvertisedDataFilterList);
  timCancel.Enabled := True;
end;

procedure TForm1.timCancelTimer(Sender: TObject);
begin
     timCancel.Enabled := False;
     btle.CancelDiscovery;

end;

procedure TForm1.tvDevicesClick(Sender: TObject);
var aDev : TBluetoothLEDevice;
    j : integer;
    scanResp : TScanResponse;
    arr : TArray<TPair<TScanResponseKey, TBytes>>;
begin
     if tvDevices.Items.Count > 0 then
     begin
          for aDev in btle.CurrentManager.AllDiscoveredDevices do
          begin
               if aDev.Paired then
               begin
                    timcancel.enabled := True;
                    aDev.DiscoverServices;
               end
               else
               begin
                    arr := aDev.AdvertisedData.ToArray;
                    for j := 0 to Length(arr) - 1 do
                    begin
                          memlog.Lines.Add(IntToStr( integer(arr[j].Key) )+ ': ' + bytesToStr(arr[j].Value));
                    end;                                                   
               end;
          end;
     end;
end;

end.
我正在使用Delphi10.3更新3
我的基本误解是什么?

在搜索德国德尔福网站后,我发现了许多类似的问题。简而言之,Delphi 10.3不支持这一点(不再需要配对),并且已经提交了QC。希望10.4有所改变

更新: 我编辑了System.Win.BluetoothWinRT,这样“无配对”状态也可以按照microsoft bluetooth le示例的c#实现查询服务

1) 将TWinRTBluetoothLEDevice.CheckInitialized更改为

  // the exception was the old code...
  if FId = 0 then
    begin
      //raise EBluetoothDeviceException.Create(SBluetoothLEDeviceNotPaired);

      if TAsyncOperation<IAsyncOperation_1__IBluetoothLEDevice>.Wait(
        TBluetoothLEDevice.Statics.FromBluetoothAddressAsync(FAddress), LBLEDeviceAsyncOp) = AsyncStatus.Completed then
      begin
        FBluetoothLEDevice := LBLEDeviceAsyncOp.GetResults;
        FClosed := False;
        if DeviceName = '' then
          FDeviceName := FBluetoothLEDevice.Name.ToString;
        FConnectionStatusChangeDelegate := TConnectionStatusChangeEventHandler.Create(Self);
        FBluetoothLEDevice.add_ConnectionStatusChanged(FConnectionStatusChangeDelegate);
exit;
      end;
//例外是旧代码。。。
如果FId=0,则
开始
//引发EBluetoothDeviceException.Create(SBluetoothLEDeviceNotPaired);
如果是TAsyncOperation,等等(
TBluetoothLEDevice.Statics.FromBluetoothAddressAsync(FadAddress),LBLEDeviceAsyncOp)=异步状态。然后完成
开始
FBluetoothLEDevice:=LBLEDeviceAsyncOp.GetResults;
FClosed:=假;
如果DeviceName='',则
FDeviceName:=FBluetoothLEDevice.Name.ToString;
FConnectionStatusChangeDelegate:=TConnectionStatusChangeEventHandler.Create(Self);
FBluetoothLEDevice.add_ConnectionStatusChanged(FConnectionStatusChangeDelegate);
出口
终止
以及DoDiscoverService的一部分

var
  I: Integer;
  LGattService: GenericAttributeProfile_IGattDeviceService;
  dev3 : IBluetoothLEDevice3;
  res3 : IAsyncOperation_1__GenericAttributeProfile_IGattDeviceServicesResult;
  serviceRes : GenericAttributeProfile_IGattDeviceServicesResult;
  LGattServices: IVectorView_1__GenericAttributeProfile_IGattDeviceService;
begin
  Result := True;
  FServices.Clear;
  CheckInitialized;
  if FID = 0 then
  begin
      dev3 := fBluetoothLEDevice as IBluetoothLEDevice3;

      if dev3 = nil then
         raise EBluetoothDeviceException.Create(SBluetoothLEDeviceNotPaired);

      if TAsyncOperation<IAsyncOperation_1__GenericAttributeProfile_IGattDeviceServicesResult>.Wait(

         dev3.GetGattServicesAsync(BluetoothCacheMode.Uncached), res3 ) = AsyncStatus.Completed then 
      begin
           serviceRes := res3.GetResults;

           LGattServices := serviceRes.Services;

           for I := 0 to LGattServices.Size - 1 do
           begin
                LGattService := LGattServices.GetAt(I);
                FServices.Add(TWinRTBluetoothGattService.Create(Self, LGattService, TBluetoothServiceType.Primary));
           end;
      end; 
  end
var
I:整数;
LGattService:GenerictTributeProfile\u iGatdDeviceService;
dev3:IBluetoothLEDevice3;
res3:iSyncoperation\u 1\u GenerictProfile\u iGattDevices服务结果;
serviceRes:GenerictTributeProfile\u iGatdDevicesServicesResult;
LGattServices:IVectorView\u 1\u通用属性文件\u iGatdDeviceService;
开始
结果:=真;
FServices.Clear;
检查初始化;
如果FID=0,则
开始
dev3:=fBluetoothLEDevice作为IBluetoothLEDevice3;
如果dev3=nil,则
引发EBluetoothDeviceException.Create(SBluetoothLEDeviceNotPaired);
如果是TAsyncOperation,等等(
dev3.GetGattServicesAsync(BluetoothCacheMode.Uncached),res3)=异步状态。然后完成
开始
serviceRes:=res3.GetResults;
LGattServices:=服务资源服务;
对于I:=0到LGattServices。大小-1 do
开始
LGattService:=LGattServices.GetAt(I);
添加(TWinRTBluetoothGattService.Create(Self、LGattService、TBluetoothServiceType.Primary));
终止
终止
终止
TWinRTBluetoothGattService.DoGetCharacteristics和 TWinRTBluetoothGattCharacteristic.DoGetDescriptors函数

DoGetCharacteristics功能的扩展:

var
  I: Integer;
  LGattCharacteristics: IVectorView_1__GenericAttributeProfile_IGattCharacteristic;
  charactRes : GenericAttributeProfile_IGattCharacteristicsResult;
  service3 : GenericAttributeProfile_IGattDeviceService3;
  characteristics3 : IAsyncOperation_1__GenericAttributeProfile_IGattCharacteristicsResult;
begin
  CheckNotClosed;
  FCharacteristics.Clear;

  if FDevice.FId = 0 then
  begin
       service3 := FGattService as GenericAttributeProfile_IGattDeviceService3;

       if TAsyncOperation<IAsyncOperation_1__GenericAttributeProfile_IGattCharacteristicsResult>.Wait(
                        service3.GetCharacteristicsAsync(BluetoothCacheMode.Uncached), characteristics3 ) = AsyncStatus.Completed then 
       begin
            charactRes := characteristics3.GetResults;    
            LGattCharacteristics := charactRes.Characteristics;
            if LGattCharacteristics.Size > 0 then
               for I := 0 to LGattCharacteristics.Size - 1 do
                   FCharacteristics.Add(TWinRTBluetoothGattCharacteristic.Create(Self, LGattCharacteristics.GetAt(I)));
       end;
  end

//old code

var
I:整数;
LGattCharacteristics:IVectorView\u 1\u通用属性文件\u iGatCharacteristic;
特征:通用属性文件\u iGatCharacteristicsResult;
服务3:GenerictTributeProfile_iGatdDeviceService 3;
特征3:iSyncoperation\u 1\u通用属性文件\u iGatCharacteristics结果;
开始
检查未关闭;
FCharacteristics.清晰;
如果FDevice.FId=0,则
开始
服务3:=FGattService作为GenerictTributeProfile\u iGatdDeviceService 3;
如果是TAsyncOperation,等等(
service3.GetCharacteristicsAsync(BluetoothCacheMode.Uncached),characteristics3)=异步状态。然后完成
开始
Characters:=characteristics3.GetResults;
LGattCharacteristics:=字符.特征;
如果LGattCharacteristics.Size>0,则
对于I:=0到LGattCharacteristics.Size-1 do
FCharacteristics.Add(TWinRTBluetoothGattCharacteristic.Create(Self,LGattCharacteristics.GetAt(I));
终止
终止
//旧代码
dogetdescriptors函数的扩展(注意,此函数不能完美地执行必要的检查…)

var
LGattDescriptor:IVectorView\u 1\u通用属性文件\u iGatdDescriptor;
I:整数;
特征3:通用属性文件特征3;
描述符3:IAsyncOperation\u 1\u通用属性文件\u IGATD描述结果;
描述:通用属性文件描述结果;
开始
描述者。清晰;
LGattDescriptors:=(FGattCharacteristic作为GenericAttributeProfile_iGatCharacteristic2)。获取所有描述符;
如果LGattDescriptors.Size>0,则
开始
对于I:=0到LGattDescriptor。大小-1 do
FDescriptors.Add(TWinRTBluetoothGattDescriptor.Create(Self,LGattDescriptors.GetAt(I));
终止
其他的
开始
特征3:=fGatCharacteristic作为通用属性文件3;
如果是TAsyncOperation,等等(
特征3.GetDescriptorsAsync(BluetoothCacheMode.Uncached),descriptorRes3)=异步状态。然后完成
开始
descrRes:=descriptorRes3.GetResults;
LGattDescriptors:=描述描述符;
对于I:=0到LGattDescriptor。大小-1 do
FDescriptors.Add(TWinRTBluetoothGattDescriptor.Create(Self,LGattDescriptors.GetAt(I));
终止
终止
结果:=描述者;
终止
var
  I: Integer;
  LGattCharacteristics: IVectorView_1__GenericAttributeProfile_IGattCharacteristic;
  charactRes : GenericAttributeProfile_IGattCharacteristicsResult;
  service3 : GenericAttributeProfile_IGattDeviceService3;
  characteristics3 : IAsyncOperation_1__GenericAttributeProfile_IGattCharacteristicsResult;
begin
  CheckNotClosed;
  FCharacteristics.Clear;

  if FDevice.FId = 0 then
  begin
       service3 := FGattService as GenericAttributeProfile_IGattDeviceService3;

       if TAsyncOperation<IAsyncOperation_1__GenericAttributeProfile_IGattCharacteristicsResult>.Wait(
                        service3.GetCharacteristicsAsync(BluetoothCacheMode.Uncached), characteristics3 ) = AsyncStatus.Completed then 
       begin
            charactRes := characteristics3.GetResults;    
            LGattCharacteristics := charactRes.Characteristics;
            if LGattCharacteristics.Size > 0 then
               for I := 0 to LGattCharacteristics.Size - 1 do
                   FCharacteristics.Add(TWinRTBluetoothGattCharacteristic.Create(Self, LGattCharacteristics.GetAt(I)));
       end;
  end

//old code

var
  LGattDescriptors: IVectorView_1__GenericAttributeProfile_IGattDescriptor;
  I: Integer;
  characteristic3 : GenericAttributeProfile_IGattCharacteristic3;
  descriptorRes3 : IAsyncOperation_1__GenericAttributeProfile_IGattDescriptorsResult;
  descrRes : GenericAttributeProfile_IGattDescriptorsResult;
begin
  FDescriptors.Clear;
  LGattDescriptors := (FGattCharacteristic as GenericAttributeProfile_IGattCharacteristic2).GetAllDescriptors;
  if LGattDescriptors.Size > 0 then
  begin
       for I := 0 to LGattDescriptors.Size - 1 do
           FDescriptors.Add(TWinRTBluetoothGattDescriptor.Create(Self, LGattDescriptors.GetAt(I)));
  end
  else
  begin
       characteristic3 := FGattCharacteristic as GenericAttributeProfile_IGattCharacteristic3;

       if TAsyncOperation<IAsyncOperation_1__GenericAttributeProfile_IGattDescriptorsResult>.Wait(
                        characteristic3.GetDescriptorsAsync(BluetoothCacheMode.Uncached), descriptorRes3 ) = AsyncStatus.Completed then 
       begin
            descrRes := descriptorRes3.GetResults;    
            LGattDescriptors := descrRes.Descriptors;
            for I := 0 to LGattDescriptors.Size - 1 do
                FDescriptors.Add(TWinRTBluetoothGattDescriptor.Create(Self, LGattDescriptors.GetAt(I)));
       end;

  end;
  Result := FDescriptors;
end;