// INTERRUPT-DRIVEN serial code
//used as an example in the serial communication doc.     
            
#include <mega32.h>
#include <stdio.h>      

//timeout values for each task
#define t1 10       // samples at 0.1 milliseconds
#define t2 50       //set this to 50 --> recognizes the pattern at 0.5 milliseconds / bit

//I like these definitions
#define begin {
#define end   }

//the  subroutines
void task1(void);  //some task for serial port
void task3(void);       // tests if button is pushed --> state machine
void task4(void);       // after sampling complete, processes button press

void gets_int(void); //starts getting a string from serial line
void puts_int(void); //starts a send to serial line
void initialize(void); //all the usual mcu stuff
         
unsigned int time1, /*time2*/ ; //task scheduling timeout counters
unsigned int time3, time4;       //time for task 3 and 4
unsigned long time;
unsigned int v;                  //option selector from serial port

//eeprom variables
eeprom int a;      //dummy
eeprom int rbuttons[26];  //this one stores the opcodes for the buttons

int buttons[26] = {16447, 8287, 24607, 4207, 20527, 12367, 28687, 2167, 18487, 127, 10327, 29707, 11347, 15427, 9307, 1147, 21547, 31747, 27667, 17467, 25627, 7267, 23587, 30727, 14407, 19507};
int buttons2[26]; //buttons is default buttons for remote 1; button2 is used for comparison
//RXC ISR variables
unsigned char r_index;  //current string index
unsigned char r_buffer[16]; //input string
unsigned char r_ready;  //flag for receive done
unsigned char r_char;  //current character 

//TX empth ISR variables
unsigned char t_index;  //current string index
unsigned char t_buffer[16]; //output string
unsigned char t_ready;  //flag for transmit done
unsigned char t_char;  //current character

char IR=0;       //this variable is 0 / 1 depending on IR signal                                     
int count=0;     //this variable keeps track of how many ones in each pulse
int trak = 0;    //this variable does 'trak'ing of the array keep[70]
int fl = 0;      //this is the state variable 
int previous = 0;      
int va;
                
int keep[70];    //128 bit number --> reduced to 32 integer array pattern (store in an array of 70) 

//variables used elsewhere
int menu;            //menu selection
int lpvar;           //loop variable
int update_key_var;  //keeps track of button numbers  
int last;            //one behind update_key_var
   
//**********************************************************
//timer 0 overflow ISR
interrupt [TIM0_COMP] void timer0_compare(void)
begin  
   time++;
  //Decrement the three times if they are not already zero
  if (time1>0) --time1;
 // if (time2>0) --time2;  
   if (time3>0) --time3;
  if (time4>0) --time4;
end 

//**********************************************************
//**********************************************************
//UART character-ready ISR
interrupt [USART_RXC] void uart_rec(void)
begin
r_char=UDR;    //get a char
UDR=r_char;    //then print it
//build the input string
if (r_char != '\r') r_buffer[r_index++]=r_char;
else
begin
putchar('\n');  //use putchar to avoid overwrite
r_buffer[r_index]=0x00;    //zero terminate
r_ready=1;    //signal cmd processor
UCSRB.7=0;   //stop rec ISR
end
end

