
                       Le Linux Serial Programming HOWTO

par Peter H. Baumann, Peter.Baumann@dlr.de
Adaptation franaise Etienne BERNARD eb@via.ecp.fr

   v1.0, 22 janvier 1998
     _________________________________________________________________

   _Ce document dcrit comment programmer sous Linux la communication
   avec des priphriques sur port srie._
     _________________________________________________________________

1. Introduction

   Voici le Linux Serial Programming HOWTO, qui explique comment
   programmer sous Linux la communication avec des priphriques ou des
   ordinateurs via le port srie. Diffrentes techniques sont abordes :
   Entres/Sorties canoniques (envoi ou rception ligne par ligne),
   asynchrones, ou l'attente de donnes depuis de multiples sources.

   Ce document ne dcrit pas comment configurer les ports sries, puisque
   c'est dcrit par Greg Hankins dans le Serial-HOWTO.

   Je tiens  insister sur le fait que je ne suis pas un expert dans ce
   domaine, mais j'ai eu  raliser un projet utilisant la communication
   par le port srie. Les exemples de code source prsents dans ce
   document sont drivs du programme miniterm, disponible dans le _Linux
   programmer's guide_
   (ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.ta
   r.gz et les miroirs, par exemple
   ftp://ftp.lip6.fr/pub/linux/docs/LDP/programmers-guide/lpg-0.4.tar.gz)
   dans le rpertoire contenant les exemples.

   Depuis la dernire version de ce document, en juin 1997, j'ai d
   installer Windows NT pour satisfaire les besoins des client, et donc
   je n'ai pas pu investiguer plus en avant sujet. Si quelqu'un a des
   commentaires  me faire, je me ferai un plaisir de les inclure dans ce
   document (voyez la section sur les commentaires). Si vous dsirez
   prendre en main l'volution de ce document, et l'amliorer, envoyez
   moi un courrier lectronique.

   Tous les exemples ont t tests avec un i386, utilisant un noyau
   Linux de version 2.0.29.

1.1 Copyright

   Le Linux Serial-Programming-HOWTO est copyright (c) 1997 Peter
   Baumann. Les HOWTO de Linux peuvent tre reproduits et distribus
   intgralement ou seulement par partie, sur quelconque support physique
   ou lectronique, aussi longtemps que ce message de copyright sera
   conserv dans toutes les copies. Une redistribution commerciale est
   autorise, et encourage; cependant, l'auteur _apprcierait_ d'tre
   prvenu en cas de distribution de ce type.

   Toutes les traductions ou travaux drivs incorporant un document
   HOWTO Linux doit tre plac sous ce copyright. C'est--dire que vous
   ne pouvez pas produire de travaux drivs  partir d'un HOWTO et
   imposer des restrictions additionnelles sur sa distribution. Des
   exceptions  cette rgle peuvent tre accordes sous certaines
   conditions  ; contactez le coordinateur des HOWTO Linux  l'adresse
   donne ci-dessous.

   En rsum, nous dsirons promouvoir la distribution de cette
   information par tous les moyens possibles. Nanmoins, nous dsirons
   conserver le copyright sur les documents HOWTO, et nous _aimerions_
   tre informs de tout projet de redistribution des HOWTO.

   Pour toute question, veuillez contacter Greg Hankins, le coordinateur
   des HOWTO Linux,  gregh@sunsite.unc.edu par mail.

1.2 Nouvelles versions de ce document.

   Les nouvelles version du Serial-Programming-HOWTO seront disponibles 
   ftp://sunsite.unc.edu:/pub/Linux/docs/HOWTO/Serial-Programming-HOWTO
   et les sites miroir, comme par exemple
   ftp://ftp.lip6.fr/pub/linux/docs/HOWTO/Serial-Programming-HOWTO. Il
   existe sous d'autres formats, comme PostScript ou DVI dans le sous
   rpertoire other-formats. Le Serial-Programming-HOWTO est galement
   disponible sur
   http://sunsite.unc.edu/LDP/HOWTO/Serial-Programming-HOWTO.html, et
   sera post dans comp.os.linux.answers tous les mois (NdT : la version
   franaise de ce document est galement poste dans
   fr.comp.os.linux.annonce tous les mois).

1.3 Commentaires

   Envoyez moi, s'il vous plat toute correction, question, commentaire,
   suggestion ou complment. Je dsire amliorer cet HOWTO ! Dites moi
   exactement ce que vous ne comprenez pas, ou ce qui pourrait tre plus
   clair. Vous pouvez me contacter  Peter.Baumann@dlr.de par courrier
   lectronique. Veuillez inclure le numro de version de ce document
   pour tout courrier. Ce document est la version 0.3.

2. Dmarrage

2.1 Dbuggage

   Le meilleur moyen de dbugguer votre code est d'installer une autre
   machine sous Linux et de connecter les deux ordinateurs par un cble
   null-modem. Utilisez miniterm (disponible dans le Linux programmers
   guide --
   ftp://sunsite.unc.edu/pub/Linux/docs/LDP/programmers-guide/lpg-0.4.tar
   .gz -- dans le rpertoire des exemples) pour transmettre des
   caractres  votre machine Linux. Miniterm est trs simple  compiler
   et transmettra toute entre clavier directement sur le port srie.
   Vous n'avez qu' adapter la commande #define MODEMDEVICE "/dev/ttyS0"
    vos besoins. Mettez ttyS0 pour COM1, ttyS1 for COM2, etc... Il est
   essentiel, pour les tests, que _tous_ les caractres soient transmis
   bruts (sans traitements) au travers de la ligne srie. Pour tester
   votre connexion, dmarrez miniterm sur les deux ordinateurs et taper
   au clavier. Les caractres crit sur un ordinateur devraient
   apparatre sur l'autre ordinateur, et vice versa. L'entre clavier
   sera galement recopie sur l'cran de l'ordinateur local.

   Pour fabriquer un cble null-modem, pour devez croiser les lignes TxD
   (_transmit_) et RxD (_receive_). Pour une description du cble,
   rfrez vous  la section 7 du Serial-HOWTO.

   Il est galement possible de faire cet essai avec uniquement un seul
   ordinateur, si vous disposez de deux ports srie. Vous pouvez lancez
   deux miniterms sur deux consoles virtuelles. Si vous librez un port
   srie en dconnectant la souris, n'oubliez pas de rediriger /dev/mouse
   si ce fichier existe. Si vous utilisez une carte srie  ports
   multiples, soyez sr de la configurer correctement. La mienne n'tait
   pas correctement configure, et tout fonctionnait correctement lorsque
   je testais sur mon ordinateur. Lorsque je l'ai connect  un autre, le
   port a commenc  perdre des caractres. L'excution de deux
   programmes sur un seul ordinateur n'est pas totalement asynchrone.

2.2 Configuration des ports

   Les priphriques /dev/ttyS* sont destins  connecter les terminaux 
   votre machine Linux, et sont configurs pour cet usage aprs le
   dmarrage. Vous devez vous en souvenir lorsque vous programmez la
   communication avec un priphrique autre. Par exemple, les ports sont
   configurs pour afficher les caractres envoys vers lui-mme, ce qui
   normalement doit tre chang pour la transmission de donnes.

   Tous les paramtres peuvent tre facilement configur depuis un
   programme. La configuration est stocke dans une structure de type
   struct termios, qui est dfinie dans <asm/termbits.h> :

#define NCCS 19
struct termios {
        tcflag_t c_iflag;               /* Modes d'entre */
        tcflag_t c_oflag;               /* Modes de sortie */
        tcflag_t c_cflag;               /* Modes de contrle */
        tcflag_t c_lflag;               /* Modes locaux */
        cc_t c_line;                    /* Discipline de ligne */
        cc_t c_cc[NCCS];                /* Caractres de contrle */
};

   Ce fichier inclus galement la dfinition des constantes. Tous les
   modes d'entre dans c_iflag prennent en charge le traitement de
   l'entre, ce qui signifie que les caractres envoys depuis le
   priphrique peuvent tre traits avant d'tre lu par read. De la mme
   faon, c_oflags se chargent du traitement en sortie. c_cflag contient
   les paramtres du port, comme la vitesse, le nombre de bits par
   caractre, les bits d'arrt, etc... Les modes locaux, stocks dans
   c_lflag dterminent si les caractres sont imprims, si des signaux
   sont envoys  votre programme, etc... Enfin, le tableau c_cc dfinit
   les caractres de contrle pour la fin de fichier, le caractre stop,
   etc... Les valeurs par dfaut pour les caractres de contrle sont
   dfinies dans <asm/termios.h>. Les modes possibles sont dcrits dans
   la page de manuel de termios(3). La structure termios contient un
   champ c_line (discipline de ligne), qui n'est pas utilis sur les
   systmes conformes  POSIX.

2.3 Faons de lire sur les priphriques srie

   Voici trois faons de lire sur les priphriques srie. Le moyen
   appropri doit tre choisi pour chaque application. Lorsque cela est
   possible, ne lisez pas les chanes caractre par caractre. Lorsque
   j'utilisais ce moyen, je perdais des caractres, alors qu'un read sur
   la chane complte ne donnait aucune erreur.

  Entre canonique

   C'est le mode de fonctionnement normal pour les terminaux, mais peut
   galement tre utilis pour communiquer avec d'autres priphriques.
   Toutes les entres sont traites lignes par lignes, ce qui signifie
   qu'un read ne renverra qu'une ligne complte. Une ligne est termine
   par dfaut avec un caractre NL (ACII LF), une fin de fichier, ou un
   caractre de fin de ligne. Un CR (le caractre de fin de ligne par
   dfaut de DOS et Windows) ne terminera pas une ligne, avec les
   paramtres par dfaut.

   L'entre canonique peut galement prendre en charge le caractre
   erase, d'effacement de mot, et de raffichage, la traduction de CR
   vers NL, etc...

  Entre non canonique

   L'entre non canonique va prendre en charge un nombre fix de
   caractre par lecture, et autorise l'utilisation d'un compteur de
   temps pour les caractres. Ce mode doit tre utilis si votre
   application lira toujours un nombre fix de caractres, ou si le
   priphrique connect envoit les caractres par paquet.

  Entre asynchrone

   Les deux modes ci-dessus peut tre utilis en mode synchrone ou
   asynchrone. Le mode synchrone est le mode par dfaut, pour lequel un
   appel  read sera bloquant, jusqu' ce que la lecture soit satisfaite.
   En mode asynchrone, un appel  read retournera immdiatement et
   lancera un signal au programme appelant en fin de transfert. Ce signal
   peut tre reu par un gestionnaire de signal.

  Attente d'entre depuis de multiples sources

   Cela ne constitue pas un mode d'entre diffrent, mais peut s'avrer
   tre utile, si vous prenez en charge des priphriques multiples. Dans
   mon application, je traitais l'entre depuis une socket TCP/IP et
   depuis une connexion srie sur un autre ordinateur quasiment en mme
   temps. L'exemple de programme donn plus loin attendra des caractres
   en entre depuis deux sources. Si des donnes sur l'une des sources
   deviennent disponibles, elles seront traites, et le programme
   attendra de nouvelles donnes.

   L'approche prsente plus loin semble plutt complexe, mais il est
   important que vous vous rappeliez que Linux est un systme
   multi-tche. L'appel systme select ne charge pas le processeur
   lorsqu'il attend des donnes, alors que le fait de faire une boucle
   jusqu' ce que des caractres deviennent disponibles ralentirait les
   autres processus.

3. Exemples de programmes

   Tous les exemples ont t extraits de miniterm.c. Le tampon d'entre
   est limit  255 caractres, tout comme l'est la longueur maximale
   d'une ligne en mode canonique (<linux/limits.h> ou <posix1_lim.h>).

   Rfrez-vous aux commentaires dans le code source pour l'explication
   des diffrents modes d'entre. J'espre que le code est
   comprhensible. L'exemple sur l'entre canonique est la plus
   commente, les autres exemples sont comments uniquement lorsqu'ils
   diffrent, afin de signaler les diffrences.

   Les descriptions ne sont pas compltes, mais je vous encourage 
   modifier les exemples pour obtenir la solution la plus intressante
   pour votre application.

   N'oubliez pas de donner les droits corrects aux ports srie (par
   exemple, chmod a+rw /dev/ttyS1) !

