]>
Commit | Line | Data |
---|---|---|
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 | #include <unistd.h> | |
22 | #include <dirent.h> | |
23 | #include <fcntl.h> | |
24 | #include <stdio.h> | |
25 | #include <errno.h> | |
26 | #include <sys/stat.h> | |
27 | #include <sys/dir.h> | |
28 | #include <linux/types.h> | |
29 | #include <string.h> | |
30 | #include <poll.h> | |
31 | #include "iio_utils.h" | |
32 | ||
33 | /** | |
34 | * size_from_channelarray() - calculate the storage size of a scan | |
35 | * @channels: the channel info array | |
36 | * @num_channels: size of the channel info array | |
37 | * | |
38 | * Has the side effect of filling the channels[i].location values used | |
39 | * in processing the buffer output. | |
40 | **/ | |
41 | int size_from_channelarray(struct iio_channel_info *channels, int num_channels) | |
42 | { | |
43 | int bytes = 0; | |
44 | int i = 0; | |
45 | while (i < num_channels) { | |
46 | if (bytes % channels[i].bytes == 0) | |
47 | channels[i].location = bytes; | |
48 | else | |
49 | channels[i].location = bytes - bytes%channels[i].bytes | |
50 | + channels[i].bytes; | |
51 | bytes = channels[i].location + channels[i].bytes; | |
52 | i++; | |
53 | } | |
54 | return bytes; | |
55 | } | |
56 | ||
57 | void print2byte(int input, struct iio_channel_info *info) | |
58 | { | |
59 | /* shift before conversion to avoid sign extension | |
60 | of left aligned data */ | |
61 | input = input >> info->shift; | |
62 | if (info->is_signed) { | |
63 | int16_t val = input; | |
64 | val &= (1 << info->bits_used) - 1; | |
65 | val = (int16_t)(val << (16 - info->bits_used)) >> | |
66 | (16 - info->bits_used); | |
67 | printf("%05f ", val, | |
68 | (float)(val + info->offset)*info->scale); | |
69 | } else { | |
70 | uint16_t val = input; | |
71 | val &= (1 << info->bits_used) - 1; | |
72 | printf("%05f ", ((float)val + info->offset)*info->scale); | |
73 | } | |
74 | } | |
75 | /** | |
76 | * process_scan() - print out the values in SI units | |
77 | * @data: pointer to the start of the scan | |
78 | * @infoarray: information about the channels. Note | |
79 | * size_from_channelarray must have been called first to fill the | |
80 | * location offsets. | |
81 | * @num_channels: the number of active channels | |
82 | **/ | |
83 | void process_scan(char *data, | |
84 | struct iio_channel_info *infoarray, | |
85 | int num_channels) | |
86 | { | |
87 | int k; | |
88 | for (k = 0; k < num_channels; k++) | |
89 | switch (infoarray[k].bytes) { | |
90 | /* only a few cases implemented so far */ | |
91 | case 2: | |
92 | print2byte(*(uint16_t *)(data + infoarray[k].location), | |
93 | &infoarray[k]); | |
94 | break; | |
95 | case 8: | |
96 | if (infoarray[k].is_signed) { | |
97 | int64_t val = *(int64_t *) | |
98 | (data + | |
99 | infoarray[k].location); | |
100 | if ((val >> infoarray[k].bits_used) & 1) | |
101 | val = (val & infoarray[k].mask) | | |
102 | ~infoarray[k].mask; | |
103 | /* special case for timestamp */ | |
104 | if (infoarray[k].scale == 1.0f && | |
105 | infoarray[k].offset == 0.0f) | |
106 | printf(" %lld", val); | |
107 | else | |
108 | printf("%05f ", ((float)val + | |
109 | infoarray[k].offset)* | |
110 | infoarray[k].scale); | |
111 | } | |
112 | break; | |
113 | default: | |
114 | break; | |
115 | } | |
116 | printf("\n"); | |
117 | } | |
118 | ||
119 | int main(int argc, char **argv) | |
120 | { | |
121 | unsigned long num_loops = 2; | |
122 | unsigned long timedelay = 1000000; | |
123 | unsigned long buf_len = 128; | |
124 | ||
125 | ||
126 | int ret, c, i, j, toread; | |
127 | ||
128 | FILE *fp_ev; | |
129 | int fp; | |
130 | ||
131 | int num_channels; | |
132 | char *trigger_name = NULL, *device_name = NULL; | |
133 | char *dev_dir_name, *buf_dir_name; | |
134 | ||
135 | int datardytrigger = 1; | |
136 | char *data; | |
137 | ssize_t read_size; | |
138 | int dev_num, trig_num; | |
139 | char *buffer_access; | |
140 | int scan_size; | |
141 | int noevents = 0; | |
142 | char *dummy; | |
143 | ||
144 | struct iio_channel_info *infoarray; | |
145 | ||
146 | while ((c = getopt(argc, argv, "l:w:c:et:n:")) != -1) { | |
147 | switch (c) { | |
148 | case 'n': | |
149 | device_name = optarg; | |
150 | break; | |
151 | case 't': | |
152 | trigger_name = optarg; | |
153 | datardytrigger = 0; | |
154 | break; | |
155 | case 'e': | |
156 | noevents = 1; | |
157 | break; | |
158 | case 'c': | |
159 | num_loops = strtoul(optarg, &dummy, 10); | |
160 | break; | |
161 | case 'w': | |
162 | timedelay = strtoul(optarg, &dummy, 10); | |
163 | break; | |
164 | case 'l': | |
165 | buf_len = strtoul(optarg, &dummy, 10); | |
166 | break; | |
167 | case '?': | |
168 | return -1; | |
169 | } | |
170 | } | |
171 | ||
172 | if (device_name == NULL) | |
173 | return -1; | |
174 | ||
175 | /* Find the device requested */ | |
176 | dev_num = find_type_by_name(device_name, "iio:device"); | |
177 | if (dev_num < 0) { | |
178 | printf("Failed to find the %s\n", device_name); | |
179 | ret = -ENODEV; | |
180 | goto error_ret; | |
181 | } | |
182 | printf("iio device number being used is %d\n", dev_num); | |
183 | ||
184 | asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); | |
185 | if (trigger_name == NULL) { | |
186 | /* | |
187 | * Build the trigger name. If it is device associated it's | |
188 | * name is <device_name>_dev[n] where n matches the device | |
189 | * number found above | |
190 | */ | |
191 | ret = asprintf(&trigger_name, | |
192 | "%s-dev%d", device_name, dev_num); | |
193 | if (ret < 0) { | |
194 | ret = -ENOMEM; | |
195 | goto error_ret; | |
196 | } | |
197 | } | |
198 | ||
199 | /* Verify the trigger exists */ | |
200 | trig_num = find_type_by_name(trigger_name, "trigger"); | |
201 | if (trig_num < 0) { | |
202 | printf("Failed to find the trigger %s\n", trigger_name); | |
203 | ret = -ENODEV; | |
204 | goto error_free_triggername; | |
205 | } | |
206 | printf("iio trigger number being used is %d\n", trig_num); | |
207 | ||
208 | /* | |
209 | * Parse the files in scan_elements to identify what channels are | |
210 | * present | |
211 | */ | |
212 | ret = build_channel_array(dev_dir_name, &infoarray, &num_channels); | |
213 | if (ret) { | |
214 | printf("Problem reading scan element information\n"); | |
215 | printf("diag %s\n", dev_dir_name); | |
216 | goto error_free_triggername; | |
217 | } | |
218 | ||
219 | /* | |
220 | * Construct the directory name for the associated buffer. | |
221 | * As we know that the lis3l02dq has only one buffer this may | |
222 | * be built rather than found. | |
223 | */ | |
224 | ret = asprintf(&buf_dir_name, | |
225 | "%siio:device%d/buffer", iio_dir, dev_num); | |
226 | if (ret < 0) { | |
227 | ret = -ENOMEM; | |
228 | goto error_free_triggername; | |
229 | } | |
230 | printf("%s %s\n", dev_dir_name, trigger_name); | |
231 | /* Set the device trigger to be the data rdy trigger found above */ | |
232 | ret = write_sysfs_string_and_verify("trigger/current_trigger", | |
233 | dev_dir_name, | |
234 | trigger_name); | |
235 | if (ret < 0) { | |
236 | printf("Failed to write current_trigger file\n"); | |
237 | goto error_free_buf_dir_name; | |
238 | } | |
239 | ||
240 | /* Setup ring buffer parameters */ | |
241 | ret = write_sysfs_int("length", buf_dir_name, buf_len); | |
242 | if (ret < 0) | |
243 | goto error_free_buf_dir_name; | |
244 | ||
245 | /* Enable the buffer */ | |
246 | ret = write_sysfs_int("enable", buf_dir_name, 1); | |
247 | if (ret < 0) | |
248 | goto error_free_buf_dir_name; | |
249 | scan_size = size_from_channelarray(infoarray, num_channels); | |
250 | data = malloc(scan_size*buf_len); | |
251 | if (!data) { | |
252 | ret = -ENOMEM; | |
253 | goto error_free_buf_dir_name; | |
254 | } | |
255 | ||
256 | ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); | |
257 | if (ret < 0) { | |
258 | ret = -ENOMEM; | |
259 | goto error_free_data; | |
260 | } | |
261 | ||
262 | /* Attempt to open non blocking the access dev */ | |
263 | fp = open(buffer_access, O_RDONLY | O_NONBLOCK); | |
264 | if (fp == -1) { /*If it isn't there make the node */ | |
265 | printf("Failed to open %s\n", buffer_access); | |
266 | ret = -errno; | |
267 | goto error_free_buffer_access; | |
268 | } | |
269 | ||
270 | /* Wait for events 10 times */ | |
271 | for (j = 0; j < num_loops; j++) { | |
272 | if (!noevents) { | |
273 | struct pollfd pfd = { | |
274 | .fd = fp, | |
275 | .events = POLLIN, | |
276 | }; | |
277 | ||
278 | poll(&pfd, 1, -1); | |
279 | toread = buf_len; | |
280 | ||
281 | } else { | |
282 | usleep(timedelay); | |
283 | toread = 64; | |
284 | } | |
285 | ||
286 | read_size = read(fp, | |
287 | data, | |
288 | toread*scan_size); | |
289 | if (read_size == -EAGAIN) { | |
290 | printf("nothing available\n"); | |
291 | continue; | |
292 | } | |
293 | for (i = 0; i < read_size/scan_size; i++) | |
294 | process_scan(data + scan_size*i, | |
295 | infoarray, | |
296 | num_channels); | |
297 | } | |
298 | ||
299 | /* Stop the ring buffer */ | |
300 | ret = write_sysfs_int("enable", buf_dir_name, 0); | |
301 | if (ret < 0) | |
302 | goto error_close_buffer_access; | |
303 | ||
304 | /* Disconnect from the trigger - just write a dummy name.*/ | |
305 | write_sysfs_string("trigger/current_trigger", | |
306 | dev_dir_name, "NULL"); | |
307 | ||
308 | error_close_buffer_access: | |
309 | close(fp); | |
310 | error_free_data: | |
311 | free(data); | |
312 | error_free_buffer_access: | |
313 | free(buffer_access); | |
314 | error_free_buf_dir_name: | |
315 | free(buf_dir_name); | |
316 | error_free_triggername: | |
317 | if (datardytrigger) | |
318 | free(trigger_name); | |
319 | error_ret: | |
320 | return ret; | |
321 | } |