如何将代码从QSerialPort迁移到QBluetoothSocket

时间:2014-11-20 15:42:30

标签: android c++ qt sockets bluetooth

我需要一段非常简单的代码,将蓝牙设备(自制)连接为虚拟COM(串行端口配置文件),将一些数据写入其中,然后读取回复。写入的数据打开设备上的LED(这样可以很容易地查看设备是否实际接收到的数据)

我使用Qt 5.3.1与QSerialPort一起使用,在Windows7上使用Visual Studio 2010编译。它适用于我的笔记本电脑,我只需要指定端口名称COMi。一旦我的设备配对,Windows的蓝牙属性对话框会告诉我应该使用哪个虚拟端口来连接设备。

我想将此Qt代码移植到Android。显然,Android系统不允许我直接打开COM端口QSerialPort/dev/tty*访问被拒绝)。所以我需要将代码移植到使用QBluetoothSocket而不是QSerialPort。

不幸的是,我无法使这个基于QBluetoothSocket的代码工作......

以下是QSerialPort代码:

#include <QApplication>
#include <QThread>
#include <QMessageBox>
#include <QtSerialPort/QSerialPort>

#include <sstream>
#include <vector>

static std::vector<char> sReceived;
class readThread : public QThread
{
public:
    readThread( QSerialPort* port ) : m_port( port ), m_bContinue( true )
    {

    }

    void run()
    {
        while ( m_bContinue )
        {
            m_port->waitForReadyRead( 100 );

            QByteArray received = m_port->readAll();
            for ( size_t i = 0; i != received.size(); ++i )
            {
                sReceived.push_back( received.at(i) );
            }
        }
    }

    volatile bool m_bContinue;

private:
    QSerialPort* m_port;
};

int main( int argc, char* argv[] )
{
    QApplication app(argc, argv);

    int res = 1;
    if ( argc != 2 )
    {
        QMessageBox::critical( NULL, "Invalid argument", "Specify COM port name as first and unic parameter" );
    }
    else
    {
        QString portName = argv[1];

        QSerialPort port( portName );

        if ( port.open( QSerialPort::ReadWrite ) )
        {
            if ( port.setBaudRate( QSerialPort::Baud115200 ) &&
                 port.setFlowControl( QSerialPort::HardwareControl ) &&
                 port.setStopBits( QSerialPort::OneStop ) &&
                 port.setParity( QSerialPort::NoParity ) &&
                 port.setDataBits( QSerialPort::Data8 ) )
            {
                readThread thrd( &port );
                thrd.start();

                static const size_t requestMessageSize = 10;
                char request[requestMessageSize] = { 0x01, 0x00, 0x07, 0x01, 0x01, 0x00, 0x00, 0xBE, 0x0B, 0x00 };
                if ( port.write( request, requestMessageSize ) == requestMessageSize )
                {
                    port.waitForBytesWritten( 1000 );

                    QThread::sleep( 5 );

                    if ( !sReceived.empty() )
                    {
                        std::stringstream str;
                        str << "Received:" << std::hex;
                        for ( size_t i = 0; i != sReceived.size(); ++i )
                        {
                            str << " 0x" << static_cast<int>( sReceived[i] );
                        }
                        str << std::endl;
                        str << "Could open port, send and receive data" << std::endl;
                        QMessageBox::information( NULL, "OK", str.str().c_str() );
                        res = 0;
                    }
                    else
                    {
                        QMessageBox::critical( NULL, "Error", "Could open port, send data, but did not received any reply" );
                    }
                }
                else
                {
                    QMessageBox::critical( NULL, "Error", "Unable to send request to port" );
                }

                thrd.m_bContinue = false;
                thrd.wait();
            }
            else
            {
                QMessageBox::critical( NULL, "Error", "Unable to configure port" );
            }
            port.close();
        }
        else
        {
            QMessageBox::critical( NULL, "Unable to connect", QString("Could not open connection with %1").arg( portName ) );
        }
    }

    return res;
}