/**********************************************************/
//UART xmit-empty ISR
interrupt [USART_DRE] void uart_send(void)
begin
t_char = t_buffer[++t_index];
if (t_char == 0)
begin
UCSRB.5=0; //kill isr
t_ready=1; //transmit done
end
else UDR = t_char ;     //send the char
end
/**********************************************************/
//**********************************************************      
//Entry point and task scheduler loop
void main(void)
begin 
  initialize();

  //main task scheduler loop -- never exits!
  while(1)
  begin  
 
 
  if (PINA==0x01)
  {
   PORTC=0x00;   //initiates PORTC to output at 0 --> no signal
  }
 
 
     //runs the tasks
    if (time1==0) task1();
   // if (time2==0) task2(); 
   if(trak<34)
    if (time3==0) task3();    
   if(trak==34)
    if (time4==0) task4();
    
     //this below is menu options for serial port communication with Atmel MEGA32
     menu = v;
     switch(menu) //menu selection
     {
     case 1:    //this case loading default values back into the system
     {
    for(lpvar = 0; lpvar < 26; lpvar++)
    {
    rbuttons[lpvar] =  buttons[lpvar];
    }
    v = 5;
     }
     break;
     case 2:   //this case allows you to reprogram all the buttons
     {  
if(update_key_var == 9999)
{
putsf("Enter a remote key for each appearing button\r\n");
for(lpvar = 0; lpvar < 26; lpvar++)
{
 buttons2[lpvar] = 0;
}   
last = update_key_var;
update_key_var = 0;
}
   
    //prompts user for each button type to get
   if((update_key_var != last) && (update_key_var != 26))
   {
   if(update_key_var < 9)
   {
sprintf(t_buffer, "%i\r", update_key_var+1);
   puts(t_buffer);
  }
else if(update_key_var == 10)
putsf("channel down\r");
else if(update_key_var == 9)
putsf("0\r");
else if(update_key_var == 11)
putsf("channel up\r");
else if(update_key_var == 12)
putsf("volume up\r");     
else if(update_key_var == 13)
putsf("volume down\r");
else if(update_key_var == 14)
putsf("POWER\r");     
else if(update_key_var == 15)
putsf("button below POWER\r");     
else if(update_key_var == 16)
putsf("TV-FM Toggle\r");     
else if(update_key_var == 17)
putsf("return\r");
else if(update_key_var == 18)
putsf("reverse\r");     
else if(update_key_var == 19)
putsf("point left\r");    
else if(update_key_var == 20)
putsf("point right\r");     
else if(update_key_var == 21)
putsf("mute\r");     
else if(update_key_var == 22)
putsf("minimise\r");     
else if(update_key_var == 23)
putsf("camera\r");     
else if(update_key_var == 24)
putsf("camcorder\r");     
else if(update_key_var == 25)
putsf("source\r");     
 
last = update_key_var;
}

    if(update_key_var==26)          //shoves the new op codes into the system
    {
    for(lpvar = 0; lpvar < 26; lpvar++)
    {
    rbuttons[lpvar] =  buttons2[lpvar];
    }
   update_key_var = 9999;                  
v = 5;
}
     }break;
               
     case 3:      // this button allows you to program just the number buttons
     {
     if(update_key_var == 9999)
{
putsf("Enter a remote key for each appearing button\r\n");
for(lpvar = 0; lpvar < 26; lpvar++)
{
 buttons2[lpvar] = 0;
}   
last = update_key_var;
update_key_var = 0;
}
   
    //prompts the user for each number button to get
   if((update_key_var != last) && (update_key_var != 26))
   {
   if(update_key_var < 9)
   {
sprintf(t_buffer, "%i\r", update_key_var+1);
   puts(t_buffer);
  }
  else if(update_key_var == 9)
putsf("0\r");
last = update_key_var;
}

    if(update_key_var==10)      //shoves the new opcodes into the system
    {
    for(lpvar = 0; lpvar < 26; lpvar++)
    {
    rbuttons[lpvar] =  buttons2[lpvar];
    }
   update_key_var = 9999;                  
v = 5;
}
     }break;
    
     case 5:                   //prints the menu
     {
     putsf("\r\nIR Remote Control Menu:\r\n"); 
   putsf("[1] Set / Reset Default Keys: \r\n");
   putsf("[2] Re-Program All Keys: \r\n");
     putsf("[3] Re-Program Number Keys: \r\n");
   putsf("[4] Test Keys \r\n");
   putsf("[5] Menu \r\n");      
     v = 0;
     }break;
    
     default:
     {
     }break;
    
     }
         
     end  
end 


 
//**********************************************************         
//**Simple State Machine for Sampling**////////////////////
int tog = 0;
void task3(void)
{  
  time3=t1;   
IR = PINB & 0b00000001;    

  if (fl==0)
{
if (IR==0)        //state triggers if first enormous zero dip detected
{
fl=1;
   count = 0;
}
}
else                  //remains in this state until signal is gotten
{
if (IR==1)         

count++;
}
else
{
   if((count > 38) && (count < 50)) //this detects start sequence ~42 to 47 counts
   tog = 1;

  if(tog == 1) //update track
   {
   keep[trak] = count;
   if(count != 0 )  //this throws away the zero and keeps the ones
trak++;
}
count = 0;
      
}

}   

}

 
int tt=0;   //this variable is a tracking variable for the array keep 
int num = 0; //this variable is a conversion of the 33 integer array into a 16-bit integer

