Qt 5.14.2 BLE not working as expected on Android
Unsolved
General and Desktop
-
I made a simple app that write a command to a device and expect the device reply with another command. On windows everything works fine, but on Android I'm not able to send the data. This is my code:
#include "communicator.hpp" #include <QDataStream> #include <QBluetoothLocalDevice> #define SERVICE_UUID "{49535343-fe7d-4ae5-8fa9-9fafd205e455}" #define SERVICE_CHARACTERISTIC_TX_UUID "{49535343-1e4d-4bd9-ba61-23c647249616}" #define READ_DATA_REQUEST_CMD 0xA5 #define READ_DATA_RESPONSE_CMD 0xA6 Communicator::Communicator() { QObject::connect(&m_receptionTimer, &QTimer::timeout, this, &Communicator::onReceptionTimerTimeout); m_receptionTimer.setInterval(2000); } void Communicator::connectToDevice(const QString& macAddress) { m_controller.reset(QLowEnergyController::createCentral(QBluetoothAddress(macAddress), QBluetoothLocalDevice().address())); QObject::connect(m_controller.data(), &QLowEnergyController::connected, this, &Communicator::onDeviceConnected); QObject::connect(m_controller.data(), &QLowEnergyController::discoveryFinished, this, &Communicator::onDiscoveryFinished); QObject::connect(m_controller.data(), QOverload<QLowEnergyController::Error>::of(&QLowEnergyController::error), this, &Communicator::onDiscoveryError); QObject::connect(m_controller.data(), &QLowEnergyController::serviceDiscovered, this, &Communicator::onServiceDiscovered); m_controller->connectToDevice(); } void Communicator::onDeviceConnected() { qDebug() << "Device connected"; m_serviceDiscovered = false; m_controller->discoverServices(); } void Communicator::onDiscoveryFinished() { if(!m_serviceDiscovered) { emit connectionFailed(); return; } m_service.reset(m_controller->createServiceObject(QBluetoothUuid(QString(SERVICE_UUID)), this)); if(m_service.isNull()) { emit connectionFailed(); return; } QObject::connect(m_service.data(), &QLowEnergyService::stateChanged, this, &Communicator::onServiceStateChanged); QObject::connect(m_service.data(), QOverload<QLowEnergyService::ServiceError>::of(&QLowEnergyService::error), this, &Communicator::onServiceError); QObject::connect(m_service.data(), &QLowEnergyService::characteristicChanged, this, &Communicator::onCharacteristicChanged); //************************ //**********TEST********** //************************ QObject::connect(m_service.data(), &QLowEnergyService::stateChanged, this, [](QLowEnergyService::ServiceState state) { qDebug() << "SERVICE STATE CHANGED -> STATE:" << state; }); QObject::connect(m_service.data(), &QLowEnergyService::characteristicWritten, this, [](const QLowEnergyCharacteristic &info, const QByteArray &value) { qDebug() << "CHARACTERISTIC WRITTEN -> UUID:" << info.uuid().toString() << "VALUE:" << value; }); QObject::connect(m_service.data(), &QLowEnergyService::characteristicChanged, this, [](const QLowEnergyCharacteristic &info, const QByteArray &value) { qDebug() << "CHARACTERISTIC CHANGED -> UUID:" << info.uuid().toString() << "VALUE:" << value; }); QObject::connect(m_service.data(), &QLowEnergyService::characteristicRead, this, [](const QLowEnergyCharacteristic &info, const QByteArray &value) { qDebug() << "CHARACTERISTIC READ -> UUID:" << info.uuid().toString() << "VALUE:" << value; }); QObject::connect(m_service.data(), &QLowEnergyService::descriptorRead, this, [](const QLowEnergyDescriptor &info, const QByteArray &value) { qDebug() << "DESCRIPTOR READ -> UUID:" << info.uuid().toString() << "VALUE:" << value; }); QObject::connect(m_service.data(), &QLowEnergyService::descriptorWritten, this, [](const QLowEnergyDescriptor &info, const QByteArray &value) { qDebug() << "DESCRIPTOR WRITTEN -> UUID:" << info.uuid().toString() << "VALUE:" << value; }); //************************ //**********TEST********** //************************ if(m_service->state() == QLowEnergyService::DiscoveryRequired) m_service->discoverDetails(); else { searchCharacteristics(); requestData(); } } void Communicator::onDiscoveryError(QLowEnergyController::Error error) { qDebug() << "Discovery error" << error; emit connectionFailed(); } void Communicator::onServiceDiscovered(const QBluetoothUuid& service) { if(service.toString() == SERVICE_UUID) m_serviceDiscovered = true; } void Communicator::onServiceStateChanged(QLowEnergyService::ServiceState state) { switch(state) { case QLowEnergyService::InvalidService: case QLowEnergyService::DiscoveryRequired: case QLowEnergyService::DiscoveringServices: case QLowEnergyService::LocalService: break; case QLowEnergyService::ServiceDiscovered: searchCharacteristics(); requestData(); break; } } void Communicator::onServiceError(QLowEnergyService::ServiceError error) { qDebug() << "Service error" << error; emit connectionFailed(); } void Communicator::onCharacteristicChanged(const QLowEnergyCharacteristic& info, const QByteArray& value) { if(info.uuid() != m_writeCharacteristic.uuid()) return; m_receptionBuffer.append(value); parseResponse(m_receptionBuffer); } void Communicator::onReceptionTimerTimeout() { qDebug() << "Reception timeout"; requestData(); emit errorOccurred(); } void Communicator::searchCharacteristics() { const auto& characteristics = m_service->characteristics(); for(const QLowEnergyCharacteristic& characteristic : characteristics) { if(!characteristic.isValid()) continue; if(characteristic.uuid().toString() != SERVICE_CHARACTERISTIC_TX_UUID) continue; if(characteristic.properties() & QLowEnergyCharacteristic::WriteNoResponse || characteristic.properties() & QLowEnergyCharacteristic::Write) { m_writeCharacteristic = characteristic; if(characteristic.properties() & QLowEnergyCharacteristic::WriteNoResponse) m_writeMode = QLowEnergyService::WriteWithoutResponse; else m_writeMode = QLowEnergyService::WriteWithResponse; QLowEnergyDescriptor notificationDescriptor = characteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration); if(notificationDescriptor.isValid()) m_service->writeDescriptor(notificationDescriptor, QByteArray::fromHex("0100")); } } } bool Communicator::write(const QByteArray& data) { if(m_service.isNull()) return false; if(!m_writeCharacteristic.isValid()) return false; m_service->writeCharacteristic(m_writeCharacteristic, data, m_writeMode); return true; } void Communicator::requestData() { m_receptionBuffer.clear(); m_receptionTimer.start(); write(QByteArray(1, READ_DATA_REQUEST_CMD)); } void Communicator::parseResponse(const QByteArray& data) { const quint8 headerLength = 3; if(data.length() < headerLength) return; quint8 cmd; quint16 length; QDataStream stream(data); stream >> cmd;
This is the log of my application on Android:
06-07-22 16:48:55.353 |W| ACCESS_COARSE|FINE_LOCATION permission available
06-07-22 16:48:57.986 |D| Device connected
06-07-22 16:48:58.018 |D| SERVICE STATE CHANGED -> STATE: QLowEnergyService::DiscoveringServices
06-07-22 16:49:03.284 |D| Discovery error QLowEnergyController::ConnectionError
06-07-22 16:49:03.287 |D| SERVICE STATE CHANGED -> STATE: QLowEnergyService::InvalidService
06-07-22 16:49:03.287 |D| Device disconnectedAm I doing something wrong?