/*
 * Copyright(C) Paul und Scherer (mct.de/mct.net)
 *
 * This example demonstrates how to...
 *
 *  ... set the RTC.
 *
 *  ... set the RTC alarm timer.
 *
 *  ... generate an interrupt when the alarm time has been reached.
 */

#include <stdio.h>
#include <conio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/arm7tdmi.h>
#include <target.h>

#define LED	0x10000				// LED =P0.16

/*
 * RTC interrupt service
 */
static void __attribute__((interrupt))		// handle as ISR!
rtc_isr(void)
{
	Intern_ilr = 2;				// clear int flag
	Intern_vicvectaddr = 0;			// reset VIC priority logic
	Intern_iodir |= LED;			// LED on
}

/*
 * The current date/alarm is displayed. If a new date/alarm is entered,
 * the current date/alarm is modified and then written back to the RTC.
 */
static void
new(int alarm)
{
	char line[30];				// input buffer
	time_t t = _gettime(alarm);		// current date/alarm

	printf("Current %s: %s"
	       "New %s (hh mm ss DD MM YYYY, no check!): ",
		alarm? "alarm": "date",
		ctime(&t),
		alarm? "alarm": "date"
	);
	if (*fgets(line, sizeof(line), stdin) != '\n') {
		struct tm *tp = localtime(&t);

		tp->tm_mon++;			// correct month
		tp->tm_year += 1900;		//         year
		sscanf(line, "%d%d%d%d%d%d",	// scan line
			&tp->tm_hour,
			&tp->tm_min,
			&tp->tm_sec,
			&tp->tm_mday,
			&tp->tm_mon,
			&tp->tm_year
		);
		tp->tm_mon--;			// tm_mon  : 0.. 11
		tp->tm_year -= 1900;		// tm_year : years since 1900
		_settime(mktime(tp), alarm);	// set new date/alarm
	}
}

/*
 * Date and alarm can be changed.
 *
 * When "Start" is selected, the remaining/passed seconds until/since
 * alarm are displayed. Any keypress returns to the menu.
 *
 * When the alarm time has been reached, an interrupt is produced and
 * the LED turned on.
 *
 * Note: Date and alarm are initially set to 00:00:00, Jan. 1, 1970.
 */
int
main(void)
{
	Intern_vicvectaddr0 = (long)rtc_isr;	// set ISR addr
	Intern_vicintenable = 0x2000;		// enable rtc int
	Intern_vicvectcntl0 = 0x2d;		//  vector
	Intern_ciir = 0;			// inc ints off
	Intern_amr  = 0;			// alarm int on

	_settime(0, 0);				// init date
	_settime(0, 1);				//      alarm

	while (1) {
		time_t last = 0;		// last date
		int c;

		Intern_iodir &= ~LED;		// LED off
		fputs("\n"
		      " (1) New date\n"
		      " (2) New alarm\n"
		      " (3) Start\n\n"
		      "Select... ", stdout
		);
		c = getchar();			// get selection
		puts("\n");
		switch (c) {
		case '1': // new date
		case '2': // new alarm
			new(c == '2');
			break;

		case '3': // start
			Intern_ilr = 3;		// clear pending ints
			ENABLE_INTERRUPTS;	// enable core ints
			while (!kbhit()) {
				time_t t = time(0);	// get date
				time_t a = _gettime(1);	//     alarm

				if (t != last) {	// date changed?
					last = t;
					if (t-a) printf("Alarm %+lds\n", t-a);
					else puts("\nA L A R M !!\7\n");
				}
			}
			DISABLE_INTERRUPTS;	// disable core ints
			getch();		// remove pending char
			break;
		}
	}
}
