Я использую qt на встроенной плате для связи с устройством IOS. Встроенная плата работает на qt 5.10 и находится в периферийном режиме. Иногда я получаю вышеупомянутую ошибку, и после этого возникает ошибка Bluetooth с сигналом ошибки следующим образом
Ошибка: QLowEnergyController :: Error (UnknownError)
Как могу я узнать источник этой проблемы? В документе ничего не говорится об этом.
Код основан на примере сервера сердечного ритма qt https://doc.qt.io/qt-5/qtbluetooth-heartrate-server-example.html
Мой класс для Bluetooth
#include "bluetooth.h"
#define log qDebug()<<"["<<__DATE__<<":"<<QTime::currentTime().toString()<<"]"<<"["<<__LINE__<<"]"<<"["<<__FILE__<<"] "
Bluetooth::Bluetooth(mainprocess *main,QObject *parent) :QObject(parent), mainObject(main)
{
initializeBluetooth();
}
void Bluetooth::initializeBluetooth(){
try{
log<<"Initializing Bluetooth...\n";
//! [Advertising Data]
advertisingData.setDiscoverability(QLowEnergyAdvertisingData::DiscoverabilityGeneral);
advertisingData.setLocalName("AtlasGo");
advertisingData.setServices(QList<QBluetoothUuid>() <<QBluetoothUuid::Atlas);
// For IOS its readonly and for Atlas its write only
ReadCharacteristicData.setUuid(QBluetoothUuid::ReadCharacteristic);
ReadCharacteristicData.setProperties(QLowEnergyCharacteristic::Notify);
ReadCharacteristicDesc.setUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
ReadCharacteristicDesc.setValue(QByteArray(2,0));
ReadCharacteristicData.addDescriptor(ReadCharacteristicDesc);
// For IOS its write only characteristic and for Atlas its read only
WriteCharactersiticData.setUuid(QBluetoothUuid::WriteCharacteristic);
WriteCharactersiticData.setProperties(QLowEnergyCharacteristic::Write |QLowEnergyCharacteristic::Notify);
WriteCharactersiticDesc.setUuid(QBluetoothUuid::AtlasDescriptor);
WriteCharactersiticDesc.setValue(QByteArray::fromHex("Write").toHex());
WriteCharactersiticData.addDescriptor(WriteCharactersiticDesc);
// For IOS its readonly and for Atlas its write only
ConnectivityData.setUuid(QBluetoothUuid::Connectivity);
ConnectivityData.setProperties(QLowEnergyCharacteristic::Notify);
ConnectivityDesc.setUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
ConnectivityDesc.setValue(QByteArray(2, 0));
ConnectivityData.addDescriptor(ConnectivityDesc);
// For IOS its write only characteristic and for Atlas its read only
TrackerData_Data.setUuid(QBluetoothUuid::TrackingData);
TrackerData_Data.setProperties(QLowEnergyCharacteristic::Notify);
TrackerDesc.setUuid(QBluetoothUuid::ClientCharacteristicConfiguration);
TrackerDesc.setValue(QByteArray(2, 0));
TrackerData_Data.addDescriptor(TrackerDesc);
serviceData.setType(QLowEnergyServiceData::ServiceTypePrimary);
serviceData.setUuid(QBluetoothUuid::Atlas);
// Adding characteristic to our service
serviceData.addCharacteristic(ReadCharacteristicData);
serviceData.addCharacteristic(WriteCharactersiticData);
serviceData.addCharacteristic(ConnectivityData);
serviceData.addCharacteristic(TrackerData_Data);
leController.reset(QLowEnergyController::createPeripheral()); // We are resetting only the pointer here (leController is a scoped pointer)
service.reset(leController->addService(serviceData)); // Resetting only the pointer here (service is a scoped pointer)
while ( localdevice.hostMode()==QBluetoothLocalDevice::HostPoweredOff){
log<<"Host is powered off";
system("sudo rfkill unblock 3");
system("sudo rfkill unblock 0");
if(localdevice.hostMode()==QBluetoothLocalDevice::HostConnectable)
break;
}
connect(&heartbeatTimer, &QTimer::timeout,mainObject, &mainprocess::TickProvider);
connect(leController.data(), &QLowEnergyController::disconnected,mainObject,&mainprocess::reconnect);
connect(leController.data(), &QLowEnergyController::connected,mainObject,&mainprocess::bleConnected);
connect(service.data(),&QLowEnergyService::characteristicChanged,mainObject,&mainprocess::parseResponse);
connect(leController.data(), static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
this,&Bluetooth::reconnectOnError);
leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,advertisingData);
// We have to check if advertising succeeded ot not. If there was an advertising error we will
// try to reinitialize our bluetooth service
while (leController->state()!= QLowEnergyController::AdvertisingState){
resetBluetoothService();
leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,advertisingData);
}
// Timer for periodically sending information to IOS
// Tracking data
// Connectivity information
log<<"Starting the Tick Timer Timer";
heartbeatTimer.start(66);
// heartbeatTimer.start(200); Just for testing
}
catch(std::exception e)
{
log<<"---------------------";
log<<"Bluetooth Crashed";
log<<"---------------------";
log<<"Bluetooth Initialization failed";
log<<e.what();
emit recoverBluetooth();
}
}
void Bluetooth::reconnectOnDisconnect(){
try{
log<<"Bluetooth Device Disconnected";
log<<"Resetting Bluetooth bt.service";
//resetBluetoothService();
if(leController->state()!= QLowEnergyController::ConnectedState){
//leController->disconnectFromDevice();
leController.reset(QLowEnergyController::createPeripheral());
service.reset(leController->addService(serviceData));
}
if (!service.isNull()){
if(leController->state()!=QLowEnergyController::AdvertisingState && leController->state()!=QLowEnergyController::ConnectedState){
leController->startAdvertising(QLowEnergyAdvertisingParameters(),advertisingData,advertisingData); //, advertisingData);
}
// We have to check if advertising succeeded ot not. If there was an advertising error we will
// try to reinitialize our bluetooth service
while (leController->state()!= QLowEnergyController::AdvertisingState && leController->state()!= QLowEnergyController::ConnectedState ){
resetBluetoothService();
leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,advertisingData);
}
connect(service.data(),&QLowEnergyService::characteristicChanged,mainObject,&mainprocess::parseResponse);
connect(leController.data(), &QLowEnergyController::disconnected,mainObject,&mainprocess::reconnect);
connect(leController.data(), &QLowEnergyController::disconnected,mainObject,&mainprocess::stopTracker);
connect(leController.data(), &QLowEnergyController::connected,mainObject,&mainprocess::bleConnected);
connect(leController.data(), static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
this,&Bluetooth::reconnectOnError);
}
}
catch(std::exception e){
log<<"---------------------";
log<<"Bluetooth Crashed";
log<<"---------------------";
log<<"Error while handling bluetooth Disconnect";
log<<e.what();
emit recoverBluetooth();
}
}
void Bluetooth::reconnectOnError(QLowEnergyController::Error error){
try{
// Have to check this error because of Qt's bug. It throws error when remote device disconnects
if(error!=QLowEnergyController::RemoteHostClosedError){
log<<"Bluetooth Error !!";
log<<"Resetting Bluetooth bt.service";
log<<"Error: "<<error;
// resetBluetoothService();
if(leController->state()!= QLowEnergyController::ConnectedState){
//leController->disconnectFromDevice();
leController.reset(QLowEnergyController::createPeripheral());
service.reset(leController->addService(serviceData));
}
if (service!=nullptr){
if(leController->state()!=QLowEnergyController::AdvertisingState && leController->state()!=QLowEnergyController::ConnectedState){
leController->startAdvertising(QLowEnergyAdvertisingParameters(),advertisingData,advertisingData); //, advertisingData);
}
// We have to check if advertising succeeded or not. If there was an advertising error we will
// try to reinitialize our bluetooth service
while (leController->state()!= QLowEnergyController::AdvertisingState && leController->state()!= QLowEnergyController::ConnectedState ){
//resetBluetoothService();
leController->startAdvertising(QLowEnergyAdvertisingParameters(), advertisingData,advertisingData);
}
// Connections
connect(service.data(),&QLowEnergyService::characteristicChanged,mainObject,&mainprocess::parseResponse);
connect(service.data(), QOverload<QLowEnergyService::ServiceError>::of(&QLowEnergyService::error),[=](QLowEnergyService::ServiceError newError){
log<<"---------------------";
log<<"Bluetooth Service Error:"<<newError;
log<<"---------------------";
});
connect(leController.data(), &QLowEnergyController::disconnected,mainObject,&mainprocess::reconnect);
connect(leController.data(), &QLowEnergyController::connected,mainObject,&mainprocess::bleConnected);
connect(leController.data(), &QLowEnergyController::disconnected,mainObject,&mainprocess::stopTracker);
connect(leController.data(), static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
this,&Bluetooth::reconnectOnError);
}
}
}
catch(std::exception e){
log<<"---------------------";
log<<"Bluetooth Crashed";
log<<"---------------------";
log<<"Error while reconnecting after remote device disconnection";
log<<e.what();
emit recoverBluetooth();
}
}
void Bluetooth::resetBluetoothService(){
try{
log<<"Trying to reset bluetooth";
if(leController->state()==QLowEnergyController::AdvertisingState)
leController->stopAdvertising();
// Todo: Use timer
system("sudo service bluetooth stop");
QThread::sleep(1);
system("sudo service bluetooth start");
QThread::sleep(1);
log<<"Bluetooth Reset complete";
}
catch(std::exception e){
log<<"---------------------";
log<<"Bluetooth Crashed";
log<<"---------------------";
log<<"Error while resetting bluetooth";
log<<e.what();
emit recoverBluetooth();
}
}