GCC Code Coverage Report


Directory: src/gate/
File: src/gate/io/gpiodevices.c
Date: 2026-10-19 17:06:30
Exec Total Coverage
Lines: 46 484 9.5%
Functions: 9 44 20.5%
Branches: 9 244 3.7%

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 #include "gate/debugging.h"
32 #include "gate/environments.h"
33 #include "gate/files.h"
34
35 #if defined(GATE_SYS_LINUX)
36 # if defined(HAVE_LINUX_GPIO_H)
37 # define GATE_IO_GPIODEVICE_IOCTL_IMPL 1
38 # else
39 # define GATE_IO_GPIODEVICE_SYSFS_IMPL 1
40 # endif
41 # define GATE_IO_PWMDEVICE_SYSFS_IMPL 1
42 # define GATE_IO_I2CDEVICE_IOCTL_IMPL 1
43 # define GATE_IO_SPIDEVICE_IOCTL_IMPL 1
44 #elif defined(GATE_SYS_ARDUINO)
45 # define GATE_IO_GPIODEVICE_ARDUINO_IMPL 1
46 # define GATE_IO_PWMDEVICE_NO_IMPL 1
47 # define GATE_IO_I2CDEVICE_WIRE_IMPL 1
48 # define GATE_IO_SPIDEVICE_ARDUINO_IMPL 1
49 #elif defined(GATE_SYS_WIN) && !defined(GATE_SYS_WIN16)
50 # define GATE_IO_GPIODEVICE_NO_IMPL 1
51 # define GATE_IO_PWMDEVICE_NO_IMPL 1
52 # define GATE_IO_I2CDEVICE_FTD2XX_IMPL 1
53 # define GATE_IO_SPIDEVICE_NO_IMPL 1
54 #else
55 # define GATE_IO_GPIODEVICE_NO_IMPL 1
56 # define GATE_IO_PWMDEVICE_NO_IMPL 1
57 # define GATE_IO_I2CDEVICE_NO_IMPL 1
58 # define GATE_IO_SPIDEVICE_NO_IMPL 1
59 #endif
60
61 4 static gate_result_t default_path_from_env_var_or_hardcoded(gate_string_t* device_path,
62 char const* env_var_name, char const* hardcoded_value)
63 {
64 4 gate_string_t const envname = GATE_STRING_INIT(env_var_name);
65 4 gate_result_t ret = gate_env_get_var(&envname, device_path);
66
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
4 if (GATE_FAILED(ret) || gate_string_is_empty(device_path))
67 {
68 4 gate_string_t const hardcoded_path = GATE_STRING_INIT(hardcoded_value);
69 4 ret = gate_file_exists(&hardcoded_path);
70
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (GATE_SUCCEEDED(ret))
71 {
72 ✗ gate_string_duplicate(device_path, &hardcoded_path);
73 }
74 }
75 4 return ret;
76 }
77
78 #if defined(GATE_SYS_POSIX)
79
80 #include "gate/platforms.h"
81 #include <fcntl.h>
82
83
84 ✗ static gate_result_t sysfs_write_to_file(gate_string_t const* path, char const* ptr_content, gate_size_t content_len)
85 {
86 gate_result_t ret;
87 ✗ gate_cstrbuffer_t pathbuffer = GATE_INIT_EMPTY;
88 gate_platform_stream_t stream;
89
90 do
91 {
92 ✗ gate_size_t len_written = 0;
93 ✗ gate_platform_stream_set_invalid(&stream);
94 ✗ if (NULL == gate_cstrbuffer_create_string(&pathbuffer, path, false))
95 {
96 ✗ ret = GATE_RESULT_OUTOFMEMORY;
97 ✗ break;
98 }
99 ✗ ret = gate_platform_stream_open(gate_cstrbuffer_get(&pathbuffer), GATE_PLATFORM_STREAM_OPEN_NATIVE, O_WRONLY, &stream);
100 ✗ GATE_BREAK_IF_FAILED(ret);
101
102 ✗ ret = gate_platform_stream_seek(stream, 0, GATE_PLATFORM_STREAM_ORIGIN_BEGIN, NULL);
103 ✗ GATE_BREAK_IF_FAILED(ret);
104
105 ✗ ret = gate_platform_stream_write(stream, ptr_content, content_len, &len_written);
106 ✗ GATE_BREAK_IF_FAILED(ret);
107
108 ✗ ret = GATE_RESULT_OK;
109 } while(0);
110
111 ✗ if (gate_platform_stream_valid(stream))
112 {
113 ✗ gate_platform_stream_close(&stream);
114 }
115
116 ✗ gate_cstrbuffer_destroy(&pathbuffer);
117 ✗ return ret;
118 }
119
120 ✗ static gate_result_t sysfs_write_int64_to_file(gate_string_t const* path, gate_int64_t value)
121 {
122 char buffer[32];
123 ✗ gate_size_t buffer_used = gate_str_print_int64(buffer, sizeof(buffer), value);
124 ✗ return sysfs_write_to_file(path, buffer, buffer_used);
125 }
126
127
128 ✗ static gate_result_t sysfs_read_from_file(gate_string_t const* path, char* buffer, gate_size_t buffer_len, gate_size_t* ptr_buffer_used)
129 {
130 gate_result_t ret;
131 ✗ gate_cstrbuffer_t pathbuffer = GATE_INIT_EMPTY;
132 gate_platform_stream_t stream;
133
134 do
135 {
136 ✗ gate_platform_stream_set_invalid(&stream);
137 ✗ if (NULL == gate_cstrbuffer_create_string(&pathbuffer, path, false))
138 {
139 ✗ ret = GATE_RESULT_OUTOFMEMORY;
140 ✗ break;
141 }
142 ✗ ret = gate_platform_stream_open(gate_cstrbuffer_get(&pathbuffer), GATE_PLATFORM_STREAM_OPEN_READ, 0, &stream);
143 ✗ GATE_BREAK_IF_FAILED(ret);
144
145 ✗ ret = gate_platform_stream_read(stream, buffer, buffer_len, ptr_buffer_used);
146 ✗ GATE_BREAK_IF_FAILED(ret);
147
148 } while(0);
149
150 ✗ if (gate_platform_stream_valid(stream))
151 {
152 ✗ gate_platform_stream_close(&stream);
153 }
154
155 ✗ gate_cstrbuffer_destroy(&pathbuffer);
156 ✗ return ret;
157 }
158
159 ✗ static gate_result_t sysfs_read_from_dir_file(gate_string_t const* dir, char const* filename, char* buffer, gate_size_t buffer_len, gate_size_t* ptr_buffer_used)
160 {
161 char pathbuffer[GATE_MAX_FILENAME_LENGTH];
162 ✗ gate_size_t pathbuffer_len = gate_file_build_path(pathbuffer, sizeof(pathbuffer), dir->str, dir->length, filename, gate_str_length(filename));
163 gate_string_t path;
164 ✗ gate_string_create_static_len(&path, pathbuffer, pathbuffer_len);
165 ✗ return sysfs_read_from_file(&path, buffer, buffer_len, ptr_buffer_used);
166 }
167
168 ✗ static gate_result_t sysfs_read_int64_from_file(gate_string_t const* path, gate_int64_t* ptr_value)
169 {
170 gate_result_t ret;
171 ✗ char value_buffer[32] = GATE_INIT_EMPTY;
172 ✗ gate_size_t value_len = 0;
173
174 ✗ ret = sysfs_read_from_file(path, value_buffer, sizeof(value_buffer), &value_len);
175 ✗ if (GATE_SUCCEEDED(ret) && (ptr_value != NULL))
176 {
177 ✗ gate_str_parse_int64(value_buffer, value_len, ptr_value);
178 }
179 ✗ return ret;
180 }
181
182
183 ✗ static gate_result_t sysfs_read_int_from_file(gate_string_t const* path, gate_int32_t* ptr_value)
184 {
185 ✗ gate_int64_t v = 0;
186 ✗ gate_result_t ret = sysfs_read_int64_from_file(path, &v);
187 ✗ if (GATE_SUCCEEDED(ret) && (ptr_value != NULL))
188 {
189 ✗ *ptr_value = (gate_int32_t)v;
190 }
191 ✗ return ret;
192 }
193
194 ✗ static gate_result_t sysfs_read_int64_from_dir_file(gate_string_t const* dir, char const* filename, gate_int64_t* ptr_value)
195 {
196 char buffer[32];
197 gate_size_t buffer_used;
198 ✗ gate_result_t ret = sysfs_read_from_dir_file(dir, filename, buffer, sizeof(buffer), &buffer_used);
199 ✗ if (GATE_SUCCEEDED(ret) && (ptr_value != NULL))
200 {
201 ✗ if (0 == gate_str_parse_int64(buffer, buffer_used, ptr_value))
202 {
203 ✗ *ptr_value = 0;
204 }
205 }
206 ✗ return ret;
207 }
208
209 #endif /* GATE_SYS_POSIX */
210
211
212 #if defined(GATE_IO_GPIODEVICE_GPIOD_IMPL) || defined(GATE_IO_GPIODEVICE_IOCTL_IMPL)
213
214 /* Linux GPIOD and IOCTL-GPIO implementation share the same default device path code */
215
216 #include "gate/environments.h"
217
218 1 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
219 {
220 1 return default_path_from_env_var_or_hardcoded(device_path, "GATE_GPIO_DEVICE_PATH", "/dev/gpiochip0");
221 }
222
223 #endif
224
225
226
227 #if defined(GATE_IO_GPIODEVICE_SYSFS_IMPL)
228
229 #include "gate/environments.h"
230 #include "gate/blobs.h"
231 #include "gate/threading.h"
232
233 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
234 {
235 return default_path_from_env_var_or_hardcoded(device_path, "GATE_GPIO_DEVICE_PATH", "/sys/class/gpio/gpiochip0");
236 }
237
238
239 static char const* sysfs_gpio_basepath = "/sys/class/gpio/gpio";
240
241 static gate_bool_t sysfs_gpio_is_exported(gate_intptr_t absolute_id)
242 {
243 gate_bool_t ret;
244 char path_buffer[128];
245 gate_string_t path = GATE_STRING_INIT_EMPTY;
246 gate_strbuilder_t sb = GATE_INIT_EMPTY;
247 gate_strbuilder_create_static(&sb, path_buffer, sizeof(path_buffer), 0);
248 gate_strbuilder_append_cstr(&sb, sysfs_gpio_basepath);
249 gate_strbuilder_append_int64(&sb, absolute_id);
250 gate_strbuilder_to_string(&sb, &path);
251 ret = (gate_file_dir_exists(&path) == GATE_RESULT_OK);
252 gate_string_release(&path);
253 gate_strbuilder_release(&sb);
254 return ret;
255 }
256
257 static gate_result_t sysfs_gpio_export(gate_intptr_t absolute_id)
258 {
259 static gate_string_t const sysfs_export_path = GATE_STRING_INIT_STATIC("/sys/class/gpio/export");
260 char id_buffer[32] = GATE_INIT_EMPTY;
261 const gate_size_t id_buffer_used = gate_str_print_int64(id_buffer, sizeof(id_buffer), absolute_id);
262 const gate_result_t ret = sysfs_write_to_file(&sysfs_export_path, id_buffer, id_buffer_used);
263 if (GATE_SUCCEEDED(ret))
264 {
265 int is_exported_retry_count = 5;
266 do
267 {
268 gate_thread_sleep(100);
269 } while(!sysfs_gpio_is_exported(absolute_id) && (is_exported_retry_count-- > 0));
270 }
271 return ret;
272 }
273
274 static gate_result_t sysfs_gpio_unexport(gate_intptr_t absolute_id)
275 {
276 static gate_string_t const sysfs_export_path = GATE_STRING_INIT_STATIC("/sys/class/gpio/unexport");
277 char id_buffer[32] = GATE_INIT_EMPTY;
278 const gate_size_t id_buffer_used = gate_str_print_int64(id_buffer, sizeof(id_buffer), absolute_id);
279 return sysfs_write_to_file(&sysfs_export_path, id_buffer, id_buffer_used);
280 }
281
282 static gate_result_t sysfs_gpio_set_direction(gate_intptr_t absolute_id, gate_bool_t output)
283 {
284 static gate_string_t const sysfs_gpio_direction_in = GATE_STRING_INIT_STATIC("in");
285 static gate_string_t const sysfs_gpio_direction_out = GATE_STRING_INIT_STATIC("out");
286 gate_string_t const* const ptr_content = output ? &sysfs_gpio_direction_out : &sysfs_gpio_direction_in;
287 gate_result_t ret;
288 char path_buffer[128];
289 gate_string_t path = GATE_STRING_INIT_EMPTY;
290 gate_strbuilder_t sb = GATE_INIT_EMPTY;
291 gate_strbuilder_create_static(&sb, path_buffer, sizeof(path_buffer), 0);
292 gate_strbuilder_append_cstr(&sb, sysfs_gpio_basepath);
293 gate_strbuilder_append_int64(&sb, absolute_id);
294 gate_strbuilder_append_cstr(&sb, "/direction");
295 gate_strbuilder_to_string(&sb, &path);
296 ret = sysfs_write_to_file(&path, ptr_content->str, ptr_content->length);
297 gate_string_release(&path);
298 gate_strbuilder_release(&sb);
299 return ret;
300 }
301
302 static gate_result_t sysfs_gpio_write(gate_intptr_t absolute_id, gate_int32_t value)
303 {
304 gate_result_t ret;
305 char path_buffer[128];
306 char value_buffer[32];
307 gate_size_t value_len = gate_str_print_int32(value_buffer, sizeof(value_buffer), value);
308 gate_string_t path = GATE_STRING_INIT_EMPTY;
309 gate_strbuilder_t sb = GATE_INIT_EMPTY;
310 gate_strbuilder_create_static(&sb, path_buffer, sizeof(path_buffer), 0);
311 gate_strbuilder_append_cstr(&sb, sysfs_gpio_basepath);
312 gate_strbuilder_append_int64(&sb, absolute_id);
313 gate_strbuilder_append_cstr(&sb, "/value");
314 gate_strbuilder_to_string(&sb, &path);
315 ret = sysfs_write_to_file(&path, value_buffer, value_len);
316 gate_string_release(&path);
317 return ret;
318 }
319
320 static gate_result_t sysfs_gpio_read(gate_intptr_t absolute_id, gate_int32_t* ptr_value)
321 {
322 static gate_string_t const sysfs_gpio_direction_in = GATE_STRING_INIT_STATIC("in");
323 static gate_string_t const sysfs_gpio_direction_out = GATE_STRING_INIT_STATIC("out");
324 gate_result_t ret;
325 char path_buffer[128];
326 gate_string_t path = GATE_STRING_INIT_EMPTY;
327 gate_strbuilder_t sb = GATE_INIT_EMPTY;
328 gate_strbuilder_create_static(&sb, path_buffer, sizeof(path_buffer), 0);
329 gate_strbuilder_append_cstr(&sb, sysfs_gpio_basepath);
330 gate_strbuilder_append_int64(&sb, absolute_id);
331 gate_strbuilder_append_cstr(&sb, "/value");
332 gate_strbuilder_to_string(&sb, &path);
333 ret = sysfs_read_int_from_file(&path, ptr_value);
334 gate_string_release(&path);
335 return ret;
336 }
337
338 struct gate_gpiodevice_native_type
339 {
340 char path[64]; /**< sysfs gpio device path /sys/class/gpio/gpiochipN */
341 gate_uint8_t opened_lines[128]; /**< each bit represents an opened line */
342 gate_size_t line_base; /**< global line export ID base */
343 gate_size_t line_count; /**< amount of lines handled by device */
344 };
345
346 static gate_bool_t gpio_is_line_opened(struct gate_gpiodevice_native_type* ptr, gate_size_t line_offset)
347 {
348 if ((line_offset < ptr->line_count) && (line_offset < sizeof(ptr->opened_lines) * 8))
349 {
350 return gate_bit_is_set(ptr->opened_lines, line_offset);
351 }
352 else
353 {
354 return false;
355 }
356 }
357
358 static void gpio_set_line_opened(struct gate_gpiodevice_native_type* ptr, gate_size_t line_offset, gate_bool_t is_opened)
359 {
360 if ((line_offset < ptr->line_count) && (line_offset < sizeof(ptr->opened_lines) * 8))
361 {
362 gate_bit_is_set(ptr->opened_lines, line_offset);
363 }
364 }
365
366 static gate_result_t read_int_from_dir_file(gate_string_t const* dirpath, gate_string_t const* filename, gate_int32_t* ptr_value)
367 {
368 char path_buffer[256] = GATE_INIT_EMPTY;
369 gate_string_t path = GATE_STRING_INIT_EMPTY;
370 gate_result_t ret;
371 const gate_size_t path_len = gate_file_build_path(
372 path_buffer, sizeof(path_buffer),
373 gate_string_ptr(dirpath, 0), gate_string_length(dirpath),
374 gate_string_ptr(filename, 0), gate_string_length(filename));
375 gate_string_create_static_len(&path, path_buffer, path_len);
376 return sysfs_read_int_from_file(&path, ptr_value);
377 }
378
379 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
380 {
381 static const gate_string_t name_base = GATE_STRING_INIT_STATIC("base");
382 static const gate_string_t name_ngpio = GATE_STRING_INIT_STATIC("ngpio");
383 gate_result_t ret;
384 struct gate_gpiodevice_native_type* ptr_handle = NULL;
385 do
386 {
387 gate_int32_t gpiodev_base = 0;
388 gate_int32_t gpiodev_ngpio = 0;
389
390 ret = gate_file_dir_exists(device_path);
391 GATE_BREAK_IF_FAILED(ret);
392
393 ret = read_int_from_dir_file(device_path, &name_base, &gpiodev_base);
394 GATE_BREAK_IF_FAILED(ret);
395
396 ret = read_int_from_dir_file(device_path, &name_ngpio, &gpiodev_ngpio);
397 GATE_BREAK_IF_FAILED(ret);
398
399 ptr_handle = (struct gate_gpiodevice_native_type*)gate_mem_alloc(sizeof(struct gate_gpiodevice_native_type));
400 if (ptr_handle == NULL)
401 {
402 ret = GATE_RESULT_OUTOFMEMORY;
403 break;
404 }
405
406 gate_mem_clear(ptr_handle, sizeof(struct gate_gpiodevice_native_type));
407 gate_string_to_buffer(device_path, ptr_handle->path, sizeof(ptr_handle->path));
408 ptr_handle->line_base = (gate_size_t)gpiodev_base;
409 ptr_handle->line_count = (gate_size_t)gpiodev_ngpio;
410
411 *ptr_device_handle = ptr_handle;
412 } while (0);
413
414 return ret;
415 }
416
417 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
418 {
419 if ((ptr_device_handle != NULL) && (*ptr_device_handle != NULL))
420 {
421 struct gate_gpiodevice_native_type* const ptr = *ptr_device_handle;
422 gate_size_t ndx;
423 for (ndx = 0; ndx != ptr->line_count; ++ndx)
424 {
425 if (gpio_is_line_opened(ptr, ndx))
426 {
427 sysfs_gpio_unexport(ptr->line_base + ndx);
428 gpio_set_line_opened(ptr, ndx, false);
429 }
430 }
431 gate_mem_dealloc(*ptr_device_handle);
432 *ptr_device_handle = NULL;
433 }
434 return GATE_RESULT_OK;
435 }
436
437 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
438 {
439 gate_result_t ret = GATE_RESULT_OK;
440 do
441 {
442 struct gate_gpiodevice_native_type* const ptr = *ptr_device_handle;
443 char descr[30] = "GPIO line \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
444 gate_size_t index;
445 for (index = 0; index != ptr->line_count; ++index)
446 {
447 gate_string_t str_descr;
448
449 gate_str_print_uint64(&descr[10], 5, index);
450 gate_string_create_static(&str_descr, descr);
451 if(false == callback((gate_intptr_t)index, &str_descr, false, param))
452 {
453 break;
454 }
455 }
456 } while (0);
457 return ret;
458 }
459
460 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
461 {
462 return GATE_RESULT_NOTIMPLEMENTED;
463 }
464
465 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
466 {
467 return GATE_RESULT_NOTIMPLEMENTED;
468 }
469
470 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
471 {
472 gate_result_t ret;
473 do
474 {
475 struct gate_gpiodevice_native_type* const ptr = *ptr_device_handle;
476 gate_int32_t value = 0;
477 const gate_intptr_t absolute_id = (gate_intptr_t)ptr->line_base + line_address;
478 if (!gpio_is_line_opened(ptr, (gate_size_t)line_address))
479 {
480 if (!sysfs_gpio_is_exported(absolute_id))
481 {
482 ret = sysfs_gpio_export(absolute_id);
483 GATE_BREAK_IF_FAILED(ret);
484 }
485 }
486 ret = sysfs_gpio_set_direction(absolute_id, false);
487 GATE_BREAK_IF_FAILED(ret);
488
489 ret = sysfs_gpio_read(absolute_id, &value);
490 } while (0);
491 return ret;
492 }
493
494 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
495 {
496 gate_result_t ret;
497 do
498 {
499 struct gate_gpiodevice_native_type* const ptr = *ptr_device_handle;
500 const gate_intptr_t absolute_id = (gate_intptr_t)ptr->line_base + line_address;
501 if (!gpio_is_line_opened(ptr, (gate_size_t)line_address))
502 {
503 if (!sysfs_gpio_is_exported(absolute_id))
504 {
505 ret = sysfs_gpio_export(absolute_id);
506 GATE_BREAK_IF_FAILED(ret);
507 }
508 }
509 ret = sysfs_gpio_set_direction(absolute_id, true);
510 GATE_BREAK_IF_FAILED(ret);
511
512 ret = sysfs_gpio_write(absolute_id, (gate_intptr_t)value);
513 } while (0);
514 return ret;
515 }
516
517 #endif /* GATE_IO_GPIODEVICE_SYSFS_IMPL */
518
519
520
521 #if defined(GATE_IO_GPIODEVICE_GPIOD_IMPL)
522
523 #include "gate/io/platform/gpiodevice_libgpiod.h"
524 #include "gate/environments.h"
525
526 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
527 {
528 gate_result_t ret;
529 gate_cstrbuffer_t pathbuffer = GATE_INIT_EMPTY;
530 gpiod_code_t* const gpiod = get_gpiod_functions();
531
532 if (gpiod == NULL)
533 {
534 return GATE_RESULT_NOTAVAILABLE;
535 }
536
537 do
538 {
539 gpiod_chip_t* ptr_chip;
540
541 if (NULL == gate_cstrbuffer_create_string(&pathbuffer, device_path, false))
542 {
543 ret = GATE_RESULT_OUTOFMEMORY;
544 break;
545 }
546
547 ptr_chip = gpiod->chip_open(gate_cstrbuffer_get(&pathbuffer));
548 if (!ptr_chip)
549 {
550 ret = GATE_RESULT_FAILED;
551 break;
552 }
553
554 /* success case: */
555 if (ptr_device_handle)
556 {
557 *ptr_device_handle = (gate_gpiodevice_t)ptr_chip;
558 }
559 else
560 {
561 gpiod->chip_close(ptr_chip);
562 }
563 ret = GATE_RESULT_OK;
564 } while (0);
565
566 gate_cstrbuffer_destroy(&pathbuffer);
567 return ret;
568 }
569
570
571 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
572 {
573 gpiod_code_t* const gpiod = get_gpiod_functions();
574
575 if (gpiod == NULL)
576 {
577 return GATE_RESULT_NOTAVAILABLE;
578 }
579
580 if (!ptr_device_handle)
581 {
582 return GATE_RESULT_INVALIDARG;
583 }
584 else if (*ptr_device_handle)
585 {
586 gpiod_chip_t* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
587 gpiod->chip_close(ptr_chip);
588 *ptr_device_handle = NULL;
589 return GATE_RESULT_OK;
590 }
591 else
592 {
593 /* the device handle was already cleared, no action required */
594 return GATE_RESULT_OK_UNCHANGED;
595 }
596 }
597
598
599 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
600 {
601 gate_result_t ret;
602 struct gpiod_chip_info* ptr_info = NULL;
603
604 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
605 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
606
607 do
608 {
609 gate_size_t line_count = 0;
610 gate_size_t ndx;
611 gate_bool_t continue_loop = true;
612 gpiod_chip_t* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
613
614 ret = gate_gpiod_get_chip_infos(ptr_chip, NULL, NULL, &line_count);
615 GATE_BREAK_IF_FAILED(ret);
616
617 /* iterate available lines and notify usable ones: */
618 for (ndx = 0; continue_loop && (ndx != line_count); ++ndx)
619 {
620 bool is_used = false;
621 gate_string_t str_name = GATE_STRING_INIT_EMPTY;
622 ret = gate_gpiod_get_line_infos(ptr_chip, ndx, &str_name, NULL, NULL, &is_used);
623 if (GATE_FAILED(ret))
624 {
625 continue;
626 }
627 if (callback)
628 {
629 continue_loop = callback((gate_intptr_t)ndx, &str_name, is_used, param);
630 }
631 gate_string_release(&str_name);
632 }
633 /* success case */
634 ret = GATE_RESULT_OK;
635 } while (0);
636 return ret;
637 }
638
639 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
640 {
641 gate_result_t ret = GATE_RESULT_FAILED;
642 /*
643 struct gpiod_line_info* ptr_lineinfo = NULL;
644
645 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
646 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
647
648 do
649 {
650 struct gpiod_chip* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
651 enum gpiod_line_direction direction;
652
653 ptr_lineinfo = gpiod_chip_get_line_info(ptr_chip, line_address);
654 if (NULL == ptr_lineinfo)
655 {
656 ret = GATE_RESULT_FAILED;
657 break;
658 }
659
660 direction = gpiod_line_info_get_direction(ptr_lineinfo);
661
662 if (ptr_config != NULL)
663 {
664 switch(direction)
665 {
666 case GPIOD_LINE_DIRECTION_INPUT: *ptr_config = GATE_GPIODEVICE_LINE_CONFIG_INPUT; break;
667 case GPIOD_LINE_DIRECTION_OUTPUT: *ptr_config = GATE_GPIODEVICE_LINE_CONFIG_OUTPUT; break;
668 default: *ptr_config = 0; break;
669 }
670 }
671 ret = GATE_RESULT_OK;
672 } while (0);
673
674 if (ptr_lineinfo != NULL)
675 {
676 gpiod_line_info_free(ptr_lineinfo);
677 }
678 */
679 return ret;
680 }
681
682
683 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
684 {
685 gate_result_t ret = GATE_RESULT_FAILED;
686 /*
687 struct gpiod_line_settings* new_settings = NULL;
688 struct gpiod_line_config* new_config = NULL;
689 struct gpiod_line_request* new_request = NULL;
690
691 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
692 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
693
694 do
695 {
696 struct gpiod_chip* ptr_chip = (struct gpiod_chip*)*ptr_device_handle;
697 enum gpiod_line_direction new_direction = (config == GATE_GPIODEVICE_LINE_CONFIG_INPUT) ? GPIOD_LINE_DIRECTION_INPUT : GPIOD_LINE_DIRECTION_OUTPUT;
698 unsigned int target_line = (unsigned int)line_address;
699
700 new_settings = gpiod_line_settings_new();
701 if (!new_settings)
702 {
703 ret = GATE_RESULT_OUTOFMEMORY;
704 break;
705 }
706
707 new_config = gpiod_line_config_new();
708 if (!new_config)
709 {
710 ret = GATE_RESULT_OUTOFMEMORY;
711 break;
712 }
713
714 if (0 != gpiod_line_settings_set_direction(new_settings, new_direction))
715 {
716 ret = GATE_RESULT_FAILED;
717 break;
718 }
719
720 if (0 != gpiod_line_config_add_line_settings(new_config, &target_line, 1, new_settings))
721 {
722 ret = GATE_RESULT_FAILED;
723 break;
724 }
725
726 new_request = gpiod_chip_request_lines(ptr_chip, NULL, new_config);
727 if (NULL == new_request)
728 {
729 ret = GATE_RESULT_FAILED;
730 break;
731 }
732
733 if(0 != gpiod_line_request_reconfigure_lines(new_request, new_config))
734 {
735 ret = GATE_RESULT_EXECUTIONFAILED;
736 break;
737 }
738 ret = GATE_RESULT_OK;
739 } while (0);
740
741 if (new_request) gpiod_line_request_release(new_request);
742 if (new_config) gpiod_line_config_free(new_config);
743 if (new_settings) gpiod_line_settings_free(new_settings);
744 */
745 return ret;
746 }
747
748
749 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
750 {
751 gate_result_t ret;
752 gpiod_chip_t* ptr_chip;
753 int value = 0;
754
755 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
756 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
757
758 ptr_chip = (gpiod_chip_t*)*ptr_device_handle;
759 ret = gate_gpiod_read_line_value(ptr_chip, line_address, &value);
760 if (GATE_SUCCEEDED(ret))
761 {
762 if (ptr_value) *ptr_value = value;
763 }
764 return ret;
765 }
766
767
768 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
769 {
770 gate_result_t ret;
771 gpiod_chip_t* ptr_chip;
772
773 GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
774 GATE_DEBUG_ASSERT(*ptr_device_handle != NULL);
775
776 ptr_chip = (gpiod_chip_t*)*ptr_device_handle;
777 ret = gate_gpiod_write_line_value(ptr_chip, line_address, value);
778 return ret;
779 }
780
781 #endif /* GATE_IO_GPIODEVICE_GPIOD_IMPL */
782
783
784
785 #if defined(GATE_IO_GPIODEVICE_IOCTL_IMPL)
786
787 #include "gate/platforms.h"
788 #include <linux/gpio.h>
789 #include <fcntl.h>
790
791 /* #define LINUX_GPIO_V2_SUPPORT 1 */
792
793 1 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
794 {
795 gate_result_t ret;
796 1 gate_cstrbuffer_t buffer = GATE_INIT_EMPTY;
797
798
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(device_path != NULL);
799 do
800 {
801 int fd;
802
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (gate_string_is_empty(device_path))
803 {
804 1 ret = GATE_RESULT_INVALIDARG;
805 1 break;
806 }
807 ✗ if (NULL == gate_cstrbuffer_create_string(&buffer, device_path, false))
808 {
809 ✗ ret = GATE_RESULT_OUTOFMEMORY;
810 ✗ break;
811 }
812
813 ✗ fd = gate_posix_open(gate_cstrbuffer_get(&buffer), O_RDWR, 0);
814 ✗ if (fd == -1)
815 {
816 ✗ ret = GATE_RESULT_NOTAVAILABLE;
817 ✗ break;
818 }
819
820 /* success case reached */
821 ✗ ret = GATE_RESULT_OK;
822 ✗ if (ptr_device_handle)
823 {
824 ✗ *ptr_device_handle = (gate_gpiodevice_t)(gate_intptr_t)fd;
825 }
826 else
827 {
828 ✗ gate_posix_close(fd);
829 }
830 } while (0);
831 1 gate_cstrbuffer_destroy(&buffer);
832 1 return ret;
833 }
834
835 ✗ gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
836 {
837 ✗ if (!ptr_device_handle)
838 {
839 ✗ return GATE_RESULT_INVALIDARG;
840 }
841 else
842 {
843 ✗ const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
844 ✗ if (fd != -1)
845 {
846 ✗ gate_posix_close(fd);
847 ✗ *ptr_device_handle = (gate_gpiodevice_t)(gate_intptr_t)-1;
848 }
849 ✗ return GATE_RESULT_OK;
850 }
851 }
852
853 ✗ gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
854 {
855 gate_result_t ret;
856
857 ✗ GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
858 ✗ GATE_DEBUG_ASSERT(callback != NULL);
859
860 do
861 {
862 ✗ const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
863 struct gpiochip_info chip_info;
864 unsigned line;
865 ✗ gate_bool_t continue_listing = true;
866
867 ✗ gate_mem_clear(&chip_info, sizeof(chip_info));
868 ✗ if (gate_posix_ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip_info) < 0)
869 {
870 ✗ ret = GATE_RESULT_FAILED;
871 ✗ break;
872 }
873
874 ✗ ret = GATE_RESULT_OK;
875 ✗ for(line = 0; (line < chip_info.lines) && continue_listing; ++line)
876 {
877 ✗ gate_string_t description = GATE_STRING_INIT_EMPTY;
878 ✗ gate_bool_t is_line_used = false;
879
880 #if !defined(LINUX_GPIO_V2_SUPPORT)
881 /* GPIO v1 interface */
882 struct gpioline_info line_info;
883 ✗ gate_mem_clear(&line_info, sizeof(line_info));
884 ✗ line_info.line_offset = line;
885
886 ✗ if (gate_posix_ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line_info) < 0)
887 {
888 ✗ continue;
889 }
890 ✗ is_line_used = GATE_FLAG_ENABLED(line_info.flags, GPIOLINE_FLAG_KERNEL);
891 ✗ gate_string_create_static(&description, line_info.name);
892 #else
893 /* GPIO v2 interface */
894 struct gpio_v2_line_info line_info;
895 gate_mem_clear(&line_info, sizeof(line_info));
896 line_info.offset = line;
897
898 if (gate_posix_ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &line_info) < 0)
899 {
900 continue;
901 }
902 is_line_used = GATE_FLAG_ENABLED(line_info.flags, GPIO_V2_LINE_FLAG_USED);
903 gate_string_create_static(&description, line_info.name);
904 #endif /* LINUX_GPIO_V2_SUPPORT */
905
906 ✗ continue_listing = callback(
907 line,
908 &description,
909 is_line_used,
910 param);
911 ✗ gate_string_release(&description);
912 }
913
914 } while (0);
915
916 ✗ return ret;
917 }
918
919 ✗ gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
920 {
921 gate_result_t ret;
922
923 ✗ GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
924 ✗ GATE_DEBUG_ASSERT(ptr_config != NULL);
925
926 do
927 {
928 ✗ const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
929 ✗ gate_enumint_t config = 0;
930
931 #if !defined(LINUX_GPIO_V2_SUPPORT)
932 /* GPIO v1 interface */
933 struct gpioline_info line_info;
934 ✗ gate_mem_clear(&line_info, sizeof(line_info));
935 ✗ line_info.line_offset = (unsigned)line_address;
936 ✗ if (gate_posix_ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line_info) < 0)
937 {
938 ✗ ret = GATE_RESULT_FAILED;
939 ✗ break;
940 }
941
942 ✗ if (GATE_FLAG_ENABLED(line_info.flags, GPIOLINE_FLAG_IS_OUT))
943 {
944 ✗ config |= GATE_GPIODEVICE_LINE_CONFIG_OUTPUT;
945 }
946 else
947 {
948 ✗ config |= GATE_GPIODEVICE_LINE_CONFIG_INPUT;
949 }
950 #else
951 /* GPIO v2 interface */
952 struct gpio_v2_line_info line_info;
953 gate_mem_clear(&line_info, sizeof(line_info));
954 line_info.offset = (unsigned)line_address;
955 if (gate_posix_ioctl(fd, GPIO_V2_GET_LINEINFO_IOCTL, &line_info) < 0)
956 {
957 ret = GATE_RESULT_FAILED;
958 break;
959 }
960
961 if (GATE_FLAG_ENABLED(line_info.flags, GPIO_V2_LINE_FLAG_INPUT))
962 {
963 config |= GATE_GPIODEVICE_LINE_CONFIG_INPUT;
964 }
965 if (GATE_FLAG_ENABLED(line_info.flags, GPIO_V2_LINE_FLAG_OUTPUT))
966 {
967 config |= GATE_GPIODEVICE_LINE_CONFIG_OUTPUT;
968 }
969 #endif /* LINUX_GPIO_V2_SUPPORT */
970
971 ✗ *ptr_config = config;
972 ✗ ret = GATE_RESULT_OK;
973 } while (0);
974
975 ✗ return ret;
976 }
977
978 ✗ gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
979 {
980 ✗ return GATE_RESULT_NOTIMPLEMENTED;
981 }
982
983 ✗ gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
984 {
985 gate_result_t ret;
986
987 ✗ GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
988 ✗ GATE_DEBUG_ASSERT(ptr_value != NULL);
989
990 do
991 {
992 ✗ const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
993
994 #if !defined(LINUX_GPIO_V2_SUPPORT)
995 /* GPIO v1 interface */
996 struct gpiohandle_request req;
997 ✗ gate_mem_clear(&req, sizeof(req));
998
999 ✗ req.lineoffsets[0] = (unsigned)line_address;
1000 ✗ req.lines = 1;
1001 ✗ req.flags = GPIOHANDLE_REQUEST_INPUT;
1002
1003 ✗ if (gate_posix_ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0)
1004 {
1005 ✗ ret = GATE_RESULT_FAILED;
1006 ✗ break;
1007 }
1008
1009 {
1010 /* now we have an opened request-fd to read values */
1011 struct gpiohandle_data data;
1012 ✗ gate_mem_clear(&data, sizeof(data));
1013 ✗ if (gate_posix_ioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data) < 0)
1014 {
1015 ✗ ret = GATE_RESULT_FAILED;
1016 }
1017 else
1018 {
1019 ✗ *ptr_value = (gate_intptr_t)data.values[0];
1020 ✗ ret = GATE_RESULT_OK;
1021 }
1022 }
1023 ✗ gate_posix_close(req.fd);
1024 #else
1025 /* GPIO v2 interface */
1026 struct gpio_v2_line_request req;
1027 gate_mem_clear(&req, sizeof(req));
1028
1029 req.offsets[0] = (unsigned)line_address;
1030 req.num_lines = 1;
1031 req.config.flags = GPIO_V2_LINE_FLAG_INPUT;
1032
1033 if (gate_posix_ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req) < 0)
1034 {
1035 ret = GATE_RESULT_FAILED;
1036 break;
1037 }
1038
1039 {
1040 /* now we have an opened request-fd to read values */
1041 struct gpio_v2_line_values data;
1042 data.mask = 1;
1043 gate_mem_clear(&data, sizeof(data));
1044 if (gate_posix_ioctl(req.fd, GPIO_V2_LINE_GET_VALUES_IOCTL, &data) < 0)
1045 {
1046 ret = GATE_RESULT_FAILED;
1047 }
1048 else
1049 {
1050 *ptr_value = (gate_intptr_t)data.bits;
1051 ret = GATE_RESULT_OK;
1052 }
1053 }
1054 gate_posix_close(req.fd);
1055 #endif /* LINUX_GPIO_V2_SUPPORT */
1056 } while (0);
1057
1058 ✗ return ret;
1059 }
1060
1061 ✗ gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
1062 {
1063 gate_result_t ret;
1064
1065 ✗ GATE_DEBUG_ASSERT(ptr_device_handle != NULL);
1066
1067 do
1068 {
1069 ✗ const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
1070
1071 #if !defined(LINUX_GPIO_V2_SUPPORT)
1072 /* GPIO v1 interface */
1073 struct gpiohandle_request req;
1074 ✗ gate_mem_clear(&req, sizeof(req));
1075
1076 ✗ req.lineoffsets[0] = (unsigned)line_address;
1077 ✗ req.lines = 1;
1078 ✗ req.flags = GPIOHANDLE_REQUEST_OUTPUT;
1079 ✗ req.default_values[0] = (value == 0) ? 0 : 1;
1080
1081 ✗ if (gate_posix_ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req) < 0)
1082 {
1083 ✗ ret = GATE_RESULT_FAILED;
1084 ✗ break;
1085 }
1086
1087 {
1088 /* now we have an opened request-fd to write values */
1089 struct gpiohandle_data data;
1090 ✗ gate_mem_clear(&data, sizeof(data));
1091 ✗ data.values[0] = (value == 0) ? 0 : 1;
1092 ✗ if (gate_posix_ioctl(req.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data) < 0)
1093 {
1094 ✗ ret = GATE_RESULT_FAILED;
1095 }
1096 else
1097 {
1098 ✗ ret = GATE_RESULT_OK;
1099 }
1100 }
1101 ✗ gate_posix_close(req.fd);
1102 #else
1103 /* GPIO v2 interface */
1104 struct gpio_v2_line_request req;
1105 gate_mem_clear(&req, sizeof(req));
1106
1107 req.offsets[0] = (unsigned)line_address;
1108 req.num_lines = 1;
1109 req.config.flags = GPIO_V2_LINE_FLAG_OUTPUT;
1110
1111 if (gate_posix_ioctl(fd, GPIO_V2_GET_LINE_IOCTL, &req) < 0)
1112 {
1113 ret = GATE_RESULT_FAILED;
1114 break;
1115 }
1116
1117 {
1118 /* now we have an opened request-fd to write values */
1119 struct gpio_v2_line_values data;
1120 gate_mem_clear(&data, sizeof(data));
1121 data.bits = (value == 0) ? 0 : 1;
1122 data.mask = 1;
1123 if (gate_posix_ioctl(req.fd, GPIO_V2_LINE_SET_VALUES_IOCTL, &data) < 0)
1124 {
1125 ret = GATE_RESULT_FAILED;
1126 }
1127 else
1128 {
1129 ret = GATE_RESULT_OK;
1130 }
1131 }
1132 gate_posix_close(req.fd);
1133 #endif /* LINUX_GPIO_V2_SUPPORT */
1134
1135 } while (0);
1136
1137 ✗ return ret;
1138 }
1139
1140 #endif /* GATE_IO_GPIODEVICE_IOCTL_IMPL */
1141
1142
1143
1144 #if defined(GATE_IO_GPIODEVICE_ARDUINO_IMPL)
1145
1146 #include "gate/platform/arduino/arduino_gate.h"
1147
1148 static gate_gpiodevice_t const invalid_handle = (gate_gpiodevice_t)0x00;
1149 static gate_gpiodevice_t const default_handle = (gate_gpiodevice_t)0x01;
1150
1151 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
1152 {
1153 gate_string_create_empty(device_path);
1154 return GATE_RESULT_OK;
1155 }
1156
1157 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
1158 {
1159 if (ptr_device_handle)
1160 {
1161 *ptr_device_handle = default_handle;
1162 }
1163 return GATE_RESULT_OK;
1164 }
1165
1166 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
1167 {
1168 if (ptr_device_handle)
1169 {
1170 *ptr_device_handle = invalid_handle;
1171 }
1172 return GATE_RESULT_OK;
1173 }
1174
1175 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
1176 {
1177 if (*ptr_device_handle != default_handle)
1178 {
1179 return GATE_RESULT_INVALIDARG;
1180 }
1181 else if (callback != NULL)
1182 {
1183 gate_result_t ret = GATE_RESULT_FAILED;
1184 gate_size_t pin_count = gate_arduino_pin_count();
1185 gate_size_t ndx;
1186 gate_bool_t continue_loop = true;
1187 static gate_string_t const descr = GATE_STRING_INIT_STATIC("Digital pin");
1188 for (ndx = 0; (ndx != pin_count) && continue_loop; ++ndx)
1189 {
1190 if (callback)
1191 {
1192 const gate_intptr_t line = (gate_intptr_t)ndx;
1193 continue_loop = callback(line, &descr, false, param);
1194 }
1195 }
1196 }
1197 return GATE_RESULT_OK;
1198 }
1199
1200 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
1201 {
1202 if (*ptr_device_handle != default_handle)
1203 {
1204 return GATE_RESULT_INVALIDARG;
1205 }
1206 return GATE_RESULT_NOTIMPLEMENTED;
1207 }
1208
1209 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
1210 {
1211 if (*ptr_device_handle != default_handle)
1212 {
1213 return GATE_RESULT_INVALIDARG;
1214 }
1215 else
1216 {
1217 gate_uint8_t const pin_num = (gate_uint8_t)line_address;
1218 gate_arduino_pin_mode_t mode;
1219 switch(config)
1220 {
1221 case GATE_GPIODEVICE_LINE_CONFIG_INPUT: mode = gate_arduino_pin_mode_input; break;
1222 case GATE_GPIODEVICE_LINE_CONFIG_OUTPUT: mode = gate_arduino_pin_mode_output; break;
1223 default: return GATE_RESULT_INVALIDARG;
1224 }
1225 gate_arduino_pin_init(pin_num, mode);
1226 return GATE_RESULT_OK;
1227 }
1228 }
1229
1230 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
1231 {
1232 if (*ptr_device_handle != default_handle)
1233 {
1234 return GATE_RESULT_INVALIDARG;
1235 }
1236 else
1237 {
1238 gate_uint8_t const pin_num = (gate_uint8_t)line_address;
1239 if (ptr_value)
1240 {
1241 *ptr_value = gate_arduino_pin_get_value(pin_num);
1242 }
1243 return GATE_RESULT_OK;
1244 }
1245 }
1246
1247 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
1248 {
1249 if (*ptr_device_handle != default_handle)
1250 {
1251 return GATE_RESULT_INVALIDARG;
1252 }
1253 else
1254 {
1255 gate_uint8_t const pin_num = (gate_uint8_t)line_address;
1256 gate_arduino_pin_set_high(pin_num, value != 0);
1257 //gate_arduino_pin_set_value(pin_num, (int)value);
1258 return GATE_RESULT_OK;
1259 }
1260 }
1261
1262 #endif /* GATE_IO_GPIODEVICE_ARDUINO_IMPL */
1263
1264
1265
1266 #if defined(GATE_IO_GPIODEVICE_NO_IMPL)
1267
1268 gate_result_t gate_gpiodevice_default_path(gate_string_t* device_path)
1269 {
1270 GATE_UNUSED_ARG(device_path);
1271 return GATE_RESULT_NOTIMPLEMENTED;
1272 }
1273
1274 gate_result_t gate_gpiodevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_gpiodevice_t* ptr_device_handle)
1275 {
1276 GATE_UNUSED_ARG(device_path);
1277 GATE_UNUSED_ARG(flags);
1278 GATE_UNUSED_ARG(ptr_device_handle);
1279 return GATE_RESULT_NOTIMPLEMENTED;
1280 }
1281
1282 gate_result_t gate_gpiodevice_close(gate_gpiodevice_t* ptr_device_handle)
1283 {
1284 GATE_UNUSED_ARG(ptr_device_handle);
1285 return GATE_RESULT_NOTIMPLEMENTED;
1286 }
1287
1288 gate_result_t gate_gpiodevice_lines_list(gate_gpiodevice_t* ptr_device_handle, gate_gpiodevice_list_lines_callback_t callback, void* param)
1289 {
1290 GATE_UNUSED_ARG(ptr_device_handle);
1291 GATE_UNUSED_ARG(callback);
1292 GATE_UNUSED_ARG(param);
1293 return GATE_RESULT_NOTIMPLEMENTED;
1294 }
1295
1296 gate_result_t gate_gpiodevice_lines_get_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t* ptr_config)
1297 {
1298 GATE_UNUSED_ARG(ptr_device_handle);
1299 GATE_UNUSED_ARG(line_address);
1300 GATE_UNUSED_ARG(ptr_config);
1301 return GATE_RESULT_NOTIMPLEMENTED;
1302 }
1303
1304 gate_result_t gate_gpiodevice_lines_set_config(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_enumint_t config)
1305 {
1306 GATE_UNUSED_ARG(ptr_device_handle);
1307 GATE_UNUSED_ARG(line_address);
1308 GATE_UNUSED_ARG(config);
1309 return GATE_RESULT_NOTIMPLEMENTED;
1310 }
1311
1312 gate_result_t gate_gpiodevice_lines_read(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t* ptr_value)
1313 {
1314 GATE_UNUSED_ARG(ptr_device_handle);
1315 GATE_UNUSED_ARG(line_address);
1316 GATE_UNUSED_ARG(ptr_value);
1317 return GATE_RESULT_NOTIMPLEMENTED;
1318 }
1319
1320 gate_result_t gate_gpiodevice_lines_write(gate_gpiodevice_t* ptr_device_handle, gate_intptr_t line_address, gate_intptr_t value)
1321 {
1322 GATE_UNUSED_ARG(ptr_device_handle);
1323 GATE_UNUSED_ARG(line_address);
1324 GATE_UNUSED_ARG(value);
1325 return GATE_RESULT_NOTIMPLEMENTED;
1326 }
1327
1328 #endif /* GATE_IO_GPIODEVICE_NO_IMPL */
1329
1330
1331
1332 #if defined(GATE_IO_PWMDEVICE_SYSFS_IMPL)
1333
1334 #include "gate/blobs.h"
1335 #include "gate/threading.h"
1336
1337 typedef struct gate_pwmdevice_native_type
1338 {
1339 gate_string_t path; /**< sysfs base path /sys/class/pwm/pwmchipN */
1340 gate_uint8_t opened_channels[128]; /**< each bit represents an opened line */
1341 } gate_sysfs_pwmdevice_t;
1342
1343 1 gate_result_t gate_pwmdevice_default_path(gate_string_t* device_path)
1344 {
1345 1 return default_path_from_env_var_or_hardcoded(device_path, "GATE_PWM_DEVICE_PATH", "/sys/class/pwm/pwmchip0");
1346 }
1347
1348 static gate_string_t const pwm_dirname_export = GATE_STRING_INIT_STATIC("export");
1349 static gate_string_t const pwm_dirname_unexport = GATE_STRING_INIT_STATIC("unexport");
1350
1351 ✗ static gate_bool_t dir_entry_exists(gate_string_t const* path, gate_string_t const* subdir)
1352 {
1353 char buffer[GATE_MAX_FILENAME_LENGTH];
1354 gate_string_t full_path;
1355 ✗ const gate_size_t length = gate_file_build_path(
1356 buffer, sizeof(buffer),
1357 ✗ path->str, path->length,
1358 ✗ subdir->str, subdir->length);
1359 ✗ gate_string_create_static_len(&full_path, buffer, length);
1360 ✗ return GATE_RESULT_OK == gate_file_exists(&full_path);
1361 }
1362
1363 ✗ static gate_bool_t sysfs_pwm_is_exported(gate_string_t const* path, gate_intptr_t channel)
1364 {
1365 char buffer[GATE_MAX_FILENAME_LENGTH];
1366 gate_strbuilder_t sb;
1367 gate_string_t pwm_path;
1368 ✗ const gate_size_t length = gate_file_build_path(
1369 buffer, sizeof(buffer),
1370 ✗ path->str, path->length,
1371 "pwm", 3);
1372 ✗ gate_strbuilder_create_static(&sb, buffer, sizeof(buffer), length);
1373 ✗ gate_strbuilder_append_int64(&sb, channel);
1374 ✗ gate_strbuilder_to_string(&sb, &pwm_path);
1375 ✗ return GATE_RESULT_OK == gate_file_dir_exists(&pwm_path);
1376 }
1377
1378 ✗ static gate_result_t sysfs_pwm_export(gate_string_t const* path, gate_intptr_t channel)
1379 {
1380 gate_result_t result;
1381 char buffer[GATE_MAX_FILENAME_LENGTH];
1382 gate_string_t export_path;
1383 ✗ const gate_size_t length = gate_file_build_path(
1384 buffer, sizeof(buffer),
1385 ✗ path->str, path->length,
1386 ✗ pwm_dirname_export.str, pwm_dirname_export.length);
1387 ✗ gate_string_create_static_len(&export_path, buffer, length);
1388 ✗ result = sysfs_write_int64_to_file(&export_path, channel);
1389 ✗ if (GATE_SUCCEEDED(result))
1390 {
1391 ✗ int is_exported_retry_count = 5;
1392 do
1393 {
1394 ✗ gate_thread_sleep(100);
1395 ✗ } while(!sysfs_pwm_is_exported(path, channel) && (is_exported_retry_count-- > 0));
1396 }
1397 ✗ return result;
1398 }
1399
1400 ✗ static gate_result_t sysfs_pwm_unexport(gate_string_t const* path, gate_intptr_t channel)
1401 {
1402 char buffer[GATE_MAX_FILENAME_LENGTH];
1403 gate_string_t unexport_path;
1404 ✗ const gate_size_t length = gate_file_build_path(
1405 buffer, sizeof(buffer),
1406 ✗ path->str, path->length,
1407 ✗ pwm_dirname_unexport.str, pwm_dirname_unexport.length);
1408 ✗ gate_string_create_static_len(&unexport_path, buffer, length);
1409 ✗ return sysfs_write_int64_to_file(&unexport_path, channel);
1410 }
1411
1412 ✗ static gate_result_t sysfs_pwm_write(gate_string_t const* path, gate_intptr_t channel,
1413 char const* target, char const* content, gate_size_t content_len)
1414 {
1415 char buffer[GATE_MAX_FILENAME_LENGTH];
1416 gate_string_t target_path;
1417 gate_strbuilder_t sb;
1418 ✗ const gate_size_t length = gate_file_build_path(
1419 buffer, sizeof(buffer),
1420 ✗ path->str, path->length,
1421 "pwm", 3);
1422 ✗ gate_strbuilder_create_static(&sb, buffer, sizeof(buffer), length);
1423 ✗ gate_strbuilder_append_int64(&sb, channel);
1424 ✗ gate_strbuilder_append_cstr(&sb, "/");
1425 ✗ gate_strbuilder_append_cstr(&sb, target);
1426 ✗ gate_strbuilder_to_string(&sb, &target_path);
1427 ✗ return sysfs_write_to_file(&target_path, content, content_len);
1428 }
1429
1430 ✗ static gate_result_t sysfs_pwm_write_int64(gate_string_t const* path, gate_intptr_t channel,
1431 char const* target, gate_int64_t value)
1432 {
1433 char buffer[32];
1434 ✗ gate_size_t buffer_used = gate_str_print_int64(buffer, sizeof(buffer), value);
1435 ✗ return sysfs_pwm_write(path, channel, target, buffer, buffer_used);
1436 }
1437
1438 ✗ static gate_result_t sysfs_pwm_read(gate_string_t const* path, gate_intptr_t channel,
1439 char const* target, char* content, gate_size_t content_len, gate_size_t* content_used)
1440 {
1441 char buffer[GATE_MAX_FILENAME_LENGTH];
1442 gate_string_t target_path;
1443 gate_strbuilder_t sb;
1444 ✗ const gate_size_t length = gate_file_build_path(
1445 buffer, sizeof(buffer),
1446 ✗ path->str, path->length,
1447 "pwm", 3);
1448 ✗ gate_strbuilder_create_static(&sb, buffer, sizeof(buffer), length);
1449 ✗ gate_strbuilder_append_int64(&sb, channel);
1450 ✗ gate_strbuilder_append_cstr(&sb, "/");
1451 ✗ gate_strbuilder_append_cstr(&sb, target);
1452 ✗ gate_strbuilder_to_string(&sb, &target_path);
1453 ✗ return sysfs_read_from_file(&target_path, content, content_len, content_used);
1454 }
1455
1456 ✗ static gate_result_t sysfs_pwm_read_int64(gate_string_t const* path, gate_intptr_t channel,
1457 char const* target, gate_int64_t* ptr_value)
1458 {
1459 char buffer[32];
1460 ✗ gate_size_t buffer_used = 0;
1461 ✗ gate_result_t ret = sysfs_pwm_read(path, channel, target, buffer, sizeof(buffer), &buffer_used);
1462 ✗ if (GATE_SUCCEEDED(ret))
1463 {
1464 ✗ if (0 == gate_str_parse_int64(buffer, buffer_used, ptr_value))
1465 {
1466 ✗ *ptr_value = 0;
1467 }
1468 }
1469 ✗ return ret;
1470 }
1471
1472 ✗ static void pwmdevice_register_opened_channel(gate_sysfs_pwmdevice_t* ptr_pwm, gate_intptr_t channel)
1473 {
1474 ✗ if (channel < 0 || channel > sizeof(ptr_pwm->opened_channels) * 8)
1475 {
1476 /* out of storage bounds */
1477 ✗ return;
1478 }
1479 ✗ gate_bit_set(&ptr_pwm->opened_channels[0], (gate_size_t)channel);
1480 }
1481
1482 1 gate_result_t gate_pwmdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_pwmdevice_t* ptr_device_handle)
1483 {
1484 1 gate_result_t ret = GATE_RESULT_FAILED;
1485 1 gate_sysfs_pwmdevice_t* ptr_pwm = NULL;
1486 do
1487 {
1488 1 ret = gate_file_dir_exists(device_path);
1489
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 GATE_BREAK_IF_FAILED(ret);
1490
1491 ✗ if (!dir_entry_exists(device_path, &pwm_dirname_export))
1492 {
1493 ✗ ret = GATE_RESULT_NOTAVAILABLE;
1494 ✗ break;
1495 }
1496
1497 ✗ ptr_pwm = (gate_sysfs_pwmdevice_t*)gate_mem_alloc(sizeof(gate_sysfs_pwmdevice_t));
1498 ✗ if (NULL == ptr_pwm)
1499 {
1500 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1501 ✗ break;
1502 }
1503 ✗ gate_mem_clear(ptr_pwm, sizeof(gate_sysfs_pwmdevice_t));
1504
1505 ✗ if (NULL == gate_string_clone(&ptr_pwm->path, device_path))
1506 {
1507 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1508 ✗ break;
1509 }
1510
1511 /* success case */
1512 ✗ if (ptr_device_handle != NULL)
1513 {
1514 ✗ *ptr_device_handle = ptr_pwm;
1515 ✗ ptr_pwm = NULL;
1516 }
1517 ✗ ret = GATE_RESULT_OK;
1518 } while (0);
1519
1520
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ptr_pwm != NULL)
1521 {
1522 ✗ gate_mem_dealloc(ptr_pwm);
1523 }
1524
1525 1 return ret;
1526 }
1527
1528 ✗ gate_result_t gate_pwmdevice_close(gate_pwmdevice_t* ptr_device_handle)
1529 {
1530 ✗ gate_sysfs_pwmdevice_t* pwm = ptr_device_handle ? *ptr_device_handle : NULL;
1531 ✗ if (pwm != NULL)
1532 {
1533 ✗ gate_int64_t pwm_count = 0;
1534 ✗ gate_result_t result = sysfs_read_int64_from_dir_file(&pwm->path, "npwm", &pwm_count);
1535 ✗ if (GATE_SUCCEEDED(result))
1536 {
1537 gate_intptr_t ndx;
1538 ✗ for (ndx = 0; ndx < pwm_count; ++ndx)
1539 {
1540 ✗ if (gate_bit_is_set(&pwm->opened_channels[0], (gate_size_t)ndx))
1541 {
1542 ✗ sysfs_pwm_unexport(&pwm->path, ndx);
1543 }
1544 }
1545 }
1546
1547 ✗ gate_string_release(&pwm->path);
1548 ✗ gate_mem_dealloc(pwm);
1549 }
1550 ✗ return GATE_RESULT_NOTIMPLEMENTED;
1551 }
1552
1553 ✗ gate_result_t gate_pwmdevice_list_channels(gate_pwmdevice_t* ptr_device_handle,
1554 gate_pwmdevice_list_channels_callback_t callback, void* param)
1555 {
1556 gate_result_t ret;
1557 ✗ gate_sysfs_pwmdevice_t* pwm = ptr_device_handle ? *ptr_device_handle : NULL;
1558
1559 do
1560 {
1561 ✗ gate_int64_t pwm_count = 0;
1562 gate_intptr_t ndx;
1563 ✗ if (pwm == NULL)
1564 {
1565 ✗ ret = GATE_RESULT_INVALIDARG;
1566 ✗ break;
1567 }
1568
1569 ✗ ret = sysfs_read_int64_from_dir_file(&pwm->path, "npwm", &pwm_count);
1570 ✗ GATE_BREAK_IF_FAILED(ret);
1571
1572 ✗ for (ndx = 0; ndx < pwm_count; ++ndx)
1573 {
1574 ✗ if (false == callback(ndx, param))
1575 {
1576 /* canceled by callback */
1577 ✗ break;
1578 }
1579 }
1580 } while (0);
1581
1582 ✗ return ret;
1583 }
1584
1585 ✗ gate_result_t gate_pwmdevice_channel_read(gate_pwmdevice_t* ptr_device_handle, gate_intptr_t channel_id,
1586 gate_uint64_t* period_nanosecs, gate_uint64_t* duty_cycle_nanosecs, gate_bool_t* enabled)
1587 {
1588 gate_result_t ret;
1589 ✗ gate_sysfs_pwmdevice_t* pwm = ptr_device_handle ? *ptr_device_handle : NULL;
1590
1591 do
1592 {
1593 ✗ if (pwm == NULL)
1594 {
1595 ✗ ret = GATE_RESULT_INVALIDARG;
1596 ✗ break;
1597 }
1598
1599 ✗ gate_int64_t period = 0, duty_cycle = 0, is_enabled = 0;
1600 ✗ if (!sysfs_pwm_is_exported(&pwm->path, channel_id))
1601 {
1602 ✗ ret = sysfs_pwm_export(&pwm->path, channel_id);
1603 ✗ GATE_BREAK_IF_FAILED(ret);
1604 ✗ pwmdevice_register_opened_channel(pwm, channel_id);
1605 }
1606 ✗ ret = sysfs_pwm_read_int64(&pwm->path, channel_id, "period", &period);
1607 ✗ GATE_BREAK_IF_FAILED(ret);
1608
1609 ✗ ret = sysfs_pwm_read_int64(&pwm->path, channel_id, "duty_cycle", &duty_cycle);
1610 ✗ GATE_BREAK_IF_FAILED(ret);
1611
1612 ✗ ret = sysfs_pwm_read_int64(&pwm->path, channel_id, "enable", &is_enabled);
1613 ✗ GATE_BREAK_IF_FAILED(ret);
1614
1615 ✗ *period_nanosecs = period;
1616 ✗ *duty_cycle_nanosecs = duty_cycle;
1617 ✗ *enabled = (is_enabled > 0);
1618 } while (0);
1619
1620 ✗ return ret;
1621 }
1622
1623 ✗ gate_result_t gate_pwmdevice_channel_write(gate_pwmdevice_t* ptr_device_handle, gate_intptr_t channel_id,
1624 gate_uint64_t period_nanosecs, gate_uint64_t duty_cycle_nanosecs, gate_bool_t enabled)
1625 {
1626 gate_result_t ret;
1627 ✗ gate_sysfs_pwmdevice_t* pwm = ptr_device_handle ? *ptr_device_handle : NULL;
1628
1629 do
1630 {
1631 ✗ gate_bool_t do_disable = !enabled;
1632 ✗ gate_bool_t do_enable = enabled;
1633 gate_bool_t is_enabled;
1634 ✗ gate_bool_t is_inverted = false;
1635 ✗ gate_int64_t is_enabled_value = 0;
1636 ✗ if (pwm == NULL)
1637 {
1638 ✗ ret = GATE_RESULT_INVALIDARG;
1639 ✗ break;
1640 }
1641
1642 ✗ if (!sysfs_pwm_is_exported(&pwm->path, channel_id))
1643 {
1644 ✗ ret = sysfs_pwm_export(&pwm->path, channel_id);
1645 ✗ GATE_BREAK_IF_FAILED(ret);
1646 ✗ pwmdevice_register_opened_channel(pwm, channel_id);
1647 }
1648
1649 ✗ ret = sysfs_pwm_read_int64(&pwm->path, channel_id, "enable", &is_enabled_value);
1650 ✗ GATE_BREAK_IF_FAILED(ret);
1651
1652 ✗ is_enabled = is_enabled_value > 0;
1653 ✗ if (do_disable && !is_enabled) do_disable = false;
1654
1655 ✗ if (do_disable)
1656 {
1657 ✗ ret = sysfs_pwm_write_int64(&pwm->path, channel_id, "enable", 0);
1658 ✗ GATE_BREAK_IF_FAILED(ret);
1659
1660 /* reset pwm cycle to zero */
1661 ✗ sysfs_pwm_write_int64(&pwm->path, channel_id, "duty_cycle", 0);
1662 }
1663
1664 ✗ if (do_enable)
1665 {
1666 ✗ if (is_inverted)
1667 {
1668 ✗ ret = sysfs_pwm_write(&pwm->path, channel_id, "polarity", "inverted", 8);
1669 }
1670 else
1671 {
1672 ✗ ret = sysfs_pwm_write(&pwm->path, channel_id, "polarity", "normal", 6);
1673 }
1674 ✗ GATE_BREAK_IF_FAILED(ret);
1675
1676 ✗ ret = sysfs_pwm_write_int64(&pwm->path, channel_id, "period", period_nanosecs);
1677 ✗ GATE_BREAK_IF_FAILED(ret);
1678
1679 ✗ ret = sysfs_pwm_write_int64(&pwm->path, channel_id, "duty_cycle", duty_cycle_nanosecs);
1680 ✗ GATE_BREAK_IF_FAILED(ret);
1681
1682 ✗ ret = sysfs_pwm_write_int64(&pwm->path, channel_id, "enable", 1);
1683 ✗ GATE_BREAK_IF_FAILED(ret);
1684 }
1685 } while (0);
1686
1687 ✗ return ret;
1688 }
1689
1690 #endif /* GATE_IO_PWMDEVICE_SYSFS_IMPL */
1691
1692
1693
1694 #if defined(GATE_IO_PWMDEVICE_NO_IMPL)
1695
1696 gate_result_t gate_pwmdevice_default_path(gate_string_t* device_path)
1697 {
1698 return GATE_RESULT_NOTIMPLEMENTED;
1699 }
1700
1701 gate_result_t gate_pwmdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_pwmdevice_t* ptr_device_handle)
1702 {
1703 return GATE_RESULT_NOTIMPLEMENTED;
1704 }
1705
1706 gate_result_t gate_pwmdevice_close(gate_pwmdevice_t* ptr_device_handle)
1707 {
1708 return GATE_RESULT_NOTIMPLEMENTED;
1709 }
1710
1711 gate_result_t gate_pwmdevice_list_channels(gate_pwmdevice_t* ptr_device_handle,
1712 gate_pwmdevice_list_channels_callback_t callback, void* param)
1713 {
1714 return GATE_RESULT_NOTIMPLEMENTED;
1715 }
1716
1717 gate_result_t gate_pwmdevice_channel_read(gate_pwmdevice_t* ptr_device_handle, gate_intptr_t channel_id,
1718 gate_uint64_t* period_nanosecs, gate_uint64_t* duty_cycle_nanosecs, gate_bool_t* enabled)
1719 {
1720 return GATE_RESULT_NOTIMPLEMENTED;
1721 }
1722
1723 gate_result_t gate_pwmdevice_channel_write(gate_pwmdevice_t* ptr_device_handle, gate_intptr_t channel_id,
1724 gate_uint64_t period_nanosecs, gate_uint64_t duty_cycle_nanosecs, gate_bool_t enabled)
1725 {
1726 return GATE_RESULT_NOTIMPLEMENTED;
1727 }
1728
1729 #endif /* GATE_IO_PWMDEVICE_NO_IMPL */
1730
1731
1732
1733 #if defined(GATE_IO_I2CDEVICE_IOCTL_IMPL)
1734
1735 #include "gate/platforms.h"
1736 #include <linux/i2c-dev.h>
1737 #include <fcntl.h>
1738
1739 1 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
1740 {
1741 1 return default_path_from_env_var_or_hardcoded(device_path, "GATE_I2C_DEVICE_PATH", "/dev/i2c-1");
1742 }
1743
1744
1745 1 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
1746 {
1747 gate_result_t ret;
1748 1 gate_cstrbuffer_t buffer = GATE_INIT_EMPTY;
1749
1750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 GATE_DEBUG_ASSERT(device_path != NULL);
1751 do
1752 {
1753 int fd;
1754
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (gate_string_is_empty(device_path))
1755 {
1756 1 ret = GATE_RESULT_INVALIDARG;
1757 1 break;
1758 }
1759 ✗ if (NULL == gate_cstrbuffer_create_string(&buffer, device_path, false))
1760 {
1761 ✗ ret = GATE_RESULT_OUTOFMEMORY;
1762 ✗ break;
1763 }
1764
1765 ✗ fd = gate_posix_open(gate_cstrbuffer_get(&buffer), O_RDWR, 0);
1766 ✗ if (fd == -1)
1767 {
1768 ✗ ret = GATE_RESULT_NOTAVAILABLE;
1769 ✗ break;
1770 }
1771
1772 /* success case reached */
1773 ✗ ret = GATE_RESULT_OK;
1774 ✗ if (ptr_device_handle)
1775 {
1776 ✗ *ptr_device_handle = (gate_i2cdevice_t)(gate_intptr_t)fd;
1777 }
1778 else
1779 {
1780 ✗ gate_posix_close(fd);
1781 }
1782 } while (0);
1783 1 gate_cstrbuffer_destroy(&buffer);
1784 1 return ret;
1785 }
1786
1787 ✗ gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
1788 {
1789 ✗ if (!ptr_device_handle)
1790 {
1791 ✗ return GATE_RESULT_INVALIDARG;
1792 }
1793 else
1794 {
1795 ✗ int fd = (int)(gate_intptr_t)(*ptr_device_handle);
1796 ✗ if (fd != -1)
1797 {
1798 ✗ gate_posix_close(fd);
1799 ✗ *ptr_device_handle = (gate_i2cdevice_t)(gate_intptr_t)-1;
1800 }
1801 ✗ return GATE_RESULT_OK;
1802 }
1803 }
1804
1805 ✗ static gate_result_t fd_i2c_select_slave(int fd, int slave_address)
1806 {
1807 ✗ int result = gate_posix_ioctl(fd, I2C_SLAVE, (void*)(gate_intptr_t)slave_address);
1808 ✗ return result < 0 ? GATE_RESULT_FAILED : GATE_RESULT_OK;
1809 }
1810
1811 ✗ gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
1812 void const* const* content_blocks, gate_size_t const* content_blocks_lengths, gate_size_t count,
1813 gate_size_t* bytes_sent)
1814 {
1815 gate_result_t ret;
1816
1817 do
1818 {
1819 int fd;
1820 ptrdiff_t write_result;
1821 ✗ gate_size_t bytes_total = 0;
1822 ✗ if (!ptr_device_handle)
1823 {
1824 ✗ ret = GATE_RESULT_INVALIDARG;
1825 ✗ break;
1826 }
1827
1828 ✗ fd = (int)(gate_intptr_t)(*ptr_device_handle);
1829 ✗ ret = fd_i2c_select_slave(fd, (int)i2c_address);
1830 ✗ GATE_BREAK_IF_FAILED(ret);
1831
1832 ✗ if (count == 1)
1833 {
1834 ✗ bytes_total = content_blocks_lengths[0];
1835 ✗ write_result = gate_posix_write(fd, content_blocks[0], bytes_total);
1836 }
1837 else
1838 {
1839 char buffer[GATE_MAX_STACK_COPYBUFFER_LENGTH];
1840 ✗ gate_size_t avail = sizeof(buffer);
1841 gate_size_t ndx;
1842 ptrdiff_t result;
1843
1844 ✗ bytes_total = 0;
1845 ✗ for (ndx = 0; ndx != count; ++ndx)
1846 {
1847 ✗ void const* const block = content_blocks[ndx];
1848 ✗ gate_size_t blocklen = content_blocks_lengths[ndx];
1849 ✗ if (blocklen > avail)
1850 {
1851 ✗ ret = GATE_RESULT_OVERFLOW;
1852 ✗ break;
1853 }
1854 ✗ gate_mem_copy(&buffer[bytes_total], block, blocklen);
1855 ✗ bytes_total += blocklen;
1856 ✗ avail -= blocklen;
1857 }
1858 ✗ GATE_BREAK_IF_FAILED(ret);
1859
1860 ✗ write_result = gate_posix_write(fd, buffer, bytes_total);
1861 }
1862
1863 ✗ if (write_result != (ptrdiff_t)bytes_total)
1864 {
1865 ✗ ret = GATE_RESULT_FAILED;
1866 ✗ break;
1867 }
1868
1869 ✗ ret = GATE_RESULT_OK;
1870 ✗ if (bytes_sent)
1871 {
1872 ✗ *bytes_sent = bytes_total;
1873 }
1874 } while (0);
1875
1876 ✗ return ret;
1877 }
1878
1879 ✗ gate_result_t gate_i2cdevice_receive(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
1880 void* content, gate_size_t content_length, gate_size_t* bytes_received)
1881 {
1882 gate_result_t ret;
1883
1884 do
1885 {
1886 int fd;
1887 ptrdiff_t read_result;
1888
1889 ✗ if (!ptr_device_handle)
1890 {
1891 ✗ ret = GATE_RESULT_INVALIDARG;
1892 ✗ break;
1893 }
1894
1895 ✗ fd = (int)(gate_intptr_t)(*ptr_device_handle);
1896 ✗ ret = fd_i2c_select_slave(fd, (int)i2c_address);
1897 ✗ GATE_BREAK_IF_FAILED(ret);
1898
1899 ✗ read_result = gate_posix_read(fd, content, content_length);
1900
1901 ✗ ret = (read_result == (ptrdiff_t)content_length)
1902 ? GATE_RESULT_OK
1903 ✗ : GATE_RESULT_FAILED;
1904
1905 ✗ if (bytes_received)
1906 {
1907 ✗ *bytes_received = (gate_size_t)read_result;
1908 }
1909 } while (0);
1910
1911 ✗ return ret;
1912 }
1913
1914 #endif /* GATE_IO_I2CDEVICE_IOCTL_IMPL */
1915
1916
1917
1918 #if defined(GATE_IO_I2CDEVICE_WIRE_IMPL)
1919
1920 #include "carduino.h"
1921
1922 static gate_i2cdevice_t invalid_i2cdevice = (gate_i2cdevice_t)0x00;
1923 static gate_i2cdevice_t default_i2cdevice = (gate_i2cdevice_t)0x02;
1924
1925 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
1926 {
1927 gate_string_create_empty(device_path);
1928 return GATE_RESULT_OK;
1929 }
1930
1931 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
1932 {
1933 carduino_i2c_master_init(0, true);
1934 *ptr_device_handle = default_i2cdevice;
1935 return GATE_RESULT_OK;
1936 }
1937
1938 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
1939 {
1940 *ptr_device_handle = invalid_i2cdevice;
1941 return GATE_RESULT_OK;
1942 }
1943
1944 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
1945 void const* const* content_blocks, gate_size_t const* content_blocks_lengths, gate_size_t count,
1946 gate_size_t* bytes_sent)
1947 {
1948 if(!ptr_device_handle || (*ptr_device_handle != default_i2cdevice))
1949 {
1950 return GATE_RESULT_INVALIDARG;
1951 }
1952 else
1953 {
1954 unsigned const sent = carduino_i2c_master_send_blocks((unsigned char)i2c_address,
1955 (char const* const*)content_blocks, content_blocks_lengths, count);
1956 *bytes_sent = sent;
1957 return GATE_RESULT_OK;
1958 }
1959 }
1960
1961 gate_result_t gate_i2cdevice_receive(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
1962 void* content, gate_size_t content_length, gate_size_t* bytes_received)
1963 {
1964 if(!ptr_device_handle || (*ptr_device_handle != default_i2cdevice))
1965 {
1966 return GATE_RESULT_INVALIDARG;
1967 }
1968 else
1969 {
1970 int received = carduino_i2c_master_request(i2c_address, (char*)content, (int)content_length);
1971 if (bytes_received)
1972 {
1973 *bytes_received = (gate_size_t)received;
1974 }
1975 return GATE_RESULT_OK;
1976 }
1977 }
1978
1979 #endif /* GATE_IO_I2CDEVICE_WIRE_IMPL */
1980
1981
1982
1983 #if defined(GATE_IO_I2CDEVICE_FTD2XX_IMPL)
1984
1985 #include "gate/io/platform/gpiodevice_ftd2xx.h"
1986
1987 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
1988 {
1989 static gate_string_t const default_path = GATE_STRING_INIT_STATIC("");
1990 gate_string_duplicate(device_path, &default_path);
1991 return GATE_RESULT_OK;
1992 }
1993
1994 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
1995 {
1996 FT_functions_t const* const code = load_ftd2xx_functions();
1997
1998 GATE_UNUSED_ARG(device_path);
1999 GATE_UNUSED_ARG(flags);
2000
2001 if (!code)
2002 {
2003 /* error: no lib */
2004 return GATE_RESULT_NOTSUPPORTED;
2005 }
2006 else
2007 {
2008 FT_HANDLE ft_handle = NULL;
2009 FT_DEVICE ft_device = 0;
2010 gate_result_t result = ft_open_channel(code, 0, &ft_handle);
2011 if (GATE_SUCCEEDED(result))
2012 {
2013 I2C_CLOCKRATE rate = I2C_CLOCK_FAST_MODE;
2014 gate_uint32_t latencyTimer = 8; /* 8=fast, 255=slow */
2015 gate_uint32_t configOptions = 0;
2016 gate_uint32_t pin = 0;
2017
2018 do
2019 {
2020 result = ft_init_channel(code, ft_handle, &ft_device, rate, latencyTimer, configOptions, pin);
2021 GATE_BREAK_IF_FAILED(result);
2022
2023 result = i2c_finish_init_channel(code, ft_handle, ft_device, configOptions, pin);
2024 GATE_BREAK_IF_FAILED(result);
2025
2026 if (!(configOptions & I2C_DISABLE_3PHASE_CLOCKING))
2027 {
2028 unsigned char data = MPSSE_CMD_ENABLE_3PHASE_CLOCKING;
2029 DWORD written = 0;
2030 FT_STATUS status = code->FT_Write(ft_handle, &data, 1, &written);
2031 if (status != FT_OK)
2032 {
2033 result = GATE_RESULT_FAILED;
2034 break;
2035 }
2036 }
2037
2038 /* initialization succeeded */
2039 if (ptr_device_handle)
2040 {
2041 *ptr_device_handle = (gate_i2cdevice_t)ft_handle;
2042 ft_handle = NULL;
2043 }
2044 } while (0);
2045
2046 if (ft_handle)
2047 {
2048 ft_close_channel(code, ft_handle);
2049 }
2050 }
2051 return result;
2052 }
2053 }
2054
2055 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
2056 {
2057 FT_functions_t const* const code = load_ftd2xx_functions();
2058 if (!code)
2059 {
2060 /* error: no lib */
2061 return GATE_RESULT_NOTSUPPORTED;
2062 }
2063 else
2064 {
2065 FT_HANDLE ft_handle = (FT_HANDLE)*ptr_device_handle;
2066 return ft_close_channel(code, ft_handle);
2067 }
2068 }
2069
2070 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
2071 void const* const* content_blocks, gate_size_t const* content_block_lengths, gate_size_t count, gate_size_t* bytes_sent)
2072 {
2073 FT_functions_t const* const code = load_ftd2xx_functions();
2074
2075 if (!code)
2076 {
2077 /* error: no lib */
2078 return GATE_RESULT_NOTSUPPORTED;
2079 }
2080 else
2081 {
2082 gate_result_t ret = GATE_RESULT_FAILED;
2083 FT_HANDLE ft_handle = (FT_HANDLE)*ptr_device_handle;
2084 unsigned char buffer[GATE_MAX_COPYBUFFER_LENGTH];
2085 unsigned char* ptr_buffer = &buffer[0];
2086 unsigned char* ptr;
2087 unsigned buffer_len = 0;
2088 unsigned ndx;
2089 static gate_uint32_t const write_options = I2C_TRANSFER_OPTIONS_START_BIT|I2C_TRANSFER_OPTIONS_STOP_BIT|I2C_TRANSFER_OPTIONS_FAST_TRANSFER_BYTES;
2090
2091 for (ndx = 0; ndx != count; ++ndx)
2092 {
2093 buffer_len += content_block_lengths[ndx];
2094 }
2095
2096 if (buffer_len > sizeof(buffer))
2097 {
2098 ptr_buffer = (unsigned char*)gate_mem_alloc(buffer_len);
2099 if (ptr_buffer == NULL)
2100 {
2101 return GATE_RESULT_OUTOFMEMORY;
2102 }
2103 }
2104 ptr = ptr_buffer;
2105 for (ndx = 0; ndx != count; ++ndx)
2106 {
2107 void const* const src = content_blocks[ndx];
2108 gate_size_t const len = content_block_lengths[ndx];
2109 gate_mem_copy(ptr, src, len);
2110 ptr += len;
2111 }
2112
2113 ret = i2c_write(code, ft_handle, i2c_address, ptr_buffer, buffer_len, write_options, bytes_sent);
2114 if (ptr_buffer != &buffer[0])
2115 {
2116 gate_mem_dealloc(ptr_buffer);
2117 }
2118 return ret;
2119 }
2120 }
2121
2122 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)
2123 {
2124 FT_functions_t const* const code = load_ftd2xx_functions();
2125
2126 if (!code)
2127 {
2128 /* error: no lib */
2129 return GATE_RESULT_NOTSUPPORTED;
2130 }
2131 else
2132 {
2133 FT_HANDLE ft_handle = (FT_HANDLE)*ptr_device_handle;
2134 gate_uint32_t read_options = I2C_TRANSFER_OPTIONS_START_BIT | I2C_TRANSFER_OPTIONS_STOP_BIT | I2C_TRANSFER_OPTIONS_FAST_TRANSFER_BYTES;
2135 return i2c_read(code, ft_handle, i2c_address, content, content_length, read_options, bytes_received);
2136 }
2137 }
2138
2139 #endif /* GATE_IO_I2CDEVICE_FTD2XX_IMPL */
2140
2141
2142
2143 #if defined(GATE_IO_I2CDEVICE_NO_IMPL)
2144
2145 gate_result_t GATE_CALL gate_i2cdevice_default_path(gate_string_t* device_path)
2146 {
2147 GATE_UNUSED_ARG(device_path);
2148 return GATE_RESULT_NOTIMPLEMENTED;
2149 }
2150
2151
2152 gate_result_t gate_i2cdevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_i2cdevice_t* ptr_device_handle)
2153 {
2154 GATE_UNUSED_ARG(device_path);
2155 GATE_UNUSED_ARG(flags);
2156 GATE_UNUSED_ARG(ptr_device_handle);
2157 return GATE_RESULT_NOTIMPLEMENTED;
2158 }
2159
2160 gate_result_t gate_i2cdevice_close(gate_i2cdevice_t* ptr_device_handle)
2161 {
2162 GATE_UNUSED_ARG(ptr_device_handle);
2163 return GATE_RESULT_NOTIMPLEMENTED;
2164 }
2165
2166 gate_result_t gate_i2cdevice_send(gate_i2cdevice_t* ptr_device_handle, gate_uint8_t i2c_address,
2167 void const* const* content_blocks, gate_size_t const* content_block_lengths, gate_size_t count, gate_size_t* bytes_sent)
2168 {
2169 GATE_UNUSED_ARG(ptr_device_handle);
2170 GATE_UNUSED_ARG(i2c_address);
2171 GATE_UNUSED_ARG(content_blocks);
2172 GATE_UNUSED_ARG(content_block_lengths);
2173 GATE_UNUSED_ARG(count);
2174 GATE_UNUSED_ARG(bytes_sent);
2175 return GATE_RESULT_NOTIMPLEMENTED;
2176 }
2177
2178 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)
2179 {
2180 GATE_UNUSED_ARG(ptr_device_handle);
2181 GATE_UNUSED_ARG(i2c_address);
2182 GATE_UNUSED_ARG(content);
2183 GATE_UNUSED_ARG(content_length);
2184 GATE_UNUSED_ARG(bytes_received);
2185 return GATE_RESULT_NOTIMPLEMENTED;
2186 }
2187
2188 #endif /* GATE_IO_I2CDEVICE_NO_IMPL */
2189
2190
2191
2192 #if defined(GATE_IO_SPIDEVICE_IOCTL_IMPL)
2193
2194 #include <stdio.h>
2195 #include <stdlib.h>
2196 #include <stdint.h>
2197 #include <fcntl.h>
2198 #include <unistd.h>
2199 #include <linux/spi/spidev.h>
2200 #include <sys/ioctl.h>
2201
2202 1 gate_result_t gate_spidevice_default_path(gate_string_t* device_path)
2203 {
2204 1 return default_path_from_env_var_or_hardcoded(device_path, "GATE_SPI_DEVICE_PATH", "/dev/spidev0.0");
2205 }
2206
2207 1 gate_result_t gate_spidevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_spidevice_t* ptr_device_handle)
2208 {
2209 gate_result_t ret;
2210 1 gate_cstrbuffer_t buffer = GATE_INIT_EMPTY;
2211
2212 do
2213 {
2214 int fd;
2215
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (gate_string_is_empty(device_path))
2216 {
2217 1 ret = GATE_RESULT_INVALIDARG;
2218 1 break;
2219 }
2220 ✗ if (NULL == gate_cstrbuffer_create_string(&buffer, device_path, false))
2221 {
2222 ✗ ret = GATE_RESULT_OUTOFMEMORY;
2223 ✗ break;
2224 }
2225
2226 ✗ fd = gate_posix_open(gate_cstrbuffer_get(&buffer), O_RDWR, 0);
2227 ✗ if (fd == -1)
2228 {
2229 ✗ ret = GATE_RESULT_NOTAVAILABLE;
2230 ✗ break;
2231 }
2232
2233 /* success case reached */
2234 ✗ ret = GATE_RESULT_OK;
2235 ✗ if (ptr_device_handle)
2236 {
2237 ✗ *ptr_device_handle = (gate_spidevice_t)(gate_intptr_t)fd;
2238 }
2239 else
2240 {
2241 ✗ gate_posix_close(fd);
2242 }
2243 } while (0);
2244 1 gate_cstrbuffer_destroy(&buffer);
2245 1 return ret;
2246
2247 }
2248
2249 ✗ gate_result_t gate_spidevice_close(gate_spidevice_t* ptr_device_handle)
2250 {
2251 ✗ if (!ptr_device_handle)
2252 {
2253 ✗ return GATE_RESULT_INVALIDARG;
2254 }
2255 else
2256 {
2257 ✗ const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
2258 ✗ if (fd != -1)
2259 {
2260 ✗ gate_posix_close(fd);
2261 ✗ *ptr_device_handle = (gate_spidevice_t)(gate_intptr_t)-1;
2262 }
2263 ✗ return GATE_RESULT_OK;
2264 }
2265 }
2266
2267 ✗ static gate_uint8_t get_spi_mode(gate_enumint_t spi_mode)
2268 {
2269 ✗ switch(spi_mode)
2270 {
2271 ✗ default:
2272 ✗ case 0: return SPI_MODE_0;
2273 ✗ case 1: return SPI_MODE_1;
2274 ✗ case 2: return SPI_MODE_2;
2275 ✗ case 3: return SPI_MODE_3;
2276 }
2277 }
2278
2279 ✗ 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)
2280 {
2281 gate_result_t ret;
2282 ✗ if (ptr_device_handle == NULL)
2283 {
2284 ✗ return GATE_RESULT_INVALIDARG;
2285 }
2286
2287 do
2288 {
2289 ✗ const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
2290 ✗ uint8_t mode = get_spi_mode(spi_mode);
2291 ✗ uint8_t bits = 8;
2292
2293 /* set SPI mode */
2294 ✗ if (gate_posix_ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0)
2295 {
2296 ✗ ret = GATE_RESULT_FAILED;
2297 ✗ break;
2298 }
2299
2300 /* set bits per word */
2301 ✗ if (gate_posix_ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0)
2302 {
2303 ✗ ret = GATE_RESULT_FAILED;
2304 ✗ break;
2305 }
2306
2307 /* success state reached */
2308 ✗ ret = GATE_RESULT_OK;
2309 } while (0);
2310
2311 ✗ return ret;
2312 }
2313
2314 ✗ gate_result_t gate_spidevice_transfer(gate_spidevice_t* ptr_device_handle, void const* send_buffer, void* receive_buffer, gate_size_t buffer_length)
2315 {
2316 gate_result_t ret;
2317 ✗ if (ptr_device_handle == NULL)
2318 {
2319 ✗ return GATE_RESULT_INVALIDARG;
2320 }
2321
2322 do
2323 {
2324 ✗ const int fd = (int)(gate_intptr_t)(*ptr_device_handle);
2325 struct spi_ioc_transfer message;
2326
2327 ✗ gate_mem_clear(&message, sizeof(message));
2328 ✗ message.tx_buf = (gate_uintptr_t)send_buffer;
2329 ✗ message.rx_buf = (gate_uintptr_t)receive_buffer;
2330 ✗ message.len = buffer_length;
2331 ✗ message.speed_hz = 0; /* override speed, 0: do not override */
2332 ✗ message.delay_usecs = 0;
2333 ✗ message.bits_per_word = 8; /* bits per word in general */
2334 ✗ message.cs_change = 0;
2335 ✗ message.tx_nbits = 8; /* bits per tx word */
2336 ✗ message.rx_nbits = 8; /* bits per rx word*/
2337
2338 ✗ if (gate_posix_ioctl(fd, SPI_IOC_MESSAGE(1), &message) < 0)
2339 {
2340 ✗ ret = GATE_RESULT_FAILED;
2341 ✗ break;
2342 }
2343
2344 /* success case reached */
2345 ✗ ret = GATE_RESULT_OK;
2346 } while (0);
2347
2348 ✗ return ret;
2349 }
2350
2351 ✗ gate_result_t gate_spidevice_end_transaction(gate_spidevice_t* ptr_device_handle)
2352 {
2353 ✗ if (ptr_device_handle == NULL)
2354 {
2355 ✗ return GATE_RESULT_INVALIDARG;
2356 }
2357 else
2358 {
2359 /* nothing to do */
2360 ✗ return GATE_RESULT_OK;
2361 }
2362 }
2363
2364 #endif /* GATE_IO_SPIDEVICE_IOCTL_IMPL */
2365
2366
2367
2368 #if defined(GATE_IO_SPIDEVICE_ARDUINO_IMPL)
2369
2370 #include "carduino.h"
2371
2372 static gate_spidevice_t invalid_spidevice = (gate_spidevice_t)0x00;
2373 static gate_spidevice_t default_spidevice = (gate_spidevice_t)0x02;
2374
2375 gate_result_t gate_spidevice_default_path(gate_string_t* device_path)
2376 {
2377 gate_string_create_empty(device_path);
2378 return GATE_RESULT_OK;
2379 }
2380
2381 gate_result_t gate_spidevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_spidevice_t* ptr_device_handle)
2382 {
2383 *ptr_device_handle = default_spidevice;
2384 return GATE_RESULT_OK;
2385 }
2386
2387 gate_result_t gate_spidevice_close(gate_spidevice_t* ptr_device_handle)
2388 {
2389 *ptr_device_handle = invalid_spidevice;
2390 return GATE_RESULT_OK;
2391 }
2392
2393 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)
2394 {
2395 if ((ptr_device_handle == NULL) || (*ptr_device_handle == invalid_spidevice))
2396 {
2397 return GATE_RESULT_INVALIDARG;
2398 }
2399 else
2400 {
2401 carduino_spi_begin(
2402 speed,
2403 GATE_FLAG_ENABLED(spi_flags, GATE_SPIDEVICE_FLAG_LSB),
2404 spi_mode);
2405 return GATE_RESULT_OK;
2406 }
2407 }
2408
2409 gate_result_t gate_spidevice_transfer(gate_spidevice_t* ptr_device_handle, void const* send_buffer, void* receive_buffer, gate_size_t buffer_length)
2410 {
2411 if ((ptr_device_handle == NULL) || (*ptr_device_handle == invalid_spidevice))
2412 {
2413 return GATE_RESULT_INVALIDARG;
2414 }
2415 else
2416 {
2417 if (receive_buffer != send_buffer)
2418 {
2419 gate_mem_copy(receive_buffer, send_buffer, buffer_length);
2420 }
2421 carduino_spi_transfer_buffer((unsigned char*)receive_buffer, buffer_length);
2422 return GATE_RESULT_OK;
2423 }
2424 }
2425
2426 gate_result_t gate_spidevice_end_transaction(gate_spidevice_t* ptr_device_handle)
2427 {
2428 carduino_spi_end();
2429 return GATE_RESULT_OK;
2430 }
2431
2432 #endif /* GATE_IO_SPIDEVICE_ARDUINO_IMPL */
2433
2434
2435
2436 #if defined(GATE_IO_SPIDEVICE_NO_IMPL)
2437
2438 gate_result_t gate_spidevice_default_path(gate_string_t* device_path)
2439 {
2440 GATE_UNUSED_ARG(device_path);
2441 return GATE_RESULT_NOTIMPLEMENTED;
2442 }
2443
2444 gate_result_t gate_spidevice_open(gate_string_t const* device_path, gate_enumint_t flags, gate_spidevice_t* ptr_device_handle)
2445 {
2446 GATE_UNUSED_ARG(device_path);
2447 GATE_UNUSED_ARG(flags);
2448 GATE_UNUSED_ARG(ptr_device_handle);
2449 return GATE_RESULT_NOTIMPLEMENTED;
2450 }
2451
2452 gate_result_t gate_spidevice_close(gate_spidevice_t* ptr_device_handle)
2453 {
2454 GATE_UNUSED_ARG(ptr_device_handle);
2455 return GATE_RESULT_NOTIMPLEMENTED;
2456 }
2457
2458 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)
2459 {
2460 GATE_UNUSED_ARG(ptr_device_handle);
2461 GATE_UNUSED_ARG(speed);
2462 GATE_UNUSED_ARG(spi_mode);
2463 GATE_UNUSED_ARG(spi_flags);
2464 return GATE_RESULT_NOTIMPLEMENTED;
2465 }
2466
2467 gate_result_t gate_spidevice_transfer(gate_spidevice_t* ptr_device_handle, void const* send_buffer, void* receive_buffer, gate_size_t buffer_length)
2468 {
2469 GATE_UNUSED_ARG(ptr_device_handle);
2470 GATE_UNUSED_ARG(send_buffer);
2471 GATE_UNUSED_ARG(receive_buffer);
2472 GATE_UNUSED_ARG(buffer_length);
2473 return GATE_RESULT_NOTIMPLEMENTED;
2474 }
2475
2476 gate_result_t gate_spidevice_end_transaction(gate_spidevice_t* ptr_device_handle)
2477 {
2478 GATE_UNUSED_ARG(ptr_device_handle);
2479 return GATE_RESULT_NOTIMPLEMENTED;
2480 }
2481
2482 #endif /* GATE_IO_SPIDEVICE_NO_IMPL */
2483