Raspberry pi : Protection des ressources GPIO
Répondre à la discussion
Affichage des résultats 1 à 12 sur 12

Raspberry pi : Protection des ressources GPIO



  1. #1
    shinishi

    Raspberry pi : Protection des ressources GPIO


    ------

    Bonjour à tous,

    je viens à la recherche d'idées parce que j'en suis à court. J'ai récemment fait une bibliothèque de fonctions permettant de diriger les pins GPIO sur mon raspberry pi. Je souhaiterai mettre un capteur de température et d'hygrométrie (le DHT22). Pour cela, je vais faire une bibliothèque qui s'appuie sur la précédente. Mais, je me suis rendu compte que deux processus pourraient avoir envie d'utiliser la même pin en même temps, ce qui parasiterait totalement la lecture ou l'écriture sur le médium. C'est pour cette raison que je souhaiterai protéger l'accès aux ressources en m'appuyant sur le principe du sémaphore.

    Pour cela, j'avais imaginé lancer un programme qui réserve quelques octets dans la mémoire centrale et qui enregistrerait le PID du processus qui a accès à la ressource en question. Une fois fini, ce programme remet à zéro les octets en question. Le fonctionnement est similaire aux fonctions init,P et V. Le problème est qu'il faut que tous les processus aient l'adresse de cette espace mémoire et qu'ils puissent y accéder. Je pensais enregistrer l'adresse comme variable d'environnement du système avec setenv(). Mais, je ne sais pas comment récupérer l'adresse comme les variables d'environnement sont des chaînes de caractère.

    Quelqu'un aurait-il une meilleure idée ou une solution à mon problème ?

    Merci par avance.

    shinishi

    -----

  2. #2
    lou_ibmix_xi

    Re : Raspberry pi : Protection des ressources GPIO

    Faire un "vrai" pilote, pour que le noyau gère les accès. En plus, ça ira plus vite.
    Mais ça impose le C et l'interface est "imposée"
    Dernière modification par lou_ibmix_xi ; 26/01/2016 à 21h45.

  3. #3
    shinishi

    Re : Raspberry pi : Protection des ressources GPIO

    Justement, j'ai fait une bibliothèque en C pour gérer les GPIO, mais quelle méthode pour protéger les ressources ?

  4. #4
    Jack
    Modérateur

    Re : Raspberry pi : Protection des ressources GPIO

    Pourquoi ne pas utiliser les ressources de l'OS, en l'occurrence les mutex et sémaphores?

  5. A voir en vidéo sur Futura
  6. #5
    shinishi

    Re : Raspberry pi : Protection des ressources GPIO

    Je vais essayer avec les mutex, bien que je ne sois pas très à l'aise avec cette notion.

  7. #6
    Jack
    Modérateur

    Re : Raspberry pi : Protection des ressources GPIO

    Si tu connais le sémaphores, ça ne devrait pas te poser de problème.

    Tu peux éventuellement intégrer la bibliothèque wiringpi qui permet de les manipuler de manière simplifiée.

    A+

  8. #7
    lou_ibmix_xi

    Re : Raspberry pi : Protection des ressources GPIO

    Citation Envoyé par shinishi Voir le message
    Justement, j'ai fait une bibliothèque en C pour gérer les GPIO, mais quelle méthode pour protéger les ressources ?
    Faire une bibliothèque en C et faire un pilote de périphérique ce n'est pas la même chose... Tes ressources seront alors protégées par le noyau linux

  9. #8
    lou_ibmix_xi

    Re : Raspberry pi : Protection des ressources GPIO

    Citation Envoyé par Jack Voir le message
    Pourquoi ne pas utiliser les ressources de l'OS, en l'occurrence les mutex et sémaphores?
    Deux petites remarques, mutex et semaphore ne sont pas forcément interchangeables. En théorie, un mutex doit être libéré par le détenteur, ce qui n'est pas le cas du semaphore. Donc en général le mutex est utilisé pour protéger une ressource, et le semaphore pour synchroniser. En pratique, un mutex est souvent un semaphore initialisé à 1 qui est sa valeur maximale.
    De plus, la problématique est "inter-process", donc pas de mutex_t, il faut regarder du côté "Inter Process Communication" (man svipc)

  10. #9
    Jack
    Modérateur

    Re : Raspberry pi : Protection des ressources GPIO

    Exact, les mutex sont réservés aux threads, donc au sein du même processus.

  11. #10
    lou_ibmix_xi

    Re : Raspberry pi : Protection des ressources GPIO

    Citation Envoyé par Jack Voir le message
    Exact, les mutex sont réservés aux threads, donc au sein du même processus.
    Je chipote mais c'est, en théorie, orthogonal. Mutex et sémaphores sont des objets différents, protection de ressources ou synchronisation, c'est du côté conception. Ces 2 concepts peuvent être utilisés dans un contexte multi-thread ou multi-processus, selon le partage mémoire, c'est plus du côté implémentation. Dans la réalité le mutex n'existe que s'il permet une optimisation, sinon tu l'émules avec un sémaphore. Par exemple, dans le contexte multi-thread linux, le pthread_mutex_t permet une optimisation par rapport au sémaphores sem_t, mais dans un contexte multi-processus il n'y a aucune optimisation possible (ou personne ne l'a écrite) donc on utilise uniquement des semaphophes ipc, et on émule un mutex avec. C'est tous de mémoire, j'ai pas les man sur mon ordi, honte à moi !!!

  12. #11
    shinishi

    Re : Raspberry pi : Protection des ressources GPIO

    Bonsoir,

    je dois avouer que la différence pour un amateur comme moi n'est pas flagrante mais je crois avoir quand même compris (je suis plus un matheux en fait).
    Du coup, je voulais avoir votre avis sur l'utilisation que j'ai faite des mutex dans mon code. Selon vous, le sémaphore aurait-il été plus approprié ?

    En fait, j'essaie de lire dans un fichier de planification des dates et des données temporels.
    Bon, après c'est surtout la dernière fonction avec l'utilisation des mutex qui m'inquiètent même si j'ai une erreur de segmentation qu'il faut que je corrige.

    N'hésitez pas à me filer des astuces SVP concernant la rédaction de mon code.
    Comme je suis novice, ça pourrait m'aider.

    Merci par avance.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <time.h>
    #include <pthread.h>
    /*********************************************/
    /*	     LES OFFSETS DU FICHIER 	     */
    /*********************************************/
    #define OFFSET_DATE_BUTOIR SEEK_SET+20
    #define OFFSET_PERIODE 20+OFFSET_DATE_BUTOIR
    #define OFFSET_DEBUT_PLANIFICATION OFFSET_PERIODE+9
    #define OFFSET_EVENT_FIN 18
    #define OFFSET_LIGNE_PLANIFICATION 34
    /*********************************************/
    #define TAILLE_MOIS 2
    #define TAILLE_ANNEE 4
    #define TAILLE_JOUR 2
    #define TAILLE_HEURE 2
    #define TAILLE_MINUTE 2
    #define TAILLE_SECONDE 2
    #define TAILLE_SEPARATEUR_DATE 1
    #define TAILLE_SEPARATEUR_HEURE 1
    #define TAILLE_SEPARATION_DATE_HEURE 1
    #define TAILLE_SEPARATION_PERIODE 2
    #define TAILLE_SEPARATION_PLANIFICATION 3
    #define TAILLE_JOUR_PERIODE 5
    #define NBRE_SECONDE_JOUR 86400
    #define NBRE_SECONDE_HEURE 3600
    #define NBRE_SECONDE_MINUTE 60
    /*********************************************/
    #define TAILLE_BUFFER 50
    
    /* EXEMPLE DE STRUCTURE DE FICHIERS
       29/02/2016 18:00:00
       28/03/2016 18:00:00
       00001d 00:00:00 
       00000d 04:00:00 - 00000d 05:30:00
       00000d 22:00:00 - 00000d 23:30:00
    
       La première ligne est la date d'initialisation
       La seconde ligne est la date butoir
       La troisième ligne est la période 
       Les autres lignes définissent la planification */
    
    //Cette fonction lit la première ligne du fichier qui est la date d'initialisation
    static long lire_initializer(FILE * file)
    {
    	struct tm * initializer;
    	char * buffer;
    	fseek(file,0,SEEK_SET);
    	printf("Ligne 56");
    	fgets(buffer,TAILLE_JOUR,file);
    	printf("Ligne 56");
    	initializer->tm_mday=atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_DATE,SEEK_CUR);
    	fgets(buffer,TAILLE_MOIS,file);
    	initializer->tm_mon=atoi(buffer)-1;
    	fseek(file,TAILLE_SEPARATEUR_DATE,SEEK_CUR);
    	fgets(buffer,TAILLE_ANNEE,file);
    	initializer->tm_year=atoi(buffer)-1900;
    	fseek(file,TAILLE_SEPARATION_DATE_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_HEURE,file);
    	initializer->tm_hour=atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_MINUTE,file);
    	initializer->tm_min=atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_SECONDE,file);
    	initializer->tm_sec=atoi(buffer);
    	return mktime(initializer);
    }
    
    //Cette fonction lit la deuxième ligne du fichier qui est la date butoir
    static long lire_ender(FILE * file)
    {
    	struct tm * ender;
    	char * buffer;
    	fseek(file,0,OFFSET_DATE_BUTOIR);
    	fgets(buffer,TAILLE_JOUR,file);
    	ender->tm_mday=atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_DATE,SEEK_CUR);
    	fgets(buffer,TAILLE_MOIS,file);
    	ender->tm_mon=atoi(buffer)-1;
    	fseek(file,TAILLE_SEPARATEUR_DATE,SEEK_CUR);
    	fgets(buffer,TAILLE_ANNEE,file);
    	ender->tm_year=atoi(buffer)-1900;
    	fseek(file,TAILLE_SEPARATION_DATE_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_HEURE,file);
    	ender->tm_hour=atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_MINUTE,file);
    	ender->tm_min=atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_SECONDE,file);
    	ender->tm_sec=atoi(buffer);
    	return mktime(ender);
    }
    
    //cette fonction lit la troisième ligne du fichier qui est le temps de la période
    static long lire_period(FILE * file)
    {
    	char * buffer;
    	long compteur;
    	fseek(file,0,OFFSET_PERIODE);
    	fgets(buffer,TAILLE_JOUR_PERIODE,file);
    	compteur=NBRE_SECONDE_JOUR*atoi(buffer);
    	fseek(file,TAILLE_SEPARATION_PERIODE,SEEK_CUR);
    	fgets(buffer,TAILLE_HEURE,file);
    	compteur+=NBRE_SECONDE_HEURE*atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_MINUTE,file);
    	compteur+=NBRE_SECONDE_MINUTE*atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_SECONDE,file);
    	compteur+=atoi(buffer);
    	return compteur;
    	 
    }
    
    static long lire_debut_ligne(FILE * file, int ligne)
    {
    	long compteur;
    	char * buffer;
    	fseek(file,0,OFFSET_DEBUT_PLANIFICATION+ligne*OFFSET_LIGNE_PLANIFICATION);
    	fgets(buffer,TAILLE_JOUR_PERIODE,file);
    	compteur=NBRE_SECONDE_JOUR*atoi(buffer);
    	fseek(file,TAILLE_SEPARATION_PERIODE,SEEK_CUR);
    	fgets(buffer,TAILLE_HEURE,file);
    	compteur+=NBRE_SECONDE_HEURE*atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_MINUTE,file);
    	compteur+=NBRE_SECONDE_MINUTE*atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_SECONDE,file);
    	compteur+=atoi(buffer);
    	return compteur;
    }
    
    static long lire_fin_ligne(FILE * file, int ligne)
    {
    	long compteur;
    	char * buffer;
    	fseek(file,0,OFFSET_DEBUT_PLANIFICATION+ligne*OFFSET_LIGNE_PLANIFICATION+OFFSET_EVENT_FIN);
    	fgets(buffer,TAILLE_JOUR_PERIODE,file);
    	compteur=NBRE_SECONDE_JOUR*atoi(buffer);
    	fseek(file,TAILLE_SEPARATION_PERIODE,SEEK_CUR);
    	fgets(buffer,TAILLE_HEURE,file);
    	compteur+=NBRE_SECONDE_HEURE*atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_MINUTE,file);
    	compteur+=NBRE_SECONDE_MINUTE*atoi(buffer);
    	fseek(file,TAILLE_SEPARATEUR_HEURE,SEEK_CUR);
    	fgets(buffer,TAILLE_SECONDE,file);
    	compteur+=atoi(buffer);
    	return compteur;
    }
    
    static long actualiser_donnees(char * addr)
    {
    	long date_event_fin,date_event_debut, now;
    	long initializer,ender, period,clock_synchro;
    	int i,ligne;	
    	pthread_mutex_t verrou = PTHREAD_MUTEX_INITIALIZER;
    	printf("Ligne 177");
    	FILE * file=NULL;
    	now=time(NULL);
    	ligne=0;
    	printf("Ligne 181");
    	//début de l'exclusion mutuelle
    	pthread_mutex_lock(&verrou);
    	file = fopen(addr,"r");
    	printf("Ligne 185");
    	if (file==NULL)
    	{
    		printf("FICHIER : %s \n L'ouverture du fichier a échoué à l'actualisation des données.\n Peut-être la ressource est déjà utilisée par un autre processus",addr);
    		
    	}
    	else
    	{
    		printf("Ligne 193");
    		initializer=lire_initializer(file);
    		period=lire_period(file);
    		ender=lire_ender(file);
    		clock_synchro=(now-initializer)%period;
    		do
    		{
    			date_event_fin=lire_fin_ligne(file, ligne);
    		}while ((fseek(file,1,SEEK_CUR)!=EOF)&&(clock_synchro>date_event_fin));
    		date_event_debut=lire_debut_ligne(file,ligne);	
    		if (date_event_debut>clock_synchro)
    		{
    			return date_event_debut;
    		}
    		else if (clock_synchro>date_event_fin)
    		{
    			return (((now-initializer)/period+1)*period+initializer);
    		}
    		else
    		{
    			return date_event_fin;
    		}
    	}
    	fclose(file);
    	pthread_mutex_unlock(&verrou);	
    	//fin de l'exclusion mutuelle
    }
    
    int main()
    {
     	struct tm * instant;
    	long temps_t=actualiser_donnees("/home/nicolas/Documents/lampe.schedule");
    	instant=localtime(&temps_t);
    	printf("%d/%d ; %d:%d:%d", instant->tm_mday+1, instant->tm_mon+1, instant->tm_hour, instant->tm_min, instant->tm_sec);
    }

  13. #12
    lou_ibmix_xi

    Re : Raspberry pi : Protection des ressources GPIO

    je dois avouer que la différence pour un amateur comme moi n'est pas flagrante mais je crois avoir quand même compris (je suis plus un matheux en fait).
    Du coup, je voulais avoir votre avis sur l'utilisation que j'ai faite des mutex dans mon code. Selon vous, le sémaphore aurait-il été plus approprié ?
    Il n'y a plus de rapport avec le sujet initial, je te réponds ici mais si tu veux plus de précision sur muetx/semaphore et le code que tu viens de poster, ouvre une nouvelle discussion.

    J'imagine que tu veux protéger ton fichier "/home/nicolas/Documents/lampe.schedule" pour qu'il ne puisse pas être accéder en même temps par deux instances de ton même programme.
    Conceptuellement c'est bien une ressource, donc l'entité qui la réquisitionne sera la même que celle qui dévérouille -> le concept de mutex est pertinent. Maintenant tu ne te trouves pas dans un contexte multithread (tu n'as pas créé de threads dans ton programme), mais bien dans un contexte multi-processus (1 processus = 1 instance d'un programme en RAM, si tu lances 3 fois ton programmes, tu auras 3 processus différents). Alors pthread_mutex_t n'est pas pertinent car il est prévu pour un contexte multi-thread et pas pour un contexte multi-processus: chaque processus aura sa propre instance de mutex, ils pourront tous accéder au même fichier puisque les mutex sont différents, il faut donc que tu utilises les outils IPC (man svipc), manque de peau il n'y pas de mutex, c'est pas grave tu peux émuler un mutex avec un sémaphore.

    Mais ce mécanisme de protection n'ai pas forcément suffisant: tu as protégé ta ressource pour le(s) programme(s) que tu as écris, mais que ce passe-t'il si quelqu'un efface le fichier pendant que ton programme tourne ? Dans ce cas là la solution est au niveau du noyau, c'est le noyau qui va gérer l'accès à la ressource pour TOUS les programmes. Pratiquement ça se traduit par les droits lectures / écritures, les drapeaux utilisés à l'ouverture du fichier / périphérique, et le pilote de périphérique de ce dernier... Et tu devrais commencer à comprendre pourquoi je te disais de faire un pilote de périphérique pour gérer les GPIO: si tu les protègent au niveau de ta bibliothèque, les programmes qui ne passeront pas par ta bibliothèque pourront toujours y accéder, le noyau étant un peu une "bibliothèque obligatoire", tous les programmes utilisant les GPIO par l'intermédiaire de ton driver auront leur accès aux GPIO contraints comme tu l'as décidé...

    Il y a une belle tartine de code, j'ai pas le temps de la lire en détail maintenant, mais je peux te dire qu'il te manque la notion d'allocation dynamique / pointeurs et c'est probablement pour ça que ton programme plantouille, un exemple "fgets(buffer,TAILLE_JOUR,file )" va mettre les chose où ? (et oui la mémoire est une ressource partagée, le noyau voit que tu n'écris pas "chez toi", il te crashe). Une autre remarque, pour un débutant je le trouve bien écris, il y a un effort pour découper en sous-fonction, tu as réduit la visibilité des fonctions avec "static", les indentations etc... Il manque un peu d'aération je trouve, regarde un peu les "C code format" qui se font (de mémoire principalement GNU, BSD et celui utilisé pour le noyau linux), choisi celui que tu préfères et tiens toi y. La lisibilité du code est une notion fondamentale...

    (Ouvre une nouvelle discussion si tu as d'autres questions qui n'ont pas grand chose à voir avec tes GPIO)

Discussions similaires

  1. Protection GPIO du Raspberry Pi
    Par USMC dans le forum Électronique
    Réponses: 47
    Dernier message: 05/08/2015, 09h47
  2. Raspberry pi 2 protection d'entree gpio avec optocoulpeur
    Par FEFE_CMC dans le forum Électronique
    Réponses: 12
    Dernier message: 20/04/2015, 10h22
  3. Raspberry pi GPIO package
    Par lm321 dans le forum Électronique
    Réponses: 1
    Dernier message: 04/03/2015, 14h54
  4. Réponses: 29
    Dernier message: 29/10/2014, 07h39
  5. GPIO.0 en entrée sur pic 12F675 et 629
    Par emile62 dans le forum Électronique
    Réponses: 3
    Dernier message: 23/07/2009, 10h42