- Implement debounce support.

- Clean up examples.
- Call deamon(3) after we open the PID file.

Submitted by:	 Mathew Kanner <mat@cnd.mcgill.ca>
This commit is contained in:
Matthew N. Dodd 2003-04-09 23:19:50 +00:00
parent 68d25868d0
commit f5a4d3f069
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=113309
2 changed files with 86 additions and 31 deletions

View File

@ -43,12 +43,10 @@
.Nd perform actions according to USB HID controls
.Sh SYNOPSIS
.Nm
.Op Fl diev
.Fl c Ar config-file
.Op Fl d
.Op Fl i
.Fl f Ar device
.Op Fl p Ar pidfile
.Op Fl v
.Ar arg ...
.Sh DESCRIPTION
.Nm
@ -60,12 +58,19 @@ die when the USB device is unplugged.
.Pp
The options are as follows:
.Bl -tag -width Ds
.It Fl c Ar config-file
Specify a path name for the config file.
.It Fl d
Toggle the daemon flag.
.It Fl e
Instruct
.Nm
to die early. Useful when specified with multiple
verbose options to see how files are parsed.
.It Fl i
Ignore HID items in the config file that does not exist in the device.
.It Fl v
Be verbose, and do not become a daemon.
.It Fl c Ar config-file
Specify a path name for the config file.
.It Fl f Ar device
Specify a path name for the device to operate on.
If
@ -77,8 +82,6 @@ path, it is taken to be the name of the device under
An absolute path is taken to be the literal device pathname.
.It Fl p Ar pidfile
Specify an alternate file in which to store the process ID.
.It Fl v
Be verbose, and do not become a daemon.
.El
.Pp
The config file will be re-read if the process gets a HUP signal.
@ -89,8 +92,8 @@ action; if a line begins with a whitespace it is considered a continuation
of the previous line.
Lines beginning with `#' are considered as comments.
.Pp
Each line has three parts: a name of a USB HID item, a value for that item,
and an action.
Each line has four parts: a name of a USB HID item, a value for that item,
a debounce value, and an action.
There must be whitespace between the parts.
.Pp
The item names are similar to those used by
@ -102,6 +105,12 @@ When the item reports this value
the action will be performed.
If the value is `*' it will match any value.
.Pp
The debouce value is an integer not less than 0. The value of 0
indicates that no debouncing should occur. A value of 1 will only
execute the action when the state changes. Values greater than one
specify that an action should be performed only when the value
changes by that amount.
.Pp
The action is a normal command that is executed with
.Xr system 3 .
Before it is executed some substitution will occur:
@ -111,7 +120,7 @@ of the HID item, `$N' will be replaced by the name
of the control, and `$H' will be replaced by the name
of the HID device.
.Sh FILES
.Bl -tag -indent
.Bl -tag -width indent
.It Pa /usr/share/misc/usb_hid_usages
The HID usage table.
.It Pa /var/run/usbaction.pid
@ -122,22 +131,26 @@ The following configuration file can be used to control a pair
of Philips USB speakers with the HID controls on the speakers.
.Bd -literal -offset indent
# Configuration for various Philips USB speakers
Consumer:Consumer_Control.Consumer:Volume_Up 1
mixerctl -f $1 -n -w fea8-i7-master++
Consumer:Consumer_Control.Consumer:Volume_Down 1
mixerctl -f $1 -n -w fea8-i7-master--
Consumer:Consumer_Control.Consumer:Mute 1
mixerctl -f $1 -n -w fea8-i7-mute++
Consumer:Consumer_Control.Consumer:Channel_Top.Microsoft:Base_Up 1
mixerctl -f $1 -n -w fea8-i7-bass++
Consumer:Consumer_Control.Consumer:Channel_Top.Microsoft:Base_Down 1
mixerctl -f $1 -n -w fea8-i7-bass--
Consumer:Volume_Up 1 0 mixer -f $1 vol +1
Consumer:Volume_Down 1 0 mixer -f $1 vol -1
# mute not supported
#Consumer:Mute 1 0 mixer -f $1 mute
Consumer:Channel_Top.Microsoft:Base_Up 1 0 mixer -f $1 bass +1
Consumer:Channel_Top.Microsoft:Base_Down 1 0 mixer -f $1 bass -1
.Ed
.Pp
A sample invocation using this configuration would be
.Bd -literal -offset indent
usbhidaction -f /dev/uhid1 -c conf /dev/mixer1
.Ed
.Pp
The following example controls the mixer volume using a Logitech Wingman.
Notice the debouce of 1 for buttons and 5 for the slider.
.Bd -literal -offset indent
Button:Button_1 1 1 mixer vol +10
Button:Button_2 1 1 mixer vol -10
Generic_Desktop:Z * 5 mixer vol `echo $V | awk '{print int($$1/255*100)}'`
.Ed
.Sh SEE ALSO
.Xr usbhidctl 1 ,
.Xr usbhid 3 ,

View File

