Comunicación serial falsa bajo Linux

Tengo una aplicación en la que quiero simular la conexión entre un dispositivo y un “módem”. El dispositivo se conectará a un puerto serie y se comunicará con el módem del software a través de este.

Para propósitos de prueba, quiero poder usar un dispositivo de software simulado para probar enviar y recibir datos.

Código de ejemplo de Python

device = Device() modem = Modem() device.connect(modem) device.write("Hello") modem_reply = device.read() 

Ahora, en mi aplicación final solo pasaré / dev / ttyS1 o COM1 o lo que sea para el uso de la aplicación. Pero, ¿cómo puedo hacer esto en el software? Estoy ejecutando Linux y la aplicación está escrita en Python .

He intentado hacer un FIFO ( mkfifo ~/my_fifo ) y eso funciona, pero luego necesitaré un FIFO para escribir y otro para leer. Lo que quiero es abrir ~/my_fake_serial_port y leer y escribir a eso.

    También he pagado con el módulo pty , pero tampoco puedo hacer que funcione. Puedo obtener un descriptor de archivo maestro y esclavo de pty.openpty() pero al intentar leerlos o escribirlos solo IOError Bad File Descriptor mensaje de error del IOError Bad File Descriptor .

    Actualizar

    Los comentarios me señalaron la pregunta de SO ¿Hay algún progtwig como COM0COM en Linux? que utiliza socat para configurar una conexión serie virtual. Lo usé así:

    socat PTY,link=$HOME/COM1 PTY,link=$HOME/COM2

    Al rest de ustedes, gracias por brindarme información valiosa. Elegí aceptar la respuesta de Vinay Sajips , ya que esa es la solución que busqué antes de que apareciera la sugerencia de socat. Parece que funciona lo suficientemente bien.

    Probablemente sea mejor usar pyserial para comunicarse con el puerto serie, y simplemente puede crear una versión simulada de la clase serial.Serial que implemente read , readline , write y cualquier otro método que necesite.

    Estás en el camino correcto con pseudo-terminales. Para hacer esto, su dispositivo de software simulado necesita abrir primero un pseudo-terminal maestro: este es el descriptor de archivo que leerá y escribirá cuando esté hablando con el software serie que está probando. A continuación, debe otorgar acceso y desbloquear el pseudo-terminal esclavo y obtener el nombre del dispositivo esclavo. Luego debe imprimir el nombre del dispositivo esclavo en algún lugar, para que pueda decirle al otro software que lo abra como su puerto serie (es decir, que el software abrirá un nombre como /dev/pts/0 lugar de /dev/ttyS1 ).

    El software del simulador simplemente lee y escribe desde el lado maestro de la pseudoterminal. En C, se vería así:

     #define _XOPEN_SOURCE #include  #include  #include  int main(int argc, char *argv[]) { int pt; pt = open("/dev/ptmx", O_RDWR | O_NOCTTY); if (pt < 0) { perror("open /dev/ptmx"); return 1; } grantpt(pt); unlockpt(pt); fprintf(stderr, "Slave device: %s\n", ptsname(pt)); /* Now start pretending to be a modem, reading and writing "pt" */ /* ... */ return 0; } 

    Esperemos que sea bastante fácil de convertir a Python.

    Aquí está la versión pythonic de la comunicación serial pts-emulated (caf’s):

     from serial import Serial driver = MyDriver() # what I want to test peer = serial.Serial() driver.port.fd, peer.fd = posix.openpty() driver.port._reconfigurePort() peer.setTimeout(timeout=0.1) peer._reconfigurePort() driver.start() # peer.write("something") # driver.get_data_from_serial() 

    Tiene algunas ventajas sobre el simulacro de serie, a saber, que se utiliza el código de serie y se ejercitan algunos artefactos de puerto serie.

    Si desea probar la apertura de los puertos serie, puede intercambiar maestro y esclavo y usar os.ttyname(salve_fd) como nombre de puerto serie. No puedo responder por los efectos secundarios del intercambio de maestro y esclavo. Lo más notable es que puede cerrar y volver a abrir el esclavo, pero si cierra también el maestro esclavo muere.

    Esto funciona como un encanto si su código de prueba se ejecuta dentro del mismo proceso. Todavía no he solucionado los problemas con procesos múltiples / separados.