]> bicyclesonthemoon.info Git - staf/staf/commitdiff
total rework, serial communication v2.0
authorb <rowerynaksiezycu@gmail.com>
Sun, 3 May 2020 13:47:23 +0000 (15:47 +0200)
committerb <rowerynaksiezycu@gmail.com>
Sun, 3 May 2020 13:47:23 +0000 (15:47 +0200)
definitions.h
main.c

index aee5ebcfd185b14f01627bd5c914deca93c7e0eb..804f50654ac76453f55258639ee31a8219393d5f 100644 (file)
@@ -2,8 +2,8 @@
 // definitions.h\r
 // Definitions used by the code.\r
 // \r
-// 17.07.2017\r
-// Copyright (C) 2014-2017  Balthasar Szczepański\r
+// 03.05.2020\r
+// Copyright (C) 2014-2017, 2020  Balthasar Szczepański\r
 //\r
 // This program is free software: you can redistribute it and/or modify\r
 // it under the terms of the GNU General Public License as published by\r
 #define SYMB_DOT (SEG_H)\r
 \r
 //operation modes\r
-#define MODE_INIT         0\r
-#define MODE_TIME         1\r
-#define MODE_SETTIME      2\r
-#define MODE_SETALARM     3\r
-#define MODE_ALARM        4\r
-#define MODE_DATE         5\r
-#define MODE_SETDATE      6\r
-#define MODE_SETYEAR      7\r
-#define MODE_COUNTUP      8\r
-#define MODE_SETCOUNTDOWN 9\r
-#define MODE_COUNTDOWN   10\r
-\r
-#define MODE_CALIBRATE   11\r
-#define MODE_DEBUG       12\r
-#define MODE_DEBUGADDR   13\r
-#define MODE_DEBUGVAL    14\r
-#define MODE_RESET       15\r
-\r
-#define MODE_CALC        16\r
-#define MODE_CALCSETNUM  17\r
-#define MODE_CALCSETOPER 18\r
+#define MODE_EDIT 0x80\r
+\r
+\r
+#define MODE_TIME  0x00\r
+#define MODE_ALARM 0x01\r
+#define MODE_DATE  0x02\r
+#define MODE_UP    0x03\r
+#define MODE_DOWN  0x04\r
+#define MODE_CALIB 0x05\r
+\r
+#define MODE_VER   0x06\r
+#define MODE_DEBUG 0x07\r
+#define MODE_RESET 0x08\r
+\r
+#define MODE_CALC  0x09\r
+\r
+\r
+#define MODE_SETTIME  0x00\r
+#define MODE_SETALARM 0x01\r
+#define MODE_SETDATE  0x02\r
+#define MODE_SETYEAR  0x03\r
+#define MODE_SETDOWN  0x04\r
+#define MODE_SETCALIB 0x05\r
+\r
+#define MODE_SETDEBUGADDR 0x06\r
+#define MODE_SETDEBUGVAL  0x07\r
+\r
+#define MODE_SETCALCNUM  0x08\r
+#define MODE_SETCALCOPER 0x09\r
+\r
+\r
+//event flags\r
+#define EVENT_RTC 0x01\r
+#define EVENT_A   0x02\r
+#define EVENT_B   0x04\r
+#define EVENT_C   0x08\r
+#define EVENT_RS  0x10\r
+\r
+#define EVENTS    0x1f\r
 \r
 #define ALARMVALUE 0xa5\r
 \r
+#define RXBUFSIZE 11\r
+#define RXDATASIZE 5\r
+\r
+\r
 unsigned char bcd_add_byte (unsigned char, unsigned char);\r
 void          lpm3         ();\r
 void          calc_add     (unsigned char *);\r
diff --git a/main.c b/main.c
index aead80a6f25b8c8f7c91d0af4d162cb8ea68dc6d..994cfda18edf283c8bb8262ddf31589e2a3f4700 100644 (file)
--- 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
        #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,
                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)
                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();
                }
        }
+}