45427ffceb92104b3f573cf68a0728513ea3e3d6
[contrib/mraa.git] / src / iio / iio.c
1 /*
2  * Author: Brendan Le Foll <brendan.le.foll@intel.com>
3  * Copyright (c) 2015 Intel Corporation.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 #include "iio.h"
26 #include "mraa_internal.h"
27 #include "dirent.h"
28 #include <string.h>
29 #include <poll.h>
30
31 #define MAX_SIZE 128
32 #define IIO_DEVICE "iio:device"
33 #define IIO_SCAN_ELEM "scan_elements"
34 #define IIO_SLASH_DEV "/dev/"IIO_DEVICE
35 #define IIO_SYSFS_DEVICE "/sys/bus/iio/devices/"IIO_DEVICE
36 #define IIO_EVENTS "events"
37
38 mraa_iio_context
39 mraa_iio_init(int device)
40 {
41     if (device > plat_iio->iio_device_count) {
42         return NULL;
43     }
44
45     mraa_iio_get_channel_data(&plat_iio->iio_devices[device]);
46     mraa_iio_get_event_data(&plat_iio->iio_devices[device]);
47
48     return &plat_iio->iio_devices[device];
49 }
50
51 int
52 mraa_iio_read_size(mraa_iio_context dev)
53 {
54     return dev->datasize;
55 }
56
57 mraa_iio_channel*
58 mraa_iio_get_channels(mraa_iio_context dev)
59 {
60     return dev->channels;
61 }
62
63 int
64 mraa_iio_get_channel_count(mraa_iio_context dev)
65 {
66     return dev->chan_num;
67 }
68
69 mraa_result_t
70 mraa_iio_get_channel_data(mraa_iio_context dev)
71 {
72     const struct dirent *ent;
73     DIR* dir;
74     int chan_num = 0;
75     char buf[MAX_SIZE];
76     char readbuf[32];
77     int fd;
78     int ret = 0;
79     int padint = 0;
80     int curr_bytes = 0;
81     char shortbuf, signchar;
82     memset(buf, 0, MAX_SIZE);
83     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_SCAN_ELEM, dev->num);
84     dir = opendir(buf);
85     if (dir != NULL) {
86         while ((ent = readdir(dir)) != NULL) {
87             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
88                     chan_num++;
89             }
90         }
91     }
92     dev->chan_num = chan_num;
93         //no need proceed if no channel found
94         if (chan_num == 0)
95                 return MRAA_SUCCESS;
96     mraa_iio_channel* chan;
97     dev->channels = calloc(chan_num, sizeof(mraa_iio_channel));
98     seekdir(dir, 0);
99     while ((ent = readdir(dir)) != NULL) {
100         if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_index"), "_index") == 0) {
101             snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_SCAN_ELEM "/%s", dev->num, ent->d_name);
102             fd = open(buf, O_RDONLY);
103             if (fd > 0) {
104                 if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
105                     break;
106                 }
107                 chan_num = ((int) strtol(readbuf, NULL, 10));
108                 chan = &dev->channels[chan_num];
109                 chan->index = chan_num;
110                 close(fd);
111
112                 buf[(strlen(buf)-5)] = '\0';
113                 char* str = strdup(buf);
114                 // grab the type of the buffer
115                 snprintf(buf, MAX_SIZE, "%stype", str);
116                 fd = open(buf, O_RDONLY);
117                 if (fd > 0) {
118                     read(fd, readbuf, 31 * sizeof(char));
119                     ret = sscanf(readbuf, "%ce:%c%u/%u>>%u", &shortbuf,
120                                     &signchar, &chan->bits_used,
121                                     &padint, &chan->shift);
122                     chan->bytes = padint / 8;
123                     if (curr_bytes % chan->bytes == 0) {
124                         chan->location = curr_bytes;
125                     } else {
126                         chan->location = curr_bytes - curr_bytes%chan->bytes + chan->bytes;
127                     }
128                     curr_bytes = chan->location + chan->bytes;
129                     // probably should be 5?
130                     if (ret < 0) {
131                         // cleanup
132                         free(str);
133                         close(fd);
134                         return MRAA_IO_SETUP_FAILURE;
135                     }
136                     chan->signedd = (signchar == 's');
137                     chan->lendian = (shortbuf == 'l');
138                     if (chan->bits_used == 64) {
139                         chan->mask = ~0;
140                     } else {
141                         chan->mask = (1 << chan->bits_used) - 1;
142                     }
143                     close(fd);
144                 }
145                 // grab the enable flag of channel
146                 snprintf(buf, MAX_SIZE, "%sen", str);
147                 fd = open(buf, O_RDONLY);
148                 if (fd > 0) {
149                     if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
150                         syslog(LOG_ERR, "iio: Failed to read a sensible value from sysfs");
151                         return -1;
152                     }
153                     chan->enabled = (int) strtol(readbuf, NULL, 10);
154                     close(fd);
155                 }
156                 // clean up str var
157                 free(str);
158             }
159         }
160     }
161     dev->datasize = curr_bytes;
162
163     return MRAA_SUCCESS;
164 }
165
166 const char*
167 mraa_iio_get_device_name(mraa_iio_context dev)
168 {
169     return dev->name;
170 }
171
172 int
173 mraa_iio_get_device_num_by_name(const char* name)
174 {
175     int i;
176
177     if (plat_iio == NULL) {
178         syslog(LOG_ERR, "iio: platform IIO structure is not initialized");
179         return -1;
180     }
181
182     if (name == NULL) {
183         syslog(LOG_ERR, "iio: device name is NULL, unable to find its number");
184         return -1;
185     }
186
187     for (i = 0; i < plat_iio->iio_device_count; i++) {
188         struct _iio* device;
189         device = &plat_iio->iio_devices[i];
190         // we want to check for exact match
191         if (strncmp(device->name, name, strlen(device->name)+1) == 0) {
192             return device->num;
193         }
194     }
195
196     return -1;
197 }
198
199 mraa_result_t
200 mraa_iio_read(mraa_iio_context dev, const char* attr_chan, float* data)
201 {
202     char buf[64];
203     snprintf(buf, 64, IIO_SYSFS_DEVICE "%d/%s", dev->num, attr_chan);
204     int fd = open(buf, O_RDONLY);
205     if (fd != -1) {
206         int len = read(fd, &buf, 64);
207         *data = strtol(buf, NULL, 10);
208         return MRAA_SUCCESS;
209     }
210     return MRAA_ERROR_UNSPECIFIED;
211 }
212
213 mraa_result_t
214 mraa_iio_write(mraa_iio_context dev, const char* attr_chan, const char* data)
215 {
216     char buf[128];
217     snprintf(buf, 128, IIO_SYSFS_DEVICE "%d/%s", dev->num, attr_chan);
218     int fd = open(buf, O_WRONLY);
219     if (fd != -1) {
220         write(fd, data, (strlen(data)+1));
221         return MRAA_SUCCESS;
222     }
223     return MRAA_ERROR_UNSPECIFIED;
224 }
225
226 static mraa_result_t
227 mraa_iio_wait_event(int fd, char* data)
228 {
229     struct pollfd pfd;
230
231     if (fd < 0) {
232         return MRAA_ERROR_INVALID_RESOURCE;
233     }
234
235     pfd.fd = fd;
236     pfd.events = POLLIN;
237
238     // Wait for it forever or until pthread_cancel
239     // poll is a cancelable point like sleep()
240     int x = poll(&pfd, 1, -1);
241
242     memset(data, 0, 100);
243     read(fd, data, 100);
244
245     return MRAA_SUCCESS;
246 }
247
248 static void*
249 mraa_iio_trigger_handler(void* arg)
250 {
251     mraa_iio_context dev = (mraa_iio_context) arg;
252     char data[MAX_SIZE*100];
253
254     for (;;) {
255         if (mraa_iio_wait_event(dev->fp, &data[0]) == MRAA_SUCCESS) {
256             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
257             dev->isr(&data);
258             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
259         } else {
260             // we must have got an error code so die nicely
261             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
262             return NULL;
263         }
264     }
265 }
266
267 mraa_result_t
268 mraa_iio_trigger_buffer(mraa_iio_context dev, void (*fptr)(char* data), void* args)
269 {
270     char bu[MAX_SIZE];
271     if (dev->thread_id != 0) {
272         return MRAA_ERROR_NO_RESOURCES;
273     }
274
275     sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
276     dev->fp = open(bu, O_RDONLY | O_NONBLOCK);
277     if (dev->fp == -1) {
278         return MRAA_ERROR_INVALID_RESOURCE;
279     }
280
281     dev->isr = fptr;
282     pthread_create(&dev->thread_id, NULL, mraa_iio_trigger_handler, (void*) dev);
283
284     return MRAA_SUCCESS;
285 }
286
287 mraa_result_t
288 mraa_iio_get_event_data(mraa_iio_context dev)
289 {
290     const struct dirent *ent;
291     DIR* dir;
292     int event_num = 0;
293     char buf[MAX_SIZE];
294     char readbuf[32];
295     int fd;
296     int ret = 0;
297     int padint = 0;
298     int curr_bytes = 0;
299     char shortbuf, signchar;
300     memset(buf, 0, MAX_SIZE);
301     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS, dev->num);
302     dir = opendir(buf);
303     if (dir != NULL) {
304         while ((ent = readdir(dir)) != NULL) {
305             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
306                 event_num++;
307             }
308         }
309         dev->event_num = event_num;
310                 //no need proceed if no event found
311                 if (event_num == 0)
312                         return MRAA_SUCCESS;
313         mraa_iio_event* event;
314                 dev->events = calloc(event_num, sizeof(mraa_iio_event));
315                 if ( dev->events == NULL)
316                 {
317                         closedir(dir);
318                         return MRAA_ERROR_UNSPECIFIED;
319                 }
320                 rewinddir(dir);
321                 event_num = 0;
322                 while ((ent = readdir(dir)) != NULL)
323                 {
324             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
325                                 event = &dev->events[event_num];
326                 event->name = strdup(ent->d_name);
327                                 snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, ent->d_name);
328                                 fd = open(buf, O_RDONLY);
329                                 if (fd > 0) {
330                                         if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
331                                                 break;
332                                         }
333                                         close(fd);
334                                 }
335                 event->enabled = ((int) strtol(readbuf, NULL, 10));
336                                 //Todo, read other event info.
337                                 event_num++;
338             }
339         }
340                 closedir(dir);
341     }
342     return MRAA_SUCCESS;
343 }
344
345 mraa_result_t
346 mraa_iio_event_read(mraa_iio_context dev, const char* attribute, float* data)
347 {
348     char buf[64];
349     snprintf(buf, 64, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, attribute);
350     int fd = open(buf, O_RDONLY);
351     if (fd != -1) {
352         int len = read(fd, &buf, 64);
353         *data = strtol(buf, NULL, 10);
354         return MRAA_SUCCESS;
355     }
356     return MRAA_ERROR_UNSPECIFIED;
357 }
358
359 mraa_result_t
360 mraa_iio_event_write(mraa_iio_context dev, const char* attribute,  const char* data)
361 {
362         int len;
363     char buf[128];
364     snprintf(buf, 128, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, attribute);
365     int fd = open(buf, O_WRONLY);
366     if (fd != -1) {
367                 int len = write(fd, data, ( strlen(data) +1 ));
368         return MRAA_SUCCESS;
369     }
370     return MRAA_ERROR_UNSPECIFIED;
371 }
372
373 static mraa_result_t
374 mraa_iio_event_poll_nonblock(int fd, struct iio_event_data* data)
375 {
376     struct pollfd pfd;
377
378     if (fd < 0) {
379         return MRAA_ERROR_INVALID_RESOURCE;
380     }
381
382     pfd.fd = fd;
383     pfd.events = POLLIN;
384
385     // Wait for it forever or until pthread_cancel
386     // poll is a cancelable point like sleep()
387     int x = poll(&pfd, 1, -1);
388
389     read(fd, data, sizeof(struct iio_event_data));
390
391     return MRAA_SUCCESS;
392 }
393
394 mraa_result_t
395 mraa_iio_event_poll(mraa_iio_context dev, struct iio_event_data* data)
396 {
397     char bu[MAX_SIZE];
398     int ret;
399         int event_fd;
400         int fd;
401
402         sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
403     fd = open(bu, 0);
404         ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
405         close(fd);
406
407         if (ret == -1 || event_fd == -1)
408                 return MRAA_ERROR_UNSPECIFIED;
409
410         ret = read(event_fd, data, sizeof(struct iio_event_data));
411
412         close(event_fd);
413     return MRAA_SUCCESS;
414 }
415
416 static void*
417 mraa_iio_event_handler(void* arg)
418 {
419         struct iio_event_data data;
420     mraa_iio_context dev = (mraa_iio_context) arg;
421
422     for (;;) {
423         if (mraa_iio_event_poll_nonblock(dev->fp_event, &data) == MRAA_SUCCESS) {
424             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
425             dev->isr_event(&data);
426             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
427         } else {
428             // we must have got an error code so die nicely
429             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
430             return NULL;
431         }
432     }
433 }
434
435 mraa_result_t
436 mraa_iio_event_setup_callback(mraa_iio_context dev, void (*fptr)(struct iio_event_data* data), void* args)
437 {
438         int ret;
439     char bu[MAX_SIZE];
440     if (dev->thread_id != 0) {
441         return MRAA_ERROR_NO_RESOURCES;
442     }
443
444     sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
445     dev->fp = open(bu, O_RDONLY | O_NONBLOCK);
446     if (dev->fp == -1) {
447         return MRAA_ERROR_INVALID_RESOURCE;
448     }
449         ret = ioctl(dev->fp, IIO_GET_EVENT_FD_IOCTL, &dev->fp_event);
450         close(dev->fp);
451
452         if (ret == -1 || dev->fp_event == -1)
453         {
454                 return MRAA_ERROR_UNSPECIFIED;
455         }
456
457     dev->isr_event = fptr;
458     pthread_create(&dev->thread_id, NULL, mraa_iio_event_handler, (void*) dev);
459
460     return MRAA_SUCCESS;
461 }
462
463 mraa_result_t
464 mraa_iio_event_extract_event(struct iio_event_data* event, int* chan_type, int* modifier, int* type, int* direction, int* channel, int* channel2, int* different)
465 {
466         *chan_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
467         *modifier= IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
468         *type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
469         *direction = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
470         *channel = IIO_EVENT_CODE_EXTRACT_CHAN(event->id);
471         *channel2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id);
472         *different = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
473     return MRAA_SUCCESS;
474 }
475 #if 0
476 // does stop make any sense on iio devices?
477 mraa_result_t
478 mraa_iio_stop(mraa_iio_context dev)
479 {
480     return MRAA_SUCCESS;
481 }
482 #endif
483