Reputation: 211
I made a simple app that write to a device a command, and 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;
stream >> length;
if(cmd != READ_DATA_RESPONSE_CMD || length == 0)
return;
// non ho ancora ricevuto tutti i dati
if(data.length() - headerLength != length)
return;
m_receptionTimer.stop();
emit dataChanged(data.mid(3));
requestData();
}
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 disconnected
Am I doing something wrong?
Upvotes: 0
Views: 192