Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to refresh Services and Characteristics values after reconnecting when using QtBluetooth?
Forum Updated to NodeBB v4.3 + New Features

How to refresh Services and Characteristics values after reconnecting when using QtBluetooth?

Scheduled Pinned Locked Moved Unsolved General and Desktop
6 Posts 2 Posters 625 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • S Offline
    S Offline
    swjqq
    wrote on 24 Apr 2024, 13:10 last edited by swjqq
    #1

    I encountered some issues when implementing OTA functionality on BLE devices using QtBluetooth (6.5.3, MSVC 2019, based on lowenergyscanner) on Windows 11. The OTA process is as follows:

    1. Write 0x0 to OTA CONTROL characteristic
    2. Device will disconnect on its own
    3. Reconnect with device (it will have OTA DATA characteristic this time)
    4. Write 0x0 to OTA CONTROL again
    5. Start writing to OTA DATA characteristic
    6. Write 0x3 to OTA CONTROL to end upload

    Perform steps 1-3 using QtBluetooth, but after reconnecting, the OTA DATA characteristic cannot be found (see Figure 1). However, when I used Bluetooth LE Explorer to perform steps 1-3, and after reconnecting, it was able to find the OTA DATA characteristic (see Figure 2). Is it possible to refresh the services and characteristic s after reconnecting?

    图片1.png
    图片2.png

    1 Reply Last reply
    0
    • P Offline
      P Offline
      Paul Colby
      wrote on 25 Apr 2024, 09:00 last edited by
      #2

      @swjqq said in How to refresh Services and Characteristics values after reconnecting when using QtBluetooth?:

      Is it possible to refresh the services and characteristic s after reconnecting?

      Have you tried connecting a slot to the QLowEnergyController::connected() signal that invokes QLowEnergyController::discoverServices(), then wait for PokitDevicePrivate::discoveryFinished() signal before looking for the service and characteristic?

      Cheers.

      S 1 Reply Last reply 25 Apr 2024, 15:09
      0
      • P Paul Colby
        25 Apr 2024, 09:00

        @swjqq said in How to refresh Services and Characteristics values after reconnecting when using QtBluetooth?:

        Is it possible to refresh the services and characteristic s after reconnecting?

        Have you tried connecting a slot to the QLowEnergyController::connected() signal that invokes QLowEnergyController::discoverServices(), then wait for PokitDevicePrivate::discoveryFinished() signal before looking for the service and characteristic?

        Cheers.

        S Offline
        S Offline
        swjqq
        wrote on 25 Apr 2024, 15:09 last edited by swjqq
        #3

        @Paul-Colby Thank you for your reply.

        Have you tried connecting a slot to the QLowEnergyController::connected() signal that invokes QLowEnergyController::discoverServices(), then wait for PokitDevicePrivate::discoveryFinished() signal before looking for the service and characteristic?

        I think I have done it(see the following pictures). Furthermore, after executing step 1, even if I close the lowenergyscanner, reopen it, and reconnect to the target BLE device, the services and characteristics remain the same as before, and the OTA DATA characteristic still cannot be found. However, after executing step 1, close the lowenergyscanner, turn off Bluetooth and reopen Bluetooth in the settings application of Win11, reopen lowenergyscanner and reconnect to the target BLE device, then it can refresh services and characteristics and find the OTA DATA characteristic(see the final picture).
        78d89e23-f6c0-421c-b5e4-454d5b2fdfb9-image.png
        2e801da7-ec5e-498a-9e4f-39962f94bc1a-image.png
        2bad5a43-ab4a-4a1c-b26e-9a34054aa87d-image.png
        019cc524-91b8-402d-9996-384f64ad54c5-image.png
        480f3afd-ffae-4a88-9b12-65c173c2d337-image.png
        3037b379-9442-4a04-9021-591347780e93-image.png

        P 1 Reply Last reply 26 Apr 2024, 01:32
        0
        • S swjqq
          25 Apr 2024, 15:09

          @Paul-Colby Thank you for your reply.

          Have you tried connecting a slot to the QLowEnergyController::connected() signal that invokes QLowEnergyController::discoverServices(), then wait for PokitDevicePrivate::discoveryFinished() signal before looking for the service and characteristic?

          I think I have done it(see the following pictures). Furthermore, after executing step 1, even if I close the lowenergyscanner, reopen it, and reconnect to the target BLE device, the services and characteristics remain the same as before, and the OTA DATA characteristic still cannot be found. However, after executing step 1, close the lowenergyscanner, turn off Bluetooth and reopen Bluetooth in the settings application of Win11, reopen lowenergyscanner and reconnect to the target BLE device, then it can refresh services and characteristics and find the OTA DATA characteristic(see the final picture).
          78d89e23-f6c0-421c-b5e4-454d5b2fdfb9-image.png
          2e801da7-ec5e-498a-9e4f-39962f94bc1a-image.png
          2bad5a43-ab4a-4a1c-b26e-9a34054aa87d-image.png
          019cc524-91b8-402d-9996-384f64ad54c5-image.png
          480f3afd-ffae-4a88-9b12-65c173c2d337-image.png
          3037b379-9442-4a04-9021-591347780e93-image.png

          P Offline
          P Offline
          Paul Colby
          wrote on 26 Apr 2024, 01:32 last edited by
          #4

          Hi @swjqq, the code looks pretty reasonable to me. A couple of quick things:

          1. just to be sure, you are re-creating the controller right?
          2. I would add some logging to Device::serviceDetailsDiscovered() - partly because there are other newState values not being explicitly handled, and it would be go at least know when the anti-hang fallback is triggered. That said, I don't think that's the issue.
          3. consider enabling Qt's Bluetooth debug log categories - especially qt.bluetooth and qt.bluetooth.windows, and possibly qt.bluetooth.winrt.service.thread. eg you could set an environment variable, something like QT_LOGGING_RULES="qt.bluetooth.debug=true;qt.bluetooth.*.debug=true"

          That said,

          even if I close the lowenergyscanner, reopen it, and reconnect to the target BLE device, the services and characteristics remain the same as before, and the OTA DATA characteristic still cannot be found.

          this suggests that underlying BLE driver (ie Windows in your case) is caching the device/service details. It would be interesting to try your code on Linux or macOS for comparison (they will also cache in lots of ways, but differently, so might be interesting).

          The following is all speculation (I don't have a Windows platform handy to test, nor a device that works like yours)... I suspect what you need is to reset the Window's BT driver's cache. I have no idea how to do that, but it appears that Qt's BLE WinRT code does have an internal implementation for closing BLE services via ComPtr<IClosable>. Tracing Qt's code back, it seems like this only really gets called when discovering. You might suspect the "close" would happen on destruction, but in fact it looks like that's only if an mAbortRequested flags is set, which appears to be set only when you explicitly requested the disconnect. Again, just speculating, but I think the BLE model here (at least for Linux/BlueZ and WinRT) is that the OS keeps connections to the BLE device, and then "leases" them out to client applications (possibly one at a time, or shared, depending on many factors).

          Anyway, it seems that the WinRT implementation does "clear the previous services cache" when (re)discovering services. However, it does this by iterating the currently known services, and closing them one by one. In the case of restarting the application, for example, there are no existing services to close, so (presumably) nothing to ask the OS to close, and ultimately nothing to get refreshed.

          So... a bit of a long shot, but I would try:

          1. explicitly disconnecting the device - immediately after writing your characteristic, and/or immediately after receiving the disconnect signal (I'd try all combinations of either/both);
          2. explicitly try to re-discover services after the initial discovery fails to find the new characteristic (the first discovery would register the WinRT BLE device with Qt, the second would close it before re-discovering).

          Be sure to enable Qt's BLE logging as well.

          Finally, it's also worth noting there were some WinRT BLE discovery improvements between Qt 6.5.3 and Qt 5.7, so definitely try upgrading Qt first if you can.

          Good luck!

          S 2 Replies Last reply 26 Apr 2024, 10:20
          1
          • P Paul Colby
            26 Apr 2024, 01:32

            Hi @swjqq, the code looks pretty reasonable to me. A couple of quick things:

            1. just to be sure, you are re-creating the controller right?
            2. I would add some logging to Device::serviceDetailsDiscovered() - partly because there are other newState values not being explicitly handled, and it would be go at least know when the anti-hang fallback is triggered. That said, I don't think that's the issue.
            3. consider enabling Qt's Bluetooth debug log categories - especially qt.bluetooth and qt.bluetooth.windows, and possibly qt.bluetooth.winrt.service.thread. eg you could set an environment variable, something like QT_LOGGING_RULES="qt.bluetooth.debug=true;qt.bluetooth.*.debug=true"

            That said,

            even if I close the lowenergyscanner, reopen it, and reconnect to the target BLE device, the services and characteristics remain the same as before, and the OTA DATA characteristic still cannot be found.

            this suggests that underlying BLE driver (ie Windows in your case) is caching the device/service details. It would be interesting to try your code on Linux or macOS for comparison (they will also cache in lots of ways, but differently, so might be interesting).

            The following is all speculation (I don't have a Windows platform handy to test, nor a device that works like yours)... I suspect what you need is to reset the Window's BT driver's cache. I have no idea how to do that, but it appears that Qt's BLE WinRT code does have an internal implementation for closing BLE services via ComPtr<IClosable>. Tracing Qt's code back, it seems like this only really gets called when discovering. You might suspect the "close" would happen on destruction, but in fact it looks like that's only if an mAbortRequested flags is set, which appears to be set only when you explicitly requested the disconnect. Again, just speculating, but I think the BLE model here (at least for Linux/BlueZ and WinRT) is that the OS keeps connections to the BLE device, and then "leases" them out to client applications (possibly one at a time, or shared, depending on many factors).

            Anyway, it seems that the WinRT implementation does "clear the previous services cache" when (re)discovering services. However, it does this by iterating the currently known services, and closing them one by one. In the case of restarting the application, for example, there are no existing services to close, so (presumably) nothing to ask the OS to close, and ultimately nothing to get refreshed.

            So... a bit of a long shot, but I would try:

            1. explicitly disconnecting the device - immediately after writing your characteristic, and/or immediately after receiving the disconnect signal (I'd try all combinations of either/both);
            2. explicitly try to re-discover services after the initial discovery fails to find the new characteristic (the first discovery would register the WinRT BLE device with Qt, the second would close it before re-discovering).

            Be sure to enable Qt's BLE logging as well.

            Finally, it's also worth noting there were some WinRT BLE discovery improvements between Qt 6.5.3 and Qt 5.7, so definitely try upgrading Qt first if you can.

            Good luck!

            S Offline
            S Offline
            swjqq
            wrote on 26 Apr 2024, 10:20 last edited by swjqq
            #5
            This post is deleted!
            1 Reply Last reply
            0
            • P Paul Colby
              26 Apr 2024, 01:32

              Hi @swjqq, the code looks pretty reasonable to me. A couple of quick things:

              1. just to be sure, you are re-creating the controller right?
              2. I would add some logging to Device::serviceDetailsDiscovered() - partly because there are other newState values not being explicitly handled, and it would be go at least know when the anti-hang fallback is triggered. That said, I don't think that's the issue.
              3. consider enabling Qt's Bluetooth debug log categories - especially qt.bluetooth and qt.bluetooth.windows, and possibly qt.bluetooth.winrt.service.thread. eg you could set an environment variable, something like QT_LOGGING_RULES="qt.bluetooth.debug=true;qt.bluetooth.*.debug=true"

              That said,

              even if I close the lowenergyscanner, reopen it, and reconnect to the target BLE device, the services and characteristics remain the same as before, and the OTA DATA characteristic still cannot be found.

              this suggests that underlying BLE driver (ie Windows in your case) is caching the device/service details. It would be interesting to try your code on Linux or macOS for comparison (they will also cache in lots of ways, but differently, so might be interesting).

              The following is all speculation (I don't have a Windows platform handy to test, nor a device that works like yours)... I suspect what you need is to reset the Window's BT driver's cache. I have no idea how to do that, but it appears that Qt's BLE WinRT code does have an internal implementation for closing BLE services via ComPtr<IClosable>. Tracing Qt's code back, it seems like this only really gets called when discovering. You might suspect the "close" would happen on destruction, but in fact it looks like that's only if an mAbortRequested flags is set, which appears to be set only when you explicitly requested the disconnect. Again, just speculating, but I think the BLE model here (at least for Linux/BlueZ and WinRT) is that the OS keeps connections to the BLE device, and then "leases" them out to client applications (possibly one at a time, or shared, depending on many factors).

              Anyway, it seems that the WinRT implementation does "clear the previous services cache" when (re)discovering services. However, it does this by iterating the currently known services, and closing them one by one. In the case of restarting the application, for example, there are no existing services to close, so (presumably) nothing to ask the OS to close, and ultimately nothing to get refreshed.

              So... a bit of a long shot, but I would try:

              1. explicitly disconnecting the device - immediately after writing your characteristic, and/or immediately after receiving the disconnect signal (I'd try all combinations of either/both);
              2. explicitly try to re-discover services after the initial discovery fails to find the new characteristic (the first discovery would register the WinRT BLE device with Qt, the second would close it before re-discovering).

              Be sure to enable Qt's BLE logging as well.

              Finally, it's also worth noting there were some WinRT BLE discovery improvements between Qt 6.5.3 and Qt 5.7, so definitely try upgrading Qt first if you can.

              Good luck!

              S Offline
              S Offline
              swjqq
              wrote on 26 Apr 2024, 12:58 last edited by swjqq
              #6

              @Paul-Colby Thanks for your reply again.

              It would be interesting to try your code on Linux or macOS for comparison (they will also cache in lots of ways, but differently, so might be interesting).

              I only tried the code on Linux for comparison (I don't have a macOS platform) and found that it didn't cache the service list. The application could find the OTA DATA characteristic after performing steps 1-3.

              1.explicitly disconnecting the device - immediately after writing your characteristic, and/or immediately after receiving the disconnect signal (I'd try all combinations of either/both);

              I tried all combinations on Windows 11, but none of them worked.

              2.explicitly try to re-discover services after the initial discovery fails to find the new characteristic (the first discovery would register the WinRT BLE device with Qt, the second would close it before re-discovering).

              I tried re-discover services and characteristics through two buttons, but none of them worked. The function QLowEnergyController::discoverServices() does nothing since it has been called immediately in the slot triggered by the QLowEnergyController::connected() signal. According to Qt help project, the best workaround is to temporarily turn Bluetooth off. So is it possible to turn Bluetooth off by code?

              ee9e7492-c5fe-472a-85cf-cd556c0e7f21-image.png

              e10dfff3-66ce-4823-808d-5299fa8a8e45-image.png

              Anyway, it seems that the WinRT implementation does "clear the previous services cache" when (re)discovering services. However, it does this by iterating the currently known services, and closing them one by one.

              Please see BluetoothLE example of Windows-universal-samples and the following codes (found at Windows Kits\10\Include\10.0.22621.0\cppwinrt\winrt):

              template <typename D> WINRT_IMPL_AUTO(winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceServicesResult>) consume_Windows_Devices_Bluetooth_IBluetoothLEDevice3<D>::GetGattServicesAsync(winrt::Windows::Devices::Bluetooth::BluetoothCacheMode const& cacheMode) const
              {
                  void* operation{};
                  check_hresult(WINRT_IMPL_SHIM(winrt::Windows::Devices::Bluetooth::IBluetoothLEDevice3)->GetGattServicesWithCacheModeAsync(static_cast<int32_t>(cacheMode), &operation));
                  return winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Devices::Bluetooth::GenericAttributeProfile::GattDeviceServicesResult>{ operation, take_ownership_from_abi };
              }
              

              In QLowEnergyControllerPrivateWinRT: : discoverServices(), I think it should use GetGattServicesWithCacheModeAsync rather than GetGattServicesAsync. In obtainCharList, I think it should use GetCharacteristicsWithCacheModeAsync rather than GetCharacteristicsAsync. I have tried to modified the source codes (see the following pictures) and found it was worked. Now the application could find the OTA DATA characteristic after performing steps 1-3, but the speed of finding services and characteristics slowed down significantly.

              72fce72e-0a82-4a31-8257-e06693fdbbdb-image.png

              454e4f40-8784-41d1-a708-89911154bf6d-image.png

              7513dc0b-4c3c-4048-ab94-244c4c809c76-image.png

              1 Reply Last reply
              0

              1/6

              24 Apr 2024, 13:10

              • Login

              • Login or register to search.
              1 out of 6
              • First post
                1/6
                Last post
              0
              • Categories
              • Recent
              • Tags
              • Popular
              • Users
              • Groups
              • Search
              • Get Qt Extensions
              • Unsolved