//******************************************************************************
//  XBMC USB Controller firmware. Version 1.0.0.31
//  Copyright © 2011 Dilshan R Jayakody.
//
//  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
//  the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
//******************************************************************************

#include <built_in.h>

unsigned char readbuff[64] absolute 0x500;
unsigned char writebuff[64] absolute 0x540;
char cnt, ren_pointer;
char remote_command;
int remote_id, tmp_out;
unsigned int ren_timer;
bit home_sw, back_sw;
bit rotery_mode, rotery_push, update_lcd;
bit disp_switch, is_advance;

sbit LCD_RS at RB4_bit;
sbit LCD_EN at RB5_bit;
sbit LCD_D4 at RB0_bit;
sbit LCD_D5 at RB1_bit;
sbit LCD_D6 at RB2_bit;
sbit LCD_D7 at RB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;

void GetRotaryState()
{
   if(PORTD.B1 != rotery_mode)
   {
      Delay_us(25);
      remote_command = 1;
      if(PORTD.B0 == 0)
         remote_id = 1;
      else
         remote_id = 2;
      rotery_mode = PORTD.B1;
   }
   if(PORTD.B2 != rotery_push)
   {
      if(PORTD.B2 == 0)
      {
         remote_command = 2;
         remote_id = 0;
      }
      rotery_push = PORTD.B2;
   }
   if(PORTD.B4 != home_sw)
   {
      if(PORTD.B4 == 0)
      {
         remote_command = 2;
         remote_id = 1;
      }
      home_sw = PORTD.B4;
   }
   if(PORTD.B5 != back_sw)
   {
      if(PORTD.B5 == 0)
      {
         remote_command = 2;
         remote_id = 2;
      }
      back_sw = PORTD.B5;
   }
}

void GetSIRCValue()
{
   char pos = 0;
   char i;
   remote_command = 0;
   remote_id = 0;
   while((PORTE.B0 == 0) && (pos < 26))
   {
      Delay_us(100);
      pos++;
   }
   if(pos == 25)
   {
     for(i = 0; i < 21; i++)
     {
        tmp_out = 0;
        while((PORTE.B0 == 1) && (tmp_out < 12001))
        {
           Delay_us(1);
           tmp_out++;
        }
        if(tmp_out<12001)
        {
           pos = 0;
           while((PORTE.B0 == 0) && (pos < 20))
           {
              Delay_us(100);
              pos++;
           }
           if(pos > 10)
           {
              if(i<8)
                 remote_command |= (1<<i);
              else
                 remote_id |= (1<<(i-8));
           }
        }
        else
        {
           remote_command = 0;
           break;
        }
     }
   }
}

void ResetLCD()
{
   Lcd_Cmd(_LCD_CLEAR);
   Lcd_Out(1,1,"Welcome to XBMC");
}

void EchoUSBInfo()
{
   char pos_;
   is_advance = 1;
   for(pos_ = 0; pos_ < 17; pos_++)
      if(readbuff[4+ren_pointer+pos_]==0)
      {
         is_advance = 0;
         Lcd_Chr(2, pos_+1, ' ');
      }
      else
         Lcd_Chr(2, pos_+1, readbuff[4+ren_pointer+pos_]);
   ren_pointer = (is_advance==1) ? (ren_pointer+1) : 0;
}

void PrintUSBInfo()
{
   char pos_;
   if((readbuff[1]>67) || (readbuff[1]<65))
      ResetLCD();
   else
   {
      Lcd_Cmd(_LCD_CLEAR);
      switch(readbuff[1])
      {
         case 65 : Lcd_Out(1,1, "Audio"); break;
         case 66 : Lcd_Out(1,1, "Video"); break;
         case 67 : Lcd_Out(1,1, "Picture"); break;
      }
      switch(readbuff[2])
      {
         case 66 : Lcd_Out(1,9, ": Play"); break;
         case 67 : Lcd_Out(1,9, ": Pause"); break;
      }
      update_lcd = ((readbuff[1]<67) && (readbuff[2]>65));
      if(update_lcd)
      {
         ren_pointer = 0;
         EchoUSBInfo();
         ren_timer = 0;
         update_lcd = 1;
      }
   }
}

void interrupt()
{
   USB_Interrupt_Proc();
}

void main(void)
{
   ADCON1 |= 0x0F;
   CMCON  |= 7;
   TRISE = 7;
   TRISA = 0;
   TRISD = 127;

   ren_pointer = 0;
   rotery_mode = 0;
   rotery_push = 0;
   update_lcd = 0;
   disp_switch = 0;
   home_sw = 0;
   back_sw = 0;
   
   HID_Enable(&readbuff, &writebuff);
   for(cnt=0;cnt<64;cnt++)
      writebuff[cnt]= 0;
   Lcd_Init();
   Lcd_Cmd(_LCD_CURSOR_OFF);
   ResetLCD();
   
mainloop:

      if(HID_Read() > 0)
         PrintUSBInfo();
      
      GetSIRCValue();
      if(remote_command == 0)
         GetRotaryState();
         
      if(remote_command != 0)
      {
         writebuff[0] = 184;
         writebuff[1] = 1;
         writebuff[2] = remote_command;
         writebuff[3] = Lo(remote_id);
         writebuff[4] = Hi(remote_id);
         
         while(!HID_Write(&writebuff,64));
      }
      
      disp_switch = !disp_switch;
      if(update_lcd && disp_switch)
      {
         ren_timer++;
         if(ren_timer >= 45000)
         {
            ren_timer = 0;
            EchoUSBInfo();
         }
      }
   goto mainloop;
}