0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <unistd.h>
0012 #include <stdlib.h>
0013 #include <stdbool.h>
0014 #include <stdint.h>
0015 #include <stdio.h>
0016 #include <dirent.h>
0017 #include <errno.h>
0018 #include <string.h>
0019 #include <poll.h>
0020 #include <fcntl.h>
0021 #include <getopt.h>
0022 #include <inttypes.h>
0023 #include <sys/ioctl.h>
0024 #include <sys/types.h>
0025 #include <linux/gpio.h>
0026 #include "gpio-utils.h"
0027
0028 int monitor_device(const char *device_name,
0029 unsigned int *lines,
0030 unsigned int num_lines,
0031 struct gpio_v2_line_config *config,
0032 unsigned int loops)
0033 {
0034 struct gpio_v2_line_values values;
0035 char *chrdev_name;
0036 int cfd, lfd;
0037 int ret;
0038 int i = 0;
0039
0040 ret = asprintf(&chrdev_name, "/dev/%s", device_name);
0041 if (ret < 0)
0042 return -ENOMEM;
0043
0044 cfd = open(chrdev_name, 0);
0045 if (cfd == -1) {
0046 ret = -errno;
0047 fprintf(stderr, "Failed to open %s\n", chrdev_name);
0048 goto exit_free_name;
0049 }
0050
0051 ret = gpiotools_request_line(device_name, lines, num_lines, config,
0052 "gpio-event-mon");
0053 if (ret < 0)
0054 goto exit_device_close;
0055 else
0056 lfd = ret;
0057
0058
0059 values.mask = 0;
0060 values.bits = 0;
0061 for (i = 0; i < num_lines; i++)
0062 gpiotools_set_bit(&values.mask, i);
0063 ret = gpiotools_get_values(lfd, &values);
0064 if (ret < 0) {
0065 fprintf(stderr,
0066 "Failed to issue GPIO LINE GET VALUES IOCTL (%d)\n",
0067 ret);
0068 goto exit_line_close;
0069 }
0070
0071 if (num_lines == 1) {
0072 fprintf(stdout, "Monitoring line %d on %s\n", lines[0], device_name);
0073 fprintf(stdout, "Initial line value: %d\n",
0074 gpiotools_test_bit(values.bits, 0));
0075 } else {
0076 fprintf(stdout, "Monitoring lines %d", lines[0]);
0077 for (i = 1; i < num_lines - 1; i++)
0078 fprintf(stdout, ", %d", lines[i]);
0079 fprintf(stdout, " and %d on %s\n", lines[i], device_name);
0080 fprintf(stdout, "Initial line values: %d",
0081 gpiotools_test_bit(values.bits, 0));
0082 for (i = 1; i < num_lines - 1; i++)
0083 fprintf(stdout, ", %d",
0084 gpiotools_test_bit(values.bits, i));
0085 fprintf(stdout, " and %d\n",
0086 gpiotools_test_bit(values.bits, i));
0087 }
0088
0089 while (1) {
0090 struct gpio_v2_line_event event;
0091
0092 ret = read(lfd, &event, sizeof(event));
0093 if (ret == -1) {
0094 if (errno == -EAGAIN) {
0095 fprintf(stderr, "nothing available\n");
0096 continue;
0097 } else {
0098 ret = -errno;
0099 fprintf(stderr, "Failed to read event (%d)\n",
0100 ret);
0101 break;
0102 }
0103 }
0104
0105 if (ret != sizeof(event)) {
0106 fprintf(stderr, "Reading event failed\n");
0107 ret = -EIO;
0108 break;
0109 }
0110 fprintf(stdout, "GPIO EVENT at %" PRIu64 " on line %d (%d|%d) ",
0111 (uint64_t)event.timestamp_ns, event.offset, event.line_seqno,
0112 event.seqno);
0113 switch (event.id) {
0114 case GPIO_V2_LINE_EVENT_RISING_EDGE:
0115 fprintf(stdout, "rising edge");
0116 break;
0117 case GPIO_V2_LINE_EVENT_FALLING_EDGE:
0118 fprintf(stdout, "falling edge");
0119 break;
0120 default:
0121 fprintf(stdout, "unknown event");
0122 }
0123 fprintf(stdout, "\n");
0124
0125 i++;
0126 if (i == loops)
0127 break;
0128 }
0129
0130 exit_line_close:
0131 if (close(lfd) == -1)
0132 perror("Failed to close line file");
0133 exit_device_close:
0134 if (close(cfd) == -1)
0135 perror("Failed to close GPIO character device file");
0136 exit_free_name:
0137 free(chrdev_name);
0138 return ret;
0139 }
0140
0141 void print_usage(void)
0142 {
0143 fprintf(stderr, "Usage: gpio-event-mon [options]...\n"
0144 "Listen to events on GPIO lines, 0->1 1->0\n"
0145 " -n <name> Listen on GPIOs on a named device (must be stated)\n"
0146 " -o <n> Offset of line to monitor (may be repeated)\n"
0147 " -d Set line as open drain\n"
0148 " -s Set line as open source\n"
0149 " -r Listen for rising edges\n"
0150 " -f Listen for falling edges\n"
0151 " -w Report the wall-clock time for events\n"
0152 " -t Report the hardware timestamp for events\n"
0153 " -b <n> Debounce the line with period n microseconds\n"
0154 " [-c <n>] Do <n> loops (optional, infinite loop if not stated)\n"
0155 " -? This helptext\n"
0156 "\n"
0157 "Example:\n"
0158 "gpio-event-mon -n gpiochip0 -o 4 -r -f -b 10000\n"
0159 );
0160 }
0161
0162 #define EDGE_FLAGS \
0163 (GPIO_V2_LINE_FLAG_EDGE_RISING | \
0164 GPIO_V2_LINE_FLAG_EDGE_FALLING)
0165
0166 int main(int argc, char **argv)
0167 {
0168 const char *device_name = NULL;
0169 unsigned int lines[GPIO_V2_LINES_MAX];
0170 unsigned int num_lines = 0;
0171 unsigned int loops = 0;
0172 struct gpio_v2_line_config config;
0173 int c, attr, i;
0174 unsigned long debounce_period_us = 0;
0175
0176 memset(&config, 0, sizeof(config));
0177 config.flags = GPIO_V2_LINE_FLAG_INPUT;
0178 while ((c = getopt(argc, argv, "c:n:o:b:dsrfwt?")) != -1) {
0179 switch (c) {
0180 case 'c':
0181 loops = strtoul(optarg, NULL, 10);
0182 break;
0183 case 'n':
0184 device_name = optarg;
0185 break;
0186 case 'o':
0187 if (num_lines >= GPIO_V2_LINES_MAX) {
0188 print_usage();
0189 return -1;
0190 }
0191 lines[num_lines] = strtoul(optarg, NULL, 10);
0192 num_lines++;
0193 break;
0194 case 'b':
0195 debounce_period_us = strtoul(optarg, NULL, 10);
0196 break;
0197 case 'd':
0198 config.flags |= GPIO_V2_LINE_FLAG_OPEN_DRAIN;
0199 break;
0200 case 's':
0201 config.flags |= GPIO_V2_LINE_FLAG_OPEN_SOURCE;
0202 break;
0203 case 'r':
0204 config.flags |= GPIO_V2_LINE_FLAG_EDGE_RISING;
0205 break;
0206 case 'f':
0207 config.flags |= GPIO_V2_LINE_FLAG_EDGE_FALLING;
0208 break;
0209 case 'w':
0210 config.flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_REALTIME;
0211 break;
0212 case 't':
0213 config.flags |= GPIO_V2_LINE_FLAG_EVENT_CLOCK_HTE;
0214 break;
0215 case '?':
0216 print_usage();
0217 return -1;
0218 }
0219 }
0220
0221 if (debounce_period_us) {
0222 attr = config.num_attrs;
0223 config.num_attrs++;
0224 for (i = 0; i < num_lines; i++)
0225 gpiotools_set_bit(&config.attrs[attr].mask, i);
0226 config.attrs[attr].attr.id = GPIO_V2_LINE_ATTR_ID_DEBOUNCE;
0227 config.attrs[attr].attr.debounce_period_us = debounce_period_us;
0228 }
0229
0230 if (!device_name || num_lines == 0) {
0231 print_usage();
0232 return -1;
0233 }
0234 if (!(config.flags & EDGE_FLAGS)) {
0235 printf("No flags specified, listening on both rising and "
0236 "falling edges\n");
0237 config.flags |= EDGE_FLAGS;
0238 }
0239 return monitor_device(device_name, lines, num_lines, &config, loops);
0240 }