Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /* Industrialio event test code.
0003  *
0004  * Copyright (c) 2011-2012 Lars-Peter Clausen <lars@metafoo.de>
0005  *
0006  * This program is primarily intended as an example application.
0007  * Reads the current buffer setup from sysfs and starts a short capture
0008  * from the specified device, pretty printing the result after appropriate
0009  * conversion.
0010  *
0011  * Usage:
0012  *  iio_event_monitor <device_name>
0013  */
0014 
0015 #include <unistd.h>
0016 #include <stdlib.h>
0017 #include <dirent.h>
0018 #include <stdbool.h>
0019 #include <stdio.h>
0020 #include <errno.h>
0021 #include <string.h>
0022 #include <poll.h>
0023 #include <fcntl.h>
0024 #include <sys/ioctl.h>
0025 #include "iio_utils.h"
0026 #include <linux/iio/events.h>
0027 #include <linux/iio/types.h>
0028 
0029 static const char * const iio_chan_type_name_spec[] = {
0030     [IIO_VOLTAGE] = "voltage",
0031     [IIO_CURRENT] = "current",
0032     [IIO_POWER] = "power",
0033     [IIO_ACCEL] = "accel",
0034     [IIO_ANGL_VEL] = "anglvel",
0035     [IIO_MAGN] = "magn",
0036     [IIO_LIGHT] = "illuminance",
0037     [IIO_INTENSITY] = "intensity",
0038     [IIO_PROXIMITY] = "proximity",
0039     [IIO_TEMP] = "temp",
0040     [IIO_INCLI] = "incli",
0041     [IIO_ROT] = "rot",
0042     [IIO_ANGL] = "angl",
0043     [IIO_TIMESTAMP] = "timestamp",
0044     [IIO_CAPACITANCE] = "capacitance",
0045     [IIO_ALTVOLTAGE] = "altvoltage",
0046     [IIO_CCT] = "cct",
0047     [IIO_PRESSURE] = "pressure",
0048     [IIO_HUMIDITYRELATIVE] = "humidityrelative",
0049     [IIO_ACTIVITY] = "activity",
0050     [IIO_STEPS] = "steps",
0051     [IIO_ENERGY] = "energy",
0052     [IIO_DISTANCE] = "distance",
0053     [IIO_VELOCITY] = "velocity",
0054     [IIO_CONCENTRATION] = "concentration",
0055     [IIO_RESISTANCE] = "resistance",
0056     [IIO_PH] = "ph",
0057     [IIO_UVINDEX] = "uvindex",
0058     [IIO_GRAVITY] = "gravity",
0059     [IIO_POSITIONRELATIVE] = "positionrelative",
0060     [IIO_PHASE] = "phase",
0061     [IIO_MASSCONCENTRATION] = "massconcentration",
0062 };
0063 
0064 static const char * const iio_ev_type_text[] = {
0065     [IIO_EV_TYPE_THRESH] = "thresh",
0066     [IIO_EV_TYPE_MAG] = "mag",
0067     [IIO_EV_TYPE_ROC] = "roc",
0068     [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
0069     [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
0070     [IIO_EV_TYPE_CHANGE] = "change",
0071     [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced",
0072 };
0073 
0074 static const char * const iio_ev_dir_text[] = {
0075     [IIO_EV_DIR_EITHER] = "either",
0076     [IIO_EV_DIR_RISING] = "rising",
0077     [IIO_EV_DIR_FALLING] = "falling"
0078 };
0079 
0080 static const char * const iio_modifier_names[] = {
0081     [IIO_MOD_X] = "x",
0082     [IIO_MOD_Y] = "y",
0083     [IIO_MOD_Z] = "z",
0084     [IIO_MOD_X_AND_Y] = "x&y",
0085     [IIO_MOD_X_AND_Z] = "x&z",
0086     [IIO_MOD_Y_AND_Z] = "y&z",
0087     [IIO_MOD_X_AND_Y_AND_Z] = "x&y&z",
0088     [IIO_MOD_X_OR_Y] = "x|y",
0089     [IIO_MOD_X_OR_Z] = "x|z",
0090     [IIO_MOD_Y_OR_Z] = "y|z",
0091     [IIO_MOD_X_OR_Y_OR_Z] = "x|y|z",
0092     [IIO_MOD_LIGHT_BOTH] = "both",
0093     [IIO_MOD_LIGHT_IR] = "ir",
0094     [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)",
0095     [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2",
0096     [IIO_MOD_LIGHT_CLEAR] = "clear",
0097     [IIO_MOD_LIGHT_RED] = "red",
0098     [IIO_MOD_LIGHT_GREEN] = "green",
0099     [IIO_MOD_LIGHT_BLUE] = "blue",
0100     [IIO_MOD_LIGHT_UV] = "uv",
0101     [IIO_MOD_LIGHT_DUV] = "duv",
0102     [IIO_MOD_QUATERNION] = "quaternion",
0103     [IIO_MOD_TEMP_AMBIENT] = "ambient",
0104     [IIO_MOD_TEMP_OBJECT] = "object",
0105     [IIO_MOD_NORTH_MAGN] = "from_north_magnetic",
0106     [IIO_MOD_NORTH_TRUE] = "from_north_true",
0107     [IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
0108     [IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
0109     [IIO_MOD_RUNNING] = "running",
0110     [IIO_MOD_JOGGING] = "jogging",
0111     [IIO_MOD_WALKING] = "walking",
0112     [IIO_MOD_STILL] = "still",
0113     [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
0114     [IIO_MOD_I] = "i",
0115     [IIO_MOD_Q] = "q",
0116     [IIO_MOD_CO2] = "co2",
0117     [IIO_MOD_ETHANOL] = "ethanol",
0118     [IIO_MOD_H2] = "h2",
0119     [IIO_MOD_VOC] = "voc",
0120     [IIO_MOD_PM1] = "pm1",
0121     [IIO_MOD_PM2P5] = "pm2p5",
0122     [IIO_MOD_PM4] = "pm4",
0123     [IIO_MOD_PM10] = "pm10",
0124     [IIO_MOD_O2] = "o2",
0125 };
0126 
0127 static bool event_is_known(struct iio_event_data *event)
0128 {
0129     enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
0130     enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
0131     enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
0132     enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
0133 
0134     switch (type) {
0135     case IIO_VOLTAGE:
0136     case IIO_CURRENT:
0137     case IIO_POWER:
0138     case IIO_ACCEL:
0139     case IIO_ANGL_VEL:
0140     case IIO_MAGN:
0141     case IIO_LIGHT:
0142     case IIO_INTENSITY:
0143     case IIO_PROXIMITY:
0144     case IIO_TEMP:
0145     case IIO_INCLI:
0146     case IIO_ROT:
0147     case IIO_ANGL:
0148     case IIO_TIMESTAMP:
0149     case IIO_CAPACITANCE:
0150     case IIO_ALTVOLTAGE:
0151     case IIO_CCT:
0152     case IIO_PRESSURE:
0153     case IIO_HUMIDITYRELATIVE:
0154     case IIO_ACTIVITY:
0155     case IIO_STEPS:
0156     case IIO_ENERGY:
0157     case IIO_DISTANCE:
0158     case IIO_VELOCITY:
0159     case IIO_CONCENTRATION:
0160     case IIO_RESISTANCE:
0161     case IIO_PH:
0162     case IIO_UVINDEX:
0163     case IIO_GRAVITY:
0164     case IIO_POSITIONRELATIVE:
0165     case IIO_PHASE:
0166     case IIO_MASSCONCENTRATION:
0167         break;
0168     default:
0169         return false;
0170     }
0171 
0172     switch (mod) {
0173     case IIO_NO_MOD:
0174     case IIO_MOD_X:
0175     case IIO_MOD_Y:
0176     case IIO_MOD_Z:
0177     case IIO_MOD_X_AND_Y:
0178     case IIO_MOD_X_AND_Z:
0179     case IIO_MOD_Y_AND_Z:
0180     case IIO_MOD_X_AND_Y_AND_Z:
0181     case IIO_MOD_X_OR_Y:
0182     case IIO_MOD_X_OR_Z:
0183     case IIO_MOD_Y_OR_Z:
0184     case IIO_MOD_X_OR_Y_OR_Z:
0185     case IIO_MOD_LIGHT_BOTH:
0186     case IIO_MOD_LIGHT_IR:
0187     case IIO_MOD_ROOT_SUM_SQUARED_X_Y:
0188     case IIO_MOD_SUM_SQUARED_X_Y_Z:
0189     case IIO_MOD_LIGHT_CLEAR:
0190     case IIO_MOD_LIGHT_RED:
0191     case IIO_MOD_LIGHT_GREEN:
0192     case IIO_MOD_LIGHT_BLUE:
0193     case IIO_MOD_LIGHT_UV:
0194     case IIO_MOD_LIGHT_DUV:
0195     case IIO_MOD_QUATERNION:
0196     case IIO_MOD_TEMP_AMBIENT:
0197     case IIO_MOD_TEMP_OBJECT:
0198     case IIO_MOD_NORTH_MAGN:
0199     case IIO_MOD_NORTH_TRUE:
0200     case IIO_MOD_NORTH_MAGN_TILT_COMP:
0201     case IIO_MOD_NORTH_TRUE_TILT_COMP:
0202     case IIO_MOD_RUNNING:
0203     case IIO_MOD_JOGGING:
0204     case IIO_MOD_WALKING:
0205     case IIO_MOD_STILL:
0206     case IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z:
0207     case IIO_MOD_I:
0208     case IIO_MOD_Q:
0209     case IIO_MOD_CO2:
0210     case IIO_MOD_ETHANOL:
0211     case IIO_MOD_H2:
0212     case IIO_MOD_VOC:
0213     case IIO_MOD_PM1:
0214     case IIO_MOD_PM2P5:
0215     case IIO_MOD_PM4:
0216     case IIO_MOD_PM10:
0217     case IIO_MOD_O2:
0218         break;
0219     default:
0220         return false;
0221     }
0222 
0223     switch (ev_type) {
0224     case IIO_EV_TYPE_THRESH:
0225     case IIO_EV_TYPE_MAG:
0226     case IIO_EV_TYPE_ROC:
0227     case IIO_EV_TYPE_THRESH_ADAPTIVE:
0228     case IIO_EV_TYPE_MAG_ADAPTIVE:
0229     case IIO_EV_TYPE_CHANGE:
0230         break;
0231     default:
0232         return false;
0233     }
0234 
0235     switch (dir) {
0236     case IIO_EV_DIR_EITHER:
0237     case IIO_EV_DIR_RISING:
0238     case IIO_EV_DIR_FALLING:
0239     case IIO_EV_DIR_NONE:
0240         break;
0241     default:
0242         return false;
0243     }
0244 
0245     return true;
0246 }
0247 
0248 static void print_event(struct iio_event_data *event)
0249 {
0250     enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
0251     enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
0252     enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
0253     enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
0254     int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event->id);
0255     int chan2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id);
0256     bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
0257 
0258     if (!event_is_known(event)) {
0259         fprintf(stderr, "Unknown event: time: %lld, id: %llx\n",
0260             event->timestamp, event->id);
0261 
0262         return;
0263     }
0264 
0265     printf("Event: time: %lld, type: %s", event->timestamp,
0266            iio_chan_type_name_spec[type]);
0267 
0268     if (mod != IIO_NO_MOD)
0269         printf("(%s)", iio_modifier_names[mod]);
0270 
0271     if (chan >= 0) {
0272         printf(", channel: %d", chan);
0273         if (diff && chan2 >= 0)
0274             printf("-%d", chan2);
0275     }
0276 
0277     printf(", evtype: %s", iio_ev_type_text[ev_type]);
0278 
0279     if (dir != IIO_EV_DIR_NONE)
0280         printf(", direction: %s", iio_ev_dir_text[dir]);
0281 
0282     printf("\n");
0283     fflush(stdout);
0284 }
0285 
0286 /* Enable or disable events in sysfs if the knob is available */
0287 static void enable_events(char *dev_dir, int enable)
0288 {
0289     const struct dirent *ent;
0290     char evdir[256];
0291     int ret;
0292     DIR *dp;
0293 
0294     snprintf(evdir, sizeof(evdir), FORMAT_EVENTS_DIR, dev_dir);
0295     evdir[sizeof(evdir)-1] = '\0';
0296 
0297     dp = opendir(evdir);
0298     if (!dp) {
0299         fprintf(stderr, "Enabling/disabling events: can't open %s\n",
0300             evdir);
0301         return;
0302     }
0303 
0304     while (ent = readdir(dp), ent) {
0305         if (iioutils_check_suffix(ent->d_name, "_en")) {
0306             printf("%sabling: %s\n",
0307                    enable ? "En" : "Dis",
0308                    ent->d_name);
0309             ret = write_sysfs_int(ent->d_name, evdir,
0310                           enable);
0311             if (ret < 0)
0312                 fprintf(stderr, "Failed to enable/disable %s\n",
0313                     ent->d_name);
0314         }
0315     }
0316 
0317     if (closedir(dp) == -1) {
0318         perror("Enabling/disabling channels: "
0319                "Failed to close directory");
0320         return;
0321     }
0322 }
0323 
0324 int main(int argc, char **argv)
0325 {
0326     struct iio_event_data event;
0327     const char *device_name;
0328     char *dev_dir_name = NULL;
0329     char *chrdev_name;
0330     int ret;
0331     int dev_num;
0332     int fd, event_fd;
0333     bool all_events = false;
0334 
0335     if (argc == 2) {
0336         device_name = argv[1];
0337     } else if (argc == 3) {
0338         device_name = argv[2];
0339         if (!strcmp(argv[1], "-a"))
0340             all_events = true;
0341     } else {
0342         fprintf(stderr,
0343             "Usage: iio_event_monitor [options] <device_name>\n"
0344             "Listen and display events from IIO devices\n"
0345             "  -a         Auto-activate all available events\n");
0346         return -1;
0347     }
0348 
0349     dev_num = find_type_by_name(device_name, "iio:device");
0350     if (dev_num >= 0) {
0351         printf("Found IIO device with name %s with device number %d\n",
0352                device_name, dev_num);
0353         ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
0354         if (ret < 0)
0355             return -ENOMEM;
0356         /* Look up sysfs dir as well if we can */
0357         ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
0358         if (ret < 0)
0359             return -ENOMEM;
0360     } else {
0361         /*
0362          * If we can't find an IIO device by name assume device_name is
0363          * an IIO chrdev
0364          */
0365         chrdev_name = strdup(device_name);
0366         if (!chrdev_name)
0367             return -ENOMEM;
0368     }
0369 
0370     if (all_events && dev_dir_name)
0371         enable_events(dev_dir_name, 1);
0372 
0373     fd = open(chrdev_name, 0);
0374     if (fd == -1) {
0375         ret = -errno;
0376         fprintf(stderr, "Failed to open %s\n", chrdev_name);
0377         goto error_free_chrdev_name;
0378     }
0379 
0380     ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
0381     if (ret == -1 || event_fd == -1) {
0382         ret = -errno;
0383         if (ret == -ENODEV)
0384             fprintf(stderr,
0385                 "This device does not support events\n");
0386         else
0387             fprintf(stderr, "Failed to retrieve event fd\n");
0388         if (close(fd) == -1)
0389             perror("Failed to close character device file");
0390 
0391         goto error_free_chrdev_name;
0392     }
0393 
0394     if (close(fd) == -1)  {
0395         ret = -errno;
0396         goto error_free_chrdev_name;
0397     }
0398 
0399     while (true) {
0400         ret = read(event_fd, &event, sizeof(event));
0401         if (ret == -1) {
0402             if (errno == EAGAIN) {
0403                 fprintf(stderr, "nothing available\n");
0404                 continue;
0405             } else {
0406                 ret = -errno;
0407                 perror("Failed to read event from device");
0408                 break;
0409             }
0410         }
0411 
0412         if (ret != sizeof(event)) {
0413             fprintf(stderr, "Reading event failed!\n");
0414             ret = -EIO;
0415             break;
0416         }
0417 
0418         print_event(&event);
0419     }
0420 
0421     if (close(event_fd) == -1)
0422         perror("Failed to close event file");
0423 
0424 error_free_chrdev_name:
0425     /* Disable events after use */
0426     if (all_events && dev_dir_name)
0427         enable_events(dev_dir_name, 0);
0428 
0429     free(chrdev_name);
0430 
0431     return ret;
0432 }