Puerto serie virtual para Linux

128

Necesito probar una aplicación de puerto serie en Linux, sin embargo, mi máquina de prueba solo tiene un puerto serie.

¿Hay alguna manera de agregar un puerto serie virtual a Linux y probar mi aplicación emulando un dispositivo a través de un shell o script?

Nota: No puedo reasignar el puerto, está codificado en ttys2 y necesito probar la aplicación tal como está escrita.

JeffV
fuente

Respuestas:

75

Puede usar un pty ("pseudo-teletipo", donde un puerto serie es un "teletipo real") para esto. Desde un extremo, abra /dev/ptyp5y luego adjunte su programa a /dev/ttyp5; ttyp5actuará como un puerto serie, pero enviará / recibirá todo lo que hace a través de / dev / ptyp5.

Si realmente lo necesitas para hablar con un archivo llamado /dev/ttys2, simplemente quita tu viejo /dev/ttys2del camino y crea un enlace simbólico de ptyp5a ttys2.

Por supuesto, puede usar otro número que no sea ptyp5. Quizás elija uno con un número alto para evitar duplicados, ya que todos sus terminales de inicio de sesión también usarán ptys.

Wikipedia tiene más información sobre ptys: http://en.wikipedia.org/wiki/Pseudo_terminal

Apenwarr
fuente
8
En Linux puede usar las llamadas al sistema openpty / forkpty. Vea la página del manual
Matthew Smith
8
¿Cómo crear un par de puertos serie virtuales mediante la herramienta de línea de comandos?
linjunhalida
8
tenga en cuenta que muchos parámetros del puerto serie, por ejemplo, baudios, paridad, control de flujo hw, tamaño de caracteres (?) no se implementan en pty, por lo tanto, es imposible probar su aplicación en presencia de errores de transmisión en serie.
Dima Tisnek
10
Esto es útil, pero describe los pseudo terminales BSD de "estilo antiguo". Los "pseudo terminales" UNIX 98 de "nuevo estilo" funcionan de manera un poco diferente; consulte la ptspágina de manual para obtener más detalles.
Craig McQueen
3
@LaszloPapp Me disculpo, estuve mintiendo todo el tiempo
Matthew Smith el
160

Complementando la respuesta de @ slonik.

Puede probar socat para crear un puerto serie virtual haciendo el siguiente procedimiento (probado en Ubuntu 12.04):

Abra una terminal (llamémosla Terminal 0) y ejecútela:

socat -d -d pty,raw,echo=0 pty,raw,echo=0

El código anterior devuelve:

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/2
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/3
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs [3,3] and [5,5]

Abra otra terminal y escriba (Terminal 1):

cat < /dev/pts/2

El nombre del puerto de este comando se puede cambiar de acuerdo con la PC. Depende de la salida anterior.

