CÓMO Programar el puerto serie en Linux

por Peter H. Baumann, Peter.Baumann@dlr.de

traducción de Pedro Pablo Fábrega pfabrega@arrakis.es v0.3, 14 Junio 1997 Este documento describe cómo programar comunicaciones con dispositivos sobre puerto serie en una máquina Linux.

Índice General

1 Introducción 1 1.1 Copyright . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.2 Versiones futuras de este Documento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Revisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2

2 Comenzando 3 2.1 Depuración . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.2 Configuración del Puerto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.3 Conceptos de entrada para dispositivos serie . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

2.3.1 Proceso de Entrada Canónico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.3.2 Proceso de Entrada No Canónico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.3.3 Entrada Asíncrona . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.3.4 Espera de Entradas Origen Múltiple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4

3 Programas Ejemplo 5 3.1 Proceso de Entrada Canónico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 3.2 Proceso de Entrada NO Canónico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 3.3 Entrada Asíncrona . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 3.4 Espera de Entradas de Origen Múltiple. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

4 Otras fuentes de Información 11

5 Contribuciones 12 5.1 Traducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

6 Anexo: El INSFLUG 12

1 Introducción

Este es el COMO Programar el puerto serie en Linux. Todo sobre cómo programar comunicaciones con otros dispositivos/ordenadores sobre una línea serie, bajo Linux. Explicaremos diferentes técnicas: E/S Canónica (sólo se transmiten/reciben líneas completas), E/S asíncrona, y espera para una entrada de origen múltiple.

Este documento no describe cómo configurar un puerto serie, ya que esto ha sido descrito por Greg Hankins en el Serial-HOWTO^{1}

Tengo que hacer notar encarecidamente que no soy un experto en este campo, pero he tenido problemas con un proyecto que necesitaba tales comunicaciones. Los ejemplos de código añadidos aquí se derivaron del código de miniterm disponible en la guía de programadores del Linux Documentation Project:

(ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/ y espejos) en el directorio de

ejemplos. Si alguien tiene algún comentario, con gusto lo incorporaré a este documento (ver sección 1.3).

Todos los ejemplos fueron comprobados usando un núcleo Linux 2.0.29 sobre un i386.

1.1 Copyright

El CÓMO Programar el puerto serie en Linux es propiedad inteletual (C) 1997 de Peter Baumann. Los documentos Linux HOWTO - Linux COMO pueden ser reproducidos y distribuidos completos o en parte, en cualquier medio físico o electrónico, con la única condición de que mantengan esta nota de propiedad intelectual en todas sus copias. La redistribución comercial está permitida y fomentada; de todas formas al autor le gustaría que se le notificaran tales distribuciones.

Todas las traducciones, trabajos derivados o trabajos agregados que incorporen cualquier documento Linux HOWTO-Linux COMO debe estar cubierto por esta nota de propiedad intelectual. En resumen, no puede crear un trabajo derivado de un HOWTO-COMO e imponer restricciones adicionales a su distribución. Se pueden conceder excepciones a estas reglas bajo ciertas condiciones; por favor contacte con el coordinador de los HOWTO en la dirección dada abajo.

Resumiendo, queremos promover la difusión de esta información a través de tantos canales com sea posible. No obstante queremos retener la propiedad intelectual de los docuentos HOWTO-COMO, y nos gustaría que se nos notificara cualquier plan para redistribuir los HOWTO-COMO.

Si tiene preguntas, por favor contacte con Greg Hankins, el coordinador de los HOWTO de Linux, en gregh@sunsite.unc.edu mediante correo electrónico.

1.2 Versiones futuras de este Documento

Las nuevas versiones de COMO Programar el puerto serie en Linux estarán disponibles en:

ftp://sunsite.unc.edu:/pub/Linux/docs/HOWTO/Serial-Programming-HOWTO y sus espejos. Hay otros

