I write a uart software using c on Jetson Nx(Ubuntu OS) to communicate with a PC. On PC there's a uart simulator to send data at a period of one second, data is :EB90021112131415161718191A1B1C1D1E1F202122232425262728292A as show below:
When my software receive the data, sometimes it will lost the first byte "EB", as show like this:
90021112131415161718191A1B1C1D1E1F202122232425262728292A
while sometimes it won't lost the first byte EB.
Besides, I tried a python software to receive data from uart on Jetson Nx, it always works OK.
My c code is as below.
int TestUart(const char * portName, int nSpeed, int nBits, char nEvent, int nStop);
void main(){
TestUart("/dev/ttyTHS0",9600,8,'N',1);
}
int TestUart(const char * portName, int nSpeed, int nBits, char nEvent, int nStop)
{
int Port = open(portName, O_RDWR | O_NOCTTY);
tcflush(Port, TCIFLUSH);
tcflush(Port, TCIOFLUSH);
usleep(500000);
if (Port == -1)
{
printf("UART.cpp : Unable to open port.");
return -1;
}
else
{
printf("UART.cpp : Port opened. Setting Port options...");
}
int fd = Port;
struct termios newtio, oldtio;
if (tcgetattr(fd, &oldtio) != 0)
{
perror("SetupSerial 1");
return -1;
}
bzero(&newtio, sizeof(newtio));
newtio.c_cflag |= CLOCAL | CREAD;
newtio.c_cflag &= ~CSIZE;
switch (nBits)
{
case 7:
newtio.c_cflag |= CS7;
break;
case 8:
newtio.c_cflag |= CS8;
break;
}
switch (nEvent)
{
case 'O':
case 'o':
newtio.c_cflag |= PARENB;
newtio.c_cflag |= PARODD;
break;
case 'E':
case 'e':
newtio.c_cflag |= PARENB;
newtio.c_cflag &= ~PARODD;
break;
case 'N':
case 'n':
newtio.c_cflag &= ~PARENB;
break;
}
cfsetispeed(&newtio,B9600);
cfsetospeed(&newtio,B9600);
newtio.c_cflag &= ~CRTSCTS;
newtio.c_iflag &= ~(IXON | IXOFF | IXANY);
if (nStop == 1)
{
newtio.c_cflag &= ~CSTOPB;
}
else if (nStop == 2)
{
newtio.c_cflag |= CSTOPB;
}
newtio.c_cc[VTIME] = 0;
newtio.c_cc[VMIN] = 1;
newtio.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
newtio.c_oflag &= ~OPOST;
if ((tcsetattr(fd, TCSANOW, &newtio)) != 0)
{
perror("com set error");
return -1;
}
tcflush(fd, TCIFLUSH);
int num = 0;
char rx_data[256];
while(1)
{
int m_curPacket_length = read(Port, rx_data,256);
tcflush(Port, TCIFLUSH);
tcflush(Port, TCIOFLUSH);
printf(" Data %d [port = %s,length = %d]: ", num,portName,m_curPacket_length);
for (int i = 0; i < m_curPacket_length; i ) {
printf("%X ", rx_data[i]);
}
printf("\n");
}
printf("set UART port paramster done!\n");
return 0;
}
I expect anyone can help me to find the bug. Thanks a lot!
Besides, when I set non-blocking mode with setting VTIME=0 and VMIN=0, there is no byte loss.
Hardware: My userspace program is running on Jetson Nx develop board, it commnunicate with a Pc. They connction with a USB TO TTL converter. as figure show below: enter image description here
CodePudding user response:
When my software receive the data, sometimes it will lost the first byte "EB", as show like this:
90021112131415161718191A1B1C1D1E1F202122232425262728292A
while sometimes it won't lost the first byte EB.
...
My c code is as below.
...
Assuming that the Jetson Nx is not horribly slow in comparison to the 9600 baud, executing your code as posted (on a PC) produces the following results for me:
$ ./a.out
UART.cpp : Port opened. Setting Port options... Data 1 [port = /dev/ttyUSB0,length = 1]: FFFFFFEB
Data 2 [port = /dev/ttyUSB0,length = 1]: FFFFFF90
Data 3 [port = /dev/ttyUSB0,length = 1]: 2
Data 4 [port = /dev/ttyUSB0,length = 1]: 11
Data 5 [port = /dev/ttyUSB0,length = 1]: 12
Data 6 [port = /dev/ttyUSB0,length = 1]: 13
Data 7 [port = /dev/ttyUSB0,length = 1]: 14
Data 8 [port = /dev/ttyUSB0,length = 1]: 15
Data 9 [port = /dev/ttyUSB0,length = 1]: 16
Data 10 [port = /dev/ttyUSB0,length = 1]: 17
Data 11 [port = /dev/ttyUSB0,length = 1]: 18
Data 12 [port = /dev/ttyUSB0,length = 1]: 19
Data 13 [port = /dev/ttyUSB0,length = 1]: 1A
Data 14 [port = /dev/ttyUSB0,length = 1]: 1B
Data 15 [port = /dev/ttyUSB0,length = 1]: 1C
Data 16 [port = /dev/ttyUSB0,length = 1]: 1D
Data 17 [port = /dev/ttyUSB0,length = 1]: 1E
Data 18 [port = /dev/ttyUSB0,length = 1]: 1F
Data 19 [port = /dev/ttyUSB0,length = 1]: 20
Data 20 [port = /dev/ttyUSB0,length = 1]: 21
Data 21 [port = /dev/ttyUSB0,length = 1]: 22
Data 22 [port = /dev/ttyUSB0,length = 1]: 23
Data 23 [port = /dev/ttyUSB0,length = 1]: 24
Data 24 [port = /dev/ttyUSB0,length = 1]: 25
Data 25 [port = /dev/ttyUSB0,length = 1]: 26
Data 26 [port = /dev/ttyUSB0,length = 1]: 27
Data 27 [port = /dev/ttyUSB0,length = 1]: 28
Data 28 [port = /dev/ttyUSB0,length = 1]: 29
Data 29 [port = /dev/ttyUSB0,length = 1]: 2A
This (poorly formated) result does not have any resemblance to the single line that you claim that you get.
More importantly there are no "missing" bytes as all 29 bytes of the message are always received and displayed, although there is an extended-sign issue with the first two bytes.
Besides, when I set non-blocking mode with setting VTIME=0 and VMIN=0, there is no byte loss.
Again your description of the results that you claim your code produces is inaccurate and misleading. You neglect to mention that your code will produce extraneous text while incessantly polling the system:
UART.cpp : Port opened. Setting Port options... Data 1 [port = /dev/ttyUSB0,length = 0]:
Data 2 [port = /dev/ttyUSB0,length = 0]:
Data 3 [port = /dev/ttyUSB0,length = 0]:
Data 4 [port = /dev/ttyUSB0,length = 0]:
Data 5 [port = /dev/ttyUSB0,length = 0]:
Data 6 [port = /dev/ttyUSB0,length = 0]:
Data 7 [port = /dev/ttyUSB0,length = 0]:
Data 8 [port = /dev/ttyUSB0,length = 0]:
Data 9 [port = /dev/ttyUSB0,length = 0]:
Data 10 [port = /dev/ttyUSB0,length = 0]:
Data 11 [port = /dev/ttyUSB0,length = 0]:
Data 12 [port = /dev/ttyUSB0,length = 0]:
Data 13 [port = /dev/ttyUSB0,length = 0]:
Data 14 [port = /dev/ttyUSB0,length = 0]:
Data 15 [port = /dev/ttyUSB0,length = 0]:
Data 16 [port = /dev/ttyUSB0,length = 0]:
Data 17 [port = /dev/ttyUSB0,length = 0]:
Data 18 [port = /dev/ttyUSB0,length = 0]:
Data 19 [port = /dev/ttyUSB0,length = 0]:
Data 20 [port = /dev/ttyUSB0,length = 0]:
Data 21 [port = /dev/ttyUSB0,length = 0]:
Data 22 [port = /dev/ttyUSB0,length = 0]:
...
How do manage to sort out the text that indicates received data versus the garbage of no input?
Your initialization is flawed because a zeroed-out termios struct is used. See Setting Terminal Modes Properly.
I have tried not zeroed-out termios struct is used, still the same problem remains.
if (tcgetattr(fd, &newtio) != 0) { perror("SetupSerial 1"); return -1; } //bzero(&newtio, sizeof(newtio));
You've done a poor job of following my advice, since you clearly did not bother to study the linked guide.
By simply deleting the bzero() statement, you are now using an uninitialized structure, which could be a worse bug and should have generated a compiler warning.
The proper correction to your code is (using patch notation):
- bzero(&newtio, sizeof(newtio));
newtio = oldtio;
Your userspace program is not synchronized with UART I/O, so flushing system buffers (discarding I/O data) is prone to inadvertent loss of real data. IOW you're misusing the flush directive
and when no flush as show below, still remains the problem
In turns out, despite the flaws in your code, I can use your original code to consistently receive the messages of 29 bytes on my PC. Although the flaws do not cause any observed misbehavior currently, they must be corrected for reliable and robust code.
I am unable to understand what you are calling "missing bytes". Is the sign-extended representation of the first two bytes the problem?
That is simply corrected by using the appropriate type for the receive buffer:
- char rx_data[256];
unsigned char rx_data[256];
Given that your system is receiving a message of 29 bytes each second, you can improve the efficiency of each read() syscall by trying to fetch a full message. Try changing the following termios attributes:
- newtio.c_cc[VTIME] = 0;
- newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 1;
newtio.c_cc[VMIN] = 29;
The program can then read a complete message per syscall:
$ ./a.out
UART.cpp : Port opened. Setting Port options...
Data 1 [port = /dev/ttyUSB0,length = 29]: EB 90 2 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A
Data 2 [port = /dev/ttyUSB0,length = 29]: EB 90 2 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A
CodePudding user response:
Thanks for your advice!
1 On Jetson Nx, it really have a different result as I mentiond in the problem. May be it's the difference of the handware? I add more hardware info on my main question borad.
This (poorly formated) result does not have any resemblance to the single line that you claim that you get. More importantly there are no "missing" bytes as all 29 bytes of the message are always received and displayed, although there is an extended-sign issue with the first two bytes.
2 Really igore the empty lines, that's just a try.
Again your description of the results that you claim your code produces is inaccurate and misleading. You neglect to mention that your code will produce extraneous text while incessantly polling the system:
3 Change as below, remains the same problem.
- bzero(&newtio, sizeof(newtio));
newtio = oldtio;
4 Below changed still no effect.
- char rx_data[256];
unsigned char rx_data[256];
5 Below changed will be print as follow:
- newtio.c_cc[VTIME] = 0;
- newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 1;
newtio.c_cc[VMIN] = 29;
print result: 90021112131415161718191A1B1C1D1E1F202122232425262728292AEB90021112131415161718191A1B1C1D1E1F202122232425262728292A
Still lost the first 'EB'