Forum Programmation.c Port serie, Asynchrone, Thread

Posté par  .
Étiquettes : aucune
0
12
mar.
2006
Bonjour a tous/tes

Je suis en train d'écrire une application C/C++ qui dialogue avec une interface électronique par le biais d'un port série /dev/ttyS0. Il s'agit d'une communication asynchrone, même si dans 90% des cas, c'est mon application qui émet une trame puis l'interface qui répond.


J'ai pour le moment trouvé que deux solutions, mais aucunes des deux me semble correcte. Cependant, je vous les expose.

Première)
1 Je lis de manière bloquante le fichier /dev/ttS0 pendant 1 seconde.
2 Si j'ai un réponse, je traite puis je continu, sinon je continu
3 Si j'ai une trame à émettre, je l'émet
4 Je reviens à l'étape 1

Ce n'est pas très élégant, on boucle en permanence.

Deuxième)
1 Je crée un premier thread de lecture bloquante T1
1 Je lis de manière bloquante et définitive cette fois-ci.
2 Je viens de recevoir une réponse, je la traite
3 Je reviens à l'etape 1

2 Je créé un deuxième thread T2
1 J'attend un quelconque évènement (touche clavier par exemple)
2 J'emet une trame
3 Je reviens à l'étape 1

Cette façon n'est pas meilleur, car elle est très lourde. Il faut à la fois mettre en place un mécanisme de protection du descripteur de fichier. Mais aussi, un mécanisme de synchronisation entre ces 2 threads, car chaque fois que j'émet une trame je dois attendre un accuse de l'interface et inversement, si l'interface m'envoit une trame, je dois émettre un accusé + quelques cas particulier.

Vous en pensez quoi? J'attends vos avis avec impatience.
  • # Ah la la la !!!

    Posté par  (site web personnel) . Évalué à 1.

    Qu'est ce que ton périphérique?
    Il utilise un protocole qui gere les collisions (HDLC)?

    j'ai développé pas mal de périph rs232 (imprimantes indus, lecteurs de cartes magnétiques, antennes télépéage) et le mieux est

    - d'avoir un thread principal qui gere le 'fonctionnel', le chef d'orchestre
    - accès des fonctions 'haut niveau de ton périphérique' (et des autres)
    - reception des comptes rendu de transaction/gestion de l'état du périphérique

    - un thread qui gere le périph (un graph d'état)
    - emission/réception de requêtes unitaires
    - message de vie par timer

    - un thread qui gere la reception et l'émission de trames
    - gestion du protocole

    les 2 dernières threads peuvent etre mis en une seule si le périphérique est simple.

    chaque thread a généralement une file de messages à gérer
  • # Un classique...

    Posté par  (site web personnel) . Évalué à 1.

    Tu peux effectivement faire comme tu proposes : 2 threads, un specialisé dans la gestion de ttyS, l'autre dans la GUI. Eviter d'envoyer des trames ttyS a partir de la GUI : preferer une bonne vieille synchro pour reveiller le thread ttyS a partir de la GUI afin de lui faire transmettre les donnees sur le port serie (message queue posix, ou plus simplement write dans la GUI / select au niveau du thread ttyS). Comme ca le thread GUI ne s'occupe que des fenetres et pas des subtilites de l'acces au ttyS, le thread ttyS gere tout seul comme un grand le port serie, et il n'y a de facto pas de probleme de synchro sur le port serie puisque c'est le thread ttyS qui centralise et regule tous ces acces.

    Mais c'est un peu lourdingue, il n'y a pas besoin de sortir l'artillerie lourde pour ca. Une GUI, c'est ni plus ni moins qu'une boucle d'evenements. Il suffit donc de faire entrer les evenements ttyS dans cette boucle. En plus comme on est en multitache cooperatif dans ce cas, on n'a pas a craindre les acces concurrents sur le port serie. Par exemple, si la gui est en gtk, on utilisera g_main_add_poll/g_source_add de la glib. Presque tous les toolkits graphiques permettent de rajouter des file descriptors dans la boucle.
  • # Un peu de code

    Posté par  . Évalué à 1.

    Salut,
    En passant dans le coin, peux tu poster ton code pour acceder au RS232 ? surtout le moment de ça configuration Entrée sortie merci d'avance dsl d'avoir fait diverger le sujet
    • [^] # Re: Un peu de code

      Posté par  . Évalué à 1.

          struct termios configuration_originale;
          struct termios configuration_nouvelle;
      
          memset(&configuration_originale, 0, sizeof(struct termios));
          memset(&configuration_nouvelle, 0, sizeof(struct termios));
          
          fd = open(fichier.c_str(), O_RDWR | O_NOCTTY );
      
          if (fd<0)
      	{	    
      	    perror(fichier.c_str()); 
      	    return false;
      	}
      
          if(tcgetattr(fd, &configuration_nouvelle) != 0)
      	{
      	    return false;
      	}    
      
          memcpy(&configuration_originale, &configuration_nouvelle, sizeof(struct termios));
          cfmakeraw(&configuration_nouvelle);
      
          configuration_nouvelle.c_cflag &= ~PARENB;
          configuration_nouvelle.c_cflag |= B9600 | CSTOPB | CLOCAL | CS8 | CREAD;
      
          configuration_nouvelle.c_iflag = IGNPAR;
          configuration_nouvelle.c_oflag = 0;
      
          configuration_nouvelle.c_cc[VMIN] = 0;   /* nb caractères en attentes */
          configuration_nouvelle.c_cc[VTIME] = 100; /* en dixiemes de secondes */
      
          if(tcsetattr(fd, TCSANOW, &configuration_nouvelle) != 0)
      	{	 
      	    return false;
      	}
      
      Et à la fin de ton programme, tu réinjectes la configuration_originale dans le descripteur de fichier. Dans mon cas, j'utilise le /dev/ttyS0 de manière brute càd sans contrôle, d'où l'utilisation de la fonction cfmakeraw. Ensuite tu lis et ecris comme dans un fichier régulier sans te soucier de la position du curseur. N'hésites pas à poster si tu continus de rencontrer des problêmes.
  • # Et hop!

    Posté par  . Évalué à 1.

    Aprés quelques heures de recherche, j'ai enfin trouvé une bonne solution à mon problême, plus légère que les threads. Il s'agit d'une fonction système nomée fcntl. En gros, elle demande au noyau de surveiller les évènements qui peuvent se produire sur un descripteur de fichier. Lorsque ce dernier en capture un, il envoit un signal à l'application. Quelques structures et un gestionnaire de signal suffisent pour de mettre en place ce mécanisme. C'est niquel et ce n'est pas trop lourd.

    La description de la fonction fcntl
    http://www.opengroup.org/onlinepubs/009695399/functions/fcnt(...)

    Merci à vous trois.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.