mraa.c: subplatforms need to be defined after platforms
[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 #if defined(X86PLAT)
105     // Use runtime x86 platform detection
106     platform_type = mraa_x86_platform();
107 #elif defined(ARMPLAT)
108     // Use runtime ARM platform detection
109     platform_type = mraa_arm_platform();
110 #else
111 #error mraa_ARCH NOTHING
112 #endif
113
114 #ifdef USBPLAT
115     // This is a platform extender so create null base platform if one doesn't already exist
116     if (plat == NULL) {
117         plat = (mraa_board_t*) calloc(1, sizeof(mraa_board_t));
118         plat->platform_name = "Null platform";
119         if (plat != NULL) {
120             int usb_platform_type = mraa_usb_platform_extender(plat);
121             if (platform_type == MRAA_UNKNOWN_PLATFORM)
122                 platform_type = usb_platform_type;
123         }
124     }
125     if (plat == NULL) {
126         printf("mraa: FATAL error, failed to initialise platform\n");
127         return MRAA_ERROR_PLATFORM_NOT_INITIALISED;
128     }
129 #endif
130
131     syslog(LOG_NOTICE, "libmraa initialised for platform '%s' of type %d", mraa_get_platform_name(), platform_type);
132     return MRAA_SUCCESS;
133 }
134
135 void
136 mraa_deinit()
137 {
138     if (plat != NULL) {
139         if (plat->pins != NULL) {
140             free(plat->pins);
141         }
142         free(plat);
143     }
144     closelog();
145 }
146
147 int
148 mraa_set_priority(const unsigned int priority)
149 {
150     struct sched_param sched_s;
151
152     memset(&sched_s, 0, sizeof(struct sched_param));
153     if (priority > sched_get_priority_max(SCHED_RR)) {
154         sched_s.sched_priority = sched_get_priority_max(SCHED_RR);
155     } else {
156         sched_s.sched_priority = priority;
157     }
158
159     return sched_setscheduler(0, SCHED_RR, &sched_s);
160 }
161
162 mraa_result_t
163 mraa_setup_mux_mapped(mraa_pin_t meta)
164 {
165     int mi;
166
167     for (mi = 0; mi < meta.mux_total; mi++) {
168         mraa_gpio_context mux_i;
169         mux_i = mraa_gpio_init_raw(meta.mux[mi].pin);
170         if (mux_i == NULL) {
171             return MRAA_ERROR_INVALID_HANDLE;
172         }
173         // this function will sometimes fail, however this is not critical as
174         // long as the write succeeds - Test case galileo gen2 pin2
175         mraa_gpio_dir(mux_i, MRAA_GPIO_OUT);
176         mraa_gpio_owner(mux_i, 0);
177
178         if (mraa_gpio_write(mux_i, meta.mux[mi].value) != MRAA_SUCCESS) {
179             mraa_gpio_close(mux_i);
180             return MRAA_ERROR_INVALID_RESOURCE;
181         }
182         mraa_gpio_close(mux_i);
183     }
184
185     return MRAA_SUCCESS;
186 }
187
188 void
189 mraa_result_print(mraa_result_t result)
190 {
191     switch (result) {
192         case MRAA_SUCCESS:
193             fprintf(stdout, "MRAA: SUCCESS\n");
194             break;
195         case MRAA_ERROR_FEATURE_NOT_IMPLEMENTED:
196             fprintf(stdout, "MRAA: Feature not implemented.\n");
197             break;
198         case MRAA_ERROR_FEATURE_NOT_SUPPORTED:
199             fprintf(stdout, "MRAA: Feature not supported by Hardware.\n");
200             break;
201         case MRAA_ERROR_INVALID_VERBOSITY_LEVEL:
202             fprintf(stdout, "MRAA: Invalid verbosity level.\n");
203             break;
204         case MRAA_ERROR_INVALID_PARAMETER:
205             fprintf(stdout, "MRAA: Invalid parameter.\n");
206             break;
207         case MRAA_ERROR_INVALID_HANDLE:
208             fprintf(stdout, "MRAA: Invalid Handle.\n");
209             break;
210         case MRAA_ERROR_NO_RESOURCES:
211             fprintf(stdout, "MRAA: No resources.\n");
212             break;
213         case MRAA_ERROR_INVALID_RESOURCE:
214             fprintf(stdout, "MRAA: Invalid resource.\n");
215             break;
216         case MRAA_ERROR_INVALID_QUEUE_TYPE:
217             fprintf(stdout, "MRAA: Invalid Queue Type.\n");
218             break;
219         case MRAA_ERROR_NO_DATA_AVAILABLE:
220             fprintf(stdout, "MRAA: No Data available.\n");
221             break;
222         case MRAA_ERROR_INVALID_PLATFORM:
223             fprintf(stdout, "MRAA: Platform not recognised.\n");
224             break;
225         case MRAA_ERROR_PLATFORM_NOT_INITIALISED:
226             fprintf(stdout, "MRAA: Platform not initialised.\n");
227             break;
228         case MRAA_ERROR_PLATFORM_ALREADY_INITIALISED:
229             fprintf(stdout, "MRAA: Platform already initialised.\n");
230             break;
231         case MRAA_ERROR_UNSPECIFIED:
232             fprintf(stdout, "MRAA: Unspecified Error.\n");
233             break;
234         default:
235             fprintf(stdout, "MRAA: Unrecognised error.\n");
236             break;
237     }
238 }
239
240 mraa_boolean_t
241 mraa_pin_mode_test(int pin, mraa_pinmodes_t mode)
242 {
243     if (plat == NULL) {
244         return 0;
245     }
246     if (pin > (plat->phy_pin_count - 1) || pin < 0)
247         return 0;
248
249     switch (mode) {
250         case MRAA_PIN_VALID:
251             if (plat->pins[pin].capabilites.valid == 1)
252                 return 1;
253             break;
254         case MRAA_PIN_GPIO:
255             if (plat->pins[pin].capabilites.gpio == 1)
256                 return 1;
257             break;
258         case MRAA_PIN_PWM:
259             if (plat->pins[pin].capabilites.pwm == 1)
260                 return 1;
261             break;
262         case MRAA_PIN_FAST_GPIO:
263             if (plat->pins[pin].capabilites.fast_gpio == 1)
264                 return 1;
265             break;
266         case MRAA_PIN_SPI:
267             if (plat->pins[pin].capabilites.spi == 1)
268                 return 1;
269             break;
270         case MRAA_PIN_I2C:
271             if (plat->pins[pin].capabilites.i2c == 1)
272                 return 1;
273             break;
274         case MRAA_PIN_AIO:
275             if (plat->pins[pin].capabilites.aio == 1)
276                 return 1;
277             break;
278         case MRAA_PIN_UART:
279             if (plat->pins[pin].capabilites.uart == 1)
280                 return 1;
281             break;
282         default:
283             syslog(LOG_NOTICE, "requested pinmode invalid");
284             break;
285     }
286     return 0;
287 }
288
289 mraa_platform_t
290 mraa_get_platform_type()
291 {
292     return platform_type;
293 }
294
295 unsigned int
296 mraa_adc_raw_bits()
297 {
298     if (plat == NULL)
299         return 0;
300
301     if (plat->aio_count == 0)
302         return 0;
303
304     return plat->adc_raw;
305 }
306
307 unsigned int
308 mraa_adc_supported_bits()
309 {
310     if (plat == NULL)
311         return 0;
312
313     if (plat->aio_count == 0)
314         return 0;
315
316     return plat->adc_supported;
317 }
318
319 char*
320 mraa_get_platform_name()
321 {
322     if (plat == NULL) {
323         return NULL;
324     }
325     return (char*) plat->platform_name;
326 }
327
328 int
329 mraa_get_i2c_bus_count()
330 {
331     if (plat == NULL) {
332         return -1;
333     }
334     return plat->i2c_bus_count;
335 }
336
337 int
338 mraa_get_i2c_bus_id(unsigned i2c_bus)
339 {
340     if (plat == NULL) {
341         return -1;
342     }
343
344     if (i2c_bus >= plat->i2c_bus_count) {
345         return -1;
346     }
347
348     return plat->i2c_bus[i2c_bus].bus_id;
349 }
350
351 unsigned int
352 mraa_get_pin_count()
353 {
354     if (plat == NULL) {
355         return 0;
356     }
357     return plat->phy_pin_count;
358 }
359
360 char*
361 mraa_get_pin_name(int pin)
362 {
363     if (plat == NULL) {
364         return NULL;
365     }
366     if (pin > (plat->phy_pin_count - 1) || pin < 0)
367         return NULL;
368     return (char*) plat->pins[pin].name;
369 }
370
371 int
372 mraa_get_default_i2c_bus()
373 {
374     if (plat == NULL) {
375         return -1;
376     } else
377         return plat->def_i2c_bus;
378 }
379
380
381
382 mraa_boolean_t
383 mraa_file_exist(const char* filename)
384 {
385     glob_t results;
386     results.gl_pathc = 0;
387     glob(filename, 0, NULL, &results);
388     int file_found = results.gl_pathc == 1;
389     globfree(&results);
390     return file_found;
391 }
392
393 mraa_boolean_t
394 mraa_file_contains(const char* filename, const char* content)
395 {
396     mraa_boolean_t found = 0;
397     if ((filename == NULL) || (content == NULL)) {
398         return 0;
399     }
400
401     char* file = mraa_file_unglob(filename);
402     if (file != NULL) {
403         size_t len = 1024;
404         char* line = malloc(len);
405         if (line == NULL) {
406             free(file);
407             return 0;
408         }
409         FILE* fh = fopen(file, "r");
410         if (fh == NULL) {
411             free(file);
412             free(line);
413             return 0;
414         }
415         while ((getline(&line, &len, fh) != -1) && (found == 0)) {
416             if (strstr(line, content)) {
417                 found = 1;
418                 break;
419             }
420         }
421         fclose(fh);
422         free(file);
423         free(line);
424     }
425     return found;
426 }
427
428 mraa_boolean_t
429 mraa_file_contains_both(const char* filename, const char* content, const char* content2)
430 {
431     mraa_boolean_t found = 0;
432     if ((filename == NULL) || (content == NULL)) {
433         return 0;
434     }
435
436     char* file = mraa_file_unglob(filename);
437     if (file != NULL) {
438         size_t len = 1024;
439         char* line = malloc(len);
440         if (line == NULL) {
441             free(file);
442             return 0;
443         }
444         FILE* fh = fopen(file, "r");
445         if (fh == NULL) {
446             free(file);
447             free(line);
448             return 0;
449         }
450         while ((getline(&line, &len, fh) != -1) && (found == 0)) {
451             if (strstr(line, content) && strstr(line, content2)) {
452                 found = 1;
453                 break;
454             }
455         }
456         fclose(fh);
457         free(file);
458         free(line);
459     }
460     return found;
461 }
462
463 char*
464 mraa_file_unglob(const char* filename)
465 {
466     glob_t results;
467     char* res = NULL;
468     results.gl_pathc = 0;
469     glob(filename, 0, NULL, &results);
470     if (results.gl_pathc == 1)
471         res = strdup(results.gl_pathv[0]);
472     globfree(&results);
473     return res;
474 }
475
476 mraa_boolean_t
477 mraa_link_targets(const char* filename, const char* targetname)
478 {
479     int size = 100;
480     int nchars = 0;
481     char* buffer = NULL;
482     while (nchars == 0) {
483         buffer = (char*) realloc(buffer, size);
484         if (buffer == NULL)
485             return 0;
486         nchars = readlink(filename, buffer, size);
487         if (nchars < 0) {
488             free(buffer);
489             return 0;
490         } else {
491             buffer[nchars] = '\0';
492         }
493         if (nchars >= size) {
494             size *= 2;
495             nchars = 0;
496         }
497     }
498     if (strstr(buffer, targetname)) {
499         free(buffer);
500         return 1;
501     } else {
502         free(buffer);
503         return 0;
504     }
505 }
506
507 static int num_i2c_devices = 0;
508
509 static int
510 mraa_count_files(const char* path, const struct stat* sb, int flag, struct FTW* ftwb)
511 {
512     switch (sb->st_mode & S_IFMT) {
513         case S_IFLNK:
514             num_i2c_devices++;
515             break;
516     }
517     return 0;
518 }
519
520 int
521 mraa_find_i2c_bus(const char* devname, int startfrom)
522 {
523     char path[64];
524     int fd;
525     int i = startfrom;
526     int ret = -1;
527
528     // because feeding mraa_find_i2c_bus result back into the function is
529     // useful treat -1 as 0
530     if (startfrom < 0) {
531         startfrom = 0;
532     }
533
534     // find how many i2c buses we have if we haven't already
535     if (num_i2c_devices == 0) {
536         if (nftw("/sys/class/i2c-dev/", &mraa_count_files, 20, FTW_PHYS) == -1) {
537             return -1;
538         }
539     }
540
541     // i2c devices are numbered numerically so 0 must exist otherwise there is
542     // no i2c-dev loaded
543     if (mraa_file_exist("/sys/class/i2c-dev/i2c-0")) {
544         for (i; i < num_i2c_devices; i++) {
545             off_t size, err;
546             snprintf(path, 64, "/sys/class/i2c-dev/i2c-%u/name", i);
547             fd = open(path, O_RDONLY);
548             if (fd < 0) {
549                 break;
550             }
551             size = lseek(fd, 0, SEEK_END);
552             if (size < 0) {
553                 syslog(LOG_WARNING, "mraa: failed to seek i2c filename file");
554                 close(fd);
555                 break;
556             }
557             err = lseek(fd, 0, SEEK_SET);
558             if (err < 0) {
559                 syslog(LOG_WARNING, "mraa: failed to seek i2c filename file");
560                 close(fd);
561                 break;
562             }
563             char* value = malloc(size);
564             if (value == NULL) {
565                 syslog(LOG_ERR, "mraa: failed to allocate memory for i2c file");
566                 close(fd);
567                 break;
568             }
569             ssize_t r = read(fd, value, size);
570             if (r > 0) {
571                 if (strcasestr(value, devname) != NULL) {
572                     free(value);
573                     close(fd);
574                     return i;
575                 }
576             } else {
577                 syslog(LOG_ERR, "mraa: sysfs i2cdev failed");
578             }
579             free(value);
580             close(fd);
581         }
582     } else {
583         syslog(LOG_WARNING, "mraa: no i2c-dev detected, load i2c-dev");
584     }
585
586     return ret;
587 }