RocketLogger 2.1.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
54struct gpiod_chip *gpio_chip[GPIO_CHIP_COUNT] = {NULL};
55
62static 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
77int 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
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
103gpio_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
130void gpio_release(gpio_t *gpio) {
131 gpiod_line_release(gpio);
132 gpio = NULL;
133}
134
135int 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
146int 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) {
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;
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
187int 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
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
#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
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_t * gpio_setup_interrupt(int gpio_number, gpio_interrupt_t edge, const char *name)
Definition: gpio.c:148
gpio_t * gpio_setup(int gpio_number, gpio_mode_t mode, const char *name)
Definition: gpio.c:103
@ 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