Problème ferture port serie

blackswords

Membre confirmé
18 Janvier 2009
31
0
Bonjour à tous! Voilà, je viens vous voir car j'ai un petit soucis qui commence à être franchement agaçant à la longue. J'essaie de faire un petit programme pour envoyer et recevoir des données sur un port série (j'utilise un adaptateur USB-Série à base de PL2303) afin de communiquer avec une carte électronique que je réalise.

J'ai trouvé un exemple de code en C sur internet qui montre comment ouvrir un port série, lire et envoyer des données puis le fermer donc je l'ai récupéré, j'ai fait des petites modifs pour que ça fasse ce dont j'ai envie et jusque là ça va. J'arrive à lire des données sans problèmes, j'arrive à en envoyer aussi mais très souvent, quand c'est pour de l'envoi, le programme n'arrive pas à fermer le port et il devient donc inutilisable. J'ai beau débrancher puis rebrancher l'adaptateur, rien n'y change. Et même une fois déconnecté, si je fais dans le terminal "ls /dev/tty.*" ou "ls /dev/cu.*" il est encore présent et la seule solution que j'ai trouvé c'est de redémarrer le Mac... (et même la plupart du temps mon macbook n'arrive pas à s'éteindre et je suis obligé de le forcer en restant appuyer sur le bouton power).

Je sais pas si c'est mon code qui est foireux ou si ya une technique pour débloquer le port après un bug donc je vous met le code et si quelque chose vous parait douteux signalez le moi. Juste pour finir, je me débrouille plutôt bien en C mais je n'y connais vraiment pas grand chose à la gestion des ports série.

Bloc de code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>

int main(int argc,char** argv) {
    struct termios tio;
    struct termios stdio;
    int tty_fd;
    
    char aff[]="SALUT salut$";
    char device[]="/dev/tty.usbserial";
    
    printf("Ouverture de %s\n",device);
    tty_fd=open(device, O_RDWR | O_NONBLOCK | O_NOCTTY); 
    if(tty_fd<0) {
        printf("Problème d'ouverture du port : code %d\n",tty_fd);
        return 0;
    }
    else printf("Port ouvert\n");
        
    memset(&stdio,0,sizeof(stdio));
    stdio.c_iflag=0;
    stdio.c_oflag=0;
    stdio.c_cflag=0;
    stdio.c_lflag=0;
    stdio.c_cc[VMIN]=1;
    stdio.c_cc[VTIME]=0;
    tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
    tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);       // make the reads non-blocking
    
    
    memset(&tio,0,sizeof(tio));
    tio.c_iflag=0;
    tio.c_oflag=0;
    tio.c_cflag=CS8|CREAD|CLOCAL;           // 8n1, see termios.h for more information
    tio.c_lflag=0;
    tio.c_cc[VMIN]=1;
    tio.c_cc[VTIME]=5;
    
    cfsetospeed(&tio,B9600);            // 9600 baud
    cfsetispeed(&tio,B9600);            // 9600 baud
    
    tcsetattr(tty_fd,TCSANOW,&tio);
    
    printf("Ecriture...\n");

    write(tty_fd, aff, 12);
    
    printf("Fermeture...\n");
    close(tty_fd);
    
    printf("Port fermé\n");
    
    return 0;
}

p.s : je me sert du caractère '$' pour signaler à ma carte électronique que la chaine reçue est fini et qu'il faut l'afficher donc ne vous en souciez pas
 

tatouille

Membre expert
1 Juin 2004
5 174
493
Stanford CA
blabla
[/CODE]p.s : je me sert du caractère '$' pour signaler à ma carte électronique que la chaine reçue est fini et qu'il faut l'afficher donc ne vous en souciez pas

hop regarde chez moi:

http://code.google.com/p/le-depotoir/source/browse/trunk/user-set/do_opentty.c // note que l'exemple date d'assez longtemps mais ca marche toujours :-8

c'est comme les sockets ca a besoin d'un "shutdown" a toi de l'implementer surtout si plusieurs app peuvent se connecter en meme temps au meme device

