mraa: add internal mraa_find_i2c_bus function
[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         return MRAA_SUCCESS;
64     }
65     return MRAA_ERROR_INVALID_PARAMETER;
66 }
67
68 #if (defined SWIGPYTHON) || (defined SWIG)
69 mraa_result_t
70 #else
71 mraa_result_t __attribute__((constructor))
72 #endif
73 mraa_init()
74 {
75     if (plat != NULL) {
76         return MRAA_ERROR_PLATFORM_ALREADY_INITIALISED;
77     }
78
79     uid_t proc_euid = geteuid();
80     struct passwd* proc_user = getpwuid(proc_euid);
81
82 #ifdef DEBUG
83     setlogmask(LOG_UPTO(LOG_DEBUG));
84 #else
85     setlogmask(LOG_UPTO(LOG_NOTICE));
86 #endif
87
88     openlog("libmraa", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
89     syslog(LOG_NOTICE, "libmraa version %s initialised by user '%s' with EUID %d",
90            mraa_get_version(), (proc_user != NULL) ? proc_user->pw_name : "<unknown>", proc_euid);
91
92 #ifdef SWIGPYTHON
93     // Initialise python threads, this allows use to grab the GIL when we are
94     // required to do so
95     Py_InitializeEx(0);
96     PyEval_InitThreads();
97 #endif
98     advance_func = (mraa_adv_func_t*) malloc(sizeof(mraa_adv_func_t));
99     memset(advance_func, 0, sizeof(mraa_adv_func_t));
100
101 #ifdef X86PLAT
102     // Use runtime x86 platform detection
103     platform_type = mraa_x86_platform();
104 #elif ARMPLAT
105     // Use runtime ARM platform detection
106     platform_type = mraa_arm_platform();
107 #else
108 #error mraa_ARCH NOTHING
109 #endif
110
111     if (plat == NULL) {
112         printf("mraa: FATAL error, failed to initialise platform\n");
113         return MRAA_ERROR_PLATFORM_NOT_INITIALISED;
114     }
115
116     syslog(LOG_INFO, "libmraa initialised for platform '%s' of type %d", mraa_get_platform_name(), platform_type);
117     return MRAA_SUCCESS;
118 }
119
120 void
121 mraa_deinit()
122 {
123     if (plat != NULL) {
124         if (plat->pins != NULL) {
125             free(plat->pins);
126         }
127         free(plat);
128     }
129     closelog();
130 }
131
132 int
133 mraa_set_priority(const unsigned int priority)
134 {
135     struct sched_param sched_s;
136
137     memset(&sched_s, 0, sizeof(struct sched_param));
138     if (priority > sched_get_priority_max(SCHED_RR)) {
139         sched_s.sched_priority = sched_get_priority_max(SCHED_RR);
140     } else {
141         sched_s.sched_priority = priority;
142     }
143
144     return sched_setscheduler(0, SCHED_RR, &sched_s);
145 }
146
147 mraa_result_t
148 mraa_setup_mux_mapped(mraa_pin_t meta)
149 {
150     int mi;
151
152     for (mi = 0; mi < meta.mux_total; mi++) {
153         mraa_gpio_context mux_i;
154         mux_i = mraa_gpio_init_raw(meta.mux[mi].pin);
155         if (mux_i == NULL) {
156             return MRAA_ERROR_INVALID_HANDLE;
157         }
158         // this function will sometimes fail, however this is not critical as
159         // long as the write succeeds - Test case galileo gen2 pin2
160         mraa_gpio_dir(mux_i, MRAA_GPIO_OUT);
161         mraa_gpio_owner(mux_i, 0);
162
163         if (mraa_gpio_write(mux_i, meta.mux[mi].value) != MRAA_SUCCESS) {
164             mraa_gpio_close(mux_i);
165             return MRAA_ERROR_INVALID_RESOURCE;
166         }
167         mraa_gpio_close(mux_i);
168     }
169
170     return MRAA_SUCCESS;
171 }
172
173 void
174 mraa_result_print(mraa_result_t result)
175 {
176     switch (result) {
177         case MRAA_SUCCESS:
178             fprintf(stdout, "MRAA: SUCCESS\n");
179             break;
180         case MRAA_ERROR_FEATURE_NOT_IMPLEMENTED:
181             fprintf(stdout, "MRAA: Feature not implemented.\n");
182             break;
183         case MRAA_ERROR_FEATURE_NOT_SUPPORTED:
184             fprintf(stdout, "MRAA: Feature not supported by Hardware.\n");
185             break;
186         case MRAA_ERROR_INVALID_VERBOSITY_LEVEL:
187             fprintf(stdout, "MRAA: Invalid verbosity level.\n");
188             break;
189         case MRAA_ERROR_INVALID_PARAMETER:
190             fprintf(stdout, "MRAA: Invalid parameter.\n");
191             break;
192         case MRAA_ERROR_INVALID_HANDLE:
193             fprintf(stdout, "MRAA: Invalid Handle.\n");
194             break;
195         case MRAA_ERROR_NO_RESOURCES:
196             fprintf(stdout, "MRAA: No resources.\n");
197             break;
198         case MRAA_ERROR_INVALID_RESOURCE:
199             fprintf(stdout, "MRAA: Invalid resource.\n");
200             break;
201         case MRAA_ERROR_INVALID_QUEUE_TYPE:
202             fprintf(stdout, "MRAA: Invalid Queue Type.\n");
203             break;
204         case MRAA_ERROR_NO_DATA_AVAILABLE:
205             fprintf(stdout, "MRAA: No Data available.\n");
206             break;
207         case MRAA_ERROR_INVALID_PLATFORM:
208             fprintf(stdout, "MRAA: Platform not recognised.\n");
209             break;
210         case MRAA_ERROR_PLATFORM_NOT_INITIALISED:
211             fprintf(stdout, "MRAA: Platform not initialised.\n");
212             break;
213         case MRAA_ERROR_PLATFORM_ALREADY_INITIALISED:
214             fprintf(stdout, "MRAA: Platform already initialised.\n");
215             break;
216         case MRAA_ERROR_UNSPECIFIED:
217             fprintf(stdout, "MRAA: Unspecified Error.\n");
218             break;
219         default:
220             fprintf(stdout, "MRAA: Unrecognised error.\n");
221             break;
222     }
223 }
224
225 mraa_boolean_t
226 mraa_pin_mode_test(int pin, mraa_pinmodes_t mode)
227 {
228     if (plat == NULL) {
229         return 0;
230     }
231     if (pin > (plat->phy_pin_count - 1) || pin < 0)
232         return 0;
233
234     switch (mode) {
235         case MRAA_PIN_VALID:
236             if (plat->pins[pin].capabilites.valid == 1)
237                 return 1;
238             break;
239         case MRAA_PIN_GPIO:
240             if (plat->pins[pin].capabilites.gpio == 1)
241                 return 1;
242             break;
243         case MRAA_PIN_PWM:
244             if (plat->pins[pin].capabilites.pwm == 1)
245                 return 1;
246             break;
247         case MRAA_PIN_FAST_GPIO:
248             if (plat->pins[pin].capabilites.fast_gpio == 1)
249                 return 1;
250             break;
251         case MRAA_PIN_SPI:
252             if (plat->pins[pin].capabilites.spi == 1)
253                 return 1;
254             break;
255         case MRAA_PIN_I2C:
256             if (plat->pins[pin].capabilites.i2c == 1)
257                 return 1;
258             break;
259         case MRAA_PIN_AIO:
260             if (plat->pins[pin].capabilites.aio == 1)
261                 return 1;
262             break;
263         case MRAA_PIN_UART:
264             if (plat->pins[pin].capabilites.uart == 1)
265                 return 1;
266             break;
267         default:
268             syslog(LOG_NOTICE, "requested pinmode invalid");
269             break;
270     }
271     return 0;
272 }
273
274 mraa_platform_t
275 mraa_get_platform_type()
276 {
277     return platform_type;
278 }
279
280 unsigned int
281 mraa_adc_raw_bits()
282 {
283     if (plat == NULL)
284         return 0;
285
286     if (plat->aio_count == 0)
287         return 0;
288
289     return plat->adc_raw;
290 }
291
292 unsigned int
293 mraa_adc_supported_bits()
294 {
295     if (plat == NULL)
296         return 0;
297
298     if (plat->aio_count == 0)
299         return 0;
300
301     return plat->adc_supported;
302 }
303
304 char*
305 mraa_get_platform_name()
306 {
307     if (plat == NULL) {
308         return NULL;
309     }
310     return (char*) plat->platform_name;
311 }
312
313 unsigned int
314 mraa_get_pin_count()
315 {
316     if (plat == NULL) {
317         return 0;
318     }
319     return plat->phy_pin_count;
320 }
321
322 char*
323 mraa_get_pin_name(int pin)
324 {
325     if (plat == NULL) {
326         return NULL;
327     }
328     if (pin > (plat->phy_pin_count - 1) || pin < 0)
329         return NULL;
330     return (char*) plat->pins[pin].name;
331 }
332
333 mraa_boolean_t
334 mraa_file_exist(const char* filename)
335 {
336     glob_t results;
337     results.gl_pathc = 0;
338     glob(filename, 0, NULL, &results);
339     int file_found = results.gl_pathc == 1;
340     globfree(&results);
341     return file_found;
342 }
343
344 mraa_boolean_t
345 mraa_file_contains(const char* filename, const char* content)
346 {
347     mraa_boolean_t found = 0;
348     if ((filename == NULL) || (content == NULL)) {
349         return 0;
350     }
351
352     char* file = mraa_file_unglob(filename);
353     if (file != NULL) {
354         size_t len = 1024;
355         char* line = malloc(len);
356         FILE* fh = fopen(file, "r");
357         while ((getline(&line, &len, fh) != -1) && (found == 0)) {
358             if (strstr(line, content)) {
359                 found = 1;
360                 break;
361             }
362         }
363         fclose(fh);
364         free(file);
365         free(line);
366     }
367     return found;
368 }
369
370 mraa_boolean_t
371 mraa_file_contains_both(const char* filename, const char* content, const char* content2)
372 {
373     mraa_boolean_t found = 0;
374     if ((filename == NULL) || (content == NULL)) {
375         return 0;
376     }
377
378     char* file = mraa_file_unglob(filename);
379     if (file != NULL) {
380         size_t len = 1024;
381         char* line = malloc(len);
382         FILE* fh = fopen(file, "r");
383         while ((getline(&line, &len, fh) != -1) && (found == 0)) {
384             if (strstr(line, content) && strstr(line, content2)) {
385                 found = 1;
386                 break;
387             }
388         }
389         fclose(fh);
390         free(file);
391         free(line);
392     }
393     return found;
394 }
395
396 char*
397 mraa_file_unglob(const char* filename)
398 {
399     glob_t results;
400     char* res = NULL;
401     results.gl_pathc = 0;
402     glob(filename, 0, NULL, &results);
403     if (results.gl_pathc == 1)
404         res = strdup(results.gl_pathv[0]);
405     globfree(&results);
406     return res;
407 }
408
409 mraa_boolean_t
410 mraa_link_targets(const char* filename, const char* targetname)
411 {
412     int size = 100;
413     int nchars = 0;
414     char* buffer = NULL;
415     while (nchars == 0) {
416         buffer = (char*) realloc(buffer, size);
417         if (buffer == NULL)
418             return 0;
419         nchars = readlink(filename, buffer, size);
420         if (nchars < 0) {
421             free(buffer);
422             return 0;
423         } else {
424             buffer[nchars] = '\0';
425         }
426         if (nchars >= size) {
427             size *= 2;
428             nchars = 0;
429         }
430     }
431     if (strstr(buffer, targetname)) {
432         free(buffer);
433         return 1;
434     } else {
435         free(buffer);
436         return 0;
437     }
438 }
439
440 static int num_i2c_devices = 0;
441
442 static int
443 mraa_count_files(const char* path, const struct stat* sb, int flag, struct FTW* ftwb)
444 {
445     switch (sb->st_mode & S_IFMT) {
446         case S_IFLNK:
447             num_i2c_devices++;
448             break;
449     }
450     return 0;
451 }
452
453 int
454 mraa_find_i2c_bus(const char* devname, int startfrom)
455 {
456     char path[64], value[64];
457     int fd;
458     int i = startfrom;
459     int ret = -1;
460
461     // because feeding mraa_find_i2c_bus result back into the function is
462     // useful treat -1 as 0
463     if (startfrom < 0) {
464         startfrom = 0;
465     }
466
467     // find how many i2c buses we have if we haven't already
468     if (num_i2c_devices == 0) {
469         if (nftw("/sys/class/i2c-dev/", &mraa_count_files, 20, FTW_PHYS) == -1) {
470             return -1;
471         }
472     }
473
474     // i2c devices are numbered numerically so 0 must exist otherwise there is
475     // no i2c-dev loaded
476     if (mraa_file_exist("/sys/class/i2c-dev/i2c-0")) {
477         for (i; i < num_i2c_devices; i++) {
478             off_t size, err;
479             snprintf(path, 64, "/sys/class/i2c-dev/i2c-%u/name", i);
480             fd = open(path, O_RDONLY);
481             if (fd < 0) {
482                 break;
483             }
484             size = lseek(fd, 0, SEEK_END);
485             if (size < 0) {
486                 syslog(LOG_WARNING, "mraa: failed to seek i2c filename file");
487                 close(fd);
488                 break;
489             }
490             err = lseek(fd, 0, SEEK_SET);
491             if (err < 0) {
492                 syslog(LOG_WARNING, "mraa: failed to seek i2c filename file");
493                 close(fd);
494                 break;
495             }
496             ssize_t r = read(fd, value, size);
497             if (r > 0) {
498                 if (strcasestr(value, devname) != NULL) {
499                     close(fd);
500                     return i;
501                 }
502             } else {
503                 syslog(LOG_ERR, "mraa: sysfs i2cdev failed");
504             }
505             close(fd);
506         }
507     } else {
508         syslog(LOG_WARNING, "mraa: no i2c-dev detected, load i2c-dev");
509     }
510
511     return ret;
512 }