#include #include #include #include #include #include #include #include #include #include "read_conf_file.h" #include /**************************************************************** * Defines ****************************************************************/ #define die(str, args...) do { \ perror(str); \ return(EXIT_FAILURE); \ } while(0) #define DEBUG_READ_CONF_FILE_PRINTF (0) #define ERROR_READ_CONF_FILE_PRINTF (1) #if (DEBUG_READ_CONF_FILE_PRINTF) #define READ_CONF_FILE_PRINTF(...) printf(__VA_ARGS__); #else #define READ_CONF_FILE_PRINTF(...) #endif #if (ERROR_READ_CONF_FILE_PRINTF) #define ERROR_CONF_FILE_PRINTF(...) printf(__VA_ARGS__); #else #define ERROR_CONF_FILE_PRINTF(...) #endif /**************************************************************** * Extern variables ****************************************************************/ extern key_names_s key_names[]; /**************************************************************** * Static variables ****************************************************************/ static STRUCT_MAPPED_GPIO * head_chained_list_mapping_gpio = NULL; static int count_valid_gpios = 0; static int gpio_pins[MAX_NUM_GPIO]; static bool gpio_active_high[MAX_NUM_GPIO]; /**************************************************************** * Static functions ****************************************************************/ /* Return linux Key code from corresponding str*/ static int find_key(const char *name) { int i=0; while(key_names[i].code >= 0){ if(!strncmp(key_names[i].name, name, 32))break; i++; } if(key_names[i].code < 0){ i = 0; } return i; } /* Return pin idx in the array of instanciated pins */ static int get_idx_pin(int* ptr_list_gpio_pins, int size_list_gpio_pins, int pin_number_to_find){ int idx; for (idx=0; idxnext_mapped_gpio = a->next_mapped_gpio; a->next_mapped_gpio = b; } /* Bubble sort the given linked list */ static void bubbleSort(STRUCT_MAPPED_GPIO *head) { int swapped, i; STRUCT_MAPPED_GPIO *ptr1 = head; STRUCT_MAPPED_GPIO *lptr = NULL; /* Checking for empty list */ if (ptr1 == NULL) return; do { swapped = 0; ptr1 = head; while (ptr1->next_mapped_gpio != lptr) { if (ptr1->nb_simultaneous_pins < ptr1->next_mapped_gpio->nb_simultaneous_pins) { swap(ptr1, ptr1->next_mapped_gpio); swapped = 1; } ptr1 = ptr1->next_mapped_gpio; } lptr = ptr1; } while (swapped); } /* Push new node in chained list */ static void push(STRUCT_MAPPED_GPIO ** head, STRUCT_MAPPED_GPIO * new_mapping) { STRUCT_MAPPED_GPIO ** current = head; while (*current != NULL) { current = &(*current)->next_mapped_gpio; } /* now we can add a new variable */ *current = malloc(sizeof(STRUCT_MAPPED_GPIO)); memcpy(*current, new_mapping, sizeof(STRUCT_MAPPED_GPIO)); (*current)->next_mapped_gpio = NULL; } /**************************************************************** * Public functions ****************************************************************/ void get_mapping_from_conf_file(STRUCT_MAPPED_GPIO ** chained_list_mapping, int* nb_valid_gpios, int ** valid_gpio_pins, bool ** gpio_pins_active_high){ /* Variables */ READ_CONF_FILE_PRINTF("Reading the config file:\n"); FILE *fp; char ln[MAX_LN_LENGTH]; int lnno = 0; char conffile[80]; bool pins_declaration_line = true; /* search for the conf file in ~/.funkey_gpio_mapping.conf and /etc/funkey_gpio_mapping.conf */ sprintf(conffile, "%s/.funkey_gpio_mapping.conf", getenv("HOME")); fp = fopen(conffile, "r"); if(!fp){ fp = fopen("/etc/funkey_gpio_mapping.conf", "r"); if(!fp){ fp = fopen("./funkey_gpio_mapping.conf", "r"); if(!fp){ perror(conffile); perror("/etc/funkey_gpio_mapping.conf"); perror("./funkey_gpio_mapping.conf"); } sprintf(conffile, "./funkey_gpio_mapping.conf"); } else{ sprintf(conffile, "/etc/funkey_gpio_mapping.conf"); } } if(fp){ printf("GPIO config file used: %s\n", conffile); } /* Main loop to read conf file (purposely exploded and not in multiple sub-functions) */ while(fp && !feof(fp)){ if(fgets(ln, MAX_LN_LENGTH, fp)){ lnno++; if(strlen(ln) > 1){ if(ln[0]=='#')continue; READ_CONF_FILE_PRINTF("\nCurrent line : %s\n", ln); // ************ Pins declaration ************ if(pins_declaration_line){ char* token; int token_int; //count nb valid GPIOs and store them token = strtok(ln, ","); while(token != NULL){ // Search for char '*' which means active low bool cur_active_high = true; char *substr = strchr(token, '*'); if(substr != NULL){ // Save polarity and set this char to \0 to end string cur_active_high = false; substr[0] = 0; } // Read pin idx token_int = atoi(token); if(token_int || !strcmp(token, "0")){ gpio_pins[count_valid_gpios] = token_int; gpio_active_high[count_valid_gpios] = cur_active_high; count_valid_gpios++; READ_CONF_FILE_PRINTF("GPIO %d declared - active %s\n", token_int, cur_active_high?"high":"low"); } else{ ERROR_CONF_FILE_PRINTF("Could not declare GPIO: %s\n", token); } token = strtok(NULL, ","); } pins_declaration_line = false; } // ************ Pins mapping ************ else{ STRUCT_MAPPED_GPIO cur_gpio_mapping; char* end_ln; char* token_comma; char * current_arg; int cur_arg_idx = MAPPING_ARG_PINS; int idx_pin = 0; int cur_pin; bool add_current_mapping = true; token_comma = strtok_r(ln, ",", &end_ln); while(token_comma != NULL && cur_arg_idx < NB_MAPPING_ARG_NAMES && add_current_mapping){ current_arg= token_comma; //remove_initial_spaces: while(*current_arg==' ' && *current_arg!=0){current_arg++;} READ_CONF_FILE_PRINTF(" Current arg: %s\n", current_arg); //Handle current mapping arg switch(cur_arg_idx){ case MAPPING_ARG_PINS: //count nb valid GPIOs and store them ;char* end_arg; char * token_plus = strtok_r(current_arg, "+", &end_arg); while(token_plus != NULL){ cur_pin = atoi(token_plus); if(cur_pin || !strcmp(token_plus, "0")){ int idx_cur_pin = get_idx_pin(gpio_pins, count_valid_gpios, cur_pin); if(idx_cur_pin == -1){ ERROR_CONF_FILE_PRINTF(" Could not find GPIO: %s in previously instanciated GPIOs\n", token_plus); add_current_mapping = false; break; } cur_gpio_mapping.pins_idx[idx_pin] = idx_cur_pin; idx_pin++; READ_CONF_FILE_PRINTF(" GPIO %d in current mapping\n", cur_pin); } else{ ERROR_CONF_FILE_PRINTF(" Could not find GPIO: %s\n", token_plus); add_current_mapping = false; break; } token_plus = strtok_r(NULL, "+", &end_arg);//strtok_r(NULL, ","); } cur_gpio_mapping.nb_simultaneous_pins = idx_pin; break; case MAPPING_ARG_TYPE: if(!strcmp(current_arg, "KEYBOARD")){ cur_gpio_mapping.type_mapping = TYPE_MAPPING_KEYBOARD; } else if(!strcmp(current_arg, "SHELL_COMMAND")){ cur_gpio_mapping.type_mapping = TYPE_MAPPING_SHELL_COMMAND; } else{ ERROR_CONF_FILE_PRINTF(" %s is not a valid mapping type\n", current_arg); add_current_mapping = false; break; } break; case MAPPING_ARG_VALUE: switch (cur_gpio_mapping.type_mapping){ case TYPE_MAPPING_KEYBOARD: cur_gpio_mapping.key_value = find_key(current_arg); if(!cur_gpio_mapping.key_value){ ERROR_CONF_FILE_PRINTF(" Could not find Key: %s\n", current_arg); add_current_mapping = false; } break; case TYPE_MAPPING_SHELL_COMMAND: cur_gpio_mapping.shell_command = malloc(strlen(current_arg)*sizeof(char)); strcpy(cur_gpio_mapping.shell_command, current_arg); break; default: ERROR_CONF_FILE_PRINTF(" %d is not a valid mapping type\n", cur_gpio_mapping.type_mapping); add_current_mapping = false; break; } break; case MAPPING_ARG_STR_HELP_PIN_NAME: if(!strlen(current_arg)) continue; cur_gpio_mapping.pin_help_str = malloc(strlen(current_arg)*sizeof(char)); strcpy(cur_gpio_mapping.pin_help_str, current_arg); break; case MAPPING_ARG_STR_HELP_PIN_FCT: if(!strlen(current_arg)) continue; cur_gpio_mapping.fct_help_str = malloc(strlen(current_arg)*sizeof(char)); strcpy(cur_gpio_mapping.fct_help_str, current_arg); break; default: break; } //next arg token_comma = strtok_r(NULL, ",", &end_ln); cur_arg_idx++; } if(add_current_mapping){ push(&head_chained_list_mapping_gpio, &cur_gpio_mapping); READ_CONF_FILE_PRINTF("Current Mapping added successfully\n\n"); } else{ ERROR_CONF_FILE_PRINTF("Current Mapping not added\n\n"); } } } } } READ_CONF_FILE_PRINTF("Sorting Chained list...\n"); bubbleSort(head_chained_list_mapping_gpio); print_all_chained_list(head_chained_list_mapping_gpio); print_gpios(gpio_pins, count_valid_gpios); if(fp){ fclose(fp); } /* Return parameters */ *chained_list_mapping = head_chained_list_mapping_gpio; *nb_valid_gpios = count_valid_gpios; *valid_gpio_pins = gpio_pins; *gpio_pins_active_high = gpio_active_high; } /* Print all chained list content */ void print_all_chained_list(STRUCT_MAPPED_GPIO * head){ STRUCT_MAPPED_GPIO * current = head; int idx = 0; READ_CONF_FILE_PRINTF("Printing Chained list:\n "); while (current != NULL) { READ_CONF_FILE_PRINTF("Chained list Mapping GPIOs, idx: %d\n", idx); print_chained_list_node(current); idx++; current = current->next_mapped_gpio; } } /* Print one chained list node */ void print_chained_list_node(STRUCT_MAPPED_GPIO * node){ // Print Pins: if(node->nb_simultaneous_pins > 1){ READ_CONF_FILE_PRINTF(" %d Simultaneous pins at following idx: [", node->nb_simultaneous_pins); int i; for (i=0; i < node->nb_simultaneous_pins; i++){ READ_CONF_FILE_PRINTF("%d%s", node->pins_idx[i], (i==node->nb_simultaneous_pins-1)?"]\n":","); } } else{ READ_CONF_FILE_PRINTF(" idx pin: %d\n", node->pins_idx[0]); } // Type mapping and Value if (node->type_mapping == TYPE_MAPPING_KEYBOARD){ READ_CONF_FILE_PRINTF(" Type mapping: TYPE_MAPPING_KEYBOARD\n"); READ_CONF_FILE_PRINTF(" Key: %d\n", node->key_value); } else if (node->type_mapping == TYPE_MAPPING_SHELL_COMMAND){ READ_CONF_FILE_PRINTF(" Type mapping: TYPE_MAPPING_SHELL_COMMAND\n"); READ_CONF_FILE_PRINTF(" Shell command: %s\n", node->shell_command); } // Pin help String if(node->pin_help_str[0]){ READ_CONF_FILE_PRINTF(" Pins: %s\n", node->pin_help_str); } // Function help String if(node->fct_help_str[0]){ READ_CONF_FILE_PRINTF(" Function: %s\n", node->fct_help_str); } } void print_gpios(int * valid_gpio_pins, int nb_valid_gpios){ READ_CONF_FILE_PRINTF("GPIO pins:\n["); for(int i = 0; i< nb_valid_gpios; i++) { READ_CONF_FILE_PRINTF("%d%s", valid_gpio_pins[i], (i==nb_valid_gpios-1)?"]\n":","); } }