Jump to content
ChrisChuah

TBluetoothLE in Windows 10

Recommended Posts

I have no news of operating differences on receiving messages in Windows.
I tested my application (which I think uses BLE like yours) in MAC, Android and Windows and no change to read and write between the platforms, OnCharacteristicRead should works.
Tomorrow I'll tested with BLE device.

 

……..

Share this post


Link to post

More Windows 10 BLE problems. I am able to see the BLE device and use its Tx Characteristic to write out to a serial device through the BLE. However, when the serial device responds, it seems to be taking quite a long time for the notification to get to my Windows app that the Rx characteristic has been updated. About 20 seconds after the serial device responds, I get a OnCharacteristicRead event and am able to read the expected message from that characteristic. What could cause such a long delay here in the notification? I know from debugging the BLE device that it is sending the message and notifying immediately, but the windows app doesnt get it for 20 seconds. This same app works as it should on iOS.

Share this post


Link to post

I can make two suggestions:

 

1) Use Bluetooth LE Lab (https://www.microsoft.com/store/productId/9N6JD37GWZC8) that you find in the Windows store and with that try to write the Gatt characteristic that affect your hardware, so you see the response times with another software;

 

2) Try to use the BLE connection parameters: these are the settings that an application can try to impose on a BLE device, related to the communication protocol between SERVER GATT and CLIENT GATT (which I never used nor know how to use). The most interesting parameters are the AdvertisingInterval, ConnectionInterval, SlaveLatency, Connection monitoring timeout. But I don't know at this moment how to monitor them or how to set them.

 

Share this post


Link to post

The connection parameters are described UUID 00002A04-0000-1000-8000-00805F9B34FB, with 8 bytes data, but this is read only characteristic; you can read the  characteristic and see how your BLE device want to be connected.

 

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2011 Bluetooth SIG, Inc. All rights reserved. -->
<Characteristic xsi:noNamespaceSchemaLocation="http://schemas.bluetooth.org/Documents/characteristic.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
name="Peripheral Preferred Connection Parameters"
type="org.bluetooth.characteristic.gap.peripheral_preferred_connection_parameters"
last-modified="2013-05-29" uuid="2A04">
  <InformativeText>
    <Abstract>
      <!--The Information included in this page is informative. The normative descriptions are contained in the applicable specification.-->
    </Abstract>
    <InformativeDisclaimer />
  </InformativeText>
  <Value>
    <Field name="Minimum Connection Interval">
      <InformativeText>connInterval_min = Minimum Connection
      Interval * 1.25 ms</InformativeText>
      <Requirement>Mandatory</Requirement>
      <Format>uint16</Format>
      <Minimum>6</Minimum>
      <Maximum>3200</Maximum>
      <AdditionalValues>
        <Enumeration key="65535" value="no specific minimum" />
      </AdditionalValues>
    </Field>
    <Field name="Maximum Connection Interval">
      <InformativeText>connInterval_max = Maximum Connection
      Interval * 1.25 ms. and is equal or greater than the Minimum
      Connection Interval</InformativeText>
      <Requirement>Mandatory</Requirement>
      <Format>uint16</Format>
      <Minimum>6</Minimum>
      <Maximum>3200</Maximum>
      <AdditionalValues>
        <Enumeration key="65535" value="no specific maximum" />
      </AdditionalValues>
    </Field>
    <Field name="Slave Latency">
      <Requirement>Mandatory</Requirement>
      <Format>uint16</Format>
      <Minimum>0</Minimum>
      <Maximum>1000</Maximum>
    </Field>
    <Field name="Connection Supervision Timeout Multiplier">
      <Requirement>Mandatory</Requirement>
      <Format>uint16</Format>
      <Minimum>10</Minimum>
      <Maximum>3200</Maximum>
      <AdditionalValues>
        <Enumeration key="65535"
        value="no specific value requested" />
      </AdditionalValues>
    </Field>
  </Value>

 

 

Share this post


Link to post

I am successfully using my BluetoothLE device now with Windows 10. My next issue is when there are multiple devices with the service ID I am using to filter the search in range. I call DiscoverDevices(4000, ServiceID) and then on Windows 10 it immediately fires the OnEndBluetoothLEScan event. I would like to check DiscoveredDevices.Count in this event and if the count is greater than 1, show the list to the user to choose from. However, this always only has 1 device in the list. It seems like whatever device is closest in range is the one that is shown here. If I run the same thing on an iOS device, OnEndBluetoothScan fires and has a list of all the devices found and I can do what I am describing. Is there a way to gather a list of devices in Windows 10?

Share this post


Link to post

