#include "main.h"

/* Includes ------------------------------------------------------------------*/
#include "RC5_IR_Emul_Receiver.h"
#include "stm324xg_eval_eeprom.h"
  
/* Private typedef -----------------------------------------------------------*/
typedef enum { NOTOK = 0, OK = !NOTOK} BitTimigStatus;

/* Private define ------------------------------------------------------------*/
#define   NOMINAL_HALF_BIT_TIME_US   889  /* Nominal half bit time in µs */
#define   MIN_HALF_BIT_TIME_US       640  /* Minimum half bit time in µs */
#define   MAX_HALF_BIT_TIME_US       1140 /* Maximum half bit time in µs */

#define   NOMINAL_FULL_BIT_TIME_US   1778 /* Nominal Full bit time in µs */
#define   MIN_FULL_BIT_TIME_US       1340 /* Minimum Full bit time in µs */
#define   MAX_FULL_BIT_TIME_US       2220 /* Maximum Full bit time in µs */

#define   RC5_TIM_PRESCALER          2

/* Private macro -------------------------------------------------------------*/
/* Private EdgesNumberiables ---------------------------------------------------------*/
__IO uint8_t EdgesNumber = 0; /* To count the first edges of the frame (max 3 edges) */
StatusYesOrNo Bit4_HasBeen_Sampled = NO; /* To know if the next sampling will be after 3/4 bit time or one bit time */
StatusYesOrNo RC5_FrameReceived = NO; /* Will be used by the user to check if an RC5 has been received or not */
BitTimigStatus BitTimeStatus = OK; /* Variable to store the timing status of the first low duration */
__IO uint8_t FieldBit = 0; /* Bit field value (command between 0-63 or 64-127 */
__IO uint16_t RC5_data[13]; /* Table that contains the value of the GPIOx_IDR register each sampling */
uint8_t RC5_Indexdata = 0; /* Variable that increments each time a RC5 bit is sampled */
__IO uint16_t LowDuration = 0; /* Contains the first low duration in in TIM count */
__IO uint32_t RC5_TIM_CLKValuekHz = 0; /* Contains the frequency input of RC5_TIM in Khz */
uint16_t HalfBitDurationCount_Min = 0; /* Minimum Half bit duration in TIM count */
uint16_t HalfBitDurationCount_Max = 0; /* Maximum Half bit duration in TIM count*/
uint16_t NominalHalfBitDurationCount  = 0; /* Nominal Half bit duration in TIM count */
uint16_t FullBitDurationCount_Min = 0; /* Minimum Full bit duration in TIM count */
uint16_t FullBitDurationCount_Max = 0; /* Maximum Full bit duration in TIM count */
uint16_t NominalBitDurationCount  = 0; /* Nominal Full bit duration in TIM count */
uint16_t NominalBitDurationCount_3div4 = 0; /* 3/4 of nominal bit time in TIM count */
TIM_HandleTypeDef    TimHandle;
StatusYesOrNo RC5_FrameReceived;

RC5Frame_TypeDef RC5_Frame;
uint8_t RC5_TogglePrevious = 0;
StatusYesOrNo FirstTimeIssued = YES;
uint8_t Command_hist; 
uint8_t Disable_Ext; 

/* Table of different Addresses (devices) */
const char* RC5_Devices[32] = {
        "TV1" ,                  /* 0 */
        "TV2" ,                  /* 1 */
        "Video Text" ,           /* 2 */
        "Extension TV",          /* 3 */
        "LaserVideoPlayer",      /* 4 */
        "VCR1",                  /* 5 */
        "VCR2",                  /* 6 */
        "Reserved",              /* 7 */
        "Sat1",                  /* 8 */
        "Extension VCR",         /* 9 */
        "Sat2",                  /* 10 */
        "Reserved",              /* 11 */
        "CD Video",              /* 12 */
        "Reserved",              /* 13 */
        "CD Photo",              /* 14 */
        "Reserved",              /* 15 */
        "Preampli Audio 1",      /* 16 */
        "Tuner",                 /* 17 */
        "Analog Magneto",        /* 18 */
        "Preampli Audio 2",      /* 19 */
        "CD",                    /* 20 */
        "Rack Audio",            /* 21 */
        "Audio Sat Receiver",    /* 22 */
        "DDC Magneto",           /* 23 */
        "Reserved",              /* 24 */
        "Reserved",              /* 25 */
        "CDRW",                  /* 26 */
        "Reserved",              /* 27 */
        "Reserved",              /* 28 */
        "Reserved",              /* 29 */
        "Reserved",              /* 30 */
        "Reserved"               /* 31 */  	             
       };