formatos, como versiones PostScript y DVI en el directorio other-formats.

CÓMO Programar el puerto serie en Linux también está disponible en

http://sunsite.unc.edu/LDP/HOWTO/Serial-Programming-HOWTO.html y será enviado a
comp.os.linux.answers mensualmente.

1.3 Revisión

Por favor, mándeme cualesquiera corrección, pregunta, comentario, sugerencia o material adicional. Me gustaría mejorar este HOWTO-COMO. Dígame exactamente qué es lo que no entiende, o qué debería estar más claro. Me puede encontrar en Peter.Baumann@dlr.de vía email. Por favor, incluya el número de versión del CÓMO Programar el puerto serie en Linux cuando escriba. Esta es la versión 0.3.

1Disponible en castellano como Serie-COMO.

2 Comenzando

2.1 Depuración

La mejor forma de depurar su código es configurar otra máquina Linux y conectar los dos ordenadores mediante un cable null-módem.

Use miniterm, disponible en el LDP Programmers Guide:

(ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/

en el directorio de ejemplos) para transmitir caracteres a su máquina Linux. Miniterm se puede compilar con mucha facilidad y transmitirá todas las entradas en bruto del teclado por el puerto serie.

Sólo las sentencias define (#define MODEMDEVICE "/dev/ttyS0") tienen que ser comprobadas. Ponga ttyS0 para COM1, ttyS1 para COM2, etc.. Es esencial para comprobar que todos los caracteres se transmiten en bruto (sin un procesamiento de salida) por la línea. Para comprobar su conexión, inicie miniterm en ambos ordemadores y teclee algo. Los caracteres introducidos en un ordenador deberían aparecer en el otro y viceversa. La entrada no tendrá eco en la pantalla del ordenador en el que escribamos.

Para hacer un cable null-modem tiene que cruzar las líneas TxD (transmit) y RxD (receive). Para una descripción del cable vea el Serie-COMO.

También es posible ejecutar estas comprobaciones con un sólo ordenador, si tiene un puerto serie no utilizado. Puede ejecutar dos miniterm en sendas consolas virtuales. Si libera un puerto serie desconectando el ratón, recuerde redirigir /dev/mouse, si existe. Si usa una tarjeta multipuerto serie, esté seguro de configurarla correctamente. Yo tenía la mía mal configurada, y todo funcionaba bien mientras hacía las comprobaciones en un sólo ordenador. Cuando lo conecté a otro, el puerto empezó a perder caracteres. La ejecución de dos programas en un ordenador nunca es completamente asíncrona.

2.2 Configuración del Puerto

Los dispositivos /dev/ttyS* tienen como misión conectar terminales a su linux, y están configurados para este uso al arrancar. Hay que tener esto presente cuando se programen comunicaciones con un dispositivo. Por ejemplo, los puertos están configurados para escribir en pantalla cada carácter enviado desde el dispositivo, que normalmente tiene que ser cambiado para la transmisión de datos.

Todos los parámetros se pueden configurar fácilmente con un programa. La configuración se guarda en una estructura struct termios, que está definida en <asm/termbits.h>:

     #define NCCS 19
     struct termios {
           tcflag_t c_iflag;         /* parametros de modo entrada */
           tcflag_t c_oflag;         /* parametros de modo salida */
           tcflag_t c_cflag;         /* parametros de modo control */
           tcflag_t c_lflag;         /* parametros de modo local */
           cc_t c_line;              /* disciplina de la linea */
           cc_t c_cc[NCCS];          /* caracteres de control */
     };

Este archivo también incluye todas las definiciones de parámetros. Los parámetros de modo entrada de c iflag manejan todos los procesos de entrada, lo cual significa que los caracteres enviados desde el dispositivo pueden ser procesados antes de ser leídos con read.

De forma similar c oflag maneja los procesos de salida. c cflag contiene la configuración del puerto, como la velocidad en baudios, bits por carácter, bits de parada, etc... Los parámetros de modo local se guardan en c lflag. Determinan si el carácter tiene eco, señales enviadas al programa, etc...

Finalmente la tabla c cc define el carácter de control para el fin de fichero, parada, etc... Los valores por defecto de los caracteres de control están definidos en <asm/termios.h>. Los parámetros están descritos en la página del manual termios(3).

La estructura termios contiene los elementos c line. Estos elementos no se mencionan ni las páginas del manual para termios de Linux ni en las páginas de manual de Solaris 2.5. ¿Podría alguien arrojar alguna luz sobre esto? ¿No debería estar incluido en la estructura termio?

2.3 Conceptos de entrada para dispositivos serie

Hay tres diferentes conceptos de entrada que queremos presentar. El concepto apropiado se tiene que escoger para la aplicación a la que lo queremos destinar. Siempre que sea posible no haga un bucle para leer un sólo carácter a fin de obtener una cadena completa. Cuando he hecho esto, he perdido caracteres, mientras que un read para toda la cadena no mostró errores.

2.3.1 Proceso de Entrada Canónico

Es el modo de proceso normal para terminales, pero puede ser útil también para comunicaciones con otros dispositivos. Toda la entrada es procesada en unidades de líneas, lo que significa que un read sólo devolverá una línea completa de entrada. Una línea está, por defecto, finalizada con un NL(ASCII LF), y fin de fichero, o un carácter fin de línea. Un CR (el fin de línea por defecto de DOS/Windows) no terminará una línea con la configuración por defecto.

El proceso de entrada canónica puede, también, manejar los caracteres borrado, borrado de palabra, reimprimir carácter, traducir CR a NL, etc..

2.3.2 Proceso de Entrada No Canónico

El Proceso de Entrada No Canónico manejará un conjunto fijo de caracteres por lectura, y permite un carácter temporizador. Este modo se debería usar si su aplicación siempre lee un número fijo de caracteres, o si el dispositivo conectado envía ráfagas de caracteres.

2.3.3 Entrada Asíncrona

Los dos modos descritos anteriomente se pueden usar en modos síncrono y asíncrono. El modo síncrono viene por defecto, donde la sentencia read se bloquará hasta que la lectura esté completa. En modo asíncrono la sentencia read devolverá inmediatamente y enviará una señal al programa llamador cuando esté completa. Esta señal puede ser recibida por un manejador de señales.

2.3.4 Espera de Entradas Origen Múltiple

No es un modo diferente de entrada, pero puede ser útil si está manejando dispositivos múltiples. En mi aplicación manejaba entradas sobre un socket TCP/IP y entradas sobre una conexión serie de otro ordenador de forma casi simultánea. El programa ejemplo dado abajo esperará una entrada de dos orígenes distintos. Si la entrada de una fuente está disponible, entonces será procesada, y el programa esperará otra entrada nueva.

La aproximación presentada abajo parece más bien compleja, pero es importante tener en cuenta que Linux es un sistema operativo multiproceso. La llamada al sistema select no carga la CPU mientras espera una entrada, mientras que un bucle hasta que hay una una entrada disponible ralentizaría demasiado el resto de procesos que se ejecuten a la misma vez.

3. Programas Ejemplo 5

3 Programas Ejemplo

Todos los ejemplos provienen de miniterm.c. El buffer está limitado a 255 caracteres, como la longitud máxima de cadena para el proceso de entrada canónica. (<linux/limits.h> o <posix1 lim.h>).

Vea los comentarios que hay en el código para una explicación del uso de los diferentes modos de entrada. Espero que el código sea comprensible. El ejemplo de entrada canónica está mejor comentado, el resto de los ejemplos están comentados sólo donde difieren del ejemplo de entrada canónica para remarcar las diferencias.

Las descripciones no son completas, por eso le invito a experimentar con los ejemplos para obtener mejores soluciones para su aplicación.

¡No olvide dar los permisos apropiados a los puertos serie:

chmod a+rw /dev/ttyS1

3.1 Proceso de Entrada Canónico

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
/* la tasa de baudios esta definida en  <asm/termbits.h>, que esta
   incluida <termios.h> */
#define BAUDRATE B38400
/* cambie esta definicion por el puerto correcto  */
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* fuentes cumple POSIX  */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
   int fd,c, res;
   struct termios oldtio,newtio;
   char buf[255];
/*
      Abre el dispositivo modem para lectura y escritura y no como controlador
      tty porque no queremos que nos mate si el ruido de la linea envia
      un CTRL-C.
*/
   fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
   if (fd <0) {  perror(MODEMDEVICE); exit(-1);  }
   tcgetattr(fd,&oldtio); /* almacenamos la configuracion actual del puerto */

bzero(newtio, sizeof(newtio)); /* limpiamos struct para recibir los
                                     nuevos parametros del puerto */
/*
   BAUDRATE: Fija la tasa bps. Podria tambien usar cfsetispeed y cfsetospeed.
   CRTSCTS : control de flujo de salida por hardware (usado solo si el cable
   tiene todas las lineas necesarias Vea sect. 7 de Serial-HOWTO)
   CS8     : 8n1 (8bit,no paridad,1 bit de parada)
   CLOCAL  : conexion local, sin control de modem
   CREAD   : activa recepcion de caracteres
*/
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
/*
   IGNPAR  : ignora los bytes con error de paridad
   ICRNL   : mapea CR a NL (en otro caso una entrada CR del otro ordenador
   no terminaria la entrada) en otro caso hace un dispositivo en bruto
   (sin otro proceso de entrada)
*/
newtio.c_iflag = IGNPAR | ICRNL;
/*
   Salida en bruto.
*/
newtio.c_oflag = 0;
/*
   ICANON  : activa entrada canonica
   desactiva todas las funcionalidades del eco, y no envia segnales al
   programa
   llamador
*/
newtio.c_lflag = ICANON;
/*
   inicializa todos los caracteres de control
   los valores por defecto se pueden encontrar en /usr/include/termios.h,
   y vienen dadas en los comentarios, pero no los necesitamos aqui
*/
newtio.c_cc[VINTR]    = 0;     /* Ctrl-c */
newtio.c_cc[VQUIT]    = 0;     /* Ctrl-\ */
newtio.c_cc[VERASE]   = 0;     /* del */
newtio.c_cc[VKILL]    = 0;     /* @ */
newtio.c_cc[VEOF]     = 4;     /* Ctrl-d */
newtio.c_cc[VTIME]    = 0;     /* temporizador entre caracter, no usado */
newtio.c_cc[VMIN]     = 1;     /* bloqu.lectura hasta llegada de caracter. 1 */
newtio.c_cc[VSWTC]    = 0;     /* '\0' */
newtio.c_cc[VSTART]   = 0;     /* Ctrl-q */
newtio.c_cc[VSTOP]    = 0;     /* Ctrl-s */
newtio.c_cc[VSUSP]    = 0;     /* Ctrl-z */
newtio.c_cc[VEOL]     = 0;     /* '\0' */
newtio.c_cc[VREPRINT] = 0;     /* Ctrl-r */
newtio.c_cc[VDISCARD] = 0;     /* Ctrl-u */

        newtio.c_cc[VWERASE]  = 0;     /* Ctrl-w */
        newtio.c_cc[VLNEXT]   = 0;     /* Ctrl-v */
        newtio.c_cc[VEOL2]    = 0;     /* '\0' */
     /*
           ahora limpiamos la linea del modem y activamos la configuracion del
           puerto
     */
        tcflush(fd, TCIFLUSH);
        tcsetattr(fd,TCSANOW,&newtio);
     /*
           configuracion del terminal realizada, ahora manejamos las entradas.
           En este ejemplo, al introducir una  'z' al inicio de linea terminara el
           programa.
     */
        while (STOP==FALSE) {     /* bucle hasta condicion de terminar */
     /*
        bloque de ejecucion de programa hasta que llega un caracter de fin de
        linea, incluso si llegan mas de 255 caracteres.
        Si el numero de caracteres leidos es menor que el numero de caracteres
        disponibles, las siguientes lecturas devolveran los caracteres restantes.
        'res' tomara el valor del numero actual de caracteres leidos.
     */
                               res = read(fd,buf,255);
                               buf[res]=0;             /* envio de fin de cadena, a fin de poder usar printf */
                               printf(":%s:%d\n", buf, res);
                               if (buf[0]=='z') STOP=TRUE;
                            }
     /* restaura la anterior configuracion del puerto  */
        tcsetattr(fd,TCSANOW,&oldtio);
     }

