  CMO Programar el puerto serie en Linux
  por Peter H. Baumann, Peter.Baumann@dlr.de
  traduccin de Pedro Pablo Fbrega pfabrega@arrakis.es
  v0.3, 14 Junio 1997

  Este documento describe cmo programar comunicaciones con dispositivos
  sobre puerto serie en una mquina Linux.
  ______________________________________________________________________

  ndice General:

  1.      Introduccin

  1.1.    Copyright

  1.2.    Versiones futuras de este Documento

  1.3.    Revisin

  2.      Comenzando

  2.1.    Depuracin

  2.2.    Configuracin del Puerto

  2.3.    Conceptos de entrada para dispositivos serie

  2.3.1.  Proceso de Entrada Cannico

  2.3.2.  Proceso de Entrada No Cannico

  2.3.3.  Entrada Asncrona

  2.3.4.  Espera de Entradas Origen Mltiple

  3.      Programas Ejemplo

  3.1.    Proceso de Entrada Cannico

  3.2.    Proceso de Entrada NO Cannico

  3.3.    Entrada Asncrona

  3.4.    Espera de Entradas de Origen Mltiple.

  4.      Otras fuentes de Informacin

  5.      Contribuciones

  5.1.    Traduccin

  6.      Anexo: El INSFLUG
  ______________________________________________________________________

  1.  Introduccin

  Este es el COMO Programar el puerto serie en Linux. Todo sobre cmo
  programar comunicaciones con otros dispositivos/ordenadores sobre una
  lnea serie, bajo Linux. Explicaremos diferentes tcnicas: E/S
  Cannica (slo se transmiten/reciben lneas completas), E/S asncrona,
  y espera para una entrada de origen mltiple.

  Este documento no describe cmo 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 cdigo aadidos aqu se derivaron del
  cdigo de miniterm disponible en la gua 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 algn
  comentario, con gusto lo incorporar a este documento (ver seccin
  ``'').

  Todos los ejemplos fueron comprobados usando un ncleo Linux 2.0.29
  sobre un i386.

  1.1.  Copyright

  El CMO 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 fsico o electrnico, con la nica condicin de que mantengan
  esta nota de propiedad intelectual en todas sus copias. La
  redistribucin comercial est permitida y fomentada; de todas formas
  al autor le gustara 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 distribucin. Se pueden conceder excepciones a estas
  reglas bajo ciertas condiciones; por favor contacte con el coordinador
  de los HOWTO en la direccin dada abajo.

  Resumiendo, queremos promover la difusin de esta informacin a travs
  de tantos canales com sea posible. No obstante queremos retener la
  propiedad intelectual de los docuentos HOWTO-COMO, y nos gustara 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 electrnico.

  1.2.  Versiones futuras de este Documento

  Las nuevas versiones de COMO Programar el puerto serie en Linux
  estarn 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.

  CMO Programar el puerto serie en Linux tambin est disponible en
  http://sunsite.unc.edu/LDP/HOWTO/Serial-Programming-HOWTO.html y ser
  enviado a comp.os.linux.answers mensualmente.

  1.3.  Revisin

  Por favor, mndeme cualesquiera correccin, pregunta, comentario,
  sugerencia o material adicional. Me gustara mejorar este HOWTO-COMO.
  Dgame exactamente qu es lo que no entiende, o qu debera estar ms
  claro. Me puede encontrar en Peter.Baumann@dlr.de va email. Por
  favor, incluya el nmero de versin del CMO Programar el puerto serie
  en Linux cuando escriba. Esta es la versin 0.3.

  2.  Comenzando

  2.1.  Depuracin

  La mejor forma de depurar su cdigo es configurar otra mquina Linux y
  conectar los dos ordenadores mediante un cable null-mdem.

  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 mquina
  Linux. Miniterm se puede compilar con mucha facilidad y transmitir
  todas las entradas en bruto del teclado por el puerto serie.

  Slo 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 lnea. Para comprobar su
  conexin, inicie miniterm en ambos ordemadores y teclee algo.  Los
  caracteres introducidos en un ordenador deberan 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 lneas TxD
  (transmit) y RxD (receive). Para una descripcin del cable vea el
  Serie-COMO.

  Tambin es posible ejecutar estas comprobaciones con un slo
  ordenador, si tiene un puerto serie no utilizado. Puede ejecutar dos
  miniterm en sendas consolas virtuales. Si libera un puerto serie
  desconectando el ratn, recuerde redirigir /dev/mouse, si existe. Si
  usa una tarjeta multipuerto serie, est seguro de configurarla
  correctamente. Yo tena la ma mal configurada, y todo funcionaba bien
  mientras haca las comprobaciones en un slo ordenador. Cuando lo
  conect a otro, el puerto empez a perder caracteres. La ejecucin de
  dos programas en un ordenador nunca es completamente asncrona.

  2.2.  Configuracin del Puerto

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

  Todos los parmetros se pueden configurar fcilmente con un programa.
  La configuracin 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 tambin incluye todas las definiciones de parmetros. Los
  parmetros 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 ledos con read.

  De forma similar c_oflag maneja los procesos de salida.  c_cflag
  contiene la configuracin del puerto, como la velocidad en baudios,
  bits por carcter, bits de parada, etc... Los parmetros de modo local
  se guardan en c_lflag. Determinan si el carcter tiene eco, seales
  enviadas al programa, etc...

  Finalmente la tabla c_cc define el carcter de control para el fin de
  fichero, parada, etc... Los valores por defecto de los caracteres de
  control estn definidos en <asm/termios.h>. Los parmetros estn
  descritos en la pgina del manual termios(3).

  La estructura termios contiene los elementos c_line.  Estos elementos
  no se mencionan ni las pginas del manual para termios de Linux ni en
  las pginas de manual de Solaris 2.5. Podra alguien arrojar alguna
  luz sobre esto? No debera 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 aplicacin a la que lo
  queremos destinar. Siempre que sea posible no haga un bucle para leer
  un slo carcter 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 Cannico

  Es el modo de proceso normal para terminales, pero puede ser til
  tambin para comunicaciones con otros dispositivos. Toda la entrada es
  procesada en unidades de lneas, lo que significa que un read slo
  devolver una lnea completa de entrada. Una lnea est, por defecto,
  finalizada con un NL(ASCII LF), y fin de fichero, o un carcter fin de
  lnea. Un CR (el fin de lnea por defecto de DOS/Windows) no terminar
  una lnea con la configuracin por defecto.

  El proceso de entrada cannica puede, tambin, manejar los caracteres
  borrado, borrado de palabra, reimprimir carcter, traducir CR a NL,
  etc..

  2.3.2.  Proceso de Entrada No Cannico

  El Proceso de Entrada No Cannico manejar un conjunto fijo de
  caracteres por lectura, y permite un carcter temporizador. Este modo
  se debera usar si su aplicacin siempre lee un nmero fijo de
  caracteres, o si el dispositivo conectado enva rfagas de caracteres.

  2.3.3.  Entrada Asncrona

  Los dos modos descritos anteriomente se pueden usar en modos sncrono
  y asncrono. El modo sncrono viene por defecto, donde la sentencia
  read se bloquar hasta que la lectura est completa. En modo asncrono
  la sentencia read devolver inmediatamente y enviar una seal al
  programa llamador cuando est completa. Esta seal puede ser recibida
  por un manejador de seales.

  2.3.4.  Espera de Entradas Origen Mltiple

  No es un modo diferente de entrada, pero puede ser til si est
  manejando dispositivos mltiples. En mi aplicacin manejaba entradas
  sobre un socket TCP/IP y entradas sobre una conexin serie de otro
  ordenador de forma casi simultnea. El programa ejemplo dado abajo
  esperar una entrada de dos orgenes distintos. Si la entrada de una
  fuente est disponible, entonces ser procesada, y el programa
  esperar otra entrada nueva.

  La aproximacin presentada abajo parece ms 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 ralentizara 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 mxima de cadena para el proceso de
  entrada cannica.  (<linux/limits.h> o <posix1_lim.h>).

  Vea los comentarios que hay en el cdigo para una explicacin del uso
  de los diferentes modos de entrada. Espero que el cdigo sea
  comprensible. El ejemplo de entrada cannica est mejor comentado, el
  resto de los ejemplos estn comentados slo donde difieren del ejemplo
  de entrada cannica para remarcar las diferencias.

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

  No olvide dar los permisos apropiados a los puertos serie:

       chmod a+rw /dev/ttyS1

  3.1.  Proceso de Entrada Cannico

  #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 Cannico

  En el modo de proceso de entrada no cannico, la entrada no est
  ensamblada en lneas y el procesamiento de la entrada (erase, kill,
  delete, etc.) no ocurre. Dos parmetros controlan el comportamiento de
  este modo:  c_cc[VTIME] fija el temporizador de carcter, y fija el
  nmero mnimo de caracteres a recibir antes de satisfacer la lectura.

  Si MIN > 0 y TIME = 0, MIN fija el nmero 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 ledo un slo carcter, o si se excede TIME (t =TIME
  *0.1 s). Si TIME se excede, no se devuelve ningn carcter.

  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 carcter y slo se hace activo una vez que se ha recibido
  el primer carcter.

  Si MIN = 0 y TIME = 0, la lectura se realizar inmediatamente.
  Devolver el nmero de caracteres disponibles en el momento, o el
  nmero de caracteres solicitados. De acuerdo con Antonino (ver
  contribuciones), podra 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 Asncrona

  #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 Mltiple.

  Esta seccin est al mnimo. Slo intenta ser un indicacin, y por
  tanto el ejemplo de cdigo es pequeo. Esto no slo funcionar con
  puertos serie, sino que tambin 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 nmero de
  descriptor de archivo vlido.  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 estn
  fijados donde ocurre una entrada, salida o excepcin. Todas la
  manipulaciones de fd_set se llevan a cabo mediante las macros
  proporcionadas. Ver tambin la pgina 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, slo 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 Informacin

    El Linux Serie-COMO describe cmo configurar un puerto serie y
     contiene informacin sobre hardware.

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

    La pgina del manual termios(3) describe todos los parmetros de la
     estructura termios.

  5.  Contribuciones

  Como se mencion en la introduccin, no soy un experto en este campo,
  pero he tenido mis propios problemas, y encontr la solucin 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.  Traduccin

  Este documento ha sido traducido por

  Pedro Pablo Fbrega Martnez, pfabrega@arrakis.es

  Si encontris mejoras, aadidos o fallos, de cualquier tipo,
  indicdmelo para mejorar el documento.

  Insultos > /dev/null

  6.  Anexo: El INSFLUG

  El INSFLUG forma parte del grupo internacional Linux Documentation
  Project, encargndose de las traducciones al castellano de los Howtos
  (Comos), as como la produccin de documentos originales en aquellos
  casos en los que no existe anlogo en ingls.

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

  Dirjase a la sede del INSFLUG para ms informacin al respecto.

  En la sede del INSFLUG encontrar siempre las ltimas versiones de las
  traducciones:  www.insflug.org. Asegrese de comprobar cul es la
  ltima versin disponible en el Insflug antes de bajar un documento de
  un servidor rplica.

  Se proporciona tambin una lista de los servidores rplica (mirror)
  del Insflug ms cercanos a Vd., e informacin relativa a otros
  recursos en castellano.

  Francisco Jos Montilla, pacopepe@insflug.org.

