8297ff5dd698bb60d1de588d5374dee779b2a1c1
[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     mraa_iio_channel* chan;
94     dev->channels = calloc(chan_num, sizeof(mraa_iio_channel));
95     seekdir(dir, 0);
96     while ((ent = readdir(dir)) != NULL) {
97         if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_index"), "_index") == 0) {
98             snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_SCAN_ELEM "/%s", dev->num, ent->d_name);
99             fd = open(buf, O_RDONLY);
100             if (fd > 0) {
101                 if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
102                     break;
103                 }
104                 chan_num = ((int) strtol(readbuf, NULL, 10));
105                 chan = &dev->channels[chan_num];
106                 chan->index = chan_num;
107                 close(fd);
108
109                 buf[(strlen(buf)-5)] = '\0';
110                 char* str = strdup(buf);
111                 // grab the type of the buffer
112                 snprintf(buf, MAX_SIZE, "%stype", str);
113                 fd = open(buf, O_RDONLY);
114                 if (fd > 0) {
115                     read(fd, readbuf, 31 * sizeof(char));
116                     ret = sscanf(readbuf, "%ce:%c%u/%u>>%u", &shortbuf,
117                                     &signchar, &chan->bits_used,
118                                     &padint, &chan->shift);
119                     chan->bytes = padint / 8;
120                     if (curr_bytes % chan->bytes == 0) {
121                         chan->location = curr_bytes;
122                     } else {
123                         chan->location = curr_bytes - curr_bytes%chan->bytes + chan->bytes;
124                     }
125                     curr_bytes = chan->location + chan->bytes;
126                     // probably should be 5?
127                     if (ret < 0) {
128                         // cleanup
129                         free(str);
130                         close(fd);
131                         return MRAA_IO_SETUP_FAILURE;
132                     }
133                     chan->signedd = (signchar == 's');
134                     chan->lendian = (shortbuf == 'l');
135                     if (chan->bits_used == 64) {
136                         chan->mask = ~0;
137                     } else {
138                         chan->mask = (1 << chan->bits_used) - 1;
139                     }
140                     close(fd);
141                 }
142                 // grab the enable flag of channel
143                 snprintf(buf, MAX_SIZE, "%sen", str);
144                 fd = open(buf, O_RDONLY);
145                 if (fd > 0) {
146                     if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
147                         syslog(LOG_ERR, "iio: Failed to read a sensible value from sysfs");
148                         return -1;
149                     }
150                     chan->enabled = (int) strtol(readbuf, NULL, 10);
151                     close(fd);
152                 }
153                 // clean up str var
154                 free(str);
155             }
156         }
157     }
158     dev->datasize = curr_bytes;
159
160     return MRAA_SUCCESS;
161 }
162
163 const char*
164 mraa_iio_get_device_name(mraa_iio_context dev)
165 {
166     return dev->name;
167 }
168
169 int
170 mraa_iio_get_device_num_by_name(const char* name)
171 {
172     int i;
173
174     if (plat_iio == NULL) {
175         syslog(LOG_ERR, "iio: platform IIO structure is not initialized");
176         return -1;
177     }
178
179     if (name == NULL) {
180         syslog(LOG_ERR, "iio: device name is NULL, unable to find its number");
181         return -1;
182     }
183
184     for (i = 0; i < plat_iio->iio_device_count; i++) {
185         struct _iio* device;
186         device = &plat_iio->iio_devices[i];
187         // we want to check for exact match
188         if (strncmp(device->name, name, strlen(device->name)+1) == 0) {
189             return device->num;
190         }
191     }
192
193     return -1;
194 }
195
196 mraa_result_t
197 mraa_iio_read(mraa_iio_context dev, const char* attr_chan, float* data)
198 {
199     char buf[64];
200     snprintf(buf, 64, IIO_SYSFS_DEVICE "%d/%s", dev->num, attr_chan);
201     int fd = open(buf, O_RDONLY);
202     if (fd != -1) {
203         int len = read(fd, &buf, 64);
204         *data = strtol(buf, NULL, 10);
205         return MRAA_SUCCESS;
206     }
207     return MRAA_ERROR_UNSPECIFIED;
208 }
209
210 mraa_result_t
211 mraa_iio_write(mraa_iio_context dev, const char* attr_chan)
212 {
213     return MRAA_ERROR_FEATURE_NOT_IMPLEMENTED;
214 }
215
216 static mraa_result_t
217 mraa_iio_wait_event(int fd, char* data)
218 {
219     struct pollfd pfd;
220
221     if (fd < 0) {
222         return MRAA_ERROR_INVALID_RESOURCE;
223     }
224
225     pfd.fd = fd;
226     pfd.events = POLLIN;
227
228     // Wait for it forever or until pthread_cancel
229     // poll is a cancelable point like sleep()
230     int x = poll(&pfd, 1, -1);
231
232     memset(data, 0, 100);
233     read(fd, data, 100);
234
235     return MRAA_SUCCESS;
236 }
237
238 static void*
239 mraa_iio_trigger_handler(void* arg)
240 {
241     mraa_iio_context dev = (mraa_iio_context) arg;
242     char data[MAX_SIZE*100];
243
244     for (;;) {
245         if (mraa_iio_wait_event(dev->fp, &data[0]) == MRAA_SUCCESS) {
246             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
247             dev->isr(&data);
248             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
249         } else {
250             // we must have got an error code so die nicely
251             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
252             return NULL;
253         }
254     }
255 }
256
257 mraa_result_t
258 mraa_iio_trigger_buffer(mraa_iio_context dev, void (*fptr)(char* data), void* args)
259 {
260     char bu[MAX_SIZE];
261     if (dev->thread_id != 0) {
262         return MRAA_ERROR_NO_RESOURCES;
263     }
264
265     sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
266     dev->fp = open(bu, O_RDONLY | O_NONBLOCK);
267     if (dev->fp == -1) {
268         return MRAA_ERROR_INVALID_RESOURCE;
269     }
270
271     dev->isr = fptr;
272     pthread_create(&dev->thread_id, NULL, mraa_iio_trigger_handler, (void*) dev);
273
274     return MRAA_SUCCESS;
275 }
276
277 mraa_result_t
278 mraa_iio_get_event_data(mraa_iio_context dev)
279 {
280     const struct dirent *ent;
281     DIR* dir;
282     int event_num = 0;
283     char buf[MAX_SIZE];
284     char readbuf[32];
285     int fd;
286     int ret = 0;
287     int padint = 0;
288     int curr_bytes = 0;
289     char shortbuf, signchar;
290     memset(buf, 0, MAX_SIZE);
291     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS, dev->num);
292     dir = opendir(buf);
293     if (dir != NULL) {
294         while ((ent = readdir(dir)) != NULL) {
295             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
296                 event_num++;
297             }
298         }
299         dev->event_num = event_num;
300         mraa_iio_event* event;
301                 dev->events = calloc(event_num, sizeof(mraa_iio_event));
302                 if ( dev->events == NULL)
303                 {
304                         closedir(dir);
305                         return MRAA_ERROR_UNSPECIFIED;
306                 }
307                 rewinddir(dir);
308                 event_num = 0;
309                 while ((ent = readdir(dir)) != NULL)
310                 {
311             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
312                                 event = &dev->events[event_num];
313                 event->name = strdup(ent->d_name);
314                                 snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, ent->d_name);
315                                 fd = open(buf, O_RDONLY);
316                                 if (fd > 0) {
317                                         if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
318                                                 break;
319                                         }
320                                         close(fd);
321                                 }
322                 event->enabled = ((int) strtol(readbuf, NULL, 10));
323                                 //Todo, read other event info.
324                                 event_num++;
325             }
326         }
327                 closedir(dir);
328     }
329     return MRAA_SUCCESS;
330 }
331
332 mraa_result_t
333 mraa_iio_event_read(mraa_iio_context dev, const char* attribute, float* data)
334 {
335     char buf[64];
336     snprintf(buf, 64, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, attribute);
337     int fd = open(buf, O_RDONLY);
338     if (fd != -1) {
339         int len = read(fd, &buf, 64);
340         *data = strtol(buf, NULL, 10);
341         return MRAA_SUCCESS;
342     }
343     return MRAA_ERROR_UNSPECIFIED;
344 }
345
346 mraa_result_t
347 mraa_iio_event_write(mraa_iio_context dev, const char* attribute,  const char* data)
348 {
349         int len;
350     char buf[128];
351     snprintf(buf, 128, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, attribute);
352     int fd = open(buf, O_WRONLY);
353     if (fd != -1) {
354                 int len = write(fd, data, ( strlen(data) +1 ));
355         return MRAA_SUCCESS;
356     }
357     return MRAA_ERROR_UNSPECIFIED;
358 }
359
360 static mraa_result_t
361 mraa_iio_event_poll_nonblock(int fd, struct iio_event_data* data)
362 {
363     struct pollfd pfd;
364
365     if (fd < 0) {
366         return MRAA_ERROR_INVALID_RESOURCE;
367     }
368
369     pfd.fd = fd;
370     pfd.events = POLLIN;
371
372     // Wait for it forever or until pthread_cancel
373     // poll is a cancelable point like sleep()
374     int x = poll(&pfd, 1, -1);
375
376     read(fd, data, sizeof(struct iio_event_data));
377
378     return MRAA_SUCCESS;
379 }
380
381 mraa_result_t
382 mraa_iio_event_poll(mraa_iio_context dev, struct iio_event_data* data)
383 {
384     char bu[MAX_SIZE];
385     int ret;
386         int event_fd;
387         int fd;
388
389         sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
390     fd = open(bu, 0);
391         ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
392         close(fd);
393
394         if (ret == -1 || event_fd == -1)
395                 return MRAA_ERROR_UNSPECIFIED;
396
397         ret = read(event_fd, data, sizeof(struct iio_event_data));
398
399         close(event_fd);
400     return MRAA_SUCCESS;
401 }
402
403 static void*
404 mraa_iio_event_handler(void* arg)
405 {
406         struct iio_event_data data;
407     mraa_iio_context dev = (mraa_iio_context) arg;
408
409     for (;;) {
410         if (mraa_iio_event_poll_nonblock(dev->fp_event, &data) == MRAA_SUCCESS) {
411             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
412             dev->isr_event(&data);
413             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
414         } else {
415             // we must have got an error code so die nicely
416             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
417             return NULL;
418         }
419     }
420 }
421
422 mraa_result_t
423 mraa_iio_event_setup_callback(mraa_iio_context dev, void (*fptr)(struct iio_event_data* data), void* args)
424 {
425         int ret;
426     char bu[MAX_SIZE];
427     if (dev->thread_id != 0) {
428         return MRAA_ERROR_NO_RESOURCES;
429     }
430
431     sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
432     dev->fp = open(bu, O_RDONLY | O_NONBLOCK);
433     if (dev->fp == -1) {
434         return MRAA_ERROR_INVALID_RESOURCE;
435     }
436         ret = ioctl(dev->fp, IIO_GET_EVENT_FD_IOCTL, &dev->fp_event);
437         close(dev->fp);
438
439         if (ret == -1 || dev->fp_event == -1)
440         {
441                 return MRAA_ERROR_UNSPECIFIED;
442         }
443
444     dev->isr_event = fptr;
445     pthread_create(&dev->thread_id, NULL, mraa_iio_event_handler, (void*) dev);
446
447     return MRAA_SUCCESS;
448 }
449
450 mraa_result_t
451 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)
452 {
453         *chan_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
454         *modifier= IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
455         *type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
456         *direction = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
457         *channel = IIO_EVENT_CODE_EXTRACT_CHAN(event->id);
458         *channel2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id);
459         *different = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
460     return MRAA_SUCCESS;
461 }
462 #if 0
463 // does stop make any sense on iio devices?
464 mraa_result_t
465 mraa_iio_stop(mraa_iio_context dev)
466 {
467     return MRAA_SUCCESS;
468 }
469 #endif
470