3.2 Proceso de Entrada NO Canónico

En el modo de proceso de entrada no canónico, la entrada no está ensamblada en líneas y el procesamiento de la entrada (erase, kill, delete, etc.) no ocurre. Dos parámetros controlan el comportamiento de este modo: c cc[VTIME] fija el temporizador de carácter, y fija el número mínimo de caracteres a recibir antes de satisfacer la lectura.

Si MIN > 0 y TIME = 0, MIN fija el número de caracteres a recibir antes de que la lectura esté realizada. Como TIME es cero, el temporizador no se usa.

Si MIN = 0 y TIME > 0, TIME indica un tiempo de espera. La lectura se realizará si es leído un sólo carácter, o si se excede TIME (t =TIME *0.1 s). Si TIME se excede, no se devuelve ningún carácter.

Si MIN > 0 y TIME > 0, TIME indica un temporizador entre caracteres. La lectura se realizará si se reciben MIN caracteres o el tiempo entre dos caracteres excede TIME. El temporizador se reinicia cada vez que se recibe un carácter y sólo se hace activo una vez que se ha recibido el primer carácter.

Si MIN = 0 y TIME = 0, la lectura se realizará inmediatamente. Devolverá el número de caracteres disponibles en el momento, o el número de caracteres solicitados. De acuerdo con Antonino (ver contribuciones), podría poner un fcntl(fd, F SETFL, FNDELAY); antes de leer para obtener el mismo resultado.

