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
'programing' 카테고리의 다른 글
UnicodeDecodeError : 'ascii'코덱이 위치 1의 바이트 0xef를 디코딩 할 수 없습니다. (0) | 2020.08.15 |
---|---|
Angular Material 2 구성 요소의 'cdk'는 무엇입니까? (0) | 2020.08.15 |
XML과 XSD의 차이점은 무엇입니까? (0) | 2020.08.14 |
자바에서 파일 읽기를 방해하는 바이트 순서 표시 (0) | 2020.08.14 |
Image.Save (..)에서 메모리 스트림이 닫히기 때문에 GDI + 예외가 발생합니다. (0) | 2020.08.14 |