3.1 Traitement canonique

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>

/* les valeurs pour la vitesse, baudrate, sont dfinies dans <asm/termbits.h>,
qui est inclus
dans <termios.h> */
#define BAUDRATE B38400
/* changez cette dfinition pour utiliser le port correct */
#define MODEMDEVICE "/dev/ttyS1"
#define _POSIX_SOURCE 1 /* code source conforme  POSIX */

#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

main()
{
  int fd,c, res;
  struct termios oldtio,newtio;
  char buf[255];
/*
  On ouvre le priphrique du modem en lecture/criture, et pas comme
  terminal de contrle, puisque nous ne voulons pas tre termin si l'on
  reoit un caractre CTRL-C.
*/
 fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
 if (fd <0) {perror(MODEMDEVICE); exit(-1); }

 tcgetattr(fd,&oldtio); /* sauvegarde de la configuration courante */
 bzero(&newtio, sizeof(newtio)); /* on initialise la structure  zro */

/*
  BAUDRATE: Affecte la vitesse. vous pouvez galement utiliser cfsetispeed
            et cfsetospeed.
  CRTSCTS : contrle de flux matriel (uniquement utilis si le cble a
            les lignes ncessaires. Voir la section 7 du Serial-HOWTO).
  CS8     : 8n1 (8 bits,sans parit, 1 bit d'arrt)
  CLOCAL  : connexion locale, pas de contrle par le modem
  CREAD   : permet la rception des caractres
*/
 newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;

/*
  IGNPAR  : ignore les octets ayant une erreur de parit.
  ICRNL   : transforme CR en NL (sinon un CR de l'autre ct de la ligne
            ne terminera pas l'entre).
  sinon, utiliser l'entre sans traitement (device en mode raw).
*/
 newtio.c_iflag = IGNPAR | ICRNL;

/*
 Sortie sans traitement (raw).
*/
 newtio.c_oflag = 0;

/*
  ICANON  : active l'entre en mode canonique
  dsactive toute fonctionnalit d'echo, et n'envoit pas de signal au
  programme appelant.
*/
 newtio.c_lflag = ICANON;

/*
  initialise les caractres de contrle.
  les valeurs par dfaut peuvent tre trouves dans
  /usr/include/termios.h, et sont donnes dans les commentaires.
  Elles sont inutiles ici.
*/
 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;     /* compteur inter-caractre non utilis */
 newtio.c_cc[VMIN]     = 1;     /* read bloquant jusqu' l'arrive d'1 caractr
e */
 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' */

/*
   prsent, on vide la ligne du modem, et on active la configuration
  pour le port
*/
 tcflush(fd, TCIFLUSH);
 tcsetattr(fd,TCSANOW,&newtio);

/*
  la configuration du terminal est faite,  prsent on traite
  les entres
  Dans cet exemple, la rception d'un 'z' en dbut de ligne mettra
  fin au programme.
*/
 while (STOP==FALSE) {     /* boucle jusqu' condition de terminaison */
 /* read bloque l'excution du programme jusqu' ce qu'un caractre de
    fin de ligne soit lu, mme si plus de 255 caractres sont saisis.
    Si le nombre de caractres lus est infrieur au nombre de caractres
    disponibles, des read suivant retourneront les caractres restants.
    res sera positionn au nombre de caractres effectivement lus */
    res = read(fd,buf,255);
    buf[res]=0;       /* on termine la ligne, pour pouvoir l'afficher */
    printf(":%s:%d\n", buf, res);
    if (buf[0]=='z') STOP=TRUE;
 }
 /* restaure les anciens paramtres du port */
 tcsetattr(fd,TCSANOW,&oldtio);
}

