Anatoly Kubasov
Anatoly Kubasov

Reputation: 11

Qt: RFCOMM BluetoothSocket Connection Problems after switching Pages in QML

I'm developing an cross plattform Application in Qt Creator, which has the exercise to control a device via Classic Bluetooth. I have a communication protocol. FIRST: I can connect to device and write Data to it with BluetoothSocket. If I put the startMotor() function into the socketConnected SLOT after beepBuzzor() command then it works fine and I get state() connected.

My problem is if I switch the page in my Application on Android and click on the "start motor" button, I get the state() unconnected, but I am still connected to the device because the LED on the device shows connected. My app does not crash. I think the problem is in the line with socket->connectToService(...), but I'm unsure what to change. The beepBuzzor command works fine, startMotor command too. But if I call the function after successfully connectToService() it does not work because the state is unconnected.

    BluetoothManager::BluetoothManager(QObject *parent) : QObject(parent)
    {
        socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol);
    }

    void BluetoothManager::startDiscovery()
    {

        // Check if Bluetooth is available on this device
        if (localDevice.isValid()) {

            qDebug() << "Bluetooth is available on this device";

            //Turn BT on
            localDevice.powerOn();

            // Make it visible to others
            localDevice.setHostMode(QBluetoothLocalDevice::HostDiscoverable);

            //Read local device name & address
            qDebug() << "Local Device:" << localDevice.name() << "(" << "Address:" << localDevice.address() << ")";

            // Create a discovery agent and connect to its signals

            discoveryAgent = new QBluetoothDeviceDiscoveryAgent(this);

            connect(discoveryAgent, SIGNAL(finished()), this, SLOT(deviceDiscoverFinished()));

            // Start a discovery
            // Trick: da es kein DiscoveryTimer für Classic gibt, suchen wir nach LE devices, da BT121 BLE unterstützt.
            // Die Verbindung erfolgt jedoch über RFCOMM sobald man sich mit dem Gerät verbindet.
            discoveryAgent->setLowEnergyDiscoveryTimeout(5000);
            discoveryAgent->start(QBluetoothDeviceDiscoveryAgent::LowEnergyMethod);


            qDebug() << "Device discover started";
        }
        else
        {
            qDebug() << "Bluetooth is not available on this device";
        }

    }
    //SLOT for the finish of device Discovery
    void BluetoothManager::deviceDiscoverFinished()
    {
        qDebug() << "Device discover finished";

        listOfDevices = discoveryAgent->discoveredDevices();

        qDebug() << "Found new devices:";

        for (int i = 0; i < listOfDevices.size(); i++)
        {
            //Q_OS_IOS / MAC do not need here cuz the run is on android device, delete later
            //We do not find galileo device on MacBook
            #if defined (Q_OS_IOS) || defined (Q_OS_MAC)
            // On MacOS and iOS we get no access to device address,
            // only unique UUIDs generated by Core Bluetooth.

            qDebug() << "getting address from deviceUuid()" << listOfDevices.at(i).name().trimmed()
            << " ( " << listOfDevices.at(i).deviceUuid().toString().trimmed() << " ) ";
            setDevice(listOfDevices.at(i).name().trimmed() + " (" + listOfDevices.at(i).deviceUuid().toString().trimmed() + ")");


            #else

            qDebug() << listOfDevices.at(i).name().trimmed()
                     << " ("
                     << listOfDevices.at(i).address().toString().trimmed()
                     << ")";
            setDevice(listOfDevices.at(i).name().trimmed() + " (" + listOfDevices.at(i).address().toString().trimmed() + ")");

            #endif
        }


    }

    /**
    *   In GUI (QML) user select a device with index i.
    *   Create a new socket, using Rfcomm protocol to communicate 
    */

    void BluetoothManager::deviceSelected(int i)
    {
        selectedDevice = listOfDevices.at(i);

        #if defined (Q_OS_IOS) || defined (Q_OS_MAC)
        qDebug() << "User select a device: " << selectedDevice.name() << " ("
                 << selectedDevice.deviceUuid().toString().trimmed() << ")";
    #else

        qDebug() << "User select a device: " << selectedDevice.name() << " ("
                 << selectedDevice.address().toString().trimmed() << ")";
    #endif



        if (localDevice.pairingStatus(selectedDevice.address())== QBluetoothLocalDevice::Paired)
            {
                qDebug() << "Pairing is allready done";
            }
            else
            {
                qDebug() << "Not paired. Please do pairing first for communication with device!";
            }

        selecDevAdress = selectedDevice.address();
        connectToSvc();
        //Connect SIGNALS with SLOTS
        connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)), this, SLOT(socketError(QBluetoothSocket::SocketError)));
        connect(socket, SIGNAL(connected()), this, SLOT(socketConnected()));
        connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
        connect(socket, SIGNAL(readyRead()), this, SLOT(socketRead()));
        connect(socket, SIGNAL(stateChanged(QBluetoothSocket::SocketState)), this, SLOT(socketStateChanged()));
    }

    void BluetoothManager::connectToSvc()
    {
        qDebug() << "Create socket";

        //socket->connectToService(selecDevAdress, QBluetoothUuid(QString("00001101-0000-1000-8000-00805F9B34FB")), QIODevice::ReadWrite);
        //static const QString serviceUuid(QStringLiteral("00001101-0000-1000-8000-00805F9B34FB"));
        socket->connectToService(selectedDevice.address(), QBluetoothUuid(QString("00001101-0000-1000-8000-00805F9B34FB")), QIODevice::ReadWrite);

        //Also works with this line instead of the two above (with declaration of serviceUuid)
        //socket->connectToService(QBluetoothAddress(selectedDevice.address()),QBluetoothUuid(QBluetoothUuid::SerialPort));
        socket->open(QIODevice::ReadWrite);

        socket->openMode();

    }

    //SLOT wenn Socket verbunden ist

    void BluetoothManager::socketConnected()
    {

        //qDebug() << ("Connected to: "+socket->peerAddress().toString() +":"+socket->peerPort());
        qDebug() << ("Connected to: "+socket->peerAddress().toString());
        qDebug() << "Socket connected";
        qDebug() << "Local: "
                 << socket->localName()
                 << socket->localAddress().toString()
                 << socket->localPort();
        qDebug() << "Peer: "
                 << socket->peerName()
                 << socket->peerAddress().toString()
                 << socket->peerPort();

        //Do "beep" sound commando after succesfull connection to Galileo device
        beepBuzzor();

    }

    /**
    *   Socket disconnected.
    *   Delete socket, free the memory.
    */

    //SLOT für Verbindungsabbruch von Socket
    void BluetoothManager::socketDisconnected()
    {
        qDebug() << "Socket disconnected";
        socket->deleteLater();
    }


    void BluetoothManager::socketError(QBluetoothSocket::SocketError error)
    {
        qDebug() << "Socket error: " << error;
    }

    void BluetoothManager::socketStateChanged()
    {
        int socketState = socket->state();

        if(socketState == QAbstractSocket::UnconnectedState)
        {
            qDebug() << "unconnected";
        }
        else if(socketState == QAbstractSocket::HostLookupState)
        {
            qDebug() << "host lookup";
        }
        else if(socketState == QAbstractSocket::ConnectingState )
        {
            qDebug() << "connecting";
        }
        else if(socketState == QAbstractSocket::ConnectedState)
        {
            qDebug() << "connected";
        }
        else if(socketState == QAbstractSocket::BoundState)
        {
            qDebug() << "bound";
        }
        else if(socketState == QAbstractSocket::ClosingState)
        {
            qDebug() << "closing";
        }
        else if(socketState == QAbstractSocket::ListeningState)
        {
            qDebug() << "listening";
        }
    }

    //   SLOT when data ready on bluetooth socket
    void BluetoothManager::socketRead()
    {
        qDebug() << "socketRead()";
        QByteArray recievedData = socket->readAll();

        emit dataRecieved(recievedData);
    }

    /**
    *   Get a string with device info
    */

    const QString &BluetoothManager::device() const
    {
        return deviceInfo;
    }


    void BluetoothManager::setDevice(const QString &newDevice)
    {
        if (newDevice != deviceInfo) {

            deviceInfo = newDevice;
            emit deviceChanged();
        }
    }

    void BluetoothManager::beepBuzzor()
    {
        QByteArray beep;
        beep.append(QByteArray::fromRawData("\x04\x00\x09\xD0\x07\x32\x00", 7));
        command(beep);
    }

    void BluetoothManager::startMotor()
    {
        qDebug() << "startMotor slot";
        if(socket->state() == QBluetoothSocket::UnconnectedState){
            qDebug() << "Socket Unconnected";
        }
        else{
            qDebug() << "Socket Unonnected";
        }
        socketStateChanged();
        //command(start);
    }

void BluetoothManager::command(QByteArray &cmdBuf)
{
    socket->write(cmdBuf);
}

Upvotes: 1

Views: 1113

Answers (1)

DJO
DJO

Reputation: 1

i do understand your probleme and i did had that probleme when i wanted to create a bluetooth SSP application so the source of the probleme is that when switching between the classes you did create an instance of the class that handel the bluetooth connection so the socket that you are using is not the same socket that is connected to the device , to solve this you need to pass the same parameter "socket" to the class that calls the send function using the same socket.i hope this solve your probleme.

Upvotes: 0

Related Questions