From: b Date: Sun, 3 May 2020 13:47:23 +0000 (+0200) Subject: total rework, serial communication X-Git-Tag: v2.0 X-Git-Url: http://bicyclesonthemoon.info/git-projects/?a=commitdiff_plain;h=4843275e27ddc0acc836c2747ecc371b0f61b152;p=staf%2Fstaf total rework, serial communication --- diff --git a/definitions.h b/definitions.h index aee5ebc..804f506 100644 --- a/definitions.h +++ b/definitions.h @@ -2,8 +2,8 @@ // definitions.h // Definitions used by the code. // -// 17.07.2017 -// Copyright (C) 2014-2017 Balthasar Szczepański +// 03.05.2020 +// Copyright (C) 2014-2017, 2020 Balthasar Szczepański // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -92,30 +92,52 @@ #define SYMB_DOT (SEG_H) //operation modes -#define MODE_INIT 0 -#define MODE_TIME 1 -#define MODE_SETTIME 2 -#define MODE_SETALARM 3 -#define MODE_ALARM 4 -#define MODE_DATE 5 -#define MODE_SETDATE 6 -#define MODE_SETYEAR 7 -#define MODE_COUNTUP 8 -#define MODE_SETCOUNTDOWN 9 -#define MODE_COUNTDOWN 10 - -#define MODE_CALIBRATE 11 -#define MODE_DEBUG 12 -#define MODE_DEBUGADDR 13 -#define MODE_DEBUGVAL 14 -#define MODE_RESET 15 - -#define MODE_CALC 16 -#define MODE_CALCSETNUM 17 -#define MODE_CALCSETOPER 18 +#define MODE_EDIT 0x80 + + +#define MODE_TIME 0x00 +#define MODE_ALARM 0x01 +#define MODE_DATE 0x02 +#define MODE_UP 0x03 +#define MODE_DOWN 0x04 +#define MODE_CALIB 0x05 + +#define MODE_VER 0x06 +#define MODE_DEBUG 0x07 +#define MODE_RESET 0x08 + +#define MODE_CALC 0x09 + + +#define MODE_SETTIME 0x00 +#define MODE_SETALARM 0x01 +#define MODE_SETDATE 0x02 +#define MODE_SETYEAR 0x03 +#define MODE_SETDOWN 0x04 +#define MODE_SETCALIB 0x05 + +#define MODE_SETDEBUGADDR 0x06 +#define MODE_SETDEBUGVAL 0x07 + +#define MODE_SETCALCNUM 0x08 +#define MODE_SETCALCOPER 0x09 + + +//event flags +#define EVENT_RTC 0x01 +#define EVENT_A 0x02 +#define EVENT_B 0x04 +#define EVENT_C 0x08 +#define EVENT_RS 0x10 + +#define EVENTS 0x1f #define ALARMVALUE 0xa5 +#define RXBUFSIZE 11 +#define RXDATASIZE 5 + + unsigned char bcd_add_byte (unsigned char, unsigned char); void lpm3 (); void calc_add (unsigned char *); diff --git a/main.c b/main.c index aead80a..994cfda 100644 --- a/main.c +++ b/main.c @@ -2,8 +2,8 @@ // main.c // The main c file. // -// 17.07.2017 -// Copyright (C) 2014-2017 Balthasar Szczepański +// 03.05.2020 +// Copyright (C) 2014-2017, 2020 Balthasar Szczepański // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by @@ -23,19 +23,37 @@ #include "msp430.h" #include "definitions.h" - unsigned char inbuf[8]; - unsigned char outbuf[8] __attribute__ ((aligned (2))); - unsigned char dispvalue[4]; - volatile unsigned char time[8]; - unsigned char leap; - unsigned char settime[3]; - volatile unsigned char mode; + unsigned char calcdata[8] __attribute__ ((aligned (2))); //data for calculator operation + unsigned char inbuf[8]; //SPI input buffer + unsigned char outbuf[8]; //SPI output buffer + unsigned char dispvalue[10]; //data to display + unsigned char forcedisp[5]={0,0,0,0,0}; //forcing the display + unsigned char time[8]; + unsigned char leap; //leap year + unsigned char step; //constant count 0 1 2 3 0 1 2 3 ... + unsigned char settime[3]; //for editing values + unsigned char limit[3]; //limits for editing + unsigned char decimal; //if edited value is BCD + volatile unsigned char mode; //main state unsigned char alarm[3]; - unsigned char lastcdn[2]; + unsigned char lastcdn[2]; //last countdown unsigned char lastyear[5]; - unsigned char digit; - unsigned char changed; - unsigned char run; + unsigned char digit; //currently selected digit + unsigned char changed; //changed value during edit + unsigned char run; //switch used in some states + unsigned char cont; //continued calculation + + //for RS232 receiving + volatile unsigned char rxbyte=0; + volatile unsigned char rxcount=0; + volatile unsigned char rxind=0; + volatile unsigned char rxpin; + volatile unsigned char rxbuf[RXBUFSIZE]; + unsigned char rxdata[RXDATASIZE]; + unsigned char rxcmd; + + volatile unsigned char event=0; + const unsigned char symbol[16] ={ SYMB_0, SYMB_1, @@ -55,6 +73,14 @@ SYMB_F}; __interrupt void P2_ISR(); + __interrupt void TA0_ISR(); + + void gettime(void); + void exec(void); + void enter(void); + void leave(void); + void showvalue(void); + void display( unsigned char *data); void spi( @@ -63,6 +89,7 @@ unsigned char *inbuf, unsigned char *outbuf, unsigned short n); + int main( void ); void display(unsigned char *data) @@ -175,990 +202,1345 @@ for(i=0;i<255;++i); //looks like the RTC might not like another SPI transmission exactly before the previous one, sometimes. } - #pragma vector=PORT2_VECTOR - __interrupt void P2_ISR() + // interrupt for timer A + // timing for RS232 sampling + #pragma vector=TIMERA0_VECTOR + __interrupt void TA0_ISR() { - if(P2IFG&0x08) // RTC - { - P2IFG &= ~0x08; - spi(RTC_READ,0x00,inbuf,outbuf,8); + rxpin = P2IN & 0x10; //quickly capture state of P2.4 - time[0]=inbuf[0]; //1/100 s - time[1]=inbuf[1]&0x7f; //seconds - time[2]=inbuf[2]&0x7f; //minutes - time[3]=inbuf[3]&0x3f; //hours - time[4]=inbuf[4]&0x07; //dow - time[5]=inbuf[5]&0x3f; //dom - time[6]=inbuf[6]&0x1f; //mon - time[7]=inbuf[7];//year - leap=inbuf[6]&0x20; - - spi(RTC_READ,0x0f,inbuf,outbuf,1); // <- because of RTC bug (probably not needed anymore?) - if(!((time[2]^alarm[1])|(time[3]^alarm[2])) && alarm[0]) - { - mode=MODE_ALARM; - alarm[0]=0; //alarm removed after activated - spi(RTC_WRITE,0x20,inbuf,alarm,1); - } - - if(mode==MODE_COUNTUP && run) + TACCTL0 &= ~CCIFG; + + ++rxcount; + + if (!(rxcount & 0x01)) //only every second count + { + if (rxcount == 2) //start bit { - if(settime[1]<0x59) - settime[1]=bcd_add_byte(settime[1],0x01); - else + if (rxpin) //start fail { - settime[1]=0x00; - settime[2]=bcd_add_byte(settime[2],0x01); + rxcount = 0; + TACCTL0 &= ~CCIE; //abort } } - else if(mode==MODE_COUNTDOWN && run && (settime[1]|settime[2])) + else if (rxcount >= 20) //stop bit { - if(settime[1]) - settime[1]=bcd_add_byte(settime[1],0x99); - else + if (rxpin) //correct stop bit { - settime[1]=0x59; - settime[2]=bcd_add_byte(settime[2],0x99); + if (rxbyte == 0x0d || rxbyte == 0x0a) // CR or NL, end of frame + { + if(rxind) + { + rxind = 0; + event |= EVENT_RS; //signal + } + } + else + { + if (rxbyte >= 'g' && rxbyte <= 'z') //new command + { + rxind=0; + } + if (rxind < RXBUFSIZE) //still place in buffer + { + rxbuf[rxind] = rxbyte; //put byte to buffer + ++rxind; + } + } } + rxcount = 0; + TACCTL0 &= ~CCIE; //stop receiving } - - if (mode==MODE_ALARM || (mode==MODE_COUNTDOWN && !(settime[1]|settime[2]))) - { - TACTL^=MC_1; - //P2DIR^=0x40; - //P2SEL^=0x40; - } - else if(TACTL & MC_3) + else //receive single bit { - TACTL&= ~MC_3; - //P2DIR&= ~0x40; - //P2SEL&= ~0x40; + rxbyte >>= 1; + rxbyte |= rxpin ? 0x80 : 0x00; } + } + if(event) + _BIC_SR_IRQ(OSCOFF|CPUOFF|SCG1|SCG0); + return; + } + + #pragma vector=PORT2_VECTOR + __interrupt void P2_ISR() + { + if(P2IFG&0x08) // RTC + { + P2IFG &= ~0x08; + event |= EVENT_RTC; + } + else if(P2IFG&0x02) // button A + { + P2IFG &= ~0x02; + event |= EVENT_A; + } + else if(P2IFG&0x01) // button B + { + P2IFG &= ~0x01; + event |= EVENT_B; + } + else if(P2IFG&0x20) // button C + { + P2IFG &= ~0x20; + event |= EVENT_C; + } + else if(P2IFG&0x10) // RS232 + { + P2IFG &= ~0x10; - lastyear[4]=(time[7]==0x00 && lastyear[0]==0x99)?bcd_add_byte(lastyear[1],0x01):lastyear[1]; - if (time[7]!=lastyear[0]) + if(!rxcount) //start bit detected { - if(time[7]==lastyear[2]) - ++(lastyear[3]); - else - lastyear[3]=0; - - lastyear[2]=time[7]; + TACTL |= TACLR; //reset timer + TACCTL0 &= ~CCIFG; //clear any waiting timer interrupt + TACCTL0 |= CCIE; //enable timer interrupts - if(lastyear[3]>55) - { - lastyear[3]=0; - - if(time[7]==0x00 && lastyear[0]==0x99) - lastyear[1]=bcd_add_byte(lastyear[1],0x01); - - lastyear[0]=time[7]; - - outbuf[0]=ALARMVALUE; - outbuf[1]=lastyear[0]; - outbuf[2]=lastyear[1]; - spi(RTC_WRITE,0x26,inbuf,outbuf,3); - } + rxcount = 1; + rxbyte = 0; } + } + else + P2IFG=0; + + if(event) + _BIC_SR_IRQ(OSCOFF|CPUOFF|SCG1|SCG0); //escaoe low power mode + return; + } + +void gettime(void) +{ + P2IFG &= ~0x08; + + //get latest time from RTC + spi(RTC_READ,0x00,inbuf,outbuf,8); + + time[0]=inbuf[0]; //1/100 s + time[1]=inbuf[1]&0x7f; //seconds + time[2]=inbuf[2]&0x7f; //minutes + time[3]=inbuf[3]&0x3f; //hours + time[4]=inbuf[4]&0x07; //dow + time[5]=inbuf[5]&0x3f; //dom + time[6]=inbuf[6]&0x1f; //mon + time[7]=inbuf[7];//year + leap=inbuf[6]&0x20; + + step = (time[1]&0x03)^((time[1]&0x10)?0x02:0x00); + + + spi(RTC_READ,0x0f,inbuf,outbuf,1); // <- because of RTC bug (probably not needed anymore?) + + //check if trigger alarm + if(!((time[2]^alarm[1])|(time[3]^alarm[2])) && alarm[0]) + { + mode=MODE_ALARM; + alarm[0]=0; //alarm removed after activated + spi(RTC_WRITE,0x20,inbuf,alarm,1); + } + + + //code to deal with centuries, functionality missing from RTC + //has to avoid accidentally reacting in case of transmission error + + lastyear[4]=(time[7]==0x00 && lastyear[0]==0x99)?bcd_add_byte(lastyear[1],0x01):lastyear[1]; + if (time[7]!=lastyear[0]) + { + if(time[7]==lastyear[2]) + ++(lastyear[3]); + else + lastyear[3]=0; + + lastyear[2]=time[7]; + + if(lastyear[3]>55) + { + lastyear[3]=0; + if(time[7]==0x00 && lastyear[0]==0x99) + lastyear[1]=bcd_add_byte(lastyear[1],0x01); - if(mode==MODE_DEBUG && changed) - spi(RTC_READ,settime[1],settime,outbuf,1); + lastyear[0]=time[7]; - if(mode==MODE_RESET && P2IN&0x02 && P2IN&0x01 && P2IN&0x20) { - WDTCTL = ALARMVALUE; - } - } - else if(P2IFG&0x02) // button A + outbuf[0]=ALARMVALUE; + outbuf[1]=lastyear[0]; + outbuf[2]=lastyear[1]; + spi(RTC_WRITE,0x26,inbuf,outbuf,3); + } + } + +} + +void leave (void) //to execute when leaving an edit state +{ + switch (mode) + { + case MODE_EDIT | MODE_SETCALCOPER: + calcdata[6] &= ~0xc0; + calcdata[6] |= settime[0]<<6; + mode=MODE_EDIT | MODE_SETCALCNUM; + break; + case MODE_EDIT | MODE_SETCALCNUM: + if (run) { - P2IFG &= ~0x02; - switch(mode) + if(cont != 0xff) //skip if triggered externally { - case MODE_CALCSETNUM: - case MODE_CALCSETOPER: - mode=MODE_CALC; - break; - case MODE_CALC: - if(outbuf[7] || outbuf[1]!=0 || outbuf[0]!=0) + calcdata[2]=settime[0]; + calcdata[3]=settime[1]; + if ((settime[1] & 0xF0)==0xA0) //minus sign encoded as 0xA { - outbuf[7]=0x00; - outbuf[6]=0x00; - outbuf[3]=0x00; - outbuf[2]=0x00; - outbuf[1]=0x00; - outbuf[0]=0x00; + calcdata[6] |= 0x04; + calcdata[3] &= 0x0f; } - else - mode=MODE_TIME; - break; - case MODE_TIME: - case MODE_SETDATE: - case MODE_SETYEAR: - mode=MODE_DATE; - break; - case MODE_DATE: - mode=MODE_COUNTUP; - settime[1]=0x00; - settime[2]=0x00; - run=0; + if (settime[2]) //decimal point + calcdata[6] |= 0x08; + } + switch(calcdata[6]&0xc0) + { + case 0xc0: + calc_div(calcdata); break; - case MODE_COUNTUP: - if(run) - { - settime[1]=0x00; - settime[2]=0x00; - run=0; - } - else - { - mode=MODE_SETCOUNTDOWN; - settime[1]=lastcdn[0]; - settime[2]=lastcdn[1]; - changed=0; - digit=3; - } + case 0x80: + calc_mul(calcdata); break; - case MODE_DEBUGADDR: - settime[1]=settime[2]; - case MODE_DEBUGVAL: - spi(RTC_READ,settime[1],settime,outbuf,1); - mode=MODE_DEBUG; + case 0x40: + calcdata[6]^=0x04; + calc_add(calcdata); + calcdata[6]^=0x04; break; - case MODE_DEBUG: - case MODE_RESET: - mode=MODE_RESET; + case 0x00: + calc_add(calcdata); break; - case MODE_SETCOUNTDOWN: - case MODE_COUNTDOWN: - if(changed || mode==MODE_COUNTDOWN) - { - mode=MODE_SETCOUNTDOWN; - settime[1]=lastcdn[0]; - settime[2]=lastcdn[1]; - changed=0; - digit=3; - break; - } default: - mode=MODE_TIME; - break; + calcdata[7]=0xff; } + mode=MODE_CALC; } - else if(P2IFG&0x01) // button B + else { - P2IFG &= ~0x01; + calcdata[4]=settime[0]; + calcdata[5]=settime[1]; + calcdata[6] &= ~0x30; + if ((settime[1] & 0xF0)==0xA0) //minus sign encoded as 0xA + { + calcdata[6] |= 0x10; + calcdata[5] &= 0x0f; + } + if (settime[2]) //decimal point + calcdata[6] |= 0x20; + mode=MODE_EDIT | MODE_SETCALCOPER; + } + break; + case MODE_EDIT | MODE_SETDEBUGVAL: + spi(RTC_WRITE,settime[1],inbuf,settime,1); + mode=MODE_DEBUG; + break; + case MODE_EDIT | MODE_SETDEBUGADDR: + settime[1]=settime[0]; + run=1; + mode=MODE_DEBUG; + break; + case MODE_EDIT | MODE_SETCALIB: + spi(RTC_WRITE,0x09,inbuf,settime,1); + outbuf[0]=time[3]|(settime[1]?0x80:0x00); + spi(RTC_WRITE,0x03,inbuf,outbuf,1); + mode=MODE_CALIB; + break; + case MODE_EDIT | MODE_SETDOWN: + lastcdn[0]=settime[0]; + lastcdn[1]=settime[1]; + + outbuf[0]=ALARMVALUE; + outbuf[1]=settime[0]; + outbuf[2]=settime[1]; + spi(RTC_WRITE,0x23,inbuf,outbuf,3); + + mode=MODE_DOWN; + break; + case MODE_EDIT | MODE_SETYEAR: + if(changed) + { + time[7]=settime[0]; + spi(RTC_WRITE,0x07,inbuf,settime,1); + + lastyear[0]=settime[0]; + lastyear[1]=settime[1]; + lastyear[2]=settime[1]; + lastyear[3]=0; + lastyear[4]=settime[1]; + + outbuf[0]=ALARMVALUE; + outbuf[1]=settime[0]; + outbuf[2]=settime[1]; + spi(RTC_WRITE,0x26,inbuf,outbuf,3); + } + mode=MODE_DATE; + break; + case MODE_EDIT | MODE_SETDATE: + if (changed) + { + time[5]=settime[0]; //day + time[6]=settime[1]; //month + settime[2]=time[7]; //year + spi(RTC_WRITE,0x06,inbuf,settime+1,2); //write month and year first + spi(RTC_WRITE,0x05,inbuf,settime,1); //and only then the day + //otherwise rtc can reject the date + } + mode=MODE_DATE; + break; + case MODE_EDIT | MODE_SETALARM: + if(changed|| !alarm[0]) + { + alarm[0]=ALARMVALUE; + alarm[1]=settime[0]; + alarm[2]=settime[1]; + + spi(RTC_WRITE,0x20,inbuf,alarm,3); + } + else + { + alarm[0]=0; + spi(RTC_WRITE,0x20,inbuf,outbuf,1); + } + mode=MODE_TIME; + break; + case MODE_EDIT | MODE_SETTIME: + if (changed) + { + outbuf[0]=0x00; + outbuf[1]=0x00; + outbuf[2]=settime[0]&0x7f; + outbuf[3]=settime[1]&0x3f; + + spi(RTC_WRITE,0x01,inbuf,outbuf,1);//stop osc. + spi(RTC_READ,0x03,inbuf,outbuf,1); + outbuf[3]|=(inbuf[0]&0x80);//keep the calsgn bit. + + spi(RTC_WRITE,0x00,inbuf,outbuf,4);//write new time + + outbuf[0]=0x80; + spi(RTC_WRITE,0x01,inbuf,outbuf,1);//start osc; - switch(mode) + time[1]=0; + time[2]=settime[0]; + time[3]=settime[1]; + } + mode = MODE_TIME; + break; + } +} + +void enter (void) //to execute when entering a state +{ + if (mode & MODE_EDIT) + { + digit = 3; + changed = 0; + limit[0]=0x59; + limit[1]=0x23; + decimal = 1; + switch (mode) + { + case MODE_EDIT | MODE_SETCALCOPER: + digit=0; + limit[0]=0x03; + settime[0] = cont ? (calcdata[6]>>6) : 0x00; + run = 1; + break; + case MODE_EDIT | MODE_SETCALCNUM: + digit=4; + limit[0]=0x99; + limit[1]=0xA9; + limit[2]=0x01; + if (run && cont) { - case MODE_CALCSETOPER: - outbuf[6]&=0x3f; - outbuf[6]|=settime[2]; - mode=MODE_CALCSETNUM; - digit=4; - if(changed) - { - settime[0]=outbuf[2]; - settime[1]=outbuf[3]; - settime[2]=(outbuf[6]&0x0c)>>2; - } - else - { - settime[0]=0x00; - settime[1]=0x00; - settime[2]=0x00; - } - changed=1; - break; - case MODE_CALCSETNUM: - if(digit) - --digit; - else + settime[0] = calcdata[2]; + settime[1] = calcdata[3]; + settime[2] = (calcdata[6]>>2)&0x03; + } + else + { + settime[0] = 0x00; + settime[1] = 0x00; + settime[2] = 0x00; + } + break; + case MODE_EDIT | MODE_SETDEBUGADDR: + if(run) + { + settime[2] = settime[0]; + settime[0] = settime[1]; + } + else + { + settime[0] = 0x00; + settime[2] = 0x00; + } + case MODE_EDIT | MODE_SETDEBUGVAL: + digit=1; + limit[0]=0xff; + decimal=0; + break; + case MODE_EDIT | MODE_SETYEAR: + limit[0]=0x99; + limit[1]=0x99; + settime[0] = time[7]; //year L + settime[1] = lastyear[4]; //year H + break; + case MODE_EDIT | MODE_SETDATE: + digit = 2; + // limit[0]=0x31; + // limit[1]=0x12; not needed will be dynamically done later + settime[0] = time[5]; //day + settime[1] = time[6]; //month + break; + case MODE_EDIT | MODE_SETCALIB: + limit[0]=0xff; + limit[1]=0x01; + decimal=0; + digit=2; + spi(RTC_READ,0x03,inbuf,outbuf,1); + settime[1]=(inbuf[0]&0x80)?0x01:0x00; + spi(RTC_READ,0x09,inbuf,outbuf,1); + settime[0]=inbuf[0]; + break; + case MODE_EDIT | MODE_SETDOWN: + limit[1] = 0x99; + settime[0] = lastcdn[0]; + settime[1] = lastcdn[1]; + break; + case MODE_EDIT | MODE_SETALARM: + settime[0] = (alarm[1]>0x59 || (settime[1]&0x0f)>0x09) ? 0x00 : alarm[1]; + settime[1] = (alarm[2]>0x59 || (settime[2]&0x0f)>0x09) ? 0x00 : alarm[2]; + break; + case MODE_EDIT | MODE_SETTIME: + settime[0] = time[2]; //minute + settime[1] = time[3]; //hour + break; + } + } + else + { + switch(mode) + { + case MODE_CALC: + run=0; + break; + case MODE_DEBUG: + event |= EVENT_RTC; + break; + case MODE_VER: + run=0; + break; + case MODE_CALIB: + spi(RTC_READ,0x03,inbuf,outbuf,1); + settime[1]=(inbuf[0]&0x80)?0x01:0x00; + spi(RTC_READ,0x09,inbuf,outbuf,1); + settime[0]=inbuf[0]; + break; + case MODE_DOWN: + run=0; + settime[0] = lastcdn[0]; + settime[1] = lastcdn[1]; + break; + case MODE_UP: + run=0; + settime[0] = 0; + settime[1] = 0; + break; + // default: + } + } +} + +void exec (void) //execute every second +{ + switch(mode) + { + case MODE_RESET: + if(P2IN&0x02 && P2IN&0x01 && P2IN&0x20) //perform a reset when no button pressed + WDTCTL = ALARMVALUE; + break; + case MODE_DEBUG: + spi(RTC_READ,settime[1],settime,outbuf,1); + event |= EVENT_RTC; + break; + case MODE_DOWN: + if(run && (settime[1] | settime[0])) + { + if(settime[0]) + settime[0]=bcd_add_byte(settime[0],0x99); + else + { + settime[0]=0x59; + settime[1]=bcd_add_byte(settime[1],0x99); + } + } + else + run=0; + break; + case MODE_UP: + if(run) + { + if(settime[0]<0x59) + settime[0]=bcd_add_byte(settime[0],0x01); + else + { + settime[0]=0x00; + settime[1]=bcd_add_byte(settime[1],0x01); + } + } + break; + // default: + } +} + +void showvalue () //determine what to show on display +{ + unsigned char dot=0; + unsigned char zero=0; + unsigned char i; + + dispvalue[4]=0; + dispvalue[5]=0; + dispvalue[6]=0; + dispvalue[7]=0; + + if (mode == (MODE_EDIT | MODE_SETCALCOPER)) + { + switch (settime[0]) + { + case 3: + dispvalue[4] = SYMB_U; + dispvalue[5] = SYMB_I; + dispvalue[6] = SYMB_D; + dispvalue[7] = SYMB_NUL; + break; + case 2: + dispvalue[4] = SYMB_L; + dispvalue[5] = SYMB_U; + dispvalue[6] = SYMB_M2; + dispvalue[7] = SYMB_M1; + break; + case 1: + dispvalue[4] = SYMB_B; + dispvalue[5] = SYMB_U; + dispvalue[6] = SYMB_5; + dispvalue[7] = SYMB_NUL; + break; + case 0: + dispvalue[4] = SYMB_D; + dispvalue[5] = SYMB_D; + dispvalue[6] = SYMB_A; + dispvalue[7] = SYMB_NUL; + break; + } + } + else if (mode & MODE_EDIT) + { + dispvalue[8] = settime[0]; + dispvalue[9] = settime[1]; + + switch (mode) + { + case MODE_EDIT | MODE_SETCALCNUM: + if ((settime[1]&0xF0) == 0xA0) //minus sign + dispvalue[7] = SYMB_MIN; + if (settime[2]) //decimal point + dot |= 0x02; + break; + case MODE_EDIT | MODE_SETDEBUGADDR: + dispvalue[6] = SYMB_A; + case MODE_EDIT | MODE_SETDEBUGVAL: + dispvalue[9]=0x00; + zero=2; + dot |= 0x03; //: + break; + case MODE_EDIT | MODE_CALIB: + if (settime[1] && (!(step&0x01) || digit==2)) + dispvalue[6] = SYMB_MIN; + zero=2; + break; + case MODE_EDIT | MODE_SETDOWN: + dot |= ((step & 0x02)?0x00:002) | ((step==0 || step==3)?0x01:00); + break; + case MODE_EDIT | MODE_SETDATE: + dispvalue[8] = settime[1]; + dispvalue[9] = settime[0]; + dot |= 0x02; + break; + case MODE_EDIT | MODE_SETALARM: + if(!(step & 0x01)) + dot |= 0x08; + case MODE_EDIT | MODE_SETTIME: + dot |= 0x03; + break; + } + + + if (step&0x01) + { + for(i=0; i<4; ++i) + { + if (i != digit) { - if(changed) + if(mode== (MODE_EDIT | MODE_SETDATE)) { - outbuf[6]&=0xf3; - outbuf[6]|=settime[2]<<2; - outbuf[3]=settime[1]; - outbuf[2]=settime[0]; - - - switch(outbuf[6]&0xc0) + switch(i) { - case 0xc0: - calc_div(outbuf); - break; - case 0x80: - calc_mul(outbuf); + case 2: + dispvalue[4] = SYMB_NUL; + dispvalue[5] = SYMB_NUL; break; - case 0x40: - outbuf[6]^=0x04; - calc_add(outbuf); - outbuf[6]^=0x04; + case 1: + case 0: + dispvalue[6+i] = SYMB_NUL; break; - case 0x00: - calc_add(outbuf); - break; - default: - outbuf[7]=0xff; } - mode=MODE_CALC; } else - { - outbuf[6]&=0xcf; - outbuf[6]|=settime[2]<<4; - outbuf[5]=settime[1]; - outbuf[4]=settime[0]; - mode=MODE_CALCSETOPER; - settime[2]=0x00; - } - } - break; - case MODE_CALC: - if(outbuf[7]) - { - outbuf[0]=0x00; - outbuf[1]=0x00; - outbuf[2]=0x00; - outbuf[3]=0x00; - outbuf[6]=0x00; - outbuf[7]=0x00; - } - else - { - outbuf[6]&=0xcf; - outbuf[6]|=(outbuf[6]&0x03)<<4; - outbuf[5]=outbuf[1]; - outbuf[4]=outbuf[0]; - mode=MODE_CALCSETOPER; - settime[2]=outbuf[6]&0xc0; - changed=1; + dispvalue[i+4] = SYMB_NUL; } - break; - case MODE_TIME: - mode=MODE_SETTIME; - digit=3; - changed=0; - settime[0]=0; - settime[1]=time[2]; - settime[2]=time[3]; - break; - case MODE_DATE: - mode=MODE_SETDATE; - digit=2; - changed=0; - settime[0]=time[5]; - settime[1]=time[6]; - break; - case MODE_COUNTDOWN: - if(settime[1]==0 && settime[2]==0) - { - settime[1]=lastcdn[0]; - settime[2]=lastcdn[1]; - run=0; - break; - } - case MODE_COUNTUP: - run=!run; - break; - case MODE_SETCOUNTDOWN: - if(digit) - { - --digit; - changed=1; - } - else - { - lastcdn[0]=settime[1]; - lastcdn[1]=settime[2]; - - outbuf[0]=ALARMVALUE; - outbuf[1]=settime[1]; - outbuf[2]=settime[2]; - spi(RTC_WRITE,0x23,inbuf,outbuf,3); - - mode=MODE_COUNTDOWN; - run=0; - } - break; - case MODE_CALIBRATE: - if(digit) - --digit; - else - { - spi(RTC_WRITE,0x09,inbuf,settime,1); - outbuf[0]=time[3]|settime[1]; - spi(RTC_WRITE,0x03,inbuf,outbuf,1); - digit=3; - } - break; - case MODE_DEBUGADDR: - if(digit) - --digit; - else + } + } + } + else + { + switch (mode) + { + case MODE_CALC: + if (calcdata[7]) + { + dispvalue[4] = SYMB_E; + dispvalue[5] = SYMB_E; + dispvalue[6] = SYMB_E; + dispvalue[7] = SYMB_NUL; + dot |= 0x03; //: + } + else + { + dispvalue[8] = calcdata[0]; + dispvalue[9] = calcdata[1]; + + if(calcdata[6] & 0x02) //decimal point { - spi(RTC_READ,settime[1],settime,outbuf,1); - mode=MODE_DEBUG; - changed=1; + dot |= 0x02; + zero=1; } - break; - case MODE_DEBUGVAL: - if(digit) - --digit; else - { - spi(RTC_WRITE,settime[1],inbuf,settime,1); - mode=MODE_DEBUG; - } - break; - case MODE_SETTIME: - if(digit) - { - if(digit==3&&settime[2]>0x23) - settime[2]&=0xf0; - --digit; + zero=3; + if(calcdata[6] & 0x01) //minus + dispvalue[7] = SYMB_MIN; + } + break; + case MODE_RESET: + dispvalue[4] = SYMB_NUL; + dispvalue[5] = SYMB_NUL; + dispvalue[6] = SYMB_NUL; + dispvalue[7] = SYMB_NUL; + break; + case MODE_VER: + dispvalue[4] = SYMB_NUL; + dispvalue[5] = SYMB_0; + dispvalue[6] = SYMB_2; + dispvalue[7] = SYMB_NUL; + dot |= 0x02; //. + break; + case MODE_CALIB: + dispvalue[8]=settime[0]; + dispvalue[9]=settime[1]; + if (settime[1]) + dispvalue[6] = SYMB_MIN; + zero=2; + break; + case MODE_DOWN: + if (!settime[0] && !settime[1]) + { + dot |= 0x80; //buzz. + if(!run) { + dispvalue[4] = SYMB_g; + dispvalue[5] = SYMB_n; + dispvalue[6] = SYMB_o; + dispvalue[7] = SYMB_NUL; } - else + } + case MODE_UP: + zero=1; + case MODE_DEBUG: + dispvalue[8]=settime[0]; //second /value + dispvalue[9]=settime[1]; //minute /address + dot |= 0x03; //: + break; + case MODE_DATE: + if(step==3) + { + dispvalue[8]= time[7]; //year L + dispvalue[9]= lastyear[4]; //year H + zero=3; + } + else + { + dispvalue[8]= time[6]; //month + dispvalue[9]= time[5]; //day + dot=0x02; //. + zero=1; + } + break; + case MODE_ALARM: + dot |= 0x88; + if(step&0x01) + { + dispvalue[4] = SYMB_g; + dispvalue[5] = SYMB_n; + dispvalue[6] = SYMB_o; + dispvalue[7] = SYMB_NUL; + } + case MODE_TIME: + dispvalue[8] = time[2]; //minute + dispvalue[9] = time[3]; //hour + dot|=(step&0x01)?0x00:0x03; //: + zero=1; + break; + default: + dispvalue[8] = 0xEE; + dispvalue[9] = 0xEE; + } + } + + dispvalue[0] = symbol[dispvalue[8]&0x0f]; + dispvalue[1] = symbol[dispvalue[8]>>4]; + dispvalue[2] = symbol[dispvalue[9]&0x0f]; + dispvalue[3] = symbol[dispvalue[9]>>4]; + + if (alarm[0] && (mode != (MODE_EDIT | MODE_SETALARM))) + dot |= 0x08; + + for(i=0; i 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(); } } +}