3.2 Entre non canonique

   Dans le mode non canonique, les caractres lus ne sont pas assembls
   ligne par ligne, et ils ne subissent pas de traitement (erase, kill,
   delete, etc...). Deux paramtres contrlent ce mode : c_cc[VTIME]
   positionne le _timer_ de caractres, et c_cc[VMIN] indique le nombre
   minimum de caractres  recevoir avant qu'une lecture soit satisfaite.

   Si MIN > 0 et TIME = 0, MIN indique le nombre de caractres  recevoir
   avant que la lecture soit satisfaite. TIME est gal  zro, et le
   _timer_ n'est pas utilis.

   Si MIN = 0 et TIME > 0, TIME est utilis comme une valeur de
   _timeout_. Une lecture est satisfaite lorsqu'un caractre est reu, ou
   que la dure TIME est dpasse (t = TIME * 0.1s). Si TIME est dpass,
   aucun caractre n'est retourn.

   Si MIN > 0 et TIME > 0, TIME est employ comme _timer_ entre chaque
   caractre. La lecture sera satisfaite si MIN caractres sont reus, ou
   que le _timer_ entre deux caractres dpasse TIME. Le _timer_ est
   rinitialis  chaque fois qu'un caractre est reu, et n'est activ
   qu'aprs la rception du premier caractre.

   Si MIN = 0 et TIME = 0, le retour est immdiat. Le nombre de
   caractres disponibles, ou bien le nombre de caractres demand est
   retourn. Selon Antonino (voir le paragraphe sur les participations),
   vous pouvez utiliser un fcntl(fd, F_SETFL, FNDELAY); avant la lecture
   pour obtenir le mme rsultat.

   Vous pouvez tester tous les modes dcrit ci-dessus en modifiant
   newtio.c_cc[VTIME] et newtio.c_cc[VMIN].

