Tous les exemples ont �t� extraits de miniterm.c
. Le tampon d'entr�e est limit� � 255 caract�res, tout comme l'est la longueur maximale d'une ligne en mode canonique (<linux/limits.h>
ou <posix1_lim.h>
).
R�f�rez-vous aux commentaires dans le code source pour l'explication des diff�rents modes d'entr�e. J'esp�re que le code est compr�hensible. L'exemple sur l'entr�e canonique est la plus comment�e, les autres exemples sont comment�s uniquement lorsqu'ils diff�rent, afin de signaler les diff�rences.
Les descriptions ne sont pas compl�tes, mais je vous encourage � modifier les exemples pour obtenir la solution la plus int�ressante pour votre application.
N'oubliez pas de donner les droits corrects aux ports s�rie (par exemple, chmod a+rw /dev/ttyS1
) !
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
/* les valeurs pour la vitesse, baudrate, sont d�finies dans <asm/termbits.h>, qui est inclus
dans <termios.h> */
#define BAUDRATE B38400
/* changez cette d�finition 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 p�riph�rique du modem en lecture/�criture, et pas comme
terminal de contr�le, puisque nous ne voulons pas �tre termin� si l'on
re�oit un caract�re 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 � z�ro */
/*
BAUDRATE: Affecte la vitesse. vous pouvez �galement utiliser cfsetispeed
et cfsetospeed.
CRTSCTS : contr�le de flux mat�riel (uniquement utilis� si le c�ble a
les lignes n�cessaires. Voir la section 7 du Serial-HOWTO).
CS8 : 8n1 (8 bits,sans parit�, 1 bit d'arr�t)
CLOCAL : connexion locale, pas de contr�le par le modem
CREAD : permet la r�ception des caract�res
*/
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 c�t� de la ligne
ne terminera pas l'entr�e).
sinon, utiliser l'entr�e sans traitement (device en mode raw).
*/
newtio.c_iflag = IGNPAR | ICRNL;
/*
Sortie sans traitement (raw).
*/
newtio.c_oflag = 0;
/*
ICANON : active l'entr�e en mode canonique
d�sactive toute fonctionnalit� d'echo, et n'envoit pas de signal au
programme appelant.
*/
newtio.c_lflag = ICANON;
/*
initialise les caract�res de contr�le.
les valeurs par d�faut peuvent �tre trouv�es dans
/usr/include/termios.h, et sont donn�es 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-caract�re non utilis� */
newtio.c_cc[VMIN] = 1; /* read bloquant jusqu'� l'arriv�e d'1 caract�re */
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' */
/*
� pr�sent, 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, � pr�sent on traite
les entr�es
Dans cet exemple, la r�ception d'un 'z' en d�but de ligne mettra
fin au programme.
*/
while (STOP==FALSE) { /* boucle jusqu'� condition de terminaison */
/* read bloque l'ex�cution du programme jusqu'� ce qu'un caract�re de
fin de ligne soit lu, m�me si plus de 255 caract�res sont saisis.
Si le nombre de caract�res lus est inf�rieur au nombre de caract�res
disponibles, des read suivant retourneront les caract�res restants.
res sera positionn� au nombre de caract�res 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 param�tres du port */
tcsetattr(fd,TCSANOW,&oldtio);
}
Dans le mode non canonique, les caract�res lus ne sont pas assembl�s ligne par ligne, et ils ne subissent pas de traitement (erase, kill, delete, etc...). Deux param�tres contr�lent ce mode : c_cc[VTIME]
positionne le timer de caract�res, et c_cc[VMIN]
indique le nombre minimum de caract�res � recevoir avant qu'une lecture soit satisfaite.
Si MIN > 0 et TIME = 0, MIN indique le nombre de caract�res � recevoir avant que la lecture soit satisfaite. TIME est �gal � z�ro, 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 caract�re est re�u, ou que la dur�e TIME est d�pass�e (t = TIME * 0.1s). Si TIME est d�pass�, aucun caract�re n'est retourn�.
Si MIN > 0 et TIME > 0, TIME est employ� comme timer entre chaque caract�re. La lecture sera satisfaite si MIN caract�res sont re�us, ou que le timer entre deux caract�res d�passe TIME. Le timer est r�initialis� � chaque fois qu'un caract�re est re�u, et n'est activ� qu'apr�s la r�ception du premier caract�re.
Si MIN = 0 et TIME = 0, le retour est imm�diat. Le nombre de caract�res disponibles, ou bien le nombre de caract�res 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 m�me r�sultat.
Vous pouvez tester tous les modes d�crit 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-caract�res non utilis� */
newtio.c_cc[VMIN] = 5; /* read bloquant jusqu'� ce que 5 */
/* caract�res soient lus */
tcflush(fd, TCIFLUSH);
tcsetattr(fd,TCSANOW,&newtio);
while (STOP==FALSE) { /* boucle de lecture */
res = read(fd,buf,255); /* retourne apr�s lecture 5 caract�res */
buf[res]=0; /* pour pouvoir les imprimer... */
printf(":%s:%d\n", buf, res);
if (buf[0]=='z') STOP=TRUE;
}
tcsetattr(fd,TCSANOW,&oldtio);
}
#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 re�u aucun signal */
main()
{
int fd,c, res;
struct termios oldtio,newtio;
struct sigaction saio; /* d�finition de l'action du signal */
char buf[255];
/* ouvre le port en mon non-bloquant (read retourne imm�diatement) */
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. g�n�ralement, on r�alise
des traitements � l'int�rieur de la boucle */
while (STOP==FALSE) {
printf(".\n");usleep(100000);
/* wait_flag = FALSE apr�s r�ception de SIGIO. Des donn�es 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 arr�te la boucle si on lit une
ligne seule */
wait_flag = TRUE; /* on attend de nouvelles donn�es */
}
}
/* restaure les anciens param�tres du port */
tcsetattr(fd,TCSANOW,&oldtio);
}
/***************************************************************************
* gestionnaire de signal. Positionne wait_flag � FALSE, pour indiquer � *
* la boucle ci-dessus que des caract�res ont �t� re�us. *
***************************************************************************/
void signal_handler_IO (int status)
{
printf("r�ception du signal SIGIO.\n);
wait_flag = FALSE;
}
Cette section est r�duite au minimum, et n'est l� que pour vous guider. Le code source d'exemple pr�sent� est donc r�duit au strict minimum. Il ne fonctionnera pas seulement avec des ports s�rie, mais avec n'importe quel ensemble de descripteurs de fichiers.
L'appel syst�me select et les macros qui lui sont attach�es 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 positionn�s 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 positionn�s. 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; /* entr�es 1 et 2 */
fd_set readfs; /* ensemble de descripteurs */
int maxfd; /* nombre max des descripteurs utilis�s */
int loop=1; /* boucle tant que TRUE */
/* open_input_source ouvre un p�riph�rique, 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; /* num�ro maximum du bit � tester */
/* boucle d'entr�e */
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 caract�res soient
disponibles en lecture */
select(maxfd, &readfs, NULL, NULL, NULL);
if (FD_ISSET(fd1)) /* caract�res sur 1 */
handle_input_from_source1();
if (FD_ISSET(fd2)) /* caract�res sur 2 */
handle_input_from_source2();
}
}
L'exemple ci-dessus bloque ind�finiment, jusqu'� ce que des caract�res 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 caract�res
disponibles = 0, il y a eu timeout */
Cet exemple verra l'expiration du delai de timeout apr�s une seconde. S'il y a timeout, select retournera 0, mais fa�tes attention, Timeout
est d�cr�ment� du temps r�ellement attendu par select
. Si la valeur de timeout est 0, select retournera imm�diatement.
Hosting by: Hurra Communications GmbH
Generated: 2007-01-26 18:01:16