#include <htc.h>
#include "gooddelay.h"
#define CS RB0
#define TIMESIG RA1 
#define DEBUGON RA2
#define DSTLED RB5

__CONFIG(0x3F2A);
__CONFIG(0x3FFC);

int a, countcheck;
char decode, decodeb, decodec, counter;
char currenthours, currentmins, dst, newmin;
long debouncecount;
char timelocked, failedparity;
char yearbitcount, monthbitcount, timebitcount;
char hours, mins, year, yearmonth, daymonth;
char currentyear, currentmonth, currentdaymonth;
int eepromaddress;

void DelayMs(unsigned char cnt)
{
	unsigned char	i;
	do {
		i = 4;
		do {
			DelayUs(250);
			CLRWDT();
		} while(--i);
	} while(--cnt);
}

void DelayBigMs(unsigned int cnt)
{
	unsigned char	i;
	do {
		i = 4;
		do {
			DelayUs(250);
			CLRWDT();
		} while(--i);
	} while(--cnt);
}

void DelayS(unsigned char cnt)
{
	unsigned char i;
	do {
		i = 4;
		do {
			DelayMs(250);
			CLRWDT();
		} while(--i);
	} while(--cnt);
}

char spi_write(char data) {
	SSPBUF = data;
	while (!BF);
	return SSPBUF;
}

void blankdisplay(void) {
    for (a=1; a<7; a++) {
        CS = 0;
        spi_write(a);
        spi_write(15);
        CS = 1;
    }
}
 
void spi_init(void) {
	TRISB1 = 1;			//set bit 1 of TRISB (SDI) to input
	TRISB2 = 0;
	TRISB4 = 0;
	SSPSTAT = 0x40;
	SSPCON = 0x21;
}

void setintensity(char intensitytoset) {
     CS = 0;
     spi_write(0xA);
     spi_write(intensitytoset);
     CS = 1;
}

void displaystartup(void) {
	CS = 0;
	spi_write(0x9);
	spi_write(0xFF);
	CS = 1;    
	setintensity(5);
	CS = 0;
    spi_write(0xB);
    spi_write(0x5);
	CS = 1;	
	CS = 0;
	spi_write(0xC);
	spi_write(0x1);
	CS = 1;	
	CS = 0;
	spi_write(0xF);
	spi_write(0x1);
	CS = 1;
	DSTLED=1;	
	DelayS(2);	
	CS = 0;
	spi_write(0xF);
	spi_write(0x0);
	CS = 1;	
	DSTLED=0;
}

void displayerror(void) {
     if (RA2) { return; }
     //clear dst led
     DSTLED = 0;
     
     //SET DECODE MODE
     CS = 0;
     spi_write(0x9);
     spi_write(0x1);
     CS = 1;

     //PUT //E// ON DISPLAY
     CS = 0;
     spi_write(1);
     spi_write(11);
     CS = 1;

     //PUT //r// ON DISPLAY
     CS = 0;
     spi_write(2);
     spi_write(5);
     CS = 1;

     //PUT //r// ON DISPLAY
     CS = 0;
     spi_write(3);
     spi_write(5);
     CS = 1;

     //PUT //o// ON DISPLAY
     CS = 0;
     spi_write(4);
     spi_write(29);
     CS = 1;

     //PUT //r// ON DISPLAY
     CS = 0;
     spi_write(5);
     spi_write(5);
     CS = 1;

     //BLANK DIGIT
     CS = 0;
     spi_write(6);
     spi_write(0);
     CS = 1;
}

void displaypfail(void) {
	     if (RA2) { return; }
     //clear dst led
     DSTLED = 0;
     
     //SET DECODE MODE
     CS = 0;
     spi_write(0x9);
     spi_write(0x21);
     CS = 1;

     //PUT P ON DISPLAY
     CS = 0;
     spi_write(1);
     spi_write(14);
     CS = 1;

     //BLANK DIGIT
     CS = 0;
     spi_write(2);
     spi_write(0);
     CS = 1;
     
     //PUT //F// ON DISPLAY
     CS = 0;
     spi_write(3);
     spi_write(0x47);
     CS = 1;

     //PUT //A// ON DISPLAY
     CS = 0;
     spi_write(4);
     spi_write(0x77);
     CS = 1;

     //PUT //I// ON DISPLAY
     CS = 0;
     spi_write(5);
     spi_write(6);
     CS = 1;

     //PUT //L// ON DISPLAY
     CS = 0;
     spi_write(6);
     spi_write(13);
     CS = 1;


}

