GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/platform/gpiodevice_libgpiod.h
Date: 2026-03-20 22:56:14
Exec Total Coverage
Lines: 0 223 0.0%
Functions: 0 5 0.0%
Branches: 0 114 0.0%

Line Branch Exec Source
1 /* GATE PROJECT LICENSE:
2 +----------------------------------------------------------------------------+
3 | Copyright (c) 2018-2026, Stefan Meislinger <sm@opengate.at> |
4 | All rights reserved. |
5 | |
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met:|
8 | |
9 | 1. Redistributions of source code must retain the above copyright notice, |
10 | this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
14 | |
15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"|
16 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
18 | ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
19 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
20 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
21 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
22 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
23 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
24 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
25 | THE POSSIBILITY OF SUCH DAMAGE. |
26 +----------------------------------------------------------------------------+
27 */
28
29 #ifndef GATE_IO_PLATFORM_GPIODEVICE_LIBGPIOD_H_INCLUDED
30 #define GATE_IO_PLATFORM_GPIODEVICE_LIBGPIOD_H_INCLUDED
31
32 #include "gate/libraries.h"
33 #include "gate/debugging.h"
34
35
36 enum gpiod_line_value
37 {
38 GPIOD_LINE_VALUE_ERROR = -1,
39 GPIOD_LINE_VALUE_INACTIVE = 0,
40 GPIOD_LINE_VALUE_ACTIVE = 1
41 };
42
43
44 enum gpiod_line_direction
45 {
46 GPIOD_LINE_DIRECTION_AS_IS = 1,
47 GPIOD_LINE_DIRECTION_INPUT = 2,
48 GPIOD_LINE_DIRECTION_OUTPUT = 3
49 };
50
51 typedef struct gpiod_chip gpiod_chip_t;
52 typedef struct gpiod_chip_info gpiod_chip_info_t;
53 typedef struct gpiod_line gpiod_line_t;
54 typedef struct gpiod_line_info gpiod_line_info_t;
55 typedef struct gpiod_line_settings gpiod_line_settings_t;
56 typedef struct gpiod_line_config gpiod_line_config_t;
57 typedef struct gpiod_line_request gpiod_line_request_t;
58 typedef struct gpiod_request_config gpiod_request_config_t;
59
60 typedef enum gpiod_line_direction gpiod_line_direction_t;
61 typedef enum gpiod_line_value gpiod_line_value_t;
62
63 typedef struct gpiod_code
64 {
65 char const* (*version_string) (void);
66
67
68 /* chip access */
69 gpiod_chip_t* (*chip_open) (const char *path);
70 void (*chip_close) (gpiod_chip_t* chip);
71
72
73 /* chip info */
74 const char* (*v1_chip_name) (gpiod_chip_t* chip);
75 const char* (*v1_chip_label) (gpiod_chip_t* chip);
76 unsigned int (*v1_chip_num_lines) (gpiod_chip_t* chip);
77
78 gpiod_chip_info_t* (*v2_chip_get_info) (gpiod_chip_t* chip);
79 void (*v2_chip_info_free) (gpiod_chip_info_t* info);
80 const char* (*v2_chip_info_get_name) (gpiod_chip_info_t* info);
81 const char* (*v2_chip_info_get_label) (gpiod_chip_info_t* info);
82 size_t (*v2_chip_info_get_num_lines) (gpiod_chip_info_t* info);
83
84 /* line info */
85 gpiod_line_t* (*v1_chip_get_line) (gpiod_chip_t* chip, unsigned int offset);
86 void (*v1_line_release) (gpiod_line_t* line);
87 const char * (*v1_line_name) (gpiod_line_t* line);
88 const char * (*v1_line_consumer) (gpiod_line_t* line);
89 int (*v1_line_direction) (gpiod_line_t* line);
90 int (*v1_line_active_state) (gpiod_line_t* line);
91 bool (*v1_line_is_used) (gpiod_line_t* line);
92
93 gpiod_line_info_t* (*v2_chip_get_line_info) (gpiod_chip_t* chip, unsigned int offset);
94 void (*v2_line_info_free) (gpiod_line_info_t *info);
95 const char * (*v2_line_info_get_name) (gpiod_line_info_t *info);
96 const char * (*v2_line_info_get_consumer) (gpiod_line_info_t *info);
97 bool (*v2_line_info_is_used) (gpiod_line_info_t *info);
98 gpiod_line_direction_t (*v2_line_info_get_direction) (gpiod_line_info_t *info);
99
100 /* line read/write access */
101 int (*v1_line_request_input) (gpiod_line_t* line, const char* consumer);
102 int (*v1_line_get_value) (gpiod_line_t* line);
103 int (*v1_line_request_output) (gpiod_line_t* line, const char *consumer, int default_val);
104 int (*v1_line_set_value) (gpiod_line_t* line, int value);
105
106 gpiod_line_settings_t* (*v2_line_settings_new) (void);
107 void (*v2_line_settings_free) (gpiod_line_settings_t* settings);
108 int (*v2_line_settings_set_direction) (gpiod_line_settings_t* settings, gpiod_line_direction_t direction);
109 int (*v2_line_settings_set_output_value)(gpiod_line_settings_t* settings, gpiod_line_value_t value);
110 gpiod_line_direction_t (*v2_line_settings_get_direction) (gpiod_line_settings_t* settings);
111 gpiod_line_config_t* (*v2_line_config_new) (void);
112 void (*v2_line_config_free) (gpiod_line_config_t* config);
113 int (*v2_line_config_add_line_settings) (gpiod_line_config_t* config, const unsigned int* offsets, size_t num_offsets, gpiod_line_settings_t* settings);
114 gpiod_line_request_t* (*v2_chip_request_lines) (gpiod_chip_t* chip, gpiod_request_config_t* req_cfg, gpiod_line_config_t* line_cfg);
115 void (*v2_line_request_release) (gpiod_line_request_t* request);
116 gpiod_line_value_t (*v2_line_request_get_value) (gpiod_line_request_t* request, unsigned int offset);
117 int (*v2_line_request_reconfigure_lines)(gpiod_line_request_t* request, gpiod_line_config_t* config);
118 int (*v2_line_request_set_value) (gpiod_line_request_t* request, unsigned int offset, gpiod_line_value_t value);
119
120 } gpiod_code_t;
121
122
123 static gpiod_code_t* get_gpiod_functions()
124 {
125 static gpiod_code_t code;
126 static gate_bool_t code_loaded = false;
127 static gate_library_t code_lib;
128
129 if (!code_loaded)
130 {
131 static gate_string_t const lib_name = GATE_STRING_INIT_STATIC("libgpiod.so");
132 gate_result_t result;
133 result = gate_library_open(&lib_name, &code_lib, 0);
134 do
135 {
136 if (GATE_FAILED(result))
137 {
138 GATE_DEBUG_TRACE("Failed to load libgpiod");
139 break;
140 }
141
142 gate_library_get_function_name(code_lib, "gpiod_version_string", &code.version_string);
143 gate_library_get_function_name(code_lib, "gpiod_chip_open", &code.chip_open);
144 gate_library_get_function_name(code_lib, "gpiod_chip_close", &code.chip_close);
145
146 gate_library_get_function_name(code_lib, "gpiod_chip_name", &code.v1_chip_name);
147 gate_library_get_function_name(code_lib, "gpiod_chip_label", &code.v1_chip_label);
148 gate_library_get_function_name(code_lib, "gpiod_chip_num_lines", &code.v1_chip_num_lines);
149
150 gate_library_get_function_name(code_lib, "gpiod_chip_get_info", &code.v2_chip_get_info);
151 gate_library_get_function_name(code_lib, "gpiod_chip_info_free", &code.v2_chip_info_free);
152 gate_library_get_function_name(code_lib, "gpiod_chip_info_get_name", &code.v2_chip_info_get_name);
153 gate_library_get_function_name(code_lib, "gpiod_chip_info_get_label", &code.v2_chip_info_get_label);
154 gate_library_get_function_name(code_lib, "gpiod_chip_info_get_num_lines", &code.v2_chip_info_get_num_lines);
155
156 gate_library_get_function_name(code_lib, "gpiod_chip_get_line", &code.v1_chip_get_line);
157 gate_library_get_function_name(code_lib, "gpiod_line_release", &code.v1_line_release);
158 gate_library_get_function_name(code_lib, "gpiod_line_name", &code.v1_line_name);
159 gate_library_get_function_name(code_lib, "gpiod_line_consumer", &code.v1_line_consumer);
160 gate_library_get_function_name(code_lib, "gpiod_line_direction", &code.v1_line_direction);
161 gate_library_get_function_name(code_lib, "gpiod_line_active_state", &code.v1_line_active_state);
162 gate_library_get_function_name(code_lib, "gpiod_line_is_used", &code.v1_line_is_used);
163
164 gate_library_get_function_name(code_lib, "gpiod_chip_get_line_info", &code.v2_chip_get_line_info);
165 gate_library_get_function_name(code_lib, "gpiod_line_info_free", &code.v2_line_info_free);
166 gate_library_get_function_name(code_lib, "gpiod_line_info_get_name", &code.v2_line_info_get_name);
167 gate_library_get_function_name(code_lib, "gpiod_line_info_get_consumer", &code.v2_line_info_get_consumer);
168 gate_library_get_function_name(code_lib, "gpiod_line_info_get_direction", &code.v2_line_info_get_direction);
169 gate_library_get_function_name(code_lib, "gpiod_line_info_is_used", &code.v2_line_info_is_used);
170
171
172
173 gate_library_get_function_name(code_lib, "gpiod_line_request_input", &code.v1_line_request_input);
174 gate_library_get_function_name(code_lib, "gpiod_line_get_value", &code.v1_line_get_value);
175 gate_library_get_function_name(code_lib, "gpiod_line_request_output", &code.v1_line_request_output);
176 gate_library_get_function_name(code_lib, "gpiod_line_set_value", &code.v1_line_set_value);
177
178 gate_library_get_function_name(code_lib, "gpiod_line_settings_new", &code.v2_line_settings_new);
179 gate_library_get_function_name(code_lib, "gpiod_line_settings_free", &code.v2_line_settings_free);
180 gate_library_get_function_name(code_lib, "gpiod_line_settings_set_direction", &code.v2_line_settings_set_direction);
181 gate_library_get_function_name(code_lib, "gpiod_line_settings_set_output_value",&code.v2_line_settings_set_output_value);
182 gate_library_get_function_name(code_lib, "gpiod_line_settings_get_direction", &code.v2_line_settings_get_direction);
183 gate_library_get_function_name(code_lib, "gpiod_line_config_new", &code.v2_line_config_new);
184 gate_library_get_function_name(code_lib, "gpiod_line_config_free", &code.v2_line_config_free);
185 gate_library_get_function_name(code_lib, "gpiod_line_config_add_line_settings", &code.v2_line_config_add_line_settings);
186 gate_library_get_function_name(code_lib, "gpiod_chip_request_lines", &code.v2_chip_request_lines);
187 gate_library_get_function_name(code_lib, "gpiod_line_request_release", &code.v2_line_request_release);
188 gate_library_get_function_name(code_lib, "gpiod_line_request_get_value", &code.v2_line_request_get_value);
189 gate_library_get_function_name(code_lib, "gpiod_line_request_reconfigure_lines",&code.v2_line_request_reconfigure_lines);
190 gate_library_get_function_name(code_lib, "gpiod_line_request_set_value", &code.v2_line_request_set_value);
191
192
193 /* success case */
194 code_loaded = true;
195 } while(0);
196 }
197
198 return code_loaded ? &code : NULL;
199 }
200
201
202 static gate_result_t gate_gpiod_get_chip_infos(gpiod_chip_t* chip, gate_string_t* ptr_name, gate_string_t* ptr_label, gate_size_t* ptr_linecount)
203 {
204 gpiod_code_t* const gpiod = get_gpiod_functions();
205
206 if (!gpiod)
207 {
208 return GATE_RESULT_NOTAVAILABLE;
209 }
210
211 if (gpiod->v2_chip_get_info)
212 {
213 /* v2 implementation*/
214 gpiod_chip_info_t* ptr_info = gpiod->v2_chip_get_info(chip);
215 if (!ptr_info)
216 {
217 return GATE_RESULT_FAILED;
218 }
219 if (ptr_name)
220 {
221 char const* name = gpiod->v2_chip_info_get_name(ptr_info);
222 gate_string_create(ptr_name, name, gate_str_length(name));
223 }
224 if (ptr_label)
225 {
226 char const* label = gpiod->v2_chip_info_get_label(ptr_info);
227 gate_string_create(ptr_label, label, gate_str_length(label));
228 }
229 if (ptr_linecount)
230 {
231 *ptr_linecount = gpiod->v2_chip_info_get_num_lines(ptr_info);
232 }
233 gpiod->v2_chip_info_free(ptr_info);
234 }
235 else
236 {
237 /* v1 implementation*/
238 if (ptr_name)
239 {
240 char const* name = gpiod->v1_chip_name(chip);
241 gate_string_create(ptr_name, name, gate_str_length(name));
242 }
243 if (ptr_label)
244 {
245 char const* label = gpiod->v1_chip_label(chip);
246 gate_string_create(ptr_label, label, gate_str_length(label));
247 }
248 if (ptr_linecount)
249 {
250 *ptr_linecount = gpiod->v1_chip_num_lines(chip);
251 }
252 }
253 return GATE_RESULT_OK;
254 }
255
256 static gate_result_t gate_gpiod_get_line_infos(gpiod_chip_t* chip, unsigned int line_offset,
257 gate_string_t* ptr_name, gate_string_t* ptr_consumer,
258 int* ptr_direction,
259 bool* ptr_is_used)
260 {
261 gpiod_code_t* const gpiod = get_gpiod_functions();
262
263 if (!gpiod)
264 {
265 return GATE_RESULT_NOTAVAILABLE;
266 }
267
268 if (gpiod->v2_line_info_free != NULL)
269 {
270 /* v2 implementation */
271 gpiod_line_info_t* ptr_line = gpiod->v2_chip_get_line_info(chip, line_offset);
272 if (NULL == ptr_line)
273 {
274 return GATE_RESULT_FAILED;
275 }
276
277 if (ptr_name)
278 {
279 char const* name = gpiod->v2_line_info_get_name(ptr_line);
280 gate_string_create(ptr_name, name, gate_str_length(name));
281 }
282 if (ptr_consumer)
283 {
284 char const* consumer = gpiod->v2_line_info_get_consumer(ptr_line);
285 gate_string_create(ptr_consumer, consumer, gate_str_length(consumer));
286 }
287
288 if (ptr_direction)
289 {
290 *ptr_direction = gpiod->v2_line_info_get_direction(ptr_line);
291 }
292
293 if (ptr_is_used)
294 {
295 *ptr_is_used = gpiod->v2_line_info_is_used(ptr_line);
296 }
297
298 gpiod->v2_line_info_free(ptr_line);
299 }
300 else
301 {
302 /* v1 implementation */
303 gpiod_line_t* ptr_line = gpiod->v1_chip_get_line(chip, line_offset);
304 if (NULL == ptr_line)
305 {
306 return GATE_RESULT_FAILED;
307 }
308
309 if (ptr_name)
310 {
311 char const* name = gpiod->v1_line_name(ptr_line);
312 gate_string_create(ptr_name, name, gate_str_length(name));
313 }
314 if (ptr_consumer)
315 {
316 char const* consumer = gpiod->v1_line_consumer(ptr_line);
317 gate_string_create(ptr_consumer, consumer, gate_str_length(consumer));
318 }
319
320 if (ptr_direction)
321 {
322 *ptr_direction = gpiod->v1_line_direction(ptr_line);
323 }
324
325 if (ptr_is_used)
326 {
327 *ptr_is_used = gpiod->v1_line_is_used(ptr_line);
328 }
329 }
330 return GATE_RESULT_OK;
331 }
332
333
334 static gate_result_t gate_gpiod_read_line_value(gpiod_chip_t* chip, unsigned int line_offset, int* ptr_value)
335 {
336 gpiod_code_t* const gpiod = get_gpiod_functions();
337
338 if (!gpiod)
339 {
340 return GATE_RESULT_NOTAVAILABLE;
341 }
342
343 if (gpiod->v2_line_settings_new != NULL)
344 {
345 /* v2 implementation */
346 gate_result_t ret;
347 gpiod_line_settings_t* new_settings = NULL;
348 gpiod_line_config_t* new_config = NULL;
349 gpiod_line_request_t* new_request = NULL;
350
351 do
352 {
353 gpiod_line_value_t new_value;
354
355 new_settings = gpiod->v2_line_settings_new();
356 if (!new_settings)
357 {
358 ret = GATE_RESULT_OUTOFMEMORY;
359 break;
360 }
361
362 new_config = gpiod->v2_line_config_new();
363 if (!new_config)
364 {
365 ret = GATE_RESULT_OUTOFMEMORY;
366 break;
367 }
368
369 if (0 != gpiod->v2_line_settings_set_direction(new_settings, GPIOD_LINE_DIRECTION_INPUT))
370 {
371 ret = GATE_RESULT_FAILED;
372 break;
373 }
374
375 if (0 != gpiod->v2_line_config_add_line_settings(new_config, &line_offset, 1, new_settings))
376 {
377 ret = GATE_RESULT_FAILED;
378 break;
379 }
380
381 new_request = gpiod->v2_chip_request_lines(chip, NULL, new_config);
382 if (NULL == new_request)
383 {
384 ret = GATE_RESULT_FAILED;
385 break;
386 }
387
388 new_value = gpiod->v2_line_request_get_value(new_request, line_offset);
389 if (new_value == GPIOD_LINE_VALUE_ERROR)
390 {
391 ret = GATE_RESULT_EXECUTIONFAILED;
392 break;
393 }
394
395 /* success case */
396 if (ptr_value)
397 {
398 *ptr_value = (GPIOD_LINE_VALUE_INACTIVE == new_value) ? 0 : 1;
399 }
400 ret = GATE_RESULT_OK;
401 } while (0);
402
403 if (new_request) gpiod->v2_line_request_release(new_request);
404 if (new_config) gpiod->v2_line_config_free(new_config);
405 if (new_settings) gpiod->v2_line_settings_free(new_settings);
406
407 return ret;
408 }
409 else
410 {
411 /* v1 implementation */
412 gate_result_t ret = GATE_RESULT_OK;
413 gpiod_line_t* ptr_line = NULL;
414 do
415 {
416 int result;
417 ptr_line = gpiod->v1_chip_get_line(chip, line_offset);
418 if (NULL == ptr_line)
419 {
420 ret = GATE_RESULT_FAILED;
421 break;
422 }
423
424 result = gpiod->v1_line_request_input(ptr_line, "gateio-gpiodevice");
425 if (result < 0)
426 {
427 ret = GATE_RESULT_FAILED;
428 break;
429 }
430
431 result = gpiod->v1_line_get_value(ptr_line);
432 if (result < 0)
433 {
434 ret = GATE_RESULT_FAILED;
435 break;
436 }
437
438 if (ptr_value)
439 {
440 *ptr_value = result;
441 }
442 } while (0);
443
444 if (ptr_line != NULL)
445 {
446 gpiod->v1_line_release(ptr_line);
447 }
448 return ret;
449 }
450 return GATE_RESULT_OK;
451 }
452
453
454 static gate_result_t gate_gpiod_write_line_value(gpiod_chip_t* chip, unsigned int line_offset, int value)
455 {
456 gpiod_code_t* const gpiod = get_gpiod_functions();
457
458 if (!gpiod)
459 {
460 return GATE_RESULT_NOTAVAILABLE;
461 }
462
463 if (gpiod->v2_line_settings_new != NULL)
464 {
465 /* v2 implementation */
466 gate_result_t ret;
467 struct gpiod_line_settings* new_settings = NULL;
468 struct gpiod_line_config* new_config = NULL;
469 struct gpiod_line_request* new_request = NULL;
470
471 do
472 {
473 int result;
474 gpiod_line_value_t new_value = (value == 0) ? GPIOD_LINE_VALUE_INACTIVE : GPIOD_LINE_VALUE_ACTIVE;
475
476 new_settings = gpiod->v2_line_settings_new();
477 if (!new_settings)
478 {
479 ret = GATE_RESULT_OUTOFMEMORY;
480 break;
481 }
482
483 new_config = gpiod->v2_line_config_new();
484 if (!new_config)
485 {
486 ret = GATE_RESULT_OUTOFMEMORY;
487 break;
488 }
489
490 result = gpiod->v2_line_settings_set_direction(new_settings, GPIOD_LINE_DIRECTION_OUTPUT);
491 if (0 != result)
492 {
493 ret = GATE_RESULT_FAILED;
494 break;
495 }
496
497 result = gpiod->v2_line_settings_set_output_value(new_settings, new_value);
498 if (0 != result)
499 {
500 ret = GATE_RESULT_FAILED;
501 break;
502 }
503
504 result = gpiod->v2_line_config_add_line_settings(new_config, &line_offset, 1, new_settings);
505 if (0 != result)
506 {
507 ret = GATE_RESULT_FAILED;
508 break;
509 }
510
511 new_request = gpiod->v2_chip_request_lines(chip, NULL, new_config);
512 if (NULL == new_request)
513 {
514 ret = GATE_RESULT_FAILED;
515 break;
516 }
517
518 result = gpiod->v2_line_request_reconfigure_lines(new_request, new_config);
519 if(0 != result)
520 {
521 ret = GATE_RESULT_EXECUTIONFAILED;
522 break;
523 }
524
525 /* success case */
526 ret = GATE_RESULT_OK;
527 } while (0);
528
529 if (new_request) gpiod->v2_line_request_release(new_request);
530 if (new_config) gpiod->v2_line_config_free(new_config);
531 if (new_settings) gpiod->v2_line_settings_free(new_settings);
532
533 return ret;
534
535 }
536 else
537 {
538 /* v1 implementation */
539 gate_result_t ret = GATE_RESULT_OK;
540 int result;
541 gpiod_line_t* const ptr_line = gpiod->v1_chip_get_line(chip, line_offset);
542 do
543 {
544 if (NULL == ptr_line)
545 {
546 ret = GATE_RESULT_FAILED;
547 break;
548 }
549
550 result = gpiod->v1_line_request_output(ptr_line, "gateio-gpiodevice", 0);
551 if (result < 0)
552 {
553 ret = GATE_RESULT_FAILED;
554 break;
555 }
556
557 result = gpiod->v1_line_set_value(ptr_line, value);
558 if (result < 0)
559 {
560 ret = GATE_RESULT_FAILED;
561 break;
562 }
563
564 /* success case */
565 ret = GATE_RESULT_OK;
566 } while(0);
567
568 if (ptr_line)
569 {
570 gpiod->v1_line_release(ptr_line);
571 }
572 return ret;
573 }
574 }
575
576 #endif
577