@ -66,6 +66,9 @@ struct command {
struct hid_item item;
int value;
int lastseen;
int lastused;
int debounce;
char anyvalue;
char *name;
char *action;
@ -91,7 +94,7 @@ main(int argc, char **argv)
const char *conf = NULL;
const char *dev = NULL;
int fd, fp, ch, sz, n, val, i;
int demon, ignore;
int demon, ignore, dieearly;
report_desc_t repd;
char buf[100];
char devnamebuf[PATH_MAX];
@ -100,7 +103,8 @@ main(int argc, char **argv)
demon = 1;
ignore = 0;
while ((ch = getopt(argc, argv, "c:df:ip:v")) != -1) {
dieearly = 0;
while ((ch = getopt(argc, argv, "c:def:ip:v")) != -1) {
switch(ch) {
case 'c':
conf = optarg;
@ -108,6 +112,9 @@ main(int argc, char **argv)
case 'd':
demon ^= 1;
break;
case 'e':
dieearly = 1;
break;
case 'i':
ignore++;
break;
@ -161,8 +168,6 @@ main(int argc, char **argv)
(void)signal(SIGHUP, sighup);
if (demon) {
if (daemon(0, 0) < 0)
err(1, "daemon()");
fp = open(pidfile, O_WRONLY|O_CREAT, S_IRUSR|S_IRGRP|S_IROTH);
if (fp >= 0) {
sz=snprintf(buf,100, "%d\n", getpid());
@ -170,6 +175,8 @@ main(int argc, char **argv)
close(fp);
} else
err(1, "%s", pidfile);
if (daemon(0, 0) < 0)
err(1, "daemon()");
isdemon = 1;
}
@ -194,9 +201,28 @@ main(int argc, char **argv)
#endif
for (cmd = commands; cmd; cmd = cmd->next) {
val = hid_get_data(buf, &cmd->item);
if (cmd->value == val || cmd->anyvalue)
if (cmd->value != val && cmd->anyvalue == 0)
goto next;
if ((cmd->debounce == 0) ||
(cmd->debounce && ((cmd->lastseen == -1) ||
(cmd->lastseen != val)))) {
docmd(cmd, val, dev, argc, argv);
goto next;
}
if ((cmd->debounce > 1) &&
((cmd->lastused == -1) ||
(abs(cmd->lastused - val) >= cmd->debounce))) {
docmd(cmd, val, dev, argc, argv);
cmd->lastused = val;
goto next;
}
next:
cmd->lastseen = val;
}
if (dieearly)
exit(0);
if (reparse) {
struct command *cmds =
parse_conf(conf, repd, reportid, ignore);
@ -215,8 +241,8 @@ void
usage(void)
{
fprintf(stderr, "Usage: %s -c config_file [-d] -f hid_dev "
"[-i] [-p pidfile] [-v]\n", getprogname());
fprintf(stderr, "Usage: %s [-deiv] -c config_file -f hid_dev "
"[-p pidfile]\n", getprogname());
exit(1);
}
@ -237,7 +263,7 @@ parse_conf(const char *conf, report_desc_t repd, int reportid, int ignore)
FILE *f;
char *p;
int line;
char buf[SIZE], name[SIZE], value[SIZE], action[SIZE];
char buf[SIZE], name[SIZE], value[SIZE], debounce[SIZE], action[SIZE];
char usage[SIZE], coll[SIZE];
struct command *cmd, *cmds;
struct hid_data *d;
@ -263,7 +289,8 @@ parse_conf(const char *conf, report_desc_t repd, int reportid, int ignore)
}
if (p)
*p = 0;
if (sscanf(buf, "%s %s %[^\n]", name, value, action) != 3) {
if (sscanf(buf, "%s %s %s %[^\n]",
name, value, debounce, action) != 4) {
if (isdemon) {
syslog(LOG_WARNING, "config file `%s', line %d"
", syntax error: %s", conf, line, buf);
@ -290,18 +317,33 @@ parse_conf(const char *conf, report_desc_t repd, int reportid, int ignore)
if (isdemon) {
syslog(LOG_WARNING,
"config file `%s', line %d, "
"bad value: %s\n",
"bad value: %s (should be * or a number)\n",
conf, line, value);
freecommands(cmds);
return (NULL);
} else {
errx(1, "config file `%s', line %d, "
"bad value: %s\n",
"bad value: %s (should be * or a number)\n",
conf, line, value);
}
}
}
if (sscanf(debounce, "%d", &cmd->debounce) != 1) {
if (isdemon) {
syslog(LOG_WARNING,
"config file `%s', line %d, "
"bad value: %s (should be a number >= 0)\n",
conf, line, debounce);
freecommands(cmds);
return (NULL);
} else {
errx(1, "config file `%s', line %d, "
"bad value: %s (should be a number >= 0)\n",
conf, line, debounce);
}
}
coll[0] = 0;
for (d = hid_start_parse(repd, 1 << hid_input, reportid);
hid_get_item(d, &h); ) {