串行丢包 - QTSerialPort
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了串行丢包 - QTSerialPort相关的知识,希望对你有一定的参考价值。
我正在制作一个程序,以每秒250个样本(115200波特)读取来自串行RN42蓝牙连接的数据流。在运行代码时,我注意到有些数据没有被删除和读取,因此不同步。
SerialMonitor::SerialMonitor(QObject *parent) :
QObject(parent)
{
// Initialization here
DAQ = new QSerialPort(this);
DAQ->setPortName("/dev/tty.BIOEXG-SPP");
DAQ->setBaudRate(QSerialPort::Baud115200);
DAQ->setDataBits(QSerialPort::Data8);
DAQ->setParity(QSerialPort::NoParity);
DAQ->setStopBits(QSerialPort::OneStop);
DAQ->setFlowControl(QSerialPort::NoFlowControl);
if (DAQ->open(QIODevice::ReadOnly)) printf("Success!
");
else printf("FAILED...
");
connect(DAQ, SIGNAL(readyRead()), this, SLOT(WriteToText()));
}
void SerialMonitor::WriteToText()
{
while (DAQ->canReadLine()) {
QString IncomingData = DAQ->readLine();
// More processing here
}
}
}
我的代码有问题吗?如果没有,有没有办法解决这个问题?这是一个EEG设备,因此每个数据点都至关重要。
提前致谢!
答案
您已禁用所有错误检查和同步机制:
- 奇偶校验位已禁用。
- 流量控制已禁用。
如果您可以控制设备上的微控制器,那么一个很好的选择就是实现一个用于恢复丢失数据的chk机制。如果您的设备是黑盒子,则必须使用HW机制来提高稳定性。当使用无线通信时,存在丢失一些数据的可能性并且在项目中被考虑。
注意:您应该在打开之后设置串行参数,而不是之前。
另一答案
- 您可以尝试使用
bytesAvailable/readAll()
而不是(can)readLine()
进行检查。 - 驱动程序有可能无法及时从FIFO读取数据,从而导致数据丢失(可能是驱动程序问题)。
另一答案
我有同样的问题。 QSerialPort有时会丢失一些字节块。我修改了我在网上找到的一段旧代码,这不会丢失任何东西。
#include "QVSerialPort.hpp"
#include <QtDebug>
//////////////////////////////////////////
// Set header file for documentation /
////////////////////////////////////////
//////////////////////////////////////////////////////
// Windows Version of the serial port driver Code
/////////////////////////////////////////////////////
#ifdef Q_OS_WIN32
#include <windows.h>
QVSerialPort::QVSerialPort(QObject *parent) :
QThread(parent)
{
// make everything in this thread, run in this thread. (Including signals/slots)
QObject::moveToThread(this);
// make our data buffer
dataBuffer = new QByteArray();
hSerial = INVALID_HANDLE_VALUE;
running = true;
deviceName=NULL;
bufferSem = new QSemaphore(1); // control access to buffer
}
QVSerialPort::~QVSerialPort() {
running = false;
CloseHandle(hSerial);
}
//write data to serial port
int QVSerialPort::writeBuffer(QByteArray *buffer) {
int dwBytesRead = 0;
if (hSerial != INVALID_HANDLE_VALUE) {
// have a valid file discriptor
WriteFile(hSerial, buffer->constData(), buffer->size(), (DWORD *)&dwBytesRead, NULL);
return dwBytesRead;
} else {
return -1;
}
}
// setup what device we should use
void QVSerialPort::usePort(QString *device_Name, int _buad, int _byteSize, int _stopBits, int _parity) {
deviceName = new QString(device_Name->toLatin1());
// serial port settings
Buad = _buad;
ByteSize = _byteSize;
StopBits = _stopBits;
Parity = _parity;
}
// data fetcher, get next byte from buffer
uint8_t QVSerialPort::getNextByte() {
// mutex needed to make thread safe
bufferSem->acquire(1); // lock access to resource, or wait untill lock is avaliable
uint8_t byte = (uint8_t)dataBuffer->at(0); // get the top most byte
dataBuffer->remove(0, 1); // remove top most byte
bufferSem->release(1);
return byte; // return top most byte
}
// return number of bytes in receive buffer
uint32_t QVSerialPort::bytesAvailable() {
// this is thread safe, read only operation
bufferSem->acquire(1); // lock access to resource, or wait untill lock is avaliable
uint32_t res = (uint32_t)dataBuffer->size();
bufferSem->release(1);
return res;
}
// our main code thread
void QVSerialPort::run() {
// bufferSem->release(1); // not in a locked state
// thread procedure
if (_SERIALTHREAD_DEBUG) {
qDebug() << "QVSerialPort: QVSerialPort Started..";
qDebug() << "QVSerialPort: Openning serial port " << deviceName->toLatin1();
}
// open selected device
hSerial = CreateFile( (WCHAR *) deviceName->constData() , GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if ( hSerial == INVALID_HANDLE_VALUE ) {
qDebug() << "QVSerialPort: Failed to open serial port " << deviceName->toLatin1();
emit openPortFailed();
return; // exit thread
}
// Yay we are able to open device as read/write
qDebug() << "QVSerialPort: Opened serial port " << deviceName->toLatin1() << " Sucessfully!";
// now save current device/terminal settings
dcbSerialParams.DCBlength=sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams)) {
qDebug() << "QVSerialPort: Failed to get com port paramters";
emit openPortFailed();
return;
}
if (_SERIALTHREAD_DEBUG) {
qDebug() << "QVSerialPort: Serial port setup and ready for use";
qDebug() << "QVSerialPort: Starting QVSerialPort main loop";
}
dcbSerialParams.BaudRate=Buad;
dcbSerialParams.ByteSize=ByteSize;
dcbSerialParams.Parity=Parity;
dcbSerialParams.StopBits=StopBits;
if(!SetCommState(hSerial, &dcbSerialParams)) {
qDebug() << "QVSerialPort: Failed to set new com port paramters";
emit openPortFailed();
return;
}
COMMTIMEOUTS timeouts;
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutMultiplier = 1;
timeouts.WriteTotalTimeoutConstant = 1;
if (!SetCommTimeouts(hSerial, &timeouts)){
qDebug()<<" error setcommtimeout";
}
// signal we are opened and running
emit openPortSuccess();
static uint8_t byte123[1023]; // temp storage byte
int dwBytesRead;
int state=0; // state machine state
// start polling loop
while(running) {
int ret = ReadFile(hSerial, (void *)byte123, 128, (DWORD *)&dwBytesRead, NULL); // reading 1 byte at a time.. only 2400 baud.
// print what we received
if (ret != 0 && dwBytesRead > 0){
if (_SERIALTHREAD_DEBUG) {
qDebug() << "QVSerialPort: Received byte with value: " << byte123[0];
}
if (dataBuffer->size() > 1023*1024) {
if ( state == 0 ) {
qDebug() << "Local buffer overflow, dropping input serial port data";
state = 1; // over-flowed state
emit bufferOverflow();
}
} else {
if ( state == 1 ) {
qDebug() << "Local buffer no-longer overflowing, back to normal";
state = 0;;
}
// stick byte read from device into buffer
// Mutex needed to make thread safe from buffer read operation
bufferSem->acquire(1);
for (int i=0;i<dwBytesRead;i++)
dataBuffer->append(byte123[i]);
bufferSem->release(1);
emit hasData(); // signal our user that there is data to receive
}
}
}
CloseHandle(hSerial);
}
#else
//////////////////////////////////////////////////////////
// Linux/Mac/BSD Version of the serial port driver Code
////////////////////////////////////////////////////////
// POSIX C stuff for accessing the serial port
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
// Constructor
QVSerialPort::QVSerialPort(QObject *parent) :
QThread(parent)
{
// make everything in this thread, run in this thread. (Including signals/slots)
QObject::moveToThread(this);
// make our data buffer
dataBuffer = new QByteArray();
running = true;
deviceName=NULL;
bufferMutex = new QMutex(); // control access to buffer
bufferMutex->unlock(); // not in a locked state
}
QVSerialPort::~QVSerialPort() {
running = false;
close(sfd);
}
//write data to serial port
int QVSerialPort::writeBuffer(QByteArray *buffer) {
if (sfd != 0) {
// have a valid file discriptor
return write(sfd, buffer->constData(), buffer->size());
} else {
return -1;
}
}
// setup what device we should use
void QVSerialPort::usePort(QString *device_Name) {
deviceName = new QString(device_Name->toLatin1());
if (_SERIALTHREAD_DEBUG) {
qDebug() << "QVSerialPort: Using device: " << deviceName->toLatin1();
}
}
// data fetcher, get next byte from buffer
uint8_t QVSerialPort::g以上是关于串行丢包 - QTSerialPort的主要内容,如果未能解决你的问题,请参考以下文章
如何让 qtserialport 为 Native QT 的 NVIDIA TX1 工作?