linux/tools/iio/generic_buffer.c
<<
>>
Prefs
   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 <stdlib.h>
  23#include <dirent.h>
  24#include <fcntl.h>
  25#include <stdio.h>
  26#include <errno.h>
  27#include <sys/stat.h>
  28#include <sys/dir.h>
  29#include <linux/types.h>
  30#include <string.h>
  31#include <poll.h>
  32#include <endian.h>
  33#include <getopt.h>
  34#include <inttypes.h>
  35#include "iio_utils.h"
  36
  37/**
  38 * size_from_channelarray() - calculate the storage size of a scan
  39 * @channels:           the channel info array
  40 * @num_channels:       number of channels
  41 *
  42 * Has the side effect of filling the channels[i].location values used
  43 * in processing the buffer output.
  44 **/
  45int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
  46{
  47        int bytes = 0;
  48        int i = 0;
  49
  50        while (i < num_channels) {
  51                if (bytes % channels[i].bytes == 0)
  52                        channels[i].location = bytes;
  53                else
  54                        channels[i].location = bytes - bytes % channels[i].bytes
  55                                               + channels[i].bytes;
  56
  57                bytes = channels[i].location + channels[i].bytes;
  58                i++;
  59        }
  60
  61        return bytes;
  62}
  63
  64void print1byte(uint8_t input, struct iio_channel_info *info)
  65{
  66        /*
  67         * Shift before conversion to avoid sign extension
  68         * of left aligned data
  69         */
  70        input >>= info->shift;
  71        input &= info->mask;
  72        if (info->is_signed) {
  73                int8_t val = (int8_t)(input << (8 - info->bits_used)) >>
  74                             (8 - info->bits_used);
  75                printf("%05f ", ((float)val + info->offset) * info->scale);
  76        } else {
  77                printf("%05f ", ((float)input + info->offset) * info->scale);
  78        }
  79}
  80
  81void print2byte(uint16_t input, struct iio_channel_info *info)
  82{
  83        /* First swap if incorrect endian */
  84        if (info->be)
  85                input = be16toh(input);
  86        else
  87                input = le16toh(input);
  88
  89        /*
  90         * Shift before conversion to avoid sign extension
  91         * of left aligned data
  92         */
  93        input >>= info->shift;
  94        input &= info->mask;
  95        if (info->is_signed) {
  96                int16_t val = (int16_t)(input << (16 - info->bits_used)) >>
  97                              (16 - info->bits_used);
  98                printf("%05f ", ((float)val + info->offset) * info->scale);
  99        } else {
 100                printf("%05f ", ((float)input + info->offset) * info->scale);
 101        }
 102}
 103
 104void print4byte(uint32_t input, struct iio_channel_info *info)
 105{
 106        /* First swap if incorrect endian */
 107        if (info->be)
 108                input = be32toh(input);
 109        else
 110                input = le32toh(input);
 111
 112        /*
 113         * Shift before conversion to avoid sign extension
 114         * of left aligned data
 115         */
 116        input >>= info->shift;
 117        input &= info->mask;
 118        if (info->is_signed) {
 119                int32_t val = (int32_t)(input << (32 - info->bits_used)) >>
 120                              (32 - info->bits_used);
 121                printf("%05f ", ((float)val + info->offset) * info->scale);
 122        } else {
 123                printf("%05f ", ((float)input + info->offset) * info->scale);
 124        }
 125}
 126
 127void print8byte(uint64_t input, struct iio_channel_info *info)
 128{
 129        /* First swap if incorrect endian */
 130        if (info->be)
 131                input = be64toh(input);
 132        else
 133                input = le64toh(input);
 134
 135        /*
 136         * Shift before conversion to avoid sign extension
 137         * of left aligned data
 138         */
 139        input >>= info->shift;
 140        input &= info->mask;
 141        if (info->is_signed) {
 142                int64_t val = (int64_t)(input << (64 - info->bits_used)) >>
 143                              (64 - info->bits_used);
 144                /* special case for timestamp */
 145                if (info->scale == 1.0f && info->offset == 0.0f)
 146                        printf("%" PRId64 " ", val);
 147                else
 148                        printf("%05f ",
 149                               ((float)val + info->offset) * info->scale);
 150        } else {
 151                printf("%05f ", ((float)input + info->offset) * info->scale);
 152        }
 153}
 154
 155/**
 156 * process_scan() - print out the values in SI units
 157 * @data:               pointer to the start of the scan
 158 * @channels:           information about the channels.
 159 *                      Note: size_from_channelarray must have been called first
 160 *                            to fill the location offsets.
 161 * @num_channels:       number of channels
 162 **/
 163void process_scan(char *data,
 164                  struct iio_channel_info *channels,
 165                  int num_channels)
 166{
 167        int k;
 168
 169        for (k = 0; k < num_channels; k++)
 170                switch (channels[k].bytes) {
 171                        /* only a few cases implemented so far */
 172                case 1:
 173                        print1byte(*(uint8_t *)(data + channels[k].location),
 174                                   &channels[k]);
 175                        break;
 176                case 2:
 177                        print2byte(*(uint16_t *)(data + channels[k].location),
 178                                   &channels[k]);
 179                        break;
 180                case 4:
 181                        print4byte(*(uint32_t *)(data + channels[k].location),
 182                                   &channels[k]);
 183                        break;
 184                case 8:
 185                        print8byte(*(uint64_t *)(data + channels[k].location),
 186                                   &channels[k]);
 187                        break;
 188                default:
 189                        break;
 190                }
 191        printf("\n");
 192}
 193
 194void print_usage(void)
 195{
 196        fprintf(stderr, "Usage: generic_buffer [options]...\n"
 197                "Capture, convert and output data from IIO device buffer\n"
 198                "  -c <n>     Do n conversions\n"
 199                "  -e         Disable wait for event (new data)\n"
 200                "  -g         Use trigger-less mode\n"
 201                "  -l <n>     Set buffer length to n samples\n"
 202                "  -n <name>  Set device name (mandatory)\n"
 203                "  -t <name>  Set trigger name\n"
 204                "  -w <n>     Set delay between reads in us (event-less mode)\n");
 205}
 206
 207int main(int argc, char **argv)
 208{
 209        unsigned long num_loops = 2;
 210        unsigned long timedelay = 1000000;
 211        unsigned long buf_len = 128;
 212
 213        int ret, c, i, j, toread;
 214        int fp;
 215
 216        int num_channels;
 217        char *trigger_name = NULL, *device_name = NULL;
 218        char *dev_dir_name, *buf_dir_name;
 219
 220        int datardytrigger = 1;
 221        char *data;
 222        ssize_t read_size;
 223        int dev_num, trig_num;
 224        char *buffer_access;
 225        int scan_size;
 226        int noevents = 0;
 227        int notrigger = 0;
 228        char *dummy;
 229
 230        struct iio_channel_info *channels;
 231
 232        while ((c = getopt(argc, argv, "c:egl:n:t:w:")) != -1) {
 233                switch (c) {
 234                case 'c':
 235                        errno = 0;
 236                        num_loops = strtoul(optarg, &dummy, 10);
 237                        if (errno)
 238                                return -errno;
 239
 240                        break;
 241                case 'e':
 242                        noevents = 1;
 243                        break;
 244                case 'g':
 245                        notrigger = 1;
 246                        break;
 247                case 'l':
 248                        errno = 0;
 249                        buf_len = strtoul(optarg, &dummy, 10);
 250                        if (errno)
 251                                return -errno;
 252
 253                        break;
 254                case 'n':
 255                        device_name = optarg;
 256                        break;
 257                case 't':
 258                        trigger_name = optarg;
 259                        datardytrigger = 0;
 260                        break;
 261                case 'w':
 262                        errno = 0;
 263                        timedelay = strtoul(optarg, &dummy, 10);
 264                        if (errno)
 265                                return -errno;
 266                        break;
 267                case '?':
 268                        print_usage();
 269                        return -1;
 270                }
 271        }
 272
 273        if (!device_name) {
 274                fprintf(stderr, "Device name not set\n");
 275                print_usage();
 276                return -1;
 277        }
 278
 279        /* Find the device requested */
 280        dev_num = find_type_by_name(device_name, "iio:device");
 281        if (dev_num < 0) {
 282                fprintf(stderr, "Failed to find the %s\n", device_name);
 283                return dev_num;
 284        }
 285
 286        printf("iio device number being used is %d\n", dev_num);
 287
 288        ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
 289        if (ret < 0)
 290                return -ENOMEM;
 291
 292        if (!notrigger) {
 293                if (!trigger_name) {
 294                        /*
 295                         * Build the trigger name. If it is device associated
 296                         * its name is <device_name>_dev[n] where n matches
 297                         * the device number found above.
 298                         */
 299                        ret = asprintf(&trigger_name,
 300                                       "%s-dev%d", device_name, dev_num);
 301                        if (ret < 0) {
 302                                ret = -ENOMEM;
 303                                goto error_free_dev_dir_name;
 304                        }
 305                }
 306
 307                /* Verify the trigger exists */
 308                trig_num = find_type_by_name(trigger_name, "trigger");
 309                if (trig_num < 0) {
 310                        fprintf(stderr, "Failed to find the trigger %s\n",
 311                                trigger_name);
 312                        ret = trig_num;
 313                        goto error_free_triggername;
 314                }
 315
 316                printf("iio trigger number being used is %d\n", trig_num);
 317        } else {
 318                printf("trigger-less mode selected\n");
 319        }
 320
 321        /*
 322         * Parse the files in scan_elements to identify what channels are
 323         * present
 324         */
 325        ret = build_channel_array(dev_dir_name, &channels, &num_channels);
 326        if (ret) {
 327                fprintf(stderr, "Problem reading scan element information\n"
 328                        "diag %s\n", dev_dir_name);
 329                goto error_free_triggername;
 330        }
 331        if (!num_channels) {
 332                fprintf(stderr,
 333                        "No channels are enabled, we have nothing to scan.\n");
 334                fprintf(stderr, "Enable channels manually in "
 335                        FORMAT_SCAN_ELEMENTS_DIR
 336                        "/*_en and try again.\n", dev_dir_name);
 337                ret = -ENOENT;
 338                goto error_free_triggername;
 339        }
 340
 341        /*
 342         * Construct the directory name for the associated buffer.
 343         * As we know that the lis3l02dq has only one buffer this may
 344         * be built rather than found.
 345         */
 346        ret = asprintf(&buf_dir_name,
 347                       "%siio:device%d/buffer", iio_dir, dev_num);
 348        if (ret < 0) {
 349                ret = -ENOMEM;
 350                goto error_free_channels;
 351        }
 352
 353        if (!notrigger) {
 354                printf("%s %s\n", dev_dir_name, trigger_name);
 355                /*
 356                 * Set the device trigger to be the data ready trigger found
 357                 * above
 358                 */
 359                ret = write_sysfs_string_and_verify("trigger/current_trigger",
 360                                                    dev_dir_name,
 361                                                    trigger_name);
 362                if (ret < 0) {
 363                        fprintf(stderr,
 364                                "Failed to write current_trigger file\n");
 365                        goto error_free_buf_dir_name;
 366                }
 367        }
 368
 369        /* Setup ring buffer parameters */
 370        ret = write_sysfs_int("length", buf_dir_name, buf_len);
 371        if (ret < 0)
 372                goto error_free_buf_dir_name;
 373
 374        /* Enable the buffer */
 375        ret = write_sysfs_int("enable", buf_dir_name, 1);
 376        if (ret < 0) {
 377                fprintf(stderr,
 378                        "Failed to enable buffer: %s\n", strerror(-ret));
 379                goto error_free_buf_dir_name;
 380        }
 381
 382        scan_size = size_from_channelarray(channels, num_channels);
 383        data = malloc(scan_size * buf_len);
 384        if (!data) {
 385                ret = -ENOMEM;
 386                goto error_free_buf_dir_name;
 387        }
 388
 389        ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num);
 390        if (ret < 0) {
 391                ret = -ENOMEM;
 392                goto error_free_data;
 393        }
 394
 395        /* Attempt to open non blocking the access dev */
 396        fp = open(buffer_access, O_RDONLY | O_NONBLOCK);
 397        if (fp == -1) { /* TODO: If it isn't there make the node */
 398                ret = -errno;
 399                fprintf(stderr, "Failed to open %s\n", buffer_access);
 400                goto error_free_buffer_access;
 401        }
 402
 403        for (j = 0; j < num_loops; j++) {
 404                if (!noevents) {
 405                        struct pollfd pfd = {
 406                                .fd = fp,
 407                                .events = POLLIN,
 408                        };
 409
 410                        ret = poll(&pfd, 1, -1);
 411                        if (ret < 0) {
 412                                ret = -errno;
 413                                goto error_close_buffer_access;
 414                        } else if (ret == 0) {
 415                                continue;
 416                        }
 417
 418                        toread = buf_len;
 419                } else {
 420                        usleep(timedelay);
 421                        toread = 64;
 422                }
 423
 424                read_size = read(fp, data, toread * scan_size);
 425                if (read_size < 0) {
 426                        if (errno == EAGAIN) {
 427                                fprintf(stderr, "nothing available\n");
 428                                continue;
 429                        } else {
 430                                break;
 431                        }
 432                }
 433                for (i = 0; i < read_size / scan_size; i++)
 434                        process_scan(data + scan_size * i, channels,
 435                                     num_channels);
 436        }
 437
 438        /* Stop the buffer */
 439        ret = write_sysfs_int("enable", buf_dir_name, 0);
 440        if (ret < 0)
 441                goto error_close_buffer_access;
 442
 443        if (!notrigger)
 444                /* Disconnect the trigger - just write a dummy name. */
 445                ret = write_sysfs_string("trigger/current_trigger",
 446                                         dev_dir_name, "NULL");
 447                if (ret < 0)
 448                        fprintf(stderr, "Failed to write to %s\n",
 449                                dev_dir_name);
 450
 451error_close_buffer_access:
 452        if (close(fp) == -1)
 453                perror("Failed to close buffer");
 454
 455error_free_buffer_access:
 456        free(buffer_access);
 457error_free_data:
 458        free(data);
 459error_free_buf_dir_name:
 460        free(buf_dir_name);
 461error_free_channels:
 462        for (i = num_channels - 1; i >= 0; i--) {
 463                free(channels[i].name);
 464                free(channels[i].generic_name);
 465        }
 466        free(channels);
 467error_free_triggername:
 468        if (datardytrigger)
 469                free(trigger_name);
 470
 471error_free_dev_dir_name:
 472        free(dev_dir_name);
 473
 474        return ret;
 475}
 476