/* Table of different commands (TV) */
const char* RC5_Commands[128] = {
        "Num0",                                       /* 0 */
        "Num1",                                       /* 1 */
        "Num2",                                       /* 2 */
        "Num3",                                       /* 3 */
        "Num4",                                       /* 4 */
        "Num5",                                       /* 5 */
        "Num6",                                       /* 6 */
        "Num7",                                       /* 7 */
        "Num8",                                       /* 8 */
        "Num9",                                       /* 9 */
        "TV Digits",                                  /* 10 */
        "TV Freq",                                    /* 11 */
        "TV StandBy",                                 /* 12 */
        "TV Mute On-Off",                             /* 13 */
        "TV Preference",                              /* 14 */
        "TV Display",                                 /* 15 */
        "Volume Up",                                  /* 16 */
        "Volume Down",                                /* 17 */
        "Brightness Up",                              /* 18 */
        "Brightness Down",                            /* 19 */
        "Color Saturation Up",                        /* 20 */
        "Color Saturation Down",                      /* 21 */
        "Bass Up",                                    /* 22 */
        "Bass Down",                                  /* 23 */
        "Treble Up",                                  /* 24 */
        "Treble Down",                                /* 25 */
        "Balance Right",                              /* 26 */
        "BalanceLeft",                                /* 27 */
        "TV Contrast Up",                             /* 28 */
        "TV Contrast Down",                           /* 29 */
        "TV Search Up",                               /* 30 */
        "TV tint-hue Down",                           /* 31 */
        "TV CH Prog Up",                              /* 32 */
        "TV CH ProgDown",                             /* 33 */
        "TV Last viewed program-channel",             /* 34 */
        "TV Select stereo sound channel-language",    /* 34 */
        "TV Spacial Stereo",                          /* 36 */
        "TV Stereo Mono",                             /* 37 */
        "TV Sleep Timer",                             /* 38 */
        "TV tint-hue Up",                             /* 39 */
        "TV RF Switch",                               /* 40 */
        "TV Store-VOTE",                              /* 41 */
        "TV Time",                                    /* 42 */
        "TV Scan Fwd Inc",                            /* 43 */
        "TV Decrement",                               /* 44 */
        "Reserved",                                   /* 45 */
        "TV Secondary control-menu",                  /* 46 */
        "TV Show Clock",                              /* 47 */
        "TV Pause",                                   /* 48 */
        "TV Erase Correct Entry",                     /* 49 */
        "TV Rewind",                                  /* 50 */                                 
        "TV Goto",                                    /* 51 */
        "TV Wind",                                    /* 52 */
        "TV Play",                                    /* 53 */
        "TV Stop",                                    /* 54 */
        "TV Record",                                  /* 55 */
        "TV External 1",                              /* 56 */                                 
        "TV External 2",                              /* 57 */
        "Reserved",                                   /* 58 */
        "TV Advance",                                 /* 59 */
        "TV TXT-TV toggle",                           /* 60 */
        "TV System StandBy",                          /* 61 */
        "TV Picture Crispener",                       /* 62 */
        "System Select",                              /* 63 */
        "Reserved",                                   /* 64 */
        "Reserved",                                   /* 65 */
        "Reserved",                                   /* 66 */
        "Reserved",                                   /* 67 */
        "Reserved",                                   /* 68 */
        "Reserved",                                   /* 69 */
        "TV Speech Music",                            /* 70 */
        "DIM Local Display",                          /* 71 */
        "Reserved",                                   /* 72 */
        "Reserved",                                   /* 73 */
        "Reserved",                                   /* 74 */
        "Reserved",                                   /* 75 */
        "Reserved",                                   /* 76 */
        "Increase Linear Control Setting",            /* 77 */
        "Decrease Linear Control Setting",            /* 78 */
        "TV Sound Scroll",                            /* 79 */
        "Step Up",                                    /* 80 */
        "Step Down",                                  /* 81 */
        "Menu On",                                    /* 82 */
        "Menu Off",                                   /* 83 */
        "AV Status",                                  /* 84 */
        "Step Left",                                  /* 85 */
        "Step Right",                                 /* 86 */
        "Acknowledge",                                /* 87 */
        "PIP On Off",                                 /* 88 */
        "PIP Shift",                                  /* 89 */
        "PIP Main Swap",                              /* 90 */
        "Strobe On Off",                              /* 91 */
        "Multi Strobe",                               /* 92 */
        "Main Frozen",                                /* 93 */
        "3div9 Multi scan",                           /* 94 */
        "PIPSelect",                                  /* 95 */                                 
        "MultiPIP",                                   /* 96 */
        "Picture DNR",                                /* 97 */
        "Main Stored",                                /* 98 */
        "PIP Strobe",                                 /* 99 */
        "Recall Main Stored Picture",                 /* 100 */
        "PIP Freeze",                                 /* 101 */
        "PIP Step Up",                                /* 102 */
        "PIP Step Down",                              /* 103 */
        "TV PIP Size",                                /* 104 */
        "TV Picture Scroll",                          /* 105 */
        "TV Actuate Colored Or Other Special Keys",   /* 106 */
        "TV Red",                                     /* 107 */
        "TV Green",                                   /* 108 */
        "TV Yellow",                                  /* 109 */
        "TV Cyan",                                    /* 110 */
        "TV Index White",                             /* 111 */
        "TV Next",                                    /* 112 */
        "TV Previous",                                /* 113 */
        "Reserved",                                   /* 114 */
        "Reserved",                                   /* 115 */
        "Reserved",                                   /* 116 */
        "Reserved",                                   /* 117 */
        "Sub Mode",                                   /* 118 */
        "Option Sub Mode",                            /* 119 */
        "Reserved",                                   /* 120 */
        "Reserved",                                   /* 121 */
        "TV Store Open Close",                        /* 122 */
        "Connect",                                    /* 123 */
        "Disconnect",                                 /* 124 */
        "Reserved",                                   /* 125 */
        "TV Movie Expand",                            /* 126 */
        "TV Parental Access"                          /* 127 */
   };

 
