16e49155898f4f344a45277c616c729c4c580e2b
[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 #include <stropts.h>
31
32 #define MAX_SIZE 128
33 #define IIO_DEVICE "iio:device"
34 #define IIO_SCAN_ELEM "scan_elements"
35 #define IIO_MOUNTING_MATRIX "mounting_matrix"
36 #define IIO_SLASH_DEV "/dev/" IIO_DEVICE
37 #define IIO_SYSFS_DEVICE "/sys/bus/iio/devices/" IIO_DEVICE
38 #define IIO_EVENTS "events"
39 #define IIO_CONFIGFS_TRIGGER "/sys/kernel/config/iio/triggers/"
40
41 mraa_iio_context
42 mraa_iio_init(int device)
43 {
44     if (device > plat_iio->iio_device_count) {
45         return NULL;
46     }
47
48     mraa_iio_get_channel_data(&plat_iio->iio_devices[device]);
49     mraa_iio_get_event_data(&plat_iio->iio_devices[device]);
50
51     return &plat_iio->iio_devices[device];
52 }
53
54 int
55 mraa_iio_read_size(mraa_iio_context dev)
56 {
57     return dev->datasize;
58 }
59
60 mraa_iio_channel*
61 mraa_iio_get_channels(mraa_iio_context dev)
62 {
63     return dev->channels;
64 }
65
66 int
67 mraa_iio_get_channel_count(mraa_iio_context dev)
68 {
69     return dev->chan_num;
70 }
71
72 mraa_result_t
73 mraa_iio_get_channel_data(mraa_iio_context dev)
74 {
75     const struct dirent* ent;
76     DIR* dir;
77     int chan_num = 0;
78     char buf[MAX_SIZE];
79     char readbuf[32];
80     int fd;
81     int ret = 0;
82     int padint = 0;
83     int curr_bytes = 0;
84     char shortbuf, signchar;
85
86     dev->datasize = 0;
87
88     memset(buf, 0, MAX_SIZE);
89     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_SCAN_ELEM, dev->num);
90     dir = opendir(buf);
91     if (dir != NULL) {
92         while ((ent = readdir(dir)) != NULL) {
93             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
94                 chan_num++;
95             }
96         }
97     }
98     dev->chan_num = chan_num;
99     // no need proceed if no channel found
100     if (chan_num == 0)
101         return MRAA_SUCCESS;
102     mraa_iio_channel* chan;
103     dev->channels = calloc(chan_num, sizeof(mraa_iio_channel));
104     seekdir(dir, 0);
105     while ((ent = readdir(dir)) != NULL) {
106         if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_index"), "_index") == 0) {
107             snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_SCAN_ELEM "/%s", dev->num, ent->d_name);
108             fd = open(buf, O_RDONLY);
109             if (fd > 0) {
110                 if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
111                     break;
112                 }
113                 chan_num = ((int) strtol(readbuf, NULL, 10));
114                 chan = &dev->channels[chan_num];
115                 chan->index = chan_num;
116                 close(fd);
117
118                 buf[(strlen(buf) - 5)] = '\0';
119                 char* str = strdup(buf);
120                 // grab the type of the buffer
121                 snprintf(buf, MAX_SIZE, "%stype", str);
122                 fd = open(buf, O_RDONLY);
123                 if (fd > 0) {
124                     read(fd, readbuf, 31 * sizeof(char));
125                     ret = sscanf(readbuf, "%ce:%c%u/%u>>%u", &shortbuf, &signchar, &chan->bits_used,
126                                  &padint, &chan->shift);
127                     chan->bytes = padint / 8;
128                     if (curr_bytes % chan->bytes == 0) {
129                         chan->location = curr_bytes;
130                     } else {
131                         chan->location = curr_bytes - curr_bytes % chan->bytes + chan->bytes;
132                     }
133                     curr_bytes = chan->location + chan->bytes;
134                     // probably should be 5?
135                     if (ret < 0) {
136                         // cleanup
137                         free(str);
138                         close(fd);
139                         return MRAA_IO_SETUP_FAILURE;
140                     }
141                     chan->signedd = (signchar == 's');
142                     chan->lendian = (shortbuf == 'l');
143                     if (chan->bits_used == 64) {
144                         chan->mask = ~0;
145                     } else {
146                         chan->mask = (1 << chan->bits_used) - 1;
147                     }
148                     close(fd);
149                 }
150                 // grab the enable flag of channel
151                 snprintf(buf, MAX_SIZE, "%sen", str);
152                 fd = open(buf, O_RDONLY);
153                 if (fd > 0) {
154                     if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
155                         syslog(LOG_ERR, "iio: Failed to read a sensible value from sysfs");
156                         return -1;
157                     }
158                     chan->enabled = (int) strtol(readbuf, NULL, 10);
159                     // only calculate enable buffer size for trigger buffer extract data
160                     if (chan->enabled) {
161                         dev->datasize += chan->bytes;
162                     }
163                     close(fd);
164                 }
165                 // clean up str var
166                 free(str);
167             }
168         }
169     }
170
171     return MRAA_SUCCESS;
172 }
173
174 const char*
175 mraa_iio_get_device_name(mraa_iio_context dev)
176 {
177     return dev->name;
178 }
179
180 int
181 mraa_iio_get_device_num_by_name(const char* name)
182 {
183     int i;
184
185     if (plat_iio == NULL) {
186         syslog(LOG_ERR, "iio: platform IIO structure is not initialized");
187         return -1;
188     }
189
190     if (name == NULL) {
191         syslog(LOG_ERR, "iio: device name is NULL, unable to find its number");
192         return -1;
193     }
194
195     for (i = 0; i < plat_iio->iio_device_count; i++) {
196         struct _iio* device;
197         device = &plat_iio->iio_devices[i];
198         // we want to check for exact match
199         if (strncmp(device->name, name, strlen(device->name) + 1) == 0) {
200             return device->num;
201         }
202     }
203
204     return -1;
205 }
206
207 mraa_result_t
208 mraa_iio_read_float(mraa_iio_context dev, const char* filename, float* data)
209 {
210     char buf[MAX_SIZE];
211     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/%s", dev->num, filename);
212     FILE* fp = fopen(buf, "r");
213     if (fp != NULL) {
214         fscanf(fp, "%f\n", data);
215         fclose(fp);
216         return MRAA_SUCCESS;
217     }
218     return MRAA_ERROR_UNSPECIFIED;
219 }
220
221 mraa_result_t
222 mraa_iio_read_integer(mraa_iio_context dev, const char* filename, int* data)
223 {
224     char buf[MAX_SIZE];
225     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/%s", dev->num, filename);
226     FILE* fp = fopen(buf, "r");
227     if (fp != NULL) {
228         fscanf(fp, "%d\n", data);
229         fclose(fp);
230         return MRAA_SUCCESS;
231     }
232     return MRAA_ERROR_UNSPECIFIED;
233 }
234
235 mraa_result_t
236 mraa_iio_read_string(mraa_iio_context dev, const char* filename, char* data)
237 {
238     char buf[MAX_SIZE];
239     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/%s", dev->num, filename);
240     FILE* fp = fopen(buf, "r");
241     if (fp != NULL) {
242         fscanf(fp, "%s\n", data);
243         fclose(fp);
244         return MRAA_SUCCESS;
245     }
246     return MRAA_ERROR_UNSPECIFIED;
247 }
248
249 mraa_result_t
250 mraa_iio_write_float(mraa_iio_context dev, const char* filename, const float data)
251 {
252     char buf[MAX_SIZE];
253     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/%s", dev->num, filename);
254     FILE* fp = fopen(buf, "w");
255     if (fp != NULL) {
256         fprintf(fp, "%f", data);
257         fclose(fp);
258         return MRAA_SUCCESS;
259     }
260     return MRAA_ERROR_UNSPECIFIED;
261 }
262
263 mraa_result_t
264 mraa_iio_write_integer(mraa_iio_context dev, const char* filename, const int data)
265 {
266     char buf[MAX_SIZE];
267     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/%s", dev->num, filename);
268     FILE* fp = fopen(buf, "w");
269     if (fp != NULL) {
270         fprintf(fp, "%d", data);
271         fclose(fp);
272         return MRAA_SUCCESS;
273     }
274     return MRAA_ERROR_UNSPECIFIED;
275 }
276
277 mraa_result_t
278 mraa_iio_write_string(mraa_iio_context dev, const char* filename, const char* data)
279 {
280     char buf[MAX_SIZE];
281     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/%s", dev->num, filename);
282     FILE* fp = fopen(buf, "w");
283     if (fp != NULL) {
284         fprintf(fp, "%s", data);
285         fclose(fp);
286         return MRAA_SUCCESS;
287     }
288     return MRAA_ERROR_UNSPECIFIED;
289 }
290
291 static mraa_result_t
292 mraa_iio_wait_event(int fd, char* data, int* read_size)
293 {
294     struct pollfd pfd;
295
296     if (fd < 0) {
297         return MRAA_ERROR_INVALID_RESOURCE;
298     }
299
300     pfd.fd = fd;
301     pfd.events = POLLIN;
302
303     // Wait for it forever or until pthread_cancel
304     // poll is a cancelable point like sleep()
305     int x = poll(&pfd, 1, -1);
306
307     memset(data, 0, 100);
308     *read_size = read(fd, data, 100);
309
310     return MRAA_SUCCESS;
311 }
312
313 static void*
314 mraa_iio_trigger_handler(void* arg)
315 {
316     mraa_iio_context dev = (mraa_iio_context) arg;
317     int i;
318     char data[MAX_SIZE * 100];
319     int read_size;
320
321     for (;;) {
322         if (mraa_iio_wait_event(dev->fp, &data[0], &read_size) == MRAA_SUCCESS) {
323             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
324             // only can process if readsize >= enabled channel's datasize
325             for (i = 0; i < (read_size / dev->datasize); i++) {
326                 dev->isr(&data);
327             }
328             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
329         } else {
330             // we must have got an error code so die nicely
331             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
332             return NULL;
333         }
334     }
335 }
336
337 mraa_result_t
338 mraa_iio_trigger_buffer(mraa_iio_context dev, void (*fptr)(char* data), void* args)
339 {
340     char bu[MAX_SIZE];
341     if (dev->thread_id != 0) {
342         return MRAA_ERROR_NO_RESOURCES;
343     }
344
345     sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
346     dev->fp = open(bu, O_RDONLY | O_NONBLOCK);
347     if (dev->fp == -1) {
348         return MRAA_ERROR_INVALID_RESOURCE;
349     }
350
351     dev->isr = fptr;
352     pthread_create(&dev->thread_id, NULL, mraa_iio_trigger_handler, (void*) dev);
353
354     return MRAA_SUCCESS;
355 }
356
357 mraa_result_t
358 mraa_iio_get_event_data(mraa_iio_context dev)
359 {
360     const struct dirent* ent;
361     DIR* dir;
362     int event_num = 0;
363     char buf[MAX_SIZE];
364     char readbuf[32];
365     int fd;
366     int ret = 0;
367     int padint = 0;
368     int curr_bytes = 0;
369     char shortbuf, signchar;
370     memset(buf, 0, MAX_SIZE);
371     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS, dev->num);
372     dir = opendir(buf);
373     if (dir != NULL) {
374         while ((ent = readdir(dir)) != NULL) {
375             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
376                 event_num++;
377             }
378         }
379         dev->event_num = event_num;
380         // no need proceed if no event found
381         if (event_num == 0)
382             return MRAA_SUCCESS;
383         mraa_iio_event* event;
384         dev->events = calloc(event_num, sizeof(mraa_iio_event));
385         if (dev->events == NULL) {
386             closedir(dir);
387             return MRAA_ERROR_UNSPECIFIED;
388         }
389         rewinddir(dir);
390         event_num = 0;
391         while ((ent = readdir(dir)) != NULL) {
392             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
393                 event = &dev->events[event_num];
394                 event->name = strdup(ent->d_name);
395                 snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, ent->d_name);
396                 fd = open(buf, O_RDONLY);
397                 if (fd > 0) {
398                     if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
399                         break;
400                     }
401                     close(fd);
402                 }
403                 event->enabled = ((int) strtol(readbuf, NULL, 10));
404                 // Todo, read other event info.
405                 event_num++;
406             }
407         }
408         closedir(dir);
409     }
410     return MRAA_SUCCESS;
411 }
412
413 static mraa_result_t
414 mraa_iio_event_poll_nonblock(int fd, struct iio_event_data* data)
415 {
416     struct pollfd pfd;
417
418     if (fd < 0) {
419         return MRAA_ERROR_INVALID_RESOURCE;
420     }
421
422     pfd.fd = fd;
423     pfd.events = POLLIN;
424
425     // Wait for it forever or until pthread_cancel
426     // poll is a cancelable point like sleep()
427     int x = poll(&pfd, 1, -1);
428
429     read(fd, data, sizeof(struct iio_event_data));
430
431     return MRAA_SUCCESS;
432 }
433
434 mraa_result_t
435 mraa_iio_event_poll(mraa_iio_context dev, struct iio_event_data* data)
436 {
437     char bu[MAX_SIZE];
438     int ret;
439     int event_fd;
440     int fd;
441
442     sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
443     fd = open(bu, 0);
444     ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
445     close(fd);
446
447     if (ret == -1 || event_fd == -1)
448         return MRAA_ERROR_UNSPECIFIED;
449
450     ret = read(event_fd, data, sizeof(struct iio_event_data));
451
452     close(event_fd);
453     return MRAA_SUCCESS;
454 }
455
456 static void*
457 mraa_iio_event_handler(void* arg)
458 {
459     struct iio_event_data data;
460     mraa_iio_context dev = (mraa_iio_context) arg;
461
462     for (;;) {
463         if (mraa_iio_event_poll_nonblock(dev->fp_event, &data) == MRAA_SUCCESS) {
464             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
465             dev->isr_event(&data);
466             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
467         } else {
468             // we must have got an error code so die nicely
469             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
470             return NULL;
471         }
472     }
473 }
474
475 mraa_result_t
476 mraa_iio_event_setup_callback(mraa_iio_context dev, void (*fptr)(struct iio_event_data* data), void* args)
477 {
478     int ret;
479     char bu[MAX_SIZE];
480     if (dev->thread_id != 0) {
481         return MRAA_ERROR_NO_RESOURCES;
482     }
483
484     sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
485     dev->fp = open(bu, O_RDONLY | O_NONBLOCK);
486     if (dev->fp == -1) {
487         return MRAA_ERROR_INVALID_RESOURCE;
488     }
489     ret = ioctl(dev->fp, IIO_GET_EVENT_FD_IOCTL, &dev->fp_event);
490     close(dev->fp);
491
492     if (ret == -1 || dev->fp_event == -1) {
493         return MRAA_ERROR_UNSPECIFIED;
494     }
495
496     dev->isr_event = fptr;
497     pthread_create(&dev->thread_id, NULL, mraa_iio_event_handler, (void*) dev);
498
499     return MRAA_SUCCESS;
500 }
501
502 mraa_result_t
503 mraa_iio_event_extract_event(struct iio_event_data* event,
504                              int* chan_type,
505                              int* modifier,
506                              int* type,
507                              int* direction,
508                              int* channel,
509                              int* channel2,
510                              int* different)
511 {
512     *chan_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
513     *modifier = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
514     *type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
515     *direction = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
516     *channel = IIO_EVENT_CODE_EXTRACT_CHAN(event->id);
517     *channel2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id);
518     *different = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
519     return MRAA_SUCCESS;
520 }
521
522 mraa_result_t
523 mraa_iio_get_mounting_matrix(mraa_iio_context dev, float mm[9])
524 {
525     char buf[MAX_SIZE];
526     FILE* fp;
527
528     memset(buf, 0, MAX_SIZE);
529     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_MOUNTING_MATRIX, dev->num);
530     fp = fopen(buf, "r");
531     if (fp != NULL) {
532         fscanf(fp, "%f %f %f\n%f %f %f\n%f %f %f\n", &mm[0], &mm[1], &mm[2], &mm[3], &mm[4], &mm[5],
533                &mm[6], &mm[7], &mm[8]);
534         fclose(fp);
535         return MRAA_SUCCESS;
536     }
537     return MRAA_ERROR_UNSPECIFIED;
538 }
539
540 mraa_result_t
541 mraa_iio_create_trigger(mraa_iio_context dev, const char* trigger)
542 {
543     struct stat configfs_status;
544     struct stat trigger_status;
545     char buf[MAX_SIZE];
546
547     if (stat(IIO_CONFIGFS_TRIGGER, &configfs_status) == 0) {
548         memset(buf, 0, MAX_SIZE);
549         snprintf(buf, MAX_SIZE, IIO_CONFIGFS_TRIGGER "%s", trigger);
550         if (stat(buf, &trigger_status) != 0) {
551             if (mkdir(buf, configfs_status.st_mode) == 0)
552                 return MRAA_SUCCESS;
553         } else {
554             // trigger folder already created
555             return MRAA_SUCCESS;
556         }
557     }
558
559     return MRAA_ERROR_UNSPECIFIED;
560 }
561
562 #if 0
563 // does stop make any sense on iio devices?
564 mraa_result_t
565 mraa_iio_stop(mraa_iio_context dev)
566 {
567     return MRAA_SUCCESS;
568 }
569 #endif