¿Cuál es la forma correcta de obtener una lista de todos los puertos / dispositivos serie disponibles en un sistema Linux?
En otras palabras, cuando itero sobre todos los dispositivos /dev/
, ¿cómo puedo saber cuáles son los puertos serie de la forma clásica, es decir, los que suelen admitir velocidades en baudios y control de flujo RTS / CTS ?
La solución estaría codificada en C.
Lo pregunto porque estoy usando una biblioteca de terceros que hace esto claramente mal: parece que solo se repite /dev/ttyS*
. El problema es que existen, por ejemplo, puertos seriales a través de USB (proporcionados por adaptadores USB-RS232), y estos se enumeran en / dev / ttyUSB *. Y leyendo el Serial-HOWTO en Linux.org , tengo la idea de que también habrá otros espacios de nombres, a medida que llegue el momento.
Entonces necesito encontrar la forma oficial de detectar dispositivos seriales. El problema es que ninguno parece estar documentado o no puedo encontrarlo.
Imagino que una forma sería abrir todos los archivos de /dev/tty*
y llamar a uno específico ioctl()
que solo está disponible en dispositivos seriales. Sin embargo, ¿sería esa una buena solución?
Actualizar
hrickards sugirió buscar en la fuente de "setserial". Su código hace exactamente lo que tenía en mente:
Primero, abre un dispositivo con:
fd = open (path, O_RDWR | O_NONBLOCK)
Entonces invoca:
ioctl (fd, TIOCGSERIAL, &serinfo)
Si esa llamada no devuelve ningún error, aparentemente es un dispositivo en serie.
Encontré un código similar en Serial Programming / termios , que sugirió agregar también la O_NOCTTY
opción.
Sin embargo, hay un problema con este enfoque:
Cuando probé este código en BSD Unix (es decir, Mac OS X), también funcionó. Sin embargo , los dispositivos en serie que se proporcionan a través de Bluetooth hacen que el sistema (controlador) intente conectarse al dispositivo Bluetooth, lo que demora un tiempo antes de que vuelva con un error de tiempo de espera. Esto se debe a que simplemente abre el dispositivo. Y puedo imaginar que cosas similares también pueden suceder en Linux; idealmente, no debería necesitar abrir el dispositivo para averiguar su tipo. Me pregunto si también hay una manera de invocar ioctl
funciones sin abrir, o abrir un dispositivo de una manera que no provoque conexiones.
¿Qué tengo que hacer?
fuente
Respuestas:
El
/sys
sistema de archivos debe contener mucha información para su búsqueda. Mi sistema (2.6.32-40-generic # 87-Ubuntu) sugiere:Lo que le brinda descripciones de todos los dispositivos TTY conocidos por el sistema. Un ejemplo recortado:
Siguiendo uno de estos enlaces:
Aquí el
dev
archivo contiene esta información:Este es el nodo mayor / menor. Estos se pueden buscar en el
/dev
directorio para obtener nombres fáciles de usar:El
/sys/class/tty
directorio contiene todos los dispositivos TTY, pero es posible que desee excluir esos molestos terminales virtuales y pseudo terminales. Le sugiero que examine solo aquellos que tienen unadevice/driver
entrada:fuente
/dev/zero
. ¿De verdad crees que este es un dispositivo en serie?En los kernels recientes (no estoy seguro desde cuándo) puede enumerar el contenido de / dev / serial para obtener una lista de los puertos seriales de su sistema. En realidad, son enlaces simbólicos que apuntan al nodo / dev / correcto:
Este es un adaptador USB-Serie, como puede ver. Tenga en cuenta que cuando no hay puertos serie en el sistema, el directorio / dev / serial / no existe. Espero que esto ayude :).
fuente
Estoy haciendo algo como el siguiente código. Funciona para dispositivos USB y también para los estúpidos dispositivos serial8250 de los que todos tenemos 30, pero solo un par de ellos realmente funcionan.
Básicamente utilizo el concepto de respuestas anteriores. Primero enumere todos los dispositivos tty en / sys / class / tty /. Los dispositivos que no contienen un subdirectorio / device se filtran. / sys / class / tty / console es uno de estos dispositivos. Luego, los dispositivos que realmente contienen un dispositivo se aceptan como puerto serie válido según el destino del controlador-enlace simbólico fx.
y para ttyS0
Todos los controladores controlados por serial8250 deben ser sondas que utilicen el ioctl mencionado anteriormente.
Solo el puerto que informa un tipo de dispositivo válido es válido.
La fuente completa para enumerar los puertos de serie se ve así. Las adiciones son bienvenidas.
fuente
Creo que encontré la respuesta en la documentación de las fuentes de mi kernel: /usr/src/linux-2.6.37-rc3/Documentation/filesystems/proc.txt
Aquí hay un enlace a este archivo: http://git.kernel.org/?p=linux/kernel/git/next/linux-next.git;a=blob_plain;f=Documentation/filesystems/proc.txt;hb = e8883f8057c0f7c9950fa9f20568f37bfa62f34a
fuente
encontré
haciendo el trabajo.
fuente
setserial con la opción -g parece hacer lo que desea y la fuente C está disponible en http://www.koders.com/c/fid39344DABD14604E70DF1B8FEA7D920A94AF78BF8.aspx .
fuente
No tengo un dispositivo serial aquí para probarlo, pero si tiene python y dbus, puede probarlo usted mismo.
Si falla, puede buscar adentro
hwmanager_i.GetAllDevicesWithProperties()
para ver si el nombre de capacidad "serial" que supuse tiene un nombre diferente.HTH
fuente
No tengo un dispositivo serie USB, pero debe haber una forma de encontrar los puertos reales usando las bibliotecas HAL directamente:
El código python-dbus publicado ni este script sh enumeran los dispositivos bluetooth / dev / rfcomm *, por lo que no es la mejor solución.
Tenga en cuenta que en otras plataformas Unix, los puertos serie no se denominan ttyS? e incluso en linux, algunas tarjetas seriales le permiten nombrar los dispositivos. Asumir un patrón en los nombres de los dispositivos seriales es incorrecto.
fuente
El uso de / proc / tty / drivers solo indica qué controladores tty están cargados. Si está buscando una lista de los puertos serie, consulte / dev / serial, tendrá dos subdirectorios: by-id y by-path.
EX:
Gracias a esta publicación: /superuser/131044/how-do-i-know-which-dev-ttys-is-my-serial-port
fuente
Mi enfoque a través de la marcación grupal para obtener cada tty con el usuario 'dialout'
ls -l /dev/tty* | grep 'dialout'
para obtener solo su carpetals -l /dev/tty* | grep 'dialout' | rev | cut -d " " -f1 | rev
Escuche fácilmente la salida tty, por ejemplo, cuando arduino serial out:
head --lines 1 < /dev/ttyUSB0
escuche cada tty para una sola línea:
for i in $(ls -l /dev/tty* | grep 'dialout' | rev | cut -d " " -f1 | rev); do head --lines 1 < $i; done
Realmente me gusta el enfoque mediante la búsqueda de controladores:
ll /sys/class/tty/*/device/driver
Puede elegir el nombre tty ahora:
ls /sys/class/tty/*/device/driver | grep 'driver' | cut -d "/" -f 5
fuente
La biblioteca del administrador de comunicaciones en serie tiene muchas API y funciones destinadas a la tarea que desea. Si el dispositivo es un USB-UART, se puede utilizar su VID / PID. Si el dispositivo es BT-SPP, se pueden utilizar API específicas de la plataforma. Eche un vistazo a este proyecto para la programación de puertos serie: https://github.com/RishiGupta12/serial-communication-manager
fuente
sí, lo sé, llego demasiado tarde (como siempre). Aquí está mi código (basado en la respuesta de mk2). Quizás esto ayude a alguien:
fuente