gpio_mapping.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include <stdlib.h>
  4. #include <stdbool.h>
  5. #include <string.h>
  6. #include <unistd.h>
  7. #include <fcntl.h>
  8. #include <errno.h>
  9. #include <assert.h>
  10. #include <sys/select.h>
  11. #include <sys/time.h>
  12. #include <linux/input.h>
  13. #include "gpio_mapping.h"
  14. #include "driver_pcal6416a.h"
  15. #include "driver_axp209.h"
  16. /****************************************************************
  17. * Defines
  18. ****************************************************************/
  19. #define die(str, args...) do { \
  20. perror(str); \
  21. return(EXIT_FAILURE); \
  22. } while(0)
  23. #define DEBUG_GPIO_PRINTF (0)
  24. #define ERROR_GPIO_PRINTF (1)
  25. #if (DEBUG_GPIO_PRINTF)
  26. #define GPIO_PRINTF(...) printf(__VA_ARGS__);
  27. #else
  28. #define GPIO_PRINTF(...)
  29. #endif
  30. #if (ERROR_GPIO_PRINTF)
  31. #define GPIO_ERROR_PRINTF(...) printf(__VA_ARGS__);
  32. #else
  33. #define GPIO_ERROR_PRINTF(...)
  34. #endif
  35. // This define forces to perform a gpio sanity check after a timeout.
  36. // If not declared, there will be no timeout and no periodical sanity check of GPIO expander values
  37. #define TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP 1
  38. //#define TIMEOUT_MICROSEC_SANITY_CHECK_GPIO_EXP (500*1000)
  39. // This is for debug purposes on cards or eval boards that do not have the AXP209
  40. #define ENABLE_AXP209_INTERRUPTS
  41. #define KEY_IDX_MAPPED_FOR_SHORT_PEK_PRESS 16 //KEY_Q
  42. #define KEY_IDX_MAPPED_FOR_LONG_PEK_PRESS 28 //KEY_ENTER
  43. /****************************************************************
  44. * Static variables
  45. ****************************************************************/
  46. static int nb_mapped_gpios;
  47. static int * gpio_pins;
  48. STRUCT_MAPPED_GPIO * chained_list_mapping;
  49. static int max_fd = 0;
  50. static int gpio_fd_interrupt_expander_gpio;
  51. static int gpio_fd_interrupt_axp209;
  52. static fd_set fds;
  53. static bool * mask_gpio_value;
  54. static bool interrupt_i2c_expander_found = false;
  55. static bool interrupt_axp209_found = false;
  56. /****************************************************************
  57. * Static functions
  58. ****************************************************************/
  59. /***** Add a fd to fd_set, and update max_fd_nb ******/
  60. static int safe_fd_set(int fd, fd_set* list_fds, int* max_fd_nb) {
  61. assert(max_fd_nb != NULL);
  62. FD_SET(fd, list_fds);
  63. if (fd > *max_fd_nb) {
  64. *max_fd_nb = fd;
  65. }
  66. return 0;
  67. }
  68. /***** Clear fd from fds, update max fd if needed *****/
  69. static int safe_fd_clr(int fd, fd_set* list_fds, int* max_fd_nb) {
  70. assert(max_fd_nb != NULL);
  71. FD_CLR(fd, list_fds);
  72. if (fd == *max_fd_nb) {
  73. (*max_fd_nb)--;
  74. }
  75. return 0;
  76. }
  77. /***** Apply mapping activation fuction *****/
  78. static void apply_mapping_activation(STRUCT_MAPPED_GPIO * node_mapping){
  79. node_mapping->activated = true;
  80. if(node_mapping->type_mapping == TYPE_MAPPING_KEYBOARD){
  81. GPIO_PRINTF("Apply mapping activation fct: Key event: %d\n", node_mapping->key_value);
  82. sendKey(node_mapping->key_value, 1);
  83. //sendKeyAndStopKey(node_mapping->key_value);
  84. }
  85. else if(node_mapping->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
  86. GPIO_PRINTF("Apply mapping activation fct: shell command \"%s\"\n", node_mapping->shell_command);
  87. system(node_mapping->shell_command);
  88. }
  89. }
  90. /***** Apply mapping desactivation function *****/
  91. static void apply_mapping_desactivation(STRUCT_MAPPED_GPIO * node_mapping){
  92. node_mapping->activated = false;
  93. if(node_mapping->type_mapping == TYPE_MAPPING_KEYBOARD){
  94. GPIO_PRINTF("Apply mapping desactivation fct: Key event: %d\n", node_mapping->key_value);
  95. sendKey(node_mapping->key_value, 0);
  96. }
  97. else if(node_mapping->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
  98. //GPIO_PRINTF("Apply mapping desactivation fct: shell command \"%s\"\n", node_mapping->shell_command);
  99. }
  100. }
  101. static void find_and_call_mapping_function(int idx_gpio_interrupted,
  102. STRUCT_MAPPED_GPIO * cl_mapping,
  103. bool* mask_gpio_current_interrupts,
  104. bool * mask_gpio_values,
  105. bool activation){
  106. // Init variables
  107. STRUCT_MAPPED_GPIO * current = cl_mapping;
  108. bool mapping_found = false;
  109. // Search if there are mappings to deactivate
  110. while (current != NULL) {
  111. int i;
  112. bool gpio_found_pin_in_mapping = false;
  113. bool all_gpio_activated_in_mapping = true;
  114. //GPIO_PRINTF(" Mapping searching for idx_gpio_interrupted: %d, and %s: \n", idx_gpio_interrupted, activation?"activation":"deactivation")
  115. for (i=0; i < current->nb_simultaneous_pins; i++){
  116. //GPIO_PRINTF(" Pin in mapping: %d, pin_idx=%d\n", gpio_pins[current->pins_idx[i]], current->pins_idx[i]);
  117. // Find if current mapping contains interrupted pin
  118. if (current->pins_idx[i] == idx_gpio_interrupted){
  119. gpio_found_pin_in_mapping = true;
  120. }
  121. // Check if all other pins of current mapping were already activated in previous mask
  122. if(!mask_gpio_values[current->pins_idx[i]]){
  123. all_gpio_activated_in_mapping = false;
  124. }
  125. }
  126. // If this mapping contains the interrupted pin and all other pins activated:
  127. if(gpio_found_pin_in_mapping && all_gpio_activated_in_mapping){
  128. // Treating activation cases
  129. if(activation){
  130. // if real mapping already found => need to deactivate previously activated ones
  131. if(mapping_found && current->activated){
  132. GPIO_PRINTF(" Mapping Deactivation because real one already found: GPIO %d found in following activated mapping: \n",
  133. gpio_pins[idx_gpio_interrupted]);
  134. print_chained_list_node(current);
  135. apply_mapping_desactivation(current);
  136. }
  137. else if(!mapping_found){ // If this is the real mapping
  138. if(current->activated){
  139. GPIO_ERROR_PRINTF("WARNING in find_and_call_mapping_function - Activating already activated mapping %s\n",
  140. current->fct_help_str);
  141. }
  142. // Print information and activate mapping
  143. GPIO_PRINTF(" Mapping Activation: GPIO %d found in following deactivated mapping: \n",
  144. gpio_pins[idx_gpio_interrupted]);
  145. print_chained_list_node(current);
  146. apply_mapping_activation(current);
  147. }
  148. }
  149. else{ // Treating deactivation cases
  150. if(current->activated){
  151. GPIO_PRINTF(" Mapping Desactivation: GPIO %d found in following activated mapping: \n",
  152. gpio_pins[idx_gpio_interrupted]);
  153. print_chained_list_node(current);
  154. apply_mapping_desactivation(current);
  155. }
  156. }
  157. // Set that mapping has been found
  158. mapping_found = true;
  159. }
  160. // Next node in chained list
  161. current = current->next_mapped_gpio;
  162. }
  163. }
  164. /***** Init GPIO Interrupt i2c expander fd *****/
  165. static int init_gpio_interrupt(int pin_nb, int *fd_saved)
  166. {
  167. // Variables
  168. GPIO_PRINTF("Initializing Interrupt on GPIO pin: %d\n", pin_nb);
  169. //Initializing I2C interrupt GPIO
  170. gpio_export(pin_nb);
  171. gpio_set_edge(pin_nb, "both"); // Can be rising, falling or both
  172. //gpio_set_edge(pin_nb, "falling"); // Can be rising, falling or both
  173. *fd_saved = gpio_fd_open(pin_nb, O_RDONLY);
  174. GPIO_PRINTF("fd is: %d\n", *fd_saved);
  175. // add stdin and the sock fd to fds fd_set
  176. safe_fd_set(*fd_saved, &fds, &max_fd);
  177. return 0;
  178. }
  179. /***** DeInit GPIO Interrupt i2c expander fd *****/
  180. static int deinit_gpio_interrupt(int fd_saved)
  181. {
  182. GPIO_PRINTF("DeInitializing Interrupt on GPIO pin fd: %d\n", fd_saved);
  183. // Remove stdin and sock fd from fds fd_set
  184. safe_fd_clr(fd_saved, &fds, &max_fd);
  185. // Unexport GPIO
  186. gpio_fd_close(fd_saved);
  187. return 0;
  188. }
  189. /****************************************************************
  190. * Public functions
  191. ****************************************************************/
  192. /***** Init I2C expander pin mappings *****/
  193. int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare,
  194. STRUCT_MAPPED_GPIO * chained_list_mapping_gpios)
  195. {
  196. // Variables
  197. int idx_gpio;
  198. unsigned int cur_pin_nb;
  199. // Store arguments
  200. nb_mapped_gpios = nb_gpios_to_declare;
  201. gpio_pins = gpio_pins_to_declare;
  202. chained_list_mapping = chained_list_mapping_gpios;
  203. // Init values
  204. mask_gpio_value = malloc(nb_mapped_gpios*sizeof(bool));
  205. memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool));
  206. STRUCT_MAPPED_GPIO * current = chained_list_mapping;
  207. do{
  208. //set mapping deactivated
  209. current->activated = false;
  210. // Next node in chained list
  211. current = current->next_mapped_gpio;
  212. } while(current != NULL);
  213. // Init fds fd_set
  214. FD_ZERO(&fds);
  215. // Init GPIO interrupt from I2C GPIO expander
  216. GPIO_PRINTF(" Initiating interrupt for GPIO_PIN_I2C_EXPANDER_INTERRUPT\n");
  217. init_gpio_interrupt(GPIO_PIN_I2C_EXPANDER_INTERRUPT, &gpio_fd_interrupt_expander_gpio);
  218. // Init I2C expander
  219. pcal6416a_init();
  220. #ifdef ENABLE_AXP209_INTERRUPTS
  221. // Init GPIO interrupt from AXP209
  222. GPIO_PRINTF(" Initiating interrupt for GPIO_PIN_AXP209_INTERRUPT\n");
  223. init_gpio_interrupt(GPIO_PIN_AXP209_INTERRUPT, &gpio_fd_interrupt_axp209);
  224. // Init AXP209
  225. axp209_init();
  226. #endif //ENABLE_AXP209_INTERRUPTS
  227. return 0;
  228. }
  229. /***** DeInit GPIO fds *****/
  230. int deinit_mapping_gpios(void)
  231. {
  232. // DeInit GPIO interrupt from I2C expander
  233. GPIO_PRINTF(" DeInitiating interrupt for GPIO_PIN_I2C_EXPANDER_INTERRUPT\n");
  234. deinit_gpio_interrupt(gpio_fd_interrupt_expander_gpio);
  235. // DeInit I2C expander
  236. pcal6416a_deinit();
  237. #ifdef ENABLE_AXP209_INTERRUPTS
  238. // DeInit GPIO interrupt from AXP209
  239. GPIO_PRINTF(" DeInitiating interrupt for GPIO_PIN_AXP209_INTERRUPT\n");
  240. deinit_gpio_interrupt(gpio_fd_interrupt_axp209);
  241. // DeInit AXP209
  242. axp209_deinit();
  243. #endif //ENABLE_AXP209_INTERRUPTS
  244. return 0;
  245. }
  246. /***** Listen GPIOs interrupts *****/
  247. int listen_gpios_interrupts(void)
  248. {
  249. // Variables
  250. char buffer[2];
  251. int value;
  252. int idx_gpio;
  253. int nb_interrupts = 0;
  254. bool previous_mask_gpio_value[nb_mapped_gpios];
  255. bool mask_gpio_current_interrupts[nb_mapped_gpios];
  256. // Back up master
  257. fd_set dup = fds;
  258. // Init masks
  259. memcpy(previous_mask_gpio_value, mask_gpio_value, nb_mapped_gpios*sizeof(bool));
  260. memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool));
  261. memset(mask_gpio_current_interrupts, false, nb_mapped_gpios*sizeof(bool));
  262. // If interrupt not already found, waiting for interrupt or timeout, Note the max_fd+1
  263. if(!interrupt_i2c_expander_found && !interrupt_axp209_found){
  264. // Listen to interrupts
  265. #ifdef TIMEOUT_MICROSEC_SANITY_CHECK_GPIO_EXP
  266. struct timeval timeout = {0, TIMEOUT_MICROSEC_SANITY_CHECK_GPIO_EXP};
  267. nb_interrupts = select(max_fd+1, NULL, NULL, &dup, &timeout);
  268. #elif TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP
  269. struct timeval timeout = {TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP, 0};
  270. nb_interrupts = select(max_fd+1, NULL, NULL, &dup, &timeout);
  271. #else
  272. nb_interrupts = select(max_fd+1, NULL, NULL, &dup, NULL);
  273. #endif //TIMEOUT_SEC_SANITY_CHECK_GPIO_EXP
  274. if(!nb_interrupts){
  275. // Timeout case
  276. GPIO_PRINTF(" Timeout, forcing sanity check\n");
  277. // Timeout forcing a "Found interrupt" event for sanity check
  278. interrupt_i2c_expander_found = true;
  279. }
  280. else if ( nb_interrupts < 0) {
  281. perror("select");
  282. return -1;
  283. }
  284. }
  285. if(nb_interrupts){
  286. // Check if interrupt from I2C expander or AXP209
  287. // Check which cur_fd is available for read
  288. for (int cur_fd = 0; cur_fd <= max_fd; cur_fd++) {
  289. if (FD_ISSET(cur_fd, &dup)) {
  290. // Rewind file
  291. lseek(cur_fd, 0, SEEK_SET);
  292. // Read current gpio value
  293. if (read(cur_fd, & buffer, 2) != 2) {
  294. perror("read");
  295. break;
  296. }
  297. // remove end of line char
  298. buffer[1] = '\0';
  299. value = atoi(buffer);
  300. //value = 1-atoi(buffer);
  301. // Found interrupt
  302. if(cur_fd == gpio_fd_interrupt_expander_gpio){
  303. GPIO_PRINTF("Found interrupt generated by PCAL6416AHF \r\n");
  304. interrupt_i2c_expander_found = true;
  305. }
  306. else if(cur_fd == gpio_fd_interrupt_axp209){
  307. GPIO_PRINTF("Found interrupt generated by AXP209\r\n");
  308. interrupt_axp209_found = true;
  309. }
  310. }
  311. }
  312. }
  313. #ifdef ENABLE_AXP209_INTERRUPTS
  314. if(interrupt_axp209_found){
  315. GPIO_PRINTF(" Processing interrupt AXP209\n");
  316. int val_int_bank_3 = axp209_read_interrupt_bank_3();
  317. if(val_int_bank_3 < 0){
  318. GPIO_PRINTF(" Could not read AXP209 with I2C\n");
  319. return 0;
  320. }
  321. interrupt_axp209_found = false;
  322. if(val_int_bank_3 & AXP209_INTERRUPT_PEK_SHORT_PRESS){
  323. GPIO_PRINTF(" AXP209 short PEK key press detected\n");
  324. sendKeyAndStopKey(KEY_IDX_MAPPED_FOR_SHORT_PEK_PRESS);
  325. }
  326. if(val_int_bank_3 & AXP209_INTERRUPT_PEK_LONG_PRESS){
  327. GPIO_PRINTF(" AXP209 long PEK key press detected\n");
  328. sendKeyAndStopKey(KEY_IDX_MAPPED_FOR_LONG_PEK_PRESS);
  329. }
  330. }
  331. #endif //ENABLE_AXP209_INTERRUPTS
  332. if(interrupt_i2c_expander_found){
  333. GPIO_PRINTF(" Processing interrupt PCAL6416AHF\n");
  334. // Read I2C GPIO masks:
  335. int val_i2c_mask_interrupted = pcal6416a_read_mask_interrupts();
  336. if(val_i2c_mask_interrupted < 0){
  337. GPIO_PRINTF(" Could not read pcal6416a_read_mask_interrupts\n");
  338. return 0;
  339. }
  340. int val_i2c_mask_active = pcal6416a_read_mask_active_GPIOs();
  341. if(val_i2c_mask_active < 0){
  342. GPIO_PRINTF(" Could not read pcal6416a_read_mask_active_GPIOs\n");
  343. return 0;
  344. }
  345. interrupt_i2c_expander_found = false;
  346. // Find GPIO idx correspondance
  347. for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){
  348. uint16_t tmp_mask_gpio = (1 << gpio_pins[idx_gpio]);
  349. // Found GPIO idx in active GPIOs
  350. if(val_i2c_mask_active & tmp_mask_gpio){
  351. mask_gpio_value[idx_gpio] = true;
  352. }
  353. // Found GPIO idx in interrupt mask
  354. if(val_i2c_mask_interrupted & tmp_mask_gpio){
  355. // Print information
  356. GPIO_PRINTF(" --> Interrupt GPIO: %d, idx_pin: %d\n", gpio_pins[idx_gpio], idx_gpio);
  357. mask_gpio_current_interrupts[idx_gpio] = true;
  358. }
  359. // Sanity check: if we missed an interrupt for some reason, check if the new values are the same
  360. if( !mask_gpio_current_interrupts[idx_gpio] &&
  361. (mask_gpio_value[idx_gpio] != previous_mask_gpio_value[idx_gpio]) ){
  362. // Print information
  363. GPIO_PRINTF(" --> No Interrupt (missed) but value has changed on GPIO: %d, idx_pin: %d\n", gpio_pins[idx_gpio], idx_gpio);
  364. mask_gpio_current_interrupts[idx_gpio] = true;
  365. }
  366. }
  367. // Find and call mapping functions (after all active gpios have been assigned):
  368. for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){
  369. if(!mask_gpio_current_interrupts[idx_gpio]) continue;
  370. if (mask_gpio_value[idx_gpio]){
  371. find_and_call_mapping_function(idx_gpio,
  372. chained_list_mapping,
  373. mask_gpio_current_interrupts,
  374. mask_gpio_value,
  375. true);
  376. }
  377. else{
  378. find_and_call_mapping_function(idx_gpio,
  379. chained_list_mapping,
  380. mask_gpio_current_interrupts,
  381. previous_mask_gpio_value,
  382. false);
  383. }
  384. }
  385. }
  386. return 0;
  387. }