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. QBluetoothSocket never connects

QBluetoothSocket never connects

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 2 Posters 750 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.
  • T Offline
    T Offline
    tjrob
    wrote on last edited by
    #1

    Background: I have a Raspberry Pi running a simple Bluetooth server using an L2CAP socket: it advertises nothing, just listens on L2CAP port 0x1001, accepts any connection, reads from the socket and prints the received data. It works just fine from a client on a second Raspberry Pi, and tests show it can achieve 100 kBytes/sec over the L2CAP socket (I need 15 kBytes/sec, well beyond RFcomm). Note the server RPI has already paired with the client RPI and with my laptop (used separately). Both RPi client and server use the Bluez library, no Qt -- this is just describing the environment, not where the trouble lies.

    The problem is on Mac OS X, for which Bluetooth development in Python is not currently possible and C++ is outrageously complex, except using Qt. My code mimics the Linux client, and tries to connect to the server. The server prints that it accepted the connection from my laptop, but the client's QBluetoothSocket never transitions from from ConnectingState to ConnectedState. I have used Qt extensively, but this is my first use of its Bluetooth module. Here's the (simplified) client code

            // QCoreApplication stuff omitted, exec() is called right after printing CC
            printf("AA\n");
            sock = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol,0);
            // ... connect all signals to callbacks that print their names + arguments
            printf("BB\n");
            QBluetoothAddress addr("B8:27:EB:71:F4:02"); // RPi Bluetooth addr
            sock->connectToService(addr, 0x1001);
            printf("CC\n");
            // QCoreApplication::exec() called here
            sleep(5);  // actually QTimer::singleShot()
            printf("DD\n");
            int n = sock->write("Test");
            printf("test: %d %s\n",n,qPrintable(sock->errorString()));
            // ... goes on to close the socket and closeup
    

    I thought that is all I need. It directly parallels the Linux client. Here's the result of running it on my Mac. The RPi server printed "accepted connection" right after CC (very early in the sleep).

    main begun
    AA
    BB
    stateChanged 2
    CC
    Enter event loop
    <RPi server prints "accepted connection [laptop address]">
    <5 second delay>
    DD
    error 19 Cannot write while not connected
    test: -1 Cannot write while not connected
    <10 second delay, after which CoreApplication::quit() is called>
    main ends
    stateChanged 6
    stateChanged 0
    disconnected
    <program exits>
    

    What am I missing?
    Why doesn't the QBluetoothSocket ever go to ConnectedState?

    Is it that QBluetoothSocket doesn't work in this mode and needs a QBluetoothServiceInfo, so I have to go to the hassle of advertising a service, and all the complexity that entails (hard-coding the RPi address is acceptable here, and much simpler).

    I can provide all the code, but thought this simplified code would be better to look at (no AttachFile on this forum).

    jsulmJ 1 Reply Last reply
    0
    • T tjrob

      Background: I have a Raspberry Pi running a simple Bluetooth server using an L2CAP socket: it advertises nothing, just listens on L2CAP port 0x1001, accepts any connection, reads from the socket and prints the received data. It works just fine from a client on a second Raspberry Pi, and tests show it can achieve 100 kBytes/sec over the L2CAP socket (I need 15 kBytes/sec, well beyond RFcomm). Note the server RPI has already paired with the client RPI and with my laptop (used separately). Both RPi client and server use the Bluez library, no Qt -- this is just describing the environment, not where the trouble lies.

      The problem is on Mac OS X, for which Bluetooth development in Python is not currently possible and C++ is outrageously complex, except using Qt. My code mimics the Linux client, and tries to connect to the server. The server prints that it accepted the connection from my laptop, but the client's QBluetoothSocket never transitions from from ConnectingState to ConnectedState. I have used Qt extensively, but this is my first use of its Bluetooth module. Here's the (simplified) client code

              // QCoreApplication stuff omitted, exec() is called right after printing CC
              printf("AA\n");
              sock = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol,0);
              // ... connect all signals to callbacks that print their names + arguments
              printf("BB\n");
              QBluetoothAddress addr("B8:27:EB:71:F4:02"); // RPi Bluetooth addr
              sock->connectToService(addr, 0x1001);
              printf("CC\n");
              // QCoreApplication::exec() called here
              sleep(5);  // actually QTimer::singleShot()
              printf("DD\n");
              int n = sock->write("Test");
              printf("test: %d %s\n",n,qPrintable(sock->errorString()));
              // ... goes on to close the socket and closeup
      

      I thought that is all I need. It directly parallels the Linux client. Here's the result of running it on my Mac. The RPi server printed "accepted connection" right after CC (very early in the sleep).

      main begun
      AA
      BB
      stateChanged 2
      CC
      Enter event loop
      <RPi server prints "accepted connection [laptop address]">
      <5 second delay>
      DD
      error 19 Cannot write while not connected
      test: -1 Cannot write while not connected
      <10 second delay, after which CoreApplication::quit() is called>
      main ends
      stateChanged 6
      stateChanged 0
      disconnected
      <program exits>
      

      What am I missing?
      Why doesn't the QBluetoothSocket ever go to ConnectedState?

      Is it that QBluetoothSocket doesn't work in this mode and needs a QBluetoothServiceInfo, so I have to go to the hassle of advertising a service, and all the complexity that entails (hard-coding the RPi address is acceptable here, and much simpler).

      I can provide all the code, but thought this simplified code would be better to look at (no AttachFile on this forum).

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @tjrob said in QBluetoothSocket never connects:

      sock->connectToService(addr, 0x1001);
      printf("CC\n");
      // QCoreApplication::exec() called here

      This is not how it should be done: QCoreApplication::exec() is a blocking call! The code after exec() will be executed when your app is terminating.
      Connect https://doc.qt.io/qt-5/qbluetoothsocket.html#connected signal to a slot and check whether it is called.

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      1 Reply Last reply
      2
      • T Offline
        T Offline
        tjrob
        wrote on last edited by
        #3

        I used QCoreApplication correctly, but as I said, I collapsed code into a single sequence so the structure and problem are more obvious. So here are T.h, T.cc, and T.pro: build via "qmake && make". Note that T::connected() is never called, but the RPi server printed "accepted connection [laptop address]". The problem is clearly on the Mac where this Qt client program is run.

        BTW I am running the RPi server in another Terminal window via a Bluetooth serial connection from the Mac via "screen /dev/cu.rpi7-SerialPort 115200" -- so I know they are paired and connectable.

        The RPi code follows.

        //      T.h
          
        #include <QObject>
        #include <QBluetoothSocket>
        
        class T : public QObject {
                Q_OBJECT
                QBluetoothSocket *sock;
        public:
                T();
                ~T() { if(sock != 0) sock->close(); sock = 0; }
        public slots:
                void connected();
                void disconnected();
                void error(QBluetoothSocket::SocketError error);
                void stateChanged(QBluetoothSocket::SocketState state);
                void test();
        };
        
        //      T.cc - Qt Bluetooth ?
        
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        
        #include <QCoreApplication>
        #include <QTimer>
        
        #include "T.h"
        
        T::T() : sock(0)
        {
                printf("AA\n");
                sock = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol,0);
                connect(sock,SIGNAL(connected()),this,SLOT(connected()));
                connect(sock,SIGNAL(disconnected()),this,SLOT(disconnected()));
                connect(sock,SIGNAL(error(QBluetoothSocket::SocketError)),
                        this,SLOT(error(QBluetoothSocket::SocketError)));
                connect(sock,SIGNAL(stateChanged(QBluetoothSocket::SocketState)),
                        this,SLOT(stateChanged(QBluetoothSocket::SocketState)));
                printf("BB\n");
                QBluetoothAddress addr("B8:27:EB:71:F4:02");
                sock->connectToService(addr,0x1001);
                printf("CC\n");
        }
        
        void T::connected()
        {
                printf("connected\n");
        }
        
        void T::disconnected()
        {
                printf("disconnected\n");
        }
        
        void T::error(QBluetoothSocket::SocketError error)
        {
                printf("error %d %s\n",error,qPrintable(sock->errorString()));
        }
        
        void T::stateChanged(QBluetoothSocket::SocketState state)
        {
                printf("stateChanged %d\n",state);
        }
        
        void T::test()
        {
                printf("DD\n");
                int n = sock->write("Test");
                printf("test: %d %s\n",n,qPrintable(sock->errorString()));
        }
        
        int main(int argc, char *argv[])
        {
                QCoreApplication app(argc,argv);
        
                printf("main begun\n");
                T t;
        
                QTimer::singleShot(5000, &t, SLOT(test()));
                QTimer::singleShot(12000, &app, SLOT(quit()));
        
                printf("Enter event loop\n");
                app.exec();
        
                printf("main ends\n");
                return 0;
        }
        
        #    T.pro
        TARGET = t
        INCLUDEPATH += .
        QT += bluetooth
        CONFIG += console
        
        HEADERS += *.h
        SOURCES += *.cc
        

        For completeness, here is the server code running on the Raspberry Pi (no Qt). The server needs to be re-run after each connection; it never gets past the call to read(). The Mac and the RPi should already be paired.

        // server.cc
        // For Raspberry Pi: sudo apt-get bluez libbluetooth-dev
        // g++ -o server server.cc -lbluetooth
        
        #include <stdio.h>
        #include <unistd.h>
        #include <stdlib.h>
        #include <string.h>
        #include <sys/socket.h>
        #include <bluetooth/bluetooth.h>
        #include <bluetooth/l2cap.h>
        
        bdaddr_t Any = { 0,0,0,0,0,0 };
        
        const int MTU=672;
        
        int main(int argc, char **argv)
        {
            struct sockaddr_l2 loc_addr = { 0 }, rem_addr = { 0 };
            char buf[1024] = { 0 };
            int s, client, bytes_read;
            socklen_t opt = sizeof(rem_addr);
        
            // allocate socket
            s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
        
            // bind socket to port 0x1001 of the first available
            // bluetooth adapter
            loc_addr.l2_family = AF_BLUETOOTH;
            loc_addr.l2_bdaddr = Any;
            //loc_addr.l2_bdaddr = *BDADDR_ANY;
            loc_addr.l2_psm = htobs(0x1001);
        
            bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
        
            // put socket into listening mode
            listen(s, 1);
        
            // accept one connection
            client = accept(s, (struct sockaddr *)&rem_addr, &opt);
        
            ba2str( &rem_addr.l2_bdaddr, buf );
            fprintf(stderr, "socket=%d accepted connection from %s\n", client, buf);
        
            // read data from the client
            bytes_read = read(client, buf, sizeof(buf));
            if( bytes_read > 0 ) {
                buf[bytes_read] = '\0';
                printf("received [%s]\n", buf);
            } else {
                printf("read error\n");
            }
        
            // write lots of data to meausre data transfer rate
            char packet[MTU];
            for(int i=0; i<MTU; ++i)
                packet[i] = 'A';
            for(int i=0; i<10000; ++i) {
                write(client, packet, MTU);
            }
        
            // close connection
            close(client);
            close(s);
        }
        

        Here is Python3 client code for a second Raspberry Pi that successfully connects to the server and measures the data transfer rate over the L2CAP socket.

        import time
        import socket
        
        serverMACAddress = 'B8:27:EB:71:F4:02'
        port = 0x1001
        s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_L2CAP)
        s.connect((serverMACAddress,port))
        
        time.sleep(5)
        print("Send Config line")
        s.send(b'Config line')
        
        # measure data transfer rate
        start = 0.0
        now = start
        update = start
        try:
            data = ""
            while 1:
                text = s.recv(1024).decode('ascii')
                if start == 0.0:
                        start = time.time()
                        update = start
                data += text
                now = time.time()
                if now-update > 10.0:
                        print(len(data)/(now-update))
                        update = now
                        data = ""
        except:
            pass
        
        s.close()
        

        Bluetooth development on Linux is much easier, because the libraries are complete. The Mac is MUCH more difficult.

        jsulmJ 1 Reply Last reply
        0
        • T tjrob

          I used QCoreApplication correctly, but as I said, I collapsed code into a single sequence so the structure and problem are more obvious. So here are T.h, T.cc, and T.pro: build via "qmake && make". Note that T::connected() is never called, but the RPi server printed "accepted connection [laptop address]". The problem is clearly on the Mac where this Qt client program is run.

          BTW I am running the RPi server in another Terminal window via a Bluetooth serial connection from the Mac via "screen /dev/cu.rpi7-SerialPort 115200" -- so I know they are paired and connectable.

          The RPi code follows.

          //      T.h
            
          #include <QObject>
          #include <QBluetoothSocket>
          
          class T : public QObject {
                  Q_OBJECT
                  QBluetoothSocket *sock;
          public:
                  T();
                  ~T() { if(sock != 0) sock->close(); sock = 0; }
          public slots:
                  void connected();
                  void disconnected();
                  void error(QBluetoothSocket::SocketError error);
                  void stateChanged(QBluetoothSocket::SocketState state);
                  void test();
          };
          
          //      T.cc - Qt Bluetooth ?
          
          #include <stdio.h>
          #include <stdlib.h>
          #include <unistd.h>
          
          #include <QCoreApplication>
          #include <QTimer>
          
          #include "T.h"
          
          T::T() : sock(0)
          {
                  printf("AA\n");
                  sock = new QBluetoothSocket(QBluetoothServiceInfo::L2capProtocol,0);
                  connect(sock,SIGNAL(connected()),this,SLOT(connected()));
                  connect(sock,SIGNAL(disconnected()),this,SLOT(disconnected()));
                  connect(sock,SIGNAL(error(QBluetoothSocket::SocketError)),
                          this,SLOT(error(QBluetoothSocket::SocketError)));
                  connect(sock,SIGNAL(stateChanged(QBluetoothSocket::SocketState)),
                          this,SLOT(stateChanged(QBluetoothSocket::SocketState)));
                  printf("BB\n");
                  QBluetoothAddress addr("B8:27:EB:71:F4:02");
                  sock->connectToService(addr,0x1001);
                  printf("CC\n");
          }
          
          void T::connected()
          {
                  printf("connected\n");
          }
          
          void T::disconnected()
          {
                  printf("disconnected\n");
          }
          
          void T::error(QBluetoothSocket::SocketError error)
          {
                  printf("error %d %s\n",error,qPrintable(sock->errorString()));
          }
          
          void T::stateChanged(QBluetoothSocket::SocketState state)
          {
                  printf("stateChanged %d\n",state);
          }
          
          void T::test()
          {
                  printf("DD\n");
                  int n = sock->write("Test");
                  printf("test: %d %s\n",n,qPrintable(sock->errorString()));
          }
          
          int main(int argc, char *argv[])
          {
                  QCoreApplication app(argc,argv);
          
                  printf("main begun\n");
                  T t;
          
                  QTimer::singleShot(5000, &t, SLOT(test()));
                  QTimer::singleShot(12000, &app, SLOT(quit()));
          
                  printf("Enter event loop\n");
                  app.exec();
          
                  printf("main ends\n");
                  return 0;
          }
          
          #    T.pro
          TARGET = t
          INCLUDEPATH += .
          QT += bluetooth
          CONFIG += console
          
          HEADERS += *.h
          SOURCES += *.cc
          

          For completeness, here is the server code running on the Raspberry Pi (no Qt). The server needs to be re-run after each connection; it never gets past the call to read(). The Mac and the RPi should already be paired.

          // server.cc
          // For Raspberry Pi: sudo apt-get bluez libbluetooth-dev
          // g++ -o server server.cc -lbluetooth
          
          #include <stdio.h>
          #include <unistd.h>
          #include <stdlib.h>
          #include <string.h>
          #include <sys/socket.h>
          #include <bluetooth/bluetooth.h>
          #include <bluetooth/l2cap.h>
          
          bdaddr_t Any = { 0,0,0,0,0,0 };
          
          const int MTU=672;
          
          int main(int argc, char **argv)
          {
              struct sockaddr_l2 loc_addr = { 0 }, rem_addr = { 0 };
              char buf[1024] = { 0 };
              int s, client, bytes_read;
              socklen_t opt = sizeof(rem_addr);
          
              // allocate socket
              s = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
          
              // bind socket to port 0x1001 of the first available
              // bluetooth adapter
              loc_addr.l2_family = AF_BLUETOOTH;
              loc_addr.l2_bdaddr = Any;
              //loc_addr.l2_bdaddr = *BDADDR_ANY;
              loc_addr.l2_psm = htobs(0x1001);
          
              bind(s, (struct sockaddr *)&loc_addr, sizeof(loc_addr));
          
              // put socket into listening mode
              listen(s, 1);
          
              // accept one connection
              client = accept(s, (struct sockaddr *)&rem_addr, &opt);
          
              ba2str( &rem_addr.l2_bdaddr, buf );
              fprintf(stderr, "socket=%d accepted connection from %s\n", client, buf);
          
              // read data from the client
              bytes_read = read(client, buf, sizeof(buf));
              if( bytes_read > 0 ) {
                  buf[bytes_read] = '\0';
                  printf("received [%s]\n", buf);
              } else {
                  printf("read error\n");
              }
          
              // write lots of data to meausre data transfer rate
              char packet[MTU];
              for(int i=0; i<MTU; ++i)
                  packet[i] = 'A';
              for(int i=0; i<10000; ++i) {
                  write(client, packet, MTU);
              }
          
              // close connection
              close(client);
              close(s);
          }
          

          Here is Python3 client code for a second Raspberry Pi that successfully connects to the server and measures the data transfer rate over the L2CAP socket.

          import time
          import socket
          
          serverMACAddress = 'B8:27:EB:71:F4:02'
          port = 0x1001
          s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_STREAM, socket.BTPROTO_L2CAP)
          s.connect((serverMACAddress,port))
          
          time.sleep(5)
          print("Send Config line")
          s.send(b'Config line')
          
          # measure data transfer rate
          start = 0.0
          now = start
          update = start
          try:
              data = ""
              while 1:
                  text = s.recv(1024).decode('ascii')
                  if start == 0.0:
                          start = time.time()
                          update = start
                  data += text
                  now = time.time()
                  if now-update > 10.0:
                          print(len(data)/(now-update))
                          update = now
                          data = ""
          except:
              pass
          
          s.close()
          

          Bluetooth development on Linux is much easier, because the libraries are complete. The Mac is MUCH more difficult.

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on last edited by
          #4

          @tjrob said in QBluetoothSocket never connects:

          I collapsed code into a single sequence so the structure and problem are more obvious

          But they weren't as the code you posted originally was simply wrong and how can anybody guess how your real code looks like? It is important to post the code you're really using.

          Is any other slot called? Especially error(...)?

          Just a note: why do you use printf() in C++?

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          1 Reply Last reply
          3
          • T Offline
            T Offline
            tjrob
            wrote on last edited by
            #5

            All slots do a printf; no other slot was called, including error. I use printf because it is often easier to format data than using cout. I guess I show my age, as I learned C in the 80s before there was C++.

            I built this same code on a Raspberry Pi 3B+, and it connects properly to the server (on the other RPi).

            main begun
            AA
            BB
            stateChanged 2
            CC
            Enter event loop
            stateChanged 3
            connected
            <... few seconds delay>
            DD
            test: 4 
            <... few seconds delay>
            main ends
            stateChanged 6
            stateChanged 0
            disconnected
            

            This is clearly a Mac issue in QBluetoothSocket. Very frustrating, as Apple uses Objective C for their Bluetooth library, making C++ usage obscure at best.

            1 Reply Last reply
            0

            • Login

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