Modificando newtio.c cc[VTIME] y newtio.c cc[VMIN] se pueden comprobar todos los modos descritos arriba.

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* fuentes cumple POSIX */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
main()
{
int fd,c, res;
struct termios oldtio,newtio;
char buf[255];
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {  perror(MODEMDEVICE); exit(-1);  }
tcgetattr(fd,&oldtio); /* salva configuracion actual del puerto  */
bzero(newtio, sizeof(newtio));
newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
newtio.c_iflag = IGNPAR;
newtio.c_oflag = 0;
/* pone el modo entrada (no-canonico, sin eco,...) */
newtio.c_lflag = 0;
newtio.c_cc[VTIME]    = 0;   /* temporizador entre caracter, no usado */
newtio.c_cc[VMIN]     = 5;   /* bloquea lectura hasta recibir 5 chars  */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);

while (STOP==FALSE) {                            /* bucle para entrada */
                       res = read(fd,buf,255);   /* devuelve tras introducir 5 */
                       buf[res]=0;               /* asi podemos printf... */
                       printf(":%s:%d\n", buf, res);
                       if (buf[0]=='z') STOP=TRUE;
                    }
tcsetattr(fd,TCSANOW,&oldtio);
}

3.3 Entrada Asíncrona

#include <termios.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/signal.h>
#include <sys/types.h>
#define BAUDRATE B38400
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* fuentes cumple POSIX  */
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
void signal_handler_IO (int status);   /* definicion del manejador de segnal */
int wait_flag=TRUE;                    /* TRUE mientras no segnal recibida */
main()
{
   int fd,c, res;
   struct termios oldtio,newtio;
   struct sigaction saio;           /* definicion de accion de segnal  */
   char buf[255];
/* abre el dispositivo en modo no bloqueo (read volvera inmediatamente) */
      fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
   if (fd <0) {  perror(MODEMDEVICE); exit(-1);  }
/* instala el manejador de segnal antes de hacer asincrono el dispositivo */
   saio.sa_handler = signal_handler_IO;
   saio.sa_mask = 0;
   saio.sa_flags = 0;
   saio.sa_restorer = NULL;
   sigaction(SIGIO,&saio,NULL);
/* permite al proceso recibir SIGIO */
      fcntl(fd, F_SETOWN, getpid());
/* Hace el descriptor de archivo asincrono (la pagina del manual dice solo
      O_APPEND y O_NONBLOCK, funcionara con  F_SETFL...) */
   fcntl(fd, F_SETFL, FASYNC);
   tcgetattr(fd,&oldtio); /* salvamos conf. actual del puerto */
/*
      fija la nueva configuracion del puerto para procesos de entrada canonica
*/
   newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
   newtio.c_iflag = IGNPAR | ICRNL;
   newtio.c_oflag = 0;

   newtio.c_lflag = ICANON;
   newtio.c_cc[VMIN]=1;
   newtio.c_cc[VTIME]=0;
   tcflush(fd, TCIFLUSH);
   tcsetattr(fd,TCSANOW,&newtio);
/* bucle de espera para entrada. Normalmente se haria algo util aqui  */
   while (STOP==FALSE) {
                          printf(".\n");usleep(100000);
/*
tras recibir SIGIO, wait_flag = FALSE, la entrada esta disponible y puede ser leida
 */
                if (wait_flag==FALSE) {
                                   res = read(fd,buf,255);
                                   buf[res]=0;
                                   printf(":%s:%d\n", buf, res);
                                   if (res==1) STOP=TRUE; /* para el bucle si solo entra un CR */
                                   wait_flag = TRUE;      /* espera una nueva entrada */
                                }
                       }
/* restaura la configuracion original del puerto  */
      tcsetattr(fd,TCSANOW,&oldtio);
}

