1 // SPDX-License-Identifier: GPL-2.0-only 2 /* Industrialio event test code. 3 * 4 * Copyright (c) 2011-2012 Lars-Peter Clausen <lars@metafoo.de> 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 * Usage: 12 * iio_event_monitor <device_name> 13 */ 14 15 #include <unistd.h> 16 #include <stdlib.h> 17 #include <dirent.h> 18 #include <stdbool.h> 19 #include <stdio.h> 20 #include <errno.h> 21 #include <string.h> 22 #include <poll.h> 23 #include <fcntl.h> 24 #include <sys/ioctl.h> 25 #include "iio_utils.h" 26 #include <linux/iio/events.h> 27 #include <linux/iio/types.h> 28 29 static const char * const iio_chan_type_name_spec[] = { 30 [IIO_VOLTAGE] = "voltage", 31 [IIO_CURRENT] = "current", 32 [IIO_POWER] = "power", 33 [IIO_ACCEL] = "accel", 34 [IIO_ANGL_VEL] = "anglvel", 35 [IIO_MAGN] = "magn", 36 [IIO_LIGHT] = "illuminance", 37 [IIO_INTENSITY] = "intensity", 38 [IIO_PROXIMITY] = "proximity", 39 [IIO_TEMP] = "temp", 40 [IIO_INCLI] = "incli", 41 [IIO_ROT] = "rot", 42 [IIO_ANGL] = "angl", 43 [IIO_TIMESTAMP] = "timestamp", 44 [IIO_CAPACITANCE] = "capacitance", 45 [IIO_ALTVOLTAGE] = "altvoltage", 46 [IIO_CCT] = "cct", 47 [IIO_PRESSURE] = "pressure", 48 [IIO_HUMIDITYRELATIVE] = "humidityrelative", 49 [IIO_ACTIVITY] = "activity", 50 [IIO_STEPS] = "steps", 51 [IIO_ENERGY] = "energy", 52 [IIO_DISTANCE] = "distance", 53 [IIO_VELOCITY] = "velocity", 54 [IIO_CONCENTRATION] = "concentration", 55 [IIO_RESISTANCE] = "resistance", 56 [IIO_PH] = "ph", 57 [IIO_UVINDEX] = "uvindex", 58 [IIO_GRAVITY] = "gravity", 59 [IIO_POSITIONRELATIVE] = "positionrelative", 60 [IIO_PHASE] = "phase", 61 [IIO_MASSCONCENTRATION] = "massconcentration", 62 [IIO_DELTA_ANGL] = "deltaangl", 63 [IIO_DELTA_VELOCITY] = "deltavelocity", 64 [IIO_COLORTEMP] = "colortemp", 65 [IIO_CHROMATICITY] = "chromaticity", 66 [IIO_ATTENTION] = "attention", 67 [IIO_ALTCURRENT] = "altcurrent", 68 [IIO_COVERAGE] = "coverage", 69 [IIO_VOLUMEFLOW] = "volumeflow", 70 [IIO_FREQUENCY] = "frequency", 71 }; 72 73 static const char * const iio_ev_type_text[] = { 74 [IIO_EV_TYPE_THRESH] = "thresh", 75 [IIO_EV_TYPE_MAG] = "mag", 76 [IIO_EV_TYPE_ROC] = "roc", 77 [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", 78 [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", 79 [IIO_EV_TYPE_CHANGE] = "change", 80 [IIO_EV_TYPE_MAG_REFERENCED] = "mag_referenced", 81 [IIO_EV_TYPE_GESTURE] = "gesture", 82 [IIO_EV_TYPE_FAULT] = "fault", 83 }; 84 85 static const char * const iio_ev_dir_text[] = { 86 [IIO_EV_DIR_EITHER] = "either", 87 [IIO_EV_DIR_RISING] = "rising", 88 [IIO_EV_DIR_FALLING] = "falling", 89 [IIO_EV_DIR_SINGLETAP] = "singletap", 90 [IIO_EV_DIR_DOUBLETAP] = "doubletap", 91 [IIO_EV_DIR_FAULT_OPENWIRE] = "openwire", 92 }; 93 94 static const char * const iio_modifier_names[] = { 95 [IIO_MOD_X] = "x", 96 [IIO_MOD_Y] = "y", 97 [IIO_MOD_Z] = "z", 98 [IIO_MOD_X_AND_Y] = "x&y", 99 [IIO_MOD_X_AND_Z] = "x&z", 100 [IIO_MOD_Y_AND_Z] = "y&z", 101 [IIO_MOD_X_AND_Y_AND_Z] = "x&y&z", 102 [IIO_MOD_X_OR_Y] = "x|y", 103 [IIO_MOD_X_OR_Z] = "x|z", 104 [IIO_MOD_Y_OR_Z] = "y|z", 105 [IIO_MOD_X_OR_Y_OR_Z] = "x|y|z", 106 [IIO_MOD_LIGHT_BOTH] = "both", 107 [IIO_MOD_LIGHT_IR] = "ir", 108 [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)", 109 [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2", 110 [IIO_MOD_LIGHT_CLEAR] = "clear", 111 [IIO_MOD_LIGHT_RED] = "red", 112 [IIO_MOD_LIGHT_GREEN] = "green", 113 [IIO_MOD_LIGHT_BLUE] = "blue", 114 [IIO_MOD_LIGHT_UV] = "uv", 115 [IIO_MOD_LIGHT_UVA] = "uva", 116 [IIO_MOD_LIGHT_UVB] = "uvb", 117 [IIO_MOD_LIGHT_DUV] = "duv", 118 [IIO_MOD_QUATERNION] = "quaternion", 119 [IIO_MOD_TEMP_AMBIENT] = "ambient", 120 [IIO_MOD_TEMP_OBJECT] = "object", 121 [IIO_MOD_NORTH_MAGN] = "from_north_magnetic", 122 [IIO_MOD_NORTH_TRUE] = "from_north_true", 123 [IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp", 124 [IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp", 125 [IIO_MOD_RUNNING] = "running", 126 [IIO_MOD_JOGGING] = "jogging", 127 [IIO_MOD_WALKING] = "walking", 128 [IIO_MOD_STILL] = "still", 129 [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)", 130 [IIO_MOD_I] = "i", 131 [IIO_MOD_Q] = "q", 132 [IIO_MOD_CO2] = "co2", 133 [IIO_MOD_ETHANOL] = "ethanol", 134 [IIO_MOD_H2] = "h2", 135 [IIO_MOD_VOC] = "voc", 136 [IIO_MOD_PM1] = "pm1", 137 [IIO_MOD_PM2P5] = "pm2p5", 138 [IIO_MOD_PM4] = "pm4", 139 [IIO_MOD_PM10] = "pm10", 140 [IIO_MOD_O2] = "o2", 141 [IIO_MOD_LINEAR_X] = "linear_x", 142 [IIO_MOD_LINEAR_Y] = "linear_y", 143 [IIO_MOD_LINEAR_Z] = "linear_z", 144 [IIO_MOD_PITCH] = "pitch", 145 [IIO_MOD_YAW] = "yaw", 146 [IIO_MOD_ROLL] = "roll", 147 [IIO_MOD_RMS] = "rms", 148 [IIO_MOD_ACTIVE] = "active", 149 [IIO_MOD_REACTIVE] = "reactive", 150 [IIO_MOD_APPARENT] = "apparent", 151 [IIO_MOD_QUATERNION_AXIS] = "quaternionaxis", 152 }; 153 154 static bool event_is_known(struct iio_event_data *event) 155 { 156 enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); 157 enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); 158 enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); 159 enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); 160 161 switch (type) { 162 case IIO_VOLTAGE: 163 case IIO_CURRENT: 164 case IIO_POWER: 165 case IIO_ACCEL: 166 case IIO_ANGL_VEL: 167 case IIO_MAGN: 168 case IIO_LIGHT: 169 case IIO_INTENSITY: 170 case IIO_PROXIMITY: 171 case IIO_TEMP: 172 case IIO_INCLI: 173 case IIO_ROT: 174 case IIO_ANGL: 175 case IIO_TIMESTAMP: 176 case IIO_CAPACITANCE: 177 case IIO_ALTVOLTAGE: 178 case IIO_CCT: 179 case IIO_PRESSURE: 180 case IIO_HUMIDITYRELATIVE: 181 case IIO_ACTIVITY: 182 case IIO_STEPS: 183 case IIO_ENERGY: 184 case IIO_DISTANCE: 185 case IIO_VELOCITY: 186 case IIO_CONCENTRATION: 187 case IIO_RESISTANCE: 188 case IIO_PH: 189 case IIO_UVINDEX: 190 case IIO_GRAVITY: 191 case IIO_POSITIONRELATIVE: 192 case IIO_PHASE: 193 case IIO_MASSCONCENTRATION: 194 case IIO_DELTA_ANGL: 195 case IIO_DELTA_VELOCITY: 196 case IIO_COLORTEMP: 197 case IIO_CHROMATICITY: 198 case IIO_ATTENTION: 199 case IIO_ALTCURRENT: 200 case IIO_COVERAGE: 201 case IIO_VOLUMEFLOW: 202 case IIO_FREQUENCY: 203 break; 204 default: 205 return false; 206 } 207 208 switch (mod) { 209 case IIO_NO_MOD: 210 case IIO_MOD_X: 211 case IIO_MOD_Y: 212 case IIO_MOD_Z: 213 case IIO_MOD_X_AND_Y: 214 case IIO_MOD_X_AND_Z: 215 case IIO_MOD_Y_AND_Z: 216 case IIO_MOD_X_AND_Y_AND_Z: 217 case IIO_MOD_X_OR_Y: 218 case IIO_MOD_X_OR_Z: 219 case IIO_MOD_Y_OR_Z: 220 case IIO_MOD_X_OR_Y_OR_Z: 221 case IIO_MOD_LIGHT_BOTH: 222 case IIO_MOD_LIGHT_IR: 223 case IIO_MOD_ROOT_SUM_SQUARED_X_Y: 224 case IIO_MOD_SUM_SQUARED_X_Y_Z: 225 case IIO_MOD_LIGHT_CLEAR: 226 case IIO_MOD_LIGHT_RED: 227 case IIO_MOD_LIGHT_GREEN: 228 case IIO_MOD_LIGHT_BLUE: 229 case IIO_MOD_LIGHT_UV: 230 case IIO_MOD_LIGHT_DUV: 231 case IIO_MOD_QUATERNION: 232 case IIO_MOD_TEMP_AMBIENT: 233 case IIO_MOD_TEMP_OBJECT: 234 case IIO_MOD_NORTH_MAGN: 235 case IIO_MOD_NORTH_TRUE: 236 case IIO_MOD_NORTH_MAGN_TILT_COMP: 237 case IIO_MOD_NORTH_TRUE_TILT_COMP: 238 case IIO_MOD_RUNNING: 239 case IIO_MOD_JOGGING: 240 case IIO_MOD_WALKING: 241 case IIO_MOD_STILL: 242 case IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z: 243 case IIO_MOD_I: 244 case IIO_MOD_Q: 245 case IIO_MOD_CO2: 246 case IIO_MOD_ETHANOL: 247 case IIO_MOD_H2: 248 case IIO_MOD_VOC: 249 case IIO_MOD_PM1: 250 case IIO_MOD_PM2P5: 251 case IIO_MOD_PM4: 252 case IIO_MOD_PM10: 253 case IIO_MOD_O2: 254 case IIO_MOD_RMS: 255 case IIO_MOD_ACTIVE: 256 case IIO_MOD_REACTIVE: 257 case IIO_MOD_APPARENT: 258 break; 259 default: 260 return false; 261 } 262 263 switch (ev_type) { 264 case IIO_EV_TYPE_THRESH: 265 case IIO_EV_TYPE_MAG: 266 case IIO_EV_TYPE_ROC: 267 case IIO_EV_TYPE_THRESH_ADAPTIVE: 268 case IIO_EV_TYPE_MAG_ADAPTIVE: 269 case IIO_EV_TYPE_CHANGE: 270 case IIO_EV_TYPE_GESTURE: 271 case IIO_EV_TYPE_FAULT: 272 break; 273 default: 274 return false; 275 } 276 277 switch (dir) { 278 case IIO_EV_DIR_EITHER: 279 case IIO_EV_DIR_RISING: 280 case IIO_EV_DIR_FALLING: 281 case IIO_EV_DIR_SINGLETAP: 282 case IIO_EV_DIR_DOUBLETAP: 283 case IIO_EV_DIR_FAULT_OPENWIRE: 284 case IIO_EV_DIR_NONE: 285 break; 286 default: 287 return false; 288 } 289 290 return true; 291 } 292 293 static void print_event(struct iio_event_data *event) 294 { 295 enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); 296 enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); 297 enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); 298 enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); 299 int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event->id); 300 int chan2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id); 301 bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id); 302 303 if (!event_is_known(event)) { 304 fprintf(stderr, "Unknown event: time: %lld, id: %llx\n", 305 event->timestamp, event->id); 306 307 return; 308 } 309 310 printf("Event: time: %lld, type: %s", event->timestamp, 311 iio_chan_type_name_spec[type]); 312 313 if (mod != IIO_NO_MOD) 314 printf("(%s)", iio_modifier_names[mod]); 315 316 if (chan >= 0) { 317 printf(", channel: %d", chan); 318 if (diff && chan2 >= 0) 319 printf("-%d", chan2); 320 } 321 322 printf(", evtype: %s", iio_ev_type_text[ev_type]); 323 324 if (dir != IIO_EV_DIR_NONE) 325 printf(", direction: %s", iio_ev_dir_text[dir]); 326 327 printf("\n"); 328 fflush(stdout); 329 } 330 331 /* Enable or disable events in sysfs if the knob is available */ 332 static void enable_events(char *dev_dir, int enable) 333 { 334 const struct dirent *ent; 335 char evdir[256]; 336 int ret; 337 DIR *dp; 338 339 snprintf(evdir, sizeof(evdir), FORMAT_EVENTS_DIR, dev_dir); 340 evdir[sizeof(evdir)-1] = '\0'; 341 342 dp = opendir(evdir); 343 if (!dp) { 344 fprintf(stderr, "Enabling/disabling events: can't open %s\n", 345 evdir); 346 return; 347 } 348 349 while (ent = readdir(dp), ent) { 350 if (iioutils_check_suffix(ent->d_name, "_en")) { 351 printf("%sabling: %s\n", 352 enable ? "En" : "Dis", 353 ent->d_name); 354 ret = write_sysfs_int(ent->d_name, evdir, 355 enable); 356 if (ret < 0) 357 fprintf(stderr, "Failed to enable/disable %s\n", 358 ent->d_name); 359 } 360 } 361 362 if (closedir(dp) == -1) { 363 perror("Enabling/disabling channels: " 364 "Failed to close directory"); 365 return; 366 } 367 } 368 369 int main(int argc, char **argv) 370 { 371 struct iio_event_data event; 372 const char *device_name; 373 char *dev_dir_name = NULL; 374 char *chrdev_name; 375 int ret; 376 int dev_num; 377 int fd, event_fd; 378 bool all_events = false; 379 380 if (argc == 2) { 381 device_name = argv[1]; 382 } else if (argc == 3) { 383 device_name = argv[2]; 384 if (!strcmp(argv[1], "-a")) 385 all_events = true; 386 } else { 387 fprintf(stderr, 388 "Usage: iio_event_monitor [options] <device_name>\n" 389 "Listen and display events from IIO devices\n" 390 " -a Auto-activate all available events\n"); 391 return -1; 392 } 393 394 dev_num = find_type_by_name(device_name, "iio:device"); 395 if (dev_num >= 0) { 396 printf("Found IIO device with name %s with device number %d\n", 397 device_name, dev_num); 398 ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num); 399 if (ret < 0) 400 return -ENOMEM; 401 /* Look up sysfs dir as well if we can */ 402 ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); 403 if (ret < 0) 404 return -ENOMEM; 405 } else { 406 /* 407 * If we can't find an IIO device by name assume device_name is 408 * an IIO chrdev 409 */ 410 chrdev_name = strdup(device_name); 411 if (!chrdev_name) 412 return -ENOMEM; 413 } 414 415 if (all_events && dev_dir_name) 416 enable_events(dev_dir_name, 1); 417 418 fd = open(chrdev_name, 0); 419 if (fd == -1) { 420 ret = -errno; 421 fprintf(stderr, "Failed to open %s\n", chrdev_name); 422 goto error_free_chrdev_name; 423 } 424 425 ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd); 426 if (ret == -1 || event_fd == -1) { 427 ret = -errno; 428 if (ret == -ENODEV) 429 fprintf(stderr, 430 "This device does not support events\n"); 431 else 432 fprintf(stderr, "Failed to retrieve event fd\n"); 433 if (close(fd) == -1) 434 perror("Failed to close character device file"); 435 436 goto error_free_chrdev_name; 437 } 438 439 if (close(fd) == -1) { 440 ret = -errno; 441 goto error_free_chrdev_name; 442 } 443 444 while (true) { 445 ret = read(event_fd, &event, sizeof(event)); 446 if (ret == -1) { 447 if (errno == EAGAIN) { 448 fprintf(stderr, "nothing available\n"); 449 continue; 450 } else { 451 ret = -errno; 452 perror("Failed to read event from device"); 453 break; 454 } 455 } 456 457 if (ret != sizeof(event)) { 458 fprintf(stderr, "Reading event failed!\n"); 459 ret = -EIO; 460 break; 461 } 462 463 print_event(&event); 464 } 465 466 if (close(event_fd) == -1) 467 perror("Failed to close event file"); 468 469 error_free_chrdev_name: 470 /* Disable events after use */ 471 if (all_events && dev_dir_name) 472 enable_events(dev_dir_name, 0); 473 474 free(chrdev_name); 475 free(dev_dir_name); 476 477 return ret; 478 } 479