Einzelnen Beitrag anzeigen

rabatscher

Registriert seit: 13. Dez 2007
Ort: Bruck an der Mur
69 Beiträge
 
#5

AW: Bluetooth LE unter Windows 11 funktioniert nicht mehr

  Alt 16. Aug 2023, 12:40
Nur kurz zur Info - es scheint, dass das Enumerieren der Characteristiken in Win11 IN einem Thread sein sollt - nicht im Haupthread...
(Message loop und BTLE stehen sowieso auf "Kriegsfuß". Manche Dinge müssen im Haupthread gemacht werden, manche eben nicht).

Der Fix ist im Endefekt in der Datei System.Win.BluetoothWinRT.pas in den Routinen "DoDiscoverServices" und
"DoGetCharacteristics" und "DoGetIncludedServices" einzubauen (Ich habe auch noch eine Art "Timeout" hinzugefügt...):

Hier mein Code:


Code:
function TWinRTBluetoothLEDevice.DoDiscoverServices: Boolean;
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
       if not Supports(FBluetoothLEDevice, IBluetoothLEDevice3, dev3) then
          raise EBluetoothDeviceException.CreateRes(@SBluetoothLEDeviceNotPaired);

       if TAsyncOperation<IAsyncOperation_1__GenericAttributeProfile_IGattDeviceServicesResult>.Wait(
          dev3.GetGattServicesAsync(BluetoothCacheMode.Uncached), res3 ) = AsyncStatus.Completed then
       begin
            serviceRes := res3.GetResults;

            LGattServices := serviceRes.Services;

            if LGattServices.Size > 0 then
            begin
                 for I := 0 to LGattServices.Size - 1 do
                 begin
                      LGattService := LGattServices.GetAt(I);
                      FServices.Add(TWinRTBluetoothGattService.Create(Self, LGattService, TBluetoothServiceType.Primary));
                 end;
            end;
       end;
  end
  else
  begin
  if FBluetoothLEDevice.GattServices.Size > 0 then
    for I := 0 to FBluetoothLEDevice.GattServices.Size - 1 do
    begin
      LGattService := FBluetoothLEDevice.GattServices.GetAt(I);
      FServices.Add(TWinRTBluetoothGattService.Create(Self, LGattService, TBluetoothServiceType.Primary));
    end;
  end;

  // ###########################################
  // #### enumerate the characteristics at once: note on windows 11 it seems
  // that the enumeration of characteristics NEED to be in a thread and
  // we trigger the characteristics fetch
  for i := 0 to fServices.Count - 1 do
  begin
       TWinRTBluetoothGattService(fServices[i]).FTimeout := fOperationTimeout;
       TWinRTBluetoothGattService(fServices[i]).DoGetCharacteristics;
  end;

  DoOnServicesDiscovered(Self, FServices);
end;

tion TWinRTBluetoothGattService.DoGetCharacteristics: TBluetoothGattCharacteristicList;
var I: Integer;
    service3 : GenericAttributeProfile_IGattDeviceService3;
    LGattCharacteristics: IVectorView_1__GenericAttributeProfile_IGattCharacteristic;
    res3 : IAsyncOperation_1__GenericAttributeProfile_IGattCharacteristicsResult;
    status1 : IAsyncOperation_1__GenericAttributeProfile_GattOpenStatus;
    charactersRes : GenericAttributeProfile_IGattCharacteristicsResult;
    characteristic : GenericAttributeProfile_IGattCharacteristic;