/***************************************************************************
* manipulacion de segnales. pone wait_flag a FALSE, para indicar al bucle  *
* anterior que los caracteres han sido recibidos                           *
***************************************************************************/
void signal_handler_IO (int status)
{
   printf("recibida segnal SIGIO.\n");
   wait_flag = FALSE;
}

3.4 Espera de Entradas de Origen Múltiple.

Esta sección está al mínimo. Sólo intenta ser un indicación, y por tanto el ejemplo de código es pequeño. Esto no sólo funcionará con puertos serie, sino que también lo hará con cualquier conjunto de descriptores de archivo.

La llamada select y las macros asociadas usan un fd set. Esto es una tabla de bits, que tiene una entrada de bit para cada número de descriptor de archivo válido. select aceptará un fd set con los bits fijados para los descriptores de archivos relevantes y devuelve un fd set, en el cual los bits para el descriptor del archivo están fijados donde ocurre una entrada, salida o excepción. Todas la manipulaciones de fd set se llevan a cabo mediante las macros proporcionadas. Ver también la página del manual select(2).

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
main()

4. Otras fuentes de Información 11

{
   int    fd1, fd2;  /* origenes de entrada  1 y 2 */
   fd_set readfs;    /* descriptor de archivo */
   int    maxfd;     /* mixmum file desciptor used */
   int    loop=1;    /* bucle mientras TRUE */
/*
   open_input_source abre un dispositivo, fija el puerto correctamente
   y devuelve un descriptor de archivo
*/
   fd1 = open_input_source("/dev/ttyS1");   /* COM2 */
   if (fd1<0) exit(0);
   fd2 = open_input_source("/dev/ttyS2");   /* COM3 */
   if (fd2<0) exit(0);
   maxfd = MAX (fd1, fd2)+1;  /* entrada maxima de bits (fd) a probar */
/* bucle para entrada */
      while (loop) {
                      FD_SET(fd1, &readfs);  /* comprobacion origen 1  */
                      FD_SET(fd2, &readfs);  /* comprobacion origen 2 */
/* bloqueo hasta que la entrada esta disponible  */
                         select(maxfd, &readfs, NULL, NULL, NULL);
                      if (FD_ISSET(fd1))         /* entrada de origen 1 esta disponible */
                         handle_input_from_source1();
                      if (FD_ISSET(fd2))         /* entrada de origen 2 esta disponible */
                         handle_input_from_source2();
                   }
}

