programing

Linux에서 모든 직렬 장치 (ttyS, ttyUSB, ..)를 열지 않고 찾는 방법은 무엇입니까?

nasanasas 2020. 8. 15. 09:20
반응형

Linux에서 모든 직렬 장치 (ttyS, ttyUSB, ..)를 열지 않고 찾는 방법은 무엇입니까?


Linux 시스템에서 사용 가능한 모든 직렬 포트 / 장치 목록을 가져 오는 올바른 방법은 무엇입니까?

즉,에서 모든 장치를 반복 할 때 /dev/일반적인 방식으로 직렬 포트, 즉 일반적으로 전송 속도 및 RTS / CTS 흐름 제어를 지원하는 장치를 어떻게 알 수 있습니까?

솔루션은 C로 코딩됩니다.

나는 이것을 분명히 잘못하는 타사 라이브러리를 사용하고 있기 때문에 묻습니다 /dev/ttyS*.. 문제는 예를 들어 USB를 통한 직렬 포트 (USB-RS232 어댑터에서 제공)가 있고 해당 포트가 / dev / ttyUSB *에 나열되어 있다는 것입니다. 그리고 Linux.org에서 Serial-HOWTO를 읽으면서 시간이 다가옴 에 따라 다른 이름 공간도있을 것이라는 생각을 얻었습니다.

따라서 직렬 장치를 감지하는 공식적인 방법을 찾아야합니다. 문제는 문서화 된 것으로 보이지 않거나 찾을 수 없다는 것입니다.

한 가지 방법은 모든 파일을 열고 직렬 장치에서만 사용할 수 /dev/tty*있는 특정 파일을 호출하는 ioctl()것입니다. 그래도 좋은 해결책이 될까요?

최신 정보

hrickards 는 "setserial"에 대한 소스를 살펴볼 것을 제안했습니다. 그 코드는 내가 염두에 둔 것과 정확히 일치합니다.

먼저 다음과 같은 장치를 엽니 다.

fd = open (path, O_RDWR | O_NONBLOCK)

그런 다음 다음을 호출합니다.

ioctl (fd, TIOCGSERIAL, &serinfo)

해당 호출이 오류를 반환하지 않으면 분명히 직렬 장치입니다.

Serial Programming / termios 에서 유사한 코드를 발견 했는데 O_NOCTTY옵션을 추가 할 것을 제안했습니다 .

하지만이 접근 방식에는 한 가지 문제가 있습니다.

이 코드를 BSD Unix (즉, Mac OS X)에서 테스트했을 때도 작동했습니다. 그러나 Bluetooth를 통해 제공되는 직렬 장치는 시스템 (드라이버)이 Bluetooth 장치에 연결을 시도하게하여 시간 초과 오류와 함께 반환되기까지 시간이 걸립니다. 이것은 장치를 열기 만하면 발생합니다. 그리고 비슷한 일이 Linux에서도 발생할 수 있다고 상상할 수 있습니다. 이상적으로는 유형을 파악하기 위해 장치를 열 필요가 없습니다. ioctl열지 않고 함수 를 호출 하거나 연결을 일으키지 않는 방식으로 장치를 여는 방법도 있는지 궁금합니다 .

어떻게해야합니까?


