read_conf_file.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6. #include <fcntl.h>
  7. #include <errno.h>
  8. #include <sys/select.h>
  9. #include <linux/input.h>
  10. #include "read_conf_file.h"
  11. #include <assert.h>
  12. /****************************************************************
  13. * Defines
  14. ****************************************************************/
  15. #define die(str, args...) do { \
  16. perror(str); \
  17. return(EXIT_FAILURE); \
  18. } while(0)
  19. #define DEBUG_READ_CONF_FILE_PRINTF (0)
  20. #define ERROR_READ_CONF_FILE_PRINTF (1)
  21. #if (DEBUG_READ_CONF_FILE_PRINTF)
  22. #define READ_CONF_FILE_PRINTF(...) printf(__VA_ARGS__);
  23. #else
  24. #define READ_CONF_FILE_PRINTF(...)
  25. #endif
  26. #if (ERROR_READ_CONF_FILE_PRINTF)
  27. #define ERROR_CONF_FILE_PRINTF(...) printf(__VA_ARGS__);
  28. #else
  29. #define ERROR_CONF_FILE_PRINTF(...)
  30. #endif
  31. /****************************************************************
  32. * Extern variables
  33. ****************************************************************/
  34. extern key_names_s key_names[];
  35. /****************************************************************
  36. * Static variables
  37. ****************************************************************/
  38. static STRUCT_MAPPED_GPIO * head_chained_list_mapping_gpio = NULL;
  39. static int count_valid_gpios = 0;
  40. static int gpio_pins[MAX_NUM_GPIO];
  41. static bool gpio_active_high[MAX_NUM_GPIO];
  42. /****************************************************************
  43. * Static functions
  44. ****************************************************************/
  45. /* Return linux Key code from corresponding str*/
  46. static int find_key(const char *name)
  47. {
  48. int i=0;
  49. while(key_names[i].code >= 0){
  50. if(!strncmp(key_names[i].name, name, 32))break;
  51. i++;
  52. }
  53. if(key_names[i].code < 0){
  54. i = 0;
  55. }
  56. return i;
  57. }
  58. /* Return pin idx in the array of instanciated pins */
  59. static int get_idx_pin(int* ptr_list_gpio_pins, int size_list_gpio_pins, int pin_number_to_find){
  60. int idx;
  61. for (idx=0; idx<size_list_gpio_pins; idx++){
  62. if(ptr_list_gpio_pins[idx] == pin_number_to_find){
  63. return idx;
  64. }
  65. }
  66. // if we get here, then we did not find the pin:
  67. idx=-1;
  68. return idx;
  69. }
  70. /* function to swap data of two nodes a and b in chained list */
  71. static void swap(STRUCT_MAPPED_GPIO *a, STRUCT_MAPPED_GPIO *b)
  72. {
  73. STRUCT_MAPPED_GPIO temp;
  74. memcpy(&temp, a, sizeof(STRUCT_MAPPED_GPIO));
  75. memcpy(a, b, sizeof(STRUCT_MAPPED_GPIO));
  76. memcpy(b, &temp, sizeof(STRUCT_MAPPED_GPIO));
  77. b->next_mapped_gpio = a->next_mapped_gpio;
  78. a->next_mapped_gpio = b;
  79. }
  80. /* Bubble sort the given linked list */
  81. static void bubbleSort(STRUCT_MAPPED_GPIO *head)
  82. {
  83. int swapped, i;
  84. STRUCT_MAPPED_GPIO *ptr1 = head;
  85. STRUCT_MAPPED_GPIO *lptr = NULL;
  86. /* Checking for empty list */
  87. if (ptr1 == NULL)
  88. return;
  89. do
  90. {
  91. swapped = 0;
  92. ptr1 = head;
  93. while (ptr1->next_mapped_gpio != lptr)
  94. {
  95. if (ptr1->nb_simultaneous_pins < ptr1->next_mapped_gpio->nb_simultaneous_pins)
  96. {
  97. swap(ptr1, ptr1->next_mapped_gpio);
  98. swapped = 1;
  99. }
  100. ptr1 = ptr1->next_mapped_gpio;
  101. }
  102. lptr = ptr1;
  103. }
  104. while (swapped);
  105. }
  106. /* Push new node in chained list */
  107. static void push(STRUCT_MAPPED_GPIO ** head, STRUCT_MAPPED_GPIO * new_mapping) {
  108. STRUCT_MAPPED_GPIO ** current = head;
  109. while (*current != NULL) {
  110. current = &(*current)->next_mapped_gpio;
  111. }
  112. /* now we can add a new variable */
  113. *current = malloc(sizeof(STRUCT_MAPPED_GPIO));
  114. memcpy(*current, new_mapping, sizeof(STRUCT_MAPPED_GPIO));
  115. (*current)->next_mapped_gpio = NULL;
  116. }
  117. /****************************************************************
  118. * Public functions
  119. ****************************************************************/
  120. void get_mapping_from_conf_file(STRUCT_MAPPED_GPIO ** chained_list_mapping,
  121. int* nb_valid_gpios, int ** valid_gpio_pins, bool ** gpio_pins_active_high){
  122. /* Variables */
  123. READ_CONF_FILE_PRINTF("Reading the config file:\n");
  124. FILE *fp;
  125. char ln[MAX_LN_LENGTH];
  126. int lnno = 0;
  127. char conffile[80];
  128. bool pins_declaration_line = true;
  129. /* search for the conf file in ~/.funkey_gpio_mapping.conf and /etc/funkey_gpio_mapping.conf */
  130. sprintf(conffile, "%s/.funkey_gpio_mapping.conf", getenv("HOME"));
  131. fp = fopen(conffile, "r");
  132. if(!fp){
  133. fp = fopen("/etc/funkey_gpio_mapping.conf", "r");
  134. if(!fp){
  135. fp = fopen("./funkey_gpio_mapping.conf", "r");
  136. if(!fp){
  137. perror(conffile);
  138. perror("/etc/funkey_gpio_mapping.conf");
  139. perror("./funkey_gpio_mapping.conf");
  140. }
  141. sprintf(conffile, "./funkey_gpio_mapping.conf");
  142. }
  143. else{
  144. sprintf(conffile, "/etc/funkey_gpio_mapping.conf");
  145. }
  146. }
  147. if(fp){
  148. printf("GPIO config file used: %s\n", conffile);
  149. }
  150. /* Main loop to read conf file (purposely exploded and not in multiple sub-functions) */
  151. while(fp && !feof(fp)){
  152. if(fgets(ln, MAX_LN_LENGTH, fp)){
  153. lnno++;
  154. if(strlen(ln) > 1){
  155. if(ln[0]=='#')continue;
  156. READ_CONF_FILE_PRINTF("\nCurrent line : %s\n", ln);
  157. // ************ Pins declaration ************
  158. if(pins_declaration_line){
  159. char* token;
  160. int token_int;
  161. //count nb valid GPIOs and store them
  162. token = strtok(ln, ",");
  163. while(token != NULL){
  164. // Search for char '*' which means active low
  165. bool cur_active_high = true;
  166. char *substr = strchr(token, '*');
  167. if(substr != NULL){
  168. // Save polarity and set this char to \0 to end string
  169. cur_active_high = false;
  170. substr[0] = 0;
  171. }
  172. // Read pin idx
  173. token_int = atoi(token);
  174. if(token_int || !strcmp(token, "0")){
  175. gpio_pins[count_valid_gpios] = token_int;
  176. gpio_active_high[count_valid_gpios] = cur_active_high;
  177. count_valid_gpios++;
  178. READ_CONF_FILE_PRINTF("GPIO %d declared - active %s\n", token_int, cur_active_high?"high":"low");
  179. }
  180. else{
  181. ERROR_CONF_FILE_PRINTF("Could not declare GPIO: %s\n", token);
  182. }
  183. token = strtok(NULL, ",");
  184. }
  185. pins_declaration_line = false;
  186. }
  187. // ************ Pins mapping ************
  188. else{
  189. STRUCT_MAPPED_GPIO cur_gpio_mapping;
  190. char* end_ln;
  191. char* token_comma;
  192. char * current_arg;
  193. int cur_arg_idx = MAPPING_ARG_PINS;
  194. int idx_pin = 0;
  195. int cur_pin;
  196. bool add_current_mapping = true;
  197. token_comma = strtok_r(ln, ",", &end_ln);
  198. while(token_comma != NULL && cur_arg_idx < NB_MAPPING_ARG_NAMES && add_current_mapping){
  199. current_arg= token_comma;
  200. //remove_initial_spaces:
  201. while(*current_arg==' ' && *current_arg!=0){current_arg++;}
  202. READ_CONF_FILE_PRINTF(" Current arg: %s\n", current_arg);
  203. //Handle current mapping arg
  204. switch(cur_arg_idx){
  205. case MAPPING_ARG_PINS:
  206. //count nb valid GPIOs and store them
  207. ;char* end_arg;
  208. char * token_plus = strtok_r(current_arg, "+", &end_arg);
  209. while(token_plus != NULL){
  210. cur_pin = atoi(token_plus);
  211. if(cur_pin || !strcmp(token_plus, "0")){
  212. int idx_cur_pin = get_idx_pin(gpio_pins, count_valid_gpios, cur_pin);
  213. if(idx_cur_pin == -1){
  214. ERROR_CONF_FILE_PRINTF(" Could not find GPIO: %s in previously instanciated GPIOs\n", token_plus);
  215. add_current_mapping = false;
  216. break;
  217. }
  218. cur_gpio_mapping.pins_idx[idx_pin] = idx_cur_pin;
  219. idx_pin++;
  220. READ_CONF_FILE_PRINTF(" GPIO %d in current mapping\n", cur_pin);
  221. }
  222. else{
  223. ERROR_CONF_FILE_PRINTF(" Could not find GPIO: %s\n", token_plus);
  224. add_current_mapping = false;
  225. break;
  226. }
  227. token_plus = strtok_r(NULL, "+", &end_arg);//strtok_r(NULL, ",");
  228. }
  229. cur_gpio_mapping.nb_simultaneous_pins = idx_pin;
  230. break;
  231. case MAPPING_ARG_TYPE:
  232. if(!strcmp(current_arg, "KEYBOARD")){
  233. cur_gpio_mapping.type_mapping = TYPE_MAPPING_KEYBOARD;
  234. }
  235. else if(!strcmp(current_arg, "SHELL_COMMAND")){
  236. cur_gpio_mapping.type_mapping = TYPE_MAPPING_SHELL_COMMAND;
  237. }
  238. else{
  239. ERROR_CONF_FILE_PRINTF(" %s is not a valid mapping type\n", current_arg);
  240. add_current_mapping = false;
  241. break;
  242. }
  243. break;
  244. case MAPPING_ARG_VALUE:
  245. switch (cur_gpio_mapping.type_mapping){
  246. case TYPE_MAPPING_KEYBOARD:
  247. cur_gpio_mapping.key_value = find_key(current_arg);
  248. if(!cur_gpio_mapping.key_value){
  249. ERROR_CONF_FILE_PRINTF(" Could not find Key: %s\n", current_arg);
  250. add_current_mapping = false;
  251. }
  252. break;
  253. case TYPE_MAPPING_SHELL_COMMAND:
  254. cur_gpio_mapping.shell_command = malloc(strlen(current_arg)*sizeof(char));
  255. strcpy(cur_gpio_mapping.shell_command, current_arg);
  256. break;
  257. default:
  258. ERROR_CONF_FILE_PRINTF(" %d is not a valid mapping type\n", cur_gpio_mapping.type_mapping);
  259. add_current_mapping = false;
  260. break;
  261. }
  262. break;
  263. case MAPPING_ARG_STR_HELP_PIN_NAME:
  264. if(!strlen(current_arg)) continue;
  265. cur_gpio_mapping.pin_help_str = malloc(strlen(current_arg)*sizeof(char));
  266. strcpy(cur_gpio_mapping.pin_help_str, current_arg);
  267. break;
  268. case MAPPING_ARG_STR_HELP_PIN_FCT:
  269. if(!strlen(current_arg)) continue;
  270. cur_gpio_mapping.fct_help_str = malloc(strlen(current_arg)*sizeof(char));
  271. strcpy(cur_gpio_mapping.fct_help_str, current_arg);
  272. break;
  273. default:
  274. break;
  275. }
  276. //next arg
  277. token_comma = strtok_r(NULL, ",", &end_ln);
  278. cur_arg_idx++;
  279. }
  280. if(add_current_mapping){
  281. push(&head_chained_list_mapping_gpio, &cur_gpio_mapping);
  282. READ_CONF_FILE_PRINTF("Current Mapping added successfully\n\n");
  283. }
  284. else{
  285. ERROR_CONF_FILE_PRINTF("Current Mapping not added\n\n");
  286. }
  287. }
  288. }
  289. }
  290. }
  291. READ_CONF_FILE_PRINTF("Sorting Chained list...\n");
  292. bubbleSort(head_chained_list_mapping_gpio);
  293. print_all_chained_list(head_chained_list_mapping_gpio);
  294. print_gpios(gpio_pins, count_valid_gpios);
  295. if(fp){
  296. fclose(fp);
  297. }
  298. /* Return parameters */
  299. *chained_list_mapping = head_chained_list_mapping_gpio;
  300. *nb_valid_gpios = count_valid_gpios;
  301. *valid_gpio_pins = gpio_pins;
  302. *gpio_pins_active_high = gpio_active_high;
  303. }
  304. /* Print all chained list content */
  305. void print_all_chained_list(STRUCT_MAPPED_GPIO * head){
  306. STRUCT_MAPPED_GPIO * current = head;
  307. int idx = 0;
  308. READ_CONF_FILE_PRINTF("Printing Chained list:\n ");
  309. while (current != NULL) {
  310. READ_CONF_FILE_PRINTF("Chained list Mapping GPIOs, idx: %d\n", idx);
  311. print_chained_list_node(current);
  312. idx++;
  313. current = current->next_mapped_gpio;
  314. }
  315. }
  316. /* Print one chained list node */
  317. void print_chained_list_node(STRUCT_MAPPED_GPIO * node){
  318. // Print Pins:
  319. if(node->nb_simultaneous_pins > 1){
  320. READ_CONF_FILE_PRINTF(" %d Simultaneous pins at following idx: [", node->nb_simultaneous_pins);
  321. int i;
  322. for (i=0; i < node->nb_simultaneous_pins; i++){
  323. READ_CONF_FILE_PRINTF("%d%s", node->pins_idx[i], (i==node->nb_simultaneous_pins-1)?"]\n":",");
  324. }
  325. }
  326. else{
  327. READ_CONF_FILE_PRINTF(" idx pin: %d\n", node->pins_idx[0]);
  328. }
  329. // Type mapping and Value
  330. if (node->type_mapping == TYPE_MAPPING_KEYBOARD){
  331. READ_CONF_FILE_PRINTF(" Type mapping: TYPE_MAPPING_KEYBOARD\n");
  332. READ_CONF_FILE_PRINTF(" Key: %d\n", node->key_value);
  333. }
  334. else if (node->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
  335. READ_CONF_FILE_PRINTF(" Type mapping: TYPE_MAPPING_SHELL_COMMAND\n");
  336. READ_CONF_FILE_PRINTF(" Shell command: %s\n", node->shell_command);
  337. }
  338. // Pin help String
  339. if(node->pin_help_str[0]){
  340. READ_CONF_FILE_PRINTF(" Pins: %s\n", node->pin_help_str);
  341. }
  342. // Function help String
  343. if(node->fct_help_str[0]){
  344. READ_CONF_FILE_PRINTF(" Function: %s\n", node->fct_help_str);
  345. }
  346. }
  347. void print_gpios(int * valid_gpio_pins, int nb_valid_gpios){
  348. READ_CONF_FILE_PRINTF("GPIO pins:\n[");
  349. for(int i = 0; i< nb_valid_gpios; i++) {
  350. READ_CONF_FILE_PRINTF("%d%s", valid_gpio_pins[i], (i==nb_valid_gpios-1)?"]\n":",");
  351. }
  352. }