je te conseille de commencer ton programme proprement, spawning a thread avec des callbacks intelligents,

open()
talk()
prompt()
quit()
close()

j'avais ecris un article (presque 10 ans whouhou) assez complet avec un exemple d'emulateur pouvant switcher serial/iokit USB/Firewire afin de faciliter a l'epoque le port d'apps opensource basé sur la presence d'un character device
si je retrouve ca je le posterais ici
 

blackswords

Membre confirmé
18 Janvier 2009
31
0
Merci de ta réponse. Comme je l'avais dit dans mon post, j'ai connais pas grand chose à tout ça donc pour moi une phrase comme " je te conseille de commencer ton programme proprement, spawning a thread avec des callbacks intelligents" c'est un peu comme du chinois. Je vais tester ton code pour voir ce que ça donne mais juste comme ça, à première vue, c'est quoi qui ferai planter mon programme?
 

blackswords

Membre confirmé
18 Janvier 2009
31
0
Je ne pouvais plus éditer mon post donc voilà les avancements.

En faisant un mix en ton programme et le mien j'ai enfin réussi à faire en sorte que le port ne se bloque plus mais par contre, je sais pas si ça vient du programme ou de mon adaptateur usb/serie, mais les données ne sortent pas à tous les coups... Souvent, la première fois que je lance le programme tout va bien, la petite loupiote de l'adaptateur s'allume signalant que des données sont envoyées et je récupère bien le texte envoyé sur l'écran de ma carte électronique mais quand je le relance une autre fois, les données ne sortent plus ou alors elle sont bien envoyées une fois sur 10. D'après vous, d'où vient le problème? Voici le nouveau code :

Bloc de code:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>

int tty_fd;
struct termios tio;
struct termios stdio;


static void mssleep(int msec) {
    usleep(msec * 1000);
}

static void tty_flush(void) {
    if (0 <= tty_fd) {
        tcsetattr(tty_fd, TCSAFLUSH, &tio);
        tty_fd = -1;
    }
}

int main(int argc,char** argv) {
    int  send,l;
    
    char aff[]="youplaboom";
    char device[]="/dev/cu.usbserial";
    
    l=strlen(aff);
    
    printf("Ouverture de %s\n",device);
    tty_fd=open(device, O_RDWR | O_NONBLOCK | O_NOCTTY); 
    if(tty_fd<0) {
        printf("Problème d'ouverture du port : code %d\n",tty_fd);
        close(tty_fd);
        return 0;
    }
    else printf("Port ouvert\n");
            
    memset(&stdio,0,sizeof(stdio));
    stdio.c_iflag=0;
    stdio.c_oflag=0;
    stdio.c_cflag=0;
    stdio.c_lflag=0;
    stdio.c_cc[VMIN]=1;
    stdio.c_cc[VTIME]=0;
    tcsetattr(STDOUT_FILENO,TCSANOW,&stdio);
    tcsetattr(STDOUT_FILENO,TCSAFLUSH,&stdio);
    fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK);
    
    
    memset(&tio,0,sizeof(tio));
    tio.c_iflag=0;
    tio.c_oflag=0;
    tio.c_cflag=CS8|CREAD|CLOCAL;
    tio.c_lflag=0;
    tio.c_cc[VMIN]=1;
    tio.c_cc[VTIME]=5;
    
    cfsetospeed(&tio,B9600);            // 9600 baud
    cfsetispeed(&tio,B9600);            // 9600 baud
    
    tcsetattr(tty_fd,TCSANOW,&tio);
    
    printf("Ecriture...\n");

    send = write(tty_fd, aff, l+1);
    if(send<=l) {
        printf("L'écriture a échouée, %d octet(s) envoyés\n",send);
        close(tty_fd);
        return 0;
    }
    
    printf("%d octets evoyés\n",send);
    
    tty_flush();
    
    mssleep(100);
    
    printf("Fermeture...\n");
    close(tty_fd);
    
    printf("Port fermé\n");
    
    return 0;
}