GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/gpiodevices.c
Date: 2026-08-06 22:46:24
Exec Total Coverage
Lines: 0 154 0.0%
Functions: 0 14 0.0%
Branches: 0 82 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 # define GATE_IO_GPIODEVICE_GPIOD_IMPL 1
35 # define GATE_IO_I2CDEVICE_IOCTL_IMPL 1
36 #elif defined(GATE_SYS_ARDUINO)
37 # define GATE_IO_GPIODEVICE_ARDUINO_IMPL 1
38 # define GATE_IO_I2CDEVICE_WIRE_IMPL 1
39 #elif defined(GATE_SYS_WIN) && !defined(GATE_SYS_WIN16)
40 # define GATE_IO_GPIODEVICE_NO_IMPL 1
41 # define GATE_IO_I2CDEVICE_FTD2XX_IMPL 1
42 #else
43 # define GATE_IO_GPIODEVICE_NO_IMPL 1
44 # define GATE_IO_I2CDEVICE_NO_IMPL 1
45 #endif
46
47
48
49
50
51 #if defined(GATE_IO_GPIODEVICE_GPIOD_IMPL)
52
53 #include "gate/debugging.h"
54 #include "gate/io/platform/gpiodevice_libgpiod.h"
55 #include "gate/environments.h"
56
57 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
58 {
59 static gate_string_t const envname = GATE_STRING_INIT_STATIC("GATE_GPIO_DEVICE_PATH");
60 gate_result_t ret = gate_env_get_var(&envname, device_path);
61 if (GATE_FAILED(ret))
62 {
63 gate_string_create_empty(device_path);
64 ret = GATE_RESULT_OK;
65 }
66 return ret;
67 }
68
69
70 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
71 {
72 gate_result_t ret;
73 gate_cstrbuffer_t pathbuffer = GATE_INIT_EMPTY;
74 gpiod_code_t* const gpiod = get_gpiod_functions();
75
76 if (gpiod == NULL)
77 {
78 return GATE_RESULT_NOTAVAILABLE;
79 }
80
81 do
82 {
83 gpiod_chip_t* ptr_chip;
84
85 if (NULL == gate_cstrbuffer_create_string(&pathbuffer, device_path, false))
86 {
87 ret = GATE_RESULT_OUTOFMEMORY;
88 break;
89 }
90
91 ptr_chip = gpiod->chip_open(gate_cstrbuffer_get(&pathbuffer));
92 if (!ptr_chip)
93 {
94 ret = GATE_RESULT_FAILED;
95 break;
96 }
97
98 /* success case: */
99 if (ptr_device_handle)
100 {
101 *ptr_device_handle = (gate_gpiodevice_t)ptr_chip;
102 }
103 else
104 {
105 gpiod->chip_close(ptr_chip);
106 }
107 ret = GATE_RESULT_OK;
108 } while (0);
109
110 gate_cstrbuffer_destroy(&pathbuffer);
111 return ret;
112 }
113
114
115 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
116 {
117 gpiod_code_t* const gpiod = get_gpiod_functions();
118
119 if (gpiod == NULL)
120 {
121 return GATE_RESULT_NOTAVAILABLE;
122 }
123
124 if (!ptr_device_handle)
125 {
126 return GATE_RESULT_INVALIDARG;
127 }
128 else if (*ptr_device_handle)
129 {
130 gpiod_chip_t* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
131 gpiod->chip_close(ptr_chip);
132 *ptr_device_handle = NULL;
133 return GATE_RESULT_OK;
134 }
135 else
136 {
137 /* the device handle was already cleared, no action required */
138 return GATE_RESULT_OK_UNCHANGED;
139 }
140 }
141
142
143 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
144 {
145 gate_result_t ret;
146 struct gpiod_chip_info* ptr_info = NULL;
147
148 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
149 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
150
151 do
152 {
153 gate_size_t line_count = 0;
154 gate_size_t ndx;
155 gate_bool_t continue_loop = true;
156 gpiod_chip_t* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
157
158 ret = gate_gpiod_get_chip_infos(ptr_chip, NULL, NULL, &line_count);
159 GATE_BREAK_IF_FAILED(ret);
160
161 /* iterate available lines and notify usable ones: */
162 for (ndx = 0; continue_loop && (ndx != line_count); ++ndx)
163 {
164 bool is_used = false;
165 gate_string_t str_name = GATE_STRING_INIT_EMPTY;
166 ret = gate_gpiod_get_line_infos(ptr_chip, ndx, &str_name, NULL, NULL, &is_used);
167 if (GATE_FAILED(ret))
168 {
169 continue;
170 }
171 if (callback)
172 {
173 continue_loop = callback((gate_intptr_t)ndx, &str_name, is_used, param);
174 }
175 gate_string_release(&str_name);
176 }
177 /* success case */
178 ret = GATE_RESULT_OK;
179 } while (0);
180 return ret;
181 }
182
183 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
184 {
185 gate_result_t ret = GATE_RESULT_FAILED;
186 /*
187 struct gpiod_line_info* ptr_lineinfo = NULL;
188
189 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
190 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
191
192 do
193 {
194 struct gpiod_chip* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
195 enum gpiod_line_direction direction;
196
197 ptr_lineinfo = gpiod_chip_get_line_info(ptr_chip, line_address);
198 if (NULL == ptr_lineinfo)
199 {
200 ret = GATE_RESULT_FAILED;
201 break;
202 }
203
204 direction = gpiod_line_info_get_direction(ptr_lineinfo);
205
206 if (ptr_config != NULL)
207 {
208 switch(direction)
209 {
210 case GPIOD_LINE_DIRECTION_INPUT: *ptr_config = GATE_GPIODEVICE_LINE_CONFIG_INPUT; break;
211 case GPIOD_LINE_DIRECTION_OUTPUT: *ptr_config = GATE_GPIODEVICE_LINE_CONFIG_OUTPUT; break;
212 default: *ptr_config = 0; break;
213 }
214 }
215 ret = GATE_RESULT_OK;
216 } while (0);
217
218 if (ptr_lineinfo != NULL)
219 {
220 gpiod_line_info_free(ptr_lineinfo);
221 }
222 */
223 return ret;
224 }
225
226
227 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
228 {
229 gate_result_t ret = GATE_RESULT_FAILED;
230 /*
231 struct gpiod_line_settings* new_settings = NULL;
232 struct gpiod_line_config* new_config = NULL;
233 struct gpiod_line_request* new_request = NULL;
234
235 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
236 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
237
238 do
239 {
240 struct gpiod_chip* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
241 enum gpiod_line_direction new_direction = (config == GATE_GPIODEVICE_LINE_CONFIG_INPUT) ? GPIOD_LINE_DIRECTION_INPUT : GPIOD_LINE_DIRECTION_OUTPUT;
242 unsigned int target_line = (unsigned int)line_address;
243
244 new_settings = gpiod_line_settings_new();
245 if (!new_settings)
246 {
247 ret = GATE_RESULT_OUTOFMEMORY;
248 break;
249 }
250
251 new_config = gpiod_line_config_new();
252 if (!new_config)
253 {
254 ret = GATE_RESULT_OUTOFMEMORY;
255 break;
256 }
257
258 if (0 != gpiod_line_settings_set_direction(new_settings, new_direction))
259 {
260 ret = GATE_RESULT_FAILED;
261 break;
262 }
263
264 if (0 != gpiod_line_config_add_line_settings(new_config, &target_line, 1, new_settings))
265 {
266 ret = GATE_RESULT_FAILED;
267 break;
268 }
269
270 new_request = gpiod_chip_request_lines(ptr_chip, NULL, new_config);
271 if (NULL == new_request)
272 {
273 ret = GATE_RESULT_FAILED;
274 break;
275 }
276
277 if(0 != gpiod_line_request_reconfigure_lines(new_request, new_config))
278 {
279 ret = GATE_RESULT_EXECUTIONFAILED;
280 break;
281 }
282 ret = GATE_RESULT_OK;
283 } while (0);
284
285 if (new_request) gpiod_line_request_release(new_request);
286 if (new_config) gpiod_line_config_free(new_config);
287 if (new_settings) gpiod_line_settings_free(new_settings);
288 */
289 return ret;
290 }
291
292
293 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
294 {
295 gate_result_t ret;
296 gpiod_chip_t* ptr_chip;
297 int value = 0;
298
299 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
300 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
301
302 ptr_chip = (gpiod_chip_t*)*ptr_device_handle;
303 ret = gate_gpiod_read_line_value(ptr_chip, line_address, &value);
304 if (GATE_SUCCEEDED(ret))
305 {
306 if (ptr_value) *ptr_value = value;
307 }
308 return ret;
309 }
310
311
312 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
313 {
314 gate_result_t ret;
315 gpiod_chip_t* ptr_chip;
316
317 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
318 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
319
320 ptr_chip = (gpiod_chip_t*)*ptr_device_handle;
321 ret = gate_gpiod_write_line_value(ptr_chip, line_address, value);
322 return ret;
323 }
324
325 #endif /* GATE_IO_GPIODEVICE_GPIOD_IMPL */
326
327
328
329 #if defined(GATE_IO_GPIODEVICE_ARDUINO_IMPL)
330
331 #include "gate/platform/arduino/arduino_gate.h"
332
333 static gate_gpiodevice_t const invalid_handle = (gate_gpiodevice_t)0x00;
334 static gate_gpiodevice_t const default_handle = (gate_gpiodevice_t)0x01;
335
336 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
337 {
338 gate_string_create_empty(device_path);
339 return GATE_RESULT_OK;
340 }
341
342 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
343 {
344 if (ptr_device_handle)
345 {
346 *ptr_device_handle = default_handle;
347 }
348 return GATE_RESULT_OK;
349 }
350
351 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
352 {
353 if (ptr_device_handle)
354 {
355 *ptr_device_handle = invalid_handle;
356 }
357 return GATE_RESULT_OK;
358 }
359
360 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
361 {
362 if (*ptr_device_handle != default_handle)
363 {
364 return GATE_RESULT_INVALIDARG;
365 }
366 else if (callback != NULL)
367 {
368 gate_result_t ret = GATE_RESULT_FAILED;
369 gate_size_t pin_count = gate_arduino_pin_count();
370 gate_size_t ndx;
371 gate_bool_t continue_loop = true;
372 static gate_string_t const descr = GATE_STRING_INIT_STATIC("Digital pin");
373 for (ndx = 0; (ndx != pin_count) && continue_loop; ++ndx)
374 {
375 if (callback)
376 {
377 gate_intptr_t line = (gate_intptr_t)ndx;
378
379 continue_loop = callback(line, &descr, false, param);
380 }
381 }
382 }
383 return GATE_RESULT_OK;
384 }
385
386 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
387 {
388 if (*ptr_device_handle != default_handle)
389 {
390 return GATE_RESULT_INVALIDARG;
391 }
392 return GATE_RESULT_NOTIMPLEMENTED;
393 }
394
395 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
396 {
397 if (*ptr_device_handle != default_handle)
398 {
399 return GATE_RESULT_INVALIDARG;
400 }
401 else
402 {
403 gate_uint8_t const pin_num = (gate_uint8_t)line_address;
404 gate_arduino_pin_mode_t mode;
405 switch(config)
406 {
407 case GATE_GPIODEVICE_LINE_CONFIG_INPUT: mode = gate_arduino_pin_mode_input; break;
408 case GATE_GPIODEVICE_LINE_CONFIG_OUTPUT: mode = gate_arduino_pin_mode_output; break;
409 default: return GATE_RESULT_INVALIDARG;
410 }
411 gate_arduino_pin_init(pin_num, mode);
412 return GATE_RESULT_OK;
413 }
414 }
415
416 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
417 {
418 if (*ptr_device_handle != default_handle)
419 {
420 return GATE_RESULT_INVALIDARG;
421 }
422 else
423 {
424 gate_uint8_t const pin_num = (gate_uint8_t)line_address;
425 if (ptr_value)
426 {
427 *ptr_value = gate_arduino_pin_get_value(pin_num);
428 }
429 return GATE_RESULT_OK;
430 }
431 }
432
433 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
434 {
435 if (*ptr_device_handle != default_handle)
436 {
437 return GATE_RESULT_INVALIDARG;
438 }
439 else
440 {
441 gate_uint8_t const pin_num = (gate_uint8_t)line_address;
442 gate_arduino_pin_set_high(pin_num, value != 0);
443 //gate_arduino_pin_set_value(pin_num, (int)value);
444 return GATE_RESULT_OK;
445 }
446 }
447
448 #endif /* GATE_IO_GPIODEVICE_ARDUINO_IMPL */
449
450
451
452 #if defined(GATE_IO_GPIODEVICE_NO_IMPL)
453
454 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
455 {
456 GATE_UNUSED_ARG(device_path);
457 return GATE_RESULT_NOTIMPLEMENTED;
458 }
459
460 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
461 {
462 GATE_UNUSED_ARG(device_path);
463 GATE_UNUSED_ARG(flags);
464 GATE_UNUSED_ARG(ptr_device_handle);
465 return GATE_RESULT_NOTIMPLEMENTED;
466 }
467
468 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
469 {
470 GATE_UNUSED_ARG(ptr_device_handle);
471 return GATE_RESULT_NOTIMPLEMENTED;
472 }
473
474 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
475 {
476 GATE_UNUSED_ARG(ptr_device_handle);
477 GATE_UNUSED_ARG(callback);
478 GATE_UNUSED_ARG(param);
479 return GATE_RESULT_NOTIMPLEMENTED;
480 }
481
482 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
483 {
484 GATE_UNUSED_ARG(ptr_device_handle);
485 GATE_UNUSED_ARG(line_address);
486 GATE_UNUSED_ARG(ptr_config);
487 return GATE_RESULT_NOTIMPLEMENTED;
488 }
489
490 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
491 {
492 GATE_UNUSED_ARG(ptr_device_handle);
493 GATE_UNUSED_ARG(line_address);
494 GATE_UNUSED_ARG(config);
495 return GATE_RESULT_NOTIMPLEMENTED;
496 }
497
498 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
499 {
500 GATE_UNUSED_ARG(ptr_device_handle);
501 GATE_UNUSED_ARG(line_address);
502 GATE_UNUSED_ARG(ptr_value);
503 return GATE_RESULT_NOTIMPLEMENTED;
504 }
505
506 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
507 {
508 GATE_UNUSED_ARG(ptr_device_handle);
509 GATE_UNUSED_ARG(line_address);
510 GATE_UNUSED_ARG(value);
511 return GATE_RESULT_NOTIMPLEMENTED;
512 }
513
514 #endif /* GATE_IO_GPIODEVICE_NO_IMPL */
515
516
517
518 #if defined(GATE_IO_I2CDEVICE_IOCTL_IMPL)
519
520 #include "gate/environments.h"
521 #include "gate/platforms.h"
522 #include "gate/files.h"
523 #include <linux/i2c-dev.h>
524 #include <fcntl.h>
525
526 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
527 {
528 static gate_string_t const envname = GATE_STRING_INIT_STATIC("GATE_I2C_DEVICE_PATH");
529 gate_result_t result = gate_env_get_var(&envname, device_path);
530 if (GATE_FAILED(result))
531 {
532 static gate_string_t const default_devpath = GATE_STRING_INIT_STATIC("/dev/i2c-1");
533 result = gate_file_exists(&default_devpath);
534 if (GATE_SUCCEEDED(result))
535 {
536 gate_string_duplicate(device_path, &default_devpath);
537 }
538 }
539 return result;
540 }
541
542
543 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
544 {
545 gate_result_t ret;
546 gate_cstrbuffer_t buffer = GATE_INIT_EMPTY;
547
548 do
549 {
550 int fd;
551 if (NULL == gate_cstrbuffer_create_string(&buffer, device_path, false))
552 {
553 ret = GATE_RESULT_OUTOFMEMORY;
554 break;
555 }
556
557 fd = gate_posix_open(gate_cstrbuffer_get(&buffer), O_RDWR, 0);
558 if (fd == -1)
559 {
560 ret = GATE_RESULT_NOTAVAILABLE;
561 break;
562 }
563
564 /* success case reached */
565 ret = GATE_RESULT_OK;
566 if (ptr_device_handle)
567 {
568 *ptr_device_handle = (gate_i2cdevice_t)(gate_intptr_t)fd;
569 }
570 else
571 {
572 gate_posix_close(fd);
573 }
574 } while (0);
575 gate_cstrbuffer_destroy(&buffer);
576 return ret;
577 }
578
579 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
580 {
581 if (!ptr_device_handle)
582 {
583 return GATE_RESULT_INVALIDARG;
584 }
585 else
586 {
587 int fd = (int)(gate_intptr_t)(*ptr_device_handle);
588 if (fd != -1)
589 {
590 gate_posix_close(fd);
591 *ptr_device_handle = (gate_i2cdevice_t)(gate_intptr_t)-1;
592 }
593 return GATE_RESULT_OK;
594 }
595 }
596
597 static gate_result_t fd_i2c_select_slave(int fd, int slave_address)
598 {
599 int result = gate_posix_ioctl(fd, I2C_SLAVE, (void*)(gate_intptr_t)slave_address);
600 return result < 0 ? GATE_RESULT_FAILED : GATE_RESULT_OK;
601 }
602
603 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
604 void const* const* content_blocks, gate_size_t const* content_blocks_lengths, gate_size_t count,
605 gate_size_t* bytes_sent)
606 {
607 gate_result_t ret;
608
609 do
610 {
611 int fd;
612 ptrdiff_t write_result;
613 gate_size_t bytes_total = 0;
614 if (!ptr_device_handle)
615 {
616 ret = GATE_RESULT_INVALIDARG;
617 break;
618 }
619
620 fd = (int)(gate_intptr_t)(*ptr_device_handle);
621 ret = fd_i2c_select_slave(fd, (int)i2c_address);
622 GATE_BREAK_IF_FAILED(ret);
623
624 if (count == 1)
625 {
626 bytes_total = content_blocks_lengths[0];
627 write_result = gate_posix_write(fd, content_blocks[0], bytes_total);
628 }
629 else
630 {
631 char buffer[GATE_MAX_STACK_COPYBUFFER_LENGTH];
632 gate_size_t avail = sizeof(buffer);
633 gate_size_t ndx;
634 ptrdiff_t result;
635
636 bytes_total = 0;
637 for (ndx = 0; ndx != count; ++ndx)
638 {
639 void const* const block = content_blocks[ndx];
640 gate_size_t blocklen = content_blocks_lengths[ndx];
641 if (blocklen > avail)
642 {
643 ret = GATE_RESULT_OVERFLOW;
644 break;
645 }
646 gate_mem_copy(&buffer[bytes_total], block, blocklen);
647 bytes_total += blocklen;
648 avail -= blocklen;
649 }
650 GATE_BREAK_IF_FAILED(ret);
651
652 write_result = gate_posix_write(fd, buffer, bytes_total);
653 }
654
655 if (write_result != (ptrdiff_t)bytes_total)
656 {
657 ret = GATE_RESULT_FAILED;
658 break;
659 }
660
661 ret = GATE_RESULT_OK;
662 if (bytes_sent)
663 {
664 *bytes_sent = bytes_total;
665 }
666 } while (0);
667
668 return ret;
669 }
670
671 gate_result_t gate_i2cdevice_receive(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
672 void* content, gate_size_t content_length, gate_size_t* bytes_received)
673 {
674 gate_result_t ret;
675
676 do
677 {
678 int fd;
679 ptrdiff_t read_result;
680
681 if (!ptr_device_handle)
682 {
683 ret = GATE_RESULT_INVALIDARG;
684 break;
685 }
686
687 fd = (int)(gate_intptr_t)(*ptr_device_handle);
688 ret = fd_i2c_select_slave(fd, (int)i2c_address);
689 GATE_BREAK_IF_FAILED(ret);
690
691 read_result = gate_posix_read(fd, content, content_length);
692
693 ret = (read_result == (ptrdiff_t)content_length)
694 ? GATE_RESULT_OK
695 : GATE_RESULT_FAILED;
696
697 if (bytes_received)
698 {
699 *bytes_received = (gate_size_t)read_result;
700 }
701 } while (0);
702
703 return ret;
704 }
705
706 #endif /* GATE_IO_I2CDEVICE_IOCTL_IMPL */
707
708
709
710
711 #if defined(GATE_IO_I2CDEVICE_WIRE_IMPL)
712
713 #include "carduino.h"
714
715 static gate_i2cdevice_t invalid_i2cdevice = (gate_i2cdevice_t)0x00;
716 static gate_i2cdevice_t default_i2cdevice = (gate_i2cdevice_t)0x02;
717
718 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
719 {
720 gate_string_create_empty(device_path);
721 return GATE_RESULT_OK;
722 }
723
724 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
725 {
726 carduino_i2c_master_init(0, true);
727 *ptr_device_handle = default_i2cdevice;
728 return GATE_RESULT_OK;
729 }
730
731 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
732 {
733 *ptr_device_handle = invalid_i2cdevice;
734 return GATE_RESULT_OK;
735 }
736
737 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
738 void const* const* content_blocks, gate_size_t const* content_blocks_lengths, gate_size_t count,
739 gate_size_t* bytes_sent)
740 {
741 if(!ptr_device_handle || (*ptr_device_handle != default_i2cdevice))
742 {
743 return GATE_RESULT_INVALIDARG;
744 }
745 else
746 {
747 unsigned const sent = carduino_i2c_master_send_blocks((unsigned char)i2c_address,
748 (char const* const*)content_blocks, content_blocks_lengths, count);
749 *bytes_sent = sent;
750 return GATE_RESULT_OK;
751 }
752 }
753
754 gate_result_t gate_i2cdevice_receive(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
755 void* content, gate_size_t content_length, gate_size_t* bytes_received)
756 {
757 if(!ptr_device_handle || (*ptr_device_handle != default_i2cdevice))
758 {
759 return GATE_RESULT_INVALIDARG;
760 }
761 else
762 {
763 int received = carduino_i2c_master_request(i2c_address, (char*)content, (int)content_length);
764 if (bytes_received)
765 {
766 *bytes_received = (gate_size_t)received;
767 }
768 return GATE_RESULT_OK;
769 }
770 }
771
772 #endif /* GATE_IO_I2CDEVICE_WIRE_IMPL */
773
774
775
776 #if defined(GATE_IO_I2CDEVICE_FTD2XX_IMPL)
777
778 #include "gate/io/platform/gpiodevice_ftd2xx.h"
779
780 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
781 {
782 static gate_string_t const default_path = GATE_STRING_INIT_STATIC("");
783 gate_string_duplicate(device_path, &default_path);
784 return GATE_RESULT_OK;
785 }
786
787 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
788 {
789 FT_functions_t const* const code = load_ftd2xx_functions();
790
791 GATE_UNUSED_ARG(device_path);
792 GATE_UNUSED_ARG(flags);
793
794 if (!code)
795 {
796 /* error: no lib */
797 return GATE_RESULT_NOTSUPPORTED;
798 }
799 else
800 {
801 FT_HANDLE ft_handle = NULL;
802 FT_DEVICE ft_device = 0;
803 gate_result_t result = ft_open_channel(code, 0, &ft_handle);
804 if (GATE_SUCCEEDED(result))
805 {
806 I2C_CLOCKRATE rate = I2C_CLOCK_FAST_MODE;
807 gate_uint32_t latencyTimer = 8; /* 8=fast, 255=slow */
808 gate_uint32_t configOptions = 0;
809 gate_uint32_t pin = 0;
810
811 do
812 {
813 result = ft_init_channel(code, ft_handle, &ft_device, rate, latencyTimer, configOptions, pin);
814 GATE_BREAK_IF_FAILED(result);
815
816 result = i2c_finish_init_channel(code, ft_handle, ft_device, configOptions, pin);
817 GATE_BREAK_IF_FAILED(result);
818
819 if (!(configOptions & I2C_DISABLE_3PHASE_CLOCKING))
820 {
821 unsigned char data = MPSSE_CMD_ENABLE_3PHASE_CLOCKING;
822 DWORD written = 0;
823 FT_STATUS status = code->FT_Write(ft_handle, &data, 1, &written);
824 if (status != FT_OK)
825 {
826 result = GATE_RESULT_FAILED;
827 break;
828 }
829 }
830
831 /* initialization succeeded */
832 if (ptr_device_handle)
833 {
834 *ptr_device_handle = (gate_i2cdevice_t)ft_handle;
835 ft_handle = NULL;
836 }
837 } while (0);
838
839 if (ft_handle)
840 {
841 ft_close_channel(code, ft_handle);
842 }
843 }
844 return result;
845 }
846 }
847
848 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
849 {
850 FT_functions_t const* const code = load_ftd2xx_functions();
851 if (!code)
852 {
853 /* error: no lib */
854 return GATE_RESULT_NOTSUPPORTED;
855 }
856 else
857 {
858 FT_HANDLE ft_handle = (FT_HANDLE)*ptr_device_handle;
859 return ft_close_channel(code, ft_handle);
860 }
861 }
862
863 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
864 void const* const* content_blocks, gate_size_t const* content_block_lengths, gate_size_t count, gate_size_t* bytes_sent)
865 {
866 FT_functions_t const* const code = load_ftd2xx_functions();
867
868 if (!code)
869 {
870 /* error: no lib */
871 return GATE_RESULT_NOTSUPPORTED;
872 }
873 else
874 {
875 gate_result_t ret = GATE_RESULT_FAILED;
876 FT_HANDLE ft_handle = (FT_HANDLE)*ptr_device_handle;
877 unsigned char buffer[GATE_MAX_COPYBUFFER_LENGTH];
878 unsigned char* ptr_buffer = &buffer[0];
879 unsigned char* ptr;
880 unsigned buffer_len = 0;
881 unsigned ndx;
882 static gate_uint32_t const write_options = I2C_TRANSFER_OPTIONS_START_BIT|I2C_TRANSFER_OPTIONS_STOP_BIT|I2C_TRANSFER_OPTIONS_FAST_TRANSFER_BYTES;
883
884 for (ndx = 0; ndx != count; ++ndx)
885 {
886 buffer_len += content_block_lengths[ndx];
887 }
888
889 if (buffer_len > sizeof(buffer))
890 {
891 ptr_buffer = (unsigned char*)gate_mem_alloc(buffer_len);
892 if (ptr_buffer == NULL)
893 {
894 return GATE_RESULT_OUTOFMEMORY;
895 }
896 }
897 ptr = ptr_buffer;
898 for (ndx = 0; ndx != count; ++ndx)
899 {
900 void const* const src = content_blocks[ndx];
901 gate_size_t const len = content_block_lengths[ndx];
902 gate_mem_copy(ptr, src, len);
903 ptr += len;
904 }
905
906 ret = i2c_write(code, ft_handle, i2c_address, ptr_buffer, buffer_len, write_options, bytes_sent);
907 if (ptr_buffer != &buffer[0])
908 {
909 gate_mem_dealloc(ptr_buffer);
910 }
911 return ret;
912 }
913 }
914
915 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)
916 {
917 FT_functions_t const* const code = load_ftd2xx_functions();
918
919 if (!code)
920 {
921 /* error: no lib */
922 return GATE_RESULT_NOTSUPPORTED;
923 }
924 else
925 {
926 FT_HANDLE ft_handle = (FT_HANDLE)*ptr_device_handle;
927 gate_uint32_t read_options = I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT | I2C_TRANSFER_OPTIONS_FAST_TRANSFER_BYTES;
928 return i2c_read(code, ft_handle, i2c_address, content, content_length, read_options, bytes_received);
929 }
930 }
931
932 #endif /* GATE_IO_I2CDEVICE_FTD2XX_IMPL */
933
934
935
936
937
938 #if defined(GATE_IO_I2CDEVICE_NO_IMPL)
939
940 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
941 {
942 GATE_UNUSED_ARG(device_path);
943 return GATE_RESULT_NOTIMPLEMENTED;
944 }
945
946
947 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
948 {
949 GATE_UNUSED_ARG(device_path);
950 GATE_UNUSED_ARG(flags);
951 GATE_UNUSED_ARG(ptr_device_handle);
952 return GATE_RESULT_NOTIMPLEMENTED;
953 }
954
955 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
956 {
957 GATE_UNUSED_ARG(ptr_device_handle);
958 return GATE_RESULT_NOTIMPLEMENTED;
959 }
960
961 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
962 void const* const* content_blocks, gate_size_t const* content_block_lengths, gate_size_t count, gate_size_t* bytes_sent)
963 {
964 GATE_UNUSED_ARG(ptr_device_handle);
965 GATE_UNUSED_ARG(i2c_address);
966 GATE_UNUSED_ARG(content_blocks);
967 GATE_UNUSED_ARG(content_block_lengths);
968 GATE_UNUSED_ARG(count);
969 GATE_UNUSED_ARG(bytes_sent);
970 return GATE_RESULT_NOTIMPLEMENTED;
971 }
972
973 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)
974 {
975 GATE_UNUSED_ARG(ptr_device_handle);
976 GATE_UNUSED_ARG(i2c_address);
977 GATE_UNUSED_ARG(content);
978 GATE_UNUSED_ARG(content_length);
979 GATE_UNUSED_ARG(bytes_received);
980 return GATE_RESULT_NOTIMPLEMENTED;
981 }
982
983 #endif /* GATE_IO_I2CDEVICE_NO_IMPL */
984