typedef unsigned char byte;
typedef unsigned short word;

volatile byte* doa=(byte*)0x1204; /* Data Out A register van de PSD */
volatile byte* dob=(byte*)0x1205; /* Data Out B register van de PSD */
volatile byte* da= (byte*)0x1206; /* Direction A register van de PSD */
volatile byte* db= (byte*)0x1207; /* Direction B register van de PSD */
volatile byte* porte=(byte*)0x100a; /* Port E van de 68HC11 */
volatile byte* tflg2=(byte*)0x1025; /* TFLG2 register van de 68HC11 */
	
/* Functies voor het inbraakalarm */

/* void wacht(word n)
 * 	Deze functie wacht n * 4.096 ms. 
 */
void wacht(word n) {
	word i;
	for (i=0; i<n+1; ++i) { /* wacht n+1 keer */
		while ((*tflg2&0x40)!=0x40) { /* wacht tot RTIF == 1 */
			/* niets */
		}
		*tflg2=0x40; /*maak RTIF 0 (door er een 1 naar toe te schrijven) */
	}
}

/* char scankey()
 * 	Deze functie geeft de op dit moment ingedrukte toets van het keyboard
 * 	in ASCII code terug. Als er geen toets is ingedrukt wordt het NUL karakter
 *	'\0' teruggegeven.
 */
char scankey() {
	static const char keys[]={'\0','1','2','3','4','5','6','7','8','9','*','0','#'};
	byte keyindex, teller;
	
	*doa=0x0f;
	wacht(1);
	keyindex = 0;
	if ((*porte&0xe0)!=0x00) {
		// key found start scan:
		*doa=0x01;
		wacht(1);
		for (teller=0; teller<4; ++teller) {
			if ((*porte&0xe0)!=0x00) {
				// key found
				if ((*porte&0x20)==0x20) keyindex+=1;
				else if ((*porte&0x40)==0x40) keyindex+=2;
				else if ((*porte&0x80)==0x80) keyindex+=3;
				break;
			}
			if (teller!=3) {
				*doa<<=1;
				wacht(1);
				keyindex+=3;
			}
			else 
				keyindex=0;
		}
	}
	*doa=0x00;
	return keys[keyindex];
}

#define VERBONDEN 0
#define VERBROKEN 1
/* byte scaninput(byte i)
 * 	Deze functie geeft de waarde terug van de digitale ingang i (i=0 t/m 3)
 * 	terug. Als de ingang hoog is (verbinding is verbroken) wordt een 1 teruggegeven
 *      en als de ingang laag is (verbinding is verbonden) wordt een 0 teruggegeven.
 *	Bij een ongeldige waarde van i wordt 0xff teruggegeven.
 */
byte scaninput(byte i) {	
	static const char mask[]={0x02,0x04,0x08,0x10};
	if (i>3)
		return 0xff;
	else
		return (*porte&mask[i])?VERBROKEN:VERBONDEN;
}

#define AAN 1
#define UIT 0
/* void buzzer(byte aanuit)
 * 	Deze functie zet de buzzer aan of uit. Als de parameter aanuit 0 is wordt de 
 *	buzzer uitgezet. Als de parameter aanuit ongelijk aan 0 is wordt de buzzer aangezet.
 *	Bij aanroep kun je voor de parameter aanuit de constante AAN of UIT gebruiken.
 */
void buzzer(byte aanuit) {
	if (aanuit)
		*dob&=~0x01; /* PPB0 laag = buzzer aan */
	else
		*dob|=0x01; /* PPB0 hoog = buzzer uit */
}

/* void relais(byte aanuit)
 * 	Deze functie zet het relais aan of uit. Als de parameter aanuit 0 is wordt het 
 *	relais uitgezet. Als de parameter aanuit ongelijk aan 0 is wordt het relais aangezet.
 *	Bij aanroep kun je voor de parameter aanuit de constante AAN of UIT gebruiken.
 */
void relais(byte aanuit) {
	if (aanuit)
		*dob&=~0x02; /* PPB1 laag = relais aan */
	else
		*dob|=0x02; /* PPB1 hoog = relais uit */
}

#define BOVEN 0
#define MIDDEN 1
#define ONDER 2
#define GROEN 1
#define ROOD 2
#define ORANJE 3
/* void led(byte i, byte k)
 * 	Deze functie zet ledje i op kleur k.
 *	Bij aanroep kun je voor de parameter i de constante BOVEN, MIDDEN of ONDER gebruiken.
 *	Bij aanroep kun je voor de parameter k de constante UIT, GROEN, ROOD of ORANJE gebruiken.
 */
void led(byte i, byte k) {
	static const char mask[]={0xc0,0x30,0x0c};
	static const char patern[]={0x00,0x80,0x40,0xc0,0x00,0x20,0x10,0x30,0x00,0x08,0x04,0x0c};
	byte b=*dob;
	if (i<=2 && k<=3) {
		b&=~mask[i];
		b|=mask[i]&~patern[i*4+k];
		*dob=b;
	}
}

int main() {
	char c;
	*db=0xff; /* PPB0 t/m PPB7 output */
	*da=0x0f; /* PPA0 t/m PPA4 output */
	*dob=0xff; /* PPB0 t/m PPB7 hoog (uit) */
	
	while (1) {
/*
	Schrijf hier je eigen inbraakalarm programma!
*/
		c=scankey();
		switch(c) {
			case '0': 	led(BOVEN, UIT);
					led(MIDDEN, UIT);
					led(ONDER, UIT);
					relais(UIT);
					buzzer(UIT);
					break;
			case '1': 	led(BOVEN, ROOD);
					break;
			case '2': 	led(BOVEN, ORANJE);
					break;
			case '3': 	led(BOVEN, GROEN);
					break;
			case '4': 	led(MIDDEN, ROOD);
					break;
			case '5': 	led(MIDDEN, ORANJE);
					break;
			case '6': 	led(MIDDEN, GROEN);
					break;
			case '7': 	led(ONDER, ROOD);
					break;
			case '8': 	led(ONDER, ORANJE);
					break;
			case '9': 	led(ONDER, GROEN);
					break;
			case '*': 	buzzer(AAN);
					break;
			case '#': 	relais(AAN);
					break;
		}
		if (scaninput(0)==VERBONDEN) {
			buzzer(AAN);
			wacht(122);
			buzzer(UIT);
			wacht(122);
		}
	}
	return 0;
}
