/*




                                       PRO mini+
                                      +--------------------------------+ 
                                      |          o o o o o o           |
                                      | o D1(TxD)                 +V o | 
                                      | o D0(RxD)                GND o | 
                                      | o RST   +-----------+    RST o | 
                                      | o GND   |O          |    VCC o | 
                                   D2 | o D2    |           |     C3 o | /RD
                                   D3 | o D3    |           |     C2 o | /WR
                                   D4 | o D4    | ATMEGA328 |     C1 o | /CS
                                   D5 | o D5    |           |     C0 o | ALE
                                   D6 | o D6    |           |     B5 o |           IR?
                                   D7 | o D7    +-----------+     B4 o | DATA
                                   D0 | o B0           C6 o C7 o  B3 o | CLK
                                   D1 | o B1           C4 o C5 o  B2 o | STB
                                      |                                |
                                      +--------------------------------+


*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include "74LS595.h"
#include "7seg.h"
#include "bcd.h"
#include "ds1287.h"
#include "mcs85bus.h"
#include "IR.h"

/*****************************| DEFINIATIONS |********************************/

#define OUTPUT             1
#define INPUT              0

#define Error          0
#define TellTime       1
#define SetTime        2
 
/************************| FUNCTION DECLARATIONS |*************************/
 
void Delay(unsigned int delay);
void Delay2(unsigned int delay);
unsigned char IRCodeTanslate(unsigned char code);
unsigned char GetTime(void);
void showTime(void);


/****************************| CODE... |***********************************/

int main (void) {

  unsigned char mode;
 
  // set up directions 
  DDRB = (INPUT << PB0 | INPUT << PB1 |OUTPUT << PB2 |OUTPUT << PB3 |OUTPUT << PB4 |INPUT << PB5 |INPUT << PB6 |INPUT << PB7);
  DDRC = (OUTPUT << PC0 | OUTPUT << PC1 |OUTPUT << PC2 |OUTPUT << PC3 |INPUT << PC4 |INPUT << PC5 |INPUT << PC6 );
  DDRD = (INPUT << PD0 | INPUT << PD1 |INPUT << PD2 |INPUT << PD3 |INPUT << PD4 |INPUT << PD5 |INPUT << PD6 |INPUT << PD7);         
  
  mode = TellTime;
  
  DS1287Init();
  IRInit();
  sei();
  
  while(1) {
    
    if(IRDataReady()) {
      if (IRData == 0x8B ) {
	  if (mode == TellTime) { mode = SetTime;   }
	  else                  { mode = TellTime; IRClrDR();}	      
      }
    }
    
    if (0) {
    } else if (mode == TellTime) { showTime(); 
    } else if (mode == SetTime)  { GetTime();
    }
  
  }
   
}

unsigned char GetTime() {  

  unsigned char digits[3];
  static unsigned char p;
  static unsigned char mins, hrs;
  unsigned char d; 
   
  d =  IRCodeTanslate(IRData);
   
  if ((IRDataReady()) != 0) {
    if (0) {
    } else if (IRData == 0x8B) {
      p    = 0;
      mins = 0;
      hrs  = 0;
    } else if (d < 10) {
      if (0) {
      } else if (p == 0) { // set hours 10
        hrs = d * 10;	
	p++;
      } else if (p == 1) { // set hours 1
        hrs += d;
	p++;
      } else if (p == 2) { // set mins  10
        mins = d * 10;
	p++;
      } else if (p == 3) { // set mins  1
        mins += d;
	p++;
	if (hrs > 12) { hrs = 12;  }
	if (mins > 59){ mins = 59; }
	DS1287SetMinutes(mins);
        DS1287SetHours(hrs);
	DS1287SetSeconds(0);
	return 1;
      }                
    } else {
     // wtf is the user doing?
    } 
     IRClrDR();        
  }
  
    LS595StrobeL();
    
    if ( p == 0) { // set hours 10's
      LS595Send(0);
      LS595Send(0);
      LS595Send(0);
      if ((DS1287GetSeconds() & 1) != 0) {   LS595Send(6); }  else LS595Send(0);
      
    }
    if ( p == 1) { // set hours 1's
      bin2bcd(hrs, digits); 
      LS595Send(0);
      LS595Send(0);
      if ((DS1287GetSeconds() & 1) != 0) {   LS595Send(0); }  else LS595Send(16);
      if (digits[1] == 0) LS595Send(0); else LS595Send(6);
    }
    if ( p == 2) { // set minutes 10's
      bin2bcd(hrs, digits); 
      LS595Send(0);
      if ((DS1287GetSeconds() & 1) != 0) {   LS595Send(0); }  else LS595Send(16);
      LS595Send(CG[digits[0]]<<1);
      if (digits[1] == 0) LS595Send(0); else LS595Send(6);
    }
   if ( p == 3) { // set minutes 10's
      bin2bcd(mins, digits); 
      if ((DS1287GetSeconds() & 1) != 0) {   LS595Send(0); }  else  LS595Send(16);
      LS595Send(CG[digits[1]]<<1);
      bin2bcd(hrs, digits); 
      LS595Send(CG[digits[0]]<<1);
      if (digits[1] == 0) LS595Send(0); else LS595Send(6);
    }
    if ( p == 4) { // set minutes 10's
      bin2bcd(mins, digits); 
      LS595Send(CG[digits[0]]<<1);
      LS595Send(CG[digits[1]]<<1);
      bin2bcd(hrs, digits); 
      LS595Send(CG[digits[0]]<<1);
      if (digits[1] == 0) LS595Send(0); else LS595Send(6);
    }
    
    LS595StrobeH(); 
  
    return 0;
}


void showTime(void) {
   unsigned char digits[3];
   
    LS595StrobeL();
    bin2bcd(DS1287GetMinutes(), digits);
    LS595Send(CG[digits[0]]<<1);
    LS595Send(CG[digits[1]]<<1);
    
    bin2bcd((DS1287GetHours() & 0x0F), digits);
    LS595Send(CG[digits[0]]<<1);
    
    if (digits[1] == 0) {
     if ((DS1287GetSeconds() & 1) != 0) { LS595Send(0);} else { LS595Send(24); }
    } else {
     if ((DS1287GetSeconds() & 1) != 0) { LS595Send(6);} else { LS595Send(6+24); }
    }

    LS595StrobeH(); 

}


void Delay(unsigned int delay) {
  unsigned int x;
  for (x = delay; x != 0; x--) {
    asm volatile ("nop"::); 
  }
}

void Delay2(unsigned int delay) {
  unsigned int x;
  for (x = delay; x != 0; x--) {
    Delay(65000);
  }
}


unsigned char IRCodeTanslate(unsigned char code) {
  switch(code) {
    case 0x1F: return 0;
    case 0x07: return 1;
    case 0x5D: return 2;
    case 0x55: return 3;
    case 0x4D: return 4;
    case 0x45: return 5;
    case 0x3E: return 6;
    case 0x36: return 7;
    case 0x2E: return 8;
    case 0x26: return 9;
    case 0x6C: return 10; // up
    case 0x64: return 11; // down
    case 0x9B: return 12; // mute
    case 0x7C: return 13; // Vup
    case 0x74: return 14; // Vdown
    case 0x8B: return 15; // on/off
  }
  return 255;

}