void display(char hoursdisp, char minsdisp, char secsdisp) {
    char dig0, dig1, dig2, dig3, dig4, dig5;
    //SET DECODE MODE   (code B)
    CS = 0;
    spi_write(0x9);
    spi_write(0xFF);
    CS = 1;
    
    dig0 = hoursdisp / 10;
    if (hoursdisp > 9) { dig1 = hoursdisp - (10 * dig0); }
    else { dig1 = hoursdisp; }

    dig2 = minsdisp / 10;
    if (minsdisp > 9) { dig3 = minsdisp - (10 * dig2); }
    else { dig3 = minsdisp; }

    dig4 = secsdisp / 10;
    if (secsdisp > 9) { dig5 = secsdisp - (10 * dig4); }
    else { dig5 = secsdisp; }

    //write hours to display
    CS = 0;
    spi_write(1);
    spi_write(dig0);
    CS = 1;
    CS = 0;
    spi_write(2);
    spi_write(dig1+128);
    CS = 1;

    //write mins to display
    CS = 0;
    spi_write(3);
    spi_write(dig2);
    CS = 1;
    CS = 0;
    spi_write(4);
    spi_write(dig3+128);
    CS = 1;
    
    //write secs to display
    CS = 0;
    spi_write(5);
    spi_write(dig4);
    CS = 1;
    CS = 0;
    spi_write(6);
    spi_write(dig5);
    CS = 1;	
}

