api: Renamed some sub-platform API calls.
[contrib/mraa.git] / src / gpio / gpio.c
1 /*
2  * Author: Thomas Ingleby <thomas.c.ingleby@intel.com>
3  * Author: Brendan Le Foll <brendan.le.foll@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 #include "gpio.h"
26 #include "mraa_internal.h"
27
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <string.h>
31 #include <unistd.h>
32 #include <poll.h>
33 #include <pthread.h>
34 #include <signal.h>
35 #include <sys/stat.h>
36 #include <sys/mman.h>
37
38 #define SYSFS_CLASS_GPIO "/sys/class/gpio"
39 #define MAX_SIZE 64
40 #define POLL_TIMEOUT
41
42 static mraa_result_t
43 mraa_gpio_get_valfp(mraa_gpio_context dev)
44 {
45     char bu[MAX_SIZE];
46     sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
47     dev->value_fp = open(bu, O_RDWR);
48     if (dev->value_fp == -1) {
49         return MRAA_ERROR_INVALID_RESOURCE;
50     }
51
52     return MRAA_SUCCESS;
53 }
54
55
56 static mraa_gpio_context
57 mraa_gpio_init_internal(mraa_adv_func_t* func_table, int pin)
58 {
59     if (pin < 0)
60         return NULL;
61
62     mraa_result_t status = MRAA_SUCCESS;
63     char bu[MAX_SIZE];
64     int length;
65
66     mraa_gpio_context dev = (mraa_gpio_context) calloc(1, sizeof(struct _gpio));
67     if (dev == NULL) {
68         syslog(LOG_CRIT, "gpio: Failed to allocate memory for context");
69         return NULL;
70     }
71     
72     dev->advance_func = func_table;
73     dev->pin = pin;    
74     
75     if (IS_FUNC_DEFINED(dev, gpio_init_internal_replace)) {
76         status = dev->advance_func->gpio_init_internal_replace(pin);
77         if (status == MRAA_SUCCESS)
78             return dev;
79         else
80             goto init_internal_cleanup;
81     }
82         
83     if (IS_FUNC_DEFINED(dev, gpio_init_pre)) {
84         status = dev->advance_func->gpio_init_pre(pin);
85         if (status != MRAA_SUCCESS)
86             goto init_internal_cleanup;
87     }
88
89     dev->value_fp = -1;
90     dev->isr_value_fp = -1;
91     dev->phy_pin = -1;
92
93     // then check to make sure the pin is exported.
94     char directory[MAX_SIZE];
95     snprintf(directory, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/", dev->pin);
96     struct stat dir;
97     if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) {
98         dev->owner = 0; // Not Owner
99     } else {
100         int export = open(SYSFS_CLASS_GPIO "/export", O_WRONLY);
101         if (export == -1) {
102             syslog(LOG_ERR, "gpio: Failed to open export for writing");
103             status = MRAA_ERROR_NO_RESOURCES;
104             goto init_internal_cleanup;
105         }
106         length = snprintf(bu, sizeof(bu), "%d", dev->pin);
107         if (write(export, bu, length * sizeof(char)) == -1) {
108             syslog(LOG_ERR, "gpio: Failed to write %d to export", dev->pin);
109             close(export);
110             status = MRAA_ERROR_NO_RESOURCES;
111             goto init_internal_cleanup;
112         }
113         dev->owner = 1;
114         close(export);
115     }
116
117 init_internal_cleanup:
118     if (status != MRAA_SUCCESS) {
119         if (dev != NULL)
120             free(dev);
121         return NULL;
122     }
123     return dev;
124 }
125
126 mraa_gpio_context
127 mraa_gpio_init(int pin)
128 {
129     mraa_board_t* board = plat;
130     if (board == NULL) {
131         syslog(LOG_ERR, "gpio: platform not initialised");
132         return NULL;
133     }
134     
135     if (mraa_is_sub_platform_id(pin)) {
136         syslog(LOG_NOTICE, "gpio: Using sub platform");
137         board = board->sub_platform;
138         if (board == NULL) {
139             syslog(LOG_ERR, "gpio: Sub platform Not Initialised");
140             return NULL;
141         }
142         pin = mraa_get_sub_platform_index(pin);
143     }
144     
145     if (pin < 0 || pin > board->phy_pin_count) {
146         syslog(LOG_ERR, "gpio: pin %i beyond platform definition", pin);
147         return NULL;
148     }
149     if (board->pins[pin].capabilites.gpio != 1) {
150         syslog(LOG_ERR, "gpio: pin %i not capable of gpio", pin);
151         return NULL;
152     }
153     if (board->pins[pin].gpio.mux_total > 0) {
154         if (mraa_setup_mux_mapped(board->pins[pin].gpio) != MRAA_SUCCESS) {
155             syslog(LOG_ERR, "gpio: unable to setup muxes");
156             return NULL;
157         }
158     }
159
160     mraa_gpio_context r = mraa_gpio_init_internal(board->adv_func, board->pins[pin].gpio.pinmap);
161     if (r == NULL) {
162         syslog(LOG_CRIT, "gpio: mraa_gpio_init_raw(%d) returned error", pin);
163         return NULL;
164     }
165     r->phy_pin = pin;
166
167     if (IS_FUNC_DEFINED(r, gpio_init_post)) {
168         mraa_result_t ret = r->advance_func->gpio_init_post(r);
169         if (ret != MRAA_SUCCESS) {
170             free(r);
171             return NULL;
172         }
173     }
174     return r;
175 }
176
177 mraa_gpio_context
178 mraa_gpio_init_raw(int pin)
179 {
180     return mraa_gpio_init_internal(plat == NULL ? NULL : plat->adv_func , pin);
181 }
182
183
184 static mraa_result_t
185 mraa_gpio_wait_interrupt(int fd)
186 {
187     unsigned char c;
188     struct pollfd pfd;
189
190     if (fd < 0) {
191         return MRAA_ERROR_INVALID_RESOURCE;
192     }
193
194     // setup poll on POLLPRI
195     pfd.fd = fd;
196     pfd.events = POLLPRI;
197
198     // do an initial read to clear interrupt
199     lseek(fd, 0, SEEK_SET);
200     read(fd, &c, 1);
201
202     // Wait for it forever or until pthread_cancel
203     // poll is a cancelable point like sleep()
204     int x = poll(&pfd, 1, -1);
205
206     // do a final read to clear interrupt
207     read(fd, &c, 1);
208
209     return MRAA_SUCCESS;
210 }
211
212 static void*
213 mraa_gpio_interrupt_handler(void* arg)
214 {
215     mraa_gpio_context dev = (mraa_gpio_context) arg;
216     if (IS_FUNC_DEFINED(dev, gpio_interrupt_handler_replace))
217         return dev->advance_func->gpio_interrupt_handler_replace(dev);
218     
219     mraa_result_t ret;
220
221     // open gpio value with open(3)
222     char bu[MAX_SIZE];
223     sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
224     int fp = open(bu, O_RDONLY);
225     if (fp < 0) {
226         syslog(LOG_ERR, "gpio: failed to open gpio%d/value", dev->pin);
227         return NULL;
228     }
229     dev->isr_value_fp = fp;
230
231     for (;;) {
232         ret = mraa_gpio_wait_interrupt(dev->isr_value_fp);
233         if (ret == MRAA_SUCCESS) {
234             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
235 #ifdef SWIGPYTHON
236             // In order to call a python object (all python functions are objects) we
237             // need to aquire the GIL (Global Interpreter Lock). This may not always be
238             // nessecary but especially if doing IO (like print()) python will segfault
239             // if we do not hold a lock on the GIL
240             PyGILState_STATE gilstate = PyGILState_Ensure();
241             PyObject* arglist;
242             PyObject* ret;
243             arglist = Py_BuildValue("(i)", dev->isr_args);
244             if (arglist == NULL) {
245                 syslog(LOG_ERR, "gpio: Py_BuildValue NULL");
246             } else {
247                 ret = PyEval_CallObject((PyObject*) dev->isr, arglist);
248                 if (ret == NULL) {
249                     syslog(LOG_ERR, "gpio: PyEval_CallObject failed");
250                 } else {
251                     Py_DECREF(ret);
252                 }
253                 Py_DECREF(arglist);
254             }
255
256             PyGILState_Release(gilstate);
257 #else
258             dev->isr(dev->isr_args);
259 #endif
260             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
261         } else {
262             // we must have got an error code so die nicely
263             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
264             close(dev->isr_value_fp);
265             dev->isr_value_fp = -1;
266             return NULL;
267         }
268     }
269 }
270
271 mraa_result_t
272 mraa_gpio_edge_mode(mraa_gpio_context dev, mraa_gpio_edge_t mode)
273 {
274     if (IS_FUNC_DEFINED(dev, gpio_edge_mode_replace))
275         return dev->advance_func->gpio_edge_mode_replace(dev, mode);
276     
277     if (dev->value_fp != -1) {
278         close(dev->value_fp);
279         dev->value_fp = -1;
280     }
281
282     char filepath[MAX_SIZE];
283     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/edge", dev->pin);
284
285     int edge = open(filepath, O_RDWR);
286     if (edge == -1) {
287         syslog(LOG_ERR, "gpio: Failed to open edge for writing");
288         return MRAA_ERROR_INVALID_RESOURCE;
289     }
290
291     char bu[MAX_SIZE];
292     int length;
293     switch (mode) {
294         case MRAA_GPIO_EDGE_NONE:
295             length = snprintf(bu, sizeof(bu), "none");
296             break;
297         case MRAA_GPIO_EDGE_BOTH:
298             length = snprintf(bu, sizeof(bu), "both");
299             break;
300         case MRAA_GPIO_EDGE_RISING:
301             length = snprintf(bu, sizeof(bu), "rising");
302             break;
303         case MRAA_GPIO_EDGE_FALLING:
304             length = snprintf(bu, sizeof(bu), "falling");
305             break;
306         default:
307             close(edge);
308             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
309     }
310     if (write(edge, bu, length * sizeof(char)) == -1) {
311         syslog(LOG_ERR, "gpio: Failed to write to edge");
312         close(edge);
313         return MRAA_ERROR_INVALID_RESOURCE;
314     }
315
316     close(edge);
317     return MRAA_SUCCESS;
318 }
319
320 mraa_result_t
321 mraa_gpio_isr(mraa_gpio_context dev, mraa_gpio_edge_t mode, void (*fptr)(void*), void* args)
322 {
323     // we only allow one isr per mraa_gpio_context
324     if (dev->thread_id != 0) {
325         return MRAA_ERROR_NO_RESOURCES;
326     }
327
328     if (MRAA_SUCCESS != mraa_gpio_edge_mode(dev, mode)) {
329         return MRAA_ERROR_UNSPECIFIED;
330     }
331
332     dev->isr = fptr;
333     dev->isr_args = args;
334     pthread_create(&dev->thread_id, NULL, mraa_gpio_interrupt_handler, (void*) dev);
335
336     return MRAA_SUCCESS;
337 }
338
339 mraa_result_t
340 mraa_gpio_isr_exit(mraa_gpio_context dev)
341 {
342     mraa_result_t ret = MRAA_SUCCESS;
343
344     // wasting our time, there is no isr to exit from
345     if (dev->thread_id == 0 && dev->isr_value_fp == -1) {
346         return ret;
347     }
348
349     // stop isr being useful
350     ret = mraa_gpio_edge_mode(dev, MRAA_GPIO_EDGE_NONE);
351
352     if ((dev->thread_id != 0)) {
353         if ((pthread_cancel(dev->thread_id) != 0) || (pthread_join(dev->thread_id, NULL) != 0)) {
354             ret = MRAA_ERROR_INVALID_HANDLE;
355         }
356     }
357
358     // close the filehandle in case it's still open
359     if (dev->isr_value_fp != -1) {
360         if (close(dev->isr_value_fp) != 0) {
361             ret = MRAA_ERROR_INVALID_PARAMETER;
362         }
363     }
364
365     // assume our thread will exit either way we just lost it's handle
366     dev->thread_id = 0;
367     dev->isr_value_fp = -1;
368     return ret;
369 }
370
371 mraa_result_t
372 mraa_gpio_mode(mraa_gpio_context dev, mraa_gpio_mode_t mode)
373 {
374     if (IS_FUNC_DEFINED(dev, gpio_mode_replace))
375         return dev->advance_func->gpio_mode_replace(dev, mode);
376
377     if (IS_FUNC_DEFINED(dev, gpio_mode_pre)) {
378         mraa_result_t pre_ret = (advance_func->gpio_mode_pre(dev, mode));
379         if (pre_ret != MRAA_SUCCESS)
380             return pre_ret;
381     }
382
383     if (dev->value_fp != -1) {
384         close(dev->value_fp);
385         dev->value_fp = -1;
386     }
387
388     char filepath[MAX_SIZE];
389     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/drive", dev->pin);
390
391     int drive = open(filepath, O_WRONLY);
392     if (drive == -1) {
393         syslog(LOG_ERR, "gpio: Failed to open drive for writing");
394         return MRAA_ERROR_INVALID_RESOURCE;
395     }
396
397     char bu[MAX_SIZE];
398     int length;
399     switch (mode) {
400         case MRAA_GPIO_STRONG:
401             length = snprintf(bu, sizeof(bu), "strong");
402             break;
403         case MRAA_GPIO_PULLUP:
404             length = snprintf(bu, sizeof(bu), "pullup");
405             break;
406         case MRAA_GPIO_PULLDOWN:
407             length = snprintf(bu, sizeof(bu), "pulldown");
408             break;
409         case MRAA_GPIO_HIZ:
410             length = snprintf(bu, sizeof(bu), "hiz");
411             break;
412         default:
413             close(drive);
414             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
415     }
416     if (write(drive, bu, length * sizeof(char)) == -1) {
417         syslog(LOG_ERR, "gpio: Failed to write to drive mode");
418         close(drive);
419         return MRAA_ERROR_INVALID_RESOURCE;
420     }
421
422     close(drive);
423     if (IS_FUNC_DEFINED(dev, gpio_mode_post))    
424         return dev->advance_func->gpio_mode_post(dev, mode);
425     return MRAA_SUCCESS;
426 }
427
428 mraa_result_t
429 mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
430 {
431     if (IS_FUNC_DEFINED(dev, gpio_dir_replace)) {
432         return dev->advance_func->gpio_dir_replace(dev, dir);
433     }
434     
435     if (IS_FUNC_DEFINED(dev, gpio_dir_pre)) {
436         mraa_result_t pre_ret = (dev->advance_func->gpio_dir_pre(dev, dir));
437         if (pre_ret != MRAA_SUCCESS) {
438             return pre_ret;
439         }
440     }
441
442     if (dev == NULL) {
443         return MRAA_ERROR_INVALID_HANDLE;
444     }
445     if (dev->value_fp != -1) {
446         close(dev->value_fp);
447         dev->value_fp = -1;
448     }
449     char filepath[MAX_SIZE];
450     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin);
451
452     int direction = open(filepath, O_RDWR);
453
454     if (direction == -1) {
455         // Direction Failed to Open. If HIGH or LOW was passed will try and set
456         // If not fail as usual.
457         switch (dir) {
458             case MRAA_GPIO_OUT_HIGH:
459                 return mraa_gpio_write(dev, 1);
460             case MRAA_GPIO_OUT_LOW:
461                 return mraa_gpio_write(dev, 0);
462             default:
463                 return MRAA_ERROR_INVALID_RESOURCE;
464         }
465     }
466
467     char bu[MAX_SIZE];
468     int length;
469     switch (dir) {
470         case MRAA_GPIO_OUT:
471             length = snprintf(bu, sizeof(bu), "out");
472             break;
473         case MRAA_GPIO_IN:
474             length = snprintf(bu, sizeof(bu), "in");
475             break;
476         case MRAA_GPIO_OUT_HIGH:
477             length = snprintf(bu, sizeof(bu), "high");
478             break;
479         case MRAA_GPIO_OUT_LOW:
480             length = snprintf(bu, sizeof(bu), "low");
481             break;
482         default:
483             close(direction);
484             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
485     }
486
487     if (write(direction, bu, length * sizeof(char)) == -1) {
488         close(direction);
489         return MRAA_ERROR_INVALID_RESOURCE;
490     }
491
492     close(direction);
493     if (IS_FUNC_DEFINED(dev, gpio_dir_post))
494         return dev->advance_func->gpio_dir_post(dev, dir);
495     return MRAA_SUCCESS;
496 }
497
498 int
499 mraa_gpio_read(mraa_gpio_context dev)
500 {
501     if (dev == NULL)
502         return -1;
503
504     if (IS_FUNC_DEFINED(dev, gpio_read_replace))
505         return dev->advance_func->gpio_read_replace(dev);
506
507     if (dev->mmap_read != NULL)
508         return dev->mmap_read(dev);
509
510     if (dev->value_fp == -1) {
511         if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) {
512             syslog(LOG_ERR, "gpio: Failed to get value file pointer");
513             return -1;
514         }
515     } else {
516         // if value_fp is new this is pointless
517         lseek(dev->value_fp, 0, SEEK_SET);
518     }
519     char bu[2];
520     if (read(dev->value_fp, bu, 2 * sizeof(char)) != 2) {
521         syslog(LOG_ERR, "gpio: Failed to read a sensible value from sysfs");
522         return -1;
523     }
524     lseek(dev->value_fp, 0, SEEK_SET);
525
526     return (int) strtol(bu, NULL, 10);
527 }
528
529 mraa_result_t
530 mraa_gpio_write(mraa_gpio_context dev, int value)
531 {
532     if (dev == NULL)
533         return MRAA_ERROR_INVALID_HANDLE;
534
535     if (dev->mmap_write != NULL)
536         return dev->mmap_write(dev, value);
537
538     if (advance_func->gpio_write_pre != NULL) {
539         mraa_result_t pre_ret = (advance_func->gpio_write_pre(dev, value));
540         if (pre_ret != MRAA_SUCCESS)
541             return pre_ret;
542     }
543
544     if (dev->value_fp == -1) {
545         if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) {
546             return MRAA_ERROR_INVALID_RESOURCE;
547         }
548     }
549
550     if (lseek(dev->value_fp, 0, SEEK_SET) == -1) {
551         return MRAA_ERROR_INVALID_RESOURCE;
552     }
553
554     char bu[MAX_SIZE];
555     int length = snprintf(bu, sizeof(bu), "%d", value);
556     if (write(dev->value_fp, bu, length * sizeof(char)) == -1) {
557         return MRAA_ERROR_INVALID_HANDLE;
558     }
559
560     if (advance_func->gpio_write_post != NULL)
561         return advance_func->gpio_write_post(dev, value);
562     return MRAA_SUCCESS;
563 }
564
565 static mraa_result_t
566 mraa_gpio_unexport_force(mraa_gpio_context dev)
567 {
568     int unexport = open(SYSFS_CLASS_GPIO "/unexport", O_WRONLY);
569     if (unexport == -1) {
570         syslog(LOG_ERR, "gpio: Failed to open unexport for writing");
571         return MRAA_ERROR_INVALID_RESOURCE;
572     }
573
574     char bu[MAX_SIZE];
575     int length = snprintf(bu, sizeof(bu), "%d", dev->pin);
576     if (write(unexport, bu, length * sizeof(char)) == -1) {
577         syslog(LOG_ERR, "gpio: Failed to write to unexport");
578         close(unexport);
579         return MRAA_ERROR_INVALID_RESOURCE;
580     }
581
582     close(unexport);
583     mraa_gpio_isr_exit(dev);
584     return MRAA_SUCCESS;
585 }
586 static mraa_result_t
587 mraa_gpio_unexport(mraa_gpio_context dev)
588 {
589     if (dev->owner) {
590         return mraa_gpio_unexport_force(dev);
591     }
592     return MRAA_ERROR_INVALID_RESOURCE;
593 }
594
595 mraa_result_t
596 mraa_gpio_close(mraa_gpio_context dev)
597 {
598     mraa_result_t result = MRAA_SUCCESS;
599
600     if (advance_func->gpio_close_pre != NULL) {
601         result = advance_func->gpio_close_pre(dev);
602     }
603
604     if (dev->value_fp != -1) {
605         close(dev->value_fp);
606     }
607     mraa_gpio_unexport(dev);
608     free(dev);
609     return result;
610 }
611
612 mraa_result_t
613 mraa_gpio_owner(mraa_gpio_context dev, mraa_boolean_t own)
614 {
615     if (dev == NULL) {
616         return MRAA_ERROR_INVALID_RESOURCE;
617     }
618     syslog(LOG_DEBUG, "gpio: Set owner to %d", (int) own);
619     dev->owner = own;
620     return MRAA_SUCCESS;
621 }
622
623 mraa_result_t
624 mraa_gpio_use_mmaped(mraa_gpio_context dev, mraa_boolean_t mmap_en)
625 {
626     if (advance_func->gpio_mmap_setup != NULL) {
627         return advance_func->gpio_mmap_setup(dev, mmap_en);
628     }
629
630     syslog(LOG_ERR, "gpio: mmap not implemented on this platform");
631     return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
632 }
633
634 int
635 mraa_gpio_get_pin(mraa_gpio_context dev)
636 {
637     if (dev == NULL) {
638         syslog(LOG_ERR, "gpio: context is invalid");
639         return -1;
640     }
641     return dev->phy_pin;
642 }
643
644 int
645 mraa_gpio_get_pin_raw(mraa_gpio_context dev)
646 {
647     if (dev == NULL) {
648         syslog(LOG_ERR, "gpio: context is invalid");
649         return -1;
650     }
651     return dev->pin;
652 }