1// SPDX-License-Identifier: GPL-2.0-only 2/* Industrialio buffer test code. 3 * 4 * Copyright (c) 2008 Jonathan Cameron 5 * 6 * This program is primarily intended as an example application. 7 * Reads the current buffer setup from sysfs and starts a short capture 8 * from the specified device, pretty printing the result after appropriate 9 * conversion. 10 * 11 * Command line parameters 12 * generic_buffer -n <device_name> -t <trigger_name> 13 * If trigger name is not specified the program assumes you want a dataready 14 * trigger associated with the device and goes looking for it. 15 */ 16 17#include <unistd.h> 18#include <stdlib.h> 19#include <dirent.h> 20#include <fcntl.h> 21#include <stdio.h> 22#include <errno.h> 23#include <sys/stat.h> 24#include <sys/dir.h> 25#include <linux/types.h> 26#include <string.h> 27#include <poll.h> 28#include <endian.h> 29#include <getopt.h> 30#include <inttypes.h> 31#include <stdbool.h> 32#include <signal.h> 33#include "iio_utils.h" 34 35/** 36 * enum autochan - state for the automatic channel enabling mechanism 37 */ 38enum autochan { 39 AUTOCHANNELS_DISABLED, 40 AUTOCHANNELS_ENABLED, 41 AUTOCHANNELS_ACTIVE, 42}; 43 44/** 45 * size_from_channelarray() - calculate the storage size of a scan 46 * @channels: the channel info array 47 * @num_channels: number of channels 48 * 49 * Has the side effect of filling the channels[i].location values used 50 * in processing the buffer output. 51 **/ 52static unsigned int size_from_channelarray(struct iio_channel_info *channels, int num_channels) 53{ 54 unsigned int bytes = 0; 55 int i = 0, max = 0; 56 unsigned int misalignment; 57 58 while (i < num_channels) { 59 if (channels[i].bytes > max) 60 max = channels[i].bytes; 61 if (bytes % channels[i].bytes == 0) 62 channels[i].location = bytes; 63 else 64 channels[i].location = bytes - bytes % channels[i].bytes 65 + channels[i].bytes; 66 67 bytes = channels[i].location + channels[i].bytes; 68 i++; 69 } 70 /* 71 * We want the data in next sample to also be properly aligned so 72 * we'll add padding at the end if needed. Adding padding only 73 * works for channel data which size is 2^n bytes. 74 */ 75 misalignment = bytes % max; 76 if (misalignment) 77 bytes += max - misalignment; 78 79 return bytes; 80} 81 82static void print1byte(uint8_t input, struct iio_channel_info *info) 83{ 84 /* 85 * Shift before conversion to avoid sign extension 86 * of left aligned data 87 */ 88 input >>= info->shift; 89 input &= info->mask; 90 if (info->is_signed) { 91 int8_t val = (int8_t)(input << (8 - info->bits_used)) >> 92 (8 - info->bits_used); 93 printf("%05f ", ((float)val + info->offset) * info->scale); 94 } else { 95 printf("%05f ", ((float)input + info->offset) * info->scale); 96 } 97} 98 99static void print2byte(uint16_t input, struct iio_channel_info *info) 100{ 101 /* First swap if incorrect endian */ 102 if (info->be) 103 input = be16toh(input); 104 else 105 input = le16toh(input); 106 107 /* 108 * Shift before conversion to avoid sign extension 109 * of left aligned data 110 */ 111 input >>= info->shift; 112 input &= info->mask; 113 if (info->is_signed) { 114 int16_t val = (int16_t)(input << (16 - info->bits_used)) >> 115 (16 - info->bits_used); 116 printf("%05f ", ((float)val + info->offset) * info->scale); 117 } else { 118 printf("%05f ", ((float)input + info->offset) * info->scale); 119 } 120} 121 122static void print4byte(uint32_t input, struct iio_channel_info *info) 123{ 124 /* First swap if incorrect endian */ 125 if (info->be) 126 input = be32toh(input); 127 else 128 input = le32toh(input); 129 130 /* 131 * Shift before conversion to avoid sign extension 132 * of left aligned data 133 */ 134 input >>= info->shift; 135 input &= info->mask; 136 if (info->is_signed) { 137 int32_t val = (int32_t)(input << (32 - info->bits_used)) >> 138 (32 - info->bits_used); 139 printf("%05f ", ((float)val + info->offset) * info->scale); 140 } else { 141 printf("%05f ", ((float)input + info->offset) * info->scale); 142 } 143} 144 145static void print8byte(uint64_t input, struct iio_channel_info *info) 146{ 147 /* First swap if incorrect endian */ 148 if (info->be) 149 input = be64toh(input); 150 else 151 input = le64toh(input); 152 153 /* 154 * Shift before conversion to avoid sign extension 155 * of left aligned data 156 */ 157 input >>= info->shift; 158 input &= info->mask; 159 if (info->is_signed) { 160 int64_t val = (int64_t)(input << (64 - info->bits_used)) >> 161 (64 - info->bits_used); 162 /* special case for timestamp */ 163 if (info->scale == 1.0f && info->offset == 0.0f) 164 printf("%" PRId64 " ", val); 165 else 166 printf("%05f ", 167 ((float)val + info->offset) * info->scale); 168 } else { 169 printf("%05f ", ((float)input + info->offset) * info->scale); 170 } 171} 172 173/** 174 * process_scan() - print out the values in SI units 175 * @data: pointer to the start of the scan 176 * @channels: information about the channels. 177 * Note: size_from_channelarray must have been called first 178 * to fill the location offsets. 179 * @num_channels: number of channels 180 **/ 181static void process_scan(char *data, struct iio_channel_info *channels, 182 int num_channels) 183{ 184 int k; 185 186 for (k = 0; k < num_channels; k++) 187 switch (channels[k].bytes) { 188 /* only a few cases implemented so far */ 189 case 1: 190 print1byte(*(uint8_t *)(data + channels[k].location), 191 &channels[k]); 192 break; 193 case 2: 194 print2byte(*(uint16_t *)(data + channels[k].location), 195 &channels[k]); 196 break; 197 case 4: 198 print4byte(*(uint32_t *)(data + channels[k].location), 199 &channels[k]); 200 break; 201 case 8: 202 print8byte(*(uint64_t *)(data + channels[k].location), 203 &channels[k]); 204 break; 205 default: 206 break; 207 } 208 printf("\n"); 209} 210 211static int enable_disable_all_channels(char *dev_dir_name, int enable) 212{ 213 const struct dirent *ent; 214 char scanelemdir[256]; 215 DIR *dp; 216 int ret; 217 218 snprintf(scanelemdir, sizeof(scanelemdir), 219 FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); 220 scanelemdir[sizeof(scanelemdir)-1] = '\0'; 221 222 dp = opendir(scanelemdir); 223 if (!dp) { 224 fprintf(stderr, "Enabling/disabling channels: can't open %s\n", 225 scanelemdir); 226 return -EIO; 227 } 228 229 ret = -ENOENT; 230 while (ent = readdir(dp), ent) { 231 if (iioutils_check_suffix(ent->d_name, "_en")) { 232 printf("%sabling: %s\n", 233 enable ? "En" : "Dis", 234 ent->d_name); 235 ret = write_sysfs_int(ent->d_name, scanelemdir, 236 enable); 237 if (ret < 0) 238 fprintf(stderr, "Failed to enable/disable %s\n", 239 ent->d_name); 240 } 241 } 242 243 if (closedir(dp) == -1) { 244 perror("Enabling/disabling channels: " 245 "Failed to close directory"); 246 return -errno; 247 } 248 return 0; 249} 250 251static void print_usage(void) 252{ 253 fprintf(stderr, "Usage: generic_buffer [options]...\n" 254 "Capture, convert and output data from IIO device buffer\n" 255 " -a Auto-activate all available channels\n" 256 " -A Force-activate ALL channels\n" 257 " -c <n> Do n conversions, or loop forever if n < 0\n" 258 " -e Disable wait for event (new data)\n" 259 " -g Use trigger-less mode\n" 260 " -l <n> Set buffer length to n samples\n" 261 " --device-name -n <name>\n" 262 " --device-num -N <num>\n" 263 " Set device by name or number (mandatory)\n" 264 " --trigger-name -t <name>\n" 265 " --trigger-num -T <num>\n" 266 " Set trigger by name or number\n" 267 " -w <n> Set delay between reads in us (event-less mode)\n"); 268} 269 270static enum autochan autochannels = AUTOCHANNELS_DISABLED; 271static char *dev_dir_name = NULL; 272static char *buf_dir_name = NULL; 273static bool current_trigger_set = false; 274 275static void cleanup(void) 276{ 277 int ret; 278 279 /* Disable trigger */ 280 if (dev_dir_name && current_trigger_set) { 281 /* Disconnect the trigger - just write a dummy name. */ 282 ret = write_sysfs_string("trigger/current_trigger", 283 dev_dir_name, "NULL"); 284 if (ret < 0) 285 fprintf(stderr, "Failed to disable trigger: %s\n", 286 strerror(-ret)); 287 current_trigger_set = false; 288 } 289 290 /* Disable buffer */ 291 if (buf_dir_name) { 292 ret = write_sysfs_int("enable", buf_dir_name, 0); 293 if (ret < 0) 294 fprintf(stderr, "Failed to disable buffer: %s\n", 295 strerror(-ret)); 296 } 297 298 /* Disable channels if auto-enabled */ 299 if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { 300 ret = enable_disable_all_channels(dev_dir_name, 0); 301 if (ret) 302 fprintf(stderr, "Failed to disable all channels\n"); 303 autochannels = AUTOCHANNELS_DISABLED; 304 } 305} 306 307static void sig_handler(int signum) 308{ 309 fprintf(stderr, "Caught signal %d\n", signum); 310 cleanup(); 311 exit(-signum); 312} 313 314static void register_cleanup(void) 315{ 316 struct sigaction sa = { .sa_handler = sig_handler }; 317 const int signums[] = { SIGINT, SIGTERM, SIGABRT }; 318 int ret, i; 319 320 for (i = 0; i < ARRAY_SIZE(signums); ++i) { 321 ret = sigaction(signums[i], &sa, NULL); 322 if (ret) { 323 perror("Failed to register signal handler"); 324 exit(-1); 325 } 326 } 327} 328 329static const struct option longopts[] = { 330 { "device-name", 1, 0, 'n' }, 331 { "device-num", 1, 0, 'N' }, 332 { "trigger-name", 1, 0, 't' }, 333 { "trigger-num", 1, 0, 'T' }, 334 { }, 335}; 336 337int main(int argc, char **argv) 338{ 339 long long num_loops = 2; 340 unsigned long timedelay = 1000000; 341 unsigned long buf_len = 128; 342 343 ssize_t i; 344 unsigned long long j; 345 unsigned long toread; 346 int ret, c; 347 int fp = -1; 348 349 int num_channels = 0; 350 char *trigger_name = NULL, *device_name = NULL; 351 352 char *data = NULL; 353 ssize_t read_size; 354 int dev_num = -1, trig_num = -1; 355 char *buffer_access = NULL; 356 unsigned int scan_size; 357 int noevents = 0; 358 int notrigger = 0; 359 char *dummy; 360 bool force_autochannels = false; 361 362 struct iio_channel_info *channels = NULL; 363 364 register_cleanup(); 365 366 while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, 367 NULL)) != -1) { 368 switch (c) { 369 case 'a': 370 autochannels = AUTOCHANNELS_ENABLED; 371 break; 372 case 'A': 373 autochannels = AUTOCHANNELS_ENABLED; 374 force_autochannels = true; 375 break; 376 case 'c': 377 errno = 0; 378 num_loops = strtoll(optarg, &dummy, 10); 379 if (errno) { 380 ret = -errno; 381 goto error; 382 } 383 384 break; 385 case 'e': 386 noevents = 1; 387 break; 388 case 'g': 389 notrigger = 1; 390 break; 391 case 'l': 392 errno = 0; 393 buf_len = strtoul(optarg, &dummy, 10); 394 if (errno) { 395 ret = -errno; 396 goto error; 397 } 398 399 break; 400 case 'n': 401 device_name = strdup(optarg); 402 break; 403 case 'N': 404 errno = 0; 405 dev_num = strtoul(optarg, &dummy, 10); 406 if (errno) { 407 ret = -errno; 408 goto error; 409 } 410 break; 411 case 't': 412 trigger_name = strdup(optarg); 413 break; 414 case 'T': 415 errno = 0; 416 trig_num = strtoul(optarg, &dummy, 10); 417 if (errno) 418 return -errno; 419 break; 420 case 'w': 421 errno = 0; 422 timedelay = strtoul(optarg, &dummy, 10); 423 if (errno) { 424 ret = -errno; 425 goto error; 426 } 427 break; 428 case '?': 429 print_usage(); 430 ret = -1; 431 goto error; 432 } 433 } 434 435 /* Find the device requested */ 436 if (dev_num < 0 && !device_name) { 437 fprintf(stderr, "Device not set\n"); 438 print_usage(); 439 ret = -1; 440 goto error; 441 } else if (dev_num >= 0 && device_name) { 442 fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n"); 443 print_usage(); 444 ret = -1; 445 goto error; 446 } else if (dev_num < 0) { 447 dev_num = find_type_by_name(device_name, "iio:device"); 448 if (dev_num < 0) { 449 fprintf(stderr, "Failed to find the %s\n", device_name); 450 ret = dev_num; 451 goto error; 452 } 453 } 454 printf("iio device number being used is %d\n", dev_num); 455 456 ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); 457 if (ret < 0) 458 return -ENOMEM; 459 /* Fetch device_name if specified by number */ 460 if (!device_name) { 461 device_name = malloc(IIO_MAX_NAME_LENGTH); 462 if (!device_name) { 463 ret = -ENOMEM; 464 goto error; 465 } 466 ret = read_sysfs_string("name", dev_dir_name, device_name); 467 if (ret < 0) { 468 fprintf(stderr, "Failed to read name of device %d\n", dev_num); 469 goto error; 470 } 471 } 472 473 if (notrigger) { 474 printf("trigger-less mode selected\n"); 475 } else if (trig_num >= 0) { 476 char *trig_dev_name; 477 ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num); 478 if (ret < 0) { 479 return -ENOMEM; 480 } 481 trigger_name = malloc(IIO_MAX_NAME_LENGTH); 482 ret = read_sysfs_string("name", trig_dev_name, trigger_name); 483 free(trig_dev_name); 484 if (ret < 0) { 485 fprintf(stderr, "Failed to read trigger%d name from\n", trig_num); 486 return ret; 487 } 488 printf("iio trigger number being used is %d\n", trig_num); 489 } else { 490 if (!trigger_name) { 491 /* 492 * Build the trigger name. If it is device associated 493 * its name is <device_name>_dev[n] where n matches 494 * the device number found above. 495 */ 496 ret = asprintf(&trigger_name, 497 "%s-dev%d", device_name, dev_num); 498 if (ret < 0) { 499 ret = -ENOMEM; 500 goto error; 501 } 502 } 503 504 /* Look for this "-devN" trigger */ 505 trig_num = find_type_by_name(trigger_name, "trigger"); 506 if (trig_num < 0) { 507 /* OK try the simpler "-trigger" suffix instead */ 508 free(trigger_name); 509 ret = asprintf(&trigger_name, 510 "%s-trigger", device_name); 511 if (ret < 0) { 512 ret = -ENOMEM; 513 goto error; 514 } 515 } 516 517 trig_num = find_type_by_name(trigger_name, "trigger"); 518 if (trig_num < 0) { 519 fprintf(stderr, "Failed to find the trigger %s\n", 520 trigger_name); 521 ret = trig_num; 522 goto error; 523 } 524 525 printf("iio trigger number being used is %d\n", trig_num); 526 } 527 528 /* 529 * Parse the files in scan_elements to identify what channels are 530 * present 531 */ 532 ret = build_channel_array(dev_dir_name, &channels, &num_channels); 533 if (ret) { 534 fprintf(stderr, "Problem reading scan element information\n" 535 "diag %s\n", dev_dir_name); 536 goto error; 537 } 538 if (num_channels && autochannels == AUTOCHANNELS_ENABLED && 539 !force_autochannels) { 540 fprintf(stderr, "Auto-channels selected but some channels " 541 "are already activated in sysfs\n"); 542 fprintf(stderr, "Proceeding without activating any channels\n"); 543 } 544 545 if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) || 546 (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { 547 fprintf(stderr, "Enabling all channels\n"); 548 549 ret = enable_disable_all_channels(dev_dir_name, 1); 550 if (ret) { 551 fprintf(stderr, "Failed to enable all channels\n"); 552 goto error; 553 } 554 555 /* This flags that we need to disable the channels again */ 556 autochannels = AUTOCHANNELS_ACTIVE; 557 558 ret = build_channel_array(dev_dir_name, &channels, 559 &num_channels); 560 if (ret) { 561 fprintf(stderr, "Problem reading scan element " 562 "information\n" 563 "diag %s\n", dev_dir_name); 564 goto error; 565 } 566 if (!num_channels) { 567 fprintf(stderr, "Still no channels after " 568 "auto-enabling, giving up\n"); 569 goto error; 570 } 571 } 572 573 if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { 574 fprintf(stderr, 575 "No channels are enabled, we have nothing to scan.\n"); 576 fprintf(stderr, "Enable channels manually in " 577 FORMAT_SCAN_ELEMENTS_DIR 578 "/*_en or pass -a to autoenable channels and " 579 "try again.\n", dev_dir_name); 580 ret = -ENOENT; 581 goto error; 582 } 583 584 /* 585 * Construct the directory name for the associated buffer. 586 * As we know that the lis3l02dq has only one buffer this may 587 * be built rather than found. 588 */ 589 ret = asprintf(&buf_dir_name, 590 "%siio:device%d/buffer", iio_dir, dev_num); 591 if (ret < 0) { 592 ret = -ENOMEM; 593 goto error; 594 } 595 596 if (!notrigger) { 597 printf("%s %s\n", dev_dir_name, trigger_name); 598 /* 599 * Set the device trigger to be the data ready trigger found 600 * above 601 */ 602 ret = write_sysfs_string_and_verify("trigger/current_trigger", 603 dev_dir_name, 604 trigger_name); 605 if (ret < 0) { 606 fprintf(stderr, 607 "Failed to write current_trigger file\n"); 608 goto error; 609 } 610 } 611 612 /* Setup ring buffer parameters */ 613 ret = write_sysfs_int("length", buf_dir_name, buf_len); 614 if (ret < 0) 615 goto error; 616 617 /* Enable the buffer */ 618 ret = write_sysfs_int("enable", buf_dir_name, 1); 619 if (ret < 0) { 620 fprintf(stderr, 621 "Failed to enable buffer: %s\n", strerror(-ret)); 622 goto error; 623 } 624 625 scan_size = size_from_channelarray(channels, num_channels); 626 627 size_t total_buf_len = scan_size * buf_len; 628 629 if (scan_size > 0 && total_buf_len / scan_size != buf_len) { 630 ret = -EFAULT; 631 perror("Integer overflow happened when calculate scan_size * buf_len"); 632 goto error; 633 } 634 635 data = malloc(total_buf_len); 636 if (!data) { 637 ret = -ENOMEM; 638 goto error; 639 } 640 641 ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); 642 if (ret < 0) { 643 ret = -ENOMEM; 644 goto error; 645 } 646 647 /* Attempt to open non blocking the access dev */ 648 fp = open(buffer_access, O_RDONLY | O_NONBLOCK); 649 if (fp == -1) { /* TODO: If it isn't there make the node */ 650 ret = -errno; 651 fprintf(stderr, "Failed to open %s\n", buffer_access); 652 goto error; 653 } 654 655 for (j = 0; j < num_loops || num_loops < 0; j++) { 656 if (!noevents) { 657 struct pollfd pfd = { 658 .fd = fp, 659 .events = POLLIN, 660 }; 661 662 ret = poll(&pfd, 1, -1); 663 if (ret < 0) { 664 ret = -errno; 665 goto error; 666 } else if (ret == 0) { 667 continue; 668 } 669 670 toread = buf_len; 671 } else { 672 usleep(timedelay); 673 toread = 64; 674 } 675 676 read_size = read(fp, data, toread * scan_size); 677 if (read_size < 0) { 678 if (errno == EAGAIN) { 679 fprintf(stderr, "nothing available\n"); 680 continue; 681 } else { 682 break; 683 } 684 } 685 for (i = 0; i < read_size / scan_size; i++) 686 process_scan(data + scan_size * i, channels, 687 num_channels); 688 } 689 690error: 691 cleanup(); 692 693 if (fp >= 0 && close(fp) == -1) 694 perror("Failed to close buffer"); 695 free(buffer_access); 696 free(data); 697 free(buf_dir_name); 698 for (i = num_channels - 1; i >= 0; i--) { 699 free(channels[i].name); 700 free(channels[i].generic_name); 701 } 702 free(channels); 703 free(trigger_name); 704 free(device_name); 705 free(dev_dir_name); 706 707 return ret; 708} 709