static uint8_t rc5_web = 0;
static RC5Frame_TypeDef RC5_frame_struct;
	 
/* Private function prototypes -----------------------------------------------*/
static void Init_IR(void);
static void RC5_NVIC_Configuration(void);
static uint32_t RC5_TIM_GetCounterCLKValue(void);
static void RC5_WaitForNextFallingEdge(void);

/* Private functions ---------------------------------------------------------*/

void RC5_Receiver_Init(void)
{
  /* Get frequency input of RC5_TIM in Khz */
  RC5_TIM_CLKValuekHz = RC5_TIM_GetCounterCLKValue()/1000;
  
  /* Compute the different timing tolerences in TIM count */
  NominalBitDurationCount =  (RC5_TIM_CLKValuekHz * NOMINAL_FULL_BIT_TIME_US)/1000;
  NominalHalfBitDurationCount = (RC5_TIM_CLKValuekHz * NOMINAL_HALF_BIT_TIME_US)/1000;
  HalfBitDurationCount_Min = (RC5_TIM_CLKValuekHz * MIN_HALF_BIT_TIME_US)/1000;
  HalfBitDurationCount_Max = (RC5_TIM_CLKValuekHz * MAX_HALF_BIT_TIME_US)/1000;
  FullBitDurationCount_Min = (RC5_TIM_CLKValuekHz * MIN_FULL_BIT_TIME_US)/1000;
  FullBitDurationCount_Max = (RC5_TIM_CLKValuekHz * MAX_FULL_BIT_TIME_US)/1000;
  
  /* Compute the 3/4 bit time duration in TIM count */
  NominalBitDurationCount_3div4 = (NominalBitDurationCount * 3)/4;
   
  /* Wait for next falling edge of RC5 frame */
  RC5_WaitForNextFallingEdge();
}


static void RC5_WaitForNextFallingEdge(void)
{
  //EXTI->IMR |= RC5_EXTI_LINE;
	Disable_Ext = 0;
	//HAL_NVIC_EnableIRQ(RC5_EXTI_IRQn);
	
  TimHandle.Instance = RC5_TIM;

  TimHandle.Init.Period = 0xFFFF;
  TimHandle.Init.Prescaler = RC5_TIM_PRESCALER;
  TimHandle.Init.ClockDivision = 0;
  TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
  if(HAL_TIM_Base_Init(&TimHandle) != HAL_OK){}
		
	__HAL_TIM_CLEAR_IT(&TimHandle, TIM_IT_UPDATE);

}


