Jetson Nx Uart communiation lost first byte

I write a uart program using c++ on Jetson Nx(Jetpack 4.6.1,Ubuntu version 18.04 LTS) to communicate with a PC. On PC there’s a uart simulator( as below figure 1) sending data at a period of one second, 30 bytes data are : EB90021112131415161718191A1B1C1D1E1F202122232425262728292A2B

When my program receive the data, it will lost the first byte “EB”, and sometimes more bytes are lost. as show in figure 2:

My c code is as below.

#include <iostream>
#include <unistd.h>
#include <sys/fcntl.h>
#include <termios.h>
#include <string.h>

using namespace std;

int TestUart(const char * portName, int nSpeed, int nBits, char nEvent, int nStop);

int main() {
    TestUart("/dev/ttyUSB0", 9600, 8, 'N', 1);
    return 0;
}


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;
    }
    newtio = oldtio;

    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;

    unsigned char rx_data[256];

    while (1)
    {
        int m_curPacket_length = read(Port, rx_data, 256);
        tcflush(Port, TCIFLUSH);
        tcflush(Port, TCIOFLUSH);

		if (m_curPacket_length <= 0) continue;

        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");
    }

    return 0;
}

Besides, I tried more tests:
1 C code check. I run my c code on a PC( Ubuntu 18.04.6 LTS os on a windows virtual machine), it doesn’t lost byte. As show in figure 3 above:

2 I changed my c code as below ,set a un-blocking mode, it will not lost any data. Thren I change back to blocking mode as below, it won’t lost any data; and then I restart the Nx, and run my original code(blocking mode), the lost first byte appears.
3 I tried two third party softwares on Nx to receive data, CuteCom won’t lost first data while MiniCom lost first byte, the same problem. Test figure as Figure 4 above:
(CuteCom not lost first byte, Note this tiem sending data are EB901f1112……1c1d)

Figure 5 (Mini Com Lost first byte ‘EB’, note sending data are eb901f1112…28cb146c)

I expect anyone can help me, thanks a lot!

hello npulrj,

had you try to disable getty for testing?
for example,
$ sudo systemctl stop nvgetty.service
$ sudo systemctl disable nvgetty.service

1 Like

thanks a lot for your advice, and it really works.
i wonder what’s the nvgetty.service used for? is there any side-effects if it’s disabled?
Can you give me more explanation or some materials to looks for?
Thanks very much again!

You were using a UART which was already in use for the serial console. The nvgetty.service is the serial console once Linux is running (there might be something related to serial console during boot stages which is separate from Linux which still runs). If you look at this command you will see which group is associated with various serial devices:
ls -l /dev/ttyS* /dev/ttyUSB* /dev/ttyTHS* /dev/ttyCUA*
(this includes two common serial drivers on a Jetson, plus some you might see on the host PC if it has serial devices)

Those which have group “dialout” are free to use. Those which are group “tty” are not available and are owned by a console program. You could run this command before and after “sudo systemctl start nvgetty.service” and “sudo systemctl stop nvgetty.service” to see group.

Incidentally, “sudo systemctl disable nvgetty.service” just changes to not enable the service at boot, but if it was already running, then you would have to “stop” the service first if you were going to avoid reboot. You can run “start” and “stop” without changing the permanent config (meaning you can have it disabled and start or stop this without enable or disable status changing…“start” and “stop” are the program, “disable” and “enable” are the configuration viewed at boot).

Thanks for your kindly explanation,i tried, but found a confused result, i tried to run below command:
ls -l /dev/ttyS* /dev/ttyUSB* /dev/ttyTHS* /dev/ttyCUA*
and found once I start the service ttyTh0 would be in group “tty” even if i stop the service, it can only restore to dialout when Nx reboot. as show below.

I can’t actually tell what all of the response is to those ls commands. You could create an actual text file and upload the file:
ls -l /dev/ttyS* /dev/ttyUSB* /dev/ttyTHS* /dev/ttyCUA* 2>&1 | tee log_tty_permissions.txt
(then upload/attach “log_tty_permissions.txt”)

