DelphiUdIT 176 Posted February 5, 2021 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
almcneil15 0 Posted February 10, 2021 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
DelphiUdIT 176 Posted February 10, 2021 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
DelphiUdIT 176 Posted February 10, 2021 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
almcneil15 0 Posted March 8, 2021 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
DelphiUdIT 176 Posted March 8, 2021 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
mikerabat 20 Posted July 15, 2021 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
DelphiUdIT 176 Posted July 15, 2021 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
mikerabat 20 Posted July 15, 2021 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
DelphiUdIT 176 Posted July 15, 2021 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
mikerabat 20 Posted July 16, 2021 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 😉 1 Share this post Link to post
DelphiUdIT 176 Posted July 16, 2021 (edited) 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 Edited July 16, 2021 by DelphiUdIT Share this post Link to post
DelphiUdIT 176 Posted July 29, 2021 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 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