У меня есть рабочий поток (QThread), который собирает данные от приборов, которые подключены либо через RS232 (который работает нормально, это легко реализовать). Другой прибор подключен через RS485 и использует протокол Modbus, но, похоже, что сам QModbus работает в отдельном потоке, что делает необходимым подключение сигнала ответа от QModbus к слоту, который затем собирает ответ от QModbus, поэтому Я должен ждать, пока этот слот будет вызван и выполнен, для этого я должен убедиться, что мой поток входит в событие l oop, что мой слот может быть вызван, я сделал это так:
do
{
QEventLoop(this).processEvents();
} while (!answerReceived);
Но это вызывает у меня тонны таких сообщений об ошибках в QtCreator:
QBasicTimer::start: Timers cannot be started from another thread
Я попробовал также эти два предложения здесь: Как сообщить QThread, что нужно дождаться окончания работы, а затем fini sh? но, к сожалению, я все еще получаю эти ошибки. Что я могу сделать, чтобы избавиться от этих ошибок, или я должен жить с этим?
Обновление.
Вот код соответствующих функций:
void Worker::requestValue(int address, int length)
{
answerReceived = false;
qDebug() << "Read values";
read(address, length);
do
{
QEventLoop(this).processEvents();
} while (!answerReceived);
}
void Worker::read(int address, int length)
{
if (!modbusDevice)
return;
if (auto *reply = modbusDevice->sendReadRequest(readRequest(address, length), 10)) {
if (!reply->isFinished())
connect(reply, &QModbusReply::finished, this, &Worker::onReceiveValues);
else
delete reply; // broadcast replies return immediately
} else {
qDebug() << tr("Read error: ") + modbusDevice->errorString();
}
}
void Worker::onReceiveValues()
{
auto reply = qobject_cast<QModbusReply *>(sender());
if (!reply)
return;
if (reply->error() == QModbusDevice::NoError) {
const QModbusDataUnit unit = reply->result();
QVector<quint16> receivedValues = unit.values();
switch(answerType)
{
case AnswerType::Flow:
{
prominentPumvValues.flow = processFloatValue(receivedValues);
}
break;
case AnswerType::Stroke:
{
prominentPumvValues.stroke = processFloatValue(receivedValues);
}
break;
case AnswerType::Frequency:
prominentPumvValues.frequency = receivedValues.at(0);
break;
case AnswerType::SerialNumber:
{
prominentPumvValues.serialNumber = processString(receivedValues);
}
default:
break;
}
} else if (reply->error() == QModbusDevice::ProtocolError) {
qDebug() << tr("Read response error: %1 (Mobus exception: 0x%2)").
arg(reply->errorString()).
arg(reply->rawResult().exceptionCode(), -1, 16);
} else {
qDebug() << tr("Read response error: %1 (code: 0x%2)").
arg(reply->errorString()).
arg(reply->error(), -1, 16);
}
reply->deleteLater();
answerReceived = true;
}
Я нашел эту ветку здесь: https://forum.qt.io/topic/82819/qbasictimer-start-timers-cannot-be-started-from-another-thread-issue/10 и изменил функцию чтения следующим образом:
void Worker::read(int address, int length)
{
if (!modbusDevice)
return;
if (auto *reply = modbusDevice->sendReadRequest(readRequest(address, length), 10)) {
if (!reply->isFinished())
{
qDebug() << "Reply not finished";
qDebug() << "Connect: " << connect(reply, &QModbusReply::finished, [reply, this]() {
qDebug() << "connect";
if(reply->error() == QModbusClient::NoError)
{
const QModbusDataUnit unit = reply->result();
receivedValues = unit.values();
qDebug() << "Lambda: " << receivedValues.length();
}
else
qDebug() << "Reply error";
reply->deleteLater();
qDebug() << "Bye";
});
qDebug() << "Ade";
}
else
{
qDebug() << "Reply finished";
delete reply; // broadcast replies return immediately
}
} else {
qDebug() << tr("Read error: ") + modbusDevice->errorString();
}
qDebug() <<receivedValues[0] << receivedValues[1];
}
Ответ соединения верен, но выглядит так код внутри лямбды не выполняется, внутри лямбды нет вывода функций qDebug ()