Linuxシステムで使用可能なすべてのシリアルポート/デバイスのリストを取得する適切な方法は何ですか?
言い換えると、/dev/
ですべてのデバイスを反復処理するとき、どのデバイスが従来の方法でシリアルポートであるか、つまり通常ボーレートと RTS/CTS フロー制御をサポートしているデバイスであるかをどのように確認できますか?
ソリューションはCでコーディングされます。
私はこれを明らかに間違っているサードパーティのライブラリを使用しているので、私は尋ねます:/dev/ttyS*
を反復処理するようです。問題は、たとえば、USB上のシリアルポート(USB-RS232アダプターが提供)があり、それらが/ dev/ttyUSB *の下にリストされていることです。 Serial-HOWTO at Linux.org を読むと、時が経つにつれて他の名前空間も存在するという考えが得られます。
そのため、シリアルデバイスを検出する公式の方法を見つける必要があります。問題は、文書化されていないように見えるか、見つからないことです。
1つの方法は、/dev/tty*
からすべてのファイルを開き、シリアルデバイスでのみ使用可能な特定のioctl()
を呼び出すことだと思います。しかし、それは良い解決策でしょうか?
hrickardsは、「setserial」のソースを調べることを提案しました。そのコードは、私が念頭に置いていたものとまったく同じです。
まず、デバイスを次のように開きます。
fd = open (path, O_RDWR | O_NONBLOCK)
次に、以下を呼び出します。
ioctl (fd, TIOCGSERIAL, &serinfo)
その呼び出しがエラーを返さない場合、それは明らかにシリアルデバイスです。
Serial Programming/termiosで同様のコードが見つかりました。これはO_NOCTTY
オプションも追加することを提案しました。
このアプローチには1つの問題があります:
このコードを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
dirにはすべての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デバイスや、私たち全員が持っている愚かなserial8250デバイスでも動作しますが、実際に動作するのはそのうちの2、3だけです。
基本的に、以前の回答の概念を使用します。最初に/ sys/class/tty /にあるすべてのttyデバイスを列挙します。/deviceサブディレクトリを含まないデバイスはフィルターで除外されます。/sys/class/tty/consoleはそのようなデバイスです。次に、実際にデバイスを含むデバイスは、driver-symlink 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オプションを指定したsetserialは、必要な処理を実行するように見え、Cソースは http://www.koders.com/c/fid39344DABD14604E70DF1B8FEA7D920A94AF78BF8.aspx で入手できます。
USBシリアルデバイスはありませんが、HALライブラリを直接使用して実際のポートを見つける方法が必要です。
====================================================================
#! /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
====================================================================
投稿されたpython-dbusコードもこのshスクリプトもbluetooth/dev/rfcomm *デバイスをリストしているため、これは最良の解決策ではありません。
他のUNIXプラットフォームでは、シリアルポートの名前はttySではないことに注意してください。 Linuxでも、一部のシリアルカードではデバイスに名前を付けることができます。シリアルデバイス名のパターンが間違っていると仮定します。
/ proc/tty/driversの使用は、どのttyドライバーがロードされているかを示すだけです。シリアルポートのリストを探している場合は、/ dev/serialをチェックアウトすると、by-idとby-pathの2つのサブディレクトリがあります。
例:
# find . -type l
./by-path/usb-0:1.1:1.0-port0
./by-id/usb-Prolific_Technology_Inc._USB-Serial_Controller-if00-port0
この投稿に感謝: https://superuser.com/questions/131044/how-do-i-know-which-dev-ttys-is-my-serial-port
テスト用のシリアルデバイスはここにありませんが、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")
失敗した場合は、hwmanager_i.GetAllDevicesWithProperties()
内を検索して、先ほど推測した機能名「シリアル」が別の名前であるかどうかを確認できます。
HTH
グループ経由の私のアプローチdialoutユーザー 'dialout'を持つすべてのttyを取得するls -l /dev/tty* | grep 'dialout'
そのフォルダーのみを取得するls -l /dev/tty* | grep 'dialout' | rev | cut -d " " -f1 | rev
tty出力を簡単に聞くArduinoシリアルアウト時:head --lines 1 < /dev/ttyUSB0
すべてのttyを1行だけリッスンします:for i in $(ls -l /dev/tty* | grep 'dialout' | rev | cut -d " " -f1 | rev); do head --lines 1 < $i; done
ドライバーを探すというアプローチが本当に好きです:ll /sys/class/tty/*/device/driver
Tty-Nameを今すぐ選択できます:ls /sys/class/tty/*/device/driver | grep 'driver' | cut -d "/" -f 5
シリアル通信マネージャーライブラリには、必要なタスクを対象とした多くのAPIと機能があります。デバイスがUSB-UARTの場合、そのVID/PIDを使用できます。デバイスがBT-SPPの場合、プラットフォーム固有のAPIを使用できます。シリアルポートプログラミングのこのプロジェクトを見てください: https://github.com/RishiGupta12/serial-communication-manager