Linux下使用C/C++获取可用串口

        最近在Jetson Nano上发现个问题,插多个USB-TTL后,串口号会发生变化。看来笔者之前

C/C++语言读写UART或USB串口数据https://blog.csdn.net/qq_25662827/article/details/122581819的同学应该都知道,笔者在代码中是将端口号写死了的。

        面对多变的串口,我们应该怎么办呢?本篇笔者就分享一下,使用C/C++获取可用串口的方法。


        之前也说过,LIUNX下万物皆文件,每个串口的注册实际上就会生成一个文件,我们要获取可用串口,也就是要查找当前的文件名。废话不多说,还是先献上代码:

#include <stdlib.h>
#include <dirent.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <linux/serial.h>
#include <iostream>
#include <list>

using namespace std;

static string get_driver(const string& tty);
static void register_comport( list<string>& comList, list<string>& comList8250, const string& dir);
static void probe_serial8250_comports(list<string>& comList, list<string> comList8250);
list<string> getComList();

int main() {
    list<string> l = getComList();

    list<string>::iterator it = l.begin();
    while (it != l.end()) {
        cout << *it << endl;
        it++;
    }

    return 0;   
}

static string get_driver(const string& tty) {
    struct stat st;
    string devicedir = tty;

    // Append '/device' to the tty-path
    devicedir += "/device";

    // Stat the devicedir and handle it if it is a symlink
    if (lstat(devicedir.c_str(), &st)==0 && S_ISLNK(st.st_mode)) {
        char buffer[1024];
        memset(buffer, 0, sizeof(buffer));

        // Append '/driver' and return basename of the target
        devicedir += "/driver";

        if (readlink(devicedir.c_str(), buffer, sizeof(buffer)) > 0)
            return basename(buffer);
    }
    return "";
}

static void register_comport( list<string>& comList, list<string>& comList8250, const string& dir) {
    // Get the driver the device is using
    string driver = get_driver(dir);

    // Skip devices without a driver
    if (driver.size() > 0) {
        string devfile = string("/dev/") + basename(dir.c_str());

        // Put serial8250-devices in a seperate list
        if (driver == "serial8250") {
            comList8250.push_back(devfile);
        } else
            comList.push_back(devfile); 
    }
}

static void probe_serial8250_comports(list<string>& comList, list<string> comList8250) {
    struct serial_struct serinfo;
    list<string>::iterator it = comList8250.begin();

    // Iterate over all serial8250-devices
    while (it != comList8250.end()) {

        // Try to open the device
        int fd = open((*it).c_str(), O_RDWR | O_NONBLOCK | O_NOCTTY);

        if (fd >= 0) {
            // Get serial_info
            if (ioctl(fd, TIOCGSERIAL, &serinfo)==0) {
                // If device type is no PORT_UNKNOWN we accept the port
                if (serinfo.type != PORT_UNKNOWN)
                    comList.push_back(*it);
            }
            close(fd);
        }
        it ++;
    }
}

list<string> getComList() {
    int n;
    struct dirent **namelist;
    list<string> comList;
    list<string> comList8250;
    const char* sysdir = "/sys/class/tty/";

    // Scan through /sys/class/tty - it contains all tty-devices in the system
    n = scandir(sysdir, &namelist, NULL, NULL);
    if (n < 0)
        perror("scandir");
    else {
        while (n--) {
            if (strcmp(namelist[n]->d_name,"..") && strcmp(namelist[n]->d_name,".")) {

                // Construct full absolute file path
                string devicedir = sysdir;
                devicedir += namelist[n]->d_name;

                // Register the device
                register_comport(comList, comList8250, devicedir);
            }
            free(namelist[n]);
        }
        free(namelist);
    }

    // Only non-serial8250 has been added to comList without any further testing
    // serial8250-devices must be probe to check for validity
    probe_serial8250_comports(comList, comList8250);

    // Return the lsit of detected comports
    return comList;
}

 笔者将代码文件命名为find.cpp,因此用命令行编译为

g++ -o find.o find.cpp

测试

在Jetson Nano B01下进行测试。

在没有插入设备的时候,由于板子自带了RX TX引脚,因此能获得三个串口设备

然后,插上了USB-TTL后,可以得到

多了个ttyUSB1。


优化

这个方法在单端口设备的时候挺有用,我们的目标仅仅是获取ttyUSB*,怎么办呢?我们只需要在main里面做改动。

    while (it != l.end()) {
        // cout << *it << endl;
        string temp = *it;
        cout << temp << endl;
        if(temp.find("/dev/ttyUSB") != string::npos)
            cout << "1" << endl;
        it++;
    }

这段代码,实现了当发现ttyUSB*的时候就打个1出来。测试情况如下:

 其他改动,就留给读者结合自己的项目情况自行展开了吧。


闲谈

那么多端口设备怎么办?笔者的方法的话,会再加个端口信息校验。当连接上串口后,通过接收到设备信息来进行设备身份识别。具体的实现方法就读者自己完善吧,自己动手,丰衣足食。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星羽空间

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值