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