api: Added API calls that support both main and sub 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 #define MAX_PLATFORM_NAME_LENGTH 128
49 mraa_board_t* plat = NULL;
50 // static mraa_board_t* current_plat = NULL;
51
52 static char platform_name[MAX_PLATFORM_NAME_LENGTH];
53 mraa_adv_func_t* advance_func;
54
55 const char*
56 mraa_get_version()
57 {
58     return gVERSION;
59 }
60
61 mraa_result_t
62 mraa_set_log_level(int level)
63 {
64     if (level <= 7 && level >= 0) {
65         setlogmask(LOG_UPTO(level));
66         syslog(LOG_DEBUG, "Loglevel %d is set", level);
67         return MRAA_SUCCESS;
68     }
69     syslog(LOG_NOTICE, "Invalid loglevel %d requested", level);
70     return MRAA_ERROR_INVALID_PARAMETER;
71 }
72
73 #if (defined SWIGPYTHON) || (defined SWIG)
74 mraa_result_t
75 #else
76 mraa_result_t __attribute__((constructor))
77 #endif
78 mraa_init()
79 {
80     if (plat != NULL) {
81         return MRAA_ERROR_PLATFORM_ALREADY_INITIALISED;
82     }
83
84     uid_t proc_euid = geteuid();
85     struct passwd* proc_user = getpwuid(proc_euid);
86
87 #ifdef DEBUG
88     setlogmask(LOG_UPTO(LOG_DEBUG));
89 #else
90     setlogmask(LOG_UPTO(LOG_NOTICE));
91 #endif
92
93     openlog("libmraa", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
94     syslog(LOG_NOTICE, "libmraa version %s initialised by user '%s' with EUID %d",
95            mraa_get_version(), (proc_user != NULL) ? proc_user->pw_name : "<unknown>", proc_euid);
96
97 #ifdef SWIGPYTHON
98     // Initialise python threads, this allows use to grab the GIL when we are
99     // required to do so
100     Py_InitializeEx(0);
101     PyEval_InitThreads();
102 #endif
103
104     advance_func = (mraa_adv_func_t*) malloc(sizeof(mraa_adv_func_t));
105     memset(advance_func, 0, sizeof(mraa_adv_func_t));
106
107     mraa_platform_t platform_type;
108 #if defined(X86PLAT)
109     // Use runtime x86 platform detection
110     platform_type = mraa_x86_platform();
111     // x86 platforms have advanced_func table in board config structure
112     free(advance_func);
113     if (plat != NULL)
114         advance_func = plat->adv_func;
115 #elif defined(ARMPLAT)
116     // Use runtime ARM platform detection
117     platform_type = mraa_arm_platform();
118 #else
119 #error mraa_ARCH NOTHING
120 #endif
121
122     if (plat != NULL)
123         plat->platform_type = platform_type;
124
125 #if defined(USBPLAT)
126     // This is a platform extender so create null base platform if one doesn't already exist
127     if (plat == NULL) {
128         plat = (mraa_board_t*) calloc(1, sizeof(mraa_board_t));
129         if (plat != NULL) {
130             plat->platform_type = MRAA_NULL_PLATFORM;
131             plat->platform_name = "Null platform";
132         }
133     }
134     // Now detect sub platform
135     if (plat != NULL) {
136         mraa_platform_t usb_platform_type = mraa_usb_platform_extender(plat);
137         if (plat->platform_type == MRAA_UNKNOWN_PLATFORM && usb_platform_type != MRAA_UNKNOWN_PLATFORM) {
138             plat->platform_type = usb_platform_type;
139         } else {
140             return MRAA_ERROR_PLATFORM_NOT_INITIALISED;
141         }
142     }
143     if (plat == NULL) {
144         printf("mraa: FATAL error, failed to initialise platform\n");
145         return MRAA_ERROR_PLATFORM_NOT_INITIALISED;
146     }
147 #endif
148
149     syslog(LOG_NOTICE, "libmraa initialised for platform '%s' of type %d", mraa_get_platform_name(), mraa_get_platform_type());
150     return MRAA_SUCCESS;
151 }
152
153 void
154 mraa_deinit()
155 {
156     if (plat != NULL) {
157         if (plat->pins != NULL) {
158             free(plat->pins);
159         }
160         mraa_board_t* sub_plat = plat->sub_platform;
161         if (sub_plat != NULL) {        
162             if (sub_plat->pins != NULL) {
163                 free(sub_plat->pins);
164             }
165             free(sub_plat);        
166         }
167         free(plat);
168         
169     }
170     closelog();
171 }
172
173 int
174 mraa_set_priority(const unsigned int priority)
175 {
176     struct sched_param sched_s;
177
178     memset(&sched_s, 0, sizeof(struct sched_param));
179     if (priority > sched_get_priority_max(SCHED_RR)) {
180         sched_s.sched_priority = sched_get_priority_max(SCHED_RR);
181     } else {
182         sched_s.sched_priority = priority;
183     }
184
185     return sched_setscheduler(0, SCHED_RR, &sched_s);
186 }
187
188 mraa_result_t
189 mraa_setup_mux_mapped(mraa_pin_t meta)
190 {
191     int mi;
192
193     for (mi = 0; mi < meta.mux_total; mi++) {
194         mraa_gpio_context mux_i;
195         mux_i = mraa_gpio_init_raw(meta.mux[mi].pin);
196         if (mux_i == NULL) {
197             return MRAA_ERROR_INVALID_HANDLE;
198         }
199         // this function will sometimes fail, however this is not critical as
200         // long as the write succeeds - Test case galileo gen2 pin2
201         mraa_gpio_dir(mux_i, MRAA_GPIO_OUT);
202         mraa_gpio_owner(mux_i, 0);
203
204         if (mraa_gpio_write(mux_i, meta.mux[mi].value) != MRAA_SUCCESS) {
205             mraa_gpio_close(mux_i);
206             return MRAA_ERROR_INVALID_RESOURCE;
207         }
208         mraa_gpio_close(mux_i);
209     }
210
211     return MRAA_SUCCESS;
212 }
213
214 void
215 mraa_result_print(mraa_result_t result)
216 {
217     switch (result) {
218         case MRAA_SUCCESS:
219             fprintf(stdout, "MRAA: SUCCESS\n");
220             break;
221         case MRAA_ERROR_FEATURE_NOT_IMPLEMENTED:
222             fprintf(stdout, "MRAA: Feature not implemented.\n");
223             break;
224         case MRAA_ERROR_FEATURE_NOT_SUPPORTED:
225             fprintf(stdout, "MRAA: Feature not supported by Hardware.\n");
226             break;
227         case MRAA_ERROR_INVALID_VERBOSITY_LEVEL:
228             fprintf(stdout, "MRAA: Invalid verbosity level.\n");
229             break;
230         case MRAA_ERROR_INVALID_PARAMETER:
231             fprintf(stdout, "MRAA: Invalid parameter.\n");
232             break;
233         case MRAA_ERROR_INVALID_HANDLE:
234             fprintf(stdout, "MRAA: Invalid Handle.\n");
235             break;
236         case MRAA_ERROR_NO_RESOURCES:
237             fprintf(stdout, "MRAA: No resources.\n");
238             break;
239         case MRAA_ERROR_INVALID_RESOURCE:
240             fprintf(stdout, "MRAA: Invalid resource.\n");
241             break;
242         case MRAA_ERROR_INVALID_QUEUE_TYPE:
243             fprintf(stdout, "MRAA: Invalid Queue Type.\n");
244             break;
245         case MRAA_ERROR_NO_DATA_AVAILABLE:
246             fprintf(stdout, "MRAA: No Data available.\n");
247             break;
248         case MRAA_ERROR_INVALID_PLATFORM:
249             fprintf(stdout, "MRAA: Platform not recognised.\n");
250             break;
251         case MRAA_ERROR_PLATFORM_NOT_INITIALISED:
252             fprintf(stdout, "MRAA: Platform not initialised.\n");
253             break;
254         case MRAA_ERROR_PLATFORM_ALREADY_INITIALISED:
255             fprintf(stdout, "MRAA: Platform already initialised.\n");
256             break;
257         case MRAA_ERROR_UNSPECIFIED:
258             fprintf(stdout, "MRAA: Unspecified Error.\n");
259             break;
260         default:
261             fprintf(stdout, "MRAA: Unrecognised error.\n");
262             break;
263     }
264 }
265
266
267 mraa_boolean_t 
268 mraa_has_sub_platform()
269 {
270     return (plat != NULL) && (plat->sub_platform != NULL);
271 }
272
273
274 mraa_boolean_t
275 mraa_pin_mode_test(int pin, mraa_pinmodes_t mode)
276 {
277     if (plat == NULL)
278         return 0;
279
280     mraa_board_t* current_plat = plat;
281     if (mraa_is_sub_platform_id(pin)) {
282         current_plat = plat->sub_platform;
283         if (current_plat == NULL) {
284             syslog(LOG_ERR, "mraa_pin_mode_test: Sub platform Not Initialised");
285             return 0;
286         }
287         pin = mraa_get_sub_platform_index(pin);
288     }
289
290     if (current_plat == NULL || current_plat->platform_type == MRAA_UNKNOWN_PLATFORM) {
291         return 0;
292     }
293     if (pin > (current_plat->phy_pin_count - 1) || pin < 0)
294         return 0;
295
296     switch (mode) {
297         case MRAA_PIN_VALID:
298             if (current_plat->pins[pin].capabilites.valid == 1)
299                 return 1;
300             break;
301         case MRAA_PIN_GPIO:
302             if (current_plat->pins[pin].capabilites.gpio == 1)
303                 return 1;
304             break;
305         case MRAA_PIN_PWM:
306             if (current_plat->pins[pin].capabilites.pwm == 1)
307                 return 1;
308             break;
309         case MRAA_PIN_FAST_GPIO:
310             if (current_plat->pins[pin].capabilites.fast_gpio == 1)
311                 return 1;
312             break;
313         case MRAA_PIN_SPI:
314             if (current_plat->pins[pin].capabilites.spi == 1)
315                 return 1;
316             break;
317         case MRAA_PIN_I2C:
318             if (current_plat->pins[pin].capabilites.i2c == 1)
319                 return 1;
320             break;
321         case MRAA_PIN_AIO:
322             if (current_plat->pins[pin].capabilites.aio == 1)
323                 return 1;
324             break;
325         case MRAA_PIN_UART:
326             if (current_plat->pins[pin].capabilites.uart == 1)
327                 return 1;
328             break;
329         default:
330             syslog(LOG_NOTICE, "requested pinmode invalid");
331             break;
332     }
333     return 0;
334 }
335
336 mraa_platform_t
337 mraa_get_platform_type()
338 {
339     if (plat == NULL)
340         return MRAA_UNKNOWN_PLATFORM;
341     return plat->platform_type;
342 }
343
344 int
345 mraa_get_platform_combined_type()
346 {
347     int type = mraa_get_platform_type();
348     int sub_type = mraa_has_sub_platform() ? plat->sub_platform->platform_type : MRAA_UNKNOWN_PLATFORM;
349     return type | (sub_type << 8);
350 }
351
352 unsigned int
353 mraa_adc_raw_bits()
354 {
355     if (plat == NULL)
356         return 0;
357
358     if (plat->aio_count == 0)
359         return 0;
360
361     return plat->adc_raw;
362 }
363
364 unsigned int
365 mraa_get_platform_adc_raw_bits(uint8_t platform_offset)
366 {
367     if (platform_offset == MRAA_MAIN_PLATFORM_OFFSET)
368         return mraa_adc_raw_bits();
369     else {
370         if (!mraa_has_sub_platform())
371             return 0;
372
373         if (plat->sub_platform->aio_count == 0)
374             return 0;
375
376         return plat->sub_platform->adc_raw;
377     }
378 }
379
380
381 unsigned int
382 mraa_adc_supported_bits()
383 {
384     if (plat == NULL)
385         return 0;
386
387     if (plat->aio_count == 0)
388         return 0;
389
390     return plat->adc_supported;
391 }
392
393 unsigned int
394 mraa_get_platform_adc_supported_bits(int platform_offset)
395 {
396     if (platform_offset == MRAA_MAIN_PLATFORM_OFFSET)
397         return mraa_adc_supported_bits();
398     else {
399         if (!mraa_has_sub_platform())
400             return 0;
401
402         if (plat->sub_platform->aio_count == 0)
403             return 0;
404
405         return plat->sub_platform->adc_supported;
406     }
407 }
408
409
410 char*
411 mraa_get_platform_name()
412 {
413     if (plat == NULL) {
414         return NULL;
415     }
416     strncpy(platform_name, plat->platform_name, MAX_PLATFORM_NAME_LENGTH);
417     if (mraa_has_sub_platform()) {
418         strncat(platform_name, " + ", MAX_PLATFORM_NAME_LENGTH);
419         strncat(platform_name, plat->sub_platform->platform_name, MAX_PLATFORM_NAME_LENGTH);        
420     }
421     return platform_name;
422 }
423
424 int
425 mraa_get_i2c_bus_count()
426 {
427     if (plat == NULL) {
428         return -1;
429     }
430     return plat->i2c_bus_count;
431 }
432
433 int
434 mraa_get_i2c_bus_id(unsigned i2c_bus)
435 {
436     if (plat == NULL) {
437         return -1;
438     }
439
440     if (i2c_bus >= plat->i2c_bus_count) {
441         return -1;
442     }
443
444     return plat->i2c_bus[i2c_bus].bus_id;
445 }
446
447 unsigned int
448 mraa_get_pin_count()
449 {
450     if (plat == NULL) {
451         return 0;
452     }
453     return plat->phy_pin_count;
454 }
455
456 unsigned int
457 mraa_get_platform_pin_count(uint8_t platform_offset)
458 {
459     if (platform_offset == MRAA_MAIN_PLATFORM_OFFSET)
460         return mraa_get_pin_count();
461     else {
462         if (mraa_has_sub_platform())
463            return plat->sub_platform->phy_pin_count;
464         else
465            return 0;
466     }
467 }
468
469
470 char*
471 mraa_get_pin_name(int pin)
472 {
473     if (plat == NULL)
474         return 0;
475
476     mraa_board_t* current_plat = plat;
477     if (mraa_is_sub_platform_id(pin)) {
478         current_plat = plat->sub_platform;
479         if (current_plat == NULL) {
480             syslog(LOG_ERR, "mraa_get_pin_name: Sub platform Not Initialised");
481             return 0;
482         }
483         pin = mraa_get_sub_platform_index(pin);
484     }
485
486     if (pin > (current_plat->phy_pin_count - 1) || pin < 0)
487         return NULL;
488     return (char*) current_plat->pins[pin].name;
489 }
490
491 int
492 mraa_get_default_i2c_bus(uint8_t platform_offset)
493 {
494     if (plat == NULL) 
495         return -1;
496     if (platform_offset == MRAA_MAIN_PLATFORM_OFFSET) {
497         return plat->def_i2c_bus;
498     } else {
499         if (mraa_has_sub_platform())
500            return plat->sub_platform->def_i2c_bus;
501         else
502            return -1;
503     }
504 }
505
506
507 mraa_boolean_t
508 mraa_file_exist(const char* filename)
509 {
510     glob_t results;
511     results.gl_pathc = 0;
512     glob(filename, 0, NULL, &results);
513     int file_found = results.gl_pathc == 1;
514     globfree(&results);
515     return file_found;
516 }
517
518 mraa_boolean_t
519 mraa_file_contains(const char* filename, const char* content)
520 {
521     mraa_boolean_t found = 0;
522     if ((filename == NULL) || (content == NULL)) {
523         return 0;
524     }
525
526     char* file = mraa_file_unglob(filename);
527     if (file != NULL) {
528         size_t len = 1024;
529         char* line = malloc(len);
530         if (line == NULL) {
531             free(file);
532             return 0;
533         }
534         FILE* fh = fopen(file, "r");
535         if (fh == NULL) {
536             free(file);
537             free(line);
538             return 0;
539         }
540         while ((getline(&line, &len, fh) != -1) && (found == 0)) {
541             if (strstr(line, content)) {
542                 found = 1;
543                 break;
544             }
545         }
546         fclose(fh);
547         free(file);
548         free(line);
549     }
550     return found;
551 }
552
553 mraa_boolean_t
554 mraa_file_contains_both(const char* filename, const char* content, const char* content2)
555 {
556     mraa_boolean_t found = 0;
557     if ((filename == NULL) || (content == NULL)) {
558         return 0;
559     }
560
561     char* file = mraa_file_unglob(filename);
562     if (file != NULL) {
563         size_t len = 1024;
564         char* line = malloc(len);
565         if (line == NULL) {
566             free(file);
567             return 0;
568         }
569         FILE* fh = fopen(file, "r");
570         if (fh == NULL) {
571             free(file);
572             free(line);
573             return 0;
574         }
575         while ((getline(&line, &len, fh) != -1) && (found == 0)) {
576             if (strstr(line, content) && strstr(line, content2)) {
577                 found = 1;
578                 break;
579             }
580         }
581         fclose(fh);
582         free(file);
583         free(line);
584     }
585     return found;
586 }
587
588 char*
589 mraa_file_unglob(const char* filename)
590 {
591     glob_t results;
592     char* res = NULL;
593     results.gl_pathc = 0;
594     glob(filename, 0, NULL, &results);
595     if (results.gl_pathc == 1)
596         res = strdup(results.gl_pathv[0]);
597     globfree(&results);
598     return res;
599 }
600
601 mraa_boolean_t
602 mraa_link_targets(const char* filename, const char* targetname)
603 {
604     int size = 100;
605     int nchars = 0;
606     char* buffer = NULL;
607     while (nchars == 0) {
608         buffer = (char*) realloc(buffer, size);
609         if (buffer == NULL)
610             return 0;
611         nchars = readlink(filename, buffer, size);
612         if (nchars < 0) {
613             free(buffer);
614             return 0;
615         } else {
616             buffer[nchars] = '\0';
617         }
618         if (nchars >= size) {
619             size *= 2;
620             nchars = 0;
621         }
622     }
623     if (strstr(buffer, targetname)) {
624         free(buffer);
625         return 1;
626     } else {
627         free(buffer);
628         return 0;
629     }
630 }
631
632 static int num_i2c_devices = 0;
633
634 static int
635 mraa_count_files(const char* path, const struct stat* sb, int flag, struct FTW* ftwb)
636 {
637     switch (sb->st_mode & S_IFMT) {
638         case S_IFLNK:
639             num_i2c_devices++;
640             break;
641     }
642     return 0;
643 }
644
645 int
646 mraa_find_i2c_bus(const char* devname, int startfrom)
647 {
648     char path[64];
649     int fd;
650     int i = startfrom;
651     int ret = -1;
652
653     // because feeding mraa_find_i2c_bus result back into the function is
654     // useful treat -1 as 0
655     if (startfrom < 0) {
656         startfrom = 0;
657     }
658
659     // find how many i2c buses we have if we haven't already
660     if (num_i2c_devices == 0) {
661         if (nftw("/sys/class/i2c-dev/", &mraa_count_files, 20, FTW_PHYS) == -1) {
662             return -1;
663         }
664     }
665
666     // i2c devices are numbered numerically so 0 must exist otherwise there is
667     // no i2c-dev loaded
668     if (mraa_file_exist("/sys/class/i2c-dev/i2c-0")) {
669         for (i; i < num_i2c_devices; i++) {
670             off_t size, err;
671             snprintf(path, 64, "/sys/class/i2c-dev/i2c-%u/name", i);
672             fd = open(path, O_RDONLY);
673             if (fd < 0) {
674                 break;
675             }
676             size = lseek(fd, 0, SEEK_END);
677             if (size < 0) {
678                 syslog(LOG_WARNING, "mraa: failed to seek i2c filename file");
679                 close(fd);
680                 break;
681             }
682             err = lseek(fd, 0, SEEK_SET);
683             if (err < 0) {
684                 syslog(LOG_WARNING, "mraa: failed to seek i2c filename file");
685                 close(fd);
686                 break;
687             }
688             char* value = malloc(size);
689             if (value == NULL) {
690                 syslog(LOG_ERR, "mraa: failed to allocate memory for i2c file");
691                 close(fd);
692                 break;
693             }
694             ssize_t r = read(fd, value, size);
695             if (r > 0) {
696                 if (strcasestr(value, devname) != NULL) {
697                     free(value);
698                     close(fd);
699                     return i;
700                 }
701             } else {
702                 syslog(LOG_ERR, "mraa: sysfs i2cdev failed");
703             }
704             free(value);
705             close(fd);
706         }
707     } else {
708         syslog(LOG_WARNING, "mraa: no i2c-dev detected, load i2c-dev");
709     }
710
711     return ret;
712 }
713
714 mraa_boolean_t
715 mraa_is_sub_platform_id(int pin_or_bus)
716 {
717     return (pin_or_bus & MRAA_SUB_PLATFORM_MASK) != 0;
718 }
719
720 int 
721 mraa_get_sub_platform_id(int pin_or_bus)
722 {
723     return pin_or_bus | MRAA_SUB_PLATFORM_MASK;
724 }
725
726 int 
727 mraa_get_sub_platform_index(int pin_or_bus)
728 {
729     return pin_or_bus & (~MRAA_SUB_PLATFORM_MASK);
730 }