From 4843275e27ddc0acc836c2747ecc371b0f61b152 Mon Sep 17 00:00:00 2001
From: b <rowerynaksiezycu@gmail.com>
Date: Sun, 3 May 2020 15:47:23 +0200
Subject: [PATCH] total rework, serial communication

---
 definitions.h |   68 +-
 main.c        | 2194 +++++++++++++++++++++++++++++--------------------
 2 files changed, 1333 insertions(+), 929 deletions(-)

diff --git a/definitions.h b/definitions.h
index aee5ebc..804f506 100644
--- a/definitions.h
+++ b/definitions.h
@@ -2,8 +2,8 @@
 // definitions.h
 // Definitions used by the code.
 // 
-// 17.07.2017
-// Copyright (C) 2014-2017  Balthasar Szczepański
+// 03.05.2020
+// Copyright (C) 2014-2017, 2020  Balthasar Szczepański
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -92,30 +92,52 @@
 #define SYMB_DOT (SEG_H)
 
 //operation modes
-#define MODE_INIT         0
-#define MODE_TIME         1
-#define MODE_SETTIME      2
-#define MODE_SETALARM     3
-#define MODE_ALARM        4
-#define MODE_DATE         5
-#define MODE_SETDATE      6
-#define MODE_SETYEAR      7
-#define MODE_COUNTUP      8
-#define MODE_SETCOUNTDOWN 9
-#define MODE_COUNTDOWN   10
-
-#define MODE_CALIBRATE   11
-#define MODE_DEBUG       12
-#define MODE_DEBUGADDR   13
-#define MODE_DEBUGVAL    14
-#define MODE_RESET       15
-
-#define MODE_CALC        16
-#define MODE_CALCSETNUM  17
-#define MODE_CALCSETOPER 18
+#define MODE_EDIT 0x80
+
+
+#define MODE_TIME  0x00
+#define MODE_ALARM 0x01
+#define MODE_DATE  0x02
+#define MODE_UP    0x03
+#define MODE_DOWN  0x04
+#define MODE_CALIB 0x05
+
+#define MODE_VER   0x06
+#define MODE_DEBUG 0x07
+#define MODE_RESET 0x08
+
+#define MODE_CALC  0x09
+
+
+#define MODE_SETTIME  0x00
+#define MODE_SETALARM 0x01
+#define MODE_SETDATE  0x02
+#define MODE_SETYEAR  0x03
+#define MODE_SETDOWN  0x04
+#define MODE_SETCALIB 0x05
+
+#define MODE_SETDEBUGADDR 0x06
+#define MODE_SETDEBUGVAL  0x07
+
+#define MODE_SETCALCNUM  0x08
+#define MODE_SETCALCOPER 0x09
+
+
+//event flags
+#define EVENT_RTC 0x01
+#define EVENT_A   0x02
+#define EVENT_B   0x04
+#define EVENT_C   0x08
+#define EVENT_RS  0x10
+
+#define EVENTS    0x1f
 
 #define ALARMVALUE 0xa5
 
+#define RXBUFSIZE 11
+#define RXDATASIZE 5
+
+
 unsigned char bcd_add_byte (unsigned char, unsigned char);
 void          lpm3         ();
 void          calc_add     (unsigned char *);
diff --git a/main.c b/main.c
index aead80a..994cfda 100644
--- a/main.c
+++ b/main.c
@@ -2,8 +2,8 @@
 // main.c
 // The main c file.
 // 
-// 17.07.2017
-// Copyright (C) 2014-2017  Balthasar Szczepański
+// 03.05.2020
+// Copyright (C) 2014-2017, 2020  Balthasar Szczepański
 // 
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -23,19 +23,37 @@
 	#include "msp430.h"
 	#include "definitions.h"
 
-	         unsigned char inbuf[8];
-	         unsigned char outbuf[8] __attribute__ ((aligned (2))); 
-	         unsigned char dispvalue[4];
-	         volatile unsigned char time[8];
-	         unsigned char leap;
-	         unsigned char settime[3];
-	volatile unsigned char mode;
+	         unsigned char calcdata[8] __attribute__ ((aligned (2))); //data for calculator operation
+	         unsigned char inbuf[8]; //SPI input buffer
+	         unsigned char outbuf[8]; //SPI output buffer
+	         unsigned char dispvalue[10]; //data to display
+	         unsigned char forcedisp[5]={0,0,0,0,0}; //forcing the display
+	         unsigned char time[8];
+	         unsigned char leap; //leap year
+	         unsigned char step; //constant count 0 1 2 3 0 1 2 3 ...
+	         unsigned char settime[3]; //for editing values
+	         unsigned char limit[3]; //limits for editing
+	         unsigned char decimal; //if edited value is BCD
+	volatile unsigned char mode; //main state
 	         unsigned char alarm[3];
-	         unsigned char lastcdn[2];
+	         unsigned char lastcdn[2]; //last countdown
 	         unsigned char lastyear[5];
-	         unsigned char digit;
-	         unsigned char changed;
-	         unsigned char run;
+	         unsigned char digit; //currently selected digit
+	         unsigned char changed; //changed value during edit
+	         unsigned char run; //switch used in some states
+	         unsigned char cont; //continued calculation
+	
+	//for RS232 receiving
+	volatile unsigned char rxbyte=0;
+	volatile unsigned char rxcount=0;
+	volatile unsigned char rxind=0;
+	volatile unsigned char rxpin;
+	volatile unsigned char rxbuf[RXBUFSIZE];
+	         unsigned char rxdata[RXDATASIZE];
+	         unsigned char rxcmd;
+	
+	volatile unsigned char event=0;
+	
 	const    unsigned char symbol[16] ={
 		SYMB_0,
 		SYMB_1,
@@ -55,6 +73,14 @@
 		SYMB_F};
 
 	__interrupt void P2_ISR();
+	__interrupt void TA0_ISR();
+	
+	void gettime(void);
+	void exec(void);
+	void enter(void);
+	void leave(void);
+	void showvalue(void);
+	
 	void display(
 		unsigned char *data);
 	void spi(
@@ -63,6 +89,7 @@
 		unsigned char *inbuf,
 		unsigned char *outbuf,
 		unsigned short n);
+	
 	int main( void );
 
 	void display(unsigned char *data)
@@ -175,990 +202,1345 @@
 		for(i=0;i<255;++i); //looks like the RTC might not like another SPI transmission exactly before the previous one, sometimes.
 	}
 