#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 /* code source conforme  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); /* sauvegarde de la configuration courante */

 bzero(&newtio, sizeof(newtio));
 newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD;
 newtio.c_iflag = IGNPAR;
 newtio.c_oflag = 0;

 /* positionne le mode de lecture (non canonique, sans echo, ...) */
 newtio.c_lflag = 0;

 newtio.c_cc[VTIME]    = 0;   /* timer inter-caractres non utilis */
 newtio.c_cc[VMIN]     = 5;   /* read bloquant jusqu' ce que 5 */
                              /* caractres soient lus */
 tcflush(fd, TCIFLUSH);
 tcsetattr(fd,TCSANOW,&newtio);


 while (STOP==FALSE) {       /* boucle de lecture */
   res = read(fd,buf,255);   /* retourne aprs lecture 5 caractres */
   buf[res]=0;               /* pour pouvoir les imprimer... */
   printf(":%s:%d\n", buf, res);
   if (buf[0]=='z') STOP=TRUE;
 }
 tcsetattr(fd,TCSANOW,&oldtio);
}

3.3 Lecture asynchrone

#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 /* code source conforme  POSIX */
#define FALSE 0
#define TRUE 1

volatile int STOP=FALSE;

void signal_handler_IO (int status);   /* le gestionnaire de signal */
int wait_flag=TRUE;              /* TRUE tant que reu aucun signal */

