I need a very straightforward piece of code that connects a bluetooth device (home made) as a virtual COM (Serial Port Profile), writes some data to it and then reads the reply. The written data turns ON a LED on the device (which makes it easy to see if data sent are actually received by the device)
I have it working with QSerialPort
, using Qt 5.3.1, compiled with Visual Studio 2010 on Windows7. It works on my laptop, I just need to specify the port name COMi
. Once my device is paired, the Bluetooth properties dialog of Windows tells me which virtual port should be used to connect the device.
I want to port this Qt code to Android. Apparently, Android system won't let me open the COM port directly as a QSerialPort
(/dev/tty*
access is denied). So I need to port the code to use a QBluetoothSocket rather than a QSerialPort.
Unfortunately, I can't get this QBluetoothSocket based code to work...
Here is the QSerialPort
code working:
#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;
}
And here is the QBluetooth based code not working:
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;
}
In this version of the code, while waiting for connection to be established (while ( socket->state() != QBluetoothSocket::ConnectedState )
), QtCreator log reports the following error:
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)