From da0514458624ccb02fda91e4dc2f16c6bae41f4a Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 21 Feb 2022 17:11:41 -0800 Subject: [PATCH] gpiod: new commands. Equivalent to the content of the gpiod debian package. Very different interface to the traditional Raspberry Pi command, but that command explicitly calls itself deprecated and tells you to use the gpiod package's commands instead. "Works for me" on a Raspberry Pi 400, with a (small) variety of things connected to GPIOs as inputs and outputs. Missing gpiomon, which -- since the rest of these are about a year old at this point -- it doesn't look like I'm going to get around to writing any time soon unless someone asks for it... --- toys/other/gpiod.c | 259 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 toys/other/gpiod.c diff --git a/toys/other/gpiod.c b/toys/other/gpiod.c new file mode 100644 index 00000000..60297b0f --- /dev/null +++ b/toys/other/gpiod.c @@ -0,0 +1,259 @@ +/* gpiod.c - gpio tools + * + * Copyright 2021 The Android Open Source Project + * + * TODO: gpiomon + +USE_GPIODETECT(NEWTOY(gpiodetect, ">0", TOYFLAG_USR|TOYFLAG_BIN)) +USE_GPIOFIND(NEWTOY(gpioinfo, "", TOYFLAG_USR|TOYFLAG_BIN)) +USE_GPIOGET(NEWTOY(gpioget, "<2l", TOYFLAG_USR|TOYFLAG_BIN)) +USE_GPIOINFO(NEWTOY(gpiofind, "<1>1", TOYFLAG_USR|TOYFLAG_BIN)) +USE_GPIOSET(NEWTOY(gpioset, "<2l", TOYFLAG_USR|TOYFLAG_BIN)) + +config GPIODETECT + bool "gpiodetect" + default y + help + usage: gpiodetect + + Show all gpio chips' names, labels, and number of lines. + +config GPIOFIND + bool "gpiofind" + default y + help + usage: gpiofind NAME + + Show the chip and line number for the given line name. + +config GPIOINFO + bool "gpioinfo" + default y + help + usage: gpioinfo [CHIP...] + + Show gpio chips' lines. + +config GPIOGET + bool "gpioget" + default y + help + usage: gpioget [-l] CHIP LINE... + + Gets the values of the given lines on CHIP. Use gpiofind to convert line + names to numbers. + + -l Active low + +config GPIOSET + bool "gpioset" + default y + help + usage: gpioset [-l] CHIP LINE=VALUE... + + Set the lines on CHIP to the given values. Use gpiofind to convert line + names to numbers. + + -l Active low +*/ + +#define FOR_gpiodetect +#define TT this.gpiod +#include "toys.h" + +GLOBALS( + struct arg_list *chips; + int chip_count; +) + +#include + +static int open_chip(char *chip) +{ + sprintf(toybuf, isdigit(*chip) ? "/dev/gpiochip%s" : "/dev/%s", chip); + return xopen(toybuf, O_RDWR); +} + +static int collect_chips(struct dirtree *node) +{ + struct arg_list *new; + int n; + + if (!node->parent) return DIRTREE_RECURSE; // Skip the directory itself. + + if (sscanf(node->name, "gpiochip%d", &n)!=1) return 0; + + new = xmalloc(sizeof(struct arg_list)); + new->arg = strdup(node->name); + new->next = TT.chips; + TT.chips = new; + TT.chip_count++; + return 0; +} + +static int comparator(const void *a, const void *b) +{ + struct arg_list *lhs = *(struct arg_list **)a; + struct arg_list *rhs = *(struct arg_list **)b; + + return strcmp(lhs->arg, rhs->arg); +} + +static void foreach_chip(void (*cb)(char *name)) +{ + struct arg_list **sorted, *chip; + int i = 0; + + dirtree_flagread("/dev", DIRTREE_SHUTUP, collect_chips); + + sorted = xmalloc(TT.chip_count*sizeof(void *)); + for (chip = TT.chips; chip; chip=chip->next, i++) sorted[i] = chip; + qsort(sorted, TT.chip_count, sizeof(void *), comparator); + + for (i=0; iarg); + cb(toybuf); + } + + free(sorted); + llist_free_arg(TT.chips); +} + +static void gpiodetect(char *path) +{ + struct gpiochip_info chip; + int fd = xopen(path, O_RDWR); + + xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip); + close(fd); + + // gpiochip0 [pinctrl-bcm2711] (58 line) + printf("%s [%s] (%u line%s)\n", chip.name, chip.label, chip.lines, + chip.lines==1?"":"s"); +} + +void gpiodetect_main(void) +{ + foreach_chip(gpiodetect); +} + +#define FOR_gpiofind +#include "generated/flags.h" + +static void gpiofind(char *path) +{ + struct gpiochip_info chip; + struct gpioline_info line; + int fd = xopen(path, O_RDWR); + + xioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &chip); + + for (line.line_offset=0; line.line_offset= GPIOHANDLES_MAX) error_exit("too many requests!"); + line = atolx_range(*args, 0, chip.lines); + req.lineoffsets[req.lines] = line; + } + xioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); + xioctl(req.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); + for (line=0; line0 ? " " : "", data.values[line]); + } + xputc('\n'); +} + +#define FOR_gpioset +#include "generated/flags.h" + +void gpioset_main(void) +{ + struct gpiohandle_request req = { .flags = GPIOHANDLE_REQUEST_OUTPUT }; + char **args = toys.optargs; + int fd, line, value; + + fd = open_chip(*args); + if (FLAG(l)) req.flags |= GPIOHANDLE_REQUEST_ACTIVE_LOW; + for (args++; *args; args++, req.lines++) { + if (req.lines >= GPIOHANDLES_MAX) error_exit("too many requests!"); + if (sscanf(*args, "%d=%d", &line, &value) != 2) + perror_exit("not LINE=VALUE: %s", *args); + req.lineoffsets[req.lines] = line; + req.default_values[req.lines] = value; + } + xioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &req); +} -- 2.39.2