Make it possible for operations to refer to GPIO pins by name

- Try to guess what is provided as a pin spec for -t or for get/set
    operation: number or name. Fails in case of ambiguity.
- Add -p and -N switches to force pin specification interpretation:
    -p forces spec to be pin number, -N forces it to be name

Submitted by:	Emmanuel Vadot <manu@bidouilliste.com>
Differential Revision:	https://reviews.freebsd.org/D5201
This commit is contained in:
Oleksandr Tymoshenko 2016-03-11 21:05:16 +00:00
parent 645e6cf5cc
commit 3b2bb13317
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296682
2 changed files with 130 additions and 45 deletions

View File

@ -27,7 +27,7 @@
.\" .\"
.\" $FreeBSD$ .\" $FreeBSD$
.\" .\"
.Dd March 8, 2015 .Dd March 11, 2016
.Dt GPIOCTL 1 .Dt GPIOCTL 1
.Os .Os
.Sh NAME .Sh NAME
@ -40,21 +40,25 @@
.Op Fl v .Op Fl v
.Nm .Nm
.Op Fl f Ar ctldev .Op Fl f Ar ctldev
.Op Fl pN
.Cm -t .Cm -t
.Ar pin .Ar pin
.Nm .Nm
.Op Fl f Ar ctldev .Op Fl f Ar ctldev
.Op Fl pN
.Cm -c .Cm -c
.Ar pin .Ar pin
.Ar flag .Ar flag
.Op flag ... .Op flag ...
.Nm .Nm
.Op Fl f Ar ctldev .Op Fl f Ar ctldev
.Op Fl pN
.Cm -n .Cm -n
.Ar pin .Ar pin
.Ar pin-name .Ar pin-name
.Nm .Nm
.Op Cm -f Ar ctldev .Op Cm -f Ar ctldev
.Op Fl pN
.Ar pin .Ar pin
.Ar [0|1] .Ar [0|1]
.Sh DESCRIPTION .Sh DESCRIPTION
@ -62,6 +66,20 @@ The
.Nm .Nm
utility could be used to manage GPIO pins from userland and list available pins. utility could be used to manage GPIO pins from userland and list available pins.
.Pp .Pp
The
.Pa pin
argument can either be a
.Pa pin-number
or a
.Pa pin-name .
If it is a number and a pin has this number as its name and you did not use
.Fl N
or
.Fl p
, then
.Nm
exits.
.Pp
The options are as follows: The options are as follows:
.Bl -tag -width ".Fl f Ar ctldev" .Bl -tag -width ".Fl f Ar ctldev"
.It Fl c Ar pin Ar flag Op flag ... .It Fl c Ar pin Ar flag Op flag ...
@ -96,9 +114,17 @@ list available pins
.It Fl n Ar pin Ar pin-name .It Fl n Ar pin Ar pin-name
set the name used to describe the pin set the name used to describe the pin
.It Fl t Ar pin .It Fl t Ar pin
toggle value of provided pin number toggle value of provided pin
.It Fl v .It Fl v
be verbose: for each listed pin print current configuration be verbose: for each listed pin print current configuration
.It Fl p
Force
.Pa pin
to be interpreted as a pin number
.It Fl N
Force
.Pa pin
to be interpreted as a pin name
.El .El
.Sh EXAMPLES .Sh EXAMPLES
.Bl -bullet .Bl -bullet
@ -114,6 +140,18 @@ gpioctl -f /dev/gpioc0 12 1
Configure pin 12 to be input pin Configure pin 12 to be input pin
.Pp .Pp
gpioctl -f /dev/gpioc0 -c 12 IN gpioctl -f /dev/gpioc0 -c 12 IN
.It
Set the name of pin 12 to test
.Pp
gpioctl -f /dev/gpioc0 -n 12 test
.It
Toggle the value the pin named test
.Pp
gpioctl -f /dev/gpioc0 -t test
.It
Toggle the value of pin number 12 even if another pin has the name 12
.Pp
gpioctl -f /dev/gpioc0 -pt 12
.El .El
.Sh SEE ALSO .Sh SEE ALSO
.Xr gpio 4 , .Xr gpio 4 ,

