- C++ linux detect all serial ports
- 3 Answers 3
- How to list all serial ports on Linux
- Background
- What do you need
- Listing the serial ports using a Linux GUI application
- Listing the serial ports using the Linux terminal
- Bash alias for listing the serial ports
- Wrap up
- How to find all serial devices (ttyS, ttyUSB, ..) on Linux without opening them?
- Update
C++ linux detect all serial ports
Is there a good way of detecting all connected devices connected on serial ports on linux? Im programming in C++ but other examples are welcome as well. You can just try to open every port and when it succeeds you add it to the list of ports but this seems not a really good solution. You could go into the dev directors and since my serial port is a USB port I can check which ttyUSB.. files have been made. But this doesn’t work for non USB serial ports since files for tty0 up to tty63 are always in this directory. My example:
std::string port; int fd std::vector> list; for(int i = 0; i < 256; ++i) < port.clear(); port.append("/dev/ttyUSB"); port.append(std::to_string(i)); fd = open(port.c_str(), O_RDWR | O_NOCTTY | O_DELAY); if(fd != -1) < list.push_back(port); >>
This gives me the feel of an XY question, where your actual problem is X, and you think the solution is Y, so you ask for Y. Why do you want to know about serial ports on the system?
On 1 of the ports a zigbee device is connected. Since I want to make it user friendly I want to list all possibilities so that the user can pick. Normally if you plug in your zigbee device you should get exactly one port number returned to you. @Hasturkun In my case since my serial device uses a USB connection it is named ttyUSB0.
in theory you could do the same for /dev/ttyX if you want normal serial ports. But again not the best way to go.
3 Answers 3
The standard way of enumerating devices in Linux is to browse the /sys filesystem. In this case, you can to the following:
- Enumerate all files in /sys/class/tty
- For each directory /sys/class/tty/foo , check if /sys/class/tty/foo/device exists using lstat() .
- If it does not exist then you are dealing with some kind of virtual tty device (virtual console port, ptmx, etc. ) and you can discard it.
- If it exists then retain serial port foo .
You should be left with a list of actual serial ports.
I get 32 devices via this mechanism. 2 are valid. You need to check that it’s not pointing at serial8250 , which is actually just the driver
On several of my systems, I have real valid serial ports where the device symlink points to serial8250 . I’m not sure why you get so many invalid ones.
the 32 comes from the kernel config value CONFIG_SERIAL_8250_RUNTIME_UARTS , I presume it’s to support more than the default 32 (this is an x64 3.2 kernel).
If I just chek sys/class/tty/ttyS.. then I find a device folder in all of them. So that is probably how Petesh gets to 32 since ttyS goes from 0 to 31.
@Lotharyx You can use udevadm info /sys/class/tty/
Given that a number of years have passed since this was answered I am adding this answer. This answer works for later versions of linux. It also uses the new std::filesystem introduced in c++17. std::filesystem is available in earlier versions of c++ either through boost or in the namespace std::experimental::filesystem (use #include ). If using boost you must include compiled component system
This example also works out the where the symlink points to and returns it’s canonical name.
#include #include #include #include using std::cout; namespace fs = boost::filesystem; std::vector get_available_ports() < std::vectorport_names; fs::path p("/dev/serial/by-id"); try < if (!exists(p)) < throw std::runtime_error(p.generic_string() + " does not exist"); >else < for (fs::directory_entry &de : fs::directory_iterator(p)) < if (is_symlink(de.symlink_status())) < fs::path symlink_points_at = read_symlink(de); fs::path canonical_path = fs::canonical(symlink_points_at, p); port_names.push_back(canonical_path.generic_string()); >> > > catch (const fs::filesystem_error &ex) < cout std::sort(port_names.begin(), port_names.end()); return port_names; >
How to list all serial ports on Linux
Linux comes with serial communication functionality built-in. Before you can communicate with a device, connected to your PC’s serial port, you just need to know the name of the serial port. On Windows it is typically COM1 , COM2 , etc. On Linux it is essentially a filename in the format of /dev/ttyS0 , /dev/ttyUSB0 or /dev/ttyACM0 . This article explains how to list all serial ports on a Linux based system.
Background
Especially when developing software for or interacting with microcontroller based systems, you often communicate using RS232 serial communication. Typically by means of an RS232-to-USB adapter. To communicate with an RS232 device, you need to know the name of the PC’s serial port to connect to. On Windows, you open up the device manager and look up the COM-port number. Listing the available serial ports on Linux is a bit different and desktop environments do not offer a graphical user interface to quickly identify the available serial ports. This article presents two methods for listing the serial ports on Linux. One with the help of a graphical user interface program and another one for working directly in the terminal.
What do you need
To complete the steps to list the available serial ports on Linux, you just need two things:
- A Linux based PC. It can be a desktop, server, virtual machine or a single board computer such as a Raspberry PI.
- A serial device connected to the PC. For example an RS232-to-USB adapter, an Arduino or a Raspberry Pico.
For this article I’ll be using my main openSUSE Tumbleweed system. It’s a Lenovo ThinkCentre with one actual physical serial port. Additionally, I connected two serial devices: An RS232-to-USB adapter and an Arduino Uno.
Listing the serial ports using a Linux GUI application
Unfortunately, Linux desktop environments do not offer a GUI program to quickly and conveniently show all the available serial ports. However we can simply install one that does. Chances are you want a GUI program for monitoring the serial port in Linux anyway. My recommendation: CuteCom. Installation instructions for CuteCom on popular Linux distributions:
- Debian and Ubuntu: sudo apt install cutecom
- Fedora: sudo dnf install cutecom
- openSUSE: sudo zypper install cutecom
Once installed, open up the CuteCom program. It shows a Device drop-down list on the top of the main window. And voilà, it lists all serial ports on your Linux system:
As you can see in the screenshot, CuteCom lists all three serial ports currently connected to my Linux system:
- /dev/ttyS0 → The physical serial port on my PC.
- /dev/ttyUSB0 → The RS232-to-USB adapter.
- /dev/ttyACM0 → The Arduino Uno board connected via USB cable.
Listing the serial ports using the Linux terminal
The past section showed that Linux assigns a file name to serial devices with the acronym TTY in it. TTY stands for teletypewriter. With these historical devices you could send typed text messages to a remote location, using serial communication. Eventually leading to the invention of the fax machine. Hardly anyone still uses these devices. Nevertheless, the term TTY stuck around.
When it comes to using the terminal to list the serial ports, I prefer the approach that looks for TTY devices that the Linux kernel detected. Basically those that it found and managed to assign a driver to. The following command lists all of these:
- ls -l /sys/class/tty/*/device/driver
That’s a long list. I expected just three devices. The command output includes all so-called virtual and pseudo terminals. We just want to list the actual hardware serial ports. We can filter out the ones we don’t want by removing all lines that contain platform/drivers/serial8250 . The command then becomes:
- ls -l /sys/class/tty/*/device/driver | grep -v «platform/drivers/serial8250»
Alright, that looks a lot better. The output lists the three TTY devices that I expected: ttyACM0 , ttyS0 and ttyUSB0 . Ideally, the output shows just the actual device filename, needed to connect to the serial port. With a little akw magic, we can clean the output up for this:
- ls -l /sys/class/tty/*/device/driver | grep -v «platform/drivers/serial8250″ | awk » | awk -F’/’ »
Bash alias for listing the serial ports
I enjoy making one-liners for the terminal to get stuff done. However, the length of this one is such that I will never remember it. And I bet that’s the thought that crossed your mind too. Two options to solve this:
- Bookmark this page in your web browser and visit it whenever you need to list the serial ports from the terminal.
- Create a Bash alias.
With a Bash alias you essentially add a new command to your user’s shell with a name of your choice. Aliases are stored in the .bashrc file inside your home directory. You can edit it with whatever text editor you prefer. I’ll just use good old Nano:
Once in the text editor, add the following line. Note that escape characters were added where needed, to make it work. That’s before every double-quote and dollar sign:
- alias lsserial=»ls -l /sys/class/tty/*/device/driver | grep -v \»platform/drivers/serial8250\» | awk » | awk -F’/’ »»
Once done, save your .bashrc file and type this command to reload it:
Alternatively, you can just close and reopen your terminal program.
From now on you can list the available serial ports on your Linux PC, by simply typing this command in the terminal:
- lsserial
Wrap up
This article presented you with two different methods for listing the available serial ports on your Linux PC.
- Using the CuteCom GUI application.
- Piping several commands together for a terminal one-liner.
Going with method two, this article explained how you can add a Bash alias for the constructed terminal one-liner. Afterwards you can list the serial devices by simply typing the lsserial command in the terminal.
If you work with serial ports in Linux, you might be interested in one of the other serial port related articles:
How to find all serial devices (ttyS, ttyUSB, ..) on Linux without opening them?
What is the proper way to get a list of all available serial ports/devices on a Linux system? In other words, when I iterate over all devices in /dev/ , how do I tell which ones are serial ports in the classic way, that is, those usually supporting baud rates and RTS/CTS flow control? The solution would be coded in C. I ask because I am using a third-party library that does this clearly wrong: It appears to only iterate over /dev/ttyS* . The problem is that there are, for instance, serial ports over USB (provided by USB-RS232 adapters), and those are listed under /dev/ttyUSB*. And reading the Serial-HOWTO at Linux.org, I get the idea that there’ll be other name spaces as well, as time comes. So I need to find the official way to detect serial devices. The problem is that none appears to be documented, or I can’t find it. I imagine one way would be to open all files from /dev/tty* and call a specific ioctl() on them that is only available on serial devices. Would that be a good solution, though?
Update
hrickards suggested to look at the source for «setserial». Its code does exactly what I had in mind: First, it opens a device with:
fd = open (path, O_RDWR | O_NONBLOCK)
ioctl (fd, TIOCGSERIAL, &serinfo)
If that call returns no error, then it’s a serial device, apparently. I found similar code in Serial Programming/termios, which suggested to also add the O_NOCTTY option. There is one problem with this approach, though: When I tested this code on BSD Unix (that is, Mac OS X), it worked as well. However, serial devices that are provided through Bluetooth cause the system (driver) to try to connect to the Bluetooth device, which takes a while before it’ll return with a timeout error. This is caused by just opening the device. And I can imagine that similar things can happen on Linux as well — ideally, I should not need to open the device to figure out its type. I wonder if there’s also a way to invoke ioctl functions without an open, or open a device in a way that it does not cause connections to be made? What should I do?