GCC Code Coverage Report


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