以下是基于QBluetooth的代码无效:

bthandler.h:

#pragma once

#include <QObject>
#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
#include <QtBluetooth/QBluetoothSocket>

class BTHandler : public QObject
{
    Q_OBJECT

public:
    BTHandler( QBluetoothDeviceDiscoveryAgent& agent );

public slots:
    void deviceDiscovered( const QBluetoothDeviceInfo& );
    void detectError( QBluetoothDeviceDiscoveryAgent::Error );
    void detectError( QBluetoothSocket::SocketError );

    QBluetoothDeviceInfo* getDevice() { return (m_foundDeviceFlag) ? &m_foundDevice : NULL; }

    QBluetoothSocket* createSocket();

private:
    volatile bool m_foundDeviceFlag;
    QBluetoothDeviceInfo m_foundDevice;
};

bthandler.cpp:

#include "bthandler.h"

#include <sstream>

#include <QtBluetooth/QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothSocket>
#include <QtBluetooth/QBluetoothUuid>

#include <QMessageBox>
#include <QThread>

BTHandler::BTHandler( QBluetoothDeviceDiscoveryAgent& agent ) : 
                         m_foundDeviceFlag( false )
{
    // Create a discovery agent and connect to its signals
    connect(&agent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)),
            this, SLOT(deviceDiscovered(QBluetoothDeviceInfo)));
    connect(&agent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)),
            this, SLOT(detectError(QBluetoothDeviceDiscoveryAgent::Error)));
}

void BTHandler::deviceDiscovered( const QBluetoothDeviceInfo& device )
{
    QBluetoothDeviceInfo::DataCompleteness complete = QBluetoothDeviceInfo::DataComplete;
    QBluetoothDeviceInfo::DataCompleteness incomplete = QBluetoothDeviceInfo::DataIncomplete;
    QList<QBluetoothUuid> services1 = device.serviceUuids();
    QList<QBluetoothUuid> services2 = device.serviceUuids(&complete);
    QList<QBluetoothUuid> services3 = device.serviceUuids(&incomplete);

    QMessageBox::information( NULL, "Found device", device.name() );

    if ( device.name() == "BLUESWEAT11" )
    {
        QMessageBox::information( NULL, "Info", "Found correct device" );
        m_foundDevice = QBluetoothDeviceInfo( device );
        m_foundDeviceFlag = true;
    }
}

void BTHandler::detectError( QBluetoothDeviceDiscoveryAgent::Error error )
{
    std::stringstream str;
    str << "An error occured during bluetooth lookup: " << (int) error;
    QMessageBox::critical( NULL, "Error", str.str().c_str() );
}

void BTHandler::detectError( QBluetoothSocket::SocketError error )
{
    std::stringstream str;
    str << "An error occured during socket use: " << (int) error;
    QMessageBox::critical( NULL, "Error", str.str().c_str() );
}

QBluetoothSocket* BTHandler::createSocket()
{
    QBluetoothSocket* socket = NULL;

    if ( m_foundDeviceFlag )
    {
        QBluetoothUuid uuid( QBluetoothUuid::Rfcomm );
        socket = new QBluetoothSocket( QBluetoothServiceInfo::RfcommProtocol );

        connect(socket, SIGNAL(error(QBluetoothSocket::SocketError)),
                this, SLOT(detectError(QBluetoothSocket::SocketError)));

        socket->connectToService( m_foundDevice.address(), uuid );

        if ( !socket->isOpen() )
        {
            QMessageBox::critical( NULL, "Error", "Unabel to open socket" );
            delete socket;
        }

        while ( socket->state() != QBluetoothSocket::ConnectedState )
        {
            QThread::sleep( 1 );
        }
    }

    return socket;
}

main.cpp中:

#include "bthandler.h"

#include <vector>
#include <sstream>

#include <QMessageBox>
#include <QApplication>

#include <QtBluetooth/QBluetoothDeviceDiscoveryAgent>
#include <QtBluetooth/QBluetoothDeviceInfo>
#include <QtBluetooth/QBluetoothSocket>
#include <QtBluetooth/QBluetoothUuid>

