diff options
Diffstat (limited to 'tools/iio')
-rw-r--r-- | tools/iio/Makefile | 16 | ||||
-rw-r--r-- | tools/iio/generic_buffer.c | 361 | ||||
-rw-r--r-- | tools/iio/iio_event_monitor.c | 310 | ||||
-rw-r--r-- | tools/iio/iio_utils.c | 651 | ||||
-rw-r--r-- | tools/iio/iio_utils.h | 71 | ||||
-rw-r--r-- | tools/iio/lsiio.c | 163 |
6 files changed, 1572 insertions, 0 deletions
diff --git a/tools/iio/Makefile b/tools/iio/Makefile new file mode 100644 index 000000000000..83813ad379f9 --- /dev/null +++ b/tools/iio/Makefile | |||
@@ -0,0 +1,16 @@ | |||
1 | CC = gcc | ||
2 | CFLAGS = -Wall -g | ||
3 | |||
4 | all: iio_event_monitor lsiio generic_buffer | ||
5 | |||
6 | iio_event_monitor: iio_event_monitor.o iio_utils.o | ||
7 | |||
8 | lsiio: lsiio.o iio_utils.o | ||
9 | |||
10 | generic_buffer: generic_buffer.o iio_utils.o | ||
11 | |||
12 | %.o: %.c iio_utils.h | ||
13 | |||
14 | .PHONY: clean | ||
15 | clean: | ||
16 | rm -f *.o iio_event_monitor lsiio generic_buffer | ||
diff --git a/tools/iio/generic_buffer.c b/tools/iio/generic_buffer.c new file mode 100644 index 000000000000..01266c2556da --- /dev/null +++ b/tools/iio/generic_buffer.c | |||
@@ -0,0 +1,361 @@ | |||
1 | /* Industrialio buffer test code. | ||
2 | * | ||
3 | * Copyright (c) 2008 Jonathan Cameron | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is primarily intended as an example application. | ||
10 | * Reads the current buffer setup from sysfs and starts a short capture | ||
11 | * from the specified device, pretty printing the result after appropriate | ||
12 | * conversion. | ||
13 | * | ||
14 | * Command line parameters | ||
15 | * generic_buffer -n <device_name> -t <trigger_name> | ||
16 | * If trigger name is not specified the program assumes you want a dataready | ||
17 | * trigger associated with the device and goes looking for it. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #define _GNU_SOURCE | ||
22 | |||
23 | #include <unistd.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <dirent.h> | ||
26 | #include <fcntl.h> | ||
27 | #include <stdio.h> | ||
28 | #include <errno.h> | ||
29 | #include <sys/stat.h> | ||
30 | #include <sys/dir.h> | ||
31 | #include <linux/types.h> | ||
32 | #include <string.h> | ||
33 | #include <poll.h> | ||
34 | #include <endian.h> | ||
35 | #include <getopt.h> | ||
36 | #include <inttypes.h> | ||
37 | #include "iio_utils.h" | ||
38 | |||
39 | /** | ||
40 | * size_from_channelarray() - calculate the storage size of a scan | ||
41 | * @channels: the channel info array | ||
42 | * @num_channels: number of channels | ||
43 | * | ||
44 | * Has the side effect of filling the channels[i].location values used | ||
45 | * in processing the buffer output. | ||
46 | **/ | ||
47 | int size_from_channelarray(struct iio_channel_info *channels, int num_channels) | ||
48 | { | ||
49 | int bytes = 0; | ||
50 | int i = 0; | ||
51 | |||
52 | while (i < num_channels) { | ||
53 | if (bytes % channels[i].bytes == 0) | ||
54 | channels[i].location = bytes; | ||
55 | else | ||
56 | channels[i].location = bytes - bytes%channels[i].bytes | ||
57 | + channels[i].bytes; | ||
58 | bytes = channels[i].location + channels[i].bytes; | ||
59 | i++; | ||
60 | } | ||
61 | return bytes; | ||
62 | } | ||
63 | |||
64 | void print2byte(int input, struct iio_channel_info *info) | ||
65 | { | ||
66 | /* First swap if incorrect endian */ | ||
67 | if (info->be) | ||
68 | input = be16toh((uint16_t)input); | ||
69 | else | ||
70 | input = le16toh((uint16_t)input); | ||
71 | |||
72 | /* | ||
73 | * Shift before conversion to avoid sign extension | ||
74 | * of left aligned data | ||
75 | */ | ||
76 | input = input >> info->shift; | ||
77 | if (info->is_signed) { | ||
78 | int16_t val = input; | ||
79 | |||
80 | val &= (1 << info->bits_used) - 1; | ||
81 | val = (int16_t)(val << (16 - info->bits_used)) >> | ||
82 | (16 - info->bits_used); | ||
83 | printf("%05f ", ((float)val + info->offset)*info->scale); | ||
84 | } else { | ||
85 | uint16_t val = input; | ||
86 | |||
87 | val &= (1 << info->bits_used) - 1; | ||
88 | printf("%05f ", ((float)val + info->offset)*info->scale); | ||
89 | } | ||
90 | } | ||
91 | /** | ||
92 | * process_scan() - print out the values in SI units | ||
93 | * @data: pointer to the start of the scan | ||
94 | * @channels: information about the channels. Note | ||
95 | * size_from_channelarray must have been called first to fill the | ||
96 | * location offsets. | ||
97 | * @num_channels: number of channels | ||
98 | **/ | ||
99 | void process_scan(char *data, | ||
100 | struct iio_channel_info *channels, | ||
101 | int num_channels) | ||
102 | { | ||
103 | int k; | ||
104 | |||
105 | for (k = 0; k < num_channels; k++) | ||
106 | switch (channels[k].bytes) { | ||
107 | /* only a few cases implemented so far */ | ||
108 | case 2: | ||
109 | print2byte(*(uint16_t *)(data + channels[k].location), | ||
110 | &channels[k]); | ||
111 | break; | ||
112 | case 4: | ||
113 | if (!channels[k].is_signed) { | ||
114 | uint32_t val = *(uint32_t *) | ||
115 | (data + channels[k].location); | ||
116 | printf("%05f ", ((float)val + | ||
117 | channels[k].offset)* | ||
118 | channels[k].scale); | ||
119 | |||
120 | } | ||
121 | break; | ||
122 | case 8: | ||
123 | if (channels[k].is_signed) { | ||
124 | int64_t val = *(int64_t *) | ||
125 | (data + | ||
126 | channels[k].location); | ||
127 | if ((val >> channels[k].bits_used) & 1) | ||
128 | val = (val & channels[k].mask) | | ||
129 | ~channels[k].mask; | ||
130 | /* special case for timestamp */ | ||
131 | if (channels[k].scale == 1.0f && | ||
132 | channels[k].offset == 0.0f) | ||
133 | printf("%" PRId64 " ", val); | ||
134 | else | ||
135 | printf("%05f ", ((float)val + | ||
136 | channels[k].offset)* | ||
137 | channels[k].scale); | ||
138 | } | ||
139 | break; | ||
140 | default: | ||
141 | break; | ||
142 | } | ||
143 | printf("\n"); | ||
144 | } | ||
145 | |||
146 | int main(int argc, char **argv) | ||
147 | { | ||
148 | unsigned long num_loops = 2; | ||
149 | unsigned long timedelay = 1000000; | ||
150 | unsigned long buf_len = 128; | ||
151 | |||
152 | int ret, c, i, j, toread; | ||
153 | int fp; | ||
154 | |||
155 | int num_channels; | ||
156 | char *trigger_name = NULL, *device_name = NULL; | ||
157 | char *dev_dir_name, *buf_dir_name; | ||
158 | |||
159 | int datardytrigger = 1; | ||
160 | char *data; | ||
161 | ssize_t read_size; | ||
162 | int dev_num, trig_num; | ||
163 | char *buffer_access; | ||
164 | int scan_size; | ||
165 | int noevents = 0; | ||
166 | int notrigger = 0; | ||
167 | char *dummy; | ||
168 | |||
169 | struct iio_channel_info *channels; | ||
170 | |||
171 | while ((c = getopt(argc, argv, "l:w:c:et:n:g")) != -1) { | ||
172 | switch (c) { | ||
173 | case 'n': | ||
174 | device_name = optarg; | ||
175 | break; | ||
176 | case 't': | ||
177 | trigger_name = optarg; | ||
178 | datardytrigger = 0; | ||
179 | break; | ||
180 | case 'e': | ||
181 | noevents = 1; | ||
182 | break; | ||
183 | case 'c': | ||
184 | num_loops = strtoul(optarg, &dummy, 10); | ||
185 | break; | ||
186 | case 'w': | ||
187 | timedelay = strtoul(optarg, &dummy, 10); | ||
188 | break; | ||
189 | case 'l': | ||
190 | buf_len = strtoul(optarg, &dummy, 10); | ||
191 | break; | ||
192 | case 'g': | ||
193 | notrigger = 1; | ||
194 | break; | ||
195 | case '?': | ||
196 | return -1; | ||
197 | } | ||
198 | } | ||
199 | |||
200 | if (device_name == NULL) | ||
201 | return -1; | ||
202 | |||
203 | /* Find the device requested */ | ||
204 | dev_num = find_type_by_name(device_name, "iio:device"); | ||
205 | if (dev_num < 0) { | ||
206 | printf("Failed to find the %s\n", device_name); | ||
207 | ret = -ENODEV; | ||
208 | goto error_ret; | ||
209 | } | ||
210 | printf("iio device number being used is %d\n", dev_num); | ||
211 | |||
212 | asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); | ||
213 | |||
214 | if (!notrigger) { | ||
215 | if (trigger_name == NULL) { | ||
216 | /* | ||
217 | * Build the trigger name. If it is device associated | ||
218 | * its name is <device_name>_dev[n] where n matches | ||
219 | * the device number found above. | ||
220 | */ | ||
221 | ret = asprintf(&trigger_name, | ||
222 | "%s-dev%d", device_name, dev_num); | ||
223 | if (ret < 0) { | ||
224 | ret = -ENOMEM; | ||
225 | goto error_ret; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | /* Verify the trigger exists */ | ||
230 | trig_num = find_type_by_name(trigger_name, "trigger"); | ||
231 | if (trig_num < 0) { | ||
232 | printf("Failed to find the trigger %s\n", trigger_name); | ||
233 | ret = -ENODEV; | ||
234 | goto error_free_triggername; | ||
235 | } | ||
236 | printf("iio trigger number being used is %d\n", trig_num); | ||
237 | } else | ||
238 | printf("trigger-less mode selected\n"); | ||
239 | |||
240 | /* | ||
241 | * Parse the files in scan_elements to identify what channels are | ||
242 | * present | ||
243 | */ | ||
244 | ret = build_channel_array(dev_dir_name, &channels, &num_channels); | ||
245 | if (ret) { | ||
246 | printf("Problem reading scan element information\n"); | ||
247 | printf("diag %s\n", dev_dir_name); | ||
248 | goto error_free_triggername; | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * Construct the directory name for the associated buffer. | ||
253 | * As we know that the lis3l02dq has only one buffer this may | ||
254 | * be built rather than found. | ||
255 | */ | ||
256 | ret = asprintf(&buf_dir_name, | ||
257 | "%siio:device%d/buffer", iio_dir, dev_num); | ||
258 | if (ret < 0) { | ||
259 | ret = -ENOMEM; | ||
260 | goto error_free_triggername; | ||
261 | } | ||
262 | |||
263 | if (!notrigger) { | ||
264 | printf("%s %s\n", dev_dir_name, trigger_name); | ||
265 | /* Set the device trigger to be the data ready trigger found | ||
266 | * above */ | ||
267 | ret = write_sysfs_string_and_verify("trigger/current_trigger", | ||
268 | dev_dir_name, | ||
269 | trigger_name); | ||
270 | if (ret < 0) { | ||
271 | printf("Failed to write current_trigger file\n"); | ||
272 | goto error_free_buf_dir_name; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /* Setup ring buffer parameters */ | ||
277 | ret = write_sysfs_int("length", buf_dir_name, buf_len); | ||
278 | if (ret < 0) | ||
279 | goto error_free_buf_dir_name; | ||
280 | |||
281 | /* Enable the buffer */ | ||
282 | ret = write_sysfs_int("enable", buf_dir_name, 1); | ||
283 | if (ret < 0) | ||
284 | goto error_free_buf_dir_name; | ||
285 | scan_size = size_from_channelarray(channels, num_channels); | ||
286 | data = malloc(scan_size*buf_len); | ||
287 | if (!data) { | ||
288 | ret = -ENOMEM; | ||
289 | goto error_free_buf_dir_name; | ||
290 | } | ||
291 | |||
292 | ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); | ||
293 | if (ret < 0) { | ||
294 | ret = -ENOMEM; | ||
295 | goto error_free_data; | ||
296 | } | ||
297 | |||
298 | /* Attempt to open non blocking the access dev */ | ||
299 | fp = open(buffer_access, O_RDONLY | O_NONBLOCK); | ||
300 | if (fp == -1) { /* If it isn't there make the node */ | ||
301 | printf("Failed to open %s\n", buffer_access); | ||
302 | ret = -errno; | ||
303 | goto error_free_buffer_access; | ||
304 | } | ||
305 | |||
306 | /* Wait for events 10 times */ | ||
307 | for (j = 0; j < num_loops; j++) { | ||
308 | if (!noevents) { | ||
309 | struct pollfd pfd = { | ||
310 | .fd = fp, | ||
311 | .events = POLLIN, | ||
312 | }; | ||
313 | |||
314 | poll(&pfd, 1, -1); | ||
315 | toread = buf_len; | ||
316 | |||
317 | } else { | ||
318 | usleep(timedelay); | ||
319 | toread = 64; | ||
320 | } | ||
321 | |||
322 | read_size = read(fp, | ||
323 | data, | ||
324 | toread*scan_size); | ||
325 | if (read_size < 0) { | ||
326 | if (errno == -EAGAIN) { | ||
327 | printf("nothing available\n"); | ||
328 | continue; | ||
329 | } else | ||
330 | break; | ||
331 | } | ||
332 | for (i = 0; i < read_size/scan_size; i++) | ||
333 | process_scan(data + scan_size*i, | ||
334 | channels, | ||
335 | num_channels); | ||
336 | } | ||
337 | |||
338 | /* Stop the buffer */ | ||
339 | ret = write_sysfs_int("enable", buf_dir_name, 0); | ||
340 | if (ret < 0) | ||
341 | goto error_close_buffer_access; | ||
342 | |||
343 | if (!notrigger) | ||
344 | /* Disconnect the trigger - just write a dummy name. */ | ||
345 | write_sysfs_string("trigger/current_trigger", | ||
346 | dev_dir_name, "NULL"); | ||
347 | |||
348 | error_close_buffer_access: | ||
349 | close(fp); | ||
350 | error_free_data: | ||
351 | free(data); | ||
352 | error_free_buffer_access: | ||
353 | free(buffer_access); | ||
354 | error_free_buf_dir_name: | ||
355 | free(buf_dir_name); | ||
356 | error_free_triggername: | ||
357 | if (datardytrigger) | ||
358 | free(trigger_name); | ||
359 | error_ret: | ||
360 | return ret; | ||
361 | } | ||
diff --git a/tools/iio/iio_event_monitor.c b/tools/iio/iio_event_monitor.c new file mode 100644 index 000000000000..f19cff19900e --- /dev/null +++ b/tools/iio/iio_event_monitor.c | |||
@@ -0,0 +1,310 @@ | |||
1 | /* Industrialio event test code. | ||
2 | * | ||
3 | * Copyright (c) 2011-2012 Lars-Peter Clausen <lars@metafoo.de> | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | * | ||
9 | * This program is primarily intended as an example application. | ||
10 | * Reads the current buffer setup from sysfs and starts a short capture | ||
11 | * from the specified device, pretty printing the result after appropriate | ||
12 | * conversion. | ||
13 | * | ||
14 | * Usage: | ||
15 | * iio_event_monitor <device_name> | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #define _GNU_SOURCE | ||
20 | |||
21 | #include <unistd.h> | ||
22 | #include <stdlib.h> | ||
23 | #include <stdbool.h> | ||
24 | #include <stdio.h> | ||
25 | #include <errno.h> | ||
26 | #include <string.h> | ||
27 | #include <poll.h> | ||
28 | #include <fcntl.h> | ||
29 | #include <sys/ioctl.h> | ||
30 | #include "iio_utils.h" | ||
31 | #include <linux/iio/events.h> | ||
32 | #include <linux/iio/types.h> | ||
33 | |||
34 | static const char * const iio_chan_type_name_spec[] = { | ||
35 | [IIO_VOLTAGE] = "voltage", | ||
36 | [IIO_CURRENT] = "current", | ||
37 | [IIO_POWER] = "power", | ||
38 | [IIO_ACCEL] = "accel", | ||
39 | [IIO_ANGL_VEL] = "anglvel", | ||
40 | [IIO_MAGN] = "magn", | ||
41 | [IIO_LIGHT] = "illuminance", | ||
42 | [IIO_INTENSITY] = "intensity", | ||
43 | [IIO_PROXIMITY] = "proximity", | ||
44 | [IIO_TEMP] = "temp", | ||
45 | [IIO_INCLI] = "incli", | ||
46 | [IIO_ROT] = "rot", | ||
47 | [IIO_ANGL] = "angl", | ||
48 | [IIO_TIMESTAMP] = "timestamp", | ||
49 | [IIO_CAPACITANCE] = "capacitance", | ||
50 | [IIO_ALTVOLTAGE] = "altvoltage", | ||
51 | [IIO_CCT] = "cct", | ||
52 | [IIO_PRESSURE] = "pressure", | ||
53 | [IIO_HUMIDITYRELATIVE] = "humidityrelative", | ||
54 | [IIO_ACTIVITY] = "activity", | ||
55 | [IIO_STEPS] = "steps", | ||
56 | }; | ||
57 | |||
58 | static const char * const iio_ev_type_text[] = { | ||
59 | [IIO_EV_TYPE_THRESH] = "thresh", | ||
60 | [IIO_EV_TYPE_MAG] = "mag", | ||
61 | [IIO_EV_TYPE_ROC] = "roc", | ||
62 | [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", | ||
63 | [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", | ||
64 | [IIO_EV_TYPE_CHANGE] = "change", | ||
65 | }; | ||
66 | |||
67 | static const char * const iio_ev_dir_text[] = { | ||
68 | [IIO_EV_DIR_EITHER] = "either", | ||
69 | [IIO_EV_DIR_RISING] = "rising", | ||
70 | [IIO_EV_DIR_FALLING] = "falling" | ||
71 | }; | ||
72 | |||
73 | static const char * const iio_modifier_names[] = { | ||
74 | [IIO_MOD_X] = "x", | ||
75 | [IIO_MOD_Y] = "y", | ||
76 | [IIO_MOD_Z] = "z", | ||
77 | [IIO_MOD_X_AND_Y] = "x&y", | ||
78 | [IIO_MOD_X_AND_Z] = "x&z", | ||
79 | [IIO_MOD_Y_AND_Z] = "y&z", | ||
80 | [IIO_MOD_X_AND_Y_AND_Z] = "x&y&z", | ||
81 | [IIO_MOD_X_OR_Y] = "x|y", | ||
82 | [IIO_MOD_X_OR_Z] = "x|z", | ||
83 | [IIO_MOD_Y_OR_Z] = "y|z", | ||
84 | [IIO_MOD_X_OR_Y_OR_Z] = "x|y|z", | ||
85 | [IIO_MOD_LIGHT_BOTH] = "both", | ||
86 | [IIO_MOD_LIGHT_IR] = "ir", | ||
87 | [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)", | ||
88 | [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2", | ||
89 | [IIO_MOD_LIGHT_CLEAR] = "clear", | ||
90 | [IIO_MOD_LIGHT_RED] = "red", | ||
91 | [IIO_MOD_LIGHT_GREEN] = "green", | ||
92 | [IIO_MOD_LIGHT_BLUE] = "blue", | ||
93 | [IIO_MOD_QUATERNION] = "quaternion", | ||
94 | [IIO_MOD_TEMP_AMBIENT] = "ambient", | ||
95 | [IIO_MOD_TEMP_OBJECT] = "object", | ||
96 | [IIO_MOD_NORTH_MAGN] = "from_north_magnetic", | ||
97 | [IIO_MOD_NORTH_TRUE] = "from_north_true", | ||
98 | [IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp", | ||
99 | [IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp", | ||
100 | [IIO_MOD_RUNNING] = "running", | ||
101 | [IIO_MOD_JOGGING] = "jogging", | ||
102 | [IIO_MOD_WALKING] = "walking", | ||
103 | [IIO_MOD_STILL] = "still", | ||
104 | }; | ||
105 | |||
106 | static bool event_is_known(struct iio_event_data *event) | ||
107 | { | ||
108 | enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); | ||
109 | enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); | ||
110 | enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); | ||
111 | enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); | ||
112 | |||
113 | switch (type) { | ||
114 | case IIO_VOLTAGE: | ||
115 | case IIO_CURRENT: | ||
116 | case IIO_POWER: | ||
117 | case IIO_ACCEL: | ||
118 | case IIO_ANGL_VEL: | ||
119 | case IIO_MAGN: | ||
120 | case IIO_LIGHT: | ||
121 | case IIO_INTENSITY: | ||
122 | case IIO_PROXIMITY: | ||
123 | case IIO_TEMP: | ||
124 | case IIO_INCLI: | ||
125 | case IIO_ROT: | ||
126 | case IIO_ANGL: | ||
127 | case IIO_TIMESTAMP: | ||
128 | case IIO_CAPACITANCE: | ||
129 | case IIO_ALTVOLTAGE: | ||
130 | case IIO_CCT: | ||
131 | case IIO_PRESSURE: | ||
132 | case IIO_HUMIDITYRELATIVE: | ||
133 | case IIO_ACTIVITY: | ||
134 | case IIO_STEPS: | ||
135 | break; | ||
136 | default: | ||
137 | return false; | ||
138 | } | ||
139 | |||
140 | switch (mod) { | ||
141 | case IIO_NO_MOD: | ||
142 | case IIO_MOD_X: | ||
143 | case IIO_MOD_Y: | ||
144 | case IIO_MOD_Z: | ||
145 | case IIO_MOD_X_AND_Y: | ||
146 | case IIO_MOD_X_AND_Z: | ||
147 | case IIO_MOD_Y_AND_Z: | ||
148 | case IIO_MOD_X_AND_Y_AND_Z: | ||
149 | case IIO_MOD_X_OR_Y: | ||
150 | case IIO_MOD_X_OR_Z: | ||
151 | case IIO_MOD_Y_OR_Z: | ||
152 | case IIO_MOD_X_OR_Y_OR_Z: | ||
153 | case IIO_MOD_LIGHT_BOTH: | ||
154 | case IIO_MOD_LIGHT_IR: | ||
155 | case IIO_MOD_ROOT_SUM_SQUARED_X_Y: | ||
156 | case IIO_MOD_SUM_SQUARED_X_Y_Z: | ||
157 | case IIO_MOD_LIGHT_CLEAR: | ||
158 | case IIO_MOD_LIGHT_RED: | ||
159 | case IIO_MOD_LIGHT_GREEN: | ||
160 | case IIO_MOD_LIGHT_BLUE: | ||
161 | case IIO_MOD_QUATERNION: | ||
162 | case IIO_MOD_TEMP_AMBIENT: | ||
163 | case IIO_MOD_TEMP_OBJECT: | ||
164 | case IIO_MOD_NORTH_MAGN: | ||
165 | case IIO_MOD_NORTH_TRUE: | ||
166 | case IIO_MOD_NORTH_MAGN_TILT_COMP: | ||
167 | case IIO_MOD_NORTH_TRUE_TILT_COMP: | ||
168 | case IIO_MOD_RUNNING: | ||
169 | case IIO_MOD_JOGGING: | ||
170 | case IIO_MOD_WALKING: | ||
171 | case IIO_MOD_STILL: | ||
172 | break; | ||
173 | default: | ||
174 | return false; | ||
175 | } | ||
176 | |||
177 | switch (ev_type) { | ||
178 | case IIO_EV_TYPE_THRESH: | ||
179 | case IIO_EV_TYPE_MAG: | ||
180 | case IIO_EV_TYPE_ROC: | ||
181 | case IIO_EV_TYPE_THRESH_ADAPTIVE: | ||
182 | case IIO_EV_TYPE_MAG_ADAPTIVE: | ||
183 | case IIO_EV_TYPE_CHANGE: | ||
184 | break; | ||
185 | default: | ||
186 | return false; | ||
187 | } | ||
188 | |||
189 | switch (dir) { | ||
190 | case IIO_EV_DIR_EITHER: | ||
191 | case IIO_EV_DIR_RISING: | ||
192 | case IIO_EV_DIR_FALLING: | ||
193 | case IIO_EV_DIR_NONE: | ||
194 | break; | ||
195 | default: | ||
196 | return false; | ||
197 | } | ||
198 | |||
199 | return true; | ||
200 | } | ||
201 | |||
202 | static void print_event(struct iio_event_data *event) | ||
203 | { | ||
204 | enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); | ||
205 | enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); | ||
206 | enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); | ||
207 | enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); | ||
208 | int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event->id); | ||
209 | int chan2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id); | ||
210 | bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id); | ||
211 | |||
212 | if (!event_is_known(event)) { | ||
213 | printf("Unknown event: time: %lld, id: %llx\n", | ||
214 | event->timestamp, event->id); | ||
215 | return; | ||
216 | } | ||
217 | |||
218 | printf("Event: time: %lld, ", event->timestamp); | ||
219 | |||
220 | if (mod != IIO_NO_MOD) { | ||
221 | printf("type: %s(%s), ", | ||
222 | iio_chan_type_name_spec[type], | ||
223 | iio_modifier_names[mod]); | ||
224 | } else { | ||
225 | printf("type: %s, ", | ||
226 | iio_chan_type_name_spec[type]); | ||
227 | } | ||
228 | |||
229 | if (diff && chan >= 0 && chan2 >= 0) | ||
230 | printf("channel: %d-%d, ", chan, chan2); | ||
231 | else if (chan >= 0) | ||
232 | printf("channel: %d, ", chan); | ||
233 | |||
234 | printf("evtype: %s", iio_ev_type_text[ev_type]); | ||
235 | |||
236 | if (dir != IIO_EV_DIR_NONE) | ||
237 | printf(", direction: %s", iio_ev_dir_text[dir]); | ||
238 | printf("\n"); | ||
239 | } | ||
240 | |||
241 | int main(int argc, char **argv) | ||
242 | { | ||
243 | struct iio_event_data event; | ||
244 | const char *device_name; | ||
245 | char *chrdev_name; | ||
246 | int ret; | ||
247 | int dev_num; | ||
248 | int fd, event_fd; | ||
249 | |||
250 | if (argc <= 1) { | ||
251 | printf("Usage: %s <device_name>\n", argv[0]); | ||
252 | return -1; | ||
253 | } | ||
254 | |||
255 | device_name = argv[1]; | ||
256 | |||
257 | dev_num = find_type_by_name(device_name, "iio:device"); | ||
258 | if (dev_num >= 0) { | ||
259 | printf("Found IIO device with name %s with device number %d\n", | ||
260 | device_name, dev_num); | ||
261 | ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num); | ||
262 | if (ret < 0) { | ||
263 | ret = -ENOMEM; | ||
264 | goto error_ret; | ||
265 | } | ||
266 | } else { | ||
267 | /* If we can't find a IIO device by name assume device_name is a | ||
268 | IIO chrdev */ | ||
269 | chrdev_name = strdup(device_name); | ||
270 | } | ||
271 | |||
272 | fd = open(chrdev_name, 0); | ||
273 | if (fd == -1) { | ||
274 | fprintf(stdout, "Failed to open %s\n", chrdev_name); | ||
275 | ret = -errno; | ||
276 | goto error_free_chrdev_name; | ||
277 | } | ||
278 | |||
279 | ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd); | ||
280 | |||
281 | close(fd); | ||
282 | |||
283 | if (ret == -1 || event_fd == -1) { | ||
284 | fprintf(stdout, "Failed to retrieve event fd\n"); | ||
285 | ret = -errno; | ||
286 | goto error_free_chrdev_name; | ||
287 | } | ||
288 | |||
289 | while (true) { | ||
290 | ret = read(event_fd, &event, sizeof(event)); | ||
291 | if (ret == -1) { | ||
292 | if (errno == EAGAIN) { | ||
293 | printf("nothing available\n"); | ||
294 | continue; | ||
295 | } else { | ||
296 | perror("Failed to read event from device"); | ||
297 | ret = -errno; | ||
298 | break; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | print_event(&event); | ||
303 | } | ||
304 | |||
305 | close(event_fd); | ||
306 | error_free_chrdev_name: | ||
307 | free(chrdev_name); | ||
308 | error_ret: | ||
309 | return ret; | ||
310 | } | ||
diff --git a/tools/iio/iio_utils.c b/tools/iio/iio_utils.c new file mode 100644 index 000000000000..aea928210187 --- /dev/null +++ b/tools/iio/iio_utils.c | |||
@@ -0,0 +1,651 @@ | |||
1 | /* IIO - useful set of util functionality | ||
2 | * | ||
3 | * Copyright (c) 2008 Jonathan Cameron | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU General Public License version 2 as published by | ||
7 | * the Free Software Foundation. | ||
8 | */ | ||
9 | |||
10 | #include <string.h> | ||
11 | #include <stdlib.h> | ||
12 | #include <stdio.h> | ||
13 | #include <stdint.h> | ||
14 | #include <dirent.h> | ||
15 | #include <errno.h> | ||
16 | #include <ctype.h> | ||
17 | #include "iio_utils.h" | ||
18 | |||
19 | const char *iio_dir = "/sys/bus/iio/devices/"; | ||
20 | |||
21 | /** | ||
22 | * iioutils_break_up_name() - extract generic name from full channel name | ||
23 | * @full_name: the full channel name | ||
24 | * @generic_name: the output generic channel name | ||
25 | **/ | ||
26 | int iioutils_break_up_name(const char *full_name, | ||
27 | char **generic_name) | ||
28 | { | ||
29 | char *current; | ||
30 | char *w, *r; | ||
31 | char *working; | ||
32 | |||
33 | current = strdup(full_name); | ||
34 | working = strtok(current, "_\0"); | ||
35 | w = working; | ||
36 | r = working; | ||
37 | |||
38 | while (*r != '\0') { | ||
39 | if (!isdigit(*r)) { | ||
40 | *w = *r; | ||
41 | w++; | ||
42 | } | ||
43 | r++; | ||
44 | } | ||
45 | *w = '\0'; | ||
46 | *generic_name = strdup(working); | ||
47 | free(current); | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | /** | ||
53 | * iioutils_get_type() - find and process _type attribute data | ||
54 | * @is_signed: output whether channel is signed | ||
55 | * @bytes: output how many bytes the channel storage occupies | ||
56 | * @mask: output a bit mask for the raw data | ||
57 | * @be: big endian | ||
58 | * @device_dir: the iio device directory | ||
59 | * @name: the channel name | ||
60 | * @generic_name: the channel type name | ||
61 | **/ | ||
62 | int iioutils_get_type(unsigned *is_signed, | ||
63 | unsigned *bytes, | ||
64 | unsigned *bits_used, | ||
65 | unsigned *shift, | ||
66 | uint64_t *mask, | ||
67 | unsigned *be, | ||
68 | const char *device_dir, | ||
69 | const char *name, | ||
70 | const char *generic_name) | ||
71 | { | ||
72 | FILE *sysfsfp; | ||
73 | int ret; | ||
74 | DIR *dp; | ||
75 | char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; | ||
76 | char signchar, endianchar; | ||
77 | unsigned padint; | ||
78 | const struct dirent *ent; | ||
79 | |||
80 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); | ||
81 | if (ret < 0) { | ||
82 | ret = -ENOMEM; | ||
83 | goto error_ret; | ||
84 | } | ||
85 | ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); | ||
86 | if (ret < 0) { | ||
87 | ret = -ENOMEM; | ||
88 | goto error_free_scan_el_dir; | ||
89 | } | ||
90 | ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); | ||
91 | if (ret < 0) { | ||
92 | ret = -ENOMEM; | ||
93 | goto error_free_builtname; | ||
94 | } | ||
95 | |||
96 | dp = opendir(scan_el_dir); | ||
97 | if (dp == NULL) { | ||
98 | ret = -errno; | ||
99 | goto error_free_builtname_generic; | ||
100 | } | ||
101 | while (ent = readdir(dp), ent != NULL) | ||
102 | /* | ||
103 | * Do we allow devices to override a generic name with | ||
104 | * a specific one? | ||
105 | */ | ||
106 | if ((strcmp(builtname, ent->d_name) == 0) || | ||
107 | (strcmp(builtname_generic, ent->d_name) == 0)) { | ||
108 | ret = asprintf(&filename, | ||
109 | "%s/%s", scan_el_dir, ent->d_name); | ||
110 | if (ret < 0) { | ||
111 | ret = -ENOMEM; | ||
112 | goto error_closedir; | ||
113 | } | ||
114 | sysfsfp = fopen(filename, "r"); | ||
115 | if (sysfsfp == NULL) { | ||
116 | printf("failed to open %s\n", filename); | ||
117 | ret = -errno; | ||
118 | goto error_free_filename; | ||
119 | } | ||
120 | |||
121 | ret = fscanf(sysfsfp, | ||
122 | "%ce:%c%u/%u>>%u", | ||
123 | &endianchar, | ||
124 | &signchar, | ||
125 | bits_used, | ||
126 | &padint, shift); | ||
127 | if (ret < 0) { | ||
128 | printf("failed to pass scan type description\n"); | ||
129 | ret = -errno; | ||
130 | goto error_close_sysfsfp; | ||
131 | } | ||
132 | *be = (endianchar == 'b'); | ||
133 | *bytes = padint / 8; | ||
134 | if (*bits_used == 64) | ||
135 | *mask = ~0; | ||
136 | else | ||
137 | *mask = (1 << *bits_used) - 1; | ||
138 | if (signchar == 's') | ||
139 | *is_signed = 1; | ||
140 | else | ||
141 | *is_signed = 0; | ||
142 | fclose(sysfsfp); | ||
143 | free(filename); | ||
144 | |||
145 | filename = 0; | ||
146 | sysfsfp = 0; | ||
147 | } | ||
148 | error_close_sysfsfp: | ||
149 | if (sysfsfp) | ||
150 | fclose(sysfsfp); | ||
151 | error_free_filename: | ||
152 | if (filename) | ||
153 | free(filename); | ||
154 | error_closedir: | ||
155 | closedir(dp); | ||
156 | error_free_builtname_generic: | ||
157 | free(builtname_generic); | ||
158 | error_free_builtname: | ||
159 | free(builtname); | ||
160 | error_free_scan_el_dir: | ||
161 | free(scan_el_dir); | ||
162 | error_ret: | ||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | int iioutils_get_param_float(float *output, | ||
167 | const char *param_name, | ||
168 | const char *device_dir, | ||
169 | const char *name, | ||
170 | const char *generic_name) | ||
171 | { | ||
172 | FILE *sysfsfp; | ||
173 | int ret; | ||
174 | DIR *dp; | ||
175 | char *builtname, *builtname_generic; | ||
176 | char *filename = NULL; | ||
177 | const struct dirent *ent; | ||
178 | |||
179 | ret = asprintf(&builtname, "%s_%s", name, param_name); | ||
180 | if (ret < 0) { | ||
181 | ret = -ENOMEM; | ||
182 | goto error_ret; | ||
183 | } | ||
184 | ret = asprintf(&builtname_generic, | ||
185 | "%s_%s", generic_name, param_name); | ||
186 | if (ret < 0) { | ||
187 | ret = -ENOMEM; | ||
188 | goto error_free_builtname; | ||
189 | } | ||
190 | dp = opendir(device_dir); | ||
191 | if (dp == NULL) { | ||
192 | ret = -errno; | ||
193 | goto error_free_builtname_generic; | ||
194 | } | ||
195 | while (ent = readdir(dp), ent != NULL) | ||
196 | if ((strcmp(builtname, ent->d_name) == 0) || | ||
197 | (strcmp(builtname_generic, ent->d_name) == 0)) { | ||
198 | ret = asprintf(&filename, | ||
199 | "%s/%s", device_dir, ent->d_name); | ||
200 | if (ret < 0) { | ||
201 | ret = -ENOMEM; | ||
202 | goto error_closedir; | ||
203 | } | ||
204 | sysfsfp = fopen(filename, "r"); | ||
205 | if (!sysfsfp) { | ||
206 | ret = -errno; | ||
207 | goto error_free_filename; | ||
208 | } | ||
209 | fscanf(sysfsfp, "%f", output); | ||
210 | break; | ||
211 | } | ||
212 | error_free_filename: | ||
213 | if (filename) | ||
214 | free(filename); | ||
215 | error_closedir: | ||
216 | closedir(dp); | ||
217 | error_free_builtname_generic: | ||
218 | free(builtname_generic); | ||
219 | error_free_builtname: | ||
220 | free(builtname); | ||
221 | error_ret: | ||
222 | return ret; | ||
223 | } | ||
224 | |||
225 | /** | ||
226 | * bsort_channel_array_by_index() - reorder so that the array is in index order | ||
227 | * | ||
228 | **/ | ||
229 | |||
230 | void bsort_channel_array_by_index(struct iio_channel_info **ci_array, | ||
231 | int cnt) | ||
232 | { | ||
233 | |||
234 | struct iio_channel_info temp; | ||
235 | int x, y; | ||
236 | |||
237 | for (x = 0; x < cnt; x++) | ||
238 | for (y = 0; y < (cnt - 1); y++) | ||
239 | if ((*ci_array)[y].index > (*ci_array)[y+1].index) { | ||
240 | temp = (*ci_array)[y + 1]; | ||
241 | (*ci_array)[y + 1] = (*ci_array)[y]; | ||
242 | (*ci_array)[y] = temp; | ||
243 | } | ||
244 | } | ||
245 | |||
246 | /** | ||
247 | * build_channel_array() - function to figure out what channels are present | ||
248 | * @device_dir: the IIO device directory in sysfs | ||
249 | * @ | ||
250 | **/ | ||
251 | int build_channel_array(const char *device_dir, | ||
252 | struct iio_channel_info **ci_array, | ||
253 | int *counter) | ||
254 | { | ||
255 | DIR *dp; | ||
256 | FILE *sysfsfp; | ||
257 | int count, i; | ||
258 | struct iio_channel_info *current; | ||
259 | int ret; | ||
260 | const struct dirent *ent; | ||
261 | char *scan_el_dir; | ||
262 | char *filename; | ||
263 | |||
264 | *counter = 0; | ||
265 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); | ||
266 | if (ret < 0) { | ||
267 | ret = -ENOMEM; | ||
268 | goto error_ret; | ||
269 | } | ||
270 | dp = opendir(scan_el_dir); | ||
271 | if (dp == NULL) { | ||
272 | ret = -errno; | ||
273 | goto error_free_name; | ||
274 | } | ||
275 | while (ent = readdir(dp), ent != NULL) | ||
276 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), | ||
277 | "_en") == 0) { | ||
278 | ret = asprintf(&filename, | ||
279 | "%s/%s", scan_el_dir, ent->d_name); | ||
280 | if (ret < 0) { | ||
281 | ret = -ENOMEM; | ||
282 | goto error_close_dir; | ||
283 | } | ||
284 | sysfsfp = fopen(filename, "r"); | ||
285 | if (sysfsfp == NULL) { | ||
286 | ret = -errno; | ||
287 | free(filename); | ||
288 | goto error_close_dir; | ||
289 | } | ||
290 | fscanf(sysfsfp, "%i", &ret); | ||
291 | if (ret == 1) | ||
292 | (*counter)++; | ||
293 | fclose(sysfsfp); | ||
294 | free(filename); | ||
295 | } | ||
296 | *ci_array = malloc(sizeof(**ci_array) * (*counter)); | ||
297 | if (*ci_array == NULL) { | ||
298 | ret = -ENOMEM; | ||
299 | goto error_close_dir; | ||
300 | } | ||
301 | seekdir(dp, 0); | ||
302 | count = 0; | ||
303 | while (ent = readdir(dp), ent != NULL) { | ||
304 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), | ||
305 | "_en") == 0) { | ||
306 | int current_enabled = 0; | ||
307 | |||
308 | current = &(*ci_array)[count++]; | ||
309 | ret = asprintf(&filename, | ||
310 | "%s/%s", scan_el_dir, ent->d_name); | ||
311 | if (ret < 0) { | ||
312 | ret = -ENOMEM; | ||
313 | /* decrement count to avoid freeing name */ | ||
314 | count--; | ||
315 | goto error_cleanup_array; | ||
316 | } | ||
317 | sysfsfp = fopen(filename, "r"); | ||
318 | if (sysfsfp == NULL) { | ||
319 | free(filename); | ||
320 | ret = -errno; | ||
321 | goto error_cleanup_array; | ||
322 | } | ||
323 | fscanf(sysfsfp, "%i", ¤t_enabled); | ||
324 | fclose(sysfsfp); | ||
325 | |||
326 | if (!current_enabled) { | ||
327 | free(filename); | ||
328 | count--; | ||
329 | continue; | ||
330 | } | ||
331 | |||
332 | current->scale = 1.0; | ||
333 | current->offset = 0; | ||
334 | current->name = strndup(ent->d_name, | ||
335 | strlen(ent->d_name) - | ||
336 | strlen("_en")); | ||
337 | if (current->name == NULL) { | ||
338 | free(filename); | ||
339 | ret = -ENOMEM; | ||
340 | goto error_cleanup_array; | ||
341 | } | ||
342 | /* Get the generic and specific name elements */ | ||
343 | ret = iioutils_break_up_name(current->name, | ||
344 | ¤t->generic_name); | ||
345 | if (ret) { | ||
346 | free(filename); | ||
347 | goto error_cleanup_array; | ||
348 | } | ||
349 | ret = asprintf(&filename, | ||
350 | "%s/%s_index", | ||
351 | scan_el_dir, | ||
352 | current->name); | ||
353 | if (ret < 0) { | ||
354 | free(filename); | ||
355 | ret = -ENOMEM; | ||
356 | goto error_cleanup_array; | ||
357 | } | ||
358 | sysfsfp = fopen(filename, "r"); | ||
359 | fscanf(sysfsfp, "%u", ¤t->index); | ||
360 | fclose(sysfsfp); | ||
361 | free(filename); | ||
362 | /* Find the scale */ | ||
363 | ret = iioutils_get_param_float(¤t->scale, | ||
364 | "scale", | ||
365 | device_dir, | ||
366 | current->name, | ||
367 | current->generic_name); | ||
368 | if (ret < 0) | ||
369 | goto error_cleanup_array; | ||
370 | ret = iioutils_get_param_float(¤t->offset, | ||
371 | "offset", | ||
372 | device_dir, | ||
373 | current->name, | ||
374 | current->generic_name); | ||
375 | if (ret < 0) | ||
376 | goto error_cleanup_array; | ||
377 | ret = iioutils_get_type(¤t->is_signed, | ||
378 | ¤t->bytes, | ||
379 | ¤t->bits_used, | ||
380 | ¤t->shift, | ||
381 | ¤t->mask, | ||
382 | ¤t->be, | ||
383 | device_dir, | ||
384 | current->name, | ||
385 | current->generic_name); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | closedir(dp); | ||
390 | /* reorder so that the array is in index order */ | ||
391 | bsort_channel_array_by_index(ci_array, *counter); | ||
392 | |||
393 | return 0; | ||
394 | |||
395 | error_cleanup_array: | ||
396 | for (i = count - 1; i >= 0; i--) | ||
397 | free((*ci_array)[i].name); | ||
398 | free(*ci_array); | ||
399 | error_close_dir: | ||
400 | closedir(dp); | ||
401 | error_free_name: | ||
402 | free(scan_el_dir); | ||
403 | error_ret: | ||
404 | return ret; | ||
405 | } | ||
406 | |||
407 | /** | ||
408 | * find_type_by_name() - function to match top level types by name | ||
409 | * @name: top level type instance name | ||
410 | * @type: the type of top level instance being sort | ||
411 | * | ||
412 | * Typical types this is used for are device and trigger. | ||
413 | **/ | ||
414 | int find_type_by_name(const char *name, const char *type) | ||
415 | { | ||
416 | const struct dirent *ent; | ||
417 | int number, numstrlen; | ||
418 | |||
419 | FILE *nameFile; | ||
420 | DIR *dp; | ||
421 | char thisname[IIO_MAX_NAME_LENGTH]; | ||
422 | char *filename; | ||
423 | |||
424 | dp = opendir(iio_dir); | ||
425 | if (dp == NULL) { | ||
426 | printf("No industrialio devices available\n"); | ||
427 | return -ENODEV; | ||
428 | } | ||
429 | |||
430 | while (ent = readdir(dp), ent != NULL) { | ||
431 | if (strcmp(ent->d_name, ".") != 0 && | ||
432 | strcmp(ent->d_name, "..") != 0 && | ||
433 | strlen(ent->d_name) > strlen(type) && | ||
434 | strncmp(ent->d_name, type, strlen(type)) == 0) { | ||
435 | numstrlen = sscanf(ent->d_name + strlen(type), | ||
436 | "%d", | ||
437 | &number); | ||
438 | /* verify the next character is not a colon */ | ||
439 | if (strncmp(ent->d_name + strlen(type) + numstrlen, | ||
440 | ":", | ||
441 | 1) != 0) { | ||
442 | filename = malloc(strlen(iio_dir) | ||
443 | + strlen(type) | ||
444 | + numstrlen | ||
445 | + 6); | ||
446 | if (filename == NULL) { | ||
447 | closedir(dp); | ||
448 | return -ENOMEM; | ||
449 | } | ||
450 | sprintf(filename, "%s%s%d/name", | ||
451 | iio_dir, | ||
452 | type, | ||
453 | number); | ||
454 | nameFile = fopen(filename, "r"); | ||
455 | if (!nameFile) { | ||
456 | free(filename); | ||
457 | continue; | ||
458 | } | ||
459 | free(filename); | ||
460 | fscanf(nameFile, "%s", thisname); | ||
461 | fclose(nameFile); | ||
462 | if (strcmp(name, thisname) == 0) { | ||
463 | closedir(dp); | ||
464 | return number; | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | } | ||
469 | closedir(dp); | ||
470 | return -ENODEV; | ||
471 | } | ||
472 | |||
473 | int _write_sysfs_int(char *filename, char *basedir, int val, int verify) | ||
474 | { | ||
475 | int ret = 0; | ||
476 | FILE *sysfsfp; | ||
477 | int test; | ||
478 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); | ||
479 | |||
480 | if (temp == NULL) | ||
481 | return -ENOMEM; | ||
482 | sprintf(temp, "%s/%s", basedir, filename); | ||
483 | sysfsfp = fopen(temp, "w"); | ||
484 | if (sysfsfp == NULL) { | ||
485 | printf("failed to open %s\n", temp); | ||
486 | ret = -errno; | ||
487 | goto error_free; | ||
488 | } | ||
489 | fprintf(sysfsfp, "%d", val); | ||
490 | fclose(sysfsfp); | ||
491 | if (verify) { | ||
492 | sysfsfp = fopen(temp, "r"); | ||
493 | if (sysfsfp == NULL) { | ||
494 | printf("failed to open %s\n", temp); | ||
495 | ret = -errno; | ||
496 | goto error_free; | ||
497 | } | ||
498 | fscanf(sysfsfp, "%d", &test); | ||
499 | fclose(sysfsfp); | ||
500 | if (test != val) { | ||
501 | printf("Possible failure in int write %d to %s%s\n", | ||
502 | val, | ||
503 | basedir, | ||
504 | filename); | ||
505 | ret = -1; | ||
506 | } | ||
507 | } | ||
508 | error_free: | ||
509 | free(temp); | ||
510 | return ret; | ||
511 | } | ||
512 | |||
513 | int write_sysfs_int(char *filename, char *basedir, int val) | ||
514 | { | ||
515 | return _write_sysfs_int(filename, basedir, val, 0); | ||
516 | } | ||
517 | |||
518 | int write_sysfs_int_and_verify(char *filename, char *basedir, int val) | ||
519 | { | ||
520 | return _write_sysfs_int(filename, basedir, val, 1); | ||
521 | } | ||
522 | |||
523 | int _write_sysfs_string(char *filename, char *basedir, char *val, int verify) | ||
524 | { | ||
525 | int ret = 0; | ||
526 | FILE *sysfsfp; | ||
527 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); | ||
528 | |||
529 | if (temp == NULL) { | ||
530 | printf("Memory allocation failed\n"); | ||
531 | return -ENOMEM; | ||
532 | } | ||
533 | sprintf(temp, "%s/%s", basedir, filename); | ||
534 | sysfsfp = fopen(temp, "w"); | ||
535 | if (sysfsfp == NULL) { | ||
536 | printf("Could not open %s\n", temp); | ||
537 | ret = -errno; | ||
538 | goto error_free; | ||
539 | } | ||
540 | fprintf(sysfsfp, "%s", val); | ||
541 | fclose(sysfsfp); | ||
542 | if (verify) { | ||
543 | sysfsfp = fopen(temp, "r"); | ||
544 | if (sysfsfp == NULL) { | ||
545 | printf("could not open file to verify\n"); | ||
546 | ret = -errno; | ||
547 | goto error_free; | ||
548 | } | ||
549 | fscanf(sysfsfp, "%s", temp); | ||
550 | fclose(sysfsfp); | ||
551 | if (strcmp(temp, val) != 0) { | ||
552 | printf("Possible failure in string write of %s " | ||
553 | "Should be %s " | ||
554 | "written to %s\%s\n", | ||
555 | temp, | ||
556 | val, | ||
557 | basedir, | ||
558 | filename); | ||
559 | ret = -1; | ||
560 | } | ||
561 | } | ||
562 | error_free: | ||
563 | free(temp); | ||
564 | |||
565 | return ret; | ||
566 | } | ||
567 | |||
568 | /** | ||
569 | * write_sysfs_string_and_verify() - string write, readback and verify | ||
570 | * @filename: name of file to write to | ||
571 | * @basedir: the sysfs directory in which the file is to be found | ||
572 | * @val: the string to write | ||
573 | **/ | ||
574 | int write_sysfs_string_and_verify(char *filename, char *basedir, char *val) | ||
575 | { | ||
576 | return _write_sysfs_string(filename, basedir, val, 1); | ||
577 | } | ||
578 | |||
579 | int write_sysfs_string(char *filename, char *basedir, char *val) | ||
580 | { | ||
581 | return _write_sysfs_string(filename, basedir, val, 0); | ||
582 | } | ||
583 | |||
584 | int read_sysfs_posint(char *filename, char *basedir) | ||
585 | { | ||
586 | int ret; | ||
587 | FILE *sysfsfp; | ||
588 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); | ||
589 | |||
590 | if (temp == NULL) { | ||
591 | printf("Memory allocation failed"); | ||
592 | return -ENOMEM; | ||
593 | } | ||
594 | sprintf(temp, "%s/%s", basedir, filename); | ||
595 | sysfsfp = fopen(temp, "r"); | ||
596 | if (sysfsfp == NULL) { | ||
597 | ret = -errno; | ||
598 | goto error_free; | ||
599 | } | ||
600 | fscanf(sysfsfp, "%d\n", &ret); | ||
601 | fclose(sysfsfp); | ||
602 | error_free: | ||
603 | free(temp); | ||
604 | return ret; | ||
605 | } | ||
606 | |||
607 | int read_sysfs_float(char *filename, char *basedir, float *val) | ||
608 | { | ||
609 | int ret = 0; | ||
610 | FILE *sysfsfp; | ||
611 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); | ||
612 | |||
613 | if (temp == NULL) { | ||
614 | printf("Memory allocation failed"); | ||
615 | return -ENOMEM; | ||
616 | } | ||
617 | sprintf(temp, "%s/%s", basedir, filename); | ||
618 | sysfsfp = fopen(temp, "r"); | ||
619 | if (sysfsfp == NULL) { | ||
620 | ret = -errno; | ||
621 | goto error_free; | ||
622 | } | ||
623 | fscanf(sysfsfp, "%f\n", val); | ||
624 | fclose(sysfsfp); | ||
625 | error_free: | ||
626 | free(temp); | ||
627 | return ret; | ||
628 | } | ||
629 | |||
630 | int read_sysfs_string(const char *filename, const char *basedir, char *str) | ||
631 | { | ||
632 | int ret = 0; | ||
633 | FILE *sysfsfp; | ||
634 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); | ||
635 | |||
636 | if (temp == NULL) { | ||
637 | printf("Memory allocation failed"); | ||
638 | return -ENOMEM; | ||
639 | } | ||
640 | sprintf(temp, "%s/%s", basedir, filename); | ||
641 | sysfsfp = fopen(temp, "r"); | ||
642 | if (sysfsfp == NULL) { | ||
643 | ret = -errno; | ||
644 | goto error_free; | ||
645 | } | ||
646 | fscanf(sysfsfp, "%s\n", str); | ||
647 | fclose(sysfsfp); | ||
648 | error_free: | ||
649 | free(temp); | ||
650 | return ret; | ||
651 | } | ||
diff --git a/tools/iio/iio_utils.h b/tools/iio/iio_utils.h new file mode 100644 index 000000000000..1bc837b2d769 --- /dev/null +++ b/tools/iio/iio_utils.h | |||
@@ -0,0 +1,71 @@ | |||
1 | #ifndef _IIO_UTILS_H_ | ||
2 | #define _IIO_UTILS_H_ | ||
3 | |||
4 | /* IIO - useful set of util functionality | ||
5 | * | ||
6 | * Copyright (c) 2008 Jonathan Cameron | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify it | ||
9 | * under the terms of the GNU General Public License version 2 as published by | ||
10 | * the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include <stdint.h> | ||
14 | |||
15 | /* Made up value to limit allocation sizes */ | ||
16 | #define IIO_MAX_NAME_LENGTH 30 | ||
17 | |||
18 | #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" | ||
19 | #define FORMAT_TYPE_FILE "%s_type" | ||
20 | |||
21 | extern const char *iio_dir; | ||
22 | |||
23 | /** | ||
24 | * struct iio_channel_info - information about a given channel | ||
25 | * @name: channel name | ||
26 | * @generic_name: general name for channel type | ||
27 | * @scale: scale factor to be applied for conversion to si units | ||
28 | * @offset: offset to be applied for conversion to si units | ||
29 | * @index: the channel index in the buffer output | ||
30 | * @bytes: number of bytes occupied in buffer output | ||
31 | * @mask: a bit mask for the raw output | ||
32 | * @is_signed: is the raw value stored signed | ||
33 | * @enabled: is this channel enabled | ||
34 | **/ | ||
35 | struct iio_channel_info { | ||
36 | char *name; | ||
37 | char *generic_name; | ||
38 | float scale; | ||
39 | float offset; | ||
40 | unsigned index; | ||
41 | unsigned bytes; | ||
42 | unsigned bits_used; | ||
43 | unsigned shift; | ||
44 | uint64_t mask; | ||
45 | unsigned be; | ||
46 | unsigned is_signed; | ||
47 | unsigned location; | ||
48 | }; | ||
49 | |||
50 | int iioutils_break_up_name(const char *full_name, char **generic_name); | ||
51 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, | ||
52 | unsigned *bits_used, unsigned *shift, | ||
53 | uint64_t *mask, unsigned *be, | ||
54 | const char *device_dir, const char *name, | ||
55 | const char *generic_name); | ||
56 | int iioutils_get_param_float(float *output, const char *param_name, | ||
57 | const char *device_dir, const char *name, | ||
58 | const char *generic_name); | ||
59 | void bsort_channel_array_by_index(struct iio_channel_info **ci_array, int cnt); | ||
60 | int build_channel_array(const char *device_dir, | ||
61 | struct iio_channel_info **ci_array, int *counter); | ||
62 | int find_type_by_name(const char *name, const char *type); | ||
63 | int write_sysfs_int(char *filename, char *basedir, int val); | ||
64 | int write_sysfs_int_and_verify(char *filename, char *basedir, int val); | ||
65 | int write_sysfs_string_and_verify(char *filename, char *basedir, char *val); | ||
66 | int write_sysfs_string(char *filename, char *basedir, char *val); | ||
67 | int read_sysfs_posint(char *filename, char *basedir); | ||
68 | int read_sysfs_float(char *filename, char *basedir, float *val); | ||
69 | int read_sysfs_string(const char *filename, const char *basedir, char *str); | ||
70 | |||
71 | #endif /* _IIO_UTILS_H_ */ | ||
diff --git a/tools/iio/lsiio.c b/tools/iio/lsiio.c new file mode 100644 index 000000000000..98a0de098130 --- /dev/null +++ b/tools/iio/lsiio.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /* | ||
2 | * Industrial I/O utilities - lsiio.c | ||
3 | * | ||
4 | * Copyright (c) 2010 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published by | ||
8 | * the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <string.h> | ||
12 | #include <dirent.h> | ||
13 | #include <stdio.h> | ||
14 | #include <errno.h> | ||
15 | #include <stdint.h> | ||
16 | #include <stdlib.h> | ||
17 | #include <unistd.h> | ||
18 | #include <sys/types.h> | ||
19 | #include <sys/stat.h> | ||
20 | #include <sys/dir.h> | ||
21 | #include "iio_utils.h" | ||
22 | |||
23 | |||
24 | static enum verbosity { | ||
25 | VERBLEVEL_DEFAULT, /* 0 gives lspci behaviour */ | ||
26 | VERBLEVEL_SENSORS, /* 1 lists sensors */ | ||
27 | } verblevel = VERBLEVEL_DEFAULT; | ||
28 | |||
29 | const char *type_device = "iio:device"; | ||
30 | const char *type_trigger = "trigger"; | ||
31 | |||
32 | |||
33 | static inline int check_prefix(const char *str, const char *prefix) | ||
34 | { | ||
35 | return strlen(str) > strlen(prefix) && | ||
36 | strncmp(str, prefix, strlen(prefix)) == 0; | ||
37 | } | ||
38 | |||
39 | static inline int check_postfix(const char *str, const char *postfix) | ||
40 | { | ||
41 | return strlen(str) > strlen(postfix) && | ||
42 | strcmp(str + strlen(str) - strlen(postfix), postfix) == 0; | ||
43 | } | ||
44 | |||
45 | static int dump_channels(const char *dev_dir_name) | ||
46 | { | ||
47 | DIR *dp; | ||
48 | const struct dirent *ent; | ||
49 | |||
50 | dp = opendir(dev_dir_name); | ||
51 | if (dp == NULL) | ||
52 | return -errno; | ||
53 | while (ent = readdir(dp), ent != NULL) | ||
54 | if (check_prefix(ent->d_name, "in_") && | ||
55 | check_postfix(ent->d_name, "_raw")) { | ||
56 | printf(" %-10s\n", ent->d_name); | ||
57 | } | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int dump_one_device(const char *dev_dir_name) | ||
63 | { | ||
64 | char name[IIO_MAX_NAME_LENGTH]; | ||
65 | int dev_idx; | ||
66 | int retval; | ||
67 | |||
68 | retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_device), | ||
69 | "%i", &dev_idx); | ||
70 | if (retval != 1) | ||
71 | return -EINVAL; | ||
72 | read_sysfs_string("name", dev_dir_name, name); | ||
73 | printf("Device %03d: %s\n", dev_idx, name); | ||
74 | |||
75 | if (verblevel >= VERBLEVEL_SENSORS) | ||
76 | return dump_channels(dev_dir_name); | ||
77 | return 0; | ||
78 | } | ||
79 | |||
80 | static int dump_one_trigger(const char *dev_dir_name) | ||
81 | { | ||
82 | char name[IIO_MAX_NAME_LENGTH]; | ||
83 | int dev_idx; | ||
84 | int retval; | ||
85 | |||
86 | retval = sscanf(dev_dir_name + strlen(iio_dir) + strlen(type_trigger), | ||
87 | "%i", &dev_idx); | ||
88 | if (retval != 1) | ||
89 | return -EINVAL; | ||
90 | read_sysfs_string("name", dev_dir_name, name); | ||
91 | printf("Trigger %03d: %s\n", dev_idx, name); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static void dump_devices(void) | ||
96 | { | ||
97 | const struct dirent *ent; | ||
98 | int number, numstrlen; | ||
99 | |||
100 | FILE *nameFile; | ||
101 | DIR *dp; | ||
102 | char thisname[IIO_MAX_NAME_LENGTH]; | ||
103 | char *filename; | ||
104 | |||
105 | dp = opendir(iio_dir); | ||
106 | if (dp == NULL) { | ||
107 | printf("No industrial I/O devices available\n"); | ||
108 | return; | ||
109 | } | ||
110 | |||
111 | while (ent = readdir(dp), ent != NULL) { | ||
112 | if (check_prefix(ent->d_name, type_device)) { | ||
113 | char *dev_dir_name; | ||
114 | |||
115 | asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); | ||
116 | dump_one_device(dev_dir_name); | ||
117 | free(dev_dir_name); | ||
118 | if (verblevel >= VERBLEVEL_SENSORS) | ||
119 | printf("\n"); | ||
120 | } | ||
121 | } | ||
122 | rewinddir(dp); | ||
123 | while (ent = readdir(dp), ent != NULL) { | ||
124 | if (check_prefix(ent->d_name, type_trigger)) { | ||
125 | char *dev_dir_name; | ||
126 | |||
127 | asprintf(&dev_dir_name, "%s%s", iio_dir, ent->d_name); | ||
128 | dump_one_trigger(dev_dir_name); | ||
129 | free(dev_dir_name); | ||
130 | } | ||
131 | } | ||
132 | closedir(dp); | ||
133 | } | ||
134 | |||
135 | int main(int argc, char **argv) | ||
136 | { | ||
137 | int c, err = 0; | ||
138 | |||
139 | while ((c = getopt(argc, argv, "d:D:v")) != EOF) { | ||
140 | switch (c) { | ||
141 | case 'v': | ||
142 | verblevel++; | ||
143 | break; | ||
144 | |||
145 | case '?': | ||
146 | default: | ||
147 | err++; | ||
148 | break; | ||
149 | } | ||
150 | } | ||
151 | if (err || argc > optind) { | ||
152 | fprintf(stderr, "Usage: lsiio [options]...\n" | ||
153 | "List industrial I/O devices\n" | ||
154 | " -v, --verbose\n" | ||
155 | " Increase verbosity (may be given multiple times)\n" | ||
156 | ); | ||
157 | exit(1); | ||
158 | } | ||
159 | |||
160 | dump_devices(); | ||
161 | |||
162 | return 0; | ||
163 | } | ||