void main()
{
	ANSEL = 0;
	PORTA = 0;
	PORTB = 0;
	TRISA = 0x1F;
	TRISB5 = 0;
	TRISB0 = 0;
	
	spi_init();
	displaystartup();
	
    debouncecount = 0; timelocked = 0; yearbitcount = 0; timebitcount = 0;
    monthbitcount = 0; countcheck = 0; currenthours = 0; counter = 0;
	year=0; yearmonth=0; daymonth=0; hours=0; mins=0;
	
    //read the current eeprom address pointer from address 0 in the eeprom
    //if it's FF then it's a new PIC, set address to 0
    eepromaddress = eeprom_read(0);
    if (eepromaddress == 0xFF) {
       eepromaddress = 1;
       eeprom_write(0,1);
    }
      
    display(12,34,56);
    	
	while (1) {
		while (TIMESIG);
        while (!TIMESIG);
        //have we not had the time in 120 cycles?
        countcheck += 1;
        if (countcheck > 120) { displayerror(); timelocked = 0; }    
        if (newmin) {             //it's the exact first second of a new minute
			newmin = 0;
			if (failedparity) { failedparity = 0; goto timeerror; }
        	if (!DEBUGON) display(hours,mins,0);    // SEND hours AND mins TO display
        	currenthours = hours;
        	currentmins = mins;
        	currentyear = year;
        	currentmonth = yearmonth;
        	currentdaymonth = daymonth;
        	//**** set the intensity based on the time
        	if (!currenthours) setintensity(0); 
        	if (currenthours > 8) setintensity(0x5); 
        	if (currenthours > 21) setintensity(0); 
        	//** end of set intensity
        	//**** write the current time to the eeprom if it's a multiple of 10
        	if (!currentmins % 10) {
				if (eepromaddress == 255) eepromaddress = 1;
          		eeprom_write(eepromaddress, currenthours);
           		eeprom_write(eepromaddress + 1, currentmins);
           		eepromaddress = eepromaddress + 2;
           		eeprom_write(0, eepromaddress);
        	}
        	//*** end of eeprom write
        	DSTLED = dst;
        	timelocked = 1;
timeerror:
        	countcheck = 0;
        	timebitcount = 0;
        	yearbitcount = 0;
        	monthbitcount = 0;
    	}    	
    	counter += 1;     
       	if (DEBUGON) timelocked = 0;   
        if (timelocked) if (counter < 60) display(currenthours,currentmins,counter);   //update the time because we're in a new second
        DelayMs(100);	
        	
       	decode = 0;
       	for (a=1; a<101; a++) { 
			if (TIMESIG) decode += 1;
            DelayMs(1);
        }		
	 	decodeb=0;
        for (a=1; a<101; a++) { 
           	if (TIMESIG) decodeb += 1;
           	DelayMs(1);
       	}
       	decodec=0;
       	for (a=1; a<101; a++) { 
           	if (TIMESIG) decodec += 1;
           	DelayMs(1);
       	}
       	
    	if (DEBUGON) display(decode,decodeb,decodec);          
        if (decode > 30) decode = 1;
        else decode = 0;
        if (decodeb > 30) decodeb = 1;
        else decodeb = 0;
        if (decodec > 30) decodec = 1;
        else decodec = 0;
        if (decodec) { hours = 0; mins = 0; year = 0; yearmonth = 0; daymonth = 0; counter = 0; }  //first sec of new minute
       
        DelayBigMs(300);
        
		switch (counter) {
			case 17: if (decode) { year += 80; yearbitcount += 1; } break;
			case 18: if (decode) { year += 40; yearbitcount += 1; } break;
			case 19: if (decode) { year += 20; yearbitcount += 1; } break;	
			case 20: if (decode) { year += 10; yearbitcount += 1; } break;
			case 21: if (decode) { year += 8; yearbitcount += 1; } break;
			case 22: if (decode) { year += 4; yearbitcount += 1; } break;
			case 23: if (decode) { year += 2; yearbitcount += 1; } break;
			case 24: if (decode) { year += 1; yearbitcount += 1; } break;		
			case 25: if (decode) { yearmonth += 10; monthbitcount +=1; } break;
			case 26: if (decode) { yearmonth += 8; monthbitcount +=1; } break;
			case 27: if (decode) { yearmonth += 4; monthbitcount +=1; } break;
			case 28: if (decode) { yearmonth += 2; monthbitcount +=1; } break;
			case 29: if (decode) { yearmonth += 1; monthbitcount +=1; } break;
			case 30: if (decode) { daymonth += 20; monthbitcount +=1; } break;
			case 31: if (decode) { daymonth += 10; monthbitcount +=1; } break;
			case 32: if (decode) { daymonth += 8; monthbitcount +=1; } break;
			case 33: if (decode) { daymonth += 4; monthbitcount +=1; } break;
			case 34: if (decode) { daymonth += 2; monthbitcount +=1; } break;
			case 35: if (decode) { daymonth += 1; monthbitcount +=1; } break;
			case 39: if (decode) { hours += 20; timebitcount += 1; } break;
			case 40: if (decode) { hours += 10; timebitcount += 1; } break;
			case 41: if (decode) { hours += 8; timebitcount += 1; } break;
			case 42: if (decode) { hours += 4; timebitcount += 1; } break;
			case 43: if (decode) { hours += 2; timebitcount += 1; } break;
			case 44: if (decode) { hours += 1; timebitcount += 1; } break;
			case 45: if (decode) { mins += 40; timebitcount += 1; } break;
			case 46: if (decode) { mins += 20; timebitcount += 1; } break;
			case 47: if (decode) { mins += 10; timebitcount += 1; } break;
			case 48: if (decode) { mins += 8; timebitcount += 1; } break;
			case 49: if (decode) { mins += 4; timebitcount += 1; } break;
			case 50: if (decode) { mins += 2; timebitcount += 1; }  break;
			case 51: if (decode) { mins += 1; timebitcount += 1; }  break;
			case 54: if (!DEBUGON) { if (!((decodeb + yearbitcount)%2)) { displaypfail(); timelocked = 0; failedparity = 1; } }  break;
			case 55: if (!DEBUGON) { if (!((decodeb + monthbitcount)%2)) { displaypfail(); timelocked = 0; failedparity = 1; } }  break;
			case 57: if (!DEBUGON) { if (!((decodeb + timebitcount)%2)) { displaypfail(); timelocked = 0; failedparity = 1; } }  break;
			case 58: dst = decodeb; break;
			case 59: newmin = 1; break;
		}		
	}
}


