Written on: 16. 05. 2022 [13:45]
|
Syberian
Oleg Dontsov
Topic creator
registered since: 11.04.2016
Posts: 3
|
Добрый день.
Проблема: При работе с транспортом Serial собственного протокола пользователя из ответа приходит только первый байт, остальное висит в буфере и может быть вычитано через cat /dev/ttyUSB0
Анализ:
Причина в файле mod_serial.cpp, функция TTrOut::MessIO, в функции приема:
// * Force wait any data in the request mode or EAGAIN
// * No wait any data in the not request mode but it can get the data later
for(int iRtr = 0; (((blen=read(fd,iBuf,iLen)) == 0 && !notReq) || (blen < 0 && errno == EAGAIN)) && iRtr < time; ++iRtr)
TSYS::sysSleep(1e-3);
При опросе готового модуля ModBus в функцию MessIO передается последним 5-м параметром таймаут ответа, который помещается в time. В пользовательском протоколе на входе 4 параметра, time по дефолту =0. Поэтому данная процедура выполняется всегда только 1 раз, после чего MessIO завершается, приняв только 1 байт ответа.
Решение:
Переписал этот участок кода так, чтобы при нулевом time таймаут брался из символьного таймаута в параметрах Serial, а чтение повторялось до тех пор, пока принимаются байты и нет символьного таймаута, либо пока не заполнен входной буфер.
//===============================================
/*
Процедура чтения до символьного либо общего (если указан) таймаута
Вход:
notReq - ответ НЕ требуется
blen - число принятых байт / еррор если < 0
time - таймаут с последнего символа входной
wCharTm - таймаут символа (мс)
Было раньше: чтение до таймаута time, blen не накапливается
Изменение: blen накапливает принятые байты, процедура чтения повторяется,
пока с последнего символа не вылезет таймаут WCharTm
READ выполняется в промежуточный буфер
*/
blen=0;
int iRtr=0;
int bidx=0; // index counter
ssize_t blen1=0;
int itmo;
itmo=time ? time : wCharTm;
while(1) {
TSYS::sysSleep(1e-3);
blen+=vmax(0,blen1);
blen1=read(fd, &iBuf[bidx],iLen-bidx);
if (blen1 < 0 && errno != EAGAIN) {blen=blen1; break;} // exit on error
if (blen1 == 0 && notReq) {blen=blen1;break;} //no response required
if (blen1 > 0) {iRtr=0; bidx+=blen1;} // clear last symbol timeout, move buffer index
if (iRtr++ >=itmo) {blen+=vmax(0,blen1); break;} // timeout exit
}
//===============================================
|
Written on: 16. 05. 2022 [13:59]
|
roman
Roman Savochenko
Moderator Contributor Developer
registered since: 12.12.2007
Posts: 3750
|
Что не ошибка, тем более для LTS, поскольку этот протокол не предназначен для работы через Serial, а соответственно не имеет механизмов контроля целостности и ожидает как минимум прихода заголовка целиком, чего Serial не гарантирует!
Learn, learn and learn better than work, work and work.
|
Written on: 02. 05. 2023 [20:26]
|
roman
Roman Savochenko
Moderator Contributor Developer
registered since: 12.12.2007
Posts: 3750
|
"roman" wrote:
Что не ошибка, тем более для LTS, поскольку этот протокол не предназначен для работы через Serial, а соответственно не имеет механизмов контроля целостности и ожидает как минимум прихода заголовка целиком, чего Serial не гарантирует!
Сейчас Собственный Протокол отдельно ожидает заголовок, а потом весь ответ и корректно обрабатывает попытки и ошибки.
Ну и фрагментация чуть ли не по байтам для него не проблема, т.е. работает с Serial, что однако не снимает проблемы проверки целосности если этот Serial — реальная физическая шина с потенциальным искажением трафика.
Исправлено!
Learn, learn and learn better than work, work and work.
|