2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**2**
2013/11/01 13:47:27 socat[2506] N PTY is /dev/pts/**3**
2013/11/01 13:47:27 socat[2506] N starting data transfer loop with FDs 

debe usar el número disponible en el área resaltada.

Abra otra terminal y escriba (Terminal 2):

echo "Test" > /dev/pts/3

Ahora regrese a la Terminal 1 y verá la cadena "Prueba".

Cantoni
fuente
Esto funcionó mejor para mí que la respuesta de slonik, porque se asigna automáticamente a los archivos de puerto COM virtual y no tiene eco.
gbmhunter
77
Si desea un nombre de archivo reproducible, use link=/path/to/linkdespués de cada declaración de dispositivo (después de echo = 0). Por lo tanto, se puede utilizar en pruebas automatizadas. (como lo hace slonik en su respuesta)
Patrick B.
Esto funcionó exactamente como se mencionó. Me ayudó gracias.
nim118
1
Para crear un Pty que los enlaces a un puerto serie real: socat -d -d pty,raw,echo=0 /dev/ttyUSB5,raw,echo=0.
Penghe Geng
¿Puedo crear un puerto serie con nombres como en /dev/ttyS0lugar de /dev/pts/1?
mrid
48

Use socat para esto:

Por ejemplo:

socat PTY,link=/dev/ttyS10 PTY,link=/dev/ttyS11
slonik
fuente
¡Esto funcionó bien para mí, probado con minicom! Parece que la entrada a un terminal se repite en ambos (por lo que también reaparecerá en el terminal de entrada).
gbmhunter
1
No tengo el mismo comportamiento de eco ... minicom tiene una función de "eco local" ... pero cuando está desactivado, funciona exactamente como lo haría un puerto serie real. gracias por el consejo.
cptHammer
16

También hay tty0tty http://sourceforge.net/projects/tty0tty/ que es un verdadero emulador de módem nulo para Linux.

Es un módulo kernel simple: un pequeño archivo fuente. No sé por qué solo obtuvo el visto bueno en sourceforge, pero funciona bien para mí. Lo mejor es que también emula los pines de hardware (RTC / CTS DSR / DTR). ¡Incluso implementa los comandos iOTcl TIOCMGET / TIOCMSET y TIOCMIWAIT!

En un kernel reciente puede obtener errores de compilación. Esto es fácil de arreglar. Simplemente inserte algunas líneas en la parte superior del módulo / tty0tty.c source (después de incluir):

#ifndef init_MUTEX
#define init_MUTEX(x) sema_init((x),1)
#endif

Cuando se carga el módulo, crea 4 pares de puertos seriales. Los dispositivos son / dev / tnt0 a / dev / tnt7 donde tnt0 está conectado a tnt1, tnt2 está conectado a tnt3, etc. Es posible que deba corregir los permisos del archivo para poder usar los dispositivos.

editar:

Supongo que fui un poco rápido con mi entusiasmo. Si bien el controlador parece prometedor, parece inestable. No estoy seguro, pero creo que se estrelló una máquina en la oficina en la que estaba trabajando desde casa. No puedo comprobarlo hasta que vuelva a la oficina el lunes.

Lo segundo es que TIOCMIWAIT no funciona. El código parece copiarse de algún código de ejemplo "tiny tty". El manejo de TIOCMIWAIT parece estar en su lugar, pero nunca se activa porque falta la llamada correspondiente a wake_up_interruptible ().

editar:

El accidente en la oficina fue realmente culpa del conductor. Faltaba una inicialización y el código TIOCMIWAIT completamente no probado provocó un bloqueo de la máquina.

Pasé ayer y hoy reescribiendo el controlador. Hubo muchos problemas, pero ahora funciona bien para mí. Todavía falta código para el control de flujo de hardware administrado por el controlador, pero no lo necesito porque estaré administrando los pines yo mismo usando TIOCMGET / TIOCMSET / TIOCMIWAIT desde el código de modo de usuario.

Si alguien está interesado en mi versión del código, envíeme un mensaje y se lo enviaré.

Peter Remmers
fuente
2
Me interesaría ver tu código. ¿Puedes contribuir de nuevo al proyecto tty0tty? Sin embargo, preferiría ver a las personas mejorar el código pseudo-terminal en el kernel de Linux. Por ejemplo, agregue soporte de apretón de manos de hardware y TIOCMIWAIT.
Craig McQueen
3
"Si alguien está interesado en mi versión del código, envíeme un mensaje y se lo enviaré". ¡Sí, estoy interesado! ¿Puedes señalarlo en algún lugar, por ejemplo, en GitHub?
Craig McQueen
77
Subí el controlador a: github.com/pitti98/nullmodem Lo siento, me tomó mucho tiempo responder. ¡No soy muy activo en stackoverflow y pasé por alto tu comentario!
Peter Remmers
No, lo escribí porque lo necesitaba y paré una vez que fue lo suficientemente bueno para hacer lo que quería. Ahora que es público, espero que sea útil para otra persona, y tal vez alguien retome donde lo dejé.
Peter Remmers
8

Es posible que desee ver Tibbo VSPDL para crear un puerto serie virtual de Linux utilizando un controlador Kernel: parece bastante nuevo y está disponible para descargar en este momento (versión beta). No estoy seguro acerca de la licencia en este momento, o si quieren que esté disponible comercialmente solo en el futuro.

Existen otras alternativas comerciales, como http://www.ttyredirector.com/ .

En Open Source, Remserial (GPL) también puede hacer lo que quiera, utilizando Unix PTY. Transmite los datos en serie en "forma cruda" a un socket de red; La configuración tipo STTY de los parámetros del terminal se debe realizar al crear el puerto; cambiarlos más tarde como se describe en RFC 2217 no parece ser compatible. Debería poder ejecutar dos instancias de remserial para crear un módem nulo virtual como com0com, excepto que deberá configurar la velocidad del puerto, etc. de antemano.

Socat (también GPL) es como una variante extendida de Remserial con muchas más opciones, incluido un método "PTY" para redirigir el PTY a otra cosa, que puede ser otra instancia de Socat. Para las unidades de prueba, es probable que socat sea más agradable que remserial porque puede capturar archivos directamente en el PTY. Vea el ejemplo de PTY en la página de manual. Existe un parche en "contrib" para proporcionar compatibilidad con RFC2217 para negociar configuraciones de línea serie.


fuente
6

Usando los enlaces publicados en las respuestas anteriores, codifiqué un pequeño ejemplo en C ++ usando un puerto serie virtual. Introduje el código en GitHub: https://github.com/cymait/virtual-serial-port-example .

El código se explica por sí mismo. Primero, crea el proceso maestro ejecutando ./main master e imprimirá para ejecutar el dispositivo que está utilizando. Después de eso, invocas ./main dispositivo esclavo, donde dispositivo es el dispositivo impreso en el primer comando.

Y eso es. Tiene un enlace bidireccional entre los dos procesos.

Con este ejemplo, puede probar la aplicación enviando todo tipo de datos y ver si funciona correctamente.

Además, siempre puede hacer un enlace simbólico del dispositivo, por lo que no necesita volver a compilar la aplicación que está probando.

Mauro Ciancio
fuente
1
while (read (fd, & inputbyte, 1) == 1) {...} leer no está definido en su código. escribir no está definido. cerrar es indefinido.
Mattis Asp
4

¿Sería capaz de usar un adaptador USB-> RS232? Tengo algunos, y solo usan el controlador FTDI. Luego, debería poder cambiar el nombre de / dev / ttyUSB0 (o ​​lo que se cree) como / dev / ttyS2.

Planchazo
fuente
4

Se me ocurren tres opciones:

Implementar RFC 2217

RFC 2217 cubre un puerto com para el estándar TCP / IP que permite a un cliente en un sistema emular un puerto serie a los programas locales, mientras envía y recibe de forma transparente datos y señales de control a un servidor en otro sistema que realmente tiene el puerto serie. Aquí hay una descripción general de alto nivel .

Lo que debería hacer es encontrar o implementar un controlador de puerto com del cliente que implemente el lado del cliente del sistema en su PC, pareciendo ser un puerto serie real pero en realidad transfiriendo todo a un servidor. Es posible que pueda obtener este controlador de forma gratuita de Digi, Lantronix, etc. en apoyo de sus servidores de puerto serie independientes reales.

Luego implementaría el lado del servidor de la conexión localmente en otro programa, permitiendo que el cliente se conecte y emitiendo los datos y los comandos de control según sea necesario.

Probablemente no sea trivial, pero el RFC está disponible y es posible que pueda encontrar un proyecto de código abierto que implemente uno o ambos lados de la conexión.

Modificar el controlador del puerto serie de Linux

Alternativamente, la fuente del controlador del puerto serie para Linux está fácilmente disponible. Tome eso, destripa las piezas de control de hardware y haga que ese controlador ejecute dos puertos / dev / ttySx, como un simple bucle invertido. Luego, conecte su programa real al ttyS2 y su simulador al otro ttySx.

Utilice dos cables serie USB <--> en un bucle invertido

¿Pero lo más fácil de hacer ahora? Gaste $ 40 en dos dispositivos USB de puerto serie, conéctelos (módem nulo) y, de hecho, tenga dos puertos serie reales: uno para el programa que está probando y otro para su simulador.

-Adán

Adam Davis
fuente
1
En realidad, los cables USB UART de módem nulo me parecen una solución bastante elegante, ya que admite pruebas locales (obtenga un concentrador USB si tiene pocos puertos) y depuración remota.
Maxthon Chan
No he revisado su calidad, pero ttynvt implementa RFC 2217 a través de Linux FUSE
Daniel Santos