View File

@ -1,6 +1,7 @@
/*- /*-
* Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org>
* Copyright (c) 2014, Rui Paulo <rpaulo@FreeBSD.org> * Copyright (c) 2014, Rui Paulo <rpaulo@FreeBSD.org>
* Copyright (c) 2015, Emmanuel Vadot <manu@bidouilliste.com>
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@ -40,6 +41,10 @@ __FBSDID("$FreeBSD$");
#include <libgpio.h> #include <libgpio.h>
#define PIN_TYPE_UNKNOWN 0
#define PIN_TYPE_NUMBER 1
#define PIN_TYPE_NAME 2
struct flag_desc { struct flag_desc {
const char *name; const char *name;
uint32_t flag; uint32_t flag;
@ -66,10 +71,10 @@ usage(void)
{ {
fprintf(stderr, "Usage:\n"); fprintf(stderr, "Usage:\n");
fprintf(stderr, "\tgpioctl [-f ctldev] -l [-v]\n"); fprintf(stderr, "\tgpioctl [-f ctldev] -l [-v]\n");
fprintf(stderr, "\tgpioctl [-f ctldev] -t pin\n"); fprintf(stderr, "\tgpioctl [-f ctldev] [-pN] -t pin\n");
fprintf(stderr, "\tgpioctl [-f ctldev] -c pin flag ...\n"); fprintf(stderr, "\tgpioctl [-f ctldev] [-pN] -c pin flag ...\n");
fprintf(stderr, "\tgpioctl [-f ctldev] -n pin pin-name\n"); fprintf(stderr, "\tgpioctl [-f ctldev] [-pN] -n pin pin-name\n");
fprintf(stderr, "\tgpioctl [-f ctldev] pin [0|1]\n"); fprintf(stderr, "\tgpioctl [-f ctldev] [-pN] pin [0|1]\n");
exit(1); exit(1);
} }
@ -163,6 +168,32 @@ dump_pins(gpio_handle_t handle, int verbose)
free(cfgs); free(cfgs);
} }
static int
get_pinnum_by_name(gpio_handle_t handle, const char *name) {
int i, maxpin, pinn;
gpio_config_t *cfgs;
gpio_config_t *pin;
pinn = -1;
maxpin = gpio_pin_list(handle, &cfgs);
if (maxpin < 0) {
perror("gpio_pin_list");
exit(1);
}
for (i = 0; i <= maxpin; i++) {
pin = cfgs + i;
gpio_pin_get(handle, pin->g_pin);
if (!strcmp(name, pin->g_name)) {
pinn = i;
break;
}
}
free(cfgs);
return pinn;
}
static void static void
fail(const char *fmt, ...) fail(const char *fmt, ...)
{ {
@ -181,19 +212,16 @@ main(int argc, char **argv)
gpio_config_t pin; gpio_config_t pin;
gpio_handle_t handle; gpio_handle_t handle;
char *ctlfile = NULL; char *ctlfile = NULL;
int pinn, pinv, ch; int pinn, pinv, pin_type, ch;
int flags, flag, ok; int flags, flag, ok;
int config, list, name, toggle, verbose; int config, list, name, toggle, verbose;
config = toggle = verbose = list = name = pinn = 0; config = toggle = verbose = list = name = pin_type = 0;
while ((ch = getopt(argc, argv, "c:f:ln:t:v")) != -1) { while ((ch = getopt(argc, argv, "cf:lntvNp")) != -1) {
switch (ch) { switch (ch) {
case 'c': case 'c':
config = 1; config = 1;
pinn = str2int(optarg, &ok);
if (!ok)
fail("Invalid pin number: %s\n", optarg);
break; break;
case 'f': case 'f':
ctlfile = optarg; ctlfile = optarg;
@ -203,15 +231,15 @@ main(int argc, char **argv)
break; break;
case 'n': case 'n':
name = 1; name = 1;
pinn = str2int(optarg, &ok); break;
if (!ok) case 'N':
fail("Invalid pin number: %s\n", optarg); pin_type = PIN_TYPE_NAME;
break;
case'p':
pin_type = PIN_TYPE_NUMBER;
break; break;
case 't': case 't':
toggle = 1; toggle = 1;
pinn = str2int(optarg, &ok);
if (!ok)
fail("Invalid pin number: %s\n", optarg);
break; break;
case 'v': case 'v':
verbose = 1; verbose = 1;
@ -232,33 +260,58 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
/* Set the pin name. */
if (name) {
if (argc == 0) {
usage();
exit(1);
}
if (gpio_pin_set_name(handle, pinn, argv[0]) < 0) {
perror("gpio_pin_set_name");
exit(1);
}
exit(0);
}
if (list) { if (list) {
dump_pins(handle, verbose); dump_pins(handle, verbose);
gpio_close(handle); gpio_close(handle);
exit(0); exit(0);
} }
if (toggle) { if (argc == 0)
/* usage();
* -t pin assumes no additional arguments
*/ /* Find the pin number by the name */
if (argc > 0) { switch (pin_type) {
case PIN_TYPE_UNKNOWN:
/* First test if it is a pin number */
pinn = str2int(argv[0], &ok);
if (ok) {
/* Test if we have any pin named by this number and tell the user */
if (get_pinnum_by_name(handle, argv[0]) != -1)
fail("%s is also a pin name, use -p or -N\n", argv[0]);
} else {
/* Test if it is a name */
if ((pinn = get_pinnum_by_name(handle, argv[0])) == -1)
fail("Can't find pin named \"%s\"\n", argv[0]);
}
break;
case PIN_TYPE_NUMBER:
pinn = str2int(argv[0], &ok);
if (!ok)
fail("Invalid pin number: %s\n", argv[0]);
break;
case PIN_TYPE_NAME:
if ((pinn = get_pinnum_by_name(handle, argv[0])) == -1)
fail("Can't find pin named \"%s\"\n", argv[0]);
break;
}
/* Set the pin name. */
if (name) {
if (argc != 2)
usage(); usage();
if (gpio_pin_set_name(handle, pinn, argv[1]) < 0) {
perror("gpio_pin_set_name");
exit(1); exit(1);
} }
exit(0);
}
if (toggle) {
/*
* -t pin assumes no additional arguments
*/
if (argc > 1)
usage();
if (gpio_pin_toggle(handle, pinn) < 0) { if (gpio_pin_toggle(handle, pinn) < 0) {
perror("gpio_pin_toggle"); perror("gpio_pin_toggle");
exit(1); exit(1);
@ -269,7 +322,7 @@ main(int argc, char **argv)
if (config) { if (config) {
flags = 0; flags = 0;
for (i = 0; i < argc; i++) { for (i = 1; i < argc; i++) {
flag = str2cap(argv[i]); flag = str2cap(argv[i]);
if (flag < 0) if (flag < 0)
fail("Invalid flag: %s\n", argv[i]); fail("Invalid flag: %s\n", argv[i]);
@ -287,14 +340,8 @@ main(int argc, char **argv)
/* /*
* Last two cases - set value or print value * Last two cases - set value or print value
*/ */
if ((argc == 0) || (argc > 2)) { if ((argc == 0) || (argc > 2))
usage(); usage();
exit(1);
}
pinn = str2int(argv[0], &ok);
if (!ok)
fail("Invalid pin number: %s\n", argv[0]);
/* /*
* Read pin value * Read pin value
@ -311,7 +358,7 @@ main(int argc, char **argv)
/* Is it valid number (0 or 1) ? */ /* Is it valid number (0 or 1) ? */
pinv = str2int(argv[1], &ok); pinv = str2int(argv[1], &ok);
if (!ok || ((pinv != 0) && (pinv != 1))) if (ok == 0 || ((pinv != 0) && (pinv != 1)))
fail("Invalid pin value: %s\n", argv[1]); fail("Invalid pin value: %s\n", argv[1]);
/* /*