RocketLogger  2.0.0
gpio.c
Go to the documentation of this file.
1 
32 #include <errno.h>
33 #include <stdint.h>
34 #include <string.h>
35 
36 #include <gpiod.h>
37 #include <time.h>
38 #include <unistd.h>
39 
40 #include "log.h"
41 #include "rl.h"
42 
43 #include "gpio.h"
44 
46 #define GPIO_CHIP_COUNT 4
47 
49 #define GPIO_LINES_PER_CHIP 32
50 
52 #define GPIO_DEBOUNCE_DELAY_US 50
53 
54 struct gpiod_chip *gpio_chip[GPIO_CHIP_COUNT] = {NULL};
55 
62 static gpio_t *gpio_get_line(int gpio_number) {
63  int gpio_chip_number = gpio_number / GPIO_LINES_PER_CHIP;
64  int gpio_line_index = gpio_number % GPIO_LINES_PER_CHIP;
65 
66  // check gpio chip initialized
67  if (gpio_chip[gpio_chip_number] == NULL) {
68  rl_log(RL_LOG_ERROR, "GPIO chip for GPIO%d uninitialized.\n",
69  gpio_number);
70  return NULL;
71  }
72 
73  // get and return gpio line
74  return gpiod_chip_get_line(gpio_chip[gpio_chip_number], gpio_line_index);
75 }
76 
77 int gpio_init() {
78  // open gpio chips
79  for (int i = 0; i < GPIO_CHIP_COUNT; i++) {
80  gpio_chip[i] = gpiod_chip_open_by_number(i);
81  if (gpio_chip[i] == NULL) {
83  "Failed opening GPIO chip %d. %d message: %s\n", i, errno,
84  strerror(errno));
85  return ERROR;
86  }
87  }
88 
89  return SUCCESS;
90 }
91 
92 void gpio_deinit() {
93  // open gpio chips
94  for (int i = 0; i < GPIO_CHIP_COUNT; i++) {
95  if (gpio_chip[i] == NULL) {
96  continue;
97  }
98  gpiod_chip_close(gpio_chip[i]);
99  gpio_chip[i] = NULL;
100  }
101 }
102 
103 gpio_t *gpio_setup(int gpio_number, gpio_mode_t mode, const char *name) {
104  // get gpio line
105  gpio_t *gpio_line = gpio_get_line(gpio_number);
106  if (gpio_line == NULL) {
108  "Failed to get GPIO line for GPIO %s. %d message: %s\n", name,
109  errno, strerror(errno));
110  return NULL;
111  }
112 
113  // configure GPIO direction
114  int ret = -1;
115  if (mode == GPIO_MODE_OUT) {
116  ret = gpiod_line_request_output(gpio_line, name, 0);
117  } else if (mode == GPIO_MODE_IN) {
118  ret = gpiod_line_request_input(gpio_line, name);
119  }
120  if (ret < 0) {
122  "Failed to configure for GPIO %s. %d message: %s\n", name, errno,
123  strerror(errno));
124  return NULL;
125  }
126 
127  return gpio_line;
128 }
129 
130 void gpio_release(gpio_t *gpio) {
131  gpiod_line_release(gpio);
132  gpio = NULL;
133 }
134 
135 int gpio_set_value(gpio_t *gpio, int value) {
136  // validate output value to set
137  if (value < 0 || value > 1) {
138  errno = EINVAL;
139  return ERROR;
140  }
141 
142  // set gpio value and return result
143  return gpiod_line_set_value(gpio, value);
144 }
145 
146 int gpio_get_value(gpio_t *gpio) { return gpiod_line_get_value(gpio); }
147 
149  const char *name) {
150  // get gpio line
151  gpio_t *gpio_line = gpio_get_line(gpio_number);
152  if (gpio_line == NULL) {
154  "Failed to get GPIO line for GPIO %s. %d message: %s\n", name,
155  errno, strerror(errno));
156  return NULL;
157  }
158 
159  // request interrupt events from gpio line
160  int ret = 0;
161  switch (edge) {
162  case GPIO_INTERRUPT_NONE:
163  break;
165  ret = gpiod_line_request_rising_edge_events(gpio_line, name);
166  break;
168  ret = gpiod_line_request_falling_edge_events(gpio_line, name);
169  break;
170  case GPIO_INTERRUPT_BOTH:
171  ret = gpiod_line_request_both_edges_events(gpio_line, name);
172  break;
173  default:
174  rl_log(RL_LOG_ERROR, "Invalid GPIO interrupt edge configuration");
175  return NULL;
176  }
177  if (ret < 0) {
179  "Failed to configure interrupt for GPIO %s. %d message: %s\n",
180  name, errno, strerror(errno));
181  return NULL;
182  }
183 
184  return gpio_line;
185 }
186 
187 int gpio_wait_interrupt(gpio_t *gpio, const struct timespec *timeout) {
188  int ret = -1;
189  struct gpiod_line_event event;
190 
191  // wait for registered events
192  ret = gpiod_line_event_wait(gpio, timeout);
193  if (ret < 0) {
194  // log error except if interrupted
195  if (errno != EINTR) {
197  "Failed waiting for interrupt of GPIO %s. %d message: %s\n",
198  gpiod_line_consumer(gpio), errno, strerror(errno));
199  }
200  return ret;
201  }
202 
203  // small debounce delay
204  usleep(GPIO_DEBOUNCE_DELAY_US);
205 
206  // get event data
207  ret = gpiod_line_event_read(gpio, &event);
208  if (ret < 0) {
210  "Failed reading event for GPIO %s. %d message: %s\n",
211  gpiod_line_consumer(gpio), errno, strerror(errno));
212  return ret;
213  }
214 
215  // decode and return resulting gpio input value
216  if (event.event_type == GPIOD_LINE_EVENT_RISING_EDGE) {
217  return 1;
218  }
219  if (event.event_type == GPIOD_LINE_EVENT_FALLING_EDGE) {
220  return 0;
221  }
222 
223  // treat neither falling nor rising edge as error
224  return ERROR;
225 }
struct gpiod_chip * gpio_chip[GPIO_CHIP_COUNT]
Definition: gpio.c:54
#define GPIO_CHIP_COUNT
Number of GPIO chips.
Definition: gpio.c:46
gpio_t * gpio_setup(int gpio_number, gpio_mode_t mode, const char *name)
Definition: gpio.c:103
#define GPIO_LINES_PER_CHIP
Number of GPIO lines per GPIO chip.
Definition: gpio.c:49
int gpio_set_value(gpio_t *gpio, int value)
Definition: gpio.c:135
int gpio_init()
Definition: gpio.c:77
#define GPIO_DEBOUNCE_DELAY_US
Minimal time a button needs to be pressed (in microseconds)
Definition: gpio.c:52
gpio_t * gpio_setup_interrupt(int gpio_number, gpio_interrupt_t edge, const char *name)
Definition: gpio.c:148
int gpio_get_value(gpio_t *gpio)
Definition: gpio.c:146
void gpio_release(gpio_t *gpio)
Definition: gpio.c:130
void gpio_deinit()
Definition: gpio.c:92
int gpio_wait_interrupt(gpio_t *gpio, const struct timespec *timeout)
Definition: gpio.c:187
@ GPIO_INTERRUPT_FALLING
Interrupt on falling edge.
Definition: gpio.h:65
@ GPIO_INTERRUPT_BOTH
Interrupt on both edges.
Definition: gpio.h:66
@ GPIO_INTERRUPT_NONE
No interrupt.
Definition: gpio.h:63
@ GPIO_INTERRUPT_RISING
Interrupt on rising edge.
Definition: gpio.h:64
enum gpio_interrupt gpio_interrupt_t
@ GPIO_MODE_OUT
GPIO write mode.
Definition: gpio.h:56
@ GPIO_MODE_IN
GPIO read mode.
Definition: gpio.h:55
struct gpiod_line gpio_t
Definition: gpio.h:72
enum gpio_mode gpio_mode_t
int rl_log(rl_log_level_t log_level, char const *const format,...)
Definition: log.c:82
@ RL_LOG_ERROR
Error.
Definition: log.h:49
#define ERROR
Function return value for errors (use errno to indicate the error)
Definition: rl.h:46
#define SUCCESS
Function return value for successful completion.
Definition: rl.h:44