QQueue を介してシリアル ポートにデータを書き込み、スロットから読み取ることができるクラスを実装しました。これには QAsyncSerial を使用します。これは、boost::asio とコールバックを使用します。クラスはスレッドに移動され、QThread が「started()」を発行すると、その start() メソッドが実行されます。
問題は、forever {} と QWaitCondition を使用して start() メソッドで QQueue をデキューすることです。これが実行されている間 (明らかに永久に実行されます)、QAsyncSerial の dataReceived 信号に接続されたスロットを呼び出すことができないため、シリアル ポートから何も読み取れません。
この問題に対する通常のアプローチは何ですか?
SerialPortHandler::SerialPortHandler(SerialPort serialPort, QObject *parent) : QObject(parent), serialPort(serialPort)
{
m_enqueueMessageMutex = new QMutex();
m_messageQueue = new QQueue<BaseMessage*>();
m_waitCondition = new QWaitCondition();
serial.open(serialPort.deviceName(), 2400);
connect(&serial, SIGNAL(dataReceived(QByteArray)), this, SLOT(serialSlotReceivedData(QByteArray)));
}
void SerialPortHandler::serialSlotReceivedData(QByteArray line)
{
qDebug() << QString(line).toAscii();
}
void SerialPortHandler::sendTestPing()
{
PingMessage *msg = new PingMessage();
enqueueMessage(msg);
}
void SerialPortHandler::enqueueMessage(BaseMessage *msg)
{
QMutexLocker locker(m_enqueueMessageMutex);
m_messageQueue->enqueue(msg);
m_waitCondition->wakeAll();
}
void SerialPortHandler::start()
{
if (!serial.isOpen())
return;
forever {
m_enqueueMessageMutex->lock();
if (m_messageQueue->isEmpty())
m_waitCondition->wait(m_enqueueMessageMutex);
BaseMessage *msg = m_messageQueue->dequeue();
serial.write(msg->encodeForWriting());
m_enqueueMessageMutex->unlock();
}
}
boost::asio で使用される変更された QAsyncSerial コールバック:
void QAsyncSerial::readCallback(const char *data, size_t size)
{
emit dataReceived(QByteArray::fromRawData(data, (int) size));
}
編集:
この問題を別のアプローチで解決しました。私は QAsyncSerial を捨て、代わりに QAsyncSerial によって直接配布されている CallbackAsyncSerial を使用しました。現在、boost::asio が使用するコールバックは serialSlotReceivedData の「スロット」です。これにより、boost :: asio が実行されるスレッドでコールバックが呼び出されるため、問題が「解決」されます。独自のスレッドがあるため、SerialPortHandler が実行されるスレッドが永久ループによってブロックされても問題ありません。
新しいコード: (QAsyncSerial は CallbackAsyncSerial のラッパーのようなものであるため、変更されたのは些細なことだけです)
SerialPortHandler::SerialPortHandler(SerialPort serialPort, QObject *parent) : QObject(parent), serialPort(serialPort)
{
m_enqueueMessageMutex = new QMutex();
m_messageQueue = new QQueue<BaseMessage*>();
m_waitCondition = new QWaitCondition();
/* serial is now CallbackAsyncSerial and not QAsyncSerial */
serial.open(QString(serialPort.deviceName()).toStdString(), 2400);
serial.setCallback(bind(&SerialPortHandler::serialSlotReceivedData, this, _1, _2));
m_messageProcessingState = MessageProcessingState::Inactive;
}
void SerialPortHandler::start()
{
if (!serial.isOpen())
return;
forever {
m_enqueueMessageMutex->lock();
if (m_messageQueue->isEmpty())
m_waitCondition->wait(m_enqueueMessageMutex);
BaseMessage *msg = m_messageQueue->dequeue();
QByteArray encodedMessage = msg->encodeForWriting();
serial.write(encodedMessage.constData(), encodedMessage.length());
m_enqueueMessageMutex->unlock();
}
}