On Friday 31 March 2006 17:49, Erik Trauschke wrote:
Ich möchte unter Linux über die serielle Schnittstelle kommunizieren und dazu benutze ich den canonical read. Wenn jetzt die Gegenseite nichts sendet bleibt das Programm am read hängen. Um das zu umgehen habe ich mittels alarm() einen timeout gesetzt. Das Programm sieht etwa so aus:
[cut]
Das Programm funktioniert auch einwandfrei, allerdings nur genau einmal. Dann funktioniert der SIGALRM nicht mehr,
man sigaction
das Programm bleibt bei read stehen. Ich hab schon alle Varianten von alarm() an und aus an verschiedenen Stellen versucht, genauso ein Rücksetzen des Signals mittels signal(SIGALRM, SIG_DFL). Außerdem hab ich das ganze mittels setitimer anstatt alarm versucht, kein Erfolg. Es wird immer nur einmal durchlaufen. Bei verschiedenen Tests hab ich dann festgestellt, dass ohne setjmp/longjmp der alarm auch öfter funktioniert, also wenn im TimeoutHandler nur ne printf Anweisung steht.
Kann ich mir nicht vorstellen.
Kann mir irgendwer dazu nen Tipp geben? Muss man das SIGALRM Signal irgendwie rücksetzen oder vielleicht die env-Variable reseten?
Wenn Du signal verwendest musst Du jedesmal wieder den Handler registrieren. Bei sigaction kannst Du von vorneherein angeben, ob es bleiben soll.
Ausserdem ist es keine gute Idee die Variable "env" zu nennen - es gibt eine env-Variable in der libc.
Oder gibts noch ne andere möglichkeit einen Timeout für das serielle Lesen zu realisieren? Ich hab ein paar Versuche mit select() gemacht, das hat allerdings garnicht funktioniert.
select() sollte eigentlich die Lösung sein. Allerdings solltest Du dazu den Filedescriptor in den non-blocking-mode versetzen (man fcntl).
Wild im Programm herumzuspringen ist auf jeden Fall keine gute Idee - es kann zuviel dabei schiefgehen.
//open int fd=open("/dev/ttyS0",O_RDONLY); //set non-block int flag; fcntl(fd,F_GETFL,&flag); flag|=O_NONBLOCK; fcntl(fd,F_SETFL,&flag); //read while(1){ //select for read on fd int max=fd+1; fd_set rd; FD_ZERO(&rd); FD_SET(fd,&rd); //timeout: 5s 20ms struct timeval tmout; tmout.tv_sec=5; tmout.tv_usec=20000; //select int ret=select(max,&rd,0,0,&tmout); //check whether we can read if(ret>0 && FD_ISSET(fd,&rd)){ char buf[256]; ret=read(fd,buf,sizeof(buf)); if(ret>0)dosomething(buf,ret); else if(ret<0){ //error switch(errno){ case EAGAIN: case EINTR: //hmm, hickups, ignore it break; case EIO: fprintf(stderr,"I/O errors, panic!"); exit(1); break; //... } }else{//if(ret==0) fprintf(stderr,"End of stream on serial..."); exit(0); } }else{ fprintf(stderr,"timeout!"); gotosomewhereelse(); } }
Warnung: der Code ist nicht getestet, aber sollte Dir hoffentlich zeigen, wo der Fehler lag.
Warnung 2: ich habe C++-Syntax verwendet. Viel Spass beim Umstellen.
Konrad