gpio_mapping.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  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 <linux/input.h>
  12. #include "gpio_mapping.h"
  13. #include "driver_pcal6416a.h"
  14. /****************************************************************
  15. * Defines
  16. ****************************************************************/
  17. #define die(str, args...) do { \
  18. perror(str); \
  19. return(EXIT_FAILURE); \
  20. } while(0)
  21. #define DEBUG_GPIO_PRINTF (0)
  22. #define ERROR_GPIO_PRINTF (1)
  23. #if (DEBUG_GPIO_PRINTF)
  24. #define GPIO_PRINTF(...) printf(__VA_ARGS__);
  25. #else
  26. #define GPIO_PRINTF(...)
  27. #endif
  28. #if (ERROR_GPIO_PRINTF)
  29. #define GPIO_ERROR_PRINTF(...) printf(__VA_ARGS__);
  30. #else
  31. #define GPIO_ERROR_PRINTF(...)
  32. #endif
  33. /****************************************************************
  34. * Static variables
  35. ****************************************************************/
  36. static int nb_mapped_gpios;
  37. static int * gpio_pins;
  38. STRUCT_MAPPED_GPIO * chained_list_mapping;
  39. static int max_fd = 0;
  40. static int gpio_fd_interrupt_i2c;
  41. static fd_set fds;
  42. static bool * mask_gpio_value;
  43. /****************************************************************
  44. * Static functions
  45. ****************************************************************/
  46. /***** Add a fd to fd_set, and update max_fd_nb ******/
  47. static int safe_fd_set(int fd, fd_set* list_fds, int* max_fd_nb) {
  48. assert(max_fd_nb != NULL);
  49. FD_SET(fd, list_fds);
  50. if (fd > *max_fd_nb) {
  51. *max_fd_nb = fd;
  52. }
  53. return 0;
  54. }
  55. /***** Clear fd from fds, update max fd if needed *****/
  56. static int safe_fd_clr(int fd, fd_set* list_fds, int* max_fd_nb) {
  57. assert(max_fd_nb != NULL);
  58. FD_CLR(fd, list_fds);
  59. if (fd == *max_fd_nb) {
  60. (*max_fd_nb)--;
  61. }
  62. return 0;
  63. }
  64. /***** Apply mapping activation fuction *****/
  65. static void apply_mapping_activation(STRUCT_MAPPED_GPIO * node_mapping){
  66. node_mapping->activated = true;
  67. if(node_mapping->type_mapping == TYPE_MAPPING_KEYBOARD){
  68. GPIO_PRINTF("Apply mapping activation fct: Key event: %d\n", node_mapping->key_value);
  69. sendKey(node_mapping->key_value, 1);
  70. //sendKeyAndStopKey(node_mapping->key_value);
  71. }
  72. else if(node_mapping->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
  73. GPIO_PRINTF("Apply mapping activation fct: shell command \"%s\"\n", node_mapping->shell_command);
  74. system(node_mapping->shell_command);
  75. }
  76. }
  77. /***** Apply mapping desactivation function *****/
  78. static void apply_mapping_desactivation(STRUCT_MAPPED_GPIO * node_mapping){
  79. node_mapping->activated = false;
  80. if(node_mapping->type_mapping == TYPE_MAPPING_KEYBOARD){
  81. GPIO_PRINTF("Apply mapping desactivation fct: Key event: %d\n", node_mapping->key_value);
  82. sendKey(node_mapping->key_value, 0);
  83. }
  84. else if(node_mapping->type_mapping == TYPE_MAPPING_SHELL_COMMAND){
  85. //GPIO_PRINTF("Apply mapping desactivation fct: shell command \"%s\"\n", node_mapping->shell_command);
  86. }
  87. }
  88. static void find_and_call_mapping_function(int idx_gpio_interrupted,
  89. STRUCT_MAPPED_GPIO * cl_mapping,
  90. bool* mask_gpio_current_interrupts,
  91. bool * mask_gpio_values,
  92. bool activation){
  93. // Init variables
  94. STRUCT_MAPPED_GPIO * current = cl_mapping;
  95. bool mapping_found = false;
  96. // Search if there are mappings to deactivate
  97. while (current != NULL) {
  98. int i;
  99. bool gpio_found_pin_in_mapping = false;
  100. bool all_gpio_activated_in_mapping = true;
  101. //GPIO_PRINTF(" Mapping searching for idx_gpio_interrupted: %d, and %s: \n", idx_gpio_interrupted, activation?"activation":"deactivation")
  102. for (i=0; i < current->nb_simultaneous_pins; i++){
  103. //GPIO_PRINTF(" Pin in mapping: %d, pin_idx=%d\n", gpio_pins[current->pins_idx[i]], current->pins_idx[i]);
  104. // Find if current mapping contains interrupted pin
  105. if (current->pins_idx[i] == idx_gpio_interrupted){
  106. gpio_found_pin_in_mapping = true;
  107. }
  108. // Check if all other pins of current mapping were already activated in previous mask
  109. if(!mask_gpio_values[current->pins_idx[i]]){
  110. all_gpio_activated_in_mapping = false;
  111. }
  112. }
  113. // If this mapping contains the interrupted pin and all other pins activated:
  114. if(gpio_found_pin_in_mapping && all_gpio_activated_in_mapping){
  115. // Treating activation cases
  116. if(activation){
  117. // if real mapping already found => need to deactivate previously activated ones
  118. if(mapping_found && current->activated){
  119. GPIO_PRINTF(" Mapping Deactivation because real one already found: GPIO %d found in following activated mapping: \n",
  120. gpio_pins[idx_gpio_interrupted]);
  121. print_chained_list_node(current);
  122. apply_mapping_desactivation(current);
  123. }
  124. else if(!mapping_found){ // If this is the real mapping
  125. if(current->activated){
  126. GPIO_ERROR_PRINTF("WARNING in find_and_call_mapping_function - Activating already activated mapping %s\n",
  127. current->fct_help_str);
  128. }
  129. // Print information and activate mapping
  130. GPIO_PRINTF(" Mapping Activation: GPIO %d found in following deactivated mapping: \n",
  131. gpio_pins[idx_gpio_interrupted]);
  132. print_chained_list_node(current);
  133. apply_mapping_activation(current);
  134. }
  135. }
  136. else{ // Treating deactivation cases
  137. if(current->activated){
  138. GPIO_PRINTF(" Mapping Desactivation: GPIO %d found in following activated mapping: \n",
  139. gpio_pins[idx_gpio_interrupted]);
  140. print_chained_list_node(current);
  141. apply_mapping_desactivation(current);
  142. }
  143. }
  144. // Set that mapping has been found
  145. mapping_found = true;
  146. }
  147. // Next node in chained list
  148. current = current->next_mapped_gpio;
  149. }
  150. }
  151. /***** Init GPIO Interrupt i2c expander fd *****/
  152. static int init_gpio_interrupt(void)
  153. {
  154. // Variables
  155. int cur_pin_nb = GPIO_PIN_I2C_EXPANDER_INTERRUPT;
  156. GPIO_PRINTF("Initializing Interrupt i2c expander GPIO pin fd: %d\n", cur_pin_nb);
  157. // Init fds fd_set
  158. FD_ZERO(&fds);
  159. //Initializing I2C interrupt GPIO
  160. gpio_export(cur_pin_nb);
  161. //gpio_set_edge(cur_pin_nb, "both"); // Can be rising, falling or both
  162. gpio_set_edge(cur_pin_nb, "falling"); // Can be rising, falling or both
  163. gpio_fd_interrupt_i2c = gpio_fd_open(cur_pin_nb, O_RDONLY);
  164. // add stdin and the sock fd to fds fd_set
  165. safe_fd_set(gpio_fd_interrupt_i2c, &fds, &max_fd);
  166. return 0;
  167. }
  168. /***** DeInit GPIO Interrupt i2c expander fd *****/
  169. static int deinit_gpio_interrupt(void)
  170. {
  171. GPIO_PRINTF("DeInitializing Interrupt i2c expander GPIO pin fd\n");
  172. // Remove stdin and sock fd from fds fd_set
  173. safe_fd_clr(gpio_fd_interrupt_i2c, &fds, &max_fd);
  174. // Unexport GPIO
  175. gpio_fd_close(gpio_fd_interrupt_i2c);
  176. return 0;
  177. }
  178. /****************************************************************
  179. * Public functions
  180. ****************************************************************/
  181. /***** Init I2C expander pin mappings *****/
  182. int init_mapping_gpios(int * gpio_pins_to_declare, int nb_gpios_to_declare,
  183. STRUCT_MAPPED_GPIO * chained_list_mapping_gpios)
  184. {
  185. // Variables
  186. int idx_gpio;
  187. unsigned int cur_pin_nb;
  188. // Store arguments
  189. nb_mapped_gpios = nb_gpios_to_declare;
  190. gpio_pins = gpio_pins_to_declare;
  191. chained_list_mapping = chained_list_mapping_gpios;
  192. // Init values
  193. mask_gpio_value = malloc(nb_mapped_gpios*sizeof(bool));
  194. memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool));
  195. STRUCT_MAPPED_GPIO * current = chained_list_mapping;
  196. do{
  197. //set mapping deactivated
  198. current->activated = false;
  199. // Next node in chained list
  200. current = current->next_mapped_gpio;
  201. } while(current != NULL);
  202. // Init GPIO interrupt from I2C expander
  203. init_gpio_interrupt();
  204. // Init I2C expander
  205. pcal6416a_init();
  206. return 0;
  207. }
  208. /***** DeInit GPIO fds *****/
  209. int deinit_mapping_gpios(void)
  210. {
  211. // DeInit GPIO interrupt from I2C expander
  212. deinit_gpio_interrupt();
  213. // DeInit I2C expander
  214. pcal6416a_deinit();
  215. return 0;
  216. }
  217. /***** Listen GPIOs interrupts *****/
  218. int listen_gpios_interrupts(void)
  219. {
  220. // Variables
  221. char buffer[2];
  222. int idx_gpio, value;
  223. bool previous_mask_gpio_value[nb_mapped_gpios];
  224. bool mask_gpio_current_interrupts[nb_mapped_gpios];
  225. uint16_t val_i2c_mask_interrupted, val_i2c_mask_active;
  226. bool interrupt_found = false;
  227. // Back up master
  228. fd_set dup = fds;
  229. // Init masks
  230. memcpy(previous_mask_gpio_value, mask_gpio_value, nb_mapped_gpios*sizeof(bool));
  231. memset(mask_gpio_value, false, nb_mapped_gpios*sizeof(bool));
  232. memset(mask_gpio_current_interrupts, false, nb_mapped_gpios*sizeof(bool));
  233. // Note the max_fd+1
  234. if (select(max_fd+1, NULL, NULL, &dup, NULL) < 0) {
  235. perror("select");
  236. return -1;
  237. }
  238. // Check if interrupt from I2C expander
  239. // Check which cur_fd is available for read
  240. for (int cur_fd = 0; cur_fd <= max_fd; cur_fd++) {
  241. if (FD_ISSET(cur_fd, &dup)) {
  242. // Revenir au debut du fichier (lectures successives).
  243. lseek(cur_fd, 0, SEEK_SET);
  244. // Read current gpio value
  245. if (read(cur_fd, & buffer, 2) != 2) {
  246. perror("read");
  247. break;
  248. }
  249. // Effacer le retour-chariot.
  250. buffer[1] = '\0';
  251. value = 1-atoi(buffer);
  252. // Found interrupt
  253. interrupt_found = true;
  254. }
  255. }
  256. if(interrupt_found){
  257. // Read I2C GPIO masks:
  258. val_i2c_mask_interrupted = pcal6416a_read_mask_interrupts();
  259. val_i2c_mask_active = pcal6416a_read_mask_active_GPIOs();
  260. // Find GPIO idx correspondance
  261. for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){
  262. uint16_t tmp_mask_gpio = (1 << gpio_pins[idx_gpio]);
  263. // Found GPIO idx in active GPIOs
  264. if(val_i2c_mask_active & tmp_mask_gpio){
  265. mask_gpio_value[idx_gpio] = true;
  266. }
  267. // Found GPIO idx in interrupt mask
  268. if(val_i2c_mask_interrupted & tmp_mask_gpio){
  269. // Print information
  270. GPIO_PRINTF(" --> Interrupt GPIO: %d, idx_pin: %d\n", gpio_pins[idx_gpio], idx_gpio);
  271. mask_gpio_current_interrupts[idx_gpio] = true;
  272. }
  273. }
  274. // Find and call mapping functions (after all active gpios have been assigned):
  275. for (idx_gpio=0; idx_gpio<nb_mapped_gpios; idx_gpio++){
  276. if(!mask_gpio_current_interrupts[idx_gpio]) continue;
  277. if (mask_gpio_value[idx_gpio]){
  278. find_and_call_mapping_function(idx_gpio,
  279. chained_list_mapping,
  280. mask_gpio_current_interrupts,
  281. mask_gpio_value,
  282. true);
  283. }
  284. else{
  285. find_and_call_mapping_function(idx_gpio,
  286. chained_list_mapping,
  287. mask_gpio_current_interrupts,
  288. previous_mask_gpio_value,
  289. false);
  290. }
  291. }
  292. }
  293. return 0;
  294. }