gpio_mapping.c 15 KB

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