Это мой первый вопрос на этом сайте!
У меня возникли проблемы с чтением данных с 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 или Hyperterminal для их чтения, у меня нет проблем.
Также, если я использую 2 эмулируемых последовательных порта COM для связи, у меня нет этой проблемы …
Это происходит только с системой чтения Qt И с 2 физическими COM-портами …
Я думаю, что я не понимаю, когда сигнал ReadyRead излучается точно …
Я очень запутался, заранее благодарю за помощь!
документация на самом деле совершенно ясно об этом:
void QIODevice :: readyRead () [сигнал]
Этот сигнал испускается один раз каждый раз, когда новые данные доступны для чтения с устройства. Он будет отправляться снова только после того, как станут доступны новые данные, например, когда в сетевую розетку поступила новая полезная нагрузка сетевых данных или когда к вашему устройству был добавлен новый блок данных.
readyRead () не генерируется рекурсивно; если вы повторно войдете в цикл обработки событий или вызовете waitForReadyRead () внутри слота, подключенного к сигналу readyRead (), сигнал не будет повторно отправлен (хотя 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);
}
}
В этом случае пример программы чтения командной строки получит все данные, которые были переданы за один кадр, но это не гарантирует длину или что-либо еще.
Кроме того, обратите внимание, что api sync, стоящий за вашими комментариями, не имеет особого смысла вместе с асинхронным API, о котором вы спрашиваете. Я имею в виду m_serialPort->waitForReadyRead(200);
здесь.
Сигнал readyRead посылается всякий раз, когда имеются ожидающие данные И когда завершено предыдущее выполнение readyRead.
Документация гласит:
Этот сигнал испускается один раз каждый раз, когда новые данные доступны для
чтение с устройства. Он будет выпущен снова только после новых данных
доступно, например, когда поступило новое полезное содержимое сетевых данных
в вашем сетевом сокете, или когда был добавлен новый блок данных
на ваше устройство.readyRead () не генерируется рекурсивно; если вы повторно входите в цикл событий
или вызвать waitForReadyRead () внутри слота, подключенного к readyRead ()
сигнал, сигнал не будет переиздан (хотя waitForReadyRead ()
может еще вернуть true).
Если это должно привести к каким-либо проблемам в вашем случае, вы можете использовать цикл while, где вы проверяете bytesAvailable ().
Используйте концепцию Thread здесь, используя потоки, вы можете достичь этого … запустите ваш portread в отдельном потоке, тогда он будет работать нормально, в противном случае сообщение будет вырезано.
другой метод: вы можете использовать Qprocess и открыть новый терминал с помощью QProcess и отправить номер порта и информацию о подключении к этому терминалу и запустить его из Qt, тогда вы также можете заархивировать это
Я имею в виду, что мы можем использовать Therad и сокет связи здесь, посмотрите на этот код
QTcpSocket *SocketTest::getSocket() {
return socket;
}
void SocketTest::Connect()
{
socket = new QTcpSocket(this);
socket->connectToHost("127.0.0.1",22);
if(socket->waitForConnected(3000))
{
qDebug()<<"connect";
socket->waitForBytesWritten(3000);
socket->waitForReadyRead(1000);
Settings::sockdata=socket->readAll();
qDebug()<<Settingssock::sockets;
socket->close();
}
else
{
qDebug()<<" not connect";
}
}............ call socket
SocketTest sock;
sock.Connect();
QTcpSocket * socket = sock.getSocket();
QObject *ob= new QThread;
mythread thread1(socket);
thread = new mythread(socket);
thread.run();
thread->start();
thread->wait();
это простой пример подключения через telnet, также вы можете указать, к какому порту вы хотите подключиться и к какому ip-порту