main()
{
  int fd,c, res;
  struct termios oldtio,newtio;
  struct sigaction saio;        /* dfinition de l'action du signal */
  char buf[255];

  /* ouvre le port en mon non-bloquant (read retourne immdiatement) */
  fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK);
  if (fd <0) {perror(MODEMDEVICE); exit(-1); }

  /* installe le gestionnaire de signal avant de passer le port en
     mode asynchrone */
  saio.sa_handler = signal_handler_IO;
  saio.sa_mask = 0;
  saio.sa_flags = 0;
  saio.sa_restorer = NULL;
  sigaction(SIGIO,&saio,NULL);

  /* permet au processus de recevoir un SIGIO */
  fcntl(fd, F_SETOWN, getpid());
  /* rend le descripteur de fichier asynchrone (la page de manuel
     indique que seuls O_APPEND et O_NONBLOCK fonctionnent avec
     F_SETFL...) */
  fcntl(fd, F_SETFL, FASYNC);

  tcgetattr(fd,&oldtio); /* sauvegarde de la configuration courante */
  /* positionne les nouvelles valeurs pour lecture canonique */
  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);

  /* on boucle en attente de lecture. gnralement, on ralise
     des traitements  l'intrieur de la boucle */
  while (STOP==FALSE) {
    printf(".\n");usleep(100000);
    /* wait_flag = FALSE aprs rception de SIGIO. Des donnes sont
       disponibles et peuvent tre lues */
    if (wait_flag==FALSE) {
      res = read(fd,buf,255);
      buf[res]=0;
      printf(":%s:%d\n", buf, res);
      if (res==1) STOP=TRUE; /* on arrte la boucle si on lit une
                                ligne seule */
      wait_flag = TRUE;      /* on attend de nouvelles donnes */
    }
  }
  /* restaure les anciens paramtres du port */
  tcsetattr(fd,TCSANOW,&oldtio);
}

/***************************************************************************
* gestionnaire de signal. Positionne wait_flag  FALSE, pour indiquer     *
* la boucle ci-dessus que des caractres ont t reus.                    *
***************************************************************************/

