swig: fix usage of SWIGPYTHON for python specific code
[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
27 #include <stdlib.h>
28 #include <fcntl.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <poll.h>
32
33 #define SYSFS_CLASS_GPIO "/sys/class/gpio"
34 #define MAX_SIZE 64
35 #define POLL_TIMEOUT
36
37 static maa_result_t
38 maa_gpio_get_valfp(maa_gpio_context *dev)
39 {
40     char bu[MAX_SIZE];
41     sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
42
43     dev->value_fp = open(bu, O_RDWR);
44     if (dev->value_fp == -1) {
45         return MAA_ERROR_INVALID_RESOURCE;
46     }
47
48     return MAA_SUCCESS;
49 }
50
51 maa_gpio_context*
52 maa_gpio_init(int pin)
53 {
54     int pinm = maa_check_gpio(pin);
55     if (pinm < 0)
56         return NULL;
57
58     return maa_gpio_init_raw(pinm);
59 }
60
61 maa_gpio_context*
62 maa_gpio_init_raw(int pin)
63 {
64     if (pin < 0)
65         return NULL;
66
67     FILE *export_f;
68     char bu[MAX_SIZE];
69     int length;
70
71     maa_gpio_context* dev = (maa_gpio_context*) malloc(sizeof(maa_gpio_context));
72     memset(dev, 0, sizeof(maa_gpio_context));
73     dev->value_fp = -1;
74     dev->pin = pin;
75
76     if ((export_f = fopen(SYSFS_CLASS_GPIO "/export", "w")) == NULL) {
77         fprintf(stderr, "Failed to open export for writing!\n");
78         return NULL;
79     }
80     length = snprintf(bu, sizeof(bu), "%d", dev->pin);
81     fwrite(bu, sizeof(char), length, export_f);
82
83     fclose(export_f);
84     return dev;
85 }
86
87 static maa_result_t
88 maa_gpio_wait_interrupt(int fd)
89 {
90     unsigned char c;
91     struct pollfd pfd;
92
93     // setup poll on POLLPRI
94     pfd.fd = fd;
95     pfd.events = POLLPRI;
96
97     // do an initial read to clear interupt
98     read (fd, &c, 1);
99
100     if (fd <= 0) {
101         return MAA_ERROR_INVALID_RESOURCE;
102     }
103
104     // Wait for it forever
105     int x = poll (&pfd, 1, -1);
106
107     // do a final read to clear interupt
108     read (fd, &c, 1);
109
110     return MAA_SUCCESS;
111 }
112
113 static void*
114 maa_gpio_interrupt_handler(void* arg)
115 {
116     maa_gpio_context* dev = (maa_gpio_context*) arg;
117     maa_result_t ret;
118
119     // open gpio value with open(3)
120     char bu[MAX_SIZE];
121     sprintf(bu, SYSFS_CLASS_GPIO "/gpio%d/value", dev->pin);
122     dev->isr_value_fp = open(bu, O_RDONLY);
123
124     for (;;) {
125         ret = maa_gpio_wait_interrupt(dev->isr_value_fp);
126         if (ret == MAA_SUCCESS) {
127 #ifdef SWIGPYTHON
128             // In order to call a python object (all python functions are objects) we
129             // need to aquire the GIL (Global Interpreter Lock). This may not always be
130             // nessecary but especially if doing IO (like print()) python will segfault
131             // if we do not hold a lock on the GIL
132             PyGILState_STATE gilstate = PyGILState_Ensure();
133
134             PyEval_CallObject(dev->isr, NULL);
135
136             PyGILState_Release (gilstate);
137 #else
138             dev->isr();
139 #endif
140         } else {
141             // we must have got an error code so die nicely
142             close(dev->isr_value_fp);
143             return;
144         }
145     }
146 }
147
148 maa_result_t
149 maa_gpio_edge_mode(maa_gpio_context *dev, gpio_edge_t mode)
150 {
151     if (dev->value_fp != -1) {
152          close(dev->value_fp);
153          dev->value_fp = -1;
154     }
155
156     char filepath[MAX_SIZE];
157     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/edge", dev->pin);
158
159     FILE *edge;
160     if ((edge= fopen(filepath, "w")) == NULL) {
161         fprintf(stderr, "Failed to open edge for writing!\n");
162         return MAA_ERROR_INVALID_RESOURCE;
163     }
164
165     char bu[MAX_SIZE];
166     int length;
167     switch(mode) {
168         case MAA_GPIO_EDGE_NONE:
169             length = snprintf(bu, sizeof(bu), "none");
170             break;
171         case MAA_GPIO_EDGE_BOTH:
172             length = snprintf(bu, sizeof(bu), "both");
173             break;
174         case MAA_GPIO_EDGE_RISING:
175             length = snprintf(bu, sizeof(bu), "rising");
176             break;
177         case MAA_GPIO_EDGE_FALLING:
178             length = snprintf(bu, sizeof(bu), "falling");
179             break;
180         default:
181             fclose(edge);
182             return MAA_ERROR_FEATURE_NOT_IMPLEMENTED;
183     }
184     fwrite(bu, sizeof(char), length, edge);
185
186     fclose(edge);
187     return MAA_SUCCESS;
188 }
189
190 maa_result_t
191 maa_gpio_isr(maa_gpio_context *dev, gpio_edge_t mode, void (*fptr)(void))
192 {
193     maa_gpio_edge_mode(dev, mode);
194     dev->isr = fptr;
195     pthread_create (&dev->thread_id, NULL, maa_gpio_interrupt_handler, (void *) dev);
196
197     return MAA_SUCCESS;
198 }
199
200 maa_result_t
201 maa_gpio_isr_exit(maa_gpio_context *dev)
202 {
203     maa_result_t ret = MAA_SUCCESS;
204
205 #ifdef SWIGPYTHON
206     // Dereference our Python call back function
207     Py_DECREF(dev->isr);
208 #endif
209
210     if (dev->thread_id == 0) {
211         return ret;
212     }
213
214     if (pthread_kill(dev->thread_id) != 0) {
215        ret = MAA_ERROR_INVALID_HANDLE;
216     }
217     if (close(dev->isr_value_fp) != 0) {
218        ret = MAA_ERROR_INVALID_PARAMETER;
219     }
220
221     // this is only required if we had an isr setup
222     if (ret == MAA_SUCCESS) {
223        ret = maa_gpio_edge_mode(dev, MAA_GPIO_EDGE_NONE);
224     }
225
226     return ret;
227 }
228
229 maa_result_t
230 maa_gpio_mode(maa_gpio_context *dev, gpio_mode_t mode)
231 {
232     if (dev->value_fp != -1) {
233          close(dev->value_fp);
234          dev->value_fp = -1;
235     }
236
237     char filepath[MAX_SIZE];
238     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/drive", dev->pin);
239
240     FILE *drive;
241     if ((drive = fopen(filepath, "w")) == NULL) {
242         fprintf(stderr, "Failed to open drive for writing!\n");
243         return MAA_ERROR_INVALID_RESOURCE;
244     }
245
246     char bu[MAX_SIZE];
247     int length;
248     switch(mode) {
249         case MAA_GPIO_STRONG:
250             length = snprintf(bu, sizeof(bu), "strong");
251             break;
252         case MAA_GPIO_PULLUP:
253             length = snprintf(bu, sizeof(bu), "pullup");
254             break;
255         case MAA_GPIO_PULLDOWN:
256             length = snprintf(bu, sizeof(bu), "pulldown");
257             break;
258         case MAA_GPIO_HIZ:
259             length = snprintf(bu, sizeof(bu), "hiz");
260             break;
261         default:
262             fclose(drive);
263             return MAA_ERROR_FEATURE_NOT_IMPLEMENTED;
264     }
265     fwrite(bu, sizeof(char), length, drive);
266
267     fclose(drive);
268     return MAA_SUCCESS;
269 }
270
271 maa_result_t
272 maa_gpio_dir(maa_gpio_context *dev, gpio_dir_t dir)
273 {
274     if (dev == NULL) {
275         return MAA_ERROR_INVALID_HANDLE;
276     }
277     if (dev->value_fp != -1) {
278          close(dev->value_fp);
279          dev->value_fp = -1;
280     }
281     char filepath[MAX_SIZE];
282     snprintf(filepath, MAX_SIZE, SYSFS_CLASS_GPIO "/gpio%d/direction", dev->pin);
283
284     FILE *direction;
285     if ((direction = fopen(filepath, "w")) == NULL) {
286         fprintf(stderr, "Failed to open direction for writing!\n");
287         return MAA_ERROR_INVALID_RESOURCE;
288     }
289
290     char bu[MAX_SIZE];
291     int length;
292     switch(dir) {
293         case MAA_GPIO_OUT:
294             length = snprintf(bu, sizeof(bu), "out");
295             break;
296         case MAA_GPIO_IN:
297             length = snprintf(bu, sizeof(bu), "in");
298             break;
299         default:
300             fclose(direction);
301             return MAA_ERROR_FEATURE_NOT_IMPLEMENTED;
302     }
303     fwrite(bu, sizeof(char), length, direction);
304
305     fclose(direction);
306     return MAA_SUCCESS;
307 }
308
309 int
310 maa_gpio_read(maa_gpio_context *dev)
311 {
312     if (dev->value_fp == -1) {
313         if (maa_gpio_get_valfp(dev) != MAA_SUCCESS) {
314              fprintf(stderr, "Failed to get value file pointer\n");
315         }
316     }
317     else {
318         // if value_fp is new this is pointless
319         lseek(dev->value_fp, 0, SEEK_SET);
320     }
321     char bu[2];
322     if (read(dev->value_fp, bu, 2*sizeof(char)) != 2) {
323         fprintf(stderr, "Failed to read a sensible value from sysfs");
324     }
325     lseek(dev->value_fp, 0, SEEK_SET);
326     int ret = strtol(bu, NULL, 10);
327
328     return ret;
329 }
330
331 maa_result_t
332 maa_gpio_write(maa_gpio_context *dev, int value)
333 {
334     if (dev->value_fp == -1) {
335         maa_gpio_get_valfp(dev);
336     }
337     if (lseek(dev->value_fp, 0, SEEK_SET) == -1) {
338         return MAA_ERROR_INVALID_RESOURCE;
339     }
340
341     char bu[MAX_SIZE];
342     int length = snprintf(bu, sizeof(bu), "%d", value);
343     if (write(dev->value_fp, bu, length*sizeof(char)) == -1) {
344         return MAA_ERROR_INVALID_HANDLE;
345     }
346
347     return MAA_SUCCESS;
348 }
349
350 maa_result_t
351 maa_gpio_unexport(maa_gpio_context *dev)
352 {
353     FILE *unexport_f;
354
355     if ((unexport_f = fopen(SYSFS_CLASS_GPIO "/unexport", "w")) == NULL) {
356         fprintf(stderr, "Failed to open unexport for writing!\n");
357         return MAA_ERROR_INVALID_RESOURCE;
358     }
359
360     char bu[MAX_SIZE];
361     int length = snprintf(bu, sizeof(bu), "%d", dev->pin);
362     fwrite(bu, sizeof(char), length, unexport_f);
363     fclose(unexport_f);
364
365     maa_gpio_isr_exit(dev);
366
367     return MAA_SUCCESS;
368 }
369
370 maa_result_t
371 maa_gpio_close(maa_gpio_context *dev)
372 {
373     if (dev->value_fp != -1) {
374         close(dev->value_fp);
375     }
376     maa_gpio_unexport(dev);
377     free(dev);
378     return MAA_SUCCESS;
379 }