El ejemplo dado bloquea indefinidamente hasta que una entrada de una de las fuentes está disponible. Si necesita un temporizador para la entrada, sólo sustituya la llamada select por:

int res;
struct timeval Timeout;
/* fija el valor del temporizador en el bucle de entrada  */
Timeout.tv_usec = 0;  /* milisegundos */
Timeout.tv_sec  = 1;  /* segundos */
res = select(maxfd, &readfs, NULL, NULL, &Timeout);
if (res==0)
/* numero de descriptores de archivo con input = 0, temporizador sobrepasado */

Este ejemplo concluye el tiempo de espera tras un segundo. Si este tiempo transcurre, select devolverá 0, pero tenga cuidado porque Timeout se decrementa por el tiempo actualmente esperado para la entrada por select. Si el valor de retardo es cero, select volverá inmediatamente.

4 Otras fuentes de Información

• El Linux Serie-COMO describe cómo configurar un puerto serie y contiene información sobre hardware.

• Serial Programming Guide for POSIX Compliant Operating Systems, por Michael Sweet.

• La página del manual termios(3) describe todos los parámetros de la estructura termios.

5 Contribuciones

Como se mencionó en la introducción, no soy un experto en este campo, pero he tenido mis propios problemas, y encontré la solución con la ayuda de otras personas. Gracias por la ayuda de Mr. Strudthoff de European Transonic Windtunnel, Cologne, Michael Carter, mcarter@rocke.electro.swri.edu, y Peter