void signal_handler_IO (int status)
{
  printf("rception du signal SIGIO.\n);
  wait_flag = FALSE;
}

3.4 Multiplexage en lecture

   Cette section est rduite au minimum, et n'est l que pour vous
   guider. Le code source d'exemple prsent est donc rduit au strict
   minimum. Il ne fonctionnera pas seulement avec des ports srie, mais
   avec n'importe quel ensemble de descripteurs de fichiers.

   L'appel systme select et les macros qui lui sont attaches utilisent
   un fd_set. C'est un tableau de bits, qui dispose d'un bit pour chaque
   descripteur de fichier valide. select accepte un fd_set ayant les bits
   positionns pour les descripteurs de fichiers qui conviennent, et
   retourne un fd_set, dans lequel les bits des descripteurs de fichier
   o une lecture, une criture ou une exception sont positionns. Toutes
   les manipulations de fd_set sont faites avec les macros fournies.
   Reportez vous galement  la page de manuel de select(2).

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

main()
{
   int    fd1, fd2;  /* entres 1 et 2 */
   fd_set readfs;    /* ensemble de descripteurs */
   int    maxfd;     /* nombre max des descripteurs utiliss */
   int    loop=1;    /* boucle tant que TRUE */

   /* open_input_source ouvre un priphrique, configure le port
      correctement, et retourne un descripteur de fichier. */
   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; /* numro maximum du bit  tester */

   /* boucle d'entre */
   while (loop) {
     FD_SET(fd1, &readfs);  /* test pour la source 1 */
     FD_SET(fd2, &readfs);  /* test pour la source 2 */
     /* on bloque jusqu' ce que des caractres soient
        disponibles en lecture */
     select(maxfd, &readfs, NULL, NULL, NULL);
     if (FD_ISSET(fd1))         /* caractres sur 1 */
       handle_input_from_source1();
     if (FD_ISSET(fd2))         /* caractres sur 2 */
       handle_input_from_source2();
   }

}

   L'exemple ci-dessus bloque indfiniment, jusqu' ce que des caractres
   venant d'une des sources soient disponibles. Si vous avez besoin d'un
   _timeout_, remplacez juste l'appel  select par :

int res;
struct timeval Timeout;

/* fixe la valeur du timeout */
Timeout.tv_usec = 0;  /* millisecondes */
Timeout.tv_sec  = 1;  /* secondes */
res = select(maxfd, &readfs, NULL, NULL, &Timeout);
if (res==0)
/* nombre de descripteurs de fichiers avec caractres
   disponibles = 0, il y a eu timeout */

   Cet exemple verra l'expiration du delai de _timeout_ aprs une
   seconde. S'il y a _timeout_, select retournera 0, mais fates
   attention, Timeout est dcrment du temps rellement attendu par
   select. Si la valeur de _timeout_ est 0, select retournera
   immdiatement.

4. Autres sources d'information

     * Le Linux Serial-HOWTO dcrit comment mettre en place les ports
       srie et contient des informations sur le matriel.
     * Le Serial Programming Guide for POSIX Compliant Operating Systems,
       par Michael Sweet. Ce lien est prim et je n'arrive pas  trouver
       la nouvelle adresse du document. Quelqu'un sait-il o je peux le
       retrouver ? C'tait un trs bon document !
     * La page de manuel de termios(3) dcrit toutes les constantes
       utilises pour la structure termios.

5. Contributions

   Comme je l'ai dit dans l'introduction, je ne suis pas un expert dans
   le domaine, mais j'ai rencontr des problmes, et j'ai trouv les
   solutions avec l'aide d'autres personnes. Je tiens  remercier pour
   leur aide M. Strudthoff du European Transonic WindTunnel, Cologne,
   Michael Carter (mcarter@rocke.electro.swri.edu) et Peter Waltenberg
   (p.waltenberg@karaka.chch.cri.nz).

   Antonino Ianella (antonino@usa.net a crit le Serial-Port-Programming
   Mini HOWTO, au mme moment o je prparais ce document. Greg Hankins
   m'a demand d'inclure le Mini-HOWTO d'Antonino dans ce document.

   La structure de ce document et le formattage SGML ont t drivs du
   Serial-HOWTO de Greg Hankins. Merci galement pour diverses
   corrections faites par : Dave Pfaltzgraff
   (Dave_Pfaltzgraff@patapsco.com), Sean Lincolne (slincol@tpgi.com.au),
   Michael Wiedmann (mw@miwie.in-berlin.de), et Adrey Bonar
   (andy@tipas.lt).
