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 :
Maintenant voici des exemples de fonctions que j'aimerais "encapsuler" :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; }
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.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 }
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!
-----