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