/sys파일 시스템은 당신의 탐구에 대한 충분한 정보를 포함해야합니다. 내 시스템 (2.6.32-40-generic # 87-Ubuntu)은 다음을 제안합니다.

/sys/class/tty

시스템에 알려진 모든 TTY 장치에 대한 설명을 제공합니다. 정리 된 예 :

# ll /sys/class/tty/ttyUSB*
lrwxrwxrwx 1 root root 0 2012-03-28 20:43 /sys/class/tty/ttyUSB0 -> ../../devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.4/2-1.4:1.0/ttyUSB0/tty/ttyUSB0/
lrwxrwxrwx 1 root root 0 2012-03-28 20:44 /sys/class/tty/ttyUSB1 -> ../../devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.3/2-1.3:1.0/ttyUSB1/tty/ttyUSB1/

다음 링크 중 하나를 따르십시오.

# ll /sys/class/tty/ttyUSB0/
insgesamt 0
drwxr-xr-x 3 root root    0 2012-03-28 20:43 ./
drwxr-xr-x 3 root root    0 2012-03-28 20:43 ../
-r--r--r-- 1 root root 4096 2012-03-28 20:49 dev
lrwxrwxrwx 1 root root    0 2012-03-28 20:43 device -> ../../../ttyUSB0/
drwxr-xr-x 2 root root    0 2012-03-28 20:49 power/
lrwxrwxrwx 1 root root    0 2012-03-28 20:43 subsystem -> ../../../../../../../../../../class/tty/
-rw-r--r-- 1 root root 4096 2012-03-28 20:43 uevent

여기 dev파일에는 다음 정보가 포함됩니다.

# cat /sys/class/tty/ttyUSB0/dev
188:0

이것은 주 / 부 노드입니다. /dev사용자에게 친숙한 이름을 얻기 위해 디렉토리 에서 검색 할 수 있습니다 .

# ll -R /dev |grep "188, *0"
crw-rw----   1 root dialout 188,   0 2012-03-28 20:44 ttyUSB0

/sys/class/tty디렉토리는 모든 TTY 장치를 포함하지만 당신은 가상 터미널 및 의사 단자 그 성가신을 제외 할 수 있습니다. device/driver항목 이있는 항목 만 검사하는 것이 좋습니다 .

# ll /sys/class/tty/*/device/driver
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS0/device/driver -> ../../../bus/pnp/drivers/serial/
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS1/device/driver -> ../../../bus/pnp/drivers/serial/
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS2/device/driver -> ../../../bus/platform/drivers/serial8250/
lrwxrwxrwx 1 root root 0 2012-03-28 19:07 /sys/class/tty/ttyS3/device/driver -> ../../../bus/platform/drivers/serial8250/
lrwxrwxrwx 1 root root 0 2012-03-28 20:43 /sys/class/tty/ttyUSB0/device/driver -> ../../../../../../../../bus/usb-serial/drivers/ftdi_sio/
lrwxrwxrwx 1 root root 0 2012-03-28 21:15 /sys/class/tty/ttyUSB1/device/driver -> ../../../../../../../../bus/usb-serial/drivers/ftdi_sio/

최근 커널 (언제부터 확실하지 않음)에서는 / dev / serial의 내용을 나열하여 시스템의 직렬 포트 목록을 얻을 수 있습니다. 실제로 올바른 / dev / 노드를 가리키는 심볼릭 링크입니다.

flu0@laptop:~$ ls /dev/serial/
total 0
drwxr-xr-x 2 root root 60 2011-07-20 17:12 by-id/
drwxr-xr-x 2 root root 60 2011-07-20 17:12 by-path/
flu0@laptop:~$ ls /dev/serial/by-id/
total 0
lrwxrwxrwx 1 root root 13 2011-07-20 17:12 usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0 -> ../../ttyUSB0
flu0@laptop:~$ ls /dev/serial/by-path/
total 0
lrwxrwxrwx 1 root root 13 2011-07-20 17:12 pci-0000:00:0b.0-usb-0:3:1.0-port0 -> ../../ttyUSB0

보시다시피 이것은 USB 직렬 어댑터입니다. 시스템에 직렬 포트가 없으면 / dev / serial / 디렉토리가 존재하지 않습니다. 도움이 되었기를 바랍니다 :).


다음 코드와 같은 작업을하고 있습니다. USB 장치와 우리 모두가 30 개를 가지고있는 어리석은 serial8250 개발에서도 작동하지만 실제로는 몇 개만 작동합니다.

기본적으로 이전 답변의 개념을 사용합니다. 먼저 / sys / class / tty /에있는 모든 tty- 장치를 열거합니다. / device 하위 디렉터리를 포함하지 않는 장치는 필터링됩니다. / sys / class / tty / console은 그러한 장치입니다. 그런 다음 실제로 장치를 포함하는 장치는 드라이버 기호 링크 fx의 대상에 따라 유효한 직렬 포트로 허용됩니다.

$ ls -al /sys/class/tty/ttyUSB0//device/driver
lrwxrwxrwx 1 root root 0 sep  6 21:28 /sys/class/tty/ttyUSB0//device/driver -> ../../../bus/platform/drivers/usbserial

및 ttyS0의 경우

$ ls -al /sys/class/tty/ttyS0//device/driver
lrwxrwxrwx 1 root root 0 sep  6 21:28 /sys/class/tty/ttyS0//device/driver -> ../../../bus/platform/drivers/serial8250

serial8250에 의해 구동되는 모든 드라이버는 앞서 언급 한 ioctl을 사용하는 프로브 여야합니다.

        if (ioctl(fd, TIOCGSERIAL, &serinfo)==0) {
            // If device type is no PORT_UNKNOWN we accept the port
            if (serinfo.type != PORT_UNKNOWN)
                the_port_is_valid

유효한 장치 유형을보고하는 포트만 유효합니다.

직렬 포트를 열거하는 전체 소스는 다음과 같습니다. 추가를 환영합니다.

#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) {
    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;
}


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

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

    return 0;   
}

