GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/gpiodevices.c
Date: 2026-09-21 06:26:40
Exec Total Coverage
Lines: 0 258 0.0%
Functions: 0 21 0.0%
Branches: 0 126 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 #include "gate/io/gpiodevices.h"
30 #include "gate/results.h"
31
32
33 #if defined(GATE_SYS_LINUX)
34 # if defined(HAVE_LINUX_GPIO_H)
35 # define GATE_IO_GPIODEVICE_IOCTL_IMPL 1
36 # else
37 # define GATE_IO_GPIODEVICE_GPIOD_IMPL 1
38 # endif
39 # define GATE_IO_I2CDEVICE_IOCTL_IMPL 1
40 # define GATE_IO_SPIDEVICE_IOCTL_IMPL 1
41 #elif defined(GATE_SYS_ARDUINO)
42 # define GATE_IO_GPIODEVICE_ARDUINO_IMPL 1
43 # define GATE_IO_I2CDEVICE_WIRE_IMPL 1
44 # define GATE_IO_SPIDEVICE_ARDUINO_IMPL 1
45 #elif defined(GATE_SYS_WIN) && !defined(GATE_SYS_WIN16)
46 # define GATE_IO_GPIODEVICE_NO_IMPL 1
47 # define GATE_IO_I2CDEVICE_FTD2XX_IMPL 1
48 # define GATE_IO_SPIDEVICE_NO_IMPL 1
49 #else
50 # define GATE_IO_GPIODEVICE_NO_IMPL 1
51 # define GATE_IO_I2CDEVICE_NO_IMPL 1
52 # define GATE_IO_SPIDEVICE_NO_IMPL 1
53 #endif
54
55 #include "gate/debugging.h"
56
57 #if defined(GATE_IO_GPIODEVICE_GPIOD_IMPL) || defined(GATE_IO_GPIODEVICE_IOCTL_IMPL)
58
59 /* GPIOD and IOCTL implementation share the same default device path code */
60
61 #include "gate/environments.h"
62
63 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
64 {
65 static gate_string_t const envname = GATE_STRING_INIT_STATIC("GATE_GPIO_DEVICE_PATH");
66 gate_result_t ret = gate_env_get_var(&envname, device_path);
67 if (GATE_FAILED(ret) || gate_string_is_empty(device_path))
68 {
69 static gate_string_t const default_device_path = GATE_STRING_INIT_STATIC("/dev/gpiochip0");
70 gate_string_duplicate(device_path, &default_device_path);
71 ret = GATE_RESULT_OK;
72 }
73 return ret;
74 }
75
76 #endif
77
78
79 #if defined(GATE_IO_GPIODEVICE_GPIOD_IMPL)
80
81 #include "gate/debugging.h"
82 #include "gate/io/platform/gpiodevice_libgpiod.h"
83 #include "gate/environments.h"
84
85 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
86 {
87 gate_result_t ret;
88 gate_cstrbuffer_t pathbuffer = GATE_INIT_EMPTY;
89 gpiod_code_t* const gpiod = get_gpiod_functions();
90
91 if (gpiod == NULL)
92 {
93 return GATE_RESULT_NOTAVAILABLE;
94 }
95
96 do
97 {
98 gpiod_chip_t* ptr_chip;
99
100 if (NULL == gate_cstrbuffer_create_string(&pathbuffer, device_path, false))
101 {
102 ret = GATE_RESULT_OUTOFMEMORY;
103 break;
104 }
105
106 ptr_chip = gpiod->chip_open(gate_cstrbuffer_get(&pathbuffer));
107 if (!ptr_chip)
108 {
109 ret = GATE_RESULT_FAILED;
110 break;
111 }
112
113 /* success case: */
114 if (ptr_device_handle)
115 {
116 *ptr_device_handle = (gate_gpiodevice_t)ptr_chip;
117 }
118 else
119 {
120 gpiod->chip_close(ptr_chip);
121 }
122 ret = GATE_RESULT_OK;
123 } while (0);
124
125 gate_cstrbuffer_destroy(&pathbuffer);
126 return ret;
127 }
128
129
130 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
131 {
132 gpiod_code_t* const gpiod = get_gpiod_functions();
133
134 if (gpiod == NULL)
135 {
136 return GATE_RESULT_NOTAVAILABLE;
137 }
138
139 if (!ptr_device_handle)
140 {
141 return GATE_RESULT_INVALIDARG;
142 }
143 else if (*ptr_device_handle)
144 {
145 gpiod_chip_t* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
146 gpiod->chip_close(ptr_chip);
147 *ptr_device_handle = NULL;
148 return GATE_RESULT_OK;
149 }
150 else
151 {
152 /* the device handle was already cleared, no action required */
153 return GATE_RESULT_OK_UNCHANGED;
154 }
155 }
156
157
158 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
159 {
160 gate_result_t ret;
161 struct gpiod_chip_info* ptr_info = NULL;
162
163 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
164 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
165
166 do
167 {
168 gate_size_t line_count = 0;
169 gate_size_t ndx;
170 gate_bool_t continue_loop = true;
171 gpiod_chip_t* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
172
173 ret = gate_gpiod_get_chip_infos(ptr_chip, NULL, NULL, &line_count);
174 GATE_BREAK_IF_FAILED(ret);
175
176 /* iterate available lines and notify usable ones: */
177 for (ndx = 0; continue_loop && (ndx != line_count); ++ndx)
178 {
179 bool is_used = false;
180 gate_string_t str_name = GATE_STRING_INIT_EMPTY;
181 ret = gate_gpiod_get_line_infos(ptr_chip, ndx, &str_name, NULL, NULL, &is_used);
182 if (GATE_FAILED(ret))
183 {
184 continue;
185 }
186 if (callback)
187 {
188 continue_loop = callback((gate_intptr_t)ndx, &str_name, is_used, param);
189 }
190 gate_string_release(&str_name);
191 }
192 /* success case */
193 ret = GATE_RESULT_OK;
194 } while (0);
195 return ret;
196 }
197
198 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
199 {
200 gate_result_t ret = GATE_RESULT_FAILED;
201 /*
202 struct gpiod_line_info* ptr_lineinfo = NULL;
203
204 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
205 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
206
207 do
208 {
209 struct gpiod_chip* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
210 enum gpiod_line_direction direction;
211
212 ptr_lineinfo = gpiod_chip_get_line_info(ptr_chip, line_address);
213 if (NULL == ptr_lineinfo)
214 {
215 ret = GATE_RESULT_FAILED;
216 break;
217 }
218
219 direction = gpiod_line_info_get_direction(ptr_lineinfo);
220
221 if (ptr_config != NULL)
222 {
223 switch(direction)
224 {
225 case GPIOD_LINE_DIRECTION_INPUT: *ptr_config = GATE_GPIODEVICE_LINE_CONFIG_INPUT; break;
226 case GPIOD_LINE_DIRECTION_OUTPUT: *ptr_config = GATE_GPIODEVICE_LINE_CONFIG_OUTPUT; break;
227 default: *ptr_config = 0; break;
228 }
229 }
230 ret = GATE_RESULT_OK;
231 } while (0);
232
233 if (ptr_lineinfo != NULL)
234 {
235 gpiod_line_info_free(ptr_lineinfo);
236 }
237 */
238 return ret;
239 }
240
241
242 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
243 {
244 gate_result_t ret = GATE_RESULT_FAILED;
245 /*
246 struct gpiod_line_settings* new_settings = NULL;
247 struct gpiod_line_config* new_config = NULL;
248 struct gpiod_line_request* new_request = NULL;
249
250 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
251 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
252
253 do
254 {
255 struct gpiod_chip* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
256 enum gpiod_line_direction new_direction = (config == GATE_GPIODEVICE_LINE_CONFIG_INPUT) ? GPIOD_LINE_DIRECTION_INPUT : GPIOD_LINE_DIRECTION_OUTPUT;
257 unsigned int target_line = (unsigned int)line_address;
258
259 new_settings = gpiod_line_settings_new();
260 if (!new_settings)
261 {
262 ret = GATE_RESULT_OUTOFMEMORY;
263 break;
264 }
265
266 new_config = gpiod_line_config_new();
267 if (!new_config)
268 {
269 ret = GATE_RESULT_OUTOFMEMORY;
270 break;
271 }
272
273 if (0 != gpiod_line_settings_set_direction(new_settings, new_direction))
274 {
275 ret = GATE_RESULT_FAILED;
276 break;
277 }
278
279 if (0 != gpiod_line_config_add_line_settings(new_config, &target_line, 1, new_settings))
280 {
281 ret = GATE_RESULT_FAILED;
282 break;
283 }
284
285 new_request = gpiod_chip_request_lines(ptr_chip, NULL, new_config);
286 if (NULL == new_request)
287 {
288 ret = GATE_RESULT_FAILED;
289 break;
290 }
291
292 if(0 != gpiod_line_request_reconfigure_lines(new_request, new_config))
293 {
294 ret = GATE_RESULT_EXECUTIONFAILED;
295 break;
296 }
297 ret = GATE_RESULT_OK;
298 } while (0);
299
300 if (new_request) gpiod_line_request_release(new_request);
301 if (new_config) gpiod_line_config_free(new_config);
302 if (new_settings) gpiod_line_settings_free(new_settings);
303 */
304 return ret;
305 }
306
307
308 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
309 {
310 gate_result_t ret;
311 gpiod_chip_t* ptr_chip;
312 int value = 0;
313
314 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
315 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
316
317 ptr_chip = (gpiod_chip_t*)*ptr_device_handle;
318 ret = gate_gpiod_read_line_value(ptr_chip, line_address, &value);
319 if (GATE_SUCCEEDED(ret))
320 {
321 if (ptr_value) *ptr_value = value;
322 }
323 return ret;
324 }
325
326
327 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
328 {
329 gate_result_t ret;
330 gpiod_chip_t* ptr_chip;
331
332 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
333 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
334
335 ptr_chip = (gpiod_chip_t*)*ptr_device_handle;
336 ret = gate_gpiod_write_line_value(ptr_chip, line_address, value);
337 return ret;
338 }
339
340 #endif /* GATE_IO_GPIODEVICE_GPIOD_IMPL */
341
342
343
344 #if defined(GATE_IO_GPIODEVICE_IOCTL_IMPL)
345
346 #include "gate/platforms.h"
347 #include <linux/gpio.h>
348 #include <fcntl.h>
349
350 /* #define LINUX_GPIO_V2_SUPPORT 1 */
351
352 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
353 {
354 gate_result_t ret;
355 gate_cstrbuffer_t buffer = GATE_INIT_EMPTY;
356
357 GATE_DEBUG_ASSERT(device_path != NULL);
358 do
359 {
360 int fd;
361 if (NULL == gate_cstrbuffer_create_string(&buffer, device_path, false))
362 {
363 ret = GATE_RESULT_OUTOFMEMORY;
364 break;
365 }
366
367 fd = gate_posix_open(gate_cstrbuffer_get(&buffer), O_RDWR, 0);
368 if (fd == -1)
369 {
370 ret = GATE_RESULT_NOTAVAILABLE;
371 break;
372 }
373
374 /* success case reached */
375 ret = GATE_RESULT_OK;
376 if (ptr_device_handle)
377 {
378 *ptr_device_handle = (gate_gpiodevice_t)(gate_intptr_t)fd;
379 }
380 else
381 {
382 gate_posix_close(fd);
383 }
384 } while (0);
385 gate_cstrbuffer_destroy(&buffer);
386 return ret;
387 }
388
389 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
390 {
391 if (!ptr_device_handle)
392 {
393 return GATE_RESULT_INVALIDARG;
394 }
395 else
396 {
397 const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
398 if (fd != -1)
399 {
400 gate_posix_close(fd);
401 *ptr_device_handle = (gate_gpiodevice_t)(gate_intptr_t)-1;
402 }
403 return GATE_RESULT_OK;
404 }
405 }
406
407 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
408 {
409 gate_result_t ret;
410
411 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
412 GATE_DEBUG_ASSERT(callback != NULL);
413
414 do
415 {
416 const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
417 struct gpiochip_info chip_info;
418 unsigned line;
419 gate_bool_t continue_listing = true;
420
421 gate_mem_clear(&chip_info, sizeof(chip_info));
422 if (gate_posix_ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip_info) < 0)
423 {
424 ret = GATE_RESULT_FAILED;
425 break;
426 }
427
428 ret = GATE_RESULT_OK;
429 for(line = 0; (line < chip_info.lines) && continue_listing; ++line)
430 {
431 gate_string_t description = GATE_STRING_INIT_EMPTY;
432 gate_bool_t is_line_used = false;
433
434 #if !defined(LINUX_GPIO_V2_SUPPORT)
435 /* GPIO v1 interface */
436 struct gpioline_info line_info;
437 gate_mem_clear(&line_info, sizeof(line_info));
438 line_info.line_offset = line;
439
440 if (gate_posix_ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line_info) < 0)
441 {
442 continue;
443 }
444 is_line_used = GATE_FLAG_ENABLED(line_info.flags, GPIOLINE_FLAG_KERNEL);
445 gate_string_create_static(&description, line_info.name);
446 #else
447 /* GPIO v2 interface */
448 struct gpio_v2_line_info line_info;
449 gate_mem_clear(&line_info, sizeof(line_info));
450 line_info.offset = line;
451
452 if (gate_posix_ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &line_info) < 0)
453 {
454 continue;
455 }
456 is_line_used = GATE_FLAG_ENABLED(line_info.flags, GPIO_V2_LINE_FLAG_USED);
457 gate_string_create_static(&description, line_info.name);
458 #endif /* LINUX_GPIO_V2_SUPPORT */
459
460 continue_listing = callback(
461 line,
462 &description,
463 is_line_used,
464 param);
465 gate_string_release(&description);
466 }
467
468 } while (0);
469
470 return ret;
471 }
472
473 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
474 {
475 gate_result_t ret;
476
477 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
478 GATE_DEBUG_ASSERT(ptr_config != NULL);
479
480 do
481 {
482 const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
483 gate_enumint_t config = 0;
484
485 #if !defined(LINUX_GPIO_V2_SUPPORT)
486 /* GPIO v1 interface */
487 struct gpioline_info line_info;
488 gate_mem_clear(&line_info, sizeof(line_info));
489 line_info.line_offset = (unsigned)line_address;
490 if (gate_posix_ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line_info) < 0)
491 {
492 ret = GATE_RESULT_FAILED;
493 break;
494 }
495
496 if (GATE_FLAG_ENABLED(line_info.flags, GPIOLINE_FLAG_IS_OUT))
497 {
498 config |= GATE_GPIODEVICE_LINE_CONFIG_OUTPUT;
499 }
500 else
501 {
502 config |= GATE_GPIODEVICE_LINE_CONFIG_INPUT;
503 }
504 #else
505 /* GPIO v2 interface */
506 struct gpio_v2_line_info line_info;
507 gate_mem_clear(&line_info, sizeof(line_info));
508 line_info.offset = (unsigned)line_address;
509 if (gate_posix_ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &line_info) < 0)
510 {
511 ret = GATE_RESULT_FAILED;
512 break;
513 }
514
515 if (GATE_FLAG_ENABLED(line_info.flags, GPIO_V2_LINE_FLAG_INPUT))
516 {
517 config |= GATE_GPIODEVICE_LINE_CONFIG_INPUT;
518 }
519 if (GATE_FLAG_ENABLED(line_info.flags, GPIO_V2_LINE_FLAG_OUTPUT))
520 {
521 config |= GATE_GPIODEVICE_LINE_CONFIG_OUTPUT;
522 }
523 #endif /* LINUX_GPIO_V2_SUPPORT */
524
525 *ptr_config = config;
526 ret = GATE_RESULT_OK;
527 } while (0);
528
529 return ret;
530 }
531
532 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
533 {
534 return GATE_RESULT_NOTIMPLEMENTED;
535 }
536
537 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
538 {
539 gate_result_t ret;
540
541 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
542 GATE_DEBUG_ASSERT(ptr_value != NULL);
543
544 do
545 {
546 const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
547
548 #if !defined(LINUX_GPIO_V2_SUPPORT)
549 /* GPIO v1 interface */
550 struct gpiohandle_request req;
551 gate_mem_clear(&req, sizeof(req));
552
553 req.lineoffsets[0] = (unsigned)line_address;
554 req.lines = 1;
555 req.flags = GPIOHANDLE_REQUEST_INPUT;
556
557 if (gate_posix_ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0)
558 {
559 ret = GATE_RESULT_FAILED;
560 break;
561 }
562
563 {
564 /* now we have an opened request-fd to read values */
565 struct gpiohandle_data data;
566 gate_mem_clear(&data, sizeof(data));
567 if (gate_posix_ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data) < 0)
568 {
569 ret = GATE_RESULT_FAILED;
570 }
571 else
572 {
573 *ptr_value = (gate_intptr_t)data.values[0];
574 ret = GATE_RESULT_OK;
575 }
576 }
577 gate_posix_close(req.fd);
578 #else
579 /* GPIO v2 interface */
580 struct gpio_v2_line_request req;
581 gate_mem_clear(&req, sizeof(req));
582
583 req.offsets[0] = (unsigned)line_address;
584 req.num_lines = 1;
585 req.config.flags = GPIO_V2_LINE_FLAG_INPUT;
586
587 if (gate_posix_ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req) < 0)
588 {
589 ret = GATE_RESULT_FAILED;
590 break;
591 }
592
593 {
594 /* now we have an opened request-fd to read values */
595 struct gpio_v2_line_values data;
596 data.mask = 1;
597 gate_mem_clear(&data, sizeof(data));
598 if (gate_posix_ioctl(req.fd, GPIO_V2_LINE_GET_VALUES_IOCTL, &data) < 0)
599 {
600 ret = GATE_RESULT_FAILED;
601 }
602 else
603 {
604 *ptr_value = (gate_intptr_t)data.bits;
605 ret = GATE_RESULT_OK;
606 }
607 }
608 gate_posix_close(req.fd);
609 #endif /* LINUX_GPIO_V2_SUPPORT */
610 } while (0);
611
612 return ret;
613 }
614
615 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
616 {
617 gate_result_t ret;
618
619 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
620
621 do
622 {
623 const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
624
625 #if !defined(LINUX_GPIO_V2_SUPPORT)
626 /* GPIO v1 interface */
627 struct gpiohandle_request req;
628 gate_mem_clear(&req, sizeof(req));
629
630 req.lineoffsets[0] = (unsigned)line_address;
631 req.lines = 1;
632 req.flags = GPIOHANDLE_REQUEST_OUTPUT;
633 req.default_values[0] = (value == 0) ? 0 : 1;
634
635 if (gate_posix_ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0)
636 {
637 ret = GATE_RESULT_FAILED;
638 break;
639 }
640
641 {
642 /* now we have an opened request-fd to write values */
643 struct gpiohandle_data data;
644 gate_mem_clear(&data, sizeof(data));
645 data.values[0] = (value == 0) ? 0 : 1;
646 if (gate_posix_ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data) < 0)
647 {
648 ret = GATE_RESULT_FAILED;
649 }
650 else
651 {
652 ret = GATE_RESULT_OK;
653 }
654 }
655 gate_posix_close(req.fd);
656 #else
657 /* GPIO v2 interface */
658 struct gpio_v2_line_request req;
659 gate_mem_clear(&req, sizeof(req));
660
661 req.offsets[0] = (unsigned)line_address;
662 req.num_lines = 1;
663 req.config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
664
665 if (gate_posix_ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req) < 0)
666 {
667 ret = GATE_RESULT_FAILED;
668 break;
669 }
670
671 {
672 /* now we have an opened request-fd to write values */
673 struct gpio_v2_line_values data;
674 gate_mem_clear(&data, sizeof(data));
675 data.bits = (value == 0) ? 0 : 1;
676 data.mask = 1;
677 if (gate_posix_ioctl(req.fd, GPIO_V2_LINE_SET_VALUES_IOCTL, &data) < 0)
678 {
679 ret = GATE_RESULT_FAILED;
680 }
681 else
682 {
683 ret = GATE_RESULT_OK;
684 }
685 }
686 gate_posix_close(req.fd);
687 #endif /* LINUX_GPIO_V2_SUPPORT */
688
689 } while (0);
690
691 return ret;
692 }
693
694 #endif /* GATE_IO_GPIODEVICE_IOCTL_IMPL */
695
696
697
698 #if defined(GATE_IO_GPIODEVICE_ARDUINO_IMPL)
699
700 #include "gate/platform/arduino/arduino_gate.h"
701
702 static gate_gpiodevice_t const invalid_handle = (gate_gpiodevice_t)0x00;
703 static gate_gpiodevice_t const default_handle = (gate_gpiodevice_t)0x01;
704
705 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
706 {
707 gate_string_create_empty(device_path);
708 return GATE_RESULT_OK;
709 }
710
711 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
712 {
713 if (ptr_device_handle)
714 {
715 *ptr_device_handle = default_handle;
716 }
717 return GATE_RESULT_OK;
718 }
719
720 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
721 {
722 if (ptr_device_handle)
723 {
724 *ptr_device_handle = invalid_handle;
725 }
726 return GATE_RESULT_OK;
727 }
728
729 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
730 {
731 if (*ptr_device_handle != default_handle)
732 {
733 return GATE_RESULT_INVALIDARG;
734 }
735 else if (callback != NULL)
736 {
737 gate_result_t ret = GATE_RESULT_FAILED;
738 gate_size_t pin_count = gate_arduino_pin_count();
739 gate_size_t ndx;
740 gate_bool_t continue_loop = true;
741 static gate_string_t const descr = GATE_STRING_INIT_STATIC("Digital pin");
742 for (ndx = 0; (ndx != pin_count) && continue_loop; ++ndx)
743 {
744 if (callback)
745 {
746 const gate_intptr_t line = (gate_intptr_t)ndx;
747 continue_loop = callback(line, &descr, false, param);
748 }
749 }
750 }
751 return GATE_RESULT_OK;
752 }
753
754 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
755 {
756 if (*ptr_device_handle != default_handle)
757 {
758 return GATE_RESULT_INVALIDARG;
759 }
760 return GATE_RESULT_NOTIMPLEMENTED;
761 }
762
763 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
764 {
765 if (*ptr_device_handle != default_handle)
766 {
767 return GATE_RESULT_INVALIDARG;
768 }
769 else
770 {
771 gate_uint8_t const pin_num = (gate_uint8_t)line_address;
772 gate_arduino_pin_mode_t mode;
773 switch(config)
774 {
775 case GATE_GPIODEVICE_LINE_CONFIG_INPUT: mode = gate_arduino_pin_mode_input; break;
776 case GATE_GPIODEVICE_LINE_CONFIG_OUTPUT: mode = gate_arduino_pin_mode_output; break;
777 default: return GATE_RESULT_INVALIDARG;
778 }
779 gate_arduino_pin_init(pin_num, mode);
780 return GATE_RESULT_OK;
781 }
782 }
783
784 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
785 {
786 if (*ptr_device_handle != default_handle)
787 {
788 return GATE_RESULT_INVALIDARG;
789 }
790 else
791 {
792 gate_uint8_t const pin_num = (gate_uint8_t)line_address;
793 if (ptr_value)
794 {
795 *ptr_value = gate_arduino_pin_get_value(pin_num);
796 }
797 return GATE_RESULT_OK;
798 }
799 }
800
801 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
802 {
803 if (*ptr_device_handle != default_handle)
804 {
805 return GATE_RESULT_INVALIDARG;
806 }
807 else
808 {
809 gate_uint8_t const pin_num = (gate_uint8_t)line_address;
810 gate_arduino_pin_set_high(pin_num, value != 0);
811 //gate_arduino_pin_set_value(pin_num, (int)value);
812 return GATE_RESULT_OK;
813 }
814 }
815
816 #endif /* GATE_IO_GPIODEVICE_ARDUINO_IMPL */
817
818
819
820 #if defined(GATE_IO_GPIODEVICE_NO_IMPL)
821
822 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
823 {
824 GATE_UNUSED_ARG(device_path);
825 return GATE_RESULT_NOTIMPLEMENTED;
826 }
827
828 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
829 {
830 GATE_UNUSED_ARG(device_path);
831 GATE_UNUSED_ARG(flags);
832 GATE_UNUSED_ARG(ptr_device_handle);
833 return GATE_RESULT_NOTIMPLEMENTED;
834 }
835
836 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
837 {
838 GATE_UNUSED_ARG(ptr_device_handle);
839 return GATE_RESULT_NOTIMPLEMENTED;
840 }
841
842 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
843 {
844 GATE_UNUSED_ARG(ptr_device_handle);
845 GATE_UNUSED_ARG(callback);
846 GATE_UNUSED_ARG(param);
847 return GATE_RESULT_NOTIMPLEMENTED;
848 }
849
850 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
851 {
852 GATE_UNUSED_ARG(ptr_device_handle);
853 GATE_UNUSED_ARG(line_address);
854 GATE_UNUSED_ARG(ptr_config);
855 return GATE_RESULT_NOTIMPLEMENTED;
856 }
857
858 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
859 {
860 GATE_UNUSED_ARG(ptr_device_handle);
861 GATE_UNUSED_ARG(line_address);
862 GATE_UNUSED_ARG(config);
863 return GATE_RESULT_NOTIMPLEMENTED;
864 }
865
866 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
867 {
868 GATE_UNUSED_ARG(ptr_device_handle);
869 GATE_UNUSED_ARG(line_address);
870 GATE_UNUSED_ARG(ptr_value);
871 return GATE_RESULT_NOTIMPLEMENTED;
872 }
873
874 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
875 {
876 GATE_UNUSED_ARG(ptr_device_handle);
877 GATE_UNUSED_ARG(line_address);
878 GATE_UNUSED_ARG(value);
879 return GATE_RESULT_NOTIMPLEMENTED;
880 }
881
882 #endif /* GATE_IO_GPIODEVICE_NO_IMPL */
883
884
885
886 #if defined(GATE_IO_I2CDEVICE_IOCTL_IMPL)
887
888 #include "gate/environments.h"
889 #include "gate/platforms.h"
890 #include "gate/files.h"
891 #include <linux/i2c-dev.h>
892 #include <fcntl.h>
893
894 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
895 {
896 static gate_string_t const envname = GATE_STRING_INIT_STATIC("GATE_I2C_DEVICE_PATH");
897 gate_result_t result;
898
899 GATE_DEBUG_ASSERT(device_path != NULL);
900
901 result = gate_env_get_var(&envname, device_path);
902 if (GATE_FAILED(result) || gate_string_is_empty(device_path))
903 {
904 static gate_string_t const default_devpath = GATE_STRING_INIT_STATIC("/dev/i2c-1");
905 result = gate_file_exists(&default_devpath);
906 if (GATE_SUCCEEDED(result))
907 {
908 gate_string_duplicate(device_path, &default_devpath);
909 }
910 }
911 return result;
912 }
913
914
915 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
916 {
917 gate_result_t ret;
918 gate_cstrbuffer_t buffer = GATE_INIT_EMPTY;
919
920 GATE_DEBUG_ASSERT(device_path != NULL);
921 do
922 {
923 int fd;
924 if (NULL == gate_cstrbuffer_create_string(&buffer, device_path, false))
925 {
926 ret = GATE_RESULT_OUTOFMEMORY;
927 break;
928 }
929
930 fd = gate_posix_open(gate_cstrbuffer_get(&buffer), O_RDWR, 0);
931 if (fd == -1)
932 {
933 ret = GATE_RESULT_NOTAVAILABLE;
934 break;
935 }
936
937 /* success case reached */
938 ret = GATE_RESULT_OK;
939 if (ptr_device_handle)
940 {
941 *ptr_device_handle = (gate_i2cdevice_t)(gate_intptr_t)fd;
942 }
943 else
944 {
945 gate_posix_close(fd);
946 }
947 } while (0);
948 gate_cstrbuffer_destroy(&buffer);
949 return ret;
950 }
951
952 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
953 {
954 if (!ptr_device_handle)
955 {
956 return GATE_RESULT_INVALIDARG;
957 }
958 else
959 {
960 int fd = (int)(gate_intptr_t)(*ptr_device_handle);
961 if (fd != -1)
962 {
963 gate_posix_close(fd);
964 *ptr_device_handle = (gate_i2cdevice_t)(gate_intptr_t)-1;
965 }
966 return GATE_RESULT_OK;
967 }
968 }
969
970 static gate_result_t fd_i2c_select_slave(int fd, int slave_address)
971 {
972 int result = gate_posix_ioctl(fd, I2C_SLAVE, (void*)(gate_intptr_t)slave_address);
973 return result < 0 ? GATE_RESULT_FAILED : GATE_RESULT_OK;
974 }
975
976 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
977 void const* const* content_blocks, gate_size_t const* content_blocks_lengths, gate_size_t count,
978 gate_size_t* bytes_sent)
979 {
980 gate_result_t ret;
981
982 do
983 {
984 int fd;
985 ptrdiff_t write_result;
986 gate_size_t bytes_total = 0;
987 if (!ptr_device_handle)
988 {
989 ret = GATE_RESULT_INVALIDARG;
990 break;
991 }
992
993 fd = (int)(gate_intptr_t)(*ptr_device_handle);
994 ret = fd_i2c_select_slave(fd, (int)i2c_address);
995 GATE_BREAK_IF_FAILED(ret);
996
997 if (count == 1)
998 {
999 bytes_total = content_blocks_lengths[0];
1000 write_result = gate_posix_write(fd, content_blocks[0], bytes_total);
1001 }
1002 else
1003 {
1004 char buffer[GATE_MAX_STACK_COPYBUFFER_LENGTH];
1005 gate_size_t avail = sizeof(buffer);
1006 gate_size_t ndx;
1007 ptrdiff_t result;
1008
1009 bytes_total = 0;
1010 for (ndx = 0; ndx != count; ++ndx)
1011 {
1012 void const* const block = content_blocks[ndx];
1013 gate_size_t blocklen = content_blocks_lengths[ndx];
1014 if (blocklen > avail)
1015 {
1016 ret = GATE_RESULT_OVERFLOW;
1017 break;
1018 }
1019 gate_mem_copy(&buffer[bytes_total], block, blocklen);
1020 bytes_total += blocklen;
1021 avail -= blocklen;
1022 }
1023 GATE_BREAK_IF_FAILED(ret);
1024
1025 write_result = gate_posix_write(fd, buffer, bytes_total);
1026 }
1027
1028 if (write_result != (ptrdiff_t)bytes_total)
1029 {
1030 ret = GATE_RESULT_FAILED;
1031 break;
1032 }
1033
1034 ret = GATE_RESULT_OK;
1035 if (bytes_sent)
1036 {
1037 *bytes_sent = bytes_total;
1038 }
1039 } while (0);
1040
1041 return ret;
1042 }
1043
1044 gate_result_t gate_i2cdevice_receive(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
1045 void* content, gate_size_t content_length, gate_size_t* bytes_received)
1046 {
1047 gate_result_t ret;
1048
1049 do
1050 {
1051 int fd;
1052 ptrdiff_t read_result;
1053
1054 if (!ptr_device_handle)
1055 {
1056 ret = GATE_RESULT_INVALIDARG;
1057 break;
1058 }
1059
1060 fd = (int)(gate_intptr_t)(*ptr_device_handle);
1061 ret = fd_i2c_select_slave(fd, (int)i2c_address);
1062 GATE_BREAK_IF_FAILED(ret);
1063
1064 read_result = gate_posix_read(fd, content, content_length);
1065
1066 ret = (read_result == (ptrdiff_t)content_length)
1067 ? GATE_RESULT_OK
1068 : GATE_RESULT_FAILED;
1069
1070 if (bytes_received)
1071 {
1072 *bytes_received = (gate_size_t)read_result;
1073 }
1074 } while (0);
1075
1076 return ret;
1077 }
1078
1079 #endif /* GATE_IO_I2CDEVICE_IOCTL_IMPL */
1080
1081
1082
1083
1084 #if defined(GATE_IO_I2CDEVICE_WIRE_IMPL)
1085
1086 #include "carduino.h"
1087
1088 static gate_i2cdevice_t invalid_i2cdevice = (gate_i2cdevice_t)0x00;
1089 static gate_i2cdevice_t default_i2cdevice = (gate_i2cdevice_t)0x02;
1090
1091 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
1092 {
1093 gate_string_create_empty(device_path);
1094 return GATE_RESULT_OK;
1095 }
1096
1097 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
1098 {
1099 carduino_i2c_master_init(0, true);
1100 *ptr_device_handle = default_i2cdevice;
1101 return GATE_RESULT_OK;
1102 }
1103
1104 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
1105 {
1106 *ptr_device_handle = invalid_i2cdevice;
1107 return GATE_RESULT_OK;
1108 }
1109
1110 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
1111 void const* const* content_blocks, gate_size_t const* content_blocks_lengths, gate_size_t count,
1112 gate_size_t* bytes_sent)
1113 {
1114 if(!ptr_device_handle || (*ptr_device_handle != default_i2cdevice))
1115 {
1116 return GATE_RESULT_INVALIDARG;
1117 }
1118 else
1119 {
1120 unsigned const sent = carduino_i2c_master_send_blocks((unsigned char)i2c_address,
1121 (char const* const*)content_blocks, content_blocks_lengths, count);
1122 *bytes_sent = sent;
1123 return GATE_RESULT_OK;
1124 }
1125 }
1126
1127 gate_result_t gate_i2cdevice_receive(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
1128 void* content, gate_size_t content_length, gate_size_t* bytes_received)
1129 {
1130 if(!ptr_device_handle || (*ptr_device_handle != default_i2cdevice))
1131 {
1132 return GATE_RESULT_INVALIDARG;
1133 }
1134 else
1135 {
1136 int received = carduino_i2c_master_request(i2c_address, (char*)content, (int)content_length);
1137 if (bytes_received)
1138 {
1139 *bytes_received = (gate_size_t)received;
1140 }
1141 return GATE_RESULT_OK;
1142 }
1143 }
1144
1145 #endif /* GATE_IO_I2CDEVICE_WIRE_IMPL */
1146
1147
1148
1149 #if defined(GATE_IO_I2CDEVICE_FTD2XX_IMPL)
1150
1151 #include "gate/io/platform/gpiodevice_ftd2xx.h"
1152
1153 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
1154 {
1155 static gate_string_t const default_path = GATE_STRING_INIT_STATIC("");
1156 gate_string_duplicate(device_path, &default_path);
1157 return GATE_RESULT_OK;
1158 }
1159
1160 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
1161 {
1162 FT_functions_t const* const code = load_ftd2xx_functions();
1163
1164 GATE_UNUSED_ARG(device_path);
1165 GATE_UNUSED_ARG(flags);
1166
1167 if (!code)
1168 {
1169 /* error: no lib */
1170 return GATE_RESULT_NOTSUPPORTED;
1171 }
1172 else
1173 {
1174 FT_HANDLE ft_handle = NULL;
1175 FT_DEVICE ft_device = 0;
1176 gate_result_t result = ft_open_channel(code, 0, &ft_handle);
1177 if (GATE_SUCCEEDED(result))
1178 {
1179 I2C_CLOCKRATE rate = I2C_CLOCK_FAST_MODE;
1180 gate_uint32_t latencyTimer = 8; /* 8=fast, 255=slow */
1181 gate_uint32_t configOptions = 0;
1182 gate_uint32_t pin = 0;
1183
1184 do
1185 {
1186 result = ft_init_channel(code, ft_handle, &ft_device, rate, latencyTimer, configOptions, pin);
1187 GATE_BREAK_IF_FAILED(result);
1188
1189 result = i2c_finish_init_channel(code, ft_handle, ft_device, configOptions, pin);
1190 GATE_BREAK_IF_FAILED(result);
1191
1192 if (!(configOptions & I2C_DISABLE_3PHASE_CLOCKING))
1193 {
1194 unsigned char data = MPSSE_CMD_ENABLE_3PHASE_CLOCKING;
1195 DWORD written = 0;
1196 FT_STATUS status = code->FT_Write(ft_handle, &data, 1, &written);
1197 if (status != FT_OK)
1198 {
1199 result = GATE_RESULT_FAILED;
1200 break;
1201 }
1202 }
1203
1204 /* initialization succeeded */
1205 if (ptr_device_handle)
1206 {
1207 *ptr_device_handle = (gate_i2cdevice_t)ft_handle;
1208 ft_handle = NULL;
1209 }
1210 } while (0);
1211
1212 if (ft_handle)
1213 {
1214 ft_close_channel(code, ft_handle);
1215 }
1216 }
1217 return result;
1218 }
1219 }
1220
1221 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
1222 {
1223 FT_functions_t const* const code = load_ftd2xx_functions();
1224 if (!code)
1225 {
1226 /* error: no lib */
1227 return GATE_RESULT_NOTSUPPORTED;
1228 }
1229 else
1230 {
1231 FT_HANDLE ft_handle = (FT_HANDLE)*ptr_device_handle;
1232 return ft_close_channel(code, ft_handle);
1233 }
1234 }
1235
1236 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
1237 void const* const* content_blocks, gate_size_t const* content_block_lengths, gate_size_t count, gate_size_t* bytes_sent)
1238 {
1239 FT_functions_t const* const code = load_ftd2xx_functions();
1240
1241 if (!code)
1242 {
1243 /* error: no lib */
1244 return GATE_RESULT_NOTSUPPORTED;
1245 }
1246 else
1247 {
1248 gate_result_t ret = GATE_RESULT_FAILED;
1249 FT_HANDLE ft_handle = (FT_HANDLE)*ptr_device_handle;
1250 unsigned char buffer[GATE_MAX_COPYBUFFER_LENGTH];
1251 unsigned char* ptr_buffer = &buffer[0];
1252 unsigned char* ptr;
1253 unsigned buffer_len = 0;
1254 unsigned ndx;
1255 static gate_uint32_t const write_options = I2C_TRANSFER_OPTIONS_START_BIT|I2C_TRANSFER_OPTIONS_STOP_BIT|I2C_TRANSFER_OPTIONS_FAST_TRANSFER_BYTES;
1256
1257 for (ndx = 0; ndx != count; ++ndx)
1258 {
1259 buffer_len += content_block_lengths[ndx];
1260 }
1261
1262 if (buffer_len > sizeof(buffer))
1263 {
1264 ptr_buffer = (unsigned char*)gate_mem_alloc(buffer_len);
1265 if (ptr_buffer == NULL)
1266 {
1267 return GATE_RESULT_OUTOFMEMORY;
1268 }
1269 }
1270 ptr = ptr_buffer;
1271 for (ndx = 0; ndx != count; ++ndx)
1272 {
1273 void const* const src = content_blocks[ndx];
1274 gate_size_t const len = content_block_lengths[ndx];
1275 gate_mem_copy(ptr, src, len);
1276 ptr += len;
1277 }
1278
1279 ret = i2c_write(code, ft_handle, i2c_address, ptr_buffer, buffer_len, write_options, bytes_sent);
1280 if (ptr_buffer != &buffer[0])
1281 {
1282 gate_mem_dealloc(ptr_buffer);
1283 }
1284 return ret;
1285 }
1286 }
1287
1288 gate_result_t gate_i2cdevice_receive(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address, void* content, gate_size_t content_length, gate_size_t* bytes_received)
1289 {
1290 FT_functions_t const* const code = load_ftd2xx_functions();
1291
1292 if (!code)
1293 {
1294 /* error: no lib */
1295 return GATE_RESULT_NOTSUPPORTED;
1296 }
1297 else
1298 {
1299 FT_HANDLE ft_handle = (FT_HANDLE)*ptr_device_handle;
1300 gate_uint32_t read_options = I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT | I2C_TRANSFER_OPTIONS_FAST_TRANSFER_BYTES;
1301 return i2c_read(code, ft_handle, i2c_address, content, content_length, read_options, bytes_received);
1302 }
1303 }
1304
1305 #endif /* GATE_IO_I2CDEVICE_FTD2XX_IMPL */
1306
1307
1308
1309
1310
1311 #if defined(GATE_IO_I2CDEVICE_NO_IMPL)
1312
1313 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
1314 {
1315 GATE_UNUSED_ARG(device_path);
1316 return GATE_RESULT_NOTIMPLEMENTED;
1317 }
1318
1319
1320 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
1321 {
1322 GATE_UNUSED_ARG(device_path);
1323 GATE_UNUSED_ARG(flags);
1324 GATE_UNUSED_ARG(ptr_device_handle);
1325 return GATE_RESULT_NOTIMPLEMENTED;
1326 }
1327
1328 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
1329 {
1330 GATE_UNUSED_ARG(ptr_device_handle);
1331 return GATE_RESULT_NOTIMPLEMENTED;
1332 }
1333
1334 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
1335 void const* const* content_blocks, gate_size_t const* content_block_lengths, gate_size_t count, gate_size_t* bytes_sent)
1336 {
1337 GATE_UNUSED_ARG(ptr_device_handle);
1338 GATE_UNUSED_ARG(i2c_address);
1339 GATE_UNUSED_ARG(content_blocks);
1340 GATE_UNUSED_ARG(content_block_lengths);
1341 GATE_UNUSED_ARG(count);
1342 GATE_UNUSED_ARG(bytes_sent);
1343 return GATE_RESULT_NOTIMPLEMENTED;
1344 }
1345
1346 gate_result_t gate_i2cdevice_receive(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address, void* content, gate_size_t content_length, gate_size_t* bytes_received)
1347 {
1348 GATE_UNUSED_ARG(ptr_device_handle);
1349 GATE_UNUSED_ARG(i2c_address);
1350 GATE_UNUSED_ARG(content);
1351 GATE_UNUSED_ARG(content_length);
1352 GATE_UNUSED_ARG(bytes_received);
1353 return GATE_RESULT_NOTIMPLEMENTED;
1354 }
1355
1356 #endif /* GATE_IO_I2CDEVICE_NO_IMPL */
1357
1358
1359 #if defined(GATE_IO_SPIDEVICE_IOCTL_IMPL)
1360
1361 #include <stdio.h>
1362 #include <stdlib.h>
1363 #include <stdint.h>
1364 #include <fcntl.h>
1365 #include <unistd.h>
1366 #include <linux/spi/spidev.h>
1367 #include <sys/ioctl.h>
1368
1369 gate_result_t gate_spidevice_default_path(gate_string_t* device_path)
1370 {
1371 static gate_string_t const envname = GATE_STRING_INIT_STATIC("GATE_SPI_DEVICE_PATH");
1372 gate_result_t ret = gate_env_get_var(&envname, device_path);
1373 if (GATE_FAILED(ret) || gate_string_is_empty(device_path))
1374 {
1375 static gate_string_t const default_spi_path = GATE_STRING_INIT_STATIC("/dev/spidev0.0");
1376 gate_string_duplicate(device_path, &default_spi_path);
1377 ret = GATE_RESULT_OK;
1378 }
1379 return ret;
1380 }
1381
1382 gate_result_t gate_spidevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_spidevice_t* ptr_device_handle)
1383 {
1384 gate_result_t ret;
1385 gate_cstrbuffer_t buffer = GATE_INIT_EMPTY;
1386
1387 do
1388 {
1389 int fd;
1390 if (NULL == gate_cstrbuffer_create_string(&buffer, device_path, false))
1391 {
1392 ret = GATE_RESULT_OUTOFMEMORY;
1393 break;
1394 }
1395
1396 fd = gate_posix_open(gate_cstrbuffer_get(&buffer), O_RDWR, 0);
1397 if (fd == -1)
1398 {
1399 ret = GATE_RESULT_NOTAVAILABLE;
1400 break;
1401 }
1402
1403 /* success case reached */
1404 ret = GATE_RESULT_OK;
1405 if (ptr_device_handle)
1406 {
1407 *ptr_device_handle = (gate_spidevice_t)(gate_intptr_t)fd;
1408 }
1409 else
1410 {
1411 gate_posix_close(fd);
1412 }
1413 } while (0);
1414 gate_cstrbuffer_destroy(&buffer);
1415 return ret;
1416
1417 }
1418
1419 gate_result_t gate_spidevice_close(gate_spidevice_t* ptr_device_handle)
1420 {
1421 if (!ptr_device_handle)
1422 {
1423 return GATE_RESULT_INVALIDARG;
1424 }
1425 else
1426 {
1427 const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
1428 if (fd != -1)
1429 {
1430 gate_posix_close(fd);
1431 *ptr_device_handle = (gate_spidevice_t)(gate_intptr_t)-1;
1432 }
1433 return GATE_RESULT_OK;
1434 }
1435 }
1436
1437 static gate_uint8_t get_spi_mode(gate_enumint_t spi_mode)
1438 {
1439 switch(spi_mode)
1440 {
1441 default:
1442 case 0: return SPI_MODE_0;
1443 case 1: return SPI_MODE_1;
1444 case 2: return SPI_MODE_2;
1445 case 3: return SPI_MODE_3;
1446 }
1447 }
1448
1449 gate_result_t gate_spidevice_begin_transaction(gate_spidevice_t* ptr_device_handle, gate_uint64_t speed, gate_enumint_t spi_mode, gate_enumint_t spi_flags)
1450 {
1451 gate_result_t ret;
1452 if (ptr_device_handle == NULL)
1453 {
1454 return GATE_RESULT_INVALIDARG;
1455 }
1456
1457 do
1458 {
1459 const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
1460 uint8_t mode = get_spi_mode(spi_mode);
1461 uint8_t bits = 8;
1462
1463 /* set SPI mode */
1464 if (gate_posix_ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0)
1465 {
1466 ret = GATE_RESULT_FAILED;
1467 break;
1468 }
1469
1470 /* set bits per word */
1471 if (gate_posix_ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0)
1472 {
1473 ret = GATE_RESULT_FAILED;
1474 break;
1475 }
1476
1477 /* success state reached */
1478 ret = GATE_RESULT_OK;
1479 } while (0);
1480
1481 return ret;
1482 }
1483
1484 gate_result_t gate_spidevice_transfer(gate_spidevice_t* ptr_device_handle, void const* send_buffer, void* receive_buffer, gate_size_t buffer_length)
1485 {
1486 gate_result_t ret;
1487 if (ptr_device_handle == NULL)
1488 {
1489 return GATE_RESULT_INVALIDARG;
1490 }
1491
1492 do
1493 {
1494 const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
1495 struct spi_ioc_transfer message;
1496
1497 gate_mem_clear(&message, sizeof(message));
1498 message.tx_buf = (gate_uintptr_t)send_buffer;
1499 message.rx_buf = (gate_uintptr_t)receive_buffer;
1500 message.len = buffer_length;
1501 message.speed_hz = 0; /* override speed, 0: do not override */
1502 message.delay_usecs = 0;
1503 message.bits_per_word = 8; /* bits per word in general */
1504 message.cs_change = 0;
1505 message.tx_nbits = 8; /* bits per tx word */
1506 message.rx_nbits = 8; /* bits per rx word*/
1507
1508 if (gate_posix_ioctl(fd, SPI_IOC_MESSAGE(1), &message) < 0)
1509 {
1510 ret = GATE_RESULT_FAILED;
1511 break;
1512 }
1513
1514 /* success case reached */
1515 ret = GATE_RESULT_OK;
1516 } while (0);
1517
1518 return ret;
1519 }
1520
1521 gate_result_t gate_spidevice_end_transaction(gate_spidevice_t* ptr_device_handle)
1522 {
1523 if (ptr_device_handle == NULL)
1524 {
1525 return GATE_RESULT_INVALIDARG;
1526 }
1527 else
1528 {
1529 /* nothing to do */
1530 return GATE_RESULT_OK;
1531 }
1532 }
1533
1534 #endif /* GATE_IO_SPIDEVICE_IOCTL_IMPL */
1535
1536
1537
1538 #if defined(GATE_IO_SPIDEVICE_ARDUINO_IMPL)
1539
1540 #include "carduino.h"
1541
1542 static gate_spidevice_t invalid_spidevice = (gate_spidevice_t)0x00;
1543 static gate_spidevice_t default_spidevice = (gate_spidevice_t)0x02;
1544
1545 gate_result_t gate_spidevice_default_path(gate_string_t* device_path)
1546 {
1547 gate_string_create_empty(device_path);
1548 return GATE_RESULT_OK;
1549 }
1550
1551 gate_result_t gate_spidevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_spidevice_t* ptr_device_handle)
1552 {
1553 *ptr_device_handle = default_spidevice;
1554 return GATE_RESULT_OK;
1555 }
1556
1557 gate_result_t gate_spidevice_close(gate_spidevice_t* ptr_device_handle)
1558 {
1559 *ptr_device_handle = invalid_spidevice;
1560 return GATE_RESULT_OK;
1561 }
1562
1563 gate_result_t gate_spidevice_begin_transaction(gate_spidevice_t* ptr_device_handle, gate_uint64_t speed, gate_enumint_t spi_mode, gate_enumint_t spi_flags)
1564 {
1565 if ((ptr_device_handle == NULL) || (*ptr_device_handle == invalid_spidevice))
1566 {
1567 return GATE_RESULT_INVALIDARG;
1568 }
1569 else
1570 {
1571 carduino_spi_begin(
1572 speed,
1573 GATE_FLAG_ENABLED(spi_flags, GATE_SPIDEVICE_FLAG_LSB),
1574 spi_mode);
1575 return GATE_RESULT_OK;
1576 }
1577 }
1578
1579 gate_result_t gate_spidevice_transfer(gate_spidevice_t* ptr_device_handle, void const* send_buffer, void* receive_buffer, gate_size_t buffer_length)
1580 {
1581 if ((ptr_device_handle == NULL) || (*ptr_device_handle == invalid_spidevice))
1582 {
1583 return GATE_RESULT_INVALIDARG;
1584 }
1585 else
1586 {
1587 if (receive_buffer != send_buffer)
1588 {
1589 gate_mem_copy(receive_buffer, send_buffer, buffer_length);
1590 }
1591 carduino_spi_transfer_buffer((unsigned char*)receive_buffer, buffer_length);
1592 return GATE_RESULT_OK;
1593 }
1594 }
1595
1596 gate_result_t gate_spidevice_end_transaction(gate_spidevice_t* ptr_device_handle)
1597 {
1598 carduino_spi_end();
1599 return GATE_RESULT_OK;
1600 }
1601
1602 #endif /* GATE_IO_SPIDEVICE_ARDUINO_IMPL */
1603
1604
1605
1606 #if defined(GATE_IO_SPIDEVICE_NO_IMPL)
1607
1608 gate_result_t gate_spidevice_default_path(gate_string_t* device_path)
1609 {
1610 GATE_UNUSED_ARG(device_path);
1611 return GATE_RESULT_NOTIMPLEMENTED;
1612 }
1613
1614 gate_result_t gate_spidevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_spidevice_t* ptr_device_handle)
1615 {
1616 GATE_UNUSED_ARG(device_path);
1617 GATE_UNUSED_ARG(flags);
1618 GATE_UNUSED_ARG(ptr_device_handle);
1619 return GATE_RESULT_NOTIMPLEMENTED;
1620 }
1621
1622 gate_result_t gate_spidevice_close(gate_spidevice_t* ptr_device_handle)
1623 {
1624 GATE_UNUSED_ARG(ptr_device_handle);
1625 return GATE_RESULT_NOTIMPLEMENTED;
1626 }
1627
1628 gate_result_t gate_spidevice_begin_transaction(gate_spidevice_t* ptr_device_handle, gate_uint64_t speed, gate_enumint_t spi_mode, gate_enumint_t spi_flags)
1629 {
1630 GATE_UNUSED_ARG(ptr_device_handle);
1631 GATE_UNUSED_ARG(speed);
1632 GATE_UNUSED_ARG(spi_mode);
1633 GATE_UNUSED_ARG(spi_flags);
1634 return GATE_RESULT_NOTIMPLEMENTED;
1635 }
1636
1637 gate_result_t gate_spidevice_transfer(gate_spidevice_t* ptr_device_handle, void const* send_buffer, void* receive_buffer, gate_size_t buffer_length)
1638 {
1639 GATE_UNUSED_ARG(ptr_device_handle);
1640 GATE_UNUSED_ARG(send_buffer);
1641 GATE_UNUSED_ARG(receive_buffer);
1642 GATE_UNUSED_ARG(buffer_length);
1643 return GATE_RESULT_NOTIMPLEMENTED;
1644 }
1645
1646 gate_result_t gate_spidevice_end_transaction(gate_spidevice_t* ptr_device_handle)
1647 {
1648 GATE_UNUSED_ARG(ptr_device_handle);
1649 return GATE_RESULT_NOTIMPLEMENTED;
1650 }
1651
1652 #endif /* GATE_IO_SPIDEVICE_NO_IMPL */
1653