/*
 * CoCo "flashy" clock example using Dunfield Micro-C
 *
 * Copyright 2013 by John W. Linville
 */

#include <6809io.h>
#include <cocoint.h>

#define SYNC()		asm " sync"

struct pia {
	struct {
		unsigned char data;
		unsigned char ctrl;
	} piaport[2];
};

struct pia *pia0 = 0xff00;

#define CURPOS		((unsigned int *)0x0088)
#define	TXTBASE		((char *)0x0400)
#define	TXTWIDTH	32
#define	TXTLINES	16
#define	TXTSIZE		((unsigned int)TXTWIDTH*TXTLINES)
#define	TXTEND		(TXTBASE+TXTSIZE)

void cls(unsigned char color)
{
	unsigned char *pos, val;

	if (color == 0)
		val = 0x80;
	else
		val = 0x8f | ((color - 1) << 4);

	for (pos = TXTBASE; pos < TXTEND; pos++)
		*pos = val;
}

void curpos(unsigned int val)
{
	if (val > TXTSIZE)
		abort("INVALID CURPOS!");

	*CURPOS = TXTBASE + val;
}

char hour, minute, second, ampm, tick;

void timeset(void) {
	char tmp;

	second = 0;

	putstr("CURRENT TIME\n\n");
	do {
		putstr("HOUR? ");
		tmp = getchr();
		putch(tmp);
		if ((tmp < '0') || (tmp > '2')) {
			hour = -1;
			putch('\n');
			continue;
		}
		hour = 10 * (tmp - '0');

		tmp = getchr();
		putch(tmp);
		putch('\n');
		if ((tmp < '0') || (tmp > '9')) {
			hour = -1;
			continue;
		}
		hour += (tmp - '0');
	} while ((hour < 1) || (hour > 23));

	do {
		putstr("MINUTE? ");
		tmp = getchr();
		putch(tmp);
		if ((tmp < '0') || (tmp > '5')) {
			minute = -1;
			putch('\n');
			continue;
		}
		minute = 10 * (tmp - '0');

		tmp = getchr();
		putch(tmp);
		putch('\n');
		if ((tmp < '0') || (tmp > '9')) {
			minute = -1;
			continue;
		}
		minute += (tmp - '0');
	} while (minute < 0);

	if (hour > 12) {
		ampm = 1;
		hour -= 12;
	} else do {
		putstr("AM/PM? ");
		tmp = getchr();
		putch(tmp);
		putch('\n');
		if (tmp == 'A')
			ampm = 0;
		else if (tmp == 'P')
			ampm = 1;
		else
			ampm = -1;
	} while (ampm < 0);
}

INTERRUPT(timer) {

	/* clear Vsync interrupt */
	pia0->piaport[1].data; /* dummy read */

	if (++tick < 60)
		return;
	tick = 0;

	if (++second < 60)
		return;
	second = 0;

	if (++minute < 60)
		return;
	minute = 0;

	if (++hour > 12)
		hour = 1;
	else if (hour == 12)
		ampm ^= 1;
}

void timestart(void) {

	disable();

	/* Enable Vsync interrupt */
	pia0->piaport[1].ctrl |= 0x05;
	pia0->piaport[1].data; /* dummy read */

	tick = 0;
	SETIRQ(timer);

	enable();
}

const char steps[] = {
	10,
	10,
	20,
	10,
	10
};

void main(void) {
	char *cursor;
	char color, curval, mode, step;
	char output[9];

	mode = step = color = 0;
	curval = 0x8f;

	timeset();

	cls(0);

	output[2] = output[5] = ':';
	output[8] = '\0';
	curpos(272);
	putch('M');

	cursor = TXTBASE + 16;

	timestart();

	SYNC();
	for (;;) {
		curpos(236);
		output[0] = '0' + (hour / 10);
		output[1] = '0' + (hour % 10);
		output[3] = '0' + (minute / 10);
		output[4] = '0' + (minute % 10);
		output[6] = '0' + (second / 10);
		output[7] = '0' + (second % 10);
		putstr(output);
		curpos(271);
		putch(ampm ? 'P' : 'A');

		switch(mode) {
		case 0:
			*cursor++ = curval;
			if (!(step & 1))
				*cursor++ = curval;
			break;
		case 1:
			*cursor = curval;
			cursor += 32;
			if (!(step & 1)) {
				*cursor = curval;
				cursor += 32;
			}
			break;
		case 2:
			*cursor-- = curval;
			if (step & 1)
				*cursor-- = curval;
			break;
		case 3:
			*cursor = curval;
			cursor -= 32;
			if (!(step & 1)) {
				*cursor = curval;
				cursor -= 32;
			}
			break;
		case 4:
			*cursor++ = curval;
			if (step & 1)
				*cursor++ = curval;
			break;
		default:
			/* should not happen! */
			abort("unknown mode");
		}

		if (++step == steps[mode]) {
			step = 0;
			if (++mode == sizeof(steps)) {
				mode = 0;
				color++;
				curval = 0x8f | ((color & 7) << 4);
			}
		}

		SYNC();
	}
}
