Fonctions variadic, et pointeurs de fonctions de différents formats
Répondre à la discussion
Affichage des résultats 1 à 10 sur 10

Fonctions variadic, et pointeurs de fonctions de différents formats



  1. #1
    ATdevice

    Question Fonctions variadic, et pointeurs de fonctions de différents formats


    ------

    Bonjour,

    Je vais essayer d'expliquer ce que je cherche à faire, mais je pense que les exemples seront plus parlant que le paragraphe qui suit :

    Je conçois un système à base de microcontrôleur Microchip et d'un écran LCD. J'essaie de mettre en place une navigation à travers différents menus sous la forme la plus modulaire possible pour pouvoir l'adapter à différents projets.
    L'architecture d'un menu est définie par une structure (typedef), et j'utilise une fonction variadic pour récupérer les éléments qui m'intéressent en fonction du type de menu (différents nombres d'images à afficher, etc).
    Jusque là tout va bien. Maintenant j'aimerais ajouter une évolution et je bloque un peu sur la manière de procéder :

    J'aimerais ajouter une option "preview", par exemple dans le menu "changer luminosité" j'aimerais que la luminosité de l'écran change en temps réel. Il faut donc que ma fonction menu accepte un pointeur de fonction comme argument, et de préférence avec un nombre d'arguments non défini

    Voici le programme actuel sans le pointeur de fonction :
    Code:
    // Structure d'un menu "Setting" :
    
    typedef struct // _system_setting_t
    {
    	// Setting value
    	unsigned char type;
    	signed long min;
    	signed long max;
    	signed long value;
    	signed long previousValue;
    	// Setting graphical objects
    	_menu_item_t background;
    	_menu_item_t digit[3];
    	// Setting action
    	int(*action)(int a,...);
    	// Setting status
    	union
    	{
    		struct
    		{
    			unsigned char preview : 1;
    			unsigned char valueChanged : 1;
    			unsigned char refresh : 1;
    			unsigned char initialized : 1;
    			unsigned char configured : 1;
    			unsigned char : 3;
    		};
    	};
    } _system_setting_t;
    
    // Déclaration des menus "display backlight" et "display sleep time":
    
    _system_setting_t setting_displayBacklight;
    
    _system_setting_t setting_displaySleepTime;
    
    // Prototypes des fonctions associées :
    
    void setting_init(_system_setting_t *s, long min, long max, long value, unsigned char type);
    
    void menu_configureSetting(_system_setting_t *s, ...);
    
    // Déclaration des fonctions associées :
    
    void setting_init(_system_setting_t *s, long min, long max, long value, unsigned char type)
    {
    	// Check setting initialized state
    	if(s->initialized == 1)
    		return;
    	// Check setting configured state
    	if(s->configured == 1)
    		return;
    	// Initialize setting values
    	s->min=min;
    	s->max=max;
    	s->value=value;
    	s->previousValue=value;
    	// Set setting type
    	s->type=type;
    	// Clear setting background display options
    	s->background.imageAddress=0;
    	s->background.value=0;
    	s->background.previousValue=0;
    	s->background.update=0;
    	// Clear setting digit display options
    	for(int i=0; i<3; i++)
    	{
    		s->digit[i].imageAddress=0;
    		s->digit[i].value=0;
    	}
    	// Clear setting status flags
    	s->preview=0;
    	s->valueChanged=0;
    	s->refresh=0;
    	s->configured=0;
    	// Set setting initialized flag
    	s->initialized=1;
    }
    
    void menu_configureSetting(_system_setting_t *s, ...)
    {
    	// Declare variadic pointer to the arguments list
    	va_list settingList;
    	// Initialize argument to the list pointer
    	va_start(settingList, s);
    	// Configure setting background - image address
    	s->background.imageAddress=va_arg(settingList, unsigned int);
    	// Configure setting background - image index
    	s->background.value=va_arg(settingList, unsigned int);
    	// Configure each digit image
    	for(int i=0; i<3; i++)
    	{
    		// Configure setting digit - image address
    		s->digit[i].imageAddress=va_arg(settingList, unsigned int);
    		// Configure setting digit - image index
    		s->digit[i].value=va_arg(settingList, unsigned int);
    	}
    	// Configure setting preview mode
    	s->preview=va_arg(settingList, unsigned int);
    	// End variadic argument list
    	va_end(settingList);
    	// Set setting configured flag
    	s->configured=1;
    }
    Maintenant voici des exemples de fonctions que j'aimerais "encapsuler" :

    Code:
    // Prototypes des fonctions à appeler :
    
    int LCD_setBacklightValue(unsigned char moduleAddress, unsigned char value); // Module I2C address, value 0 to 100%
    
    void display_setSleepTimer(unsigned short time); // Time in ms before turn off display backlight : 0 to 500 ms
    
    // Déclaration des fonctions à appeler :
    
    int LCD_setBacklightValue(unsigned char moduleAddress, unsigned char value)
    {
    	int status=0;
    	I2C_sendByte(moduleAddress);
    	I2C_sendByte(value);
    	I2C_getByte(&status);
    	return status;
    }
    
    void display_setSleepTimer(unsigned short time)
    {
    	sleepTime = time; // sleepTime est une variable volatile utilisée par un Timer
    }
    
    void enable_powerSupply(void)
    {
    	_TRISB0=0;	// Output
    	_LATB0=1;	// True
    }
    
    void disable_powerSupply(void)
    {
    	_TRISB0=0;	// Output
    	_LATB0=0;	// False
    }
    La plus grosse difficulté étant que le type de fonction, ainsi que le type et le nombre d'arguments varient d'une fonction à l'autre. De plus, je ne sais pas comment avoir accès aux arguments à travers le pointeur.

    Une alternative serait de créer des fonctions "miroir" pour formater de manière uniforme, mais cela implique de le faire pour chaque fonction. Cela implique une augmentation de la taille du code et le nombre d'appels de la pile (simple supposition car je ne me suis pas encore pencher sur l'optimisation), mais idéalement j'aimerais m'en passer pour que le code reste le plus générique possible

    Merci beaucoup!

    -----
    Dernière modification par ATdevice ; 01/08/2023 à 12h34.

  2. #2
    ATdevice

    Re : Fonctions variadic, et pointeurs de fonctions de différents formats

    Personne?

  3. #3
    Flyingbike
    Modérateur*

    Re : Fonctions variadic, et pointeurs de fonctions de différents formats

    Déplacé depuis le forum Electronique.
    Flyingbike pour la modération.
    La vie trouve toujours un chemin

  4. #4
    Ikhar84
    Animateur Informatique

    Re : Fonctions variadic, et pointeurs de fonctions de différents formats

    C'est pour un smartphone DIY ?
    J'ai glissé Chef !

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

    Re : Fonctions variadic, et pointeurs de fonctions de différents formats

    Bonjour,

    Merci Flyingbike pour le déplacement

    @Ikhar84 Non c'est pour une famille d'équipement de mesure que je développe. La carte mère pour laquelle je veux implémenter ce code est axée sur un microcontrôleur Microchip PIC24.

    Il peut y avoir de 1 à 3 modules écran LCD tactiles "autonomes" de notre conception (ils intègrent le stockage et la gestion d'affichage, la carte mère envoie simplement des commandes via I²C).

  7. #6
    pm42

    Re : Fonctions variadic, et pointeurs de fonctions de différents formats

    Une possibilité pour passer un nombre variable d'arguments est de les mettre dans des structures.
    Tu passes l'adresse de la structure comme un void* quand tu appelle ton pointeur de fonction qui lui le caste dans le type attendu.

    En C, faire du générique est compliqué. Perso, je passerais pas les fonctions miroir parce que le surcoût est faible et que le code est certes un peu plus gros et fastidieux à écrire mais plus lisible et facile à maintenir.

  8. #7
    polo974

    Re : Fonctions variadic, et pointeurs de fonctions de différents formats

    THE fonction en C qui accepte un nombre variable de paramètres de types indéterminés, c'est printf...

    Donc, c'est faisable.

    Mais je ne dis pas que c'est simple... voir par exemple par ici et/ou chercher va_arg...

    https://codesteps.com/2014/05/16/how...cpp-functions/
    Jusqu'ici tout va bien...

  9. #8
    pm42

    Re : Fonctions variadic, et pointeurs de fonctions de différents formats

    Oui avec les varargs en effet c'est faisable. Il faut savoir ce qu'on fait comme tu le dis.
    J'aurais tendance à conseiller d'expérimenter avec les différentes solutions.

  10. #9
    ATdevice

    Re : Fonctions variadic, et pointeurs de fonctions de différents formats

    Bonjour et merci pour ces solutions

    En C, faire du générique est compliqué. Perso, je passerais pas les fonctions miroir parce que le surcoût est faible et que le code est certes un peu plus gros et fastidieux à écrire mais plus lisible et facile à maintenir.
    Oui j'en sais quelque chose, j'ai développé pas mal de bibliothèques pour différents composants, une fois que c'est en place l'implémentation c'est du LEGO mais il faut toujours faire attention à ce qui se passe derrière!

    Une possibilité pour passer un nombre variable d'arguments est de les mettre dans des structures.
    Tu passes l'adresse de la structure comme un void* quand tu appelle ton pointeur de fonction qui lui le caste dans le type attendu.
    Il faudrait que j'essaie de faire ça, c'est peut-être le plus adapté à mon cas, à voir.

    Mais je ne dis pas que c'est simple... voir par exemple par ici et/ou chercher va_arg...
    Oui avec les varargs en effet c'est faisable. Il faut savoir ce qu'on fait comme tu le dis.
    Alors j'utilise déjà var_arg pour récupérer les adresses et index des différentes images d'un menu, car l'intérêt est de pouvoir avoir un nombre "illimité" de menus, tous avec leurs propres images/boutons. Pour le moment ça fonctionne, j'arrive à définir différents menus, et créer une hiérarchie pour naviguer à travers. Mais la machine à états et d'autant plus grande que l'on a de menus.

    Le petit plus, qui se fait de manière externe pour le moment, c'est de pouvoir appliquer directement la valeur lorsque j'appuie sur le bouton "valider", ou si le mode "preview" est actif : faire varier le rétroéclairage de l'écran en même temps qu'on change sa valeur par exemple.

    Ainsi, j'aurais une fonction où j'initialise tous les menus, et la navigation se ferait non plus par une machine à N états, mais simplement une boucle for qui scrute tous les menus, avec à l'intérieur une condition "menu actif".

    L'utilisation de va_arg pour l'ajout d'une fonction à X arguments me paraît compliqué du fait que va_arg contraint les arguments au format "int". Cela ne pose pas de problème pour des variables de format inférieur, mais pour des "long" je risque d'avoir des erreurs/crash. Et je ne peux pas modifier les fonctions, sous peine de devoir modifier toutes mes bibliothèques :/

    Je vais déjà essayer de jouer en passant par une structure comme suggéré par pm42, si j'y arrive ce sera un bon début!

  11. #10
    polo974

    Re : Fonctions variadic, et pointeurs de fonctions de différents formats

    Je ne vois ppas de contrainte au type int.


    https://linux.die.net/man/3/va_arg

    Tout a la fin, il y a un exemple.

    Par contre, comme c'est dit, il faut savoir ce qu'on cherche comme data, donc l'historique de la liste doit permettre de savoir à quoi s'attendre pour la suite.


    Sinon, ça peut faire mal... (edit: ça VA faire mal)
    Jusqu'ici tout va bien...

Discussions similaires

  1. Réponses: 16
    Dernier message: 14/04/2018, 17h57
  2. Mêmes fonctions à ensembles de définition différents ?
    Par invite3f764c1d dans le forum Mathématiques du collège et du lycée
    Réponses: 1
    Dernier message: 02/11/2017, 17h34
  3. Réponses: 1
    Dernier message: 18/09/2014, 11h59
  4. Programme en C les pointeurs et fonctions
    Par invite3394e7df dans le forum Programmation et langages, Algorithmique
    Réponses: 1
    Dernier message: 17/04/2013, 03h10
  5. Petit problème en C (pointeurs et fonctions)
    Par invitee724cc92 dans le forum Programmation et langages, Algorithmique
    Réponses: 3
    Dernier message: 09/02/2011, 10h24