void RC5_Sample_Data(void)
{
	if (__HAL_TIM_GET_ITSTATUS(&TimHandle, TIM_IT_UPDATE)!= RESET) {
    /* Sample RC5 GPIO input */
    RC5_data[RC5_Indexdata++] = IR_PORT->IDR & IR;
    
    if(Bit4_HasBeen_Sampled == NO) /* RC5 bit 4 has been sampled? */
    {                              /*(to know if the next sampling will be after 3/4 or 1 bit time) */

      /* If NO: Set the RC5_TIM auto-reload register to allow the next sampling at 1bit time */ 
      RC5_TIM->ARR = NominalBitDurationCount; 
      
      /* Set the variable to yes */
      Bit4_HasBeen_Sampled = YES;
    }
    
    /* If the number of data reaches 13 (without start bit and field bit and extra bit is sampled: (14-2) + 1) */
    if(RC5_Indexdata == 13) 
    {
      /* Initialize the RC5 data index */
      RC5_Indexdata = 0;
      
      /* Set this flag software to inform the user that a RC5 frame is ready to be read */
      RC5_FrameReceived = YES;
      
      /* Initialize  Bit4_HasBeen_Sampled variable for next reception */
      Bit4_HasBeen_Sampled = NO;

      /* Disable RC5_TIM Update event Interrupt Request */
      //TIM_ITConfig(RC5_TIM, TIM_IT_Update, DISABLE);
			__HAL_TIM_DISABLE_IT(&TimHandle, TIM_IT_UPDATE);
      
      /* Disable RC5_TIM counter */	
			HAL_TIM_Base_Stop_IT(&TimHandle);
    }
		 __HAL_TIM_CLEAR_IT(&TimHandle, TIM_IT_UPDATE);
  }
	
} 

void RC5_MeasureFirstLowDuration(void)
{	
  /* If an edge is detected on RC5 input pin */
	if(__HAL_GPIO_EXTI_GET_IT(IR) != RESET)
  {
		if(Disable_Ext == 1){
			HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
			return;
		}
		
    /* Increment the edges number */
    EdgesNumber++;

    /* If it was the first edge */
    if(EdgesNumber == 1)
    {
      /* Reset the RC5_TIM counter */
      RC5_TIM->CNT = 0;
      
      /* Enable RC5_TIM counter */
			HAL_TIM_Base_Start_IT(&TimHandle) ;
    }
    /* If it was the 2nd edge */
    else if(EdgesNumber == 2)
    {
      /* Disable RC5_TIM counter */
      //TIM_Cmd(RC5_TIM, DISABLE);
			HAL_TIM_Base_Stop_IT(&TimHandle);
      
      /* Read RC5_TIM counter to get the first low duration */
      LowDuration = RC5_TIM->CNT;
      
      /* Reset RC5_TIM counter */
      RC5_TIM->CNT = 0;
    
      /* If low duration is between 640µs*TimClk and 1140µs*TimClk (min and max half bit time) */
      if ((LowDuration >= HalfBitDurationCount_Min) && (LowDuration <= HalfBitDurationCount_Max)) 
      {
        /* Validate the frame, by setting this variable to OK */
        BitTimeStatus = OK; 
      }
      /* If low duration is between 1340µs*TimClk and 2220µs*TimClk (min and max full bit time)*/
      else if ((LowDuration >= FullBitDurationCount_Min) && (LowDuration <= FullBitDurationCount_Max)) 
      {
        /* Disable EXTI line x to avoid jumping to this interrupt while receiving
        the RC5 data bits (it will be reenabled in the next RC5 data reception */
        //EXTI->IMR &= ((uint32_t)~RC5_EXTI_LINE);
				Disable_Ext = 1;
				//HAL_NVIC_DisableIRQ(RC5_EXTI_IRQn);

        /* Enable RC5_TIM counter */
				HAL_TIM_Base_Start_IT(&TimHandle) ;
       
        /* Enable RC5_TIM Update Event Interrupt Request */
			  __HAL_TIM_ENABLE_IT(&TimHandle, TIM_IT_UPDATE);
       
        /* Validate the frame, by setting this variable to OK */
        BitTimeStatus = OK;

        /* Set the RC5_TIM auto-reload register to allow the next sampling at 3/4 bit time */
        RC5_TIM->ARR = NominalBitDurationCount_3div4; 
       
        /* The bit field value is equal to 0 */
        FieldBit = 0;
       
        /* Initialize edges detected number */
        EdgesNumber = 0;

      }
      else /* If the first low duration is not in the right timing range */
      {  
        /* Set the Bit timing to NOTOK */
        BitTimeStatus = NOTOK;

        /* Reset RC5_TIM counter */
        RC5_TIM->CNT = 0;
         
        /* Initialize the number of glitches detected */
        EdgesNumber = 0;
      }
    }
    else if(EdgesNumber == 3) /* If the number of edges is equal to 3 */
    {
      /* Disable EXTI line x to avoid jumping to this interrupt while receiving
      the RC5 data bits (it will be reenabled in the next RC5 data reception */
      //EXTI->IMR &= ((uint32_t)~RC5_EXTI_LINE);
			Disable_Ext = 1;
			//HAL_NVIC_DisableIRQ(RC5_EXTI_IRQn);
       
      /* Enable RC5_TIM counter */
			HAL_TIM_Base_Start_IT(&TimHandle) ;
      
      /* Enable RC5_TIM Update Event Interrupt Request */
			__HAL_TIM_ENABLE_IT(&TimHandle, TIM_IT_UPDATE);
       
      /* Validate the frame, by setting this variable to OK */
      BitTimeStatus = OK;
       
      /* Set the RC5_TIM auto-reload register to allow the next sampling at 3/4 bit time */
      RC5_TIM->ARR = NominalBitDurationCount_3div4;  
       
      /* The bit field value is equal to 1 */
      FieldBit = 1;

      /* Initialize the number of glitches detected */
      EdgesNumber = 0;
    }
   
    /* Clear the RC5 EXTI line pending bit */
  }
	// HAL_GPIO_EXTI_IRQHandler(IR);
}


