Solved Delayed readReady signal of QSerialPort
-
Hi J.Hilk
You are right, could have been done better. This way I prevent the GUI from freezing and return to the called line in my statemachine. However, could this eventloop cause the delay of the readyRead signal? -
I removed the eventloop and used a signal instead_
void IBHandler::slotRxComplete() { qDebug() << "Data received: " << m_rxMsgData.toHex('|'); disconnect(this, SIGNAL(communicationFinished()), this, SLOT(slotRxComplete())); emit sigRxComplete(m_rxStatus,m_rxMsgData); } RegGetStatusTypes IBHandler::readRegister(const quint8 devId, const quint8 regId) { if (m_serialport->isOpen()) { // Hookup the local eventloop connect(this, SIGNAL(communicationFinished()), this, SLOT(slotRxComplete())); // Send the message m_txMsgRetries = 3; // Max 3 message retries m_txCRCRetries = 3; m_txBUSYRetries = 3; m_msgService->slotSendMessage(devId, regId, msgRead, QByteArray()); return GetSuccess; } return GetPortClosed; }
Unfortunately this did not have any impact on the readyRead delay...
-
@dazi said in Delayed readReady signal of QSerialPort:
I prevent the GUI from freezing
If you want to prevent UI from freezing then do not use synchronous API, use the asynchronous one...
-
The code I posted previously is using the async API only. Everything is triggered by signals and processed by slots, but the delay of the readyRead signal remains.
-
I'm think, you can't improve the time. As it depends on a system scheduler, Qt-event loop and so on. Besides, the readyRead() signal triggering chain on windows is following:
- system RX event -> system start read FIFO -> system FIFO read complete event -> qt readyRead() signal.
PS: You can try to buy a more powerfull CPU. :)
PS2: You can look e.g. this: https://docs.microsoft.com/en-us/windows/win32/procthread/multitasking for your info.
PS3: Or, maybe, you can try to move your QSP instance to a separate thread and to give the 'highest' priority to that thread.
-
@kuzulis said in Delayed readReady signal of QSerialPort:
PS: You can try to buy a more powerfull CPU. :)
Well I hope an i7 core should be able to handle the serial port :)
I know that the PC is able to fetch data in a much higher rate. This GUI should actually replace a Labview program, which retrieves data like this (timebase of the scope is the same as in the picture above):
-
@dazi Are you using a real hardware RS-232 or an USB-serial adapter like FTDI? (which one?)
Because for the USB adapters there is a buffering involved which will delay the received data. For FTDI devices, you can reduce this delay in the advanced device settings down to one millisecond. I don't know if that's possible for other vendors.
Regards
-
@aha_1980 said in Delayed readReady signal of QSerialPort:
@dazi Are you using a real hardware RS-232 or an USB-serial adapter like FTDI? (which one?)
You are absolutly right! Thank you so much for pointing this out.
I'm using the FT232R USB to RS232 converter from FTDI, reduced the buffering time to 1ms and this is the result:
Do you know by any chance if this settings can be changed from the application?
-
@dazi said in Delayed readReady signal of QSerialPort:
Do you know by any chance if this settings can be changed from the application?
I'm sorry, no; but I would be interested in this answer also :) So if you find a solution, feel free to share.
Regards
-
but I would be interested in this answer also :)
As I remember, we did some project where we do changes for FTDI latency parameter:
#ifdef Q_OS_WIN // Возвращает указатель реестра для устройства с заданным именем, // если оно является последовательным портом FTDI, либо 0. HKEY openFtdiDeviceParameters(const QString &portName) { const wchar_t *keypath = L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS"; HKEY key; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keypath, 0, KEY_READ, &key)) { // Порты FTDI отсутствуют. return 0; } // Просматриваем все порты FTDI. int idx = 0; HKEY readOnlyKey = 0; HKEY paramKey = 0; while (true) { if (paramKey) { RegCloseKey(paramKey); paramKey = 0; } DWORD subkeySize = 140; wchar_t subKey[140] = {0}; // Последовательный порт не является устройством FTDI. if (RegEnumKeyEx(key, idx++, subKey, &subkeySize, 0, 0, 0, 0)) { break; } QString paramPath(QString(QLatin1String("%1\\0000\\Device Parameters")).arg(QString::fromWCharArray(subKey))); if (RegOpenKeyEx(key, paramPath.toStdWString().c_str(), 0, KEY_READ, &readOnlyKey)) { continue; } DWORD regPortNameSize = 20; wchar_t regPortName[20] = {0}; DWORD type = 0; LONG result = RegQueryValueEx(readOnlyKey, L"PortName", 0, &type, (LPBYTE) ®PortName, ®PortNameSize); if (ERROR_SUCCESS == result) { QString name = QString::fromWCharArray(regPortName); if (portName == name) { RegOpenKeyEx(readOnlyKey, 0, 0, KEY_READ | KEY_SET_VALUE, ¶mKey); } } RegCloseKey(readOnlyKey); if (paramKey) { break; } } RegCloseKey(key); return paramKey; } #endif
and then:
#ifdef Q_OS_WIN // Если выбранный порт является FTDI, устанавливаем его latency в 1. DWORD latency = 0; HKEY latencyKey = openFtdiDeviceParameters(name); DWORD dwType = 0; DWORD dwSize = sizeof(DWORD); bool foundFtdiDevice; if (latencyKey && !RegQueryValueEx(latencyKey, L"LatencyTimer", 0, &dwType, (LPBYTE) &latency, &dwSize) && dwType == REG_DWORD) { foundFtdiDevice = true; } else { foundFtdiDevice = false; } if (foundFtdiDevice) { if (latency != 1) { DWORD dwLatency = 1; RegSetValueEx(latencyKey, L"LatencyTimer", 0, REG_DWORD, (LPBYTE) &dwLatency, sizeof(DWORD)); RegCloseKey(latencyKey); } } #endif
Here we did set the latency to 1 msec.
PS: Sorry, all comments in russian (because it is copy-paste).