/*
 * Copyright(C) Paul und Scherer (mct.de/mct.net)
 *
 * This example demonstrates how to...
 *
 *  ... read and set the external RTC.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "../iic.h"

#define RTC	0x9e				// RTC IIC bus address

/*
 * Return binary of bcd
 */
static int
bcd2bin(int bcd)
{
	return (bcd>>4)*10+(bcd&0xf);
}

/*
 * Return binary coded decimal of bin
 */
static int
bin2bcd(int bin)
{
	return (bin/10<<4)|(bin%10);
}

/*
 * Read RTC to tp, compare with cp and return 0 if equal.
 */
static int
getrtc(struct tm *tp, struct tm *cp)
{
	unsigned char buf[7];			// clock buffer

	iic_start(RTC);				// write
	iic_write("\xc0\x00", 2);		//  access clock cmd, addr 0
	iic_start(RTC|1);			// read
	iic_read(buf, sizeof(buf));		//  counters

	tp->tm_sec  = bcd2bin(buf[0]);
	tp->tm_min  = bcd2bin(buf[1]);
	tp->tm_hour = bcd2bin(buf[2]);
	tp->tm_mday = bcd2bin(buf[4]);
	tp->tm_mon  = bcd2bin(buf[5]);
	tp->tm_year = bcd2bin(buf[6]);

	return tp->tm_sec  != cp->tm_sec
	    || tp->tm_min  != cp->tm_min
	    || tp->tm_hour != cp->tm_hour
	    || tp->tm_mday != cp->tm_mday
	    || tp->tm_mon  != cp->tm_mon
	    || tp->tm_year != cp->tm_year;
}

/*
 * Initialize IIC bus interface, and probe for RTC.
 */
static void
probe(void)
{
	static int done;			// skip if already done

	if (!done) {
		iic_init();
		if (iic_start(RTC)) puts("RTC not found!"), abort();
		done = 1;
	}
}

/*
 * Return date (the alarm flag is ignored!)
 * in seconds since 00:00:00, Jan. 1, 1970.
 */
time_t
_gettime(int alarm)
{
	struct tm tm1, tm2;

	probe();				// RTC functional?

	/*
	 * Read until two successive reads are equal.
	 */
	while (getrtc(&tm1, &tm2) && getrtc(&tm2, &tm1)) ;

	/*
	 *  tm_year  : 1970.. 2069  (year-1900)
	 *  tm_mon   :    0.. 11
	 *  tm_isdst : No daylight saving time
	 */
	if (tm1.tm_year < 70) tm1.tm_year += 100;
	tm1.tm_mon--;
	tm1.tm_isdst = 0;

	return mktime(&tm1);
}

/*
 * Set date (the alarm flag is ignored!) to t
 * (t = seconds since 00:00:00, Jan. 1, 1970).
 */
void
_settime(time_t t, int alarm)
{
	unsigned char buf[7];			// clock buffer
	struct tm *tp = localtime(&t);

	probe();				// RTC functional?

	buf[0] = bin2bcd(tp->tm_sec);		// set counters
	buf[1] = bin2bcd(tp->tm_min);
	buf[2] = bin2bcd(tp->tm_hour);
	buf[3] = bin2bcd(tp->tm_wday);
	buf[4] = bin2bcd(tp->tm_mday);
	buf[5] = bin2bcd(tp->tm_mon+1);
	buf[6] = bin2bcd(tp->tm_year < 100? tp->tm_year: tp->tm_year-100);

	iic_start(RTC);				// write
	iic_write("\xc0\x00", 2);		//  access clock cmd, addr 0
	iic_write(buf, sizeof(buf));		//  counters
}

/*
 * Here, the "regular" date program gets included for main().
 * It uses the functions time() and _settime() to read/write
 * the clock.
 *
 * But the system functions _gettime(), which gets called by
 * time(), and _settime() operate on the internal RTC. These
 * functions however are replaced by their above equivalents,
 * accessing the external RTC instead.
 *
 * Note: Reading from and writing to the RTC is done without
 * checking return values. Both functions probe once for the
 * RTC and if found, assume proper operation.
 *
 * If you use these functions in your own program, you could
 * extract the RTC probing (together with the initialisation
 * of the IIC bus interface) and perform this in your global
 * init section.
*/
#include "../date.c"

