1 /* Industrialio event test code. 2 * 3 * Copyright (c) 2011-2012 Lars-Peter Clausen <lars@metafoo.de> 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 * Usage: 15 * iio_event_monitor <device_name> 16 */ 17 18 #include <unistd.h> 19 #include <stdlib.h> 20 #include <stdbool.h> 21 #include <stdio.h> 22 #include <errno.h> 23 #include <string.h> 24 #include <poll.h> 25 #include <fcntl.h> 26 #include <sys/ioctl.h> 27 #include "iio_utils.h" 28 #include <linux/iio/events.h> 29 #include <linux/iio/types.h> 30 31 static const char * const iio_chan_type_name_spec[] = { 32 [IIO_VOLTAGE] = "voltage", 33 [IIO_CURRENT] = "current", 34 [IIO_POWER] = "power", 35 [IIO_ACCEL] = "accel", 36 [IIO_ANGL_VEL] = "anglvel", 37 [IIO_MAGN] = "magn", 38 [IIO_LIGHT] = "illuminance", 39 [IIO_INTENSITY] = "intensity", 40 [IIO_PROXIMITY] = "proximity", 41 [IIO_TEMP] = "temp", 42 [IIO_INCLI] = "incli", 43 [IIO_ROT] = "rot", 44 [IIO_ANGL] = "angl", 45 [IIO_TIMESTAMP] = "timestamp", 46 [IIO_CAPACITANCE] = "capacitance", 47 [IIO_ALTVOLTAGE] = "altvoltage", 48 [IIO_CCT] = "cct", 49 [IIO_PRESSURE] = "pressure", 50 [IIO_HUMIDITYRELATIVE] = "humidityrelative", 51 [IIO_ACTIVITY] = "activity", 52 [IIO_STEPS] = "steps", 53 [IIO_ENERGY] = "energy", 54 [IIO_DISTANCE] = "distance", 55 [IIO_VELOCITY] = "velocity", 56 [IIO_CONCENTRATION] = "concentration", 57 [IIO_RESISTANCE] = "resistance", 58 [IIO_PH] = "ph", 59 [IIO_UVINDEX] = "uvindex", 60 [IIO_GRAVITY] = "gravity", 61 [IIO_POSITIONRELATIVE] = "positionrelative", 62 [IIO_PHASE] = "phase", 63 [IIO_MASSCONCENTRATION] = "massconcentration", 64 }; 65 66 static const char * const iio_ev_type_text[] = { 67 [IIO_EV_TYPE_THRESH] = "thresh", 68 [IIO_EV_TYPE_MAG] = "mag", 69 [IIO_EV_TYPE_ROC] = "roc", 70 [IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive", 71 [IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive", 72 [IIO_EV_TYPE_CHANGE] = "change", 73 }; 74 75 static const char * const iio_ev_dir_text[] = { 76 [IIO_EV_DIR_EITHER] = "either", 77 [IIO_EV_DIR_RISING] = "rising", 78 [IIO_EV_DIR_FALLING] = "falling" 79 }; 80 81 static const char * const iio_modifier_names[] = { 82 [IIO_MOD_X] = "x", 83 [IIO_MOD_Y] = "y", 84 [IIO_MOD_Z] = "z", 85 [IIO_MOD_X_AND_Y] = "x&y", 86 [IIO_MOD_X_AND_Z] = "x&z", 87 [IIO_MOD_Y_AND_Z] = "y&z", 88 [IIO_MOD_X_AND_Y_AND_Z] = "x&y&z", 89 [IIO_MOD_X_OR_Y] = "x|y", 90 [IIO_MOD_X_OR_Z] = "x|z", 91 [IIO_MOD_Y_OR_Z] = "y|z", 92 [IIO_MOD_X_OR_Y_OR_Z] = "x|y|z", 93 [IIO_MOD_LIGHT_BOTH] = "both", 94 [IIO_MOD_LIGHT_IR] = "ir", 95 [IIO_MOD_ROOT_SUM_SQUARED_X_Y] = "sqrt(x^2+y^2)", 96 [IIO_MOD_SUM_SQUARED_X_Y_Z] = "x^2+y^2+z^2", 97 [IIO_MOD_LIGHT_CLEAR] = "clear", 98 [IIO_MOD_LIGHT_RED] = "red", 99 [IIO_MOD_LIGHT_GREEN] = "green", 100 [IIO_MOD_LIGHT_BLUE] = "blue", 101 [IIO_MOD_LIGHT_UV] = "uv", 102 [IIO_MOD_LIGHT_DUV] = "duv", 103 [IIO_MOD_QUATERNION] = "quaternion", 104 [IIO_MOD_TEMP_AMBIENT] = "ambient", 105 [IIO_MOD_TEMP_OBJECT] = "object", 106 [IIO_MOD_NORTH_MAGN] = "from_north_magnetic", 107 [IIO_MOD_NORTH_TRUE] = "from_north_true", 108 [IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp", 109 [IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp", 110 [IIO_MOD_RUNNING] = "running", 111 [IIO_MOD_JOGGING] = "jogging", 112 [IIO_MOD_WALKING] = "walking", 113 [IIO_MOD_STILL] = "still", 114 [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)", 115 [IIO_MOD_I] = "i", 116 [IIO_MOD_Q] = "q", 117 [IIO_MOD_CO2] = "co2", 118 [IIO_MOD_ETHANOL] = "ethanol", 119 [IIO_MOD_H2] = "h2", 120 [IIO_MOD_VOC] = "voc", 121 [IIO_MOD_PM1] = "pm1", 122 [IIO_MOD_PM2P5] = "pm2p5", 123 [IIO_MOD_PM4] = "pm4", 124 [IIO_MOD_PM10] = "pm10", 125 }; 126 127 static bool event_is_known(struct iio_event_data *event) 128 { 129 enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); 130 enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); 131 enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); 132 enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); 133 134 switch (type) { 135 case IIO_VOLTAGE: 136 case IIO_CURRENT: 137 case IIO_POWER: 138 case IIO_ACCEL: 139 case IIO_ANGL_VEL: 140 case IIO_MAGN: 141 case IIO_LIGHT: 142 case IIO_INTENSITY: 143 case IIO_PROXIMITY: 144 case IIO_TEMP: 145 case IIO_INCLI: 146 case IIO_ROT: 147 case IIO_ANGL: 148 case IIO_TIMESTAMP: 149 case IIO_CAPACITANCE: 150 case IIO_ALTVOLTAGE: 151 case IIO_CCT: 152 case IIO_PRESSURE: 153 case IIO_HUMIDITYRELATIVE: 154 case IIO_ACTIVITY: 155 case IIO_STEPS: 156 case IIO_ENERGY: 157 case IIO_DISTANCE: 158 case IIO_VELOCITY: 159 case IIO_CONCENTRATION: 160 case IIO_RESISTANCE: 161 case IIO_PH: 162 case IIO_UVINDEX: 163 case IIO_GRAVITY: 164 case IIO_POSITIONRELATIVE: 165 case IIO_PHASE: 166 case IIO_MASSCONCENTRATION: 167 break; 168 default: 169 return false; 170 } 171 172 switch (mod) { 173 case IIO_NO_MOD: 174 case IIO_MOD_X: 175 case IIO_MOD_Y: 176 case IIO_MOD_Z: 177 case IIO_MOD_X_AND_Y: 178 case IIO_MOD_X_AND_Z: 179 case IIO_MOD_Y_AND_Z: 180 case IIO_MOD_X_AND_Y_AND_Z: 181 case IIO_MOD_X_OR_Y: 182 case IIO_MOD_X_OR_Z: 183 case IIO_MOD_Y_OR_Z: 184 case IIO_MOD_X_OR_Y_OR_Z: 185 case IIO_MOD_LIGHT_BOTH: 186 case IIO_MOD_LIGHT_IR: 187 case IIO_MOD_ROOT_SUM_SQUARED_X_Y: 188 case IIO_MOD_SUM_SQUARED_X_Y_Z: 189 case IIO_MOD_LIGHT_CLEAR: 190 case IIO_MOD_LIGHT_RED: 191 case IIO_MOD_LIGHT_GREEN: 192 case IIO_MOD_LIGHT_BLUE: 193 case IIO_MOD_LIGHT_UV: 194 case IIO_MOD_LIGHT_DUV: 195 case IIO_MOD_QUATERNION: 196 case IIO_MOD_TEMP_AMBIENT: 197 case IIO_MOD_TEMP_OBJECT: 198 case IIO_MOD_NORTH_MAGN: 199 case IIO_MOD_NORTH_TRUE: 200 case IIO_MOD_NORTH_MAGN_TILT_COMP: 201 case IIO_MOD_NORTH_TRUE_TILT_COMP: 202 case IIO_MOD_RUNNING: 203 case IIO_MOD_JOGGING: 204 case IIO_MOD_WALKING: 205 case IIO_MOD_STILL: 206 case IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z: 207 case IIO_MOD_I: 208 case IIO_MOD_Q: 209 case IIO_MOD_CO2: 210 case IIO_MOD_ETHANOL: 211 case IIO_MOD_H2: 212 case IIO_MOD_VOC: 213 case IIO_MOD_PM1: 214 case IIO_MOD_PM2P5: 215 case IIO_MOD_PM4: 216 case IIO_MOD_PM10: 217 break; 218 default: 219 return false; 220 } 221 222 switch (ev_type) { 223 case IIO_EV_TYPE_THRESH: 224 case IIO_EV_TYPE_MAG: 225 case IIO_EV_TYPE_ROC: 226 case IIO_EV_TYPE_THRESH_ADAPTIVE: 227 case IIO_EV_TYPE_MAG_ADAPTIVE: 228 case IIO_EV_TYPE_CHANGE: 229 break; 230 default: 231 return false; 232 } 233 234 switch (dir) { 235 case IIO_EV_DIR_EITHER: 236 case IIO_EV_DIR_RISING: 237 case IIO_EV_DIR_FALLING: 238 case IIO_EV_DIR_NONE: 239 break; 240 default: 241 return false; 242 } 243 244 return true; 245 } 246 247 static void print_event(struct iio_event_data *event) 248 { 249 enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id); 250 enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id); 251 enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id); 252 enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id); 253 int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event->id); 254 int chan2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id); 255 bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id); 256 257 if (!event_is_known(event)) { 258 fprintf(stderr, "Unknown event: time: %lld, id: %llx\n", 259 event->timestamp, event->id); 260 261 return; 262 } 263 264 printf("Event: time: %lld, type: %s", event->timestamp, 265 iio_chan_type_name_spec[type]); 266 267 if (mod != IIO_NO_MOD) 268 printf("(%s)", iio_modifier_names[mod]); 269 270 if (chan >= 0) { 271 printf(", channel: %d", chan); 272 if (diff && chan2 >= 0) 273 printf("-%d", chan2); 274 } 275 276 printf(", evtype: %s", iio_ev_type_text[ev_type]); 277 278 if (dir != IIO_EV_DIR_NONE) 279 printf(", direction: %s", iio_ev_dir_text[dir]); 280 281 printf("\n"); 282 } 283 284 int main(int argc, char **argv) 285 { 286 struct iio_event_data event; 287 const char *device_name; 288 char *chrdev_name; 289 int ret; 290 int dev_num; 291 int fd, event_fd; 292 293 if (argc <= 1) { 294 fprintf(stderr, "Usage: %s <device_name>\n", argv[0]); 295 return -1; 296 } 297 298 device_name = argv[1]; 299 300 dev_num = find_type_by_name(device_name, "iio:device"); 301 if (dev_num >= 0) { 302 printf("Found IIO device with name %s with device number %d\n", 303 device_name, dev_num); 304 ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num); 305 if (ret < 0) 306 return -ENOMEM; 307 } else { 308 /* 309 * If we can't find an IIO device by name assume device_name is 310 * an IIO chrdev 311 */ 312 chrdev_name = strdup(device_name); 313 if (!chrdev_name) 314 return -ENOMEM; 315 } 316 317 fd = open(chrdev_name, 0); 318 if (fd == -1) { 319 ret = -errno; 320 fprintf(stderr, "Failed to open %s\n", chrdev_name); 321 goto error_free_chrdev_name; 322 } 323 324 ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd); 325 if (ret == -1 || event_fd == -1) { 326 ret = -errno; 327 if (ret == -ENODEV) 328 fprintf(stderr, 329 "This device does not support events\n"); 330 else 331 fprintf(stderr, "Failed to retrieve event fd\n"); 332 if (close(fd) == -1) 333 perror("Failed to close character device file"); 334 335 goto error_free_chrdev_name; 336 } 337 338 if (close(fd) == -1) { 339 ret = -errno; 340 goto error_free_chrdev_name; 341 } 342 343 while (true) { 344 ret = read(event_fd, &event, sizeof(event)); 345 if (ret == -1) { 346 if (errno == EAGAIN) { 347 fprintf(stderr, "nothing available\n"); 348 continue; 349 } else { 350 ret = -errno; 351 perror("Failed to read event from device"); 352 break; 353 } 354 } 355 356 if (ret != sizeof(event)) { 357 fprintf(stderr, "Reading event failed!\n"); 358 ret = -EIO; 359 break; 360 } 361 362 print_event(&event); 363 } 364 365 if (close(event_fd) == -1) 366 perror("Failed to close event file"); 367 368 error_free_chrdev_name: 369 free(chrdev_name); 370 371 return ret; 372 } 373