iio: added mraa_iio_write
[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, const char* data)
212 {
213     char buf[128];
214     snprintf(buf, 128, IIO_SYSFS_DEVICE "%d/%s", dev->num, attr_chan);
215     int fd = open(buf, O_WRONLY);
216     if (fd != -1) {
217         write(fd, data, (strlen(data)+1));
218         return MRAA_SUCCESS;
219     }
220     return MRAA_ERROR_UNSPECIFIED;
221 }
222
223 static mraa_result_t
224 mraa_iio_wait_event(int fd, char* data)
225 {
226     struct pollfd pfd;
227
228     if (fd < 0) {
229         return MRAA_ERROR_INVALID_RESOURCE;
230     }
231
232     pfd.fd = fd;
233     pfd.events = POLLIN;
234
235     // Wait for it forever or until pthread_cancel
236     // poll is a cancelable point like sleep()
237     int x = poll(&pfd, 1, -1);
238
239     memset(data, 0, 100);
240     read(fd, data, 100);
241
242     return MRAA_SUCCESS;
243 }
244
245 static void*
246 mraa_iio_trigger_handler(void* arg)
247 {
248     mraa_iio_context dev = (mraa_iio_context) arg;
249     char data[MAX_SIZE*100];
250
251     for (;;) {
252         if (mraa_iio_wait_event(dev->fp, &data[0]) == MRAA_SUCCESS) {
253             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
254             dev->isr(&data);
255             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
256         } else {
257             // we must have got an error code so die nicely
258             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
259             return NULL;
260         }
261     }
262 }
263
264 mraa_result_t
265 mraa_iio_trigger_buffer(mraa_iio_context dev, void (*fptr)(char* data), void* args)
266 {
267     char bu[MAX_SIZE];
268     if (dev->thread_id != 0) {
269         return MRAA_ERROR_NO_RESOURCES;
270     }
271
272     sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
273     dev->fp = open(bu, O_RDONLY | O_NONBLOCK);
274     if (dev->fp == -1) {
275         return MRAA_ERROR_INVALID_RESOURCE;
276     }
277
278     dev->isr = fptr;
279     pthread_create(&dev->thread_id, NULL, mraa_iio_trigger_handler, (void*) dev);
280
281     return MRAA_SUCCESS;
282 }
283
284 mraa_result_t
285 mraa_iio_get_event_data(mraa_iio_context dev)
286 {
287     const struct dirent *ent;
288     DIR* dir;
289     int event_num = 0;
290     char buf[MAX_SIZE];
291     char readbuf[32];
292     int fd;
293     int ret = 0;
294     int padint = 0;
295     int curr_bytes = 0;
296     char shortbuf, signchar;
297     memset(buf, 0, MAX_SIZE);
298     snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS, dev->num);
299     dir = opendir(buf);
300     if (dir != NULL) {
301         while ((ent = readdir(dir)) != NULL) {
302             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
303                 event_num++;
304             }
305         }
306         dev->event_num = event_num;
307         mraa_iio_event* event;
308                 dev->events = calloc(event_num, sizeof(mraa_iio_event));
309                 if ( dev->events == NULL)
310                 {
311                         closedir(dir);
312                         return MRAA_ERROR_UNSPECIFIED;
313                 }
314                 rewinddir(dir);
315                 event_num = 0;
316                 while ((ent = readdir(dir)) != NULL)
317                 {
318             if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), "_en") == 0) {
319                                 event = &dev->events[event_num];
320                 event->name = strdup(ent->d_name);
321                                 snprintf(buf, MAX_SIZE, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, ent->d_name);
322                                 fd = open(buf, O_RDONLY);
323                                 if (fd > 0) {
324                                         if (read(fd, readbuf, 2 * sizeof(char)) != 2) {
325                                                 break;
326                                         }
327                                         close(fd);
328                                 }
329                 event->enabled = ((int) strtol(readbuf, NULL, 10));
330                                 //Todo, read other event info.
331                                 event_num++;
332             }
333         }
334                 closedir(dir);
335     }
336     return MRAA_SUCCESS;
337 }
338
339 mraa_result_t
340 mraa_iio_event_read(mraa_iio_context dev, const char* attribute, float* data)
341 {
342     char buf[64];
343     snprintf(buf, 64, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, attribute);
344     int fd = open(buf, O_RDONLY);
345     if (fd != -1) {
346         int len = read(fd, &buf, 64);
347         *data = strtol(buf, NULL, 10);
348         return MRAA_SUCCESS;
349     }
350     return MRAA_ERROR_UNSPECIFIED;
351 }
352
353 mraa_result_t
354 mraa_iio_event_write(mraa_iio_context dev, const char* attribute,  const char* data)
355 {
356         int len;
357     char buf[128];
358     snprintf(buf, 128, IIO_SYSFS_DEVICE "%d/" IIO_EVENTS "/%s", dev->num, attribute);
359     int fd = open(buf, O_WRONLY);
360     if (fd != -1) {
361                 int len = write(fd, data, ( strlen(data) +1 ));
362         return MRAA_SUCCESS;
363     }
364     return MRAA_ERROR_UNSPECIFIED;
365 }
366
367 static mraa_result_t
368 mraa_iio_event_poll_nonblock(int fd, struct iio_event_data* data)
369 {
370     struct pollfd pfd;
371
372     if (fd < 0) {
373         return MRAA_ERROR_INVALID_RESOURCE;
374     }
375
376     pfd.fd = fd;
377     pfd.events = POLLIN;
378
379     // Wait for it forever or until pthread_cancel
380     // poll is a cancelable point like sleep()
381     int x = poll(&pfd, 1, -1);
382
383     read(fd, data, sizeof(struct iio_event_data));
384
385     return MRAA_SUCCESS;
386 }
387
388 mraa_result_t
389 mraa_iio_event_poll(mraa_iio_context dev, struct iio_event_data* data)
390 {
391     char bu[MAX_SIZE];
392     int ret;
393         int event_fd;
394         int fd;
395
396         sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
397     fd = open(bu, 0);
398         ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
399         close(fd);
400
401         if (ret == -1 || event_fd == -1)
402                 return MRAA_ERROR_UNSPECIFIED;
403
404         ret = read(event_fd, data, sizeof(struct iio_event_data));
405
406         close(event_fd);
407     return MRAA_SUCCESS;
408 }
409
410 static void*
411 mraa_iio_event_handler(void* arg)
412 {
413         struct iio_event_data data;
414     mraa_iio_context dev = (mraa_iio_context) arg;
415
416     for (;;) {
417         if (mraa_iio_event_poll_nonblock(dev->fp_event, &data) == MRAA_SUCCESS) {
418             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
419             dev->isr_event(&data);
420             pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
421         } else {
422             // we must have got an error code so die nicely
423             pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
424             return NULL;
425         }
426     }
427 }
428
429 mraa_result_t
430 mraa_iio_event_setup_callback(mraa_iio_context dev, void (*fptr)(struct iio_event_data* data), void* args)
431 {
432         int ret;
433     char bu[MAX_SIZE];
434     if (dev->thread_id != 0) {
435         return MRAA_ERROR_NO_RESOURCES;
436     }
437
438     sprintf(bu, IIO_SLASH_DEV "%d", dev->num);
439     dev->fp = open(bu, O_RDONLY | O_NONBLOCK);
440     if (dev->fp == -1) {
441         return MRAA_ERROR_INVALID_RESOURCE;
442     }
443         ret = ioctl(dev->fp, IIO_GET_EVENT_FD_IOCTL, &dev->fp_event);
444         close(dev->fp);
445
446         if (ret == -1 || dev->fp_event == -1)
447         {
448                 return MRAA_ERROR_UNSPECIFIED;
449         }
450
451     dev->isr_event = fptr;
452     pthread_create(&dev->thread_id, NULL, mraa_iio_event_handler, (void*) dev);
453
454     return MRAA_SUCCESS;
455 }
456
457 mraa_result_t
458 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)
459 {
460         *chan_type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
461         *modifier= IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
462         *type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
463         *direction = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
464         *channel = IIO_EVENT_CODE_EXTRACT_CHAN(event->id);
465         *channel2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id);
466         *different = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
467     return MRAA_SUCCESS;
468 }
469 #if 0
470 // does stop make any sense on iio devices?
471 mraa_result_t
472 mraa_iio_stop(mraa_iio_context dev)
473 {
474     return MRAA_SUCCESS;
475 }
476 #endif
477