4

このウェブサイトでの最初の質問です。

COM ポートからデータを読み取るのに問題があり、別の COM ポートから完全なメッセージを送信します。Qt で受信すると、常に複数のサブメッセージに分割されます。

void SerialPortReader::init()
{
    connect(m_serialPort, SIGNAL(readyRead()), this, SLOT(readData()));
}   

void SerialPortReader::readData()
{
//    m_serialPort->waitForReadyRead(200);
    QByteArray byteArray = m_serialPort->readAll();
    qDebug() << byteArray;

    if(byteArray.startsWith(SOF) && byteArray.endsWith(EOF_LS)
        && byteArray.size() >= MIN_SIZE_DATA) {
    decodeData(byteArray.constData());
    } else {
        qDebug() << "LIB SWCom : Unvalid trame !";
    }
}

送信されるメッセージの長さは 25 または 27 バイトですが、Putty またはハイパーターミナルを使用してそれらを読み取る場合、問題はありません。また、2 つのエミュレートされたシリアル ポート COM を使用して通信する場合、この問題は発生しません... Qt 読み取りシステムと 2 つの物理 COM ポートでのみ発生します...

readyRead シグナルが正確に発行されたときに取得できないと思います...

私は非常に混乱しています, 助けてくれてありがとう!

4

3 に答える 3

11

ドキュメントは実際にはそれについて非常に明確です:

void QIODevice::readyRead() [シグナル]

このシグナルは、デバイスからの読み取りに新しいデータが使用可能になるたびに 1 回発行されます。ネットワークデータの新しいペイロードがネットワークソケットに到着したとき、またはデータの新しいブロックがデバイスに追加されたときなど、新しいデータが利用可能になったときにのみ再度送信されます。

readyRead() は再帰的に発行されません。イベント ループに再度入るか、readyRead() シグナルに接続されたスロット内で waitForReadyRead() を呼び出すと、シグナルは再送信されません (ただし、waitForReadyRead() は true を返す場合があります)。

QIODevice から派生したクラスを実装する開発者への注意: 新しいデータが到着したときは常に readyRead() を発行する必要があります (バッファにまだ読み取るデータがあるという理由だけで発行しないでください)。他の条件で readyRead() を発行しないでください。

これは、読み取りに使用できるデータの量が実際に保証されているわけではなく、一部が使用可能であることを意味します。

一度に送信されるよりも多くのデータを読み取りたい場合は、タイムアウト値および/または readyRead を選択できます。それはあなたが何を達成しようとしているかによって異なります。

この操作については、私が少し前に書いたコマンド ライン非同期リーダーの例も参照してください。

#include "serialportreader.h"

#include <QCoreApplication>

QT_USE_NAMESPACE

SerialPortReader::SerialPortReader(QSerialPort *serialPort, QObject *parent)
    : QObject(parent)
    , m_serialPort(serialPort)
    , m_standardOutput(stdout)
{
    connect(m_serialPort, SIGNAL(readyRead()), SLOT(handleReadyRead()));
    connect(m_serialPort, SIGNAL(error(QSerialPort::SerialPortError)), SLOT(handleError(QSerialPort::SerialPortError)));
    connect(&m_timer, SIGNAL(timeout()), SLOT(handleTimeout()));

    m_timer.start(5000);
}

SerialPortReader::~SerialPortReader()
{
}

void SerialPortReader::handleReadyRead()
{
    m_readData.append(m_serialPort->readAll());

    if (!m_timer.isActive())
        m_timer.start(5000);
}

void SerialPortReader::handleTimeout()
{
    if (m_readData.isEmpty()) {
        m_standardOutput << QObject::tr("No data was currently available for reading from port %1").arg(m_serialPort->portName()) << endl;
    } else {
        m_standardOutput << QObject::tr("Data successfully received from port %1").arg(m_serialPort->portName()) << endl;
        m_standardOutput << m_readData << endl;
    }

    QCoreApplication::quit();
}

void SerialPortReader::handleError(QSerialPort::SerialPortError serialPortError)
{
    if (serialPortError == QSerialPort::ReadError) {
        m_standardOutput << QObject::tr("An I/O error occurred while reading the data from port %1, error: %2").arg(m_serialPort->portName()).arg(m_serialPort->errorString()) << endl;
        QCoreApplication::exit(1);
    }
}

この場合、コマンド ライン リーダーの例では、渡されたすべてのデータが 1 回で取得されますが、長さなどは保証されません。

また、コメントの背後にある同期APIは、あなたが求めている非同期APIと一緒に意味をなさないことに注意してください. 私はm_serialPort->waitForReadyRead(200);ここで言及しています。

于 2014-10-28T16:09:07.577 に答える
1

保留中のデータがあり、readyRead の前回の実行が終了すると、readyRead シグナルが発行されます。

ドキュメントには次のように記載されています。

このシグナルは、デバイスからの読み取りに新しいデータが使用可能になるたびに 1 回発行されます。ネットワークデータの新しいペイロードがネットワークソケットに到着したとき、またはデータの新しいブロックがデバイスに追加されたときなど、新しいデータが利用可能になったときにのみ再度送信されます。

readyRead() は再帰的に発行されません。イベント ループに再度入るか、readyRead() シグナルに接続されたスロット内で waitForReadyRead() を呼び出すと、シグナルは再送信されません (ただし、waitForReadyRead() は true を返す場合があります)。

これにより問題が発生する場合は、bytesAvailable() をチェックする while ループを使用できます。

于 2014-10-28T16:02:39.967 に答える