usb: Skeleton platform code for FTDI FT4222 USB to i2c bridge
[contrib/mraa.git] / src / mraa.c
1 /*
2  * Author: Brendan Le Foll <brendan.le.foll@intel.com>
3  * Author: Thomas Ingleby <thomas.c.ingleby@intel.com>
4  * Copyright (c) 2014 Intel Corporation.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 #define _GNU_SOURCE
27 #if !defined(_XOPEN_SOURCE) || _XOPEN_SOURCE < 600
28 #define _XOPEN_SOURCE 600 /* Get nftw() and S_IFSOCK declarations */
29 #endif
30
31 #include <stddef.h>
32 #include <stdlib.h>
33 #include <sched.h>
34 #include <string.h>
35 #include <pwd.h>
36 #include <glob.h>
37 #include <ftw.h>
38 #include <dirent.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <string.h>
42 #include <stdio.h>
43
44 #include "mraa_internal.h"
45 #include "gpio.h"
46 #include "version.h"
47
48 mraa_board_t* plat = NULL;
49 static mraa_platform_t platform_type = MRAA_UNKNOWN_PLATFORM;
50 mraa_adv_func_t* advance_func;
51
52 const char*
53 mraa_get_version()
54 {
55     return gVERSION;
56 }
57
58 mraa_result_t
59 mraa_set_log_level(int level)
60 {
61     if (level <= 7 && level >= 0) {
62         setlogmask(LOG_UPTO(level));
63         syslog(LOG_DEBUG, "Loglevel %d is set", level);
64         return MRAA_SUCCESS;
65     }
66     syslog(LOG_NOTICE, "Invalid loglevel %d requested", level);
67     return MRAA_ERROR_INVALID_PARAMETER;
68 }
69
70 #if (defined SWIGPYTHON) || (defined SWIG)
71 mraa_result_t
72 #else
73 mraa_result_t __attribute__((constructor))
74 #endif
75 mraa_init()
76 {
77     if (plat != NULL) {
78         return MRAA_ERROR_PLATFORM_ALREADY_INITIALISED;
79     }
80
81     uid_t proc_euid = geteuid();
82     struct passwd* proc_user = getpwuid(proc_euid);
83
84 #ifdef DEBUG
85     setlogmask(LOG_UPTO(LOG_DEBUG));
86 #else
87     setlogmask(LOG_UPTO(LOG_NOTICE));
88 #endif
89
90     openlog("libmraa", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
91     syslog(LOG_NOTICE, "libmraa version %s initialised by user '%s' with EUID %d",
92            mraa_get_version(), (proc_user != NULL) ? proc_user->pw_name : "<unknown>", proc_euid);
93
94 #ifdef SWIGPYTHON
95     // Initialise python threads, this allows use to grab the GIL when we are
96     // required to do so
97     Py_InitializeEx(0);
98     PyEval_InitThreads();
99 #endif
100
101     advance_func = (mraa_adv_func_t*) malloc(sizeof(mraa_adv_func_t));
102     memset(advance_func, 0, sizeof(mraa_adv_func_t));
103
104 #ifdef X86PLAT
105     // Use runtime x86 platform detection
106     platform_type = mraa_x86_platform();
107 #ifdef USBPLAT
108     // This is a platform extender so create null base platform if one doesn't already exist
109     if (plat == NULL) {
110         plat = (mraa_board_t*) calloc(1, sizeof(mraa_board_t));
111         plat->platform_name = "Null platform";
112         if (plat != NULL) {
113             int usb_platform_type = mraa_usb_platform_extender(plat);
114             if (platform_type == MRAA_UNKNOWN_PLATFORM)
115                 platform_type = usb_platform_type;
116         }
117     }
118 #endif
119
120 #if defined(ARMPLAT)
121     // Use runtime ARM platform detection
122     platform_type = mraa_arm_platform();
123 #endif
124
125     if (plat == NULL) {
126         printf("mraa: FATAL error, failed to initialise platform\n");
127         return MRAA_ERROR_PLATFORM_NOT_INITIALISED;
128     }
129
130     syslog(LOG_NOTICE, "libmraa initialised for platform '%s' of type %d", mraa_get_platform_name(), platform_type);
131     return MRAA_SUCCESS;
132 }
133
134 void
135 mraa_deinit()
136 {
137     if (plat != NULL) {
138         if (plat->pins != NULL) {
139             free(plat->pins);
140         }
141         free(plat);
142     }
143     closelog();
144 }
145
146 int
147 mraa_set_priority(const unsigned int priority)
148 {
149     struct sched_param sched_s;
150
151     memset(&sched_s, 0, sizeof(struct sched_param));
152     if (priority > sched_get_priority_max(SCHED_RR)) {
153         sched_s.sched_priority = sched_get_priority_max(SCHED_RR);
154     } else {
155         sched_s.sched_priority = priority;
156     }
157
158     return sched_setscheduler(0, SCHED_RR, &sched_s);
159 }
160
161 mraa_result_t
162 mraa_setup_mux_mapped(mraa_pin_t meta)
163 {
164     int mi;
165
166     for (mi = 0; mi < meta.mux_total; mi++) {
167         mraa_gpio_context mux_i;
168         mux_i = mraa_gpio_init_raw(meta.mux[mi].pin);
169         if (mux_i == NULL) {
170             return MRAA_ERROR_INVALID_HANDLE;
171         }
172         // this function will sometimes fail, however this is not critical as
173         // long as the write succeeds - Test case galileo gen2 pin2
174         mraa_gpio_dir(mux_i, MRAA_GPIO_OUT);
175         mraa_gpio_owner(mux_i, 0);
176
177         if (mraa_gpio_write(mux_i, meta.mux[mi].value) != MRAA_SUCCESS) {
178             mraa_gpio_close(mux_i);
179             return MRAA_ERROR_INVALID_RESOURCE;
180         }
181         mraa_gpio_close(mux_i);
182     }
183
184     return MRAA_SUCCESS;
185 }
186
187 void
188 mraa_result_print(mraa_result_t result)
189 {
190     switch (result) {
191         case MRAA_SUCCESS:
192             fprintf(stdout, "MRAA: SUCCESS\n");
193             break;
194         case MRAA_ERROR_FEATURE_NOT_IMPLEMENTED:
195             fprintf(stdout, "MRAA: Feature not implemented.\n");
196             break;
197         case MRAA_ERROR_FEATURE_NOT_SUPPORTED:
198             fprintf(stdout, "MRAA: Feature not supported by Hardware.\n");
199             break;
200         case MRAA_ERROR_INVALID_VERBOSITY_LEVEL:
201             fprintf(stdout, "MRAA: Invalid verbosity level.\n");
202             break;
203         case MRAA_ERROR_INVALID_PARAMETER:
204             fprintf(stdout, "MRAA: Invalid parameter.\n");
205             break;
206         case MRAA_ERROR_INVALID_HANDLE:
207             fprintf(stdout, "MRAA: Invalid Handle.\n");
208             break;
209         case MRAA_ERROR_NO_RESOURCES:
210             fprintf(stdout, "MRAA: No resources.\n");
211             break;
212         case MRAA_ERROR_INVALID_RESOURCE:
213             fprintf(stdout, "MRAA: Invalid resource.\n");
214             break;
215         case MRAA_ERROR_INVALID_QUEUE_TYPE:
216             fprintf(stdout, "MRAA: Invalid Queue Type.\n");
217             break;
218         case MRAA_ERROR_NO_DATA_AVAILABLE:
219             fprintf(stdout, "MRAA: No Data available.\n");
220             break;
221         case MRAA_ERROR_INVALID_PLATFORM:
222             fprintf(stdout, "MRAA: Platform not recognised.\n");
223             break;
224         case MRAA_ERROR_PLATFORM_NOT_INITIALISED:
225             fprintf(stdout, "MRAA: Platform not initialised.\n");
226             break;
227         case MRAA_ERROR_PLATFORM_ALREADY_INITIALISED:
228             fprintf(stdout, "MRAA: Platform already initialised.\n");
229             break;
230         case MRAA_ERROR_UNSPECIFIED:
231             fprintf(stdout, "MRAA: Unspecified Error.\n");
232             break;
233         default:
234             fprintf(stdout, "MRAA: Unrecognised error.\n");
235             break;
236     }
237 }
238
239 mraa_boolean_t
240 mraa_pin_mode_test(int pin, mraa_pinmodes_t mode)
241 {
242     if (plat == NULL) {
243         return 0;
244     }
245     if (pin > (plat->phy_pin_count - 1) || pin < 0)
246         return 0;
247
248     switch (mode) {
249         case MRAA_PIN_VALID:
250             if (plat->pins[pin].capabilites.valid == 1)
251                 return 1;
252             break;
253         case MRAA_PIN_GPIO:
254             if (plat->pins[pin].capabilites.gpio == 1)
255                 return 1;
256             break;
257         case MRAA_PIN_PWM:
258             if (plat->pins[pin].capabilites.pwm == 1)
259                 return 1;
260             break;
261         case MRAA_PIN_FAST_GPIO:
262             if (plat->pins[pin].capabilites.fast_gpio == 1)
263                 return 1;
264             break;
265         case MRAA_PIN_SPI:
266             if (plat->pins[pin].capabilites.spi == 1)
267                 return 1;
268             break;
269         case MRAA_PIN_I2C:
270             if (plat->pins[pin].capabilites.i2c == 1)
271                 return 1;
272             break;
273         case MRAA_PIN_AIO:
274             if (plat->pins[pin].capabilites.aio == 1)
275                 return 1;
276             break;
277         case MRAA_PIN_UART:
278             if (plat->pins[pin].capabilites.uart == 1)
279                 return 1;
280             break;
281         default:
282             syslog(LOG_NOTICE, "requested pinmode invalid");
283             break;
284     }
285     return 0;
286 }
287
288 mraa_platform_t
289 mraa_get_platform_type()
290 {
291     return platform_type;
292 }
293
294 unsigned int
295 mraa_adc_raw_bits()
296 {
297     if (plat == NULL)
298         return 0;
299
300     if (plat->aio_count == 0)
301         return 0;
302
303     return plat->adc_raw;
304 }
305
306 unsigned int
307 mraa_adc_supported_bits()
308 {
309     if (plat == NULL)
310         return 0;
311
312     if (plat->aio_count == 0)
313         return 0;
314
315     return plat->adc_supported;
316 }
317
318 char*
319 mraa_get_platform_name()
320 {
321     if (plat == NULL) {
322         return NULL;
323     }
324     return (char*) plat->platform_name;
325 }
326
327 int
328 mraa_get_i2c_bus_count()
329 {
330     if (plat == NULL) {
331         return -1;
332     }
333     return plat->i2c_bus_count;
334 }
335
336 int
337 mraa_get_i2c_bus_id(unsigned i2c_bus)
338 {
339     if (plat == NULL) {
340         return -1;
341     }
342
343     if (i2c_bus >= plat->i2c_bus_count) {
344         return -1;
345     }
346
347     return plat->i2c_bus[i2c_bus].bus_id;
348 }
349
350 unsigned int
351 mraa_get_pin_count()
352 {
353     if (plat == NULL) {
354         return 0;
355     }
356     return plat->phy_pin_count;
357 }
358
359 char*
360 mraa_get_pin_name(int pin)
361 {
362     if (plat == NULL) {
363         return NULL;
364     }
365     if (pin > (plat->phy_pin_count - 1) || pin < 0)
366         return NULL;
367     return (char*) plat->pins[pin].name;
368 }
369
370 int
371 mraa_get_default_i2c_bus()
372 {
373     if (plat == NULL) {
374         return -1;
375     } else
376         return plat->def_i2c_bus;
377 }
378
379
380
381 mraa_boolean_t
382 mraa_file_exist(const char* filename)
383 {
384     glob_t results;
385     results.gl_pathc = 0;
386     glob(filename, 0, NULL, &results);
387     int file_found = results.gl_pathc == 1;
388     globfree(&results);
389     return file_found;
390 }
391
392 mraa_boolean_t
393 mraa_file_contains(const char* filename, const char* content)
394 {
395     mraa_boolean_t found = 0;
396     if ((filename == NULL) || (content == NULL)) {
397         return 0;
398     }
399
400     char* file = mraa_file_unglob(filename);
401     if (file != NULL) {
402         size_t len = 1024;
403         char* line = malloc(len);
404         if (line == NULL) {
405             free(file);
406             return 0;
407         }
408         FILE* fh = fopen(file, "r");
409         if (fh == NULL) {
410             free(file);
411             free(line);
412             return 0;
413         }
414         while ((getline(&line, &len, fh) != -1) && (found == 0)) {
415             if (strstr(line, content)) {
416                 found = 1;
417                 break;
418             }
419         }
420         fclose(fh);
421         free(file);
422         free(line);
423     }
424     return found;
425 }
426
427 mraa_boolean_t
428 mraa_file_contains_both(const char* filename, const char* content, const char* content2)
429 {
430     mraa_boolean_t found = 0;
431     if ((filename == NULL) || (content == NULL)) {
432         return 0;
433     }
434
435     char* file = mraa_file_unglob(filename);
436     if (file != NULL) {
437         size_t len = 1024;
438         char* line = malloc(len);
439         if (line == NULL) {
440             free(file);
441             return 0;
442         }
443         FILE* fh = fopen(file, "r");
444         if (fh == NULL) {
445             free(file);
446             free(line);
447             return 0;
448         }
449         while ((getline(&line, &len, fh) != -1) && (found == 0)) {
450             if (strstr(line, content) && strstr(line, content2)) {
451                 found = 1;
452                 break;
453             }
454         }
455         fclose(fh);
456         free(file);
457         free(line);
458     }
459     return found;
460 }
461
462 char*
463 mraa_file_unglob(const char* filename)
464 {
465     glob_t results;
466     char* res = NULL;
467     results.gl_pathc = 0;
468     glob(filename, 0, NULL, &results);
469     if (results.gl_pathc == 1)
470         res = strdup(results.gl_pathv[0]);
471     globfree(&results);
472     return res;
473 }
474
475 mraa_boolean_t
476 mraa_link_targets(const char* filename, const char* targetname)
477 {
478     int size = 100;
479     int nchars = 0;
480     char* buffer = NULL;
481     while (nchars == 0) {
482         buffer = (char*) realloc(buffer, size);
483         if (buffer == NULL)
484             return 0;
485         nchars = readlink(filename, buffer, size);
486         if (nchars < 0) {
487             free(buffer);
488             return 0;
489         } else {
490             buffer[nchars] = '\0';
491         }
492         if (nchars >= size) {
493             size *= 2;
494             nchars = 0;
495         }
496     }
497     if (strstr(buffer, targetname)) {
498         free(buffer);
499         return 1;
500     } else {
501         free(buffer);
502         return 0;
503     }
504 }
505
506 static int num_i2c_devices = 0;
507
508 static int
509 mraa_count_files(const char* path, const struct stat* sb, int flag, struct FTW* ftwb)
510 {
511     switch (sb->st_mode & S_IFMT) {
512         case S_IFLNK:
513             num_i2c_devices++;
514             break;
515     }
516     return 0;
517 }
518
519 int
520 mraa_find_i2c_bus(const char* devname, int startfrom)
521 {
522     char path[64];
523     int fd;
524     int i = startfrom;
525     int ret = -1;
526
527     // because feeding mraa_find_i2c_bus result back into the function is
528     // useful treat -1 as 0
529     if (startfrom < 0) {
530         startfrom = 0;
531     }
532
533     // find how many i2c buses we have if we haven't already
534     if (num_i2c_devices == 0) {
535         if (nftw("/sys/class/i2c-dev/", &mraa_count_files, 20, FTW_PHYS) == -1) {
536             return -1;
537         }
538     }
539
540     // i2c devices are numbered numerically so 0 must exist otherwise there is
541     // no i2c-dev loaded
542     if (mraa_file_exist("/sys/class/i2c-dev/i2c-0")) {
543         for (i; i < num_i2c_devices; i++) {
544             off_t size, err;
545             snprintf(path, 64, "/sys/class/i2c-dev/i2c-%u/name", i);
546             fd = open(path, O_RDONLY);
547             if (fd < 0) {
548                 break;
549             }
550             size = lseek(fd, 0, SEEK_END);
551             if (size < 0) {
552                 syslog(LOG_WARNING, "mraa: failed to seek i2c filename file");
553                 close(fd);
554                 break;
555             }
556             err = lseek(fd, 0, SEEK_SET);
557             if (err < 0) {
558                 syslog(LOG_WARNING, "mraa: failed to seek i2c filename file");
559                 close(fd);
560                 break;
561             }
562             char* value = malloc(size);
563             if (value == NULL) {
564                 syslog(LOG_ERR, "mraa: failed to allocate memory for i2c file");
565                 close(fd);
566                 break;
567             }
568             ssize_t r = read(fd, value, size);
569             if (r > 0) {
570                 if (strcasestr(value, devname) != NULL) {
571                     free(value);
572                     close(fd);
573                     return i;
574                 }
575             } else {
576                 syslog(LOG_ERR, "mraa: sysfs i2cdev failed");
577             }
578             free(value);
579             close(fd);
580         }
581     } else {
582         syslog(LOG_WARNING, "mraa: no i2c-dev detected, load i2c-dev");
583     }
584
585     return ret;
586 }