gpio.c: Added ISR thread termination flag
[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, 2015 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 static mraa_gpio_context
56 mraa_gpio_init_internal(mraa_adv_func_t* func_table, int pin)
57 {
58     if (pin < 0)
59         return NULL;
60
61     mraa_result_t status = MRAA_SUCCESS;
62     char bu[MAX_SIZE];
63     int length;
64
65     mraa_gpio_context dev = (mraa_gpio_context) calloc(1, sizeof(struct _gpio));
66     if (dev == NULL) {
67         syslog(LOG_CRIT, "gpio: Failed to allocate memory for context");
68         return NULL;
69     }
70
71     dev->advance_func = func_table;
72     dev->pin = pin;
73
74     if (IS_FUNC_DEFINED(dev, gpio_init_internal_replace)) {
75         status = dev->advance_func->gpio_init_internal_replace(pin);
76         if (status == MRAA_SUCCESS)
77             return dev;
78         else
79             goto init_internal_cleanup;
80     }
81
82     if (IS_FUNC_DEFINED(dev, gpio_init_pre)) {
83         status = dev->advance_func->gpio_init_pre(pin);
84         if (status != MRAA_SUCCESS)
85             goto init_internal_cleanup;
86     }
87
88     dev->value_fp = -1;
89     dev->isr_value_fp = -1;
90     dev->isr_thread_terminating = 0;
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 && !dev->isr_thread_terminating) {
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 or exit request 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     // mark the beginning of the thread termination process for interested parties
349     dev->isr_thread_terminating = 1;
350
351     // stop isr being useful
352     ret = mraa_gpio_edge_mode(dev, MRAA_GPIO_EDGE_NONE);
353
354     if ((dev->thread_id != 0)) {
355         if ((pthread_cancel(dev->thread_id) != 0) || (pthread_join(dev->thread_id, NULL) != 0)) {
356             ret = MRAA_ERROR_INVALID_HANDLE;
357         }
358     }
359
360     // close the filehandle in case it's still open
361     if (dev->isr_value_fp != -1) {
362         if (close(dev->isr_value_fp) != 0) {
363             ret = MRAA_ERROR_INVALID_PARAMETER;
364         }
365     }
366
367     // assume our thread will exit either way we just lost it's handle
368     dev->thread_id = 0;
369     dev->isr_value_fp = -1;
370     dev->isr_thread_terminating = 0;
371     return ret;
372 }
373
374 mraa_result_t
375 mraa_gpio_mode(mraa_gpio_context dev, mraa_gpio_mode_t mode)
376 {
377     if (IS_FUNC_DEFINED(dev, gpio_mode_replace))
378         return dev->advance_func->gpio_mode_replace(dev, mode);
379
380     if (IS_FUNC_DEFINED(dev, gpio_mode_pre)) {
381         mraa_result_t pre_ret = (dev->advance_func->gpio_mode_pre(dev, mode));
382         if (pre_ret != MRAA_SUCCESS)
383             return pre_ret;
384     }
385
386     if (dev->value_fp != -1) {
387         close(dev->value_fp);
388         dev->value_fp = -1;
389     }
390
391     char filepath[MAX_SIZE];
392     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/drive", dev->pin);
393
394     int drive = open(filepath, O_WRONLY);
395     if (drive == -1) {
396         syslog(LOG_ERR, "gpio: Failed to open drive for writing");
397         return MRAA_ERROR_INVALID_RESOURCE;
398     }
399
400     char bu[MAX_SIZE];
401     int length;
402     switch (mode) {
403         case MRAA_GPIO_STRONG:
404             length = snprintf(bu, sizeof(bu), "strong");
405             break;
406         case MRAA_GPIO_PULLUP:
407             length = snprintf(bu, sizeof(bu), "pullup");
408             break;
409         case MRAA_GPIO_PULLDOWN:
410             length = snprintf(bu, sizeof(bu), "pulldown");
411             break;
412         case MRAA_GPIO_HIZ:
413             length = snprintf(bu, sizeof(bu), "hiz");
414             break;
415         default:
416             close(drive);
417             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
418     }
419     if (write(drive, bu, length * sizeof(char)) == -1) {
420         syslog(LOG_ERR, "gpio: Failed to write to drive mode");
421         close(drive);
422         return MRAA_ERROR_INVALID_RESOURCE;
423     }
424
425     close(drive);
426     if (IS_FUNC_DEFINED(dev, gpio_mode_post))
427         return dev->advance_func->gpio_mode_post(dev, mode);
428     return MRAA_SUCCESS;
429 }
430
431 mraa_result_t
432 mraa_gpio_dir(mraa_gpio_context dev, mraa_gpio_dir_t dir)
433 {
434     if (IS_FUNC_DEFINED(dev, gpio_dir_replace)) {
435         return dev->advance_func->gpio_dir_replace(dev, dir);
436     }
437
438     if (IS_FUNC_DEFINED(dev, gpio_dir_pre)) {
439         mraa_result_t pre_ret = (dev->advance_func->gpio_dir_pre(dev, dir));
440         if (pre_ret != MRAA_SUCCESS) {
441             return pre_ret;
442         }
443     }
444
445     if (dev == NULL) {
446         return MRAA_ERROR_INVALID_HANDLE;
447     }
448     if (dev->value_fp != -1) {
449         close(dev->value_fp);
450         dev->value_fp = -1;
451     }
452     char filepath[MAX_SIZE];
453     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin);
454
455     int direction = open(filepath, O_RDWR);
456
457     if (direction == -1) {
458         // Direction Failed to Open. If HIGH or LOW was passed will try and set
459         // If not fail as usual.
460         switch (dir) {
461             case MRAA_GPIO_OUT_HIGH:
462                 return mraa_gpio_write(dev, 1);
463             case MRAA_GPIO_OUT_LOW:
464                 return mraa_gpio_write(dev, 0);
465             default:
466                 return MRAA_ERROR_INVALID_RESOURCE;
467         }
468     }
469
470     char bu[MAX_SIZE];
471     int length;
472     switch (dir) {
473         case MRAA_GPIO_OUT:
474             length = snprintf(bu, sizeof(bu), "out");
475             break;
476         case MRAA_GPIO_IN:
477             length = snprintf(bu, sizeof(bu), "in");
478             break;
479         case MRAA_GPIO_OUT_HIGH:
480             length = snprintf(bu, sizeof(bu), "high");
481             break;
482         case MRAA_GPIO_OUT_LOW:
483             length = snprintf(bu, sizeof(bu), "low");
484             break;
485         default:
486             close(direction);
487             return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
488     }
489
490     if (write(direction, bu, length * sizeof(char)) == -1) {
491         close(direction);
492         return MRAA_ERROR_INVALID_RESOURCE;
493     }
494
495     close(direction);
496     if (IS_FUNC_DEFINED(dev, gpio_dir_post))
497         return dev->advance_func->gpio_dir_post(dev, dir);
498     return MRAA_SUCCESS;
499 }
500
501 int
502 mraa_gpio_read(mraa_gpio_context dev)
503 {
504     if (dev == NULL)
505         return -1;
506
507     if (IS_FUNC_DEFINED(dev, gpio_read_replace))
508         return dev->advance_func->gpio_read_replace(dev);
509
510     if (dev->mmap_read != NULL)
511         return dev->mmap_read(dev);
512
513     if (dev->value_fp == -1) {
514         if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) {
515             syslog(LOG_ERR, "gpio: Failed to get value file pointer");
516             return -1;
517         }
518     } else {
519         // if value_fp is new this is pointless
520         lseek(dev->value_fp, 0, SEEK_SET);
521     }
522     char bu[2];
523     if (read(dev->value_fp, bu, 2 * sizeof(char)) != 2) {
524         syslog(LOG_ERR, "gpio: Failed to read a sensible value from sysfs");
525         return -1;
526     }
527     lseek(dev->value_fp, 0, SEEK_SET);
528
529     return (int) strtol(bu, NULL, 10);
530 }
531
532 mraa_result_t
533 mraa_gpio_write(mraa_gpio_context dev, int value)
534 {
535     if (dev == NULL)
536         return MRAA_ERROR_INVALID_HANDLE;
537
538     if (dev->mmap_write != NULL)
539         return dev->mmap_write(dev, value);
540
541     if (IS_FUNC_DEFINED(dev, gpio_write_pre)) {
542         mraa_result_t pre_ret = (dev->advance_func->gpio_write_pre(dev, value));
543         if (pre_ret != MRAA_SUCCESS)
544             return pre_ret;
545     }
546
547     if (dev->value_fp == -1) {
548         if (mraa_gpio_get_valfp(dev) != MRAA_SUCCESS) {
549             return MRAA_ERROR_INVALID_RESOURCE;
550         }
551     }
552
553     if (lseek(dev->value_fp, 0, SEEK_SET) == -1) {
554         return MRAA_ERROR_INVALID_RESOURCE;
555     }
556
557     char bu[MAX_SIZE];
558     int length = snprintf(bu, sizeof(bu), "%d", value);
559     if (write(dev->value_fp, bu, length * sizeof(char)) == -1) {
560         return MRAA_ERROR_INVALID_HANDLE;
561     }
562
563     if (IS_FUNC_DEFINED(dev, gpio_write_post))
564         return dev->advance_func->gpio_write_post(dev, value);
565     return MRAA_SUCCESS;
566 }
567
568 static mraa_result_t
569 mraa_gpio_unexport_force(mraa_gpio_context dev)
570 {
571     int unexport = open(SYSFS_CLASS_GPIO "/unexport", O_WRONLY);
572     if (unexport == -1) {
573         syslog(LOG_ERR, "gpio: Failed to open unexport for writing");
574         return MRAA_ERROR_INVALID_RESOURCE;
575     }
576
577     char bu[MAX_SIZE];
578     int length = snprintf(bu, sizeof(bu), "%d", dev->pin);
579     if (write(unexport, bu, length * sizeof(char)) == -1) {
580         syslog(LOG_ERR, "gpio: Failed to write to unexport");
581         close(unexport);
582         return MRAA_ERROR_INVALID_RESOURCE;
583     }
584
585     close(unexport);
586     mraa_gpio_isr_exit(dev);
587     return MRAA_SUCCESS;
588 }
589 static mraa_result_t
590 mraa_gpio_unexport(mraa_gpio_context dev)
591 {
592     if (dev->owner) {
593         return mraa_gpio_unexport_force(dev);
594     }
595     return MRAA_ERROR_INVALID_RESOURCE;
596 }
597
598 mraa_result_t
599 mraa_gpio_close(mraa_gpio_context dev)
600 {
601     mraa_result_t result = MRAA_SUCCESS;
602
603     if (IS_FUNC_DEFINED(dev, gpio_close_pre)) {
604         result = dev->advance_func->gpio_close_pre(dev);
605     }
606
607     if (dev->value_fp != -1) {
608         close(dev->value_fp);
609     }
610     mraa_gpio_unexport(dev);
611     free(dev);
612     return result;
613 }
614
615 mraa_result_t
616 mraa_gpio_owner(mraa_gpio_context dev, mraa_boolean_t own)
617 {
618     if (dev == NULL) {
619         return MRAA_ERROR_INVALID_RESOURCE;
620     }
621     syslog(LOG_DEBUG, "gpio: Set owner to %d", (int) own);
622     dev->owner = own;
623     return MRAA_SUCCESS;
624 }
625
626 mraa_result_t
627 mraa_gpio_use_mmaped(mraa_gpio_context dev, mraa_boolean_t mmap_en)
628 {
629     if (IS_FUNC_DEFINED(dev, gpio_mmap_setup)) {
630         return dev->advance_func->gpio_mmap_setup(dev, mmap_en);
631     }
632
633     syslog(LOG_ERR, "gpio: mmap not implemented on this platform");
634     return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
635 }
636
637 int
638 mraa_gpio_get_pin(mraa_gpio_context dev)
639 {
640     if (dev == NULL) {
641         syslog(LOG_ERR, "gpio: context is invalid");
642         return -1;
643     }
644     return dev->phy_pin;
645 }
646
647 int
648 mraa_gpio_get_pin_raw(mraa_gpio_context dev)
649 {
650     if (dev == NULL) {
651         syslog(LOG_ERR, "gpio: context is invalid");
652         return -1;
653     }
654     return dev->pin;
655 }