Waltenberg, p.waltenberg@karaka.chch.cri.nz

Antonino Ianella, antonino@usa.net escribió el Serial-Port-Programming Mini HOWTO, a la misma vez que yo preparaba este documento. Greg Hankins me pidió que incorporara el Mini-Howto de Antonino en este documento.

La estructura de este documento y el formateo SGML provienen del Serial-HOWTO de Greg Hankins.

5.1 Traducción

Este documento ha sido traducido por

Pedro Pablo Fábrega Martínez, pfabrega@arrakis.es

Si encontráis mejoras, añadidos o fallos, de cualquier tipo, indicádmelo para mejorar el documento.

Insultos > /dev/null

6 Anexo: El INSFLUG

El INSFLUG forma parte del grupo internacional Linux Documentation Project, encargándose de las traducciones al castellano de los Howtos (Comos), así como la producción de documentos originales en aquellos casos en los que no existe análogo en inglés.

En el INSFLUG se orienta preferentemente a la traducción de documentos breves, como los COMOs y PUFs (Preguntas de Uso Frecuente, las FAQs. :) ), etc.

Diríjase a la sede del INSFLUG para más información al respecto.

En la sede del INSFLUG encontrará siempre las últimas versiones de las traducciones: www.insflug.org. Asegúrese de comprobar cuál es la última versión disponible en el Insflug antes de bajar un documento de un servidor réplica.

Se proporciona también una lista de los servidores réplica (mirror) del Insflug más cercanos a Vd., e información relativa a otros recursos en castellano.

Francisco José Montilla, pacopepe@insflug.org.