//********************************************************************************************************************************************************************************** // Fichier SERIAL.C // // Contient toutes les fonctions liées aux ports série // //**********************************************************************************************************************************************************************************/ // Includes : #include "main.h" // Prototypes : void gestion_rx_serial0(void); void gestion_rx_serial1(void); int init_serial0(void); int init_serial1(void); // Variables globales : struct Struct_config_serial config_serial0; struct Struct_config_serial config_serial1; struct Struct_serial serial0; struct Struct_serial serial1; /********************************************************************************************************************************************************************************** Fonction gestion_rx_serial0 Fonction de réception des caractères provenant de Serial0 et leur enregistrement dans un buffer tournant (avec gestion de dépassement si 'ptr_fin' rattrape 'ptr_début') Ce port SERIAL 0 est affecté au M-Bus sur les CM3P (ShipBase V1) Ce port SERIAL 0 est affecté au GNSS sur les CM4 (ShipBase V2) **********************************************************************************************************************************************************************************/ void gestion_rx_serial0(void) { uint16_t i; uint8_t tmp_rx_buffer[MAX_TAILLE_TMP_RX_BUFFER_UART]; int16_t lg_tmp_rx_buffer; char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; if ((config_serial0.validite == 1) && (config_serial0.filestream != -1)) { lg_tmp_rx_buffer = read(config_serial0.filestream, tmp_rx_buffer, MAX_TAILLE_TMP_RX_BUFFER_UART); //Filestream, buffer to store in, number of bytes to read (max) if (lg_tmp_rx_buffer > 0) { for (i=0; i 0) { for (i=0; i variable locale options : if (tcgetattr(config_serial0.filestream, &options) < 0) { sprintf(tmp, "Initialisation de l'UART0 impossible : erreur lors de lecture des paramètres du port..."); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } //-------------------------------------------------------------------------------------------------------------------------------- // Mise à jour des paramètres non configurables dans la BDD : // Configuration du registre 'cflag' : // options.c_cflag = 0; options.c_cflag |= CLOCAL; // Ignore modem status lines options.c_cflag |= CREAD; // Enable receiver options.c_cflag &= ~CRTSCTS; // no hardware flowcontrol // options.c_cflag |= CMSPAR; // force Even parity to SPACE // Configuration du registre 'lflag' : // options.c_lflag = 0; options.c_lflag &= ~ECHO; options.c_lflag &= ~ECHOE; options.c_lflag &= ~ECHONL; options.c_lflag &= ~ICANON; options.c_lflag &= ~ISIG; options.c_lflag &= ~IEXTEN; // Configuration du registre 'iflag' : // options.c_iflag = 0; options.c_iflag &= ~IGNCR; // preserve carriage return options.c_iflag &= ~INLCR; // Don't map NL to CR on input options.c_iflag &= ~ICRNL; // Don't map CR to NL on input options.c_iflag &= ~IUCLC; // Don't map upper-case to lower-case on input options.c_iflag &= ~IUCLC; // Don't convert uppecase to lowercase on input options.c_iflag &= ~IMAXBEL; // Don't beep on reception as input buffer is full options.c_iflag &= ~IXANY; // Don't enable any character to restart outputno SW flowcontrol options.c_iflag &= ~IXON; // Don't enable start output control options.c_iflag &= ~IXOFF; // Don't enable stop output control (attention : doc pas très claire entre Xon et Xoff) options.c_iflag |= IGNBRK; // ignore breaks options.c_iflag &= ~ISTRIP; // Don't clear MSB (b8) on input options.c_iflag &= ~IGNPAR; // Don't ignore (check) parity errors options.c_iflag |= INPCK; // test parity options.c_iflag &= ~PARMRK; // Don't use verbose parity error (Signaler les erreurs de parité par une séquence 255-0-car. ) // Configuration du registre 'oflag' : options.c_oflag &= ~OPOST; // Don't use post-process output (?) // Configuration des caractères de contrôle 'c_cc' : // options.c_cc[VEOL] = 0; // options.c_cc[VEOL2] = 0; // options.c_cc[VEOF] = 0x04; //-------------------------------------------------------------------------------------------------------------------------------- // Initialisation de la vitesse de communication : switch(config_serial0.vitesse) { case 1200: { speed = B1200; break; } case 2400: { speed = B2400; break; } case 4800: { speed = B4800; break; } case 9600: { speed = B9600; break; } case 19200: { speed = B19200; break; } case 38400: { speed = B38400; break; } case 57600: { speed = B57600; break; } case 115200: { speed = B115200; break; } case 921600 : { speed = B921600; break; } default : { sprintf(tmp, "\tInitialisation de l'UART0 impossible : vitesse de communication non valide (%i b/s) ...", config_serial0.vitesse); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } // Mise à jour de la valeur dans la structure : cfsetospeed(&options, speed); cfsetispeed(&options, speed); // Mise à jour du message de configuration : sprintf(chaine_temp, "%i b/s", config_serial0.vitesse); strcat(tmp, chaine_temp); //-------------------------------------------------------------------------------------------------------------------------------- // Initialisation du nombre de bits de données : options.c_cflag &= ~CSIZE; // RAZ des bits concernés switch(config_serial0.longueur) { case 8: { options.c_cflag |= CS8; break; } case 7: { options.c_cflag |= CS7; break; } case 6: { options.c_cflag |= CS6; break; } case 5: { options.c_cflag |= CS5; break; } default : { sprintf(tmp, "Initialisation de l'UART0 impossible : nombre de bits de données non valide (%i bits) ...", config_serial0.longueur); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } // Mise à jour du message de configuration : sprintf(chaine_temp, ", %i bits", config_serial0.longueur); strcat(tmp, chaine_temp); //-------------------------------------------------------------------------------------------------------------------------------- // Initialisation de la parité : // ATTENTION : les tests de parité ne semblent pas fonctionner !!! Leur configuration ne semble avoir aucun effet (pas d'erreur générée). switch(config_serial0.parite) { case 0: // Pas de parité : { options.c_cflag &= ~PARENB; /* Disable parity */ strcat(tmp, ", pas de parité"); break; } case 1: // Parité impaire : { options.c_cflag |= PARENB; // Parité validée options.c_cflag |= PARODD; /* Odd parity */ strcat(tmp, ", parité impaire"); break; } case 2: // Parité paire : { options.c_cflag |= PARENB; // Parité validée options.c_cflag &= ~PARODD; /* Even parity */ strcat(tmp, ", parité paire"); break; } default : { sprintf(tmp, "\tInitialisation de l'UART0 impossible : parité non valide (%i) ...", config_serial0.parite); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } //-------------------------------------------------------------------------------------------------------------------------------- // Initialisation du nombre de bits de stop : switch(config_serial0.stops) { case 1: { options.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ strcat(tmp, ", un bit de stop"); break; } case 2: { options.c_cflag |= CSTOPB; /* activate double stop bits */ strcat(tmp, ", deux bits de stop"); break; } default : { sprintf(tmp, "Initialisation de l'UART0 impossible : nombre de bits de stop non valide (%i) ...", config_serial0.stops); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } //-------------------------------------------------------------------------------------------------------------------------------- // Mise à jour des nouveaux paramètres : tcsetattr(config_serial0.filestream, TCSANOW, &options); // Mise à jour des nouvelles valeurs de configuration (depuis 'options') delai_dixieme_sec(2); // Délai nécessaire pour que le flush fonctionne (testé avec délai = 1 : Ok) tcflush(config_serial0.filestream, TCIOFLUSH); // Vidage du port (en Inputs et en Ouptuts) //-------------------------------------------------------------------------------------------------------------------------------- // Finalisation du message de débug : strcat(tmp, ")\t: OK"); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK); return(0); } else // Cas où l'ouverture du port ne s'est pas passée correctement : { sprintf(tmp, "Initialisation de l'UART0 impossible : erreur lors de l'ouverture du port..."); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } else // L'UART n'est pas validé : { sprintf(tmp, "La configuration en cours ne prévoit pas l'utilisation de l'UART0 (la configuration de celui-ci n'a pas été affectée par l'application)..."); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); return(0); // On ne considère pas cela comme une erreur et l'init peut continuer. } } /********************************************************************************************************************************************************************************** Fonction init_serial1 Fonction d'initialisation de la liaison 'serial1'. **********************************************************************************************************************************************************************************/ int init_serial1(void) { char chaine_temp[MAX_TAILLE_CHAINE_TEMP_UARTS]; struct termios options; speed_t speed; char tmp[MAX_LONGUEUR_BUFFER_TEMPORAIRE_DEBUG]; // Paramètres de configuration (en dur car inutile de les importer de la BDD) : config_serial1.validite = 1; config_serial1.vitesse = 115200; // 1200 à 115200 config_serial1.longueur = 8; // 7 ou 8 config_serial1.parite = 0; // 0=No, 1=Odd et 2=Even config_serial1.stops = 1; // 1 ou 2 if (config_serial1.validite == 1) // Cas où la config en cours prévoit l'utilisation de l'UART1 : { config_serial1.filestream = -1; sprintf(tmp, "Initialisation de l'UART1 ("); config_serial1.filestream = open("/dev/serial1", O_RDWR | O_NOCTTY | O_NDELAY); //Open in non blocking read/write mode // O_NDELAY / O_NONBLOCK (same function) - Enables nonblocking mode. When set read requests on the file can return immediately with a failure status // if there is no input immediately available (instead of blocking). Likewise, write requests can also return // immediately with a failure status if the output can't be written immediately. // O_NOCTTY - When set and path identifies a terminal device, open() shall not cause the terminal device to become the controlling terminal for the process. if (config_serial1.filestream != -1) { //The flags (defined in /usr/include/termios.h - see http://pubs.opengroup.org/onlinepubs/007908799/xsh/termios.h.html): // Baud rate:- B1200, B2400, B4800, B9600, B19200, B38400, B57600, B115200, B230400, B460800, B500000, B576000, B921600, B1000000, B1152000, B1500000, B2000000, B2500000, B3000000, B3500000, B4000000 // CSIZE:- CS5, CS6, CS7, CS8 // CLOCAL - Ignore modem status lines // CREAD - Enable receiver // IGNPAR = Ignore characters with parity errors // ICRNL - Map CR to NL on input (Use for ASCII comms where you want to auto correct end of line characters - don't use for binary comms!) // PARENB - Parity enable // PARODD - Odd parity (else even) //-------------------------------------------------------------------------------------------------------------------------------- // Lecture de la configuration en cours => variable locale options : if (tcgetattr(config_serial1.filestream, &options) < 0) { sprintf(tmp, "Initialisation de l'UART1 impossible : erreur lors de lecture des paramètres du port..."); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } //-------------------------------------------------------------------------------------------------------------------------------- // Mise à jour des paramètres non configurables dans la BDD : // Configuration du registre 'cflag' : // options.c_cflag = 0; options.c_cflag |= CLOCAL; // Ignore modem status lines options.c_cflag |= CREAD; // Enable receiver options.c_cflag &= ~CRTSCTS; // no hardware flowcontrol // options.c_cflag |= CMSPAR; // force Even parity to SPACE // Configuration du registre 'lflag' : // options.c_lflag = 0; options.c_lflag &= ~ECHO; options.c_lflag &= ~ECHOE; options.c_lflag &= ~ECHONL; options.c_lflag &= ~ICANON; options.c_lflag &= ~ISIG; options.c_lflag &= ~IEXTEN; // Configuration du registre 'iflag' : // options.c_iflag = 0; options.c_iflag &= ~IGNCR; // preserve carriage return options.c_iflag &= ~INLCR; // Don't map NL to CR on input options.c_iflag &= ~ICRNL; // Don't map CR to NL on input options.c_iflag &= ~IUCLC; // Don't map upper-case to lower-case on input options.c_iflag &= ~IUCLC; // Don't convert uppecase to lowercase on input options.c_iflag &= ~IMAXBEL; // Don't beep on reception as input buffer is full options.c_iflag &= ~IXANY; // Don't enable any character to restart outputno SW flowcontrol options.c_iflag &= ~IXON; // Don't enable start output control options.c_iflag &= ~IXOFF; // Don't enable stop output control (attention : doc pas très claire entre Xon et Xoff) options.c_iflag |= IGNBRK; // ignore breaks options.c_iflag &= ~ISTRIP; // Don't clear MSB (b8) on input options.c_iflag &= ~IGNPAR; // Don't ignore (check) parity errors options.c_iflag |= INPCK; // test parity options.c_iflag &= ~PARMRK; // Don't use verbose parity error (Signaler les erreurs de parité par une séquence 255-0-car. ) // Configuration du registre 'oflag' : options.c_oflag &= ~OPOST; // Don't use post-process output (?) // Configuration des caractères de contrôle 'c_cc' : // options.c_cc[VEOL] = 0; // options.c_cc[VEOL2] = 0; // options.c_cc[VEOF] = 0x04; //-------------------------------------------------------------------------------------------------------------------------------- // Initialisation de la vitesse de communication : switch(config_serial1.vitesse) { case 1200: { speed = B1200; break; } case 2400: { speed = B2400; break; } case 4800: { speed = B4800; break; } case 9600: { speed = B9600; break; } case 19200: { speed = B19200; break; } case 38400: { speed = B38400; break; } case 57600: { speed = B57600; break; } case 115200: { speed = B115200; break; } case 921600 : { speed = B921600; break; } default : { sprintf(tmp, "\tInitialisation de l'UART1 impossible : vitesse de communication non valide (%i b/s) ...", config_serial1.vitesse); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } // Mise à jour de la valeur dans la structure : cfsetospeed(&options, speed); cfsetispeed(&options, speed); // Mise à jour du message de configuration : sprintf(chaine_temp, "%i b/s", config_serial1.vitesse); strcat(tmp, chaine_temp); //-------------------------------------------------------------------------------------------------------------------------------- // Initialisation du nombre de bits de données : options.c_cflag &= ~CSIZE; // RAZ des bits concernés switch(config_serial1.longueur) { case 8: { options.c_cflag |= CS8; break; } case 7: { options.c_cflag |= CS7; break; } case 6: { options.c_cflag |= CS6; break; } case 5: { options.c_cflag |= CS5; break; } default : { sprintf(tmp, "Initialisation de l'UART1 impossible : nombre de bits de données non valide (%i bits) ...", config_serial1.longueur); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } // Mise à jour du message de configuration : sprintf(chaine_temp, ", %i bits", config_serial1.longueur); strcat(tmp, chaine_temp); //-------------------------------------------------------------------------------------------------------------------------------- // Initialisation de la parité : // ATTENTION : les tests de parité ne semblent pas fonctionner !!! Leur configuration ne semble avoir aucun effet (pas d'erreur générée). switch(config_serial1.parite) { case 0: // Pas de parité : { options.c_cflag &= ~PARENB; /* Disable parity */ strcat(tmp, ", pas de parité"); break; } case 1: // Parité impaire : { options.c_cflag |= PARENB; // Parité validée options.c_cflag |= PARODD; /* Odd parity */ strcat(tmp, ", parité impaire"); break; } case 2: // Parité paire : { options.c_cflag |= PARENB; // Parité validée options.c_cflag &= ~PARODD; /* Even parity */ strcat(tmp, ", parité paire"); break; } default : { sprintf(tmp, "\tInitialisation de l'UART1 impossible : parité non valide (%i) ...", config_serial1.parite); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } //-------------------------------------------------------------------------------------------------------------------------------- // Initialisation du nombre de bits de stop : switch(config_serial1.stops) { case 1: { options.c_cflag &= ~CSTOPB; /* only need 1 stop bit */ strcat(tmp, ", un bit de stop"); break; } case 2: { options.c_cflag |= CSTOPB; /* activate double stop bits */ strcat(tmp, ", deux bits de stop"); break; } default : { sprintf(tmp, "Initialisation de l'UART1 impossible : nombre de bits de stop non valide (%i) ...", config_serial1.stops); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } //-------------------------------------------------------------------------------------------------------------------------------- // Mise à jour des nouveaux paramètres : tcsetattr(config_serial1.filestream, TCSANOW, &options); // Mise à jour des nouvelles valeurs de configuration (depuis 'options') delai_dixieme_sec(2); // Délai nécessaire pour que le flush fonctionne (testé avec délai = 1 : Ok) tcflush(config_serial1.filestream, TCIOFLUSH); // Vidage du port (en Inputs et en Ouptuts) //-------------------------------------------------------------------------------------------------------------------------------- // Finalisation du message de débug : strcat(tmp, ")\t: OK"); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_OK); return(0); } else // Cas où l'ouverture du port ne s'est pas passée correctement : { sprintf(tmp, "Initialisation de l'UART1 impossible : erreur lors de l'ouverture du port..."); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_ERREUR); return(-1); } } else // L'UART n'est pas validé : { sprintf(tmp, "La configuration en cours ne prévoit pas l'utilisation de l'UART1 (la configuration de celui-ci n'a pas été affectée par l'application)..."); affichage_debug(__FILE__, __LINE__, tmp, TYPE_MESSAGE_DEBUG_WARNING); return(0); // On ne considère pas cela comme une erreur et l'init peut continuer. } }