These patches will add Bluetooth support for Windows platforms and will fix some potential issues.
Since we cannot use the QtBluetooth framework I needed to implement our custom Bluetooth device discovery agent. I decided to create a separated class and raise the same signals as QtBluetoothDeviceDiscoveryAgent class. I am not sure if this is the best idea or the most elegant one but it works. Claudiu
From 3d2e55d597aed27515650792f8bd77bf742f6576 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Wed, 12 Aug 2015 22:46:31 +0300 Subject: [PATCH 01/17] Cleanup Bluetooth local device and the discovery agent on exit Do some extra cleanup when the BtDeviceSelectionDialog is destroyed. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index 007fe94..ce759cc 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -61,6 +61,15 @@ BtDeviceSelectionDialog::BtDeviceSelectionDialog(QWidget *parent) : BtDeviceSelectionDialog::~BtDeviceSelectionDialog() { delete ui; + + // Clean the local device + delete localDevice; + + // Clean the device discovery agent + if (remoteDeviceDiscoveryAgent->isActive()) + remoteDeviceDiscoveryAgent->stop(); + + delete remoteDeviceDiscoveryAgent; } void BtDeviceSelectionDialog::on_changeDeviceState_clicked() -- 2.4.3
From aaa885948c1847bf766d3f0f6e546e4651100cca Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Wed, 12 Aug 2015 22:46:56 +0300 Subject: [PATCH 02/17] Check the last error when the BTH device scanning is finished If there is no error reported when the device scanning is finished then report to the dialog status that the scanning finished successfully. Otherwise report the last error. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index ce759cc..3af2501 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -124,7 +124,12 @@ void BtDeviceSelectionDialog::on_scan_clicked() void BtDeviceSelectionDialog::remoteDeviceScanFinished() { - ui->dialogStatus->setText("Scanning finished."); + if (remoteDeviceDiscoveryAgent->error() == QBluetoothDeviceDiscoveryAgent::NoError) { + ui->dialogStatus->setText("Scanning finished successfully."); + } else { + deviceDiscoveryError(remoteDeviceDiscoveryAgent->error()); + } + ui->scan->setEnabled(true); } -- 2.4.3
From f21c7c9f9a9a135faed50b66b57223f6165658b3 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Wed, 12 Aug 2015 22:48:54 +0300 Subject: [PATCH 03/17] Use only the BTH address to check if the device was already added There are moments when the name of the device cannot be obtained. Therefore we should use only the Bluetooth address to identify if the discovered device was already added to the list. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index 3af2501..7fd2c7c 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -146,7 +146,7 @@ void BtDeviceSelectionDialog::hostModeStateChanged(QBluetoothLocalDevice::HostMo void BtDeviceSelectionDialog::addRemoteDevice(const QBluetoothDeviceInfo &remoteDeviceInfo) { QString deviceLabel = QString("%1 (%2)").arg(remoteDeviceInfo.name()).arg(remoteDeviceInfo.address().toString()); - QList<QListWidgetItem *> itemsWithSameSignature = ui->discoveredDevicesList->findItems(deviceLabel, Qt::MatchStartsWith); + QList<QListWidgetItem *> itemsWithSameSignature = ui->discoveredDevicesList->findItems(remoteDeviceInfo.address().toString(), Qt::MatchContains); // Check if the remote device is already in the list if (itemsWithSameSignature.empty()) { -- 2.4.3
From d24aa8f4eeb6182750d79c78ff093a4043b3fad2 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Wed, 12 Aug 2015 22:56:46 +0300 Subject: [PATCH 04/17] Add set_timeout callback for Bluetooth custom serial implementation The new callback will be usefull when we will implement the support for Windows. The implementation of native serial set_timeout method uses a HANDLER on Windows and we will use the WinSock2 API which has a socket descriptor. Signed-off-by: Claudiu Olteanu <[email protected]> --- qtserialbluetooth.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/qtserialbluetooth.cpp b/qtserialbluetooth.cpp index 5a982d6..378f330 100644 --- a/qtserialbluetooth.cpp +++ b/qtserialbluetooth.cpp @@ -224,6 +224,15 @@ static int qt_serial_get_transmitted(serial_t *device) return device->socket->bytesToWrite(); } +static int qt_serial_set_timeout(serial_t *device, long timeout) +{ + if (device == NULL) + return DC_STATUS_INVALIDARGS; + + device->timeout = timeout; + + return DC_STATUS_SUCCESS; +} const dc_serial_operations_t qt_serial_ops = { .open = qt_serial_open, @@ -232,7 +241,8 @@ const dc_serial_operations_t qt_serial_ops = { .write = qt_serial_write, .flush = qt_serial_flush, .get_received = qt_serial_get_received, - .get_transmitted = qt_serial_get_transmitted + .get_transmitted = qt_serial_get_transmitted, + .set_timeout = qt_serial_set_timeout }; extern void dc_serial_init (dc_serial_t *serial, void *data, const dc_serial_operations_t *ops); -- 2.4.3
From 278ea6e20e7d92e7bdc84fb73eedac7bad829962 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 00:09:14 +0300 Subject: [PATCH 05/17] Add skeleton for Bluetooth custom serial implementation on Windows platforms Add a skeleton which will be used to develop the Bluetooth custom serial implementation for Windows platforms. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 89 ++++++++++++++++++++++++++++++++++++++- qt-ui/btdeviceselectiondialog.h | 45 ++++++++++++++++++++ qtserialbluetooth.cpp | 72 ++++++++++++++++++++++++++++--- 3 files changed, 200 insertions(+), 6 deletions(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index 7fd2c7c..bf0842c 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -8,7 +8,6 @@ BtDeviceSelectionDialog::BtDeviceSelectionDialog(QWidget *parent) : QDialog(parent), - localDevice(new QBluetoothLocalDevice), ui(new Ui::BtDeviceSelectionDialog) { ui->setupUi(this); @@ -21,9 +20,16 @@ BtDeviceSelectionDialog::BtDeviceSelectionDialog(QWidget *parent) : // Disable the save button because there is no device selected ui->save->setEnabled(false); + // Add event for item selection connect(ui->discoveredDevicesList, SIGNAL(itemClicked(QListWidgetItem*)), this, SLOT(itemClicked(QListWidgetItem*))); +#if defined(Q_OS_WIN) + // TODO do the initialization +#else + // Initialize the local Bluetooth device + localDevice = new QBluetoothLocalDevice(); + // Populate the list with local bluetooth devices QList<QBluetoothHostInfo> localAvailableDevices = localDevice->allDevices(); int availableDevicesSize = localAvailableDevices.size(); @@ -56,14 +62,20 @@ BtDeviceSelectionDialog::BtDeviceSelectionDialog(QWidget *parent) : // Initialize the device discovery agent if (localDevice->isValid()) initializeDeviceDiscoveryAgent(); +#endif } BtDeviceSelectionDialog::~BtDeviceSelectionDialog() { delete ui; +#if defined(Q_OS_WIN) + // Terminate the use of Winsock 2 DLL + WSACleanup(); +#else // Clean the local device delete localDevice; +#endif // Clean the device discovery agent if (remoteDeviceDiscoveryAgent->isActive()) @@ -74,6 +86,9 @@ BtDeviceSelectionDialog::~BtDeviceSelectionDialog() void BtDeviceSelectionDialog::on_changeDeviceState_clicked() { +#if defined(Q_OS_WIN) + // TODO add implementation +#else if (localDevice->hostMode() == QBluetoothLocalDevice::HostPoweredOff) { ui->dialogStatus->setText("Trying to turn on the local Bluetooth device..."); localDevice->powerOn(); @@ -81,6 +96,7 @@ void BtDeviceSelectionDialog::on_changeDeviceState_clicked() ui->dialogStatus->setText("Trying to turn off the local Bluetooth device..."); localDevice->setHostMode(QBluetoothLocalDevice::HostPoweredOff); } +#endif } void BtDeviceSelectionDialog::on_save_clicked() @@ -135,16 +151,23 @@ void BtDeviceSelectionDialog::remoteDeviceScanFinished() void BtDeviceSelectionDialog::hostModeStateChanged(QBluetoothLocalDevice::HostMode mode) { +#if defined(Q_OS_WIN) + // TODO add implementation +#else bool on = !(mode == QBluetoothLocalDevice::HostPoweredOff); ui->dialogStatus->setText(QString("The local Bluetooth device was turned %1.") .arg(on? "ON" : "OFF")); ui->deviceState->setChecked(on); ui->scan->setEnabled(on); +#endif } void BtDeviceSelectionDialog::addRemoteDevice(const QBluetoothDeviceInfo &remoteDeviceInfo) { +#if defined(Q_OS_WIN) + // TODO add the remote device +#else QString deviceLabel = QString("%1 (%2)").arg(remoteDeviceInfo.name()).arg(remoteDeviceInfo.address().toString()); QList<QListWidgetItem *> itemsWithSameSignature = ui->discoveredDevicesList->findItems(remoteDeviceInfo.address().toString(), Qt::MatchContains); @@ -167,10 +190,14 @@ void BtDeviceSelectionDialog::addRemoteDevice(const QBluetoothDeviceInfo &remote ui->discoveredDevicesList->addItem(item); } +#endif } void BtDeviceSelectionDialog::itemClicked(QListWidgetItem *item) { +#if defined(Q_OS_WIN) + // TODO enable the save button and log information about the selected item +#else QBluetoothDeviceInfo remoteDeviceInfo = item->data(Qt::UserRole).value<QBluetoothDeviceInfo>(); QBluetoothLocalDevice::Pairing pairingStatus = localDevice->pairingStatus(remoteDeviceInfo.address()); @@ -183,10 +210,14 @@ void BtDeviceSelectionDialog::itemClicked(QListWidgetItem *item) .arg(remoteDeviceInfo.address().toString())); ui->save->setEnabled(true); } +#endif } void BtDeviceSelectionDialog::localDeviceChanged(int index) { +#if defined(Q_OS_WIN) + //TODO add implementation +#else QBluetoothAddress localDeviceSelectedAddress = ui->localSelectedDevice->itemData(index, Qt::UserRole).value<QBluetoothAddress>(); // Delete the old localDevice @@ -207,10 +238,14 @@ void BtDeviceSelectionDialog::localDeviceChanged(int index) // Initialize the device discovery agent if (localDevice->isValid()) initializeDeviceDiscoveryAgent(); +#endif } void BtDeviceSelectionDialog::displayPairingMenu(const QPoint &pos) { +#if defined(Q_OS_WIN) + // TODO add implementation +#else QMenu menu(this); QAction *pairAction = menu.addAction("Pair"); QAction *removePairAction = menu.addAction("Remove Pairing"); @@ -237,6 +272,7 @@ void BtDeviceSelectionDialog::displayPairingMenu(const QPoint &pos) .arg(currentRemoteDeviceInfo.address().toString())); localDevice->requestPairing(currentRemoteDeviceInfo.address(), QBluetoothLocalDevice::Unpaired); } +#endif } void BtDeviceSelectionDialog::pairingFinished(const QBluetoothAddress &address, QBluetoothLocalDevice::Pairing pairing) @@ -330,6 +366,9 @@ QString BtDeviceSelectionDialog::getSelectedDeviceName() void BtDeviceSelectionDialog::updateLocalDeviceInformation() { +#if defined(Q_OS_WIN) + // TODO add implementation +#else // Check if the selected Bluetooth device can be accessed if (!localDevice->isValid()) { QString na = QString("Not available"); @@ -369,10 +408,14 @@ void BtDeviceSelectionDialog::updateLocalDeviceInformation() connect(localDevice, SIGNAL(error(QBluetoothLocalDevice::Error)), this, SLOT(error(QBluetoothLocalDevice::Error))); +#endif } void BtDeviceSelectionDialog::initializeDeviceDiscoveryAgent() { +#if defined(Q_OS_WIN) + // TODO initialize the discovery agency +#else // Intialize the discovery agent remoteDeviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(localDevice->address()); @@ -392,4 +435,48 @@ void BtDeviceSelectionDialog::initializeDeviceDiscoveryAgent() this, SLOT(remoteDeviceScanFinished())); connect(remoteDeviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), this, SLOT(deviceDiscoveryError(QBluetoothDeviceDiscoveryAgent::Error))); +#endif +} + + +#if defined(Q_OS_WIN) +static QString +getLastErrorAsString() +{ + // TODO get the last error +} + +WinBluetoothDeviceDiscoveryAgent::WinBluetoothDeviceDiscoveryAgent(QObject *parent) : QThread(parent) +{ +} + +WinBluetoothDeviceDiscoveryAgent::~WinBluetoothDeviceDiscoveryAgent() +{ +} + +bool WinBluetoothDeviceDiscoveryAgent::isActive() const +{ + return running; +} + +QString WinBluetoothDeviceDiscoveryAgent::errorToString() const +{ + return lastErrorToString; +} + +QBluetoothDeviceDiscoveryAgent::Error WinBluetoothDeviceDiscoveryAgent::error() const +{ + return lastError; +} + +void WinBluetoothDeviceDiscoveryAgent::run() +{ + // TODO initialize the resources and start the device discovery +} + +void WinBluetoothDeviceDiscoveryAgent::stop() +{ + // Stop the inqury + stopped = true; } +#endif diff --git a/qt-ui/btdeviceselectiondialog.h b/qt-ui/btdeviceselectiondialog.h index b6c34e8..d6b09f7 100644 --- a/qt-ui/btdeviceselectiondialog.h +++ b/qt-ui/btdeviceselectiondialog.h @@ -8,14 +8,55 @@ #include <QtBluetooth/qbluetoothglobal.h> #include <QtBluetooth/QBluetoothDeviceDiscoveryAgent> +#if defined(Q_OS_WIN) + #include <QThread> + #include <winsock2.h> + #include <ws2bth.h> + + #define SUCCESS 0 + #define BTH_ADDR_STR_LEN 100 + + #undef ERROR // this is already declared in our headers + #undef IGNORE // this is already declared in our headers + #undef DC_VERSION // this is already declared in libdivecomputer header +#endif + #if QT_VERSION < 0x050500 Q_DECLARE_METATYPE(QBluetoothDeviceInfo) #endif +#if defined(Q_OS_WIN) +Q_DECLARE_METATYPE(QBluetoothDeviceDiscoveryAgent::Error) +#endif + namespace Ui { class BtDeviceSelectionDialog; } +#if defined(Q_OS_WIN) +class WinBluetoothDeviceDiscoveryAgent : public QThread { + Q_OBJECT +signals: + void deviceDiscovered(const QBluetoothDeviceInfo &info); + void error(QBluetoothDeviceDiscoveryAgent::Error error); + +public: + WinBluetoothDeviceDiscoveryAgent(QObject *parent); + ~WinBluetoothDeviceDiscoveryAgent(); + bool isActive() const; + QString errorToString() const; + QBluetoothDeviceDiscoveryAgent::Error error() const; + virtual void run(); + virtual void stop(); + +private: + bool running; + bool stopped; + QString lastErrorToString; + QBluetoothDeviceDiscoveryAgent::Error lastError; +}; +#endif + class BtDeviceSelectionDialog : public QDialog { Q_OBJECT @@ -42,8 +83,12 @@ private slots: private: Ui::BtDeviceSelectionDialog *ui; +#if defined(Q_OS_WIN) + WinBluetoothDeviceDiscoveryAgent *remoteDeviceDiscoveryAgent; +#else QBluetoothLocalDevice *localDevice; QBluetoothDeviceDiscoveryAgent *remoteDeviceDiscoveryAgent; +#endif QSharedPointer<QBluetoothDeviceInfo> selectedRemoteDeviceInfo; void updateLocalDeviceInformation(); diff --git a/qtserialbluetooth.cpp b/qtserialbluetooth.cpp index 378f330..37ea225 100644 --- a/qtserialbluetooth.cpp +++ b/qtserialbluetooth.cpp @@ -10,6 +10,12 @@ #if defined(SSRF_CUSTOM_SERIAL) +#if defined(Q_OS_WIN) + #include <winsock2.h> + #include <windows.h> + #include <ws2bth.h> +#endif + #include <libdivecomputer/custom_serial.h> extern "C" { @@ -19,7 +25,11 @@ typedef struct serial_t { /* * RFCOMM socket used for Bluetooth Serial communication. */ +#if defined(Q_OS_WIN) + SOCKET socket; +#else QBluetoothSocket *socket; +#endif long timeout; } serial_t; @@ -40,6 +50,9 @@ static int qt_serial_open(serial_t **out, dc_context_t *context, const char* dev // Default to blocking reads. serial_port->timeout = -1; +#if defined(Q_OS_WIN) + // TODO connect the device +#else // Create a RFCOMM socket serial_port->socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol); @@ -118,7 +131,7 @@ static int qt_serial_open(serial_t **out, dc_context_t *context, const char* dev return QBluetoothSocket::UnknownSocketError; } } - +#endif *out = serial_port; return DC_STATUS_SUCCESS; @@ -126,19 +139,36 @@ static int qt_serial_open(serial_t **out, dc_context_t *context, const char* dev static int qt_serial_close(serial_t *device) { - if (device == NULL || device->socket == NULL) + if (device == NULL) return DC_STATUS_SUCCESS; +#if defined(Q_OS_WIN) + // TODO do the cleanup +#else + if (device->socket == NULL) { + free(device); + return DC_STATUS_SUCCESS; + } + device->socket->close(); delete device->socket; free(device); +#endif return DC_STATUS_SUCCESS; } static int qt_serial_read(serial_t *device, void* data, unsigned int size) { +#if defined(Q_OS_WIN) + if (device == NULL) + return DC_STATUS_INVALIDARGS; + + // TODO read *size* bytes from the device + + return 0; +#else if (device == NULL || device->socket == NULL) return DC_STATUS_INVALIDARGS; @@ -167,10 +197,19 @@ static int qt_serial_read(serial_t *device, void* data, unsigned int size) } return nbytes; +#endif } static int qt_serial_write(serial_t *device, const void* data, unsigned int size) { +#if defined(Q_OS_WIN) + if (device == NULL) + return DC_STATUS_INVALIDARGS; + + // TODO write *size* bytes from data to the device + + return 0; +#else if (device == NULL || device->socket == NULL) return DC_STATUS_INVALIDARGS; @@ -196,32 +235,54 @@ static int qt_serial_write(serial_t *device, const void* data, unsigned int size } return nbytes; +#endif } static int qt_serial_flush(serial_t *device, int queue) { - if (device == NULL || device->socket == NULL) + if (device == NULL) return DC_STATUS_INVALIDARGS; - - //TODO: add implementation +#if !defined(Q_OS_WIN) + if (device->socket == NULL) + return DC_STATUS_INVALIDARGS; +#endif + // TODO: add implementation return DC_STATUS_SUCCESS; } static int qt_serial_get_received(serial_t *device) { +#if defined(Q_OS_WIN) + if (device == NULL) + return DC_STATUS_INVALIDARGS; + + // TODO use WSAIoctl to get the information + + return 0; +#else if (device == NULL || device->socket == NULL) return DC_STATUS_INVALIDARGS; return device->socket->bytesAvailable(); +#endif } static int qt_serial_get_transmitted(serial_t *device) { +#if defined(Q_OS_WIN) + if (device == NULL) + return DC_STATUS_INVALIDARGS; + + // TODO add implementation + + return 0; +#else if (device == NULL || device->socket == NULL) return DC_STATUS_INVALIDARGS; return device->socket->bytesToWrite(); +#endif } static int qt_serial_set_timeout(serial_t *device, long timeout) @@ -234,6 +295,7 @@ static int qt_serial_set_timeout(serial_t *device, long timeout) return DC_STATUS_SUCCESS; } + const dc_serial_operations_t qt_serial_ops = { .open = qt_serial_open, .close = qt_serial_close, -- 2.4.3
From 40288f74307d6920b2d9658b19149c36d0fa29e1 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 00:17:46 +0300 Subject: [PATCH 06/17] Add implementation for BTH custom serial open method on Windows platforms Implement the custom serial open method using the WinSocket2 API. First the device address is converted from text representation into a sockaddr structure. Then a connection is initiated to the device using device's Serial Port service. Signed-off-by: Claudiu Olteanu <[email protected]> --- qtserialbluetooth.cpp | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/qtserialbluetooth.cpp b/qtserialbluetooth.cpp index 37ea225..0edd3d4 100644 --- a/qtserialbluetooth.cpp +++ b/qtserialbluetooth.cpp @@ -51,7 +51,49 @@ static int qt_serial_open(serial_t **out, dc_context_t *context, const char* dev serial_port->timeout = -1; #if defined(Q_OS_WIN) - // TODO connect the device + // Create a RFCOMM socket + serial_port->socket = ::socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM); + + if (serial_port->socket == INVALID_SOCKET) + return DC_STATUS_IO; + + SOCKADDR_BTH socketBthAddress; + int socketBthAddressBth = sizeof (socketBthAddress); + char *address = strdup(devaddr); + + ZeroMemory(&socketBthAddress, socketBthAddressBth); + qDebug() << "Trying to connect to address " << devaddr; + + if (WSAStringToAddressA(address, + AF_BTH, + NULL, + (LPSOCKADDR) &socketBthAddress, + &socketBthAddressBth + ) != 0) { + qDebug() << "FAiled to convert the address " << address; + free(address); + + return DC_STATUS_IO; + } + + free(address); + + socketBthAddress.addressFamily = AF_BTH; + socketBthAddress.port = BT_PORT_ANY; + memset(&socketBthAddress.serviceClassId, 0, sizeof(socketBthAddress.serviceClassId)); + socketBthAddress.serviceClassId = SerialPortServiceClass_UUID; + + // Try to connect to the device + if (::connect(serial_port->socket, + (struct sockaddr *) &socketBthAddress, + socketBthAddressBth + ) != 0) { + qDebug() << "Failed to connect to device"; + + return DC_STATUS_NODEVICE; + } + + qDebug() << "Succesfully connected to device"; #else // Create a RFCOMM socket serial_port->socket = new QBluetoothSocket(QBluetoothServiceInfo::RfcommProtocol); -- 2.4.3
From b91b5df5e6329a5d0df64ea6a0d9b6501fd266cb Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 00:23:56 +0300 Subject: [PATCH 07/17] Add implementation for BTH custom serial close method on Windows Implement the close method used on Windows platforms for our custom serial implementation. Signed-off-by: Claudiu Olteanu <[email protected]> --- qtserialbluetooth.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/qtserialbluetooth.cpp b/qtserialbluetooth.cpp index 0edd3d4..20f2ecd 100644 --- a/qtserialbluetooth.cpp +++ b/qtserialbluetooth.cpp @@ -185,7 +185,9 @@ static int qt_serial_close(serial_t *device) return DC_STATUS_SUCCESS; #if defined(Q_OS_WIN) - // TODO do the cleanup + // Cleanup + closesocket(device->socket); + free(device); #else if (device->socket == NULL) { free(device); -- 2.4.3
From f57e439433f32540ac6ae731585db3ed32bd3329 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 00:25:29 +0300 Subject: [PATCH 08/17] Add implementation for BTH custom serial read method used on Windows Implement the read method used for our custom serial implementation on Windows platforms. Signed-off-by: Claudiu Olteanu <[email protected]> --- qtserialbluetooth.cpp | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/qtserialbluetooth.cpp b/qtserialbluetooth.cpp index 20f2ecd..9d1c14b 100644 --- a/qtserialbluetooth.cpp +++ b/qtserialbluetooth.cpp @@ -209,9 +209,22 @@ static int qt_serial_read(serial_t *device, void* data, unsigned int size) if (device == NULL) return DC_STATUS_INVALIDARGS; - // TODO read *size* bytes from the device + unsigned int nbytes = 0; + int rc; - return 0; + while (nbytes < size) { + rc = recv (device->socket, (char *) data + nbytes, size - nbytes, 0); + + if (rc < 0) { + return -1; // Error during recv call. + } else if (rc == 0) { + break; // EOF reached. + } + + nbytes += rc; + } + + return nbytes; #else if (device == NULL || device->socket == NULL) return DC_STATUS_INVALIDARGS; -- 2.4.3
From 79ec0c545f14d1f034b2dbba32722599baca913a Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 00:27:36 +0300 Subject: [PATCH 09/17] Add implementation for BTH custom serial write method used on Windows Implement the write method used for our custom serial implementation on Windows platforms. Signed-off-by: Claudiu Olteanu <[email protected]> --- qtserialbluetooth.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/qtserialbluetooth.cpp b/qtserialbluetooth.cpp index 9d1c14b..45fc8d1 100644 --- a/qtserialbluetooth.cpp +++ b/qtserialbluetooth.cpp @@ -263,9 +263,20 @@ static int qt_serial_write(serial_t *device, const void* data, unsigned int size if (device == NULL) return DC_STATUS_INVALIDARGS; - // TODO write *size* bytes from data to the device + unsigned int nbytes = 0; + int rc; - return 0; + while (nbytes < size) { + rc = send(device->socket, (char *) data + nbytes, size - nbytes, 0); + + if (rc < 0) { + return -1; // Error during send call. + } + + nbytes += rc; + } + + return nbytes; #else if (device == NULL || device->socket == NULL) return DC_STATUS_INVALIDARGS; -- 2.4.3
From 24ce7e2afdfd1f3f4812893c7bc1e10863d0f48f Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 00:43:33 +0300 Subject: [PATCH 10/17] Add internal method which returns a pretty message about the last error on Windows Implement an internal method which can be used to get a pretty print message about the last error from a Windows platform. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index bf0842c..c1755a5 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -443,7 +443,21 @@ void BtDeviceSelectionDialog::initializeDeviceDiscoveryAgent() static QString getLastErrorAsString() { - // TODO get the last error + LPVOID lpMsgBuf = NULL; + DWORD lastError = GetLastError(); + + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + lastError, + 0, + (LPTSTR) &lpMsgBuf, + 0,NULL)) { + return QString((char *)lpMsgBuf); + } else { + qDebug() << "Failed to format the message for the last error! Error number : " << lastError; + } + + return QString("Unknown"); } WinBluetoothDeviceDiscoveryAgent::WinBluetoothDeviceDiscoveryAgent(QObject *parent) : QThread(parent) -- 2.4.3
From aa6a270e4323cc3cf088e63cca6448913203a526 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 00:46:02 +0300 Subject: [PATCH 11/17] Add implementation for our custom BTH device discovery service Implement a custom lookup service for remote Bluetooth devices discovery. This will be used on Windows platforms to collect information about the name and the address of a remote Bluetooth device. In the beginning we initialize the queryset with the necessary flags and we start the lookup service. When a device is discovered we collect information about its name and its address and we raise a signal with it using the same signature as the one emitted by QtBluetoothDeviceDiscoveryAgent implementation. Finally we end the lookup service and we reset the internal flags. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 100 +++++++++++++++++++++++++++++++++++++- 1 file changed, 99 insertions(+), 1 deletion(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index c1755a5..262cf0a 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -485,7 +485,105 @@ QBluetoothDeviceDiscoveryAgent::Error WinBluetoothDeviceDiscoveryAgent::error() void WinBluetoothDeviceDiscoveryAgent::run() { - // TODO initialize the resources and start the device discovery + // Initialize query for device and start the lookup service + WSAQUERYSET queryset; + HANDLE hLookup; + int result = SUCCESS; + + running = true; + lastError = QBluetoothDeviceDiscoveryAgent::NoError; + + memset(&queryset, 0, sizeof(WSAQUERYSET)); + queryset.dwSize = sizeof(WSAQUERYSET); + queryset.dwNameSpace = NS_BTH; + + // The LUP_CONTAINERS flag is used to signal that we are doing a device inquiry + // while LUP_FLUSHCACHE flag is used to flush the device cache for all inquiries + // and to do a fresh lookup instead. + result = WSALookupServiceBegin(&queryset, LUP_CONTAINERS | LUP_FLUSHCACHE, &hLookup); + + if (result != SUCCESS) { + // Get the last error and emit a signal + lastErrorToString = getLastErrorAsString(); + lastError = QBluetoothDeviceDiscoveryAgent::PoweredOffError; + emit error(lastError); + + // Announce that the inquiry finished and restore the stopped flag + running = false; + stopped = false; + + return; + } + + // Declare the necessary variables to collect the information + BYTE buffer[4096]; + DWORD bufferLength = sizeof(buffer); + WSAQUERYSET *pResults = (WSAQUERYSET*)&buffer; + + memset(buffer, 0, sizeof(buffer)); + + pResults->dwSize = sizeof(WSAQUERYSET); + pResults->dwNameSpace = NS_BTH; + pResults->lpBlob = NULL; + + //Start looking for devices + while (result == SUCCESS && !stopped){ + // LUP_RETURN_NAME and LUP_RETURN_ADDR flags are used to return the name and the address of the discovered device + result = WSALookupServiceNext(hLookup, LUP_RETURN_NAME | LUP_RETURN_ADDR, &bufferLength, pResults); + + if (result == SUCCESS) { + // Found a device + char addressAsString[BTH_ADDR_STR_LEN]; + DWORD addressSize = sizeof (addressAsString); + + // Collect the address of the device from the WSAQUERYSET + SOCKADDR_BTH *socketBthAddress = (SOCKADDR_BTH *) pResults->lpcsaBuffer->RemoteAddr.lpSockaddr; + + // Convert the BTH_ADDR to string + if (WSAAddressToStringA((LPSOCKADDR) socketBthAddress, + sizeof (*socketBthAddress), + NULL, + addressAsString, + &addressSize + ) != 0) { + // Get the last error and emit a signal + lastErrorToString = getLastErrorAsString(); + lastError = QBluetoothDeviceDiscoveryAgent::UnknownError; + emit(lastError); + + break; + } + + // Save the address and the name of the discovered device + QString deviceName = QString(pResults->lpszServiceInstanceName); + QString deviceAddress = QString(addressAsString); + + // Remove the round parentheses + deviceAddress.remove(')'); + deviceAddress.remove('('); + + // Create an object with information about the discovered device + QBluetoothDeviceInfo deviceInfo = QBluetoothDeviceInfo(QBluetoothAddress(deviceAddress), deviceName, 0); + + // Raise a signal with information about the found remote device + emit deviceDiscovered(deviceInfo); + } else { + // Get the last error and emit a signal + lastErrorToString = getLastErrorAsString(); + lastError = QBluetoothDeviceDiscoveryAgent::UnknownError; + emit(lastError); + } + } + + // Announce that the inquiry finished and restore the stopped flag + running = false; + stopped = false; + + // Restore the error status + lastError = QBluetoothDeviceDiscoveryAgent::NoError; + + // End the lookup service + WSALookupServiceEnd(hLookup); } void WinBluetoothDeviceDiscoveryAgent::stop() -- 2.4.3
From ff993b7f565efa8a485a279c3ea0a9956617f6c8 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 00:57:42 +0300 Subject: [PATCH 12/17] Initialize WinSock and hide the information about the local device On Windows we cannot select a device or show information about the local device. Therefore we disable the UI section related to local device details. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index 262cf0a..af70897 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -25,7 +25,23 @@ BtDeviceSelectionDialog::BtDeviceSelectionDialog(QWidget *parent) : this, SLOT(itemClicked(QListWidgetItem*))); #if defined(Q_OS_WIN) - // TODO do the initialization + ULONG ulRetCode = SUCCESS; + WSADATA WSAData = { 0 }; + + // Initialize WinSock and ask for version 2.2. + ulRetCode = WSAStartup(MAKEWORD(2, 2), &WSAData); + if (ulRetCode != SUCCESS) { + QMessageBox::StandardButton warningBox; + warningBox = QMessageBox::critical(this, "Bluetooth", + "Could not initialize the Winsock version 2.2", QMessageBox::Ok); + return; + } + + // Initialize the device discovery agent + initializeDeviceDiscoveryAgent(); + + // On Windows we cannot select a device or show information about the local device + ui->localDeviceDetails->hide(); #else // Initialize the local Bluetooth device localDevice = new QBluetoothLocalDevice(); -- 2.4.3
From 0a04c001d280d7847779762b2ef24b4772c24bd0 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 01:01:15 +0300 Subject: [PATCH 13/17] Wait for BTH device discovery thread to finish on stop call We should wait for the WinBluetoothDeviceDiscoveryAgent completion when the stop method was called. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index af70897..922e7db 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -94,8 +94,12 @@ BtDeviceSelectionDialog::~BtDeviceSelectionDialog() #endif // Clean the device discovery agent - if (remoteDeviceDiscoveryAgent->isActive()) + if (remoteDeviceDiscoveryAgent->isActive()) { remoteDeviceDiscoveryAgent->stop(); +#if defined(Q_OS_WIN) + remoteDeviceDiscoveryAgent->wait(); +#endif + } delete remoteDeviceDiscoveryAgent; } @@ -127,6 +131,9 @@ void BtDeviceSelectionDialog::on_save_clicked() if (remoteDeviceDiscoveryAgent->isActive()) { // Stop the SDP agent if the clear button is pressed and enable the Scan button remoteDeviceDiscoveryAgent->stop(); +#if defined(Q_OS_WIN) + remoteDeviceDiscoveryAgent->wait(); +#endif ui->scan->setEnabled(true); } @@ -143,6 +150,9 @@ void BtDeviceSelectionDialog::on_clear_clicked() if (remoteDeviceDiscoveryAgent->isActive()) { // Stop the SDP agent if the clear button is pressed and enable the Scan button remoteDeviceDiscoveryAgent->stop(); +#if defined(Q_OS_WIN) + remoteDeviceDiscoveryAgent->wait(); +#endif ui->scan->setEnabled(true); } } -- 2.4.3
From 3269c2a635c70990dbcc1a276015fbbdfefc4c59 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 01:05:05 +0300 Subject: [PATCH 14/17] Add implementation for add remote Bluetooth device handler Check if the discovered device is already in our list and add it if it isn't. Also save the information about it on the item inserted. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index 922e7db..97ef429 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -192,7 +192,15 @@ void BtDeviceSelectionDialog::hostModeStateChanged(QBluetoothLocalDevice::HostMo void BtDeviceSelectionDialog::addRemoteDevice(const QBluetoothDeviceInfo &remoteDeviceInfo) { #if defined(Q_OS_WIN) - // TODO add the remote device + QString deviceLabel = QString("%1 (%2)").arg(remoteDeviceInfo.name()).arg(remoteDeviceInfo.address().toString()); + QList<QListWidgetItem *> itemsWithSameSignature = ui->discoveredDevicesList->findItems(remoteDeviceInfo.address().toString(), Qt::MatchContains); + + if (itemsWithSameSignature.empty()) { + QListWidgetItem *item = new QListWidgetItem(deviceLabel); + + item->setData(Qt::UserRole, QVariant::fromValue(remoteDeviceInfo)); + ui->discoveredDevicesList->addItem(item); + } #else QString deviceLabel = QString("%1 (%2)").arg(remoteDeviceInfo.name()).arg(remoteDeviceInfo.address().toString()); QList<QListWidgetItem *> itemsWithSameSignature = ui->discoveredDevicesList->findItems(remoteDeviceInfo.address().toString(), Qt::MatchContains); -- 2.4.3
From 57d1f73226243c2a8c9aefe9fec540af137cb5e6 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 01:07:59 +0300 Subject: [PATCH 15/17] Add implementation for BTH device item selection on Windows platforms When a Bluetooth device is selected from the discovered list display information about its address and enable the save button. On Windows we don't need to check if the devices are paired because the pairing process is done automatically on the connection step. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index 97ef429..6847529 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -230,7 +230,11 @@ void BtDeviceSelectionDialog::addRemoteDevice(const QBluetoothDeviceInfo &remote void BtDeviceSelectionDialog::itemClicked(QListWidgetItem *item) { #if defined(Q_OS_WIN) - // TODO enable the save button and log information about the selected item + QBluetoothDeviceInfo remoteDeviceInfo = item->data(Qt::UserRole).value<QBluetoothDeviceInfo>(); + + ui->dialogStatus->setText(QString("The device %1 can be used for connection. You can press the Save button.") + .arg(remoteDeviceInfo.address().toString())); + ui->save->setEnabled(true); #else QBluetoothDeviceInfo remoteDeviceInfo = item->data(Qt::UserRole).value<QBluetoothDeviceInfo>(); QBluetoothLocalDevice::Pairing pairingStatus = localDevice->pairingStatus(remoteDeviceInfo.address()); -- 2.4.3
From 77402bfe8f37d7bfcf69f612fb660e5707d030ae Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 01:12:47 +0300 Subject: [PATCH 16/17] Get a pretty print message when a device discovery error occured Try to get a pretty print message when a device discovery error is raised and it is unknown. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index 6847529..e66bd92 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -377,7 +377,11 @@ void BtDeviceSelectionDialog::deviceDiscoveryError(QBluetoothDeviceDiscoveryAgen errorDescription = QString("Writing or reading from the device resulted in an error."); break; default: +#if defined(Q_OS_WIN) + errorDescription = remoteDeviceDiscoveryAgent->errorToString(); +#else errorDescription = QString("An unknown error has occurred."); +#endif break; } -- 2.4.3
From 9418075412fa91a349dc91530bd0cdc22fde2d96 Mon Sep 17 00:00:00 2001 From: Claudiu Olteanu <[email protected]> Date: Thu, 13 Aug 2015 01:15:28 +0300 Subject: [PATCH 17/17] Add implementation for device discovery agent initialization (Windows) Register the metatypes needed for Windows platforms and initialize our custom discovery agent. Signed-off-by: Claudiu Olteanu <[email protected]> --- qt-ui/btdeviceselectiondialog.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/qt-ui/btdeviceselectiondialog.cpp b/qt-ui/btdeviceselectiondialog.cpp index e66bd92..a18d323 100644 --- a/qt-ui/btdeviceselectiondialog.cpp +++ b/qt-ui/btdeviceselectiondialog.cpp @@ -456,7 +456,21 @@ void BtDeviceSelectionDialog::updateLocalDeviceInformation() void BtDeviceSelectionDialog::initializeDeviceDiscoveryAgent() { #if defined(Q_OS_WIN) - // TODO initialize the discovery agency + // Register QBluetoothDeviceInfo metatype + qRegisterMetaType<QBluetoothDeviceInfo>(); + + // Register QBluetoothDeviceDiscoveryAgent metatype (Needed for QBluetoothDeviceDiscoveryAgent::Error) + qRegisterMetaType<QBluetoothDeviceDiscoveryAgent::Error>(); + + // Intialize the discovery agent + remoteDeviceDiscoveryAgent = new WinBluetoothDeviceDiscoveryAgent(this); + + connect(remoteDeviceDiscoveryAgent, SIGNAL(deviceDiscovered(QBluetoothDeviceInfo)), + this, SLOT(addRemoteDevice(QBluetoothDeviceInfo))); + connect(remoteDeviceDiscoveryAgent, SIGNAL(finished()), + this, SLOT(remoteDeviceScanFinished())); + connect(remoteDeviceDiscoveryAgent, SIGNAL(error(QBluetoothDeviceDiscoveryAgent::Error)), + this, SLOT(deviceDiscoveryError(QBluetoothDeviceDiscoveryAgent::Error))); #else // Intialize the discovery agent remoteDeviceDiscoveryAgent = new QBluetoothDeviceDiscoveryAgent(localDevice->address()); -- 2.4.3
_______________________________________________ subsurface mailing list [email protected] http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface
