У меня проблема при чтении с последовательного порта.
Проблема заключается в том, что последние 2 байта (байты CRC) считываются из rs232
порт, который ожидает чтение, пока тайм-аут не установлен в timeval
заканчивается, потом возвращается. На rs485
, с тем же методом, который используется для чтения, чтение возвращает нормально. То, что я видел во время отладки, это то, что на rs485
есть дополнительный байт со значением FF
после 2 байтов CRC. Я не могу найти другую разницу между 2.
Вот соответствующие части кода:
настройка порта
bool Serial::setup(){if(!openPort()){
return false;
}
tcgetattr(fdPort, &options);
cfsetispeed(&options, B115200);
cfsetospeed(&options, B115200);
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
options.c_cc[VMIN] = 0;
options.c_cc[VTIME] = 1;
options.c_oflag &= ~(OCRNL | ONLCR | ONLRET |
ONOCR | OFILL | OLCUC | OPOST);
options.c_iflag &= ~(IGNBRK | BRKINT | ICRNL | INLCR |
PARMRK | INPCK | ISTRIP | IXON) ;
options.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN | ISIG);
if(tcsetattr(this->fdPort, TCSANOW, &options)){
return false;
}
return true;
}
открытие порта
bool Serial::openPort(){
this->fdPort = open(this->port, O_RDWR | O_NOCTTY | O_NDELAY | O_NONBLOCK);
if(fdPort == -1){
return false;
}
else{
//fcntl(fdPort, F_SETFL, 0);
//fcntl(fdPort, F_SETFL, FNDELAY);
}
int status = 0;
status |= TIOCM_RTS;
ioctl(this->fdPort, TIOCMSET, &status);
return true;
}
Кадр ожидания, где данные интерпретируются и читаются порциями.
bool GlobalProtocol::WaitFrame(uint32_t timeOut) {
int32_t bytesRec = 0;
int32_t bytesToRec = 1;
int recPhase = GC_PHASE_START;
uint8_t *pData = m_RxBuff;
bool commSuccess = true;
m_LastError = boards::GCL_ERR_OK;
while (readData(pData, bytesToRec, &bytesRec, timeOut)) {
if (bytesRec) {
switch (recPhase) {
case GC_PHASE_START:
if (*pData != GC_START_FRAME_BYTE) {
continue;
}
recPhase++;
pData++;
break;
case GC_PHASE_DEST:
if (*pData != m_MasterAddr) {
commSuccess = false;
break;
}
recPhase++;
pData++;
break;
case GC_PHASE_SRC:
recPhase++;
pData++;
break;
case GC_PHASE_LEN_LO:
if (*pData < 2 || *pData > GC_MAX_COMM_DATA_LEN) {
commSuccess = false;
break;
}
recPhase++;
pData++;
break;
case GC_PHASE_LEN_HI:
if (*pData != 0) {
commSuccess = false;
break;
}
recPhase++;
pData++;
bytesToRec = m_RxBuff[GC_PHASE_LEN_LO];
break;
case GC_PHASE_DATA:
if (bytesRec != bytesToRec) {
commSuccess = false;
break;
}
recPhase++;
pData += bytesRec;
bytesToRec = 2;
break;
case GC_PHASE_CRC_LO:
if (bytesRec != bytesToRec) {
commSuccess = false;
break;
}
if (CheckCRC(m_RxBuff, m_RxBuff[GC_PHASE_LEN_LO] + GC_PHASE_DATA + sizeof(uint16_t))) {
m_RecAddr = m_RxBuff[GC_PHASE_SRC];
return true;
}
commSuccess = false;
break;
}
if (!commSuccess) break;
}
else break;
}
m_LastError = boards::GCL_ERR_ANSWERNOTREC;
return false;
}
И где чтение сделано.
bool Serial::readData(uint8_t *data, uint32_t length, int32_t *receivedDataBytes, int32_t timeoutVal){
int32_t tempReceivedDataBytes = -1;
fd_set readFd;
FD_ZERO(&readFd);
FD_SET(fdPort, &readFd);
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = timeoutVal * 1000;
int test = 0;
uint32_t bytesAvail = 0;
QTime timer;
timer.start();
if(fcntl(fdPort, F_GETFD) != -1){
while(((test = select(this->fdPort + 1, &readFd, NULL, NULL, &timeout)) == 1) && (tempReceivedDataBytes == -1)){
ioctl(fdPort, FIONREAD, &bytesAvail);
if(FD_ISSET(fdPort, &readFd) && bytesAvail >= length){
tempReceivedDataBytes = read(fdPort, data, length);
}
if(timer.elapsed() > (timeoutVal + 5)){ //fail-safe
logger[debug_log] << "TIMEOUT" << endl;
break;
}
}
if(test == -1)
logger[debug_log]<< strerror(errno) << endl;
if(tempReceivedDataBytes < 0){
return false;
}
if(tempReceivedDataBytes >= 0){
*receivedDataBytes = tempReceivedDataBytes;
return true;
}
}
return false;
}
Если я установлю тайм-аут на 100 мс, то он будет ждать 100 мс, чтобы прочитать 2 байта, если я установлю его на 10 мс, то он будет ждать 10 мс, чтобы прочитать 2 байта.
Я попытался изменить настройки порта, но безуспешно.
Я пытался решить это в течение нескольких дней, но безуспешно.
Редактировать:
Я должен добавить, что ioctl(fdPort, FIONREAD, &bytesAvail);
устанавливает bytesAvail
до 2, но read
ждет до истечения времени ожидания, чтобы прочитать их.
Изменить 2:
Вот журнал с тайм-аутом, установленным на 25 секунд, чтобы вы могли понять, в чем проблема:
04/17/2014 15:51:50:584,Main board start:
04/17/2014 15:51:50:586,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:586,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:586,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:587,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:587,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:597,1 Received 110 Needed to receive 110
04/17/2014 15:51:50:597,1 Received 2 Needed to receive 2
04/17/2014 15:51:50:634,PID board start:
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:635,1 Received 1 Needed to receive 1
04/17/2014 15:51:50:641,1 Received 70 Needed to receive 70
04/17/2014 15:52:15:647,0 Received 2 Needed to receive 2
04/17/2014 15:52:15:647,Set Leds board start:
04/17/2014 15:52:15:649,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:649,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:652,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:652,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:652,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:652,1 Received 2 Needed to receive 2
04/17/2014 15:52:15:652,1 Received 2 Needed to receive 2
04/17/2014 15:52:15:652,Get state board start:
04/17/2014 15:52:15:654,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:654,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:654,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:654,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:655,1 Received 1 Needed to receive 1
04/17/2014 15:52:15:657,1 Received 30 Needed to receive 30
04/17/2014 15:52:15:657,1 Received 2 Needed to receive 2
Одной из проблем является плата PID (на RS232), остальные на той же RS485.
И вот один с таймаутом около 30 мс (я не могу вспомнить точное значение):
04/17/2014 15:08:08:045,Main board start:
04/17/2014 15:08:08:046,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:046,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:046,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:047,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:047,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:056,1 Received 110 Needed to receive 110
04/17/2014 15:08:08:056,1 Received 2 Needed to receive 2
04/17/2014 15:08:08:078,PID board start:
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:079,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:094,1 Received 70 Needed to receive 70
04/17/2014 15:08:08:120,0 Received 2 Needed to receive 2
04/17/2014 15:08:08:120,Set Leds board start:
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:122,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:122,1 Received 2 Needed to receive 2
04/17/2014 15:08:08:122,1 Received 2 Needed to receive 2
04/17/2014 15:08:08:123,Get state board start:
04/17/2014 15:08:08:124,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:124,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:124,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:125,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:125,1 Received 1 Needed to receive 1
04/17/2014 15:08:08:128,1 Received 30 Needed to receive 30
04/17/2014 15:08:08:128,1 Received 2 Needed to receive 2
Редактировать: я до сих пор не могу понять, что не так. Если я уберу лишний байт на rs485, это то же самое. Вот еще один журнал:
06/24/2014 12:57:01:923,Set Leds board start:
06/24/2014 12:57:06:701,Select value 1 Received: 1 Needed: 1 Bytes available: 9
06/24/2014 12:57:06:701,Select value 1 Received: 1 Needed: 1 Bytes available: 8
06/24/2014 12:57:06:702,Select value 1 Received: 1 Needed: 1 Bytes available: 7
06/24/2014 12:57:06:702,Select value 1 Received: 1 Needed: 1 Bytes available: 6
06/24/2014 12:57:06:702,Select value 1 Received: 1 Needed: 1 Bytes available: 5
06/24/2014 12:57:06:702,Select value 1 Received: 2 Needed: 2 Bytes available: 4
06/24/2014 12:57:06:752,Select value 0 Received: 2 Needed: 2 Bytes available: 2
06/24/2014 12:57:06:752,Get state board start:
06/24/2014 12:57:06:754,Select value 1 Received: 1 Needed: 1 Bytes available: 4
06/24/2014 12:57:06:754,Select value 1 Received: 1 Needed: 1 Bytes available: 3
06/24/2014 12:57:06:754,Select value 1 Received: 1 Needed: 1 Bytes available: 2
06/24/2014 12:57:06:754,Select value 1 Received: 1 Needed: 1 Bytes available: 1
06/24/2014 12:57:06:755,Select value 1 Received: 1 Needed: 1 Bytes available: 10
06/24/2014 12:57:06:758,Select value 1 Received: 30 Needed: 30 Bytes available: 30
06/24/2014 12:57:06:808,Select value 0 Received: 2 Needed: 2 Bytes available: 2
06/24/2014 12:57:06:886,Main board start:
06/24/2014 12:57:06:888,Select value 1 Received: 1 Needed: 1 Bytes available: 3
06/24/2014 12:57:06:888,Select value 1 Received: 1 Needed: 1 Bytes available: 2
06/24/2014 12:57:06:889,Select value 1 Received: 1 Needed: 1 Bytes available: 1
06/24/2014 12:57:06:890,Select value 1 Received: 1 Needed: 1 Bytes available: 23
06/24/2014 12:57:06:890,Select value 1 Received: 1 Needed: 1 Bytes available: 22
06/24/2014 12:57:06:898,Select value 1 Received: 110 Needed: 110 Bytes available: 113
06/24/2014 12:57:06:898,Select value 1 Received: 2 Needed: 2 Bytes available: 3
Как вы можете видеть, когда число доступных байтов равно количеству байтов для чтения, он ждет в функции чтения до истечения времени ожидания и затем возвращается.
Какое оборудование вы используете? Реальный последовательный порт или USB-адаптер? Некоторые адаптеры FTDI от usb к последовательному интерфейсу настроены таким образом, что они посылают байты через usb порциями Это ускоряет передачу, когда порт полностью загружен, но они ведут себя так, как вы упомянули при работе с несколькими байтами за раз.
Мне удалось это исправить. Это было просто исправить.
Я должен был заменить while(((test = select(this->fdPort + 1, &readFd, NULL, NULL, &timeout)) == 1) && (tempReceivedDataBytes == -1))
с while( (tempReceivedDataBytes == -1) && ((test = select(this->fdPort + 1, &readFd, NULL, NULL, &timeout)) == 1))
,
Если последовательный буфер был пуст, он ожидал select
до таймаута, даже если он что-то прочитал. Если в порту что-то было, он проверял вторую часть времени и выходил из него.
Установите ненулевое значение VMIN, чтобы чтение могло быть выполнено, как только по крайней мере что много символов было получено.
Это будет означать, что:
Если данные не были буферизованы, вызов будет ожидать тайм-аут для некоторых данных
Если по крайней мере символы VMIN были буферизованы, вызов немедленно возвращается вместе с ними, не дожидаясь истечения времени ожидания.