C�MO Programar el puerto serie en Linux
 por Peter H. Baumann, [email protected]
 traducci�n de Pedro Pablo F�brega [email protected]
 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.    Copyright

 1.2.    Versiones futuras de este Documento

 1.3.    Revisi�n

 2.      Comenzando

 2.1.    Depuraci�n

 2.2.    Configuraci�n del Puerto

 2.3.    Conceptos de entrada para dispositivos serie

 2.3.1.  Proceso de Entrada Can�nico

 2.3.2.  Proceso de Entrada No Can�nico

 2.3.3.  Entrada As�ncrona

 2.3.4.  Espera de Entradas Origen M�ltiple

 3.      Programas Ejemplo

 3.1.    Proceso de Entrada Can�nico

 3.2.    Proceso de Entrada NO Can�nico

 3.3.    Entrada As�ncrona

 3.4.    Espera de Entradas de Origen M�ltiple.

 4.      Otras fuentes de Informaci�n

 5.      Contribuciones

 5.1.    Traducci�n

 6.      Anexo: El INSFLUG
 ______________________________________________________________________

 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 (--
 Disponible en castellano como Serie-COMO.--)
 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
 ``'').

 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 [email protected] 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 [email protected] 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.

 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

 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()
 {
    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,
 [email protected], y Peter Waltenberg,
 [email protected]

 Antonino Ianella, [email protected] 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, [email protected]

 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, [email protected].