#include <QThread>

static std::vector<char> sReceived;
class readThread : public QThread
{
public:
    readThread( QBluetoothSocket* port ) : m_port( port ), m_bContinue( true )
    {

    }

    void run()
    {
        while ( m_bContinue )
        {
            m_port->waitForReadyRead( 100 );

            QByteArray received = m_port->readAll();
            for ( size_t i = 0; i != received.size(); ++i )
            {
                sReceived.push_back( received.at(i) );
            }
        }
    }

    volatile bool m_bContinue;

private:
    QBluetoothSocket* m_port;
};

int main( int argc, char* argv[] )
{
    QApplication app(argc, argv);

    QBluetoothDeviceDiscoveryAgent discoveryAgent;
    BTHandler handler( discoveryAgent );

    discoveryAgent.start();
    while ( handler.getDevice() == NULL )
    {
        QThread::sleep( 1 );
        app.processEvents();
    }
    discoveryAgent.stop();

    int res = 1;

    QBluetoothSocket* socket = handler.createSocket();

    if ( socket )
    {
        readThread thrd( socket );
        thrd.start();

        static const size_t requestMessageSize = 10;
        char request[requestMessageSize] = { 0x01, 0x00, 0x07, 0x01, 0x01, 0x00, 0x00, 0xBE, 0x0B, 0x00 };
        if ( socket->write( request, requestMessageSize ) == requestMessageSize )
        {
            socket->waitForBytesWritten( 1000 );

            QThread::sleep( 5 );

            if ( !sReceived.empty() )
            {
                std::stringstream str;
                str << "Received:" << std::hex;
                for ( size_t i = 0; i != sReceived.size(); ++i )
                {
                    str << " 0x" << static_cast<int>( sReceived[i] );
                }
                str << std::endl;
                str << "Could open port, send and receive data" << std::endl;
                QMessageBox::information( NULL, "OK", str.str().c_str() );
                res = 0;
            }
            else
            {
                QMessageBox::critical( NULL, "Error", "Could open port, send data, but did not received any reply" );
            }
        }
        else
        {
            QMessageBox::critical( NULL, "Error", "Unable to send request to port" );
        }

        thrd.m_bContinue = false;
        thrd.wait();

        socket->close();
        delete socket;
    }
    else
    {
        QMessageBox::critical( NULL, "Unable to connect", "Could not open bluetooth connection with device" );
    }

    return res;
}

在此版本的代码中,在等待建立连接(while ( socket->state() != QBluetoothSocket::ConnectedState ))时,QtCreator日志会报告以下错误:

W/BluetoothAdapter( 5866): getBluetoothService() called with no BluetoothManagerCallback
D/BluetoothSocket( 5866): connect(), SocketState: INIT, mPfd: {ParcelFileDescriptor: FileDescriptor[65]}
W/System.err( 5866): java.io.IOException: read failed, socket might closed or timeout, read ret: -1
W/System.err( 5866):    at android.bluetooth.BluetoothSocket.readAll(BluetoothSocket.java:505)
W/System.err( 5866):    at android.bluetooth.BluetoothSocket.readInt(BluetoothSocket.java:516)
W/System.err( 5866):    at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:320)
W/System.err( 5866):    at dalvik.system.NativeStart.run(Native Method)

2 个答案:

答案 0 :(得分:0)

你是否确定你有一个连接,所有的握手都是在你调用waitForReadyRead时完成的?

USB /蓝牙通常需要比串行更多的等待。

答案 1 :(得分:0)

在网上再次搜索后,我发现这个Qtbug报告了同样的问题: https://bugreports.qt-project.org/browse/QTBUG-40172

我升级到Qt 5.3.2,代码很简单!!!

感谢Surt的帮助,不知道如果没有while ( socket->state() != QBluetoothSocket::ConnectedState )循环就行了。但可以肯定的是,它无法与Qt 5.3.1一起使用!