/*
 * Created by jiaqiang.ye@lnxall.com
 *
 * Simple New implementation for QYWDT
 *
 * 2024/10/25
 */

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <sched.h>
#include <time.h>
#include <signal.h>

#include "lnxall_gpio.h"

static int have_signal;
static struct lnxall_gpio * lgpio;
static struct lnxall_gpio * egpio;

static void qywdt_signal(int signo)
{
	have_signal++;
	if (egpio != NULL)
		lnxall_gpio_setval(egpio, 0);
	fprintf(stderr, "Warning, Received signal %d, about to exit...\n", signo);
	fflush(stderr);
}

static void raise_priority(void)
{
	int ret, niceval, error;
	struct sched_param sp;

	ret = errno = 0;
	niceval = nice(0);
	error = errno;
	if (error == 0) {
		ret = nice(-19 - niceval);
		error = errno;
	}

	if (error != 0) {
		fprintf(stderr, "Error, nice has failed with %d: %s\n",
			ret, strerror(error));
		fflush(stderr);
	}

	sp.sched_priority = 99;
	ret = sched_setscheduler(0, SCHED_RR, &sp);
	if (ret < 0) {
		error = errno;
		fprintf(stderr, "Error, failed to set scheduler: %s\n",
			strerror(error));
		fflush(stderr);
	}
}

static int qywdt_msleep(unsigned int ms)
{
	struct timespec spec;

	spec.tv_sec = (time_t) (ms / 1000);
	spec.tv_nsec = (long) ((ms % 1000) * 1000000);
	return nanosleep(&spec, NULL);
}

int main(int argc, char *argv[])
{
	int ret;

	have_signal = 0;
	lgpio = egpio = NULL;
	raise_priority();

	egpio = lnxall_gpios_init(1);
	egpio->gpio_num = 6;
	egpio->isout = 1;
	ret = lnxall_gpio_open(egpio, 1);
	if (ret < 0) {
		fprintf(stderr, "Error, failed to open GPIO: %d\n", ret);
		fflush(stderr);
		return 1;
	}

	// disable the watch dog
	lnxall_gpio_setval(egpio, 0);

	lgpio = lnxall_gpios_init(1);
	lgpio->gpio_num = 5;
	lgpio->isout = 1;
	ret = lnxall_gpio_open(lgpio, 1);
	if (ret < 0) {
		fprintf(stderr, "Error, failed to open GPIO for QYWDT: %d\n", ret);
		fflush(stderr);
		return 2;
	}

	// feed the dog
	lnxall_gpio_setval(lgpio, 1);
	qywdt_msleep(600);
	lnxall_gpio_setval(lgpio, 0);

	// register signal handler
	signal(SIGINT, qywdt_signal);
	signal(SIGTERM, qywdt_signal);
	signal(SIGHUP, qywdt_signal);

	// enable the watch dog
	lnxall_gpio_setval(egpio, 1);
	fputs("Feeding RK3568 external watch dog...\n", stdout);
	fflush(stdout);
	while (have_signal == 0) {
		ret = lnxall_gpio_setval(lgpio, 1);
		if (ret < 0) {
			fputs("Error, failed to feed the watch dog1\n", stderr);
			fflush(stderr);
		}

		qywdt_msleep(600);
		ret = lnxall_gpio_setval(lgpio, 0);
		if (ret < 0) {
			fputs("Error, failed to feed the watch dog0\n", stderr);
			fflush(stderr);
		}
		qywdt_msleep(600);
	}

	// disable the watch dog
	lnxall_gpio_setval(egpio, 0);
	return 0;
}
