File:  [ELWIX - Embedded LightWeight unIX -] / embedtools / src / butz.c
Revision 1.1.2.7: download - view: text, annotated - select for diffs - revision graph
Sat Feb 8 18:56:50 2014 UTC (10 years, 3 months ago) by misho
Branches: tools2_6
change places

#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;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>