gpio_mapping.c 15 KB

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