You must wait near 10.4 seconds (but it's possible that works also in 5 seconds) after the OnEndBluetoothLEScan and after that time you can inquiry the count. This is because Windows fire that event immediatly and doesn't wait any timing. Remember that your devices MUST HAVE BEEN PAIRED at least once with Windows !!!

 

Hope this helps you.

 

Bye

Share this post


Link to post

I ran into the same problem and managed to fix that with an external timer that calls CancelDiscovery. It works but leaves a massive

memory/thread leak since every time a new discovery is started the timer variable gets overwritten and not freed leaving the pending thread and

it's resources....

 

The problem actually is:

the problem is within the Delphi implementation of the Thread that triggers the CancelDiscovery function.

In Windows there is a Thread (TWinRTBluetoothLEAdapter.TDiscoverThreadTimer in System.Win.BluetoothWinRT.pas) that

actually just waits for a specific amount of time and calls the given timer procedure. The problem here is that the

Timer procedure cleans up the thread (calls .Free) which waits for the end of the Thread -> deadlock.

 

To circumvent that problem I needed to adjust System.Win.BluetoothWinRT do the following:

 

Augment the class

TWinRTBluetoothLEAdapter

by

 

private
    const WM_BTLE_CANCELDISCOVERY = $400 + 666; // WM_USER

...

private

  fHDL : HWND;
  procedure BTLETimerHandler( var msg : TMessage );

protected

  procedure ThrDoCancelDiscovery;

 

..

implementation

 

procedure TWinRTBluetoothLEAdapter.BTLETimerHandler(var msg: TMessage);
begin
     if msg.Msg = WM_BTLE_CANCELDISCOVERY then
        DoCancelDiscovery;
end;

 

procedure TWinRTBluetoothLEAdapter.ThrDoCancelDiscovery;
begin
     // just post otherwise the thread hangs!
     PostMessage( fHDL, WM_BTLE_CANCELDISCOVERY, 0, 0);
end;

 

constructor TWinRTBluetoothLEAdapter.Create(const AManager: TBluetoothLEManager; const ARadioInfo: TBluetoothRadioInfo);

begin

  inherited Create(AManager);
  fHDL := AllocateHWnd(BTLETimerHandler);

...

end;

 

destructor TWinRTBluetoothLEAdapter.Destroy;
begin
  DeallocateHWnd(fHDL);

...

end;

 

function TWinRTBluetoothLEAdapter.DoStartDiscovery(Timeout: Cardinal; const AFilterUUIDList: TBluetoothUUIDsList;
  const ABluetoothLEScanFilterList: TBluetoothLEScanFilterList): Boolean;

begin

...

 

// new code

if Assigned(fTimerThread) then
  begin
    fTimerThread.Cancel;
    fTimerThread.Free;
  end;

// changed from DoCancelDiscovery to ThrDoCancelDiscovery

  FTimerThread := TDiscoverThreadTimer.Create(Self, ThrDoCancelDiscovery, Timeout);

...

end;

 

I guess one could also use TThread.Queue instead of the "complicated" window allocation in the timer and that should do the trick too!

Share this post


Link to post
I don't know the WinRT API and have never developed a UWP application.
I would have created an external timer (a normal TTimer) and called the CancelDiscovery function without "touching" the BLE timer.
 
In normal WIN32 api I do this and I have no problems whatsoever.
 
Bye.
 
 

Share this post


Link to post
1 hour ago, DelphiUdIT said:
I don't know the WinRT API and have never developed a UWP application.
I would have created an external timer (a normal TTimer) and called the CancelDiscovery function without "touching" the BLE timer.
 
In normal WIN32 api I do this and I have no problems whatsoever.

And how do you do that in win32? I wasn't able to find any BT LE classes or functions besides the WinRT stuff that is covered in Delphi.

Please note that my code here patches the actual TBluetoothLE component that ships with Delphi 10.4.2!

And yes I use this code in conjunction with a standard VCL app 😉

Share this post


Link to post

The WIN32 apis for BlueTooth are system based and are present in:

 

 rtl/net/System.Bluetooth

 rtl/net/System.Bluetooth.Components

 

All systems supported by Delphi have BLE (IOS does not have the classic BlueTooth).

I use FMX with BLE because I usually make apps for Android too.

 

Some difference with use of BLE is that with Windows the devices must be paired almost one time to be used with BLE.

 

Bye.

Share this post


Link to post
17 hours ago, DelphiUdIT said:

The WIN32 apis for BlueTooth are system based and are present in:

 

 rtl/net/System.Bluetooth

 rtl/net/System.Bluetooth.Components

That is only the one half of the story. This is the base - in the next abstraction layer Emba decided to go to the different platforms -

and for windows and Bluetooth LE the last file that actually implements stuff is System.Win.BluetoothWinRT.pas

 

 

17 hours ago, DelphiUdIT said:

Some difference with use of BLE is that with Windows the devices must be paired almost one time to be used with BLE. 

That is also not entierly true. The imlementation from Embarcadero lacks this ability yes - I managed though to extend the WinRT implementation such that this

is possible too.

See the attached file on:
https://quality.embarcadero.com/browse/RSP-21711

 

hope that helps 😉

  • Like 1

Share this post


Link to post
5 hours ago, mikerabat said:

That is only the one half of the story. This is the base - in the next abstraction layer Emba decided to go to the different platforms -

and for windows and Bluetooth LE the last file that actually implements stuff is System.Win.BluetoothWinRT.pas

 

 

That is also not entierly true. The imlementation from Embarcadero lacks this ability yes - I managed though to extend the WinRT implementation such that this

is possible too.

See the attached file on:
https://quality.embarcadero.com/browse/RSP-21711

 

hope that helps 😉

I try your last implementation, but with the original Delphi file all is working, while with your solution only one service is found. I'll try to debug whats wrong next week.

 

And, 👍 YES with your solution seems that devices should not be paired anymore. Good work.

 

Bye

Immagine.png

Immagine1.png

Edited by DelphiUdIT

Share this post


Link to post

Everything good.


Everything works under both Windows and Android (but probably also under MACOS and IOS).

The problem I encountered in my last post stemmed from my VERY BAD :classic_blush: programming: I assumed that the services were listed in order as the device proposed them (which is true with the original EMB file but not with the changes made).

Congratulations @mikerabat, I think EMB will use some of your code in the next versions.

 

Bye

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×