커널 소스 문서에서 답을 찾은 것 같습니다. /usr/src/linux-2.6.37-rc3/Documentation/filesystems/proc.txt

1.7 TTY info in /proc/tty
-------------------------

Information about  the  available  and actually used tty's can be found in the
directory /proc/tty.You'll  find  entries  for drivers and line disciplines in
this directory, as shown in Table 1-11.


Table 1-11: Files in /proc/tty
..............................................................................
 File          Content                                        
 drivers       list of drivers and their usage                
 ldiscs        registered line disciplines                    
 driver/serial usage statistic and status of single tty lines 
..............................................................................

To see  which  tty's  are  currently in use, you can simply look into the file
/proc/tty/drivers:

  > cat /proc/tty/drivers 
  pty_slave            /dev/pts      136   0-255 pty:slave 
  pty_master           /dev/ptm      128   0-255 pty:master 
  pty_slave            /dev/ttyp       3   0-255 pty:slave 
  pty_master           /dev/pty        2   0-255 pty:master 
  serial               /dev/cua        5   64-67 serial:callout 
  serial               /dev/ttyS       4   64-67 serial 
  /dev/tty0            /dev/tty0       4       0 system:vtmaster 
  /dev/ptmx            /dev/ptmx       5       2 system 
  /dev/console         /dev/console    5       1 system:console 
  /dev/tty             /dev/tty        5       0 system:/dev/tty 
  unknown              /dev/tty        4    1-63 console 

다음은이 파일에 대한 링크입니다. http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git;a=blob_plain;f=Documentation/filesystems/proc.txt;hb = e8883f8057c0f7c9950fa9f20568f37bfa62f34a


나는 발견했다

dmesg | grep tty

일을.


-g 옵션이있는 seterial은 원하는 작업을 수행하는 것으로 보이며 C 소스는 http://www.koders.com/c/fid39344DABD14604E70DF1B8FEA7D920A94AF78BF8.aspx 에서 사용할 수 있습니다 .


여기에는 테스트 할 직렬 장치가 없지만 python과 dbus가 있으면 직접 시도해 볼 수 있습니다.

import dbus
bus = dbus.SystemBus()
hwmanager = bus.get_object('org.freedesktop.Hal', '/org/freedesktop/Hal/Manager')
hwmanager_i = dbus.Interface(hwmanager, 'org.freedesktop.Hal.Manager')
print hwmanager_i.FindDeviceByCapability("serial")

If it fails you can search inside hwmanager_i.GetAllDevicesWithProperties() to see if the capability name "serial" that I just guessed has a different name.

HTH


I do not have a USB serial device, but there must be a way to find the real ports using the HAL libraries directly:

====================================================================
#! /usr/bin/env bash
#
# Uses HAL to find existing serial hardware
#

for sport in $(hal-find-by-capability --capability serial) ; do
  hal-get-property --udi "${sport}" --key serial.device
done

====================================================================

The posted python-dbus code nor this sh script lists the bluetooth /dev/rfcomm* devices, so it is not the best solution.

Note that on other unix platforms, the serial ports are not named ttyS? and even in linux, some serial cards allow you to name the devices. Assuming a pattern in the serial devices names is wrong.


Using /proc/tty/drivers only indicates which tty drivers are loaded. If you're looking for a list of the serial ports check out /dev/serial, it will have two subdirectories: by-id and by-path.

EX:

# find . -type l
./by-path/usb-0:1.1:1.0-port0
./by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0

Thanks to this post: https://superuser.com/questions/131044/how-do-i-know-which-dev-ttys-is-my-serial-port


My approach via group dialout to get every tty with user 'dialout' ls -l /dev/tty* | grep 'dialout' to only get its folder ls -l /dev/tty* | grep 'dialout' | rev | cut -d " " -f1 | rev

easy listen to the tty output e.g. when arduino serial out: head --lines 1 < /dev/ttyUSB0

listen to every tty out for one line only: for i in $(ls -l /dev/tty* | grep 'dialout' | rev | cut -d " " -f1 | rev); do head --lines 1 < $i; done

I really like the approach via looking for drivers: ll /sys/class/tty/*/device/driver

You can pick the tty-Name now: ls /sys/class/tty/*/device/driver | grep 'driver' | cut -d "/" -f 5


The serial communication manager library has many API and features targeted for the task you want. If the device is a USB-UART its VID/PID can be used. If the device is BT-SPP than platform specific APIs can be used. Take a look at this project for serial port programming: https://github.com/RishiGupta12/serial-communication-manager

참고URL : https://stackoverflow.com/questions/2530096/how-to-find-all-serial-devices-ttys-ttyusb-on-linux-without-opening-them

반응형