begin
  Result := FCharacteristics;
  if fCharacteristicsFetched then
     exit;

  CheckNotClosed;
  FCharacteristics.Clear;

  if Supports(FGattService, GenericAttributeProfile_IGattDeviceService3, service3) then
  begin
       if TAsyncOperation<IAsyncOperation_1__GenericAttributeProfile_GattOpenStatus>.Wait(
              service3.OpenAsync(GenericAttributeProfile_GattSharingMode.SharedReadAndWrite), status1 ) <> AsyncStatus.Completed
       then
           exit(nil);

       if (status1.GetResults = GenericAttributeProfile_GattOpenStatus.Success) or
          (status1.GetResults = GenericAttributeProfile_GattOpenStatus.AlreadyOpened) then
       begin
            if TAsyncOperation<IAsyncOperation_1__GenericAttributeProfile_IGattCharacteristicsResult>.Wait(
                   service3.GetCharacteristicsAsync(BluetoothCacheMode.Uncached), res3, FTimeout ) = AsyncStatus.Completed
            then
            begin
                 charactersRes := res3.GetResults;

                 LGattCharacteristics := charactersRes.Characteristics;

                 if LGattCharacteristics.Size > 0 then
                 begin
                      for I := LGattCharacteristics.Size - 1 downto 0 do
                      begin
                           characteristic := LGattCharacteristics.GetAt(I);
                           FCharacteristics.Add(TWinRTBluetoothGattCharacteristic.Create(Self, characteristic));
                      end;
                 end;
            end;
       end
       else
           OutputDebugString(PChar('RequestAccessAysync failed with code ' + Integer(status1.GetResults).tostring));
  end
  else
  begin
       // does not work any more -> need to do sync
       LGattCharacteristics := (FGattService as GenericAttributeProfile_IGattDeviceService2).GetAllCharacteristics;
       if LGattCharacteristics.Size > 0 then
         for I := 0 to LGattCharacteristics.Size - 1 do
           FCharacteristics.Add(TWinRTBluetoothGattCharacteristic.Create(Self, LGattCharacteristics.GetAt(I)));
  end;

  for i := 0 to FCharacteristics.Count - 1 do
  begin
       TWinRTBluetoothGattCharacteristic(fCharacteristics[i]).FTimeout := FTimeout;
       TWinRTBluetoothGattCharacteristic(fCharacteristics[i]).DoGetDescriptors;
  end;

  fCharacteristicsFetched := True;
  Result := FCharacteristics;
end;

function TWinRTBluetoothGattService.DoGetIncludedServices: TBluetoothGattServiceList;
var
  I: Integer;
  LGattServices: IVectorView_1__GenericAttributeProfile_IGattDeviceService;
  service3 : GenericAttributeProfile_IGattDeviceService3;
  res3 : IAsyncOperation_1__GenericAttributeProfile_IGattDeviceServicesResult;
  serviceRes : GenericAttributeProfile_IGattDeviceServicesResult;
  status1 : IAsyncOperation_1__GenericAttributeProfile_GattOpenStatus;
begin
  CheckNotClosed;
  FIncludedServices.Clear;

  if Supports(FGattService, GenericAttributeProfile_IGattDeviceService3, service3) then
  begin
       if TAsyncOperation<IAsyncOperation_1__GenericAttributeProfile_GattOpenStatus>.Wait(
              service3.OpenAsync(GenericAttributeProfile_GattSharingMode.SharedReadAndWrite), status1 ) <> AsyncStatus.Completed
       then
           exit(nil);

       if (status1.GetResults = GenericAttributeProfile_GattOpenStatus.Success) or
          (status1.GetResults = GenericAttributeProfile_GattOpenStatus.AlreadyOpened) then
       begin
            if TAsyncOperation<IAsyncOperation_1__GenericAttributeProfile_IGattDeviceServicesResult>.Wait(
                   service3.GetIncludedServicesAsync, res3, FTimeout ) = AsyncStatus.Completed
            then
            begin
                 serviceRes := res3.GetResults;

                 LGattServices := serviceRes.Services;

                 if LGattServices.Size > 0 then
                 begin
                      for I := LGattServices.Size - 1 downto 0 do
                          FIncludedServices.Add(TWinRTBluetoothGattService.Create(FDevice, LGattServices.GetAt(I), TBluetoothServiceType.Primary));
                 end;
            end;
       end
       else
           OutputDebugString(PChar('RequestAccessAysync failed with code ' + Integer(status1.GetResults).tostring));
  end
  else
  begin
       LGattServices := (FGattService as GenericAttributeProfile_IGattDeviceService2).GetAllIncludedServices;
       if LGattServices.Size > 0 then
         for I := 0 to LGattServices.Size - 1 do
           FIncludedServices.Add(TWinRTBluetoothGattService.Create(FDevice, LGattServices.GetAt(I), TBluetoothServiceType.Primary));
  end;

  Result := FIncludedServices;
end;
Bitte mal mit dem Snipplets probieren und für fTimeout = 10000 einsetzen. fCharacteristicsFetched ist auch von mir und sollte im TWinRTBluetoothGattService als private variable deklariert werden.

Falls wer noch interesse hat ich kann das File auch schicken - nur nicht ganz öffentlich machen...
  Mit Zitat antworten Zitat