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. Bluetooth Low Energy Scanner: Discover Service Details
QtWS25 Last Chance

Bluetooth Low Energy Scanner: Discover Service Details

Scheduled Pinned Locked Moved Solved General and Desktop
blebluetooth low escanner
9 Posts 4 Posters 1.8k Views
  • 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
    SpaceToon
    wrote on 7 Dec 2019, 12:58 last edited by
    #1

    Hello,

    I am trying to understand how BLE works by playing with the BLE Scanner example from Qt. So after discovering BLE devices, connecting to a device and selecting a service, the next step is to print the characteristics. For this purpose, there is the following code in the example:

    void Device::connectToService(const QString &uuid)
    {
        QLowEnergyService *service = nullptr;
        for (auto s: qAsConst(m_services)) {
            auto serviceInfo = qobject_cast<ServiceInfo *>(s);
            if (!serviceInfo)
                continue;
    
            if (serviceInfo->getUuid() == uuid) {
                service = serviceInfo->service();
                break;
            }
        }
    
        if (!service)
            return;
    
        qDeleteAll(m_characteristics);
        m_characteristics.clear();
        emit characteristicsUpdated();
    
        if (service->state() == QLowEnergyService::DiscoveryRequired) {
            //! [les-service-3]
            connect(service, &QLowEnergyService::stateChanged,
                    this, &Device::serviceDetailsDiscovered);
            service->discoverDetails();
            setUpdate("Back\n(Discovering details...)");
            //! [les-service-3]
            return;
        }
    
        //discovery already done
        const QList<QLowEnergyCharacteristic> chars = service->characteristics();
        for (const QLowEnergyCharacteristic &ch : chars) {
            auto cInfo = new CharacteristicInfo(ch);
            m_characteristics.append(cInfo);
        }
    
        QTimer::singleShot(0, this, &Device::characteristicsUpdated);
    }
    
    
    void Device::serviceDetailsDiscovered(QLowEnergyService::ServiceState newState)
    {
        qDebug() << "service details discovered" << newState; //this line is from me for debugging
    
        if (newState != QLowEnergyService::ServiceDiscovered) {
            // do not hang in "Scanning for characteristics" mode forever
            // in case the service discovery failed
            // We have to queue the signal up to give UI time to even enter
            // the above mode
            if (newState != QLowEnergyService::DiscoveringServices) {
                QMetaObject::invokeMethod(this, "characteristicsUpdated",
                                          Qt::QueuedConnection);
            }
            return;
        }
    
        auto service = qobject_cast<QLowEnergyService *>(sender());
        if (!service)
            return;
    
    
    
        //! [les-chars]
        const QList<QLowEnergyCharacteristic> chars = service->characteristics();
        for (const QLowEnergyCharacteristic &ch : chars) {
            auto cInfo = new CharacteristicInfo(ch);
            m_characteristics.append(cInfo);
        }
        //! [les-chars]
    
        emit characteristicsUpdated();
    }
    

    So when I run the program with the code line I inserted for debugging in the serviceDetailsDiscovered - slot

        qDebug() << "service details discovered" << newState;
    

    This code is called twice and the output is:
    "service details discovered QLowEnergyService::DiscoveringServices
    service details discovered QLowEnergyService::ServiceDiscovered"

    But as I can see, the slot is only called once in the code, when the state changes. So how is it possible, that the slot is executed twice although it is only called once? if I debug with a breakpoint, it is not working because only when main is executed to end the UI is shown up..

    S 1 Reply Last reply 8 Dec 2019, 09:15
    0
    • S SpaceToon
      7 Dec 2019, 12:58

      Hello,

      I am trying to understand how BLE works by playing with the BLE Scanner example from Qt. So after discovering BLE devices, connecting to a device and selecting a service, the next step is to print the characteristics. For this purpose, there is the following code in the example:

      void Device::connectToService(const QString &uuid)
      {
          QLowEnergyService *service = nullptr;
          for (auto s: qAsConst(m_services)) {
              auto serviceInfo = qobject_cast<ServiceInfo *>(s);
              if (!serviceInfo)
                  continue;
      
              if (serviceInfo->getUuid() == uuid) {
                  service = serviceInfo->service();
                  break;
              }
          }
      
          if (!service)
              return;
      
          qDeleteAll(m_characteristics);
          m_characteristics.clear();
          emit characteristicsUpdated();
      
          if (service->state() == QLowEnergyService::DiscoveryRequired) {
              //! [les-service-3]
              connect(service, &QLowEnergyService::stateChanged,
                      this, &Device::serviceDetailsDiscovered);
              service->discoverDetails();
              setUpdate("Back\n(Discovering details...)");
              //! [les-service-3]
              return;
          }
      
          //discovery already done
          const QList<QLowEnergyCharacteristic> chars = service->characteristics();
          for (const QLowEnergyCharacteristic &ch : chars) {
              auto cInfo = new CharacteristicInfo(ch);
              m_characteristics.append(cInfo);
          }
      
          QTimer::singleShot(0, this, &Device::characteristicsUpdated);
      }
      
      
      void Device::serviceDetailsDiscovered(QLowEnergyService::ServiceState newState)
      {
          qDebug() << "service details discovered" << newState; //this line is from me for debugging
      
          if (newState != QLowEnergyService::ServiceDiscovered) {
              // do not hang in "Scanning for characteristics" mode forever
              // in case the service discovery failed
              // We have to queue the signal up to give UI time to even enter
              // the above mode
              if (newState != QLowEnergyService::DiscoveringServices) {
                  QMetaObject::invokeMethod(this, "characteristicsUpdated",
                                            Qt::QueuedConnection);
              }
              return;
          }
      
          auto service = qobject_cast<QLowEnergyService *>(sender());
          if (!service)
              return;
      
      
      
          //! [les-chars]
          const QList<QLowEnergyCharacteristic> chars = service->characteristics();
          for (const QLowEnergyCharacteristic &ch : chars) {
              auto cInfo = new CharacteristicInfo(ch);
              m_characteristics.append(cInfo);
          }
          //! [les-chars]
      
          emit characteristicsUpdated();
      }
      

      So when I run the program with the code line I inserted for debugging in the serviceDetailsDiscovered - slot

          qDebug() << "service details discovered" << newState;
      

      This code is called twice and the output is:
      "service details discovered QLowEnergyService::DiscoveringServices
      service details discovered QLowEnergyService::ServiceDiscovered"

      But as I can see, the slot is only called once in the code, when the state changes. So how is it possible, that the slot is executed twice although it is only called once? if I debug with a breakpoint, it is not working because only when main is executed to end the UI is shown up..

      S Offline
      S Offline
      sierdzio
      Moderators
      wrote on 8 Dec 2019, 09:15 last edited by
      #2

      @SpaceToon said in Bluetooth Low Energy Scanner: Discover Service Details:

      But as I can see, the slot is only called once in the code, when the state changes

      That method is a slot. It is called every time QLowEnergyService::stateChanged() signal is emitted. In this case, visibly, it is emitted twice: first when discovery is started, then when a service was discovered.

      (Z(:^

      S 1 Reply Last reply 8 Dec 2019, 14:37
      2
      • S sierdzio
        8 Dec 2019, 09:15

        @SpaceToon said in Bluetooth Low Energy Scanner: Discover Service Details:

        But as I can see, the slot is only called once in the code, when the state changes

        That method is a slot. It is called every time QLowEnergyService::stateChanged() signal is emitted. In this case, visibly, it is emitted twice: first when discovery is started, then when a service was discovered.

        S Offline
        S Offline
        SpaceToon
        wrote on 8 Dec 2019, 14:37 last edited by
        #3

        @sierdzio said in Bluetooth Low Energy Scanner: Discover Service Details:

        @SpaceToon said in Bluetooth Low Energy Scanner: Discover Service Details:

        But as I can see, the slot is only called once in the code, when the state changes

        That method is a slot. It is called every time QLowEnergyService::stateChanged() signal is emitted. In this case, visibly, it is emitted twice: first when discovery is started, then when a service was discovered.

        Hey, thank you for your response. That makes sense. The problem is, that in my code, the method is only called once so that means, that the state "ServiceDiscovered" is not reached at all. Do you have any clue why? This is my code:

        void Scanner::discoveryFinished(){
            qDebug() << "\nService Discovery finished. Following Services found:\n";
            QList<QBluetoothUuid> serviceList = controller->services();
        
            QLowEnergyService *uartService = controller->createServiceObject(adafruitServiceUuid);
            connect(uartService, &QLowEnergyService::stateChanged, this, &Scanner::printChars);
            uartService->discoverDetails();
        }
        
        
        
        void Scanner::printChars(QLowEnergyService::ServiceState newState){
        
            auto service = qobject_cast<QLowEnergyService *>(sender());
        
            const QList<QLowEnergyCharacteristic> chars = service->characteristics();
            qDebug()<< chars.size();
            for (const QLowEnergyCharacteristic &ch : chars) {
                qDebug() << &ch;
            }
        }
        

        My Slot printChars is only called once so the chars.size() gives me 0. But Why the state is not changing to ServiceDiscovered so that I can print the characteristics?

        1 Reply Last reply
        0
        • S Offline
          S Offline
          sierdzio
          Moderators
          wrote on 8 Dec 2019, 19:56 last edited by
          #4

          It's possible that your service has already discovered all the details, and it is not searching anymore. https://doc.qt.io/qt-5/qlowenergyservice.html#ServiceState-enum

          What is the returned state at this point?

          (Z(:^

          S 1 Reply Last reply 9 Dec 2019, 10:53
          0
          • S sierdzio
            8 Dec 2019, 19:56

            It's possible that your service has already discovered all the details, and it is not searching anymore. https://doc.qt.io/qt-5/qlowenergyservice.html#ServiceState-enum

            What is the returned state at this point?

            S Offline
            S Offline
            SpaceToon
            wrote on 9 Dec 2019, 10:53 last edited by
            #5

            @sierdzio said in Bluetooth Low Energy Scanner: Discover Service Details:

            It's possible that your service has already discovered all the details, and it is not searching anymore. https://doc.qt.io/qt-5/qlowenergyservice.html#ServiceState-enum

            What is the returned state at this point?

            It is "DiscoveringServices" - so it is not done discovering the details but I do not know why.
            When I run the Scanner example and chose my BLE device, the characteristics are shown normally. But when I execute my own written code, the state "QLowEnergyService::ServiceDiscovered" is not reached, so I think the problem is not my BLE device but something in my code.

            1 Reply Last reply
            0
            • S Offline
              S Offline
              sierdzio
              Moderators
              wrote on 9 Dec 2019, 12:03 last edited by
              #6

              No idea.

              But notice that the example code specifically does not call characteristics() method when state is DiscoveringServices. Perhaps try doing the same?

              (Z(:^

              S 1 Reply Last reply 9 Dec 2019, 12:40
              0
              • S sierdzio
                9 Dec 2019, 12:03

                No idea.

                But notice that the example code specifically does not call characteristics() method when state is DiscoveringServices. Perhaps try doing the same?

                S Offline
                S Offline
                SpaceToon
                wrote on 9 Dec 2019, 12:40 last edited by
                #7

                @sierdzio said in Bluetooth Low Energy Scanner: Discover Service Details:

                No idea.

                But notice that the example code specifically does not call characteristics() method when state is DiscoveringServices. Perhaps try doing the same?

                I made a switch statement in my slot so if state is Discovering i should only print the state and if the state is "ServiceDiscovered" then it shoul call characteristics(). But as I mentioned, the state "ServiceDiscovered" is never reached.

                1 Reply Last reply
                0
                • A Offline
                  A Offline
                  abeat
                  wrote on 2 Dec 2020, 17:27 last edited by
                  #8

                  I am facing the same issue but only on certain windows and linux machines. Under Mac it never happens and under newer Linux machines it neither happens.

                  1 Reply Last reply
                  0
                  • O Offline
                    O Offline
                    ovadi
                    wrote on 18 Feb 2021, 12:53 last edited by
                    #9

                    i had same error in my project.
                    this page helped me -> https://forum.qt.io/topic/117241/why-qlowenergyservice-unknownerror/2

                    i have changed my code from

                    connect(controller, &QLowEnergyController::discoveryFinished,
                                    this, &Device::serviceScanDone);
                    

                    to

                    connect(controller, &QLowEnergyController::discoveryFinished,
                                    this, &Device::serviceScanDone,Qt::QueuedConnection);
                    

                    and problem disappeared.

                    1 Reply Last reply
                    1

                    • Login

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