RC5Frame_TypeDef RC5_Decode(void)
{
   uint32_t RC5_dataIndex = 0;
	
	if(rc5_web == 1){
		rc5_web = 0;
		RC5_FrameReceived = NO;
		return RC5_frame_struct;
	}
	
   /* Initialize the different fields of the RC5 structure */
   RC5_frame_struct.ToggleBit = 0;
   RC5_frame_struct.Address = 0; 
   RC5_frame_struct.Command = 0;
  
   /* Get the Toggle bit value */
   if(RC5_data[0] & IR)
   {
     RC5_frame_struct.ToggleBit = 1;
   }
   else
   {
     RC5_frame_struct.ToggleBit = 0;
   }
  
   /* Get RC5 Address value */
   for(RC5_dataIndex=1; RC5_dataIndex<6; RC5_dataIndex++)
   {
     RC5_frame_struct.Address <<= 1 ;
     if(RC5_data[RC5_dataIndex] & IR)
     {
       RC5_frame_struct.Address |= 1;
     }
   }
     
  /* Get RC5 Command value */
  for(RC5_dataIndex=6; RC5_dataIndex<12; RC5_dataIndex++)
   {
     RC5_frame_struct.Command <<= 1 ;
     if(RC5_data[RC5_dataIndex] & IR)
     {
       RC5_frame_struct.Command |= 1;
     }
   }
  
   /* Set the 6th bit of the command regarding of the filed bit value */
   if(FieldBit == 0) /* logic 0 = command from 64 to 127 */
   {
     RC5_frame_struct.Command |= 0x40;
   }
   
   /* Initialize RC5_FrameReceived for next RC5 reception */
   RC5_FrameReceived = NO;  
  
   /* Wait for next falling edge of RC5 frame*/
   RC5_WaitForNextFallingEdge();
  
   if(Command_hist == RC5_frame_struct.Command){
			RC5_frame_struct.ToggleBit = 1;
	 }
	 else{
			RC5_frame_struct.ToggleBit = 0;
	 }

	 Command_hist = RC5_frame_struct.Command; 
	 
	 rc5_web = 0;
   return RC5_frame_struct;
}
  

static uint32_t RC5_TIM_GetCounterCLKValue(void)
{
  uint32_t apbprescaler = 0, apbfrequency = 0;

	/* Get the clock prescaler of APB1 */
	apbprescaler = ((RCC->CFGR >> 8) & 0x7);
	//apbfrequency = RCC_ClockFreq.PCLK1_Frequency;  
	apbfrequency = HAL_RCC_GetPCLK1Freq();

  /* If APBx clock div >= 4 */
  if (apbprescaler >= 4)
  {
    return ((apbfrequency * 2)/(RC5_TIM_PRESCALER + 1));
  }
  else
  {
    return (apbfrequency/(RC5_TIM_PRESCALER + 1));
  }
}

void RC5_CGI(char *Command){ 
	rc5_web = 1;
	RC5_FrameReceived = YES;
	
	RC5_frame_struct.ToggleBit = 0;
  RC5_frame_struct.Address = 0; 
	
	RC5_frame_struct.Command = atoi(Command);
	
 if(RC5_frame_struct.Command == Key_UPDATE_FIRMWARE)
	{ 
			//labspirt
				HAL_GPIO_WritePin(BEPPER_PORT, BEPPER, GPIO_PIN_SET);
				HAL_Delay(100);
					uint8_t EEPROM_tmp = 0;	
					if (BSP_EEPROM_WriteBuffer(&EEPROM_tmp,0, sizeof(EEPROM_tmp)) == EEPROM_OK){
						HAL_GPIO_WritePin(BEPPER_PORT, BEPPER, GPIO_PIN_RESET);
						HAL_Delay(100);
						NVIC_SystemReset();
						while(1){}
				}
				//labspirt			
	}
	
}

