Gestion du port série en C

Gestion du port série en C #

L’objectif de ce travail est de gérer des données obtenues via le port série.

Si le port série a peu à peu disparu des PCs de bureau, il est encore largement répandu sur les cartes à micro-contrôleurs ou les machines monocartes types Raspberry. Il peut être aussi émulé sur un port USB, ce qui est maintenant la méthode d’utilisation la plus courante dans laquelle nous allons nous placer.

Votre objectif sera de récupérer des données émises par une carte à microcontrôleur, sur une Raspberry Pi, afin de les stocker.

Lecture ligne par ligne #

Sur le port série, la carte à microcontrôleur émet des lignes de texte. Notre code devra récupérer ces lignes de manière continue et les traiter.

L’ouverture et le réglage du port série étant un peu verbeux en C, une partie du code vous est fournie :

#include <stdio.h>
#include <string.h>

// Linux headers
#include <fcntl.h> 
#include <errno.h>
#include <termios.h>
#include <unistd.h> 

int configure_serial(char * file, int bauds) {
  int serial_port = open(file, O_RDONLY);
  struct termios tty;
  if (serial_port < 0) {
    fprintf(stderr, "Erreur à l'ouverture du fichier %s\n", file);
    return -1;
  }
  
  // Initialisation de la structure tty
  if(tcgetattr(serial_port, &tty) != 0) {
      fprintf(stderr,"Error %i from tcgetattr: %s\n", errno, strerror(errno));
      return -1;
  }

  tty.c_cflag &= ~PARENB; // Pas de bit de parité
  tty.c_cflag &= ~CSTOPB; // 1 bit stop
  tty.c_cflag &= ~CSIZE; // 8 bits de données (cleat + set)
  tty.c_cflag |= CS8; 
  tty.c_cflag &= ~CRTSCTS; // Désactiver RTS/CTS
  tty.c_cflag |= CREAD | CLOCAL; // Activation de la lecture et on ignore les inst. de contrôle

  tty.c_lflag |= ICANON; // lecture caractère par caractère et non ligne par ligne
  tty.c_lflag &= ~ECHO; // Pas d'écho
  tty.c_lflag &= ~ECHOE;
  tty.c_lflag &= ~ECHONL;
  tty.c_lflag &= ~ISIG; // On n'interpête pas les caractères INTR, QUIT and SUSP
  tty.c_iflag &= ~(IXON | IXOFF | IXANY); // Désactiver le contrôle de flux logiciel
  tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL); // Pas de traitement des octets de contrôle

  // tty.c_oflag &= ~OPOST; // Prevent special interpretation of output bytes (e.g. newline chars)
  // tty.c_oflag &= ~ONLCR; // Prevent conversion of newline to carriage return/line feed
  // tty.c_oflag &= ~OXTABS; // Prevent conversion of tabs to spaces (NOT PRESENT ON LINUX)
  // tty.c_oflag &= ~ONOEOT; // Prevent removal of C-d chars (0x004) in output (NOT PRESENT ON LINUX)

  tty.c_cc[VTIME] = 100;    // Lecture bloquante, avec un timeout de 10 secondes (unité : 0.1 s)
  tty.c_cc[VMIN] = 0;

  // Vitesse 
  cfsetispeed(&tty, bauds);
  //cfsetospeed(&tty, bauds);

  // Enregistrement des réglages
  if (tcsetattr(serial_port, TCSANOW, &tty) != 0) {
      fprintf(stderr,"Error %i from tcsetattr: %s\n", errno, strerror(errno));
      return -1;
  }
  return serial_port; 
}

int main(void) {
  // Buffer pour stocker les données lues
  // Une ligne ne pourra pas faire plus que 256 caractères
  char read_buf [256];
  int serial_port; 
  
  // Effacement du buffer
  memset(&read_buf, '\0', sizeof(read_buf));
  // Ouverture du port série
  serial_port=configure_serial("/dev/ttyUSB0", B9600);
  if (serial_port < 0) return 1;
  
  // La lecture des données est réalisé par un appel à la fonction read
  close(serial_port);
  return 0;
}

Dans le code qui précède, vous avez juste à compléter la fonction main, de manière à lire quelques lignes de texte avec la fonction read.

Pour compiler et exécuter du code sous Linux, si votre source s’appelle : read_serial_line :

$ gcc -Wall -o read_serial_line read_serial_line.c
$ ./read_serial_line