void task4(void)
{                     
//putsf("success\r\n");
time4=t2;
//if (trak == 34 && tt != 34) 
//if(tt>15 && tt < 32)
//sprintf(t_buffer, "%i, %i\r", keep[tt], tt);
//puts(t_buffer);                 
  
 tt++;          
 if(tt == 34)  //if count hits 34 we do pattern matching to discover button
{

 //putsf("stop!");
 //sprintf(t_buffer, "%i", num);
 //puts(t_buffer); 
  
  trak = 0;  //reset trak variable to 0
  tt = 0;    //reset another trak-like variable to 0       
  fl = 0;    //reset state machine for sampling
    //the following code is repetitive but slightly different
    //PORTC sends out a signal for which button was pressed
    //if(v==4) then a display is sent for what button is pressed
    //on to the serial port terminal
if(num == rbuttons[0])
{
   if(v == 0)
   PORTC = 0x01;
    if(v == 4)
putsf("1\r\n"); 
}  

else if(num == rbuttons[1])
{
if(v == 0)
   PORTC = 0x02;
    if(v == 4)
putsf("2\r\n");
}   

else if(num == rbuttons[2])
{
if(v == 0)
   PORTC = 0x03;   
if(v == 4)
putsf("3\r\n");


else if(num == rbuttons[3])
{
if(v == 0)
   PORTC = 0x04; 
if(v == 4)
putsf("4\r\n");
}        

else if(num == rbuttons[4])
{
   if(v == 0)
   PORTC = 0x05;
if(v == 4)
putsf("5\r\n");
}       

else if(num == rbuttons[5])
{
   if(v == 0)
   PORTC = 0x06; 
if(v == 4)
putsf("6\r\n");
}        

else if(num == rbuttons[6])
{
   if(v == 0)
   PORTC = 0x07; 
if(v == 4)
putsf("7\r\n");
}       

else if(num == rbuttons[7])
{
   if(v == 0)
   PORTC = 0x08;    
if(v == 4)
putsf("8\r\n");
}   

else if(num == rbuttons[8])
{
   if(v == 0)
   PORTC = 0x09;
if(v == 4)
putsf("9\r\n");
}   

else if(num == rbuttons[10])
{
   if(v == 0)
   PORTC = 0x0A;       
if(v == 4)
putsf("Channel Down\r\n");
}   

else if(num == rbuttons[9])
{
   if(v == 0)
   PORTC = 0x0B;
if(v == 4)
putsf("0\r\n");
}   

else if(num == rbuttons[11])
{          
   if(v == 0)
   PORTC = 0x0C;
if(v == 4)
putsf("Channel Up\r\n");
}     

else if(num == rbuttons[12])
{         
   if(v == 0)
   PORTC = 0x0D;
if(v == 4)
putsf("Volume Up\r\n");
}

else if(num == rbuttons[13])
{
   if(v == 0)
   PORTC = 0x0E;
if(v == 4)
putsf("Volume Down\r\n");
}        

else if(num == rbuttons[14])
{         
   if(v == 0)
   PORTC = 0x0F;
if(v == 4)
putsf("POWER\r\n");
}        
               
else if(num == rbuttons[15])
{          
   if(v == 0)
   PORTC = 0x10;
if(v == 4)
putsf("TV-FM Toggle\r\n");
}        
               
else if(num == rbuttons[16])
{          
   if(v == 0)
   PORTC = 0x11;
if(v == 4)
putsf("Button below POWER\r\n");
}        
               
else if(num == rbuttons[17])
{
   if(v == 0)
   PORTC = 0x12;         
if(v == 4)
putsf("Return\r\n");
}     
                  
else if(num == rbuttons[18])
{
   if(v == 0)
   PORTC = 0x13;    
if(v == 4)
putsf("Reverse\r\n");
}   
                    
else if(num == rbuttons[19])
{
   if(v == 0)
   PORTC = 0x14;    
if(v == 4)
putsf("Point Left\r\n");
}           
              
else if(num == rbuttons[20])
{
   if(v == 0)
   PORTC = 0x15;
  if(v == 4)
putsf("Point Right\r\n");
}            
           
else if(num == rbuttons[21])
{
   if(v == 0)
   PORTC = 0x16;  
if(v == 4)
putsf("Mute\r\n");
}       
               
else if(num == rbuttons[22])
{
   if(v == 0)
   PORTC = 0x17;     
if(v == 4)
putsf("Minimise\r\n");
}          
             
else if(num == rbuttons[23])
{
   if(v == 0)
   PORTC = 0x18;         
if(v == 4)
putsf("Camera-Snap\r\n");
}      
                 
else if(num == rbuttons[24])
{
   if(v == 0)
   PORTC = 0x19;
if(v == 4)
putsf("Camcorder-Record\r\n");
}  
                     
else if(num == rbuttons[25])
{
   if(v == 0)
   PORTC = 0x1A;       
if(v == 4)
putsf("Source\r\n");


else
{
if((v != 2) && (v !=3))
putsf("Invalid Entry\n\r"); 
}
    //the following if statement checks if a previous button has already been programmed/registered in the system
if((v == 2) || (v == 3))
{
    if((buttons2[0] == num )|| (buttons2[1] == num )||(buttons2[2] == num )||(buttons2[3] == num )||(buttons2[4] == num )||
    (buttons2[5] == num )||(buttons2[6] == num )||(buttons2[7] == num )||(buttons2[8] == num )||(buttons2[9] == num )||
    (buttons2[10] == num )||(buttons2[11] == num )||(buttons2[12] == num )||(buttons2[13] == num )||(buttons2[14] == num )||
    (buttons2[15] == num )||(buttons2[16] == num )||(buttons2[17] == num )||(buttons2[18] == num )||(buttons2[19] == num )||
    (buttons2[20] == num )||(buttons2[21] == num )||(buttons2[22] == num )||(buttons2[23] == num )||(buttons2[24] == num )||
    (buttons2[25] == num ))
     previous = 1;
    
if(previous == 0)
{
buttons2[update_key_var] = num;
update_key_var++;
}
else
putsf("You have already programmed this key!\n\r");
}
  
previous = 0;
   tog = 0;
   num = 0;      
  }
 //this part changes a 33 bit number into a 16 bit int
 //we throw away the first 16 bit because they are the same for all buttons
 if((tt>15) && (tt < 32)){
 if(keep[tt] < 10)
 {
 num = num << 1;  
 //putsf("less than 10\r");
 }
 if(keep[tt] > 10)  
  {
 num = num << 1;
 num = num + 0x0001; 
 //putsf("greater than 10\r"); 
 
 }
   
 
 }
 
 }


//Task 1   input a string and print it
void task1(void)
begin

  time1=t1;  //reset the task timer
  //print ad get another serial string     
  if (r_ready )   
  begin
  sscanf(r_buffer,"%d",&v);
    gets_int();    
  end    
end 
 
void gets_int(void)
begin
  r_ready=0;
  r_index=0;
  UCSRB.7=1;
end

//**********************************************************
//  -- nonblocking print: initializes ISR-driven
// transmit. This routine merely sets up the ISR, then
//send one character, The ISR does all the work.  
void puts_int(void)
begin
  t_ready=0;
  t_index=0;
  if (t_buffer[0]>0)
  begin
  putchar(t_buffer[0]);
  UCSRB.5=1;
 end
end

//**********************************************************
//Set it all up
void initialize(void)
begin
  
  //serial setop for debugging using printf, etc.    
  UCSRB = 0x18 ;
  UBRRL = 103 ;    
  DDRC = 0xFF;
  DDRA = 0x00;
 
  PORTC=0x00;
 
 
  putsf("\r\nRemote Control Menu:\r\n"); 
  putsf("[1] Set / Reset Default Keys: \r\n");
  putsf("[2] Re-Program All Keys: \r\n");
  putsf("[3] Re-Program Number Keys: \r\n");
  putsf("[4] Test Keys \r\n");
  putsf("[5] Menu \r\n");

  //set up timer 0    
  OCR0=20;    //0.01 mSec  /20   --> x 10 = 0.1 mSec
  TIMSK=2;    //turn on timer 0 cmp-match ISR
  TCCR0=0b00001010; //prescalar to 8 and Clr-on-match
 
  //GICR = 0b10000000;
 // MCUCR = 0b00001100;
  //init the task timers
  time1=t1;
 // time2=t2;   
 time3 = t1;
 time4 = t2;
 
  r_ready=0;
  t_ready=1;      

  trak = 0; 
  menu = 0;
  lpvar = 0;
  update_key_var = 9999;
  last = 0;
 // gettime = 0;
 // sendout = 0;
    
  //crank up the ISRs
  #asm
  sei
  #endasm 
 
  gets_int();
end