#include <8051.h>
#include "paulmon2.h"

// variables that keep track of the time.  Note the "volatile" keyword
// should be used by all variables that are written by the interrupt
// service routines and may be read by the main program.
volatile unsigned char hours;
volatile unsigned char minutes;
volatile unsigned char seconds;
volatile bit time_changed_flag;

// function prototypes.  The interrupt service routine must be
// defined in the same file that includes the main() function
void timer0_isr(void) interrupt 1;
void print_time(void);
void print_2digit_uchar(unsigned char n);


void main()
{
	IE = 0;				// turn off all interrupts
	hours = minutes = seconds = 0;	// zero hours, minutes, seconds
	TR0 = 0;			// make sure timer 0 is stopped
	TF0 = 0;			// clear the overflow flag
	TMOD &= 0xF0;			// set to mode 0 (timer1 unchanged)
	TL0 = TH0 = 0;			// clear the timer 0 value
	pm2_pstr("\r\n\r\n\r\n");	
	pm2_pstr("Timekeeping Example (Interrupts)\r\n");
	pm2_pstr("Press ESC to stop...\r\n\r\n");
	time_changed_flag = 0;
	TR0 = 1;			// start the timing
	IP = 0;				// set interrupt priorities (all low)
	IE = 0x82;			// enable timer0 interrupt
	print_time();
	while (1) {
		if (pm2_esc()) {
			pm2_pstr("\r\n\r\nStopped.  Press a key to reboot");
			pm2_restart();
		}
		if (time_changed_flag) {
			time_changed_flag = 0;
			print_time();
		}
	}
}

/* this interrupt service routine will run every time timer0 sets
 * the TF0 flag.  The 8051 hardware automatically clears TF0 for
 * us.  The special syntax "interrupt 1" causes SDCC to make this
 * function the interrupt service routine for timer 0.  See the
 * SDCC manual for other interrupt numbers, and optional register
 * bank options.  Special care is needed if this routine calls any
 * other functions or uses 16 or 32 mulitplication or division or
 * any floating point math.  Usually, it is best to avoid these
 * inside interrupt service routines, and avoid calling any other
 * functions if possible.
 */
#pragma SAVE
#pragma NOOVERLAY   // disable overlaying local vars w/ other functions
void timer0_isr(void) interrupt 1
{
	static unsigned char ov_countdown=225;

	if (--ov_countdown == 0) {
		ov_countdown = 225;
		if (++seconds == 60) {
			seconds = 0;
			if (++minutes == 60) {
				minutes = 0;
				if (++hours == 24) {
					hours = 0;
				}
			}

		}
		time_changed_flag = 1;
	}
}
#pragma RESTORE


/* Print the time.  The time is read quickly with the interrupt
 * disabled, to avoid any chance that the interrupt routine could
 * change the bytes while they're being read.
 */
void print_time(void)
{
	unsigned char m_hours, m_minutes, m_seconds;

	ET0 = 0;		// temporarily disable interrupt
	m_hours = hours;
	m_minutes = minutes;
	m_seconds = seconds;
	ET0 = 1;		// reenable interrupt ASAP
	print_2digit_uchar(m_hours);
	pm2_cout(':');
	print_2digit_uchar(m_minutes);
	pm2_cout(':');
	print_2digit_uchar(m_seconds);
	pm2_newline();
}

/* print a number as two digits with leading zero
 */
void print_2digit_uchar(unsigned char n)
{
	pm2_cout((n / 10) + '0');
	pm2_cout((n % 10) + '0');
}