-	#pragma vector=PORT2_VECTOR
-	__interrupt void P2_ISR()
+	// interrupt for timer A
+	// timing for RS232 sampling
+	#pragma vector=TIMERA0_VECTOR
+	__interrupt void TA0_ISR()
 	{
-		if(P2IFG&0x08) // RTC
-		{
-			P2IFG &= ~0x08;
-			spi(RTC_READ,0x00,inbuf,outbuf,8);
+		rxpin = P2IN & 0x10; //quickly capture state of P2.4
 		
-			time[0]=inbuf[0]; //1/100 s
-			time[1]=inbuf[1]&0x7f; //seconds
-			time[2]=inbuf[2]&0x7f; //minutes
-			time[3]=inbuf[3]&0x3f; //hours
-			time[4]=inbuf[4]&0x07; //dow
-			time[5]=inbuf[5]&0x3f; //dom
-			time[6]=inbuf[6]&0x1f; //mon
-			time[7]=inbuf[7];//year
-			leap=inbuf[6]&0x20;
-			
-			spi(RTC_READ,0x0f,inbuf,outbuf,1); // <- because of RTC bug (probably not needed anymore?)
-			if(!((time[2]^alarm[1])|(time[3]^alarm[2])) && alarm[0])
-			{
-				mode=MODE_ALARM;
-				alarm[0]=0; //alarm removed after activated
-				spi(RTC_WRITE,0x20,inbuf,alarm,1);
-			}
-			
-			if(mode==MODE_COUNTUP && run)
+		TACCTL0 &= ~CCIFG;
+		
+		++rxcount;
+		
+		if (!(rxcount & 0x01)) //only every second count
+		{
+			if (rxcount == 2) //start bit
 			{
-				if(settime[1]<0x59)
-					settime[1]=bcd_add_byte(settime[1],0x01);
-				else
+				if (rxpin) //start fail
 				{
-					settime[1]=0x00;
-					settime[2]=bcd_add_byte(settime[2],0x01);
+					rxcount = 0;
+					TACCTL0 &= ~CCIE; //abort
 				}
 			}
-			else if(mode==MODE_COUNTDOWN && run && (settime[1]|settime[2]))
+			else if (rxcount >= 20) //stop bit
 			{
-				if(settime[1])
-					settime[1]=bcd_add_byte(settime[1],0x99);
-				else
+				if (rxpin) //correct stop bit
 				{
-					settime[1]=0x59;
-					settime[2]=bcd_add_byte(settime[2],0x99);
+					if (rxbyte == 0x0d || rxbyte == 0x0a) // CR or NL, end of frame
+					{
+						if(rxind)
+						{
+							rxind = 0;
+							event |= EVENT_RS; //signal 
+						}
+					}
+					else
+					{
+						if (rxbyte >= 'g' && rxbyte <= 'z') //new command
+						{
+							rxind=0;
+						}
+						if (rxind < RXBUFSIZE) //still place in buffer
+						{
+							rxbuf[rxind] = rxbyte; //put byte to buffer
+							++rxind;
+						}
+					}
 				}
+				rxcount = 0;
+				TACCTL0 &= ~CCIE; //stop receiving
 			}
-			
-			if (mode==MODE_ALARM || (mode==MODE_COUNTDOWN && !(settime[1]|settime[2])))
-			{
-				TACTL^=MC_1;
-				//P2DIR^=0x40;
-				//P2SEL^=0x40;
-			}
-			else if(TACTL & MC_3)
+			else //receive single bit
 			{
-				TACTL&= ~MC_3;
-				//P2DIR&= ~0x40;
-				//P2SEL&= ~0x40;
+				rxbyte >>= 1;
+				rxbyte |= rxpin ? 0x80 : 0x00;
 			}
+		}
+		if(event)
+			_BIC_SR_IRQ(OSCOFF|CPUOFF|SCG1|SCG0);
+		return;
+	}
+	
+	#pragma vector=PORT2_VECTOR
+	__interrupt void P2_ISR()
+	{
+		if(P2IFG&0x08) // RTC
+		{
+			P2IFG &= ~0x08;
+			event |= EVENT_RTC;
+		}
+		else if(P2IFG&0x02) // button A
+		{
+			P2IFG &= ~0x02;
+			event |= EVENT_A;
+		}
+		else if(P2IFG&0x01) // button B
+		{
+			P2IFG &= ~0x01;
+			event |= EVENT_B;
+		}
+		else if(P2IFG&0x20) // button C
+		{
+			P2IFG &= ~0x20;
+			event |= EVENT_C;
+		}
+		else if(P2IFG&0x10) // RS232
+		{
+			P2IFG &= ~0x10;
 			
-			lastyear[4]=(time[7]==0x00 && lastyear[0]==0x99)?bcd_add_byte(lastyear[1],0x01):lastyear[1];
-			if (time[7]!=lastyear[0])
+			if(!rxcount) //start bit detected
 			{
-				if(time[7]==lastyear[2])
-					++(lastyear[3]);
-				else
-					lastyear[3]=0;
-				
-				lastyear[2]=time[7];
+				TACTL |= TACLR; //reset timer
+				TACCTL0 &= ~CCIFG; //clear any waiting timer interrupt
+				TACCTL0 |= CCIE; //enable timer interrupts
 				
-				if(lastyear[3]>55)
-				{
-					lastyear[3]=0;
-					
-					if(time[7]==0x00 && lastyear[0]==0x99)
-						lastyear[1]=bcd_add_byte(lastyear[1],0x01);
-					
-					lastyear[0]=time[7];
-					
-					outbuf[0]=ALARMVALUE;
-					outbuf[1]=lastyear[0];
-					outbuf[2]=lastyear[1];
-					spi(RTC_WRITE,0x26,inbuf,outbuf,3);
-				}      
+				rxcount = 1;
+				rxbyte = 0;
 			}
+		}
+		else
+			P2IFG=0;
+		
+		if(event)
+			_BIC_SR_IRQ(OSCOFF|CPUOFF|SCG1|SCG0); //escaoe low power mode
+		return;
+	}
+
+void gettime(void)
+{
+	P2IFG &= ~0x08;
+	
+	//get latest time from RTC
+	spi(RTC_READ,0x00,inbuf,outbuf,8);
+	
+	time[0]=inbuf[0]; //1/100 s
+	time[1]=inbuf[1]&0x7f; //seconds
+	time[2]=inbuf[2]&0x7f; //minutes
+	time[3]=inbuf[3]&0x3f; //hours
+	time[4]=inbuf[4]&0x07; //dow
+	time[5]=inbuf[5]&0x3f; //dom
+	time[6]=inbuf[6]&0x1f; //mon
+	time[7]=inbuf[7];//year
+	leap=inbuf[6]&0x20;
+	
+	step = (time[1]&0x03)^((time[1]&0x10)?0x02:0x00);
+	
+	
+	spi(RTC_READ,0x0f,inbuf,outbuf,1); // <- because of RTC bug (probably not needed anymore?)
+	
+	//check if trigger alarm
+	if(!((time[2]^alarm[1])|(time[3]^alarm[2])) && alarm[0])
+	{
+		mode=MODE_ALARM;
+		alarm[0]=0; //alarm removed after activated
+		spi(RTC_WRITE,0x20,inbuf,alarm,1);
+	}
+	
+	
+	//code to deal with centuries, functionality missing from RTC
+	//has to avoid accidentally reacting in case of transmission error
+	
+	lastyear[4]=(time[7]==0x00 && lastyear[0]==0x99)?bcd_add_byte(lastyear[1],0x01):lastyear[1];
+	if (time[7]!=lastyear[0])
+	{
+		if(time[7]==lastyear[2])
+			++(lastyear[3]);
+		else
+			lastyear[3]=0;
+		
+		lastyear[2]=time[7];
+		
+		if(lastyear[3]>55)
+		{
+			lastyear[3]=0;
 			
+			if(time[7]==0x00 && lastyear[0]==0x99)
+				lastyear[1]=bcd_add_byte(lastyear[1],0x01);
 			
-			if(mode==MODE_DEBUG && changed)
-				spi(RTC_READ,settime[1],settime,outbuf,1);
+			lastyear[0]=time[7];
 			
-			if(mode==MODE_RESET && P2IN&0x02 && P2IN&0x01 && P2IN&0x20) {
-				WDTCTL = ALARMVALUE;
-			}
-		}
-		else if(P2IFG&0x02) // button A
+			outbuf[0]=ALARMVALUE;
+			outbuf[1]=lastyear[0];
+			outbuf[2]=lastyear[1];
+			spi(RTC_WRITE,0x26,inbuf,outbuf,3);
+		}      
+	}
+	
+}
+
+void leave (void) //to execute when leaving an edit state
+{
+	switch (mode)
+	{
+	case MODE_EDIT | MODE_SETCALCOPER:
+		calcdata[6] &= ~0xc0;
+		calcdata[6] |= settime[0]<<6;
+		mode=MODE_EDIT | MODE_SETCALCNUM;
+		break;
+	case MODE_EDIT | MODE_SETCALCNUM:
+		if (run)
 		{
-			P2IFG &= ~0x02;
-			switch(mode)
+			if(cont != 0xff) //skip if triggered externally
 			{
-			case MODE_CALCSETNUM:
-			case MODE_CALCSETOPER:
-				mode=MODE_CALC;
-				break;
-			case MODE_CALC:
-				if(outbuf[7] || outbuf[1]!=0 || outbuf[0]!=0)
+				calcdata[2]=settime[0];
+				calcdata[3]=settime[1];
+				if ((settime[1] & 0xF0)==0xA0) //minus sign encoded as 0xA
 				{
-					outbuf[7]=0x00;
-					outbuf[6]=0x00;
-					outbuf[3]=0x00;
-					outbuf[2]=0x00;
-					outbuf[1]=0x00;
-					outbuf[0]=0x00;
+					calcdata[6] |= 0x04;
+					calcdata[3] &= 0x0f;
 				}
-				else
-					mode=MODE_TIME;
-				break;
-			case MODE_TIME:
-			case MODE_SETDATE:
-			case MODE_SETYEAR:
-				mode=MODE_DATE;
-				break;
-			case MODE_DATE:
-				mode=MODE_COUNTUP;
-				settime[1]=0x00;
-				settime[2]=0x00;
-				run=0;
+				if (settime[2]) //decimal point
+					calcdata[6] |= 0x08;
+			}
+			switch(calcdata[6]&0xc0)
+			{
+			case 0xc0:
+				calc_div(calcdata);
 				break;
-			case MODE_COUNTUP:
-				if(run)
-				{
-					settime[1]=0x00;
-					settime[2]=0x00;
-					run=0;
-				}
-				else
-				{
-					mode=MODE_SETCOUNTDOWN;
-					settime[1]=lastcdn[0];
-					settime[2]=lastcdn[1];
-					changed=0;
-					digit=3;
-				}
+			case 0x80:
+				calc_mul(calcdata);
 				break;
-			case MODE_DEBUGADDR:
-				settime[1]=settime[2];
-			case MODE_DEBUGVAL:
-				spi(RTC_READ,settime[1],settime,outbuf,1);
-				mode=MODE_DEBUG;
+			case 0x40:
+				calcdata[6]^=0x04;
+				calc_add(calcdata);
+				calcdata[6]^=0x04;
 				break;
-			case MODE_DEBUG:
-			case MODE_RESET:
-				mode=MODE_RESET;
+			case 0x00:
+				calc_add(calcdata);
 				break;
-			case MODE_SETCOUNTDOWN:
-			case MODE_COUNTDOWN:
-				if(changed || mode==MODE_COUNTDOWN)
-				{
-					mode=MODE_SETCOUNTDOWN;
-					settime[1]=lastcdn[0];
-					settime[2]=lastcdn[1];
-					changed=0;
-					digit=3;
-					break;
-				}
 			default:
-				mode=MODE_TIME;
-				break;
+				calcdata[7]=0xff;
 			}
+			mode=MODE_CALC;
 		}
-		else if(P2IFG&0x01) // button B
+		else
 		{
-			P2IFG &= ~0x01;
+			calcdata[4]=settime[0];
+			calcdata[5]=settime[1];
+			calcdata[6] &= ~0x30;
+			if ((settime[1] & 0xF0)==0xA0) //minus sign encoded as 0xA
+			{
+				calcdata[6] |= 0x10;
+				calcdata[5] &= 0x0f;
+			}
+			if (settime[2]) //decimal point
+				calcdata[6] |= 0x20;
+			mode=MODE_EDIT | MODE_SETCALCOPER;
+		}
+		break;
+	case MODE_EDIT | MODE_SETDEBUGVAL:
+		spi(RTC_WRITE,settime[1],inbuf,settime,1);
+		mode=MODE_DEBUG;
+		break;
+	case MODE_EDIT | MODE_SETDEBUGADDR:
+		settime[1]=settime[0];
+		run=1;
+		mode=MODE_DEBUG;
+		break;
+	case MODE_EDIT | MODE_SETCALIB:
+		spi(RTC_WRITE,0x09,inbuf,settime,1);
+		outbuf[0]=time[3]|(settime[1]?0x80:0x00);
+		spi(RTC_WRITE,0x03,inbuf,outbuf,1);
+		mode=MODE_CALIB;
+		break;
+	case MODE_EDIT | MODE_SETDOWN:
+		lastcdn[0]=settime[0];
+		lastcdn[1]=settime[1];
+		
+		outbuf[0]=ALARMVALUE;
+		outbuf[1]=settime[0];
+		outbuf[2]=settime[1];
+		spi(RTC_WRITE,0x23,inbuf,outbuf,3);
+		
+		mode=MODE_DOWN;
+		break;
+	case MODE_EDIT | MODE_SETYEAR:
+		if(changed)
+		{
+			time[7]=settime[0];
+			spi(RTC_WRITE,0x07,inbuf,settime,1);
+			
+			lastyear[0]=settime[0];
+			lastyear[1]=settime[1];
+			lastyear[2]=settime[1];
+			lastyear[3]=0;
+			lastyear[4]=settime[1];
+			
+			outbuf[0]=ALARMVALUE;
+			outbuf[1]=settime[0];
+			outbuf[2]=settime[1];
+			spi(RTC_WRITE,0x26,inbuf,outbuf,3);
+		}
+		mode=MODE_DATE;
+		break;
+	case MODE_EDIT | MODE_SETDATE:
+		if (changed)
+		{
+			time[5]=settime[0]; //day
+			time[6]=settime[1]; //month
+			settime[2]=time[7]; //year
+			spi(RTC_WRITE,0x06,inbuf,settime+1,2); //write month and year first
+			spi(RTC_WRITE,0x05,inbuf,settime,1);  //and only then the day
+			                                     //otherwise rtc can reject the date
+		}
+		mode=MODE_DATE;
+		break;
+	case MODE_EDIT | MODE_SETALARM:
+		if(changed|| !alarm[0])
+		{
+			alarm[0]=ALARMVALUE;
+			alarm[1]=settime[0];
+			alarm[2]=settime[1];
+			
+			spi(RTC_WRITE,0x20,inbuf,alarm,3);
+		}
+		else
+		{
+			alarm[0]=0;
+			spi(RTC_WRITE,0x20,inbuf,outbuf,1);
+		}
+		mode=MODE_TIME;
+		break;
+	case MODE_EDIT | MODE_SETTIME:
+		if (changed)
+		{
+			outbuf[0]=0x00;
+			outbuf[1]=0x00;
+			outbuf[2]=settime[0]&0x7f;
+			outbuf[3]=settime[1]&0x3f;
+			
+			spi(RTC_WRITE,0x01,inbuf,outbuf,1);//stop osc.
+			spi(RTC_READ,0x03,inbuf,outbuf,1);
+			outbuf[3]|=(inbuf[0]&0x80);//keep the calsgn bit.
+		
+			spi(RTC_WRITE,0x00,inbuf,outbuf,4);//write new time
+		
+			outbuf[0]=0x80;
+			spi(RTC_WRITE,0x01,inbuf,outbuf,1);//start osc;
 			
-			switch(mode)
+			time[1]=0;
+			time[2]=settime[0];
+			time[3]=settime[1];
+		}
+		mode = MODE_TIME;
+		break;
+	}
+}
+
+void enter (void) //to execute when entering a state
+{
+	if (mode & MODE_EDIT)
+	{
+		digit = 3;
+		changed = 0;
+		limit[0]=0x59;
+		limit[1]=0x23;
+		decimal = 1;
+		switch (mode)
+		{
+		case MODE_EDIT | MODE_SETCALCOPER:
+			digit=0;
+			limit[0]=0x03;
+			settime[0] = cont ? (calcdata[6]>>6) : 0x00;
+			run = 1;
+			break;
+		case MODE_EDIT | MODE_SETCALCNUM:
+			digit=4;
+			limit[0]=0x99;
+			limit[1]=0xA9;
+			limit[2]=0x01;
+			if (run && cont)
 			{
-			case MODE_CALCSETOPER:
-				outbuf[6]&=0x3f;
-				outbuf[6]|=settime[2];
-				mode=MODE_CALCSETNUM;
-				digit=4;
-				if(changed)
-				{
-					settime[0]=outbuf[2];
-					settime[1]=outbuf[3];
-					settime[2]=(outbuf[6]&0x0c)>>2;
-				}
-				else
-				{
-					settime[0]=0x00;
-					settime[1]=0x00;
-					settime[2]=0x00;
-				}
-				changed=1;
-				break;
-			case MODE_CALCSETNUM:
-				if(digit)
-					--digit;
-				else
+				settime[0] = calcdata[2];
+				settime[1] = calcdata[3];
+				settime[2] = (calcdata[6]>>2)&0x03;
+			}
+			else
+			{
+				settime[0] = 0x00;
+				settime[1] = 0x00;
+				settime[2] = 0x00;
+			}
+			break;
+		case MODE_EDIT | MODE_SETDEBUGADDR:
+			if(run)
+			{
+				settime[2] = settime[0];
+				settime[0] = settime[1]; 
+			}
+			else
+			{
+				settime[0] = 0x00;
+				settime[2] = 0x00;
+			}
+		case MODE_EDIT | MODE_SETDEBUGVAL:
+			digit=1;
+			limit[0]=0xff;
+			decimal=0;
+			break;
+		case MODE_EDIT | MODE_SETYEAR:
+			limit[0]=0x99;
+			limit[1]=0x99;
+			settime[0] = time[7]; //year L
+			settime[1] = lastyear[4]; //year H
+			break;
+		case MODE_EDIT | MODE_SETDATE:
+			digit = 2;
+			// limit[0]=0x31;
+			// limit[1]=0x12; not needed will be dynamically done later
+			settime[0] = time[5]; //day
+			settime[1] = time[6]; //month
+			break;
+		case MODE_EDIT | MODE_SETCALIB:
+			limit[0]=0xff;
+			limit[1]=0x01;
+			decimal=0;
+			digit=2;
+			spi(RTC_READ,0x03,inbuf,outbuf,1);
+			settime[1]=(inbuf[0]&0x80)?0x01:0x00;
+			spi(RTC_READ,0x09,inbuf,outbuf,1);
+			settime[0]=inbuf[0];
+			break;
+		case MODE_EDIT | MODE_SETDOWN:
+			limit[1] = 0x99;
+			settime[0] = lastcdn[0];
+			settime[1] = lastcdn[1];
+			break;
+		case MODE_EDIT | MODE_SETALARM:
+			settime[0] = (alarm[1]>0x59 || (settime[1]&0x0f)>0x09) ? 0x00 : alarm[1];
+			settime[1] = (alarm[2]>0x59 || (settime[2]&0x0f)>0x09) ? 0x00 : alarm[2];
+			break;
+		case MODE_EDIT | MODE_SETTIME:
+			settime[0] = time[2]; //minute
+			settime[1] = time[3]; //hour
+			break;
+		}
+	}
+	else
+	{
+		switch(mode)
+		{
+		case MODE_CALC:
+			run=0;
+			break;
+		case MODE_DEBUG:
+			event |= EVENT_RTC;
+			break;
+		case MODE_VER:
+			run=0;
+			break;
+		case MODE_CALIB:
+			spi(RTC_READ,0x03,inbuf,outbuf,1);
+			settime[1]=(inbuf[0]&0x80)?0x01:0x00;
+			spi(RTC_READ,0x09,inbuf,outbuf,1);
+			settime[0]=inbuf[0];
+			break;
+		case MODE_DOWN:
+			run=0;
+			settime[0] = lastcdn[0];
+			settime[1] = lastcdn[1];
+			break;
+		case MODE_UP:
+			run=0;
+			settime[0] = 0;
+			settime[1] = 0;
+			break;
+		// default:
+		}
+	}
+}
+
+void exec (void) //execute every second
+{
+	switch(mode)
+	{
+	case MODE_RESET:
+		if(P2IN&0x02 && P2IN&0x01 && P2IN&0x20) //perform a reset when no button pressed
+			WDTCTL = ALARMVALUE;
+		break;
+	case MODE_DEBUG:
+		spi(RTC_READ,settime[1],settime,outbuf,1);
+		event |= EVENT_RTC;
+		break;
+	case MODE_DOWN:
+		if(run && (settime[1] | settime[0]))
+		{
+			if(settime[0])
+				settime[0]=bcd_add_byte(settime[0],0x99);
+			else
+			{
+				settime[0]=0x59;
+				settime[1]=bcd_add_byte(settime[1],0x99);
+			}
+		}
+		else
+			run=0;
+		break;
+	case MODE_UP:
+		if(run)
+		{
+			if(settime[0]<0x59)
+				settime[0]=bcd_add_byte(settime[0],0x01);
+			else
+			{
+				settime[0]=0x00;
+				settime[1]=bcd_add_byte(settime[1],0x01);
+			}
+		}
+		break;
+	// default:
+	}
+}
+
+void showvalue () //determine what to show on display
+{
+	unsigned char dot=0;
+	unsigned char zero=0;
+	unsigned char i;
+	
+	dispvalue[4]=0;
+	dispvalue[5]=0;
+	dispvalue[6]=0;
+	dispvalue[7]=0;
+		
+	if (mode == (MODE_EDIT | MODE_SETCALCOPER))
+	{
+		switch (settime[0])
+		{
+		case 3:
+			dispvalue[4] = SYMB_U;
+			dispvalue[5] = SYMB_I;
+			dispvalue[6] = SYMB_D;
+			dispvalue[7] = SYMB_NUL;
+			break;
+		case 2:
+			dispvalue[4] = SYMB_L;
+			dispvalue[5] = SYMB_U;
+			dispvalue[6] = SYMB_M2;
+			dispvalue[7] = SYMB_M1;
+			break;
+		case 1:
+			dispvalue[4] = SYMB_B;
+			dispvalue[5] = SYMB_U;
+			dispvalue[6] = SYMB_5;
+			dispvalue[7] = SYMB_NUL;
+			break;
+		case 0:
+			dispvalue[4] = SYMB_D;
+			dispvalue[5] = SYMB_D;
+			dispvalue[6] = SYMB_A;
+			dispvalue[7] = SYMB_NUL;
+			break;
+		}
+	}
+	else if (mode & MODE_EDIT)
+	{
+		dispvalue[8] = settime[0];
+		dispvalue[9] = settime[1];
+		
+		switch (mode)
+		{
+		case MODE_EDIT | MODE_SETCALCNUM:
+			if ((settime[1]&0xF0) == 0xA0) //minus sign
+				dispvalue[7] = SYMB_MIN;
+			if (settime[2]) //decimal point
+				dot |= 0x02;
+			break;
+		case MODE_EDIT | MODE_SETDEBUGADDR:
+			dispvalue[6] = SYMB_A;
+		case MODE_EDIT | MODE_SETDEBUGVAL:
+			dispvalue[9]=0x00;
+			zero=2;
+			dot |= 0x03; //:
+			break;
+		case MODE_EDIT | MODE_CALIB:
+			if	(settime[1] && (!(step&0x01) || digit==2))
+				dispvalue[6] = SYMB_MIN;
+			zero=2;
+			break;
+		case MODE_EDIT | MODE_SETDOWN:
+			dot |= ((step & 0x02)?0x00:002) | ((step==0 || step==3)?0x01:00);
+			break;
+		case MODE_EDIT | MODE_SETDATE:
+			dispvalue[8] = settime[1];
+			dispvalue[9] = settime[0];
+			dot |= 0x02;
+			break;
+		case MODE_EDIT | MODE_SETALARM:
+			if(!(step & 0x01))
+				dot |= 0x08;
+		case MODE_EDIT | MODE_SETTIME:
+			dot |= 0x03;
+			break;
+		}
+		
+		
+		if (step&0x01)
+		{
+			for(i=0; i<4; ++i)
+			{
+				if (i != digit)
 				{
-					if(changed)
+					if(mode== (MODE_EDIT | MODE_SETDATE))
 					{
-						outbuf[6]&=0xf3;
-						outbuf[6]|=settime[2]<<2;
-						outbuf[3]=settime[1];
-						outbuf[2]=settime[0];
-						
-						
-						switch(outbuf[6]&0xc0)
+						switch(i)
 						{
-						case 0xc0:
-							calc_div(outbuf);
-							break;
-						case 0x80:
-							calc_mul(outbuf);
+						case 2:
+							dispvalue[4] = SYMB_NUL;
+							dispvalue[5] = SYMB_NUL;
 							break;
-						case 0x40:
-							outbuf[6]^=0x04;
-							calc_add(outbuf);
-							outbuf[6]^=0x04;
+						case 1:
+						case 0:
+							dispvalue[6+i] = SYMB_NUL;
 							break;
-						case 0x00:
-							calc_add(outbuf);
-							break;
-						default:
-							outbuf[7]=0xff;
 						}
-						mode=MODE_CALC;
 					}
 					else
-					{
-						outbuf[6]&=0xcf;
-						outbuf[6]|=settime[2]<<4;
-						outbuf[5]=settime[1];
-						outbuf[4]=settime[0];
-						mode=MODE_CALCSETOPER;
-						settime[2]=0x00;
-					}
-				}
-				break;
-			case MODE_CALC:
-				if(outbuf[7])
-				{
-					outbuf[0]=0x00;
-					outbuf[1]=0x00;
-					outbuf[2]=0x00;
-					outbuf[3]=0x00;
-					outbuf[6]=0x00;
-					outbuf[7]=0x00;
-				}
-				else
-				{
-					outbuf[6]&=0xcf;
-					outbuf[6]|=(outbuf[6]&0x03)<<4;
-					outbuf[5]=outbuf[1];
-					outbuf[4]=outbuf[0];
-					mode=MODE_CALCSETOPER;
-					settime[2]=outbuf[6]&0xc0;
-					changed=1;
+						dispvalue[i+4] = SYMB_NUL;
 				}
-				break;
-			case MODE_TIME:
-				mode=MODE_SETTIME;
-				digit=3;
-				changed=0;
-				settime[0]=0;
-				settime[1]=time[2];
-				settime[2]=time[3];
-				break;
-			case MODE_DATE:
-				mode=MODE_SETDATE;
-				digit=2;
-				changed=0;
-				settime[0]=time[5];
-				settime[1]=time[6];
-				break;
-			case MODE_COUNTDOWN:
-				if(settime[1]==0 && settime[2]==0)
-				{
-					settime[1]=lastcdn[0];
-					settime[2]=lastcdn[1];
-					run=0;
-					break;
-				}
-			case MODE_COUNTUP:
-				run=!run;
-				break;
-			case MODE_SETCOUNTDOWN:
-				if(digit)
-				{
-					--digit;
-					changed=1;
-				}
-				else
-				{
-					lastcdn[0]=settime[1];
-					lastcdn[1]=settime[2];
-					
-					outbuf[0]=ALARMVALUE;
-					outbuf[1]=settime[1];
-					outbuf[2]=settime[2];
-					spi(RTC_WRITE,0x23,inbuf,outbuf,3);
-
-					mode=MODE_COUNTDOWN;
-					run=0;
-				}
-				break;
-			case MODE_CALIBRATE:
-				if(digit)
-					--digit;
-				else
-				{
-					spi(RTC_WRITE,0x09,inbuf,settime,1);
-					outbuf[0]=time[3]|settime[1];
-					spi(RTC_WRITE,0x03,inbuf,outbuf,1);
-					digit=3;
-				}
-				break;
-			case MODE_DEBUGADDR:
-				if(digit)
-					--digit;
-				else
+			}
+		}
+	}
+	else
+	{
+		switch (mode)
+		{
+		case MODE_CALC:
+			if (calcdata[7])
+			{
+				dispvalue[4] = SYMB_E;
+				dispvalue[5] = SYMB_E;
+				dispvalue[6] = SYMB_E;
+				dispvalue[7] = SYMB_NUL;
+				dot |= 0x03; //:
+			}
+			else
+			{
+				dispvalue[8] = calcdata[0];
+				dispvalue[9] = calcdata[1];
+				
+				if(calcdata[6] & 0x02) //decimal point
 				{
-					spi(RTC_READ,settime[1],settime,outbuf,1);
-					mode=MODE_DEBUG;
-					changed=1;
+					dot |= 0x02;
+					zero=1;
 				}
-				break;
-			case MODE_DEBUGVAL:
-				if(digit)
-					--digit;
 				else
-				{
-					spi(RTC_WRITE,settime[1],inbuf,settime,1);
-					mode=MODE_DEBUG;
-				}
-				break;
-			case MODE_SETTIME:
-				if(digit)
-				{
-					if(digit==3&&settime[2]>0x23)
-						 settime[2]&=0xf0;
-					--digit;
+					zero=3;
+				if(calcdata[6] & 0x01) //minus
+					dispvalue[7] = SYMB_MIN;
+			}
+			break;
+		case MODE_RESET:
+			dispvalue[4] = SYMB_NUL;
+			dispvalue[5] = SYMB_NUL;
+			dispvalue[6] = SYMB_NUL;
+			dispvalue[7] = SYMB_NUL;
+			break;
+		case MODE_VER:
+			dispvalue[4] = SYMB_NUL;
+			dispvalue[5] = SYMB_0;
+			dispvalue[6] = SYMB_2;
+			dispvalue[7] = SYMB_NUL;
+			dot |= 0x02; //.
+			break;
+		case MODE_CALIB:
+			dispvalue[8]=settime[0];
+			dispvalue[9]=settime[1];
+			if	(settime[1])
+				dispvalue[6] = SYMB_MIN;
+			zero=2;
+			break;
+		case MODE_DOWN:
+			if (!settime[0] && !settime[1])
+			{
+				dot |= 0x80; //buzz.
+				if(!run) { 
+					dispvalue[4] = SYMB_g;
+					dispvalue[5] = SYMB_n;
+					dispvalue[6] = SYMB_o;
+					dispvalue[7] = SYMB_NUL;
 				}
-				else
+			}
+		case MODE_UP:
+			zero=1;
+		case MODE_DEBUG:
+			dispvalue[8]=settime[0]; //second /value
+			dispvalue[9]=settime[1]; //minute /address
+			dot |= 0x03; //:
+			break;
+		case MODE_DATE:
+			if(step==3)
+			{
+				dispvalue[8]= time[7]; //year L
+				dispvalue[9]= lastyear[4]; //year H
+				zero=3;
+			}
+			else
+			{
+				dispvalue[8]= time[6]; //month
+				dispvalue[9]= time[5]; //day
+				dot=0x02; //.
+				zero=1;
+			}
+			break;
+		case MODE_ALARM:
+			dot |= 0x88;
+			if(step&0x01)
+			{
+				dispvalue[4] = SYMB_g;
+				dispvalue[5] = SYMB_n;
+				dispvalue[6] = SYMB_o;
+				dispvalue[7] = SYMB_NUL;
+			}
+		case MODE_TIME:
+			dispvalue[8] = time[2]; //minute
+			dispvalue[9] = time[3]; //hour
+			dot|=(step&0x01)?0x00:0x03; //:
+			zero=1;
+			break;
+		default:
+			dispvalue[8] = 0xEE;
+			dispvalue[9] = 0xEE;
+		}
+	}
+	
+	dispvalue[0] = symbol[dispvalue[8]&0x0f];
+	dispvalue[1] = symbol[dispvalue[8]>>4];
+	dispvalue[2] = symbol[dispvalue[9]&0x0f];
+	dispvalue[3] = symbol[dispvalue[9]>>4];
+	
+	if (alarm[0] && (mode != (MODE_EDIT | MODE_SETALARM)))
+		dot |= 0x08;
+	
+	for(i=0; i<zero; ++i)
+	{
+		if(dispvalue[3-i] == SYMB_0)
+			dispvalue[3-i] = SYMB_NUL;
+		else
+			break;
+	}
+	
+	for(i=0; i<4; ++i)
+	{
+		if(dispvalue[i+4])
+			dispvalue[i]=dispvalue[i+4]; 
+		if(dot & (1<<i))
+			dispvalue[i] &= SYMB_DOT;
+	}
+	if (dot & 0x80)
+		P2SEL ^=  0x04;
+	else
+		P2SEL &= ~0x04;
+	
+}
+
+int main( void )
+{
+	unsigned char i,j;
+	
+	//watchdog:
+	WDTCTL = WDTPW + WDTHOLD;
+	
+	//init 7 segment display
+	
+	P1OUT =0xff; //display data on p1
+	P1DIR =0xff;
+	
+	P3OUT &=0x0f; //display control on p3.4-7
+	P3DIR |=0xf0; 
+	
+	dispvalue[0]=SYMB_NUL;
+	dispvalue[1]=SYMB_o;
+	dispvalue[2]=SYMB_o;
+	dispvalue[3]=SYMB_NUL;
+	
+	display(dispvalue);  
+	
+	//clocking:
+		
+	BCSCTL2 |= DIVM_3; //errata sheet recommends this here 
+	
+	DCOCTL =0x00;
+	BCSCTL1 =
+		RSEL2| //in the
+		XTS| //hi freq
+		0; //ACLK = 6/1 MHz
+	
+	#if !(defined DEBAG)
+	do
+	{
+		IFG1 &= ~OFIFG;
+		for (i = 0xFF; i > 0; --i);
+	}
+	while ((IFG1 & OFIFG)); 
+	#endif
+	
+	BCSCTL2 =
+		SELM_2| //MCLK from XT2
+		DIVM_1| //MCLK = 6/2 MHz
+		SELS| //SMCLK from XT2
+		DIVS_0; //SMCLK = 6/1 MHz
+		
+	//init SPI
+	
+	P3SEL =0x0e; // SPI on p3.1, 3.2, 3.3
+	P3OUT |=0x01;
+	P3DIR |=0x01; //RTC CS on p3.0
+	
+	U0CTL =
+		SWRST| //reset
+		MM| //master
+		SYNC| //SPI mode
+		CHAR; //8 bit data
+	U0TCTL=
+		CKPH| //polarity and phase
+		SSEL0|SSEL1| //SMCLK
+		STC; //3 pin mode
+	U0BR1=0x00;
+	U0BR0=0x02; //baudrate = SMCLK/2 = 3MHz
+	U0MCTL=0x00;
+	ME2|=USPIE0;
+	U0CTL &= ~SWRST;
+	
+	
+	//init RTC
+	
+	//Looks like sometimes the first SPI reads from the RTC may be incorrect.
+	//To be sure, let's do a few redundant reads before starting the real work
+	
+	#if !(defined DEBAG)
+	for (i = 0xFF; i > 0; --i)
+		 spi(RTC_READ,0x00,inbuf,outbuf,1);
+	#endif
+	
+	//set 24 hour mode
+	spi(RTC_READ,0x03,inbuf,outbuf,1);
+	if(inbuf[0]&0x40)
+	{
+		outbuf[0]=inbuf[0]&(~0x40);
+		spi(RTC_WRITE,0x03,inbuf,outbuf,1);
+	}
+		
+	//enable battery
+	spi(RTC_READ,0x04,inbuf,outbuf,1);
+	if(!(inbuf[0]&0x08))
+	{
+		outbuf[0]=inbuf[0]|0x08; //enable battery
+		spi(RTC_WRITE,0x04,inbuf,outbuf,1);
+	}
+	
+	//set control register
+	//spi(RTC_READ,0x08,inbuf,outbuf,1);
+	outbuf[0]=
+		0x40| //squarewave enable
+		0x04; //1Hz
+	//no hardware alarms :(
+	spi(RTC_WRITE,0x08,inbuf,outbuf,1);
+	
+	//get (soft) alarm from RTC SRAM
+	spi(RTC_READ,0x20,inbuf,outbuf,3);
+	
+	alarm[0]=(inbuf[0]==ALARMVALUE)?ALARMVALUE:0;
+	alarm[1]=inbuf[1];
+	alarm[2]=inbuf[2];
+	
+	spi(RTC_READ,0x2f,inbuf,outbuf,1); // <- because of RTC bug (?)
+	
+	//get last countdown value from RTC SRAM
+	spi(RTC_READ,0x23,inbuf,outbuf,3);
+	if(inbuf[0]==ALARMVALUE)
+	{
+		lastcdn[0]=inbuf[1];
+		lastcdn[1]=inbuf[2];
+	}
+	else
+	{
+		lastcdn[0]=0;
+		lastcdn[1]=0;
+	}
+	
+	spi(RTC_READ,0x2f,inbuf,outbuf,1); // <- because of RTC bug (?)
+	
+	//get last year value from RTC SRAM
+	spi(RTC_READ,0x26,inbuf,outbuf,3);
+	if(inbuf[0]==ALARMVALUE)
+	{
+		lastyear[0]=inbuf[1];
+		lastyear[1]=inbuf[2];
+	}
+	else
+	{
+		lastyear[0]=0x00;
+		lastyear[1]=0x20;
+		//also clear calibration
+		outbuf[0]=0x00;
+		spi(RTC_WRITE,0x09,inbuf,outbuf,1);
+	}
+	lastyear[3]=0;
+	
+	//start oscillator
+	spi(RTC_READ,0x01,inbuf,outbuf,1);
+	if(!(inbuf[0]&0x80))
+	{
+		outbuf[0]=inbuf[0]|0x80;
+		spi(RTC_WRITE,0x01,inbuf,outbuf,1);
+	}
+	
+	//init timer:
+	TACCR0 = 625-1; //6MHz/625 = 9600Hz (buzz. 4.8kHz)
+	TACCTL0=   //also, compare, not capture
+		// CCIE| //enable interupt
+		OUTMOD_4; //toggle
+	TACTL=
+		TASSEL_1| //ACLK, 6MHz
+		ID_0| //6MHz/1
+		MC_1| //up mode
+		TACLR; //reset
+	// P2SEL|=0x04; //P2.2 timer output.
+	P2OUT &= ~0x04;
+	P2SEL &= ~0x04;
+	P2DIR |=  0x04;
+	
+	// Init interrupts
+	P2IE=
+		0x10| //p2.4 - int. from RS232
+		0x08| //p2.3 - int. from RTC
+		0x02| //p2.1 - int. from button A
+		0x01| //p2.0 - int. from button B
+		0x20; //p2.5 - int. from button C
+	P2IES|=0x01|0x02|0x20|0x10; //button int. on falling edge
+	P2IES&= ~0x08; //RTC int. on rising edge
+	P2IFG=0x00;
+	
+	if(!(P2IN&0x02)) //button A pressed at start?
+		mode=MODE_CALIB;
+	else if(!(P2IN&0x01)) //button B pressed at start?
+	{
+		calcdata[0] = 0x00;
+		calcdata[1] = 0x00;
+		calcdata[2] = 0x00;
+		calcdata[3] = 0x00;
+		calcdata[4] = 0x00;
+		calcdata[5] = 0x00;
+		calcdata[6] = 0x00;
+		calcdata[7] = 0x00;
+		mode=MODE_CALC;
+	}
+	else if(!(P2IN&0x20)) //button C pressed at start?
+		mode=MODE_VER;
+	else
+		mode=MODE_TIME;
+	
+	enter();
+	
+	__enable_interrupt();
+	
+	while(1)
+	{
+		event &= EVENTS; //to cancel undefined events
+		if(event)
+		{
+			i=0; //block state setup;
+			
+			if (event & EVENT_A)
+			{
+				event &= ~ EVENT_A;
+				
+				if (mode & MODE_EDIT) 
 				{
-					if(changed)
-					{
-						outbuf[0]=0x00;
-						outbuf[1]=0x00;
-						outbuf[2]=settime[1]&0x7f;
-						outbuf[3]=settime[2]&0x3f;
-						
-						spi(RTC_WRITE,0x01,inbuf,outbuf,1);//stop osc.
-						spi(RTC_READ,0x03,inbuf,outbuf,1);
-						outbuf[3]|=(inbuf[0]&0x80);//keep the calsgn bit.
-					
-						spi(RTC_WRITE,0x00,inbuf,outbuf,4);//write new time
 					
-						outbuf[0]=0x80;
-						spi(RTC_WRITE,0x01,inbuf,outbuf,1);//start osc;
-						
-						time[1]=0;
-						time[2]=settime[1];
-						time[3]=settime[2];
+					switch (mode)
+					{
+					case MODE_EDIT | MODE_SETCALCOPER:
+					case MODE_EDIT | MODE_SETCALCNUM:
+						mode = MODE_CALC;
+						break;
+					case MODE_EDIT | MODE_SETDEBUGADDR:
+						settime[0]=settime[2];
+					case MODE_EDIT | MODE_SETDEBUGVAL:
+						mode = run ? MODE_DEBUG : MODE_VER;
+						break;
+					case MODE_EDIT | MODE_SETYEAR:
+					case MODE_EDIT | MODE_SETDATE:
+						mode=MODE_DATE;
+						break;
+					case MODE_EDIT | MODE_SETDOWN:
+						if(changed)
+							break;
+					default:
+						mode=MODE_TIME;
 					}
-					mode=MODE_TIME;
+					enter();
 				}
-				break;
-			case MODE_SETYEAR:
-				if(digit)
-					--digit;
 				else
 				{
-					if(changed)
+					switch (mode)
 					{
-						time[7]=settime[1];
-						spi(RTC_WRITE,0x07,inbuf,settime+1,1);
-						
-						lastyear[0]=settime[1];
-						lastyear[1]=settime[2];
-						settime[0]=ALARMVALUE;
-						
-						spi(RTC_WRITE,0x26,inbuf,settime,3);
+					case MODE_CALC:
+						if (calcdata[7] || calcdata[1] || calcdata[0]) //if error on non-0
+						{
+							calcdata[0]=0x00;
+							calcdata[1]=0x00;
+							calcdata[2]=0x00;
+							calcdata[3]=0x00;
+							calcdata[4]=0x00;
+							calcdata[5]=0x00;
+							calcdata[6]=0x00;
+							calcdata[7]=0x00;
+						}
+						else
+							mode = MODE_TIME;
+						break;
+					case MODE_RESET:
+					case MODE_DEBUG:
+					case MODE_VER:
+						mode = MODE_RESET;
+						break;
+					case MODE_DOWN:
+						mode = MODE_EDIT | MODE_SETDOWN;
+					case MODE_UP:
+						if(run || settime[0] || settime [1]) //reset
+							{}
+						else
+							mode = MODE_EDIT | MODE_SETDOWN;
+						break;
+					case MODE_DATE:
+						mode = MODE_UP;
+						break;
+					case MODE_TIME:
+						mode = MODE_DATE;
+						break;
+					default:
+						mode = MODE_TIME;
 					}
-					mode=MODE_DATE; 
+					enter();
 				}
-				break;
-			case MODE_SETDATE:
-				if(digit)
+			}
+			else if (event & EVENT_B)
+			{
+				event &= ~ EVENT_B;
+				
+				if (mode & MODE_EDIT) 
 				{
-					--digit;
-					if(settime[0]>((settime[1]==0x02)?(leap?0x29:0x28):(((settime[1]&0x18) && !(settime[1]&0x01) || !(settime[1]&0x18) && (settime[1]&0x01))?0x31:0x30)))
-						settime[0]&=(digit?0x00:0xf0);
-					if(settime[0]==0x00)
-						settime[0]=0x01;
+					if (digit)
+					{
+						switch(mode)
+						{
+						case MODE_EDIT | MODE_SETDATE:
+							if (digit==2)
+							{
+								limit[0] = (settime[1]==0x02) ?
+									(leap?0x29:0x28) :
+									(
+										(((settime[1]&0x18) && !(settime[1]&0x01)) || (!(settime[1]&0x18) && (settime[1]&0x01))) ? 0x31 : 0x30
+									);
+								if (settime[0] > (limit[0]|0xf))
+									settime[0] = 0x01;
+							}
+							break;
+						case MODE_EDIT | MODE_SETDOWN:
+							changed=1;
+							break;
+						}
+						--digit;
+						i = digit >> 1;
+						if(!(digit&0x01))
+						{
+							if ((settime[i] > limit [i]) && (mode!=(MODE_EDIT | MODE_SETDOWN))) //don't check for countdown!
+								settime[i] &= 0xf0;
+						}
+						if ((settime[i]==0) && (mode == (MODE_EDIT | MODE_SETDATE)))
+							settime[i] = 0x01;
+					}
+					else
+					{
+						leave();
+						enter();
+					}
 				}
 				else
 				{
-					if (changed)
+					switch (mode)
 					{
-						time[5]=settime[0];
-						time[6]=settime[1];
-						settime[2]=time[7];
-						spi(RTC_WRITE,0x06,inbuf,settime+1,2);
-						spi(RTC_WRITE,0x05,inbuf,settime,1);
+					case MODE_CALC:
+						if(calcdata[7])
+						{
+							calcdata[0]=0x00;
+							calcdata[1]=0x00;
+							calcdata[2]=0x00;
+							calcdata[3]=0x00;
+							calcdata[4]=0x00;
+							calcdata[5]=0x00;
+							calcdata[6]=0x00;
+							calcdata[7]=0x00;
+						}
+						else
+						{
+							calcdata[4]=calcdata[0];
+							calcdata[5]=calcdata[1];
+							calcdata[6]&= ~0x30;
+							calcdata[6]|=(calcdata[6]&0x03)<<4;
+							cont=1;
+							mode=MODE_EDIT | MODE_SETCALCOPER;
+						}
+						break;
+					case MODE_DEBUG:
+					case MODE_VER:
+						mode = MODE_EDIT | MODE_SETDEBUGADDR;
+						break;
+					case MODE_CALIB:
+						mode = MODE_EDIT | MODE_SETCALIB;
+						break;
+					case MODE_DOWN:
+						if(!settime[0] & !settime[1])
+							break;
+					case MODE_UP:
+						run = !run;
+						i = 1;
+						break;
+					case MODE_DATE:
+						mode = MODE_EDIT | MODE_SETDATE;
+						break;
+					case MODE_ALARM:
+						mode = MODE_TIME;
+						break;
+					case MODE_TIME:
+						mode = MODE_EDIT | MODE_SETTIME;
+						break;
+					default:
+						i = 1;
 					}
-					mode=MODE_DATE;
+					
+					if(!i)
+						enter();
 				}
+			}
+			else if (event & EVENT_C)
+			{
+				event &= ~ EVENT_C;
 				
-				break;
-			case MODE_SETALARM:
-				if(digit)
-				{
-					if(digit==3&&settime[2]>0x23)
-						 settime[2]&=0xf0;
-					--digit;
-				}
-				else
+				if (mode & MODE_EDIT) 
 				{
-					if(changed|| !alarm[0])
+					changed = 1;
+					i = digit >> 1;
+					j = settime[i];
+					if (digit & 0x01)
 					{
-						alarm[0]=ALARMVALUE;
-						alarm[1]=settime[1];
-						alarm[2]=settime[2];
-						
-						spi(RTC_WRITE,0x20,inbuf,alarm,3);
+						j += 0x10;
+						if (j> (limit [i] | 0x0f))
+							j &= 0x0F;
 					}
 					else
 					{
-						alarm[0]=0;
-						spi(RTC_WRITE,0x20,inbuf,outbuf,1);
+						if ((mode == (MODE_EDIT | MODE_SETDATE)) && (digit == 2))
+						{
+							j = bcd_add_byte(j,0x01);
+							if (j>0x12)
+								j=0x01;
+						}
+						else
+						{
+							j = (j&0xf0) | ((j+0x01)&0x0f);
+							if((j>limit[i]) || (decimal && ((j&0x0f)>0x09)))
+								j &= 0xF0;
+						}
+						if ((mode == (MODE_EDIT | MODE_SETDATE)) && (j == 0))
+							j = 0x01;
 					}
-					mode=MODE_TIME;
-				}
-				break;
-			case MODE_ALARM:
-				alarm[0]=0;
-				spi(RTC_WRITE,0x20,inbuf,outbuf,1);
-				mode=MODE_TIME;
-				break;
-			case MODE_DEBUG:
-				//changed=1;
-				digit=1;
-				settime[2]=settime[1];
-				mode=MODE_DEBUGADDR;
-				break;  
-			default:
-				break;
-			}
-		}
-		else if(P2IFG&0x20) // button C
-		{
-			P2IFG &= ~0x20;
-			
-			switch(mode)
-			{
-			case MODE_CALC:
-				if(outbuf[7])
-				{
-					outbuf[0]=0x00;
-					outbuf[1]=0x00;
-					outbuf[2]=0x00;
-					outbuf[3]=0x00;
-					outbuf[6]=0x00;
-					outbuf[7]=0x00;
+					settime[i] = j;
 				}
 				else
 				{
-					mode=MODE_CALCSETNUM;
-					changed=0;
-					digit=4;
-					settime[0]=0x00;
-					settime[1]=0x00;
-					settime[2]=0x00;
-				}
-				break;
-			case MODE_CALCSETNUM:
-				if (digit==4)
-					settime[2]^=0x02;
-				else if (digit==3)
-				{
-					if((settime[1]&0xf0)==0x90)
+					switch (mode)
 					{
-						settime[1]&=0x0f;
-						settime[2]|=0x01;
+					case MODE_CALC:
+						if(calcdata[7])
+						{
+							calcdata[0]=0x00;
+							calcdata[1]=0x00;
+							calcdata[2]=0x00;
+							calcdata[3]=0x00;
+							calcdata[4]=0x00;
+							calcdata[5]=0x00;
+							calcdata[6]=0x00;
+							calcdata[7]=0x00;
+						}
+						else
+						{
+							cont=0;
+							mode=MODE_EDIT | MODE_SETCALCNUM;
+						}
+						break;
+					case MODE_DEBUG:
+						mode = MODE_EDIT | MODE_SETDEBUGVAL;
+						break;
+					case MODE_DOWN:
+						if(!run && !settime[0] && !settime[1])
+							run=1;
+						settime[0]=lastcdn[0];
+						settime[1]=lastcdn[1];
+						i = 1;
+						break;
+					case MODE_UP:
+						settime[0]=0;
+						settime[1]=0;
+						i = 1;
+						break;
+					case MODE_DATE:
+						mode = MODE_EDIT | MODE_SETYEAR;
+						break;
+					case MODE_ALARM:
+						mode = MODE_TIME;
+						break;
+					case MODE_TIME:
+						mode = MODE_EDIT | MODE_SETALARM;
+						break;
+					default:
+						i = 1;
 					}
-					else if (settime[2]&0x01)
-						settime[2]&=0xfe;
-					else
-						settime[1]+=0x10;
+					
+					if(!i)
+						enter();
 				}
-				else
+			}
+			else if (event & EVENT_RS) //received frame
+			{
+				event &= ~ EVENT_RS;
+				
+				rxcmd = rxbuf[0]; //get command
+				for(i=0; i<(RXBUFSIZE-1); ++i) //decode arguments: hex digits
 				{
-					if ((settime[(digit&0x02)?1:0]&((digit&0x01)?0xf0:0x0f)) == ((digit&0x01)?0x90:0x09))
-						settime[(digit&0x02)?1:0]&=((digit&0x01)?0x0f:0xf0);
+					j=rxbuf[i+1];
+					
+					if(j>='a') //decode digits
+						j-= 87;
+					else if(j>='A')
+						j-= 55;
+					else
+						j-= 48;
+					
+					if(i&0x01)
+						rxdata[i>>1] |= j&0x0f;
 					else
-						settime[(digit&0x02)?1:0]+=((digit&0x01)?0x10:0x01);
+						rxdata[i>>1] = j<<4;
 				}
-				break;
-			case MODE_CALCSETOPER:
-				settime[2]+=0x40;
-				break;
-			case MODE_COUNTUP:
-				settime[1]=0x00;
-				settime[2]=0x00;
-				break;
-			case MODE_COUNTDOWN:
-				settime[1]=lastcdn[0];
-				settime[2]=lastcdn[1];
-				//changed=0;
-				//mode=MODE_SETCOUNTDOWN;
-				//digit=3;
-				break;
-			case MODE_CALIBRATE:
-				if(digit==2)
-					settime[1]^=0x80;
-				if(digit>=2)
-					break;
-			case MODE_DEBUGADDR:
-			case MODE_DEBUGVAL:
-				settime[(mode==MODE_DEBUGADDR)?1:0]+=(digit==1?0x10:(((settime[(mode==MODE_DEBUGADDR)?1:0]&0x0f)==0x0f)?0xf1:0x01));
-				break;
-			case MODE_SETTIME:
-			case MODE_SETALARM:
-			case MODE_SETYEAR:
-			case MODE_SETCOUNTDOWN:
-				changed=1;
-				//these 4 lines replaced a larger switch structure
-				if((settime[digit&0x02?2:1]&((digit&0x01)?0xf0:0x0f))<(digit==1?((mode==MODE_SETYEAR)?0x90:0x50):(digit==3?((mode==MODE_SETCOUNTDOWN||mode==MODE_SETYEAR)?0x90:0x20):((mode!=MODE_SETCOUNTDOWN&&mode!=MODE_SETYEAR&&digit==2&&settime[2]>0x19)?0x03:0x09))))
-					settime[digit&0x02?2:1]+=((digit&0x01)?0x10:0x01);
-				else
-					settime[digit&0x02?2:1]&=((digit&0x01)?0x0f:0xf0);
-				break;
-			case MODE_SETDATE:
-				changed=1;
-				switch (digit)
+				
+				switch (rxcmd)
 				{
-				case 2:
-					if(settime[1]<0x12)
-						settime[1]=bcd_add_byte(settime[1],0x01);
-					else
-						settime[1]=0x01;
+				case 'g': //force display value
+					forcedisp[0]=rxdata[0];
+					forcedisp[1]=rxdata[1];
+					forcedisp[2]=rxdata[2];
+					forcedisp[3]=rxdata[3];
+					forcedisp[4]=1;
 					break;
-				case 1:
-					if((settime[0]&0xf0)<((settime[1]==0x02)?0x20:0x30))
-						settime[0]+=0x10;
-					else
-						settime[0]&=0x0f;
+				case 'h': //free display value
+					forcedisp[4]=0;
 					break;
-					
-				case 0:
-					if((settime[0]<((settime[1]==0x02)?(leap?0x29:0x28):(((settime[1]&0x18) && !(settime[1]&0x01) || !(settime[1]&0x18) && (settime[1]&0x01))?0x31:0x30))) && (settime[0]&0x0f)<0x09)
-						++settime[0];
+				case 'i': //trigger event
+					event |= rxdata[0];
+					break;
+				case 'j': //go to mode
+					mode = rxdata[0];
+					enter();
+					break;
+				case 'k': //select digit
+					digit = rxdata[0];
+					break;
+				case 'l': //value under digit
+					i = digit >> 1;
+					j = settime[i];
+					if (digit & 0x01)
+					{	
+						j &= 0x0f;
+						j |= rxdata[0]<<4;
+					}
 					else
-						settime[0]&=0xf0;
-					if(settime[0]==0x00)
-						settime[0]=0x01;
+					{
+						j &= 0xf0;
+						j |= rxdata[0]&0x0f;
+					}
+					settime[i] = j;
 					break;
-				}
-				break;
-			case MODE_DATE:
-				mode=MODE_SETYEAR;
-				digit=3;
-				changed=0;
-				
-				settime[1]=time[7];
-				settime[2]=lastyear[1];
-				break;
-			case MODE_TIME:
-				mode=MODE_SETALARM;
-				digit=3;
-				changed=0;
-				
-				settime[0]=0;
-				settime[1]=alarm[1]; //get last alarm time
-				if(settime[1]>0x59 || (settime[1]&0x0f)>0x09)
-					settime[1]=0x00;
-				settime[2]=alarm[2];
-				if(settime[2]>0x23 || (settime[2]&0x0f)>0x09)
-					settime[2]=0x00;
-				break;
-			case MODE_ALARM:
-				alarm[0]=0;
-				spi(RTC_WRITE,0x20,inbuf,outbuf,1);
-				mode=MODE_TIME;
-				break;
-			case MODE_DEBUG:
-				if(changed)
-				{
-					digit=1;
-					mode=MODE_DEBUGVAL;
-				}
-				break;
-			default:
-				break;
-			}
-		}
-		else
-			P2IFG=0;
-		
-		switch(mode)
-		{
-		case MODE_CALC:
-			if(outbuf[7])
-			{
-				dispvalue[0]=SYMB_E & SYMB_DOT;
-				dispvalue[1]=SYMB_E & SYMB_DOT;
-				dispvalue[2]=SYMB_E;
-				dispvalue[3]=SYMB_NUL;
-			}
-			else
-			{
-				dispvalue[0]=symbol[outbuf[0]&0x0f] | (((outbuf[0]&0x0f)==0x00 && (outbuf[6]&0x02))?SYMB_NUL:SYMB_8);
-				dispvalue[1]=(symbol[(outbuf[0]&0xf0)>>4] | (((outbuf[0]&0xf0)==0x00 && outbuf[1]==0x00 && !(outbuf[6]&0x02))?SYMB_NUL:SYMB_8)) & ((outbuf[6]&0x02)?SYMB_DOT:SYMB_NUL);
-				dispvalue[2]=symbol[outbuf[1]&0x0f] | ((outbuf[1]==0x00 && !(outbuf[6]&0x02))?SYMB_NUL:SYMB_8);
-				dispvalue[3]=(outbuf[6]&0x01)?SYMB_MIN:(symbol[(outbuf[1]&0xf0)>>4] |  (((outbuf[1]&0xf0)==0x00)?SYMB_NUL:SYMB_8));
-			}
-			if(alarm[0])
-				dispvalue[3]&=SYMB_DOT;
-			break;
-		case MODE_CALCSETNUM:
-			dispvalue[0]=(symbol[settime[0]&0x0f]      | ((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8));
-			dispvalue[1]=(symbol[(settime[0]&0xf0)>>4] | ((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & ((settime[2]&0x02)?SYMB_DOT:SYMB_NUL);
-			dispvalue[2]=(symbol[settime[1]&0x0f]      | ((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8));
-			dispvalue[3]=(((settime[2]&0x01)?SYMB_MIN:symbol[(settime[1]&0xf0)>>4]) | ((digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & (alarm[0]?SYMB_DOT:SYMB_NUL);
-			break;
-		case MODE_CALCSETOPER:
-			switch (settime[2] & 0xc0)
-			{
-			case 0xc0:
-				dispvalue[0]=SYMB_U;
-				dispvalue[1]=SYMB_I;
-				dispvalue[2]=SYMB_D;
-				dispvalue[3]=SYMB_NUL;
-				break;
-			case 0x80:
-				dispvalue[0]=SYMB_L;
-				dispvalue[1]=SYMB_U;
-				dispvalue[2]=SYMB_M2;
-				dispvalue[3]=SYMB_M1;
-				break;
-			case 0x40:
-				dispvalue[0]=SYMB_B;
-				dispvalue[1]=SYMB_U;
-				dispvalue[2]=SYMB_5;
-				dispvalue[3]=SYMB_NUL;
-				break;
-			default:
-				dispvalue[0]=SYMB_D;
-				dispvalue[1]=SYMB_D;
-				dispvalue[2]=SYMB_A;
-				dispvalue[3]=SYMB_NUL;
-			}
-			if(alarm[0])
-				dispvalue[3]&=SYMB_DOT;
-			break;
-		case MODE_SETTIME:
-		case MODE_SETALARM:
-		case MODE_SETCOUNTDOWN:
-		case MODE_SETYEAR:
-			dispvalue[0]=(symbol[settime[1]&0x0f]      | ((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & ((((((time[1]+0x01)&0x02)^((time[1]&0x10)>>3))&&mode==MODE_SETCOUNTDOWN)||mode==MODE_SETYEAR)?SYMB_NUL:SYMB_DOT);
-			dispvalue[1]=(symbol[(settime[1]&0xf0)>>4] | ((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & (((((time[1]&0x02)^((time[1]&0x10)>>3))&&mode==MODE_SETCOUNTDOWN)||mode==MODE_SETYEAR)?SYMB_NUL:SYMB_DOT);
-			dispvalue[2]=(symbol[settime[2]&0x0f]      | ((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) ;
-			dispvalue[3]=(symbol[(settime[2]&0xf0)>>4] | ((digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) & ((mode!=MODE_SETALARM && alarm[0] || mode==MODE_SETALARM && !(time[1]&0x01))?SYMB_DOT:SYMB_NUL);
-			break;
-		case MODE_DEBUGADDR:
-		case MODE_DEBUGVAL:
-			dispvalue[0]=(symbol[settime[(mode==MODE_DEBUGADDR)?1:0]&0x0f]      | ((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) &SYMB_DOT;
-			dispvalue[1]=(symbol[(settime[(mode==MODE_DEBUGADDR)?1:0]&0xf0)>>4] | ((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8)) &SYMB_DOT;
-			dispvalue[2]=(mode==MODE_DEBUGADDR)?SYMB_A:SYMB_NUL;   
-			dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL;
-			break;
-		case MODE_SETDATE:
-			dispvalue[0]=(symbol[settime[1]&0x0f]|((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8));
-			dispvalue[1]=(symbol[(settime[1]&0xf0)>>4]|((digit!=2 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&SYMB_DOT;
-			dispvalue[2]=(symbol[settime[0]&0x0f]|((digit!=0 && (time[1]&0x01))?SYMB_NUL:SYMB_8));
-			dispvalue[3]=(symbol[(settime[0]&0xf0)>>4]|((digit!=1 && (time[1]&0x01))?SYMB_NUL:SYMB_8))&(alarm[0]?SYMB_DOT:SYMB_NUL);
-			break;
-		case MODE_CALIBRATE:
-			dispvalue[0]=symbol[settime[0]&0x0f]|((digit!=0 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8);
-			dispvalue[1]=symbol[(settime[0]&0xf0)>>4]|((digit!=1 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8);
-			dispvalue[2]=(settime[1]?SYMB_MIN:SYMB_NUL)|((digit!=2 && digit!=3 && (time[1]&0x01))?SYMB_NUL:SYMB_8);
-			dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL;
-			break;
-		case MODE_DATE:
-			if((time[1]&0x03)==((time[1]&0x10)?0x01:0x03))
-			{
-				dispvalue[0]=symbol[time[7]&0x0f];
-				dispvalue[1]=symbol[(time[7]&0xf0)>>4];
-				dispvalue[2]=symbol[lastyear[4]&0x0f];
-				dispvalue[3]=symbol[(lastyear[4]&0xf0)>>4]&(alarm[0]?SYMB_DOT:SYMB_NUL);
-			}
-			else
-			{
-				dispvalue[0]=symbol[time[6]&0x0f];
-				dispvalue[1]=symbol[(time[6]&0xf0)>>4]&SYMB_DOT;
-				dispvalue[2]=symbol[time[5]&0x0f];
-				dispvalue[3]=((time[5]&0xf0)?symbol[(time[5]&0xf0)>>4]:SYMB_NUL)&(alarm[0]?SYMB_DOT:SYMB_NUL);
-			}
-			break;
-		case MODE_COUNTDOWN:
-			if(!(settime[1]|settime[2]))
-			{
-				if(!run)
-				{
-					dispvalue[0]=SYMB_g&SYMB_DOT;
-					dispvalue[1]=SYMB_n&SYMB_DOT;
-					dispvalue[2]=SYMB_o;
-					dispvalue[3]=alarm[0]?SYMB_DOT:SYMB_NUL;
+				case 'm': //confirm editing
+					changed=1;
+					leave();
+					enter();
+					break;
+				case 'n':
+				case 'o':
+				case 'p':
+				case 'q':
+				case 'r':
+				case 's':
+				case 't':
+				case 'u':
+				case 'v': //enter values
+					changed = 1;
+					settime[0] = rxdata[0];
+					settime[1] = rxdata[1];
+					settime[2] = rxdata[2];
+					switch (rxcmd)
+					{
+					case 'n': //set time
+						mode = MODE_EDIT | MODE_SETTIME;
+						break;
+					case 'o': //set alarm
+						mode = MODE_EDIT | MODE_SETALARM;
+						if(settime[0]==0xff && settime[1]==0xff)
+							changed=0;
+						break;
+					case 'p': //set date
+						mode = MODE_EDIT | MODE_SETDATE;
+						break;
+					case 'q': //set year
+						mode = MODE_EDIT | MODE_SETYEAR;
+						break;
+					case 'r': //set countdown
+						mode = MODE_EDIT | MODE_SETDOWN;
+						run=0;
+						break;
+					case 's': //set calibration
+						mode = MODE_EDIT | MODE_SETCALIB;
+						break;
+					case 't': //set debug address
+						mode = MODE_EDIT | MODE_SETDEBUGADDR;
+						break;
+					case 'u': //set debug value
+						mode = MODE_EDIT | MODE_SETDEBUGVAL;
+						break;
+					case 'v': //perform calculation
+						calcdata[0]=0x00;
+						calcdata[1]=0x00;
+						calcdata[2]=rxdata[0];
+						calcdata[3]=rxdata[1];
+						calcdata[4]=rxdata[2];
+						calcdata[5]=rxdata[3];
+						calcdata[6]=rxdata[4];
+						calcdata[7]=0;
+						run = 1;
+						cont = 0xFF;
+						mode = MODE_EDIT | MODE_SETCALCNUM;
+					}
+					leave();
 					break;
 				}
-				run=0;
-			}
-		case MODE_COUNTUP:
-			dispvalue[0]=symbol[settime[1]&0x0f]&SYMB_DOT;
-			dispvalue[1]=symbol[(settime[1]&0xf0)>>4]&SYMB_DOT;
-			dispvalue[2]=symbol[settime[2]&0x0f];
-			dispvalue[3]=((settime[2]&0xf0)?symbol[(settime[2]&0xf0)>>4]:SYMB_NUL)&(alarm[0]?SYMB_DOT:SYMB_NUL);
-			break;
-		case MODE_RESET:
-			dispvalue[0]=SYMB_NUL;
-			dispvalue[1]=SYMB_NUL;
-			dispvalue[2]=SYMB_NUL;
-			dispvalue[3]=SYMB_NUL;
-		break;
-		case MODE_DEBUG:
-			if(changed)
-			{
-				dispvalue[0]=symbol[settime[0]&0x0f]&SYMB_DOT;
-				dispvalue[1]=symbol[(settime[0]&0xf0)>>4]&SYMB_DOT;
-				dispvalue[2]=symbol[settime[1]&0x0f];
-				dispvalue[3]=symbol[(settime[1]&0xf0)>>4]&(alarm[0]?SYMB_DOT:SYMB_NUL);
-			}
-			else
-			{
-				dispvalue[0]=SYMB_NUL;
-				dispvalue[1]=SYMB_6&SYMB_DOT;
-				dispvalue[2]=SYMB_1;
-				dispvalue[3]=SYMB_NUL&(alarm[0]?SYMB_DOT:SYMB_NUL);
 			}
-			break;
-		case MODE_ALARM:
-		case MODE_TIME:
-			if(((time[1]&0x01) && mode==MODE_ALARM) || (time[3]==0x04 && time[2]==0x33 && time[1]==0x00))
+			else if (event & EVENT_RTC)
 			{
-				dispvalue[0]=SYMB_g;
-				dispvalue[1]=SYMB_n;
-				dispvalue[2]=SYMB_o;
-				dispvalue[3]=SYMB_DOT;
-				break;
+				event &= ~ EVENT_RTC;
+				gettime();
+				exec();
 			}
-		default:
-			dispvalue[0]=symbol[time[2]&0x0f]&((time[1]&0x01)?SYMB_NUL:SYMB_DOT);
-			dispvalue[1]=symbol[(time[2]&0xf0)>>4]&((time[1]&0x01)?SYMB_NUL:SYMB_DOT);
-			dispvalue[2]=symbol[time[3]&0x0f];
-			dispvalue[3]=((time[3]&0xf0)?symbol[(time[3]&0xf0)>>4]:SYMB_NUL)&((alarm[0] || mode==MODE_ALARM)?SYMB_DOT:SYMB_NUL);
-			break;
-		}
-		
-		display(dispvalue);
-		
-		
-		return;
-	}
-
-	int main( void )
-	{
-		unsigned char delay;
-		
-		//watchdog:
-		WDTCTL = WDTPW + WDTHOLD;
-		
-		mode=MODE_INIT;
-		
-		//init 7 segment display
-		
-		P1OUT =0xff; //display data on p1
-		P1DIR =0xff;
-		
-		P3OUT &=0x0f; //display control on p3.4-7
-		P3DIR |=0xf0; 
-		
-		dispvalue[0]=SYMB_NUL;
-		dispvalue[1]=SYMB_o;
-		dispvalue[2]=SYMB_o;
-		dispvalue[3]=SYMB_NUL;
-		
-		display(dispvalue);  
-		
-		//clocking:
-			
-		BCSCTL2 |= DIVM_3; //errata sheet recommends this here 
-		
-		DCOCTL =0x00;
-		BCSCTL1 =
-			RSEL2| //in the
-			XTS| //hi freq
-			DIVA_1; //ACLK = 6/2 MHz
-		
-		#if !(defined DEBAG)
-		do
-		{
-			IFG1 &= ~OFIFG;
-			for (delay = 0xFF; delay > 0; --delay);
-		}
-		while ((IFG1 & OFIFG)); 
-		#endif
-		
-		BCSCTL2 =
-			SELM_2| //MCLK from XT2
-			DIVM_1| //MCLK = 6/2 MHz
-			SELS| //SMCLK from XT2
-			DIVS_0; //SMCLK = 6/1 MHz
 			
-		//init SPI
-		
-		P3SEL =0x0e; // SPI on p3.1, 3.2, 3.3
-		P3OUT |=0x01;
-		P3DIR |=0x01; //RTC CS on p3.0
-		
-		U0CTL =
-			SWRST| //reset
-			MM| //master
-			SYNC| //SPI mode
-			CHAR; //8 bit data
-		U0TCTL=
-			CKPH| //polarity and phase
-			SSEL0|SSEL1| //SMCLK
-			STC; //3 pin mode
-		U0BR1=0x00;
-		U0BR0=0x02; //baudrate = SMCLK/2 = 3MHz
-		U0MCTL=0x00;
-		ME2|=USPIE0;
-		U0CTL &= ~SWRST;
-		
-		
-		//init RTC
-		
-		//Looks like sometimes the first SPI reads rom the RTC may be incorrect.
-		//To be sure, let's do a few redundant reads before starting the real work
-		
-		#if !(defined DEBAG)
-		for (delay = 0xFF; delay > 0; --delay)
-			 spi(RTC_READ,0x00,inbuf,outbuf,1);
-		#endif
-		
-		//set 24 hour mode
-		spi(RTC_READ,0x03,inbuf,outbuf,1);
-		if(inbuf[0]&0x40)
-		{
-			outbuf[0]=inbuf[0]&(~0x40);
-			spi(RTC_WRITE,0x03,inbuf,outbuf,1);
-		}
+			showvalue();
 			
-		//enable battery
-		spi(RTC_READ,0x04,inbuf,outbuf,1);
-		if(!(inbuf[0]&0x08))
-		{
-			outbuf[0]=inbuf[0]|0x08; //enable battery
-			spi(RTC_WRITE,0x04,inbuf,outbuf,1);
-		}
-		
-		//set control register
-		//spi(RTC_READ,0x08,inbuf,outbuf,1);
-		outbuf[0]=
-			0x40| //squarewave enable
-			0x04; //1Hz
-		//no hardware alarms :(
-		spi(RTC_WRITE,0x08,inbuf,outbuf,1);
-		
-		//get (soft) alarm from RTC SRAM
-		spi(RTC_READ,0x20,inbuf,outbuf,3);
-		
-		alarm[0]=(inbuf[0]==ALARMVALUE)?ALARMVALUE:0;
-		alarm[1]=inbuf[1];
-		alarm[2]=inbuf[2];
-		
-		spi(RTC_READ,0x2f,inbuf,outbuf,1); // <- because of RTC bug (?)
-		
-		//get last countdown value from RTC SRAM
-		spi(RTC_READ,0x23,inbuf,outbuf,3);
-		if(inbuf[0]==ALARMVALUE)
-		{
-			lastcdn[0]=inbuf[1];
-			lastcdn[1]=inbuf[2];
-		}
-		else
-		{
-			lastcdn[0]=0;
-			lastcdn[1]=0;
-		}
-		
-		spi(RTC_READ,0x2f,inbuf,outbuf,1); // <- because of RTC bug (?)
-		
-		//get last year value from RTC SRAM
-		spi(RTC_READ,0x26,inbuf,outbuf,3);
-		if(inbuf[0]==ALARMVALUE)
-		{
-			lastyear[0]=inbuf[1];
-			lastyear[1]=inbuf[2];
-		}
-		else
-		{
-			lastyear[0]=0x00;
-			lastyear[1]=0x20;
-			//also clear calibration
-			outbuf[0]=0x00;
-			spi(RTC_WRITE,0x09,inbuf,outbuf,1);
-		}
-		lastyear[3]=0;
-		
-		//start oscillator
-		spi(RTC_READ,0x01,inbuf,outbuf,1);
-		if(!(inbuf[0]&0x80))
-		{
-			outbuf[0]=inbuf[0]|0x80;
-			spi(RTC_WRITE,0x01,inbuf,outbuf,1);
-		}
-		
-		//init timer:
-		TACCR0 = 375-1; //3MHz/375/2=4kHz
-		TACCTL0=   //also, compare, not capture
-			OUTMOD_4; //toggle
-		TACTL=
-			TASSEL_1| //ACLK, 3MHz
-			ID_0| //3MHz/1
-			//MC_1| //up mode
-			TACLR; //reset
-		P2SEL|=0x04; //P2.2 timer output.
-		P2DIR|=0x04;
-		
-		// Init interrupts
-		P2IE=
-			0x08| //p2.3 - int. from RTC
-			0x02| //p2.1 - int. from button A
-			0x01| //p2.0 - int. from button B
-			0x20; //p2.5 - int. from button C
-		P2IES|=0x01|0x02|0x20; //button int. on falling edge
-		P2IES&= ~0x08; //RTC int. on rising edge
-		P2IFG=0x00;
-		
-		if(!(P2IN&0x02)) //button A pressed at start?
-		{
-			mode=MODE_CALIBRATE;
-			spi(RTC_READ,0x03,inbuf,outbuf,1);
-			settime[1]=inbuf[0]&0x80;
-			spi(RTC_READ,0x09,inbuf,outbuf,1);
-			settime[0]=inbuf[0];
-			digit=3;
-		}
-		else if(!(P2IN&0x01)) //button B pressed at start?
-		{
-			mode=MODE_CALC;
-			outbuf[0]=0x00;
-			outbuf[1]=0x00;
-			outbuf[2]=0x00;
-			outbuf[3]=0x00;
-			outbuf[6]=0x00;
-			outbuf[7]=0x00;
+			display(forcedisp[4]?forcedisp:dispvalue);
 		}
-		else if(!(P2IN&0x20)) //button C pressed at start?
+		else //go to low power mode if nothing's going on
 		{
-			mode=MODE_DEBUG;
-			settime[1]=0x00;
-			changed=0;
-		}
-		else
-			mode=MODE_TIME;
-		
-		__enable_interrupt();
-		
-		
-		while(1)
-		{
-			switch(mode)
-			{
-			case MODE_DEBUG:
-				P2IFG|=0x08;
-			case MODE_DEBUGADDR:
-			case MODE_DEBUGVAL:
-				break;
-			default:
-				lpm3();
-				break;
-			}
+			lpm3();
 		}
 	}
+}
-- 
2.30.2