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<std::string>> 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);
}
}
Thanks!
The standard way of enumerating devices in Linux is to browse the /sys
filesystem. In this case, you can to the following:
/sys/class/tty
/sys/class/tty/foo
, check if /sys/class/tty/foo/device
exists using lstat()
.
foo
.You should be left with a list of actual serial ports.
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 <experimental/filesystem>
). 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 <iostream>
#include <string>
#include <boost/filesystem.hpp>
#include <boost/asio.hpp>
using std::cout;
namespace fs = boost::filesystem;
std::vector<std::string> get_available_ports() {
std::vector<std::string> port_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 << ex.what() << '\n';
throw ex;
}
std::sort(port_names.begin(), port_names.end());
return port_names;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With