I want to communicate with other devices with serial port (UART) in my C++ application.
I don’t know what the best and easiest library for the C++ language is.
I have to read and write byte arrays and I want to flush the rx and tx line.
how can I do that?
If the port is already set up, then you just read or write the port like a file. You can also sync or flush like any other file.
Incidentally, if you were to use a C-style fprintf or read, you’d simply wrap it with extern “C”. You can use ordinary C++ I/O as well.
The default for Jetson ports is 115200 8N1. Traditionally, one would tend to use an
ioctl call when setting up if the port is not already what you want for settings. If you use the C-style
ioctl, then just wrap it extern “C”. Note that
ioctl talks directly to the driver of the device you use it with, so the
ioctl function depends on which driver runs the device special file.
Incidentally, look at who owns the device special file before using it. For example, if you are using “
ls -l /dev/ttyTHS0
If the owner is
console, then this is in use by serial console. If the owner is
dialout, then it is free to use. If the group is
dialout, then you could either operate on the port as root (
sudo), or you could add your user to group
dialout. If your user name is “
nvidia”, then you could add your user to group
dialout like this:
sudo usermod -aG dialout nvidia
thank you for your help
could you please show me a sample code on this function that you say?
like read, write, and flush the rx and tx.
or let me know if there is any documentation for this method.
Just treat it like a file. Use
fstream to open your device special file read/write. A nice example, although not specific to device special files:
Which serial port do you want to open? Perhaps it is something like “
/dev/ttyTHS0”? If so, just substitute that for the file name in the example on that URL. From there
sync() can be used, and those are members of your
iostream). A great C++ reference is here:
You can look up the member methods to your stream class.
All of that assumes you’ve set up the port speed and settings. If you are running at speed 115200, 8-bit data, no parity bit, and one stop bit, then there is no need to change anything (and no need to deal with
ioctl). To learn more about the C
ioctl, if the man pages are installed, see “
man ioctl”. More description:
I’m not sure I can give you a good
ioctl description or example. When it comes to
ioctl, the argument being passed depends on the particular driver which created the device special file. It is often said in any *NIX environment, e.g., Linux, that “everything is a file”. That’s true for reading, writing, opening, closing, dealing with buffers, so on. However, there are operations which simply don’t exist for some drivers. UARTs in general have a speed (baud rate), but regular files do not, and although ethernet has a speed, it isn’t set as a baud rate. Within UARTs it depends on the chipset driver what
ioctl to use, e.g., you might find a different
ioctl for changing something based on one manufacturer versus another. Historically, there are the older 16450 UARTs, then 16550 UARTs, then 16550A UARTs, which the Tegra SoCs can be set to emulate any one of those. The 16550A is what serial UARTs using the legacy port would use, and those in turn have the naming convention “
# is a number from
0 or higher). That same UART might have a naming convention like “
/dev/ttyTHS#”, which means a different driver created it, and this means the
ioctl is custom to that driver.
FYI, files of the name “
/dev/ttyS#” can be the same exact hardware as a file of the name “
/dev/ttyTHS#”. This is the case because the Tegra UARTs are compatible with both legacy drivers and with their “Tegra High Speed” (THS) drivers, and when using the ttyTHS driver, DMA is available (but you don’t need to change anything to use DMA, it just happens if you use the ttyTHS device special file). You wouldn’t want to use both the
ttyTHS# driver simultaneously, but look at this and you will see both versions exist:
ls -l /dev/ttyS* /dev/ttyTHS*
Trivia: The reason both exist is that (A) the UART can be set up as either, and (B) third party software used during boot, e.g., the bootloader itself, usually does not understand the ttyTHS version. The implication is that if you want a serial console to log or interact with the bootloader, when the bootloader software is from a third party, then you cannot use the
ttyTHS driver unless you’ve customized the bootloader. Thus pretty much the only time people use the
ttyS# legacy driver is if (A) the operation has to exist in boot stages, or (B) the software is from a third party which doesn’t understand that this is a serial UART.
As for the list of
ioctl control calls which actually set up speed, parity, bits, stop bits, so on, I don’t know from memory. Someone from NVIDIA would have to give the
ioctl calls for controlling the THS driver. Most people just set up the UART to default to what they want it to be during boot (which can be accomplished via the device tree). Are you ok with running with the default setting of 115200 baud, 8-bit, no stop bits, and one parity bit? If so, you don’t even need to worry about it.
thank you so much for your help @linuxdev
your explanation was very helpful 🖐🌸
have a good day ❤
This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.