Note that only serial device consoles would revert from group tty to dialout. However, ttyTHS0 is in fact a serial device, and so if this is run via service nvgetty.service, then the combination of stopping nvgetty.service, and also disabling nvgetty.service, should cause it to revert to group dialout. One reboot should not be needed, but is advisable. If you run the command “sudo systemctl status nvgetty.service”, does it show that it is “active” still?

thanks, and i tried. But it seems once start a serial device console and group convert to tty, it no longer get back to dialout, even if service or serial program is stoped, as show below:

kz@JetsonNx:~$ ls -l /dev/ttyS* /dev/ttyUSB* /dev/ttyTHS* /dev/ttyCUDA*
ls: 无法访问’/dev/ttyUSB*‘: 没有那个文件或目录
ls: 无法访问’/dev/ttyCUDA*‘: 没有那个文件或目录
crw-rw---- 1 root dialout 4, 64 11月 23 13:12 /dev/ttyS0
crw-rw---- 1 root dialout 4, 65 11月 23 13:12 /dev/ttyS1
crw-rw---- 1 root dialout 4, 66 11月 23 13:12 /dev/ttyS2
crw-rw---- 1 root dialout 4, 67 11月 23 13:12 /dev/ttyS3
crw-rw---- 1 root dialout 238, 0 11月 23 13:12 /dev/ttyTHS0
crw-rw---- 1 root dialout 238, 1 11月 23 13:12 /dev/ttyTHS1
crw-rw---- 1 root dialout 238, 4 11月 23 13:12 /dev/ttyTHS4
kz@JetsonNx:~$ sudo systemctl start nvgetty.service
kz@JetsonNx:~$ ls -l /dev/ttyS* /dev/ttyUSB* /dev/ttyTHS* /dev/ttyCUDA*
ls: 无法访问’/dev/ttyUSB*‘: 没有那个文件或目录
ls: 无法访问’/dev/ttyCUDA*‘: 没有那个文件或目录
crw-rw---- 1 root dialout 4, 64 11月 23 13:12 /dev/ttyS0
crw-rw---- 1 root dialout 4, 65 11月 23 13:12 /dev/ttyS1
crw-rw---- 1 root dialout 4, 66 11月 23 13:12 /dev/ttyS2
crw-rw---- 1 root dialout 4, 67 11月 23 13:12 /dev/ttyS3
crw–w---- 1 root tty 238, 0 11月 23 19:14 /dev/ttyTHS0
crw-rw---- 1 root dialout 238, 1 11月 23 13:12 /dev/ttyTHS1
crw-rw---- 1 root dialout 238, 4 11月 23 13:12 /dev/ttyTHS4
kz@JetsonNx:~$ sudo systemctl stop nvgetty.service
kz@JetsonNx:~$ ls -l /dev/ttyS* /dev/ttyUSB* /dev/ttyTHS* /dev/ttyCUDA*
ls: 无法访问’/dev/ttyUSB*‘: 没有那个文件或目录
ls: 无法访问’/dev/ttyCUDA*': 没有那个文件或目录
crw-rw---- 1 root dialout 4, 64 11月 23 13:12 /dev/ttyS0
crw-rw---- 1 root dialout 4, 65 11月 23 13:12 /dev/ttyS1
crw-rw---- 1 root dialout 4, 66 11月 23 13:12 /dev/ttyS2
crw-rw---- 1 root dialout 4, 67 11月 23 13:12 /dev/ttyS3
crw–w---- 1 root tty 238, 0 11月 23 19:14 /dev/ttyTHS0
crw-rw---- 1 root dialout 238, 1 11月 23 13:12 /dev/ttyTHS1
crw-rw---- 1 root dialout 238, 4 11月 23 13:12 /dev/ttyTHS4
kz@JetsonNx:~$ sudo systemctl status nvgetty.service
● nvgetty.service - UART on ttyTHS0
Loaded: loaded (/etc/systemd/system/nvgetty.service; disabled; vendor preset: enabled)
Active: inactive (dead) since Wed 2022-11-23 19:14:51 CST; 34s ago
Process: 9737 ExecStart=/etc/systemd/nvgetty.sh (code=killed, signal=TERM)
Main PID: 9737 (code=killed, signal=TERM)

11月 23 19:14:40 JetsonNx systemd[1]: Started UART on ttyTHS0.
11月 23 19:14:51 JetsonNx systemd[1]: Stopping UART on ttyTHS0…
11月 23 19:14:51 JetsonNx systemd[1]: Stopped UART on ttyTHS0

Besides, back to the problem the post issued, as test result below:

So why they are different between blocking and unblocking, and why back to blocking it turned to work well?
I guess maybe different initailing state? or different work mode?

I can’t answer the blocking/non-blocking. However, which specific code are you referring to for this change? Is it from an ioctl call? Do you use the CTS/RTS wires, and enable/disable hardware flow control? Do you mean that upon switch to/from blocking/non-blocking that a previously buffered character suddenly shows up, or do you mean that in one mode it always works, and in the other mode it always fails?

Incidentally, have you tried this in loopback mode with TX and RX directly wired together without a long cable (and if flow control is used, CTS and RTS wired together)? Or is this entirely across two separate devices over a cable and not local to the Jetson?

At beginning, the code as post is blocking mode, and when running its first byte lost.
Then test as folling steps:

  1. I change the below code:
-   newtio.c_cc[VTIME] = 0;
-   newtio.c_cc[VMIN] = 1;
+   newtio.c_cc[VTIME] = 0;
+   newtio.c_cc[VMIN] = 0;

so this time it is non-blocking mode. when running this code, it won’t lost byte.

  1. and then change the above code back:
-   newtio.c_cc[VTIME] = 0;
-   newtio.c_cc[VMIN] = 0;
+  newtio.c_cc[VTIME] = 0;
+  newtio.c_cc[VMIN] = 1;

so now it’s blocking again as post. When running this time, it won’t lost byte.

  1. then I reboot the Jetson Nx, and run the code as post, and it lost byte again!

I hope I give a clear explanation!

So I doubt if there’s difference between blocking / non-blocking mode, such as initial the serial port configuation, and result the above case.

I’m not sure what code is actually doing when “newtio.c_cc[parameter key]” is changed. I am only guessing, but this is likely resulting in an ioctl() call, which in turn is custom to each driver (for example, this might differ if the port is accessed with a ttyS# port instead of a ttyTHS# port since drivers differ, and also would differ versus a ttyACM# or a ttyUSB#).

Regardless, someone who knows the specific driver will need to answer (likely someone from NVIDIA if using their serial UART driver). Plus, can you post what newtio.c_cc[] code is, or a man page, or a reference to find this online? I don’t know that specific call, and it is likely someone who has not used this directly also won’t recognize it.

Theanks for your kind advices.
there’s introduction of newtio.c_cc Noncanonical Input (The GNU C Library), and here Serial Programming Guide for POSIX Operating Systems (libero.it), in charpt" Control Characters"

It sounds like going through “newtio.c_cc[parameter key]” is actually designed to filter some content. If you simply run the UART in loopback mode and a terminal program, e.g., “gtkterm” or “minicom” or “PuTTY”, does the UART still have this issue? It would be good to confirm if the issue only occurs using the “Noncanonical Input” library. In any case where the library is sensative to “special editing characters” I also worry that the result will change depending on the terminal’s locale (or character set). If you directly use a terminal program without any of that other intervening software, it might turn out that it isn’t the UART making this byte disappear…it might be an intended filter.

Note that gtkterm has the ability to send a raw file, and to receive in hexadecimal mode. You can “sudo apt-get install gtkterm”. Then, assuming this is at settings of 115200 8N1, and that it is talking to “/dev/ttyUSB0” (which is not a Jetson hardware device, but instead is an external third party device using their driver…but standard on most all of Linux):
gtkterm -b 8 -t 1 -s 115200 -p /dev/ttyUSB0

For loopback mode one would normally wire TX directly to RX. In the case of a USB serial UART you might require an approximation of simply running gtkterm at both ends. One gtkterm sending a raw file and the other end reading with hexadecimal mode. You could then check that first byte.

OK, thanks a lot!
In fact, when I stop and disable nvgetty service using the following cmd, the problem won’t occure again. and I will try your advices!

$ sudo systemctl stop nvgetty.service
$ sudo systemctl disable nvgetty.service