version 1.1, 2014/02/07 23:37:41
|
version 1.2, 2014/02/08 20:57:16
|
Line 0
|
Line 1
|
|
#include "global.h" |
|
|
|
|
|
cfg_root_t cfg; |
|
sched_root_task_t *root; |
|
int Kill, gpio, flg, maxpins, defact, resbut, led = -1; |
|
extern char compiled[], compiledby[], compilehost[]; |
|
char szCfgName[PATH_MAX] = BUTZ_CFG; |
|
char szDevName[PATH_MAX] = _PATH_DEVGPIOC"0"; |
|
|
|
static void |
|
Usage() |
|
{ |
|
printf( " -= Butz =- Service for board buttons management\n" |
|
"=== %s === %s@%s ===\n\n" |
|
" Syntax: butz [options] [set_value]\n" |
|
"\n" |
|
"\t-c <cfgfile>\tConfig file [default: /etc/butz.conf]\n" |
|
"\t-d <devname>\tGPIO control device [default: /dev/gpioc]\n" |
|
"\n", compiled, compiledby, compilehost); |
|
} |
|
|
|
static int |
|
prepareGPIO() |
|
{ |
|
const char *str; |
|
struct gpio_pin pin; |
|
struct gpio_req req; |
|
|
|
str = cfg_getAttribute(&cfg, "reset", "default_after"); |
|
if (str) |
|
defact = strtol(str, NULL, 0); |
|
str = cfg_getAttribute(&cfg, "reset", "gpio_led_ping"); |
|
if (str) |
|
led = strtol(str, NULL, 0); |
|
str = cfg_getAttribute(&cfg, "reset", "gpio_pin"); |
|
if (!str || maxpins < (resbut = strtol(str, NULL, 0))) { |
|
EERROR(EINVAL, "Reset button pin not defined or wrong number!"); |
|
return -1; |
|
} |
|
|
|
/* switch button pin into input state */ |
|
pin.gp_pin = resbut; |
|
pin.gp_flags = GPIO_PIN_INPUT; |
|
if (ioctl(gpio, GPIOSETCONFIG, &pin) == -1) |
|
return -1; |
|
/* toggle led pin */ |
|
if (led != -1) { |
|
req.gp_pin = led; |
|
if (ioctl(gpio, GPIOTOGGLE, &req) == -1) { |
|
ESYSERR(0); |
|
return -1; |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static void * |
|
sigHandler(sched_task_t *task) |
|
{ |
|
switch (TASK_VAL(task)) { |
|
case SIGHUP: |
|
cfgUnloadConfig(&cfg); |
|
if (cfgLoadConfig(szCfgName, &cfg)) { |
|
ELIBERR(cfg); |
|
Kill++; |
|
} |
|
if (prepareGPIO()) |
|
Kill++; |
|
break; |
|
case SIGTERM: |
|
Kill++; |
|
break; |
|
default: |
|
EERROR(EINVAL, "Undefined signal %lu!", TASK_VAL(task)); |
|
break; |
|
} |
|
taskExit(task, NULL); |
|
} |
|
|
|
static void * |
|
execReset(sched_task_t *task) |
|
{ |
|
pid_t pid; |
|
const char *str; |
|
|
|
str = cfg_getAttribute(&cfg, "reset", "click"); |
|
if (!str) |
|
taskExit(task, NULL); |
|
|
|
if ((pid = fork()) == -1) |
|
ESYSERR(0); |
|
else if (!pid) { |
|
execl(str, str, "click", NULL); |
|
ESYSERR(0); |
|
_exit(127); |
|
} |
|
|
|
flg ^= flg; |
|
taskExit(task, NULL); |
|
} |
|
|
|
static void * |
|
execDefault(sched_task_t *task) |
|
{ |
|
pid_t pid; |
|
const char *str; |
|
|
|
str = cfg_getAttribute(&cfg, "reset", "default"); |
|
if (!str) |
|
taskExit(task, NULL); |
|
|
|
if ((pid = fork()) == -1) |
|
ESYSERR(0); |
|
else if (!pid) { |
|
execl(str, str, "default", NULL); |
|
ESYSERR(0); |
|
_exit(127); |
|
} |
|
|
|
flg ^= flg; |
|
taskExit(task, NULL); |
|
} |
|
|
|
static void * |
|
butReset(sched_task_t *task) |
|
{ |
|
struct timespec ts = { 1, 0 }; |
|
struct gpio_req req; |
|
|
|
/* check reset button */ |
|
req.gp_pin = resbut; |
|
if (ioctl(gpio, GPIOGET, &req) == -1) { |
|
ESYSERR(0); |
|
goto end; |
|
} |
|
/* switch on */ |
|
if (flg != -1 && !req.gp_value) |
|
if (++flg == 1) |
|
schedSuspend(TASK_ROOT(task), execReset, NULL, flg, NULL, 0); |
|
if (defact && flg >= defact) { |
|
schedCancelby(TASK_ROOT(task), taskSUSPEND, CRITERIA_CALL, execReset, NULL); |
|
schedEvent(TASK_ROOT(task), execDefault, NULL, flg, NULL, 0); |
|
flg = -1; |
|
goto end; |
|
} |
|
if (flg > 0 && req.gp_value) |
|
schedResumeby(TASK_ROOT(task), CRITERIA_ID, (void*) 1); |
|
|
|
/* toggle led pin */ |
|
if (flg != -1 && led != -1) { |
|
req.gp_pin = led; |
|
if (ioctl(gpio, GPIOTOGGLE, &req) == -1) |
|
ESYSERR(0); |
|
} |
|
end: |
|
schedTimer(TASK_ROOT(task), TASK_FUNC(task), TASK_ARG(task), |
|
ts, TASK_DATA(task), TASK_DATLEN(task)); |
|
taskExit(task, NULL); |
|
} |
|
|
|
|
|
int |
|
main(int argc, char **argv) |
|
{ |
|
char ch; |
|
pid_t pid; |
|
struct timespec ts = { 1, 0 }; |
|
|
|
while ((ch = getopt(argc, argv, "hc:d:")) != -1) |
|
switch (ch) { |
|
case 'd': |
|
strlcpy(szDevName, optarg, sizeof szDevName); |
|
break; |
|
case 'c': |
|
strlcpy(szCfgName, optarg, sizeof szCfgName); |
|
break; |
|
case 'h': |
|
default: |
|
Usage(); |
|
return 1; |
|
} |
|
argc -= optind; |
|
argv += optind; |
|
|
|
switch ((pid = fork())) { |
|
case -1: |
|
printf("Error:: failed fork() #%d - %s\n", errno, strerror(errno)); |
|
return 1; |
|
case 0: |
|
setsid(); |
|
chdir("/"); |
|
|
|
gpio = open(_PATH_DEVNULL, O_RDWR); |
|
if (gpio > 2) { |
|
dup2(gpio, STDIN_FILENO); |
|
dup2(gpio, STDOUT_FILENO); |
|
dup2(gpio, STDERR_FILENO); |
|
close(gpio); |
|
} |
|
break; |
|
default: |
|
return 0; |
|
} |
|
|
|
openlog("butz", LOG_PID | LOG_CONS, LOG_DAEMON); |
|
gpio = open(szDevName, O_RDONLY); |
|
if (gpio == -1) { |
|
ESYSERR(0); |
|
return 1; |
|
} |
|
if (ioctl(gpio, GPIOMAXPIN, &maxpins) == -1) { |
|
ESYSERR(0); |
|
return 1; |
|
} |
|
|
|
if (cfgLoadConfig(szCfgName, &cfg)) { |
|
ELIBERR(cfg); |
|
close(gpio); |
|
return 1; |
|
} |
|
if (prepareGPIO()) { |
|
close(gpio); |
|
return 1; |
|
} |
|
root = schedBegin(); |
|
if (!root) { |
|
ELIBERR(sched); |
|
close(gpio); |
|
return 1; |
|
} |
|
|
|
schedSignal(root, sigHandler, NULL, SIGHUP, NULL, 0); |
|
schedSignal(root, sigHandler, NULL, SIGTERM, NULL, 0); |
|
schedTimer(root, butReset, NULL, ts, NULL, 0); |
|
|
|
schedRun(root, &Kill); |
|
schedEnd(&root); |
|
cfgUnloadConfig(&cfg); |
|
close(gpio); |
|
closelog(); |
|
return 0; |
|
} |