/****************************************************************************
 Module
   IRReloadService.c

 Revision
   1.0.1

 Description
   This module contains the service for the IR reload signal detection and emission

 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 02/22/18       r.adenekan    first pass

****************************************************************************/
// the common headers for C99 types
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>

// the headers to access the TivaWare Library
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"

/* include header files for hardware access
*/
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_timer.h"
#include "inc/hw_nvic.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"  // Define PART_TM4C123GH6PM in project
#include "driverlib/gpio.h"

/* include header files for the framework
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_Timers.h"
#include "ES_Events.h"

#include "IRReloadService.h"
#include "LolaGameMaster.h"
#include "MotorCommands.h"

// **********************************************************************
// PROTOTYPES

// READABILITY DEFINES
#define NO_SIGNAL 500 //may need to change
#define TicksPerMicroSec 40

// MODULE LEVEL VARIABLES
static uint8_t MyPriority;
static IRReloadState_t CurrentState; 

static uint8_t NumTimesSeen_ReloadSignal;

static uint32_t LastPeriod;
static uint32_t CurrentPeriod;
static uint32_t Tolerance = 100; //need to tune this value

static uint32_t PeriodInMicro;

static uint32_t LastCapture;
static uint32_t ThisCapture;

// **********************************************************************
// PUBLIC FUNCTIONS //
// **********************************************************************

/****************************************************************************
 Function
     InitIRReloadService

 Parameters
     uint8_t : the priority of this service

 Returns
     bool, false if error in initialization, true otherwise

 Description
     Saves away the priority, sets up the initial transition and does any
     other required initialization for this state machine

****************************************************************************/

// Saves away the priority, sets up the initial transition and does any
//     other required initialization for this state machine
bool InitIRReloadService(uint8_t Priority)
{
	//Create ThisEvent variable
  ES_Event_t ThisEvent;
	//Set MyPriority to be the priority passed in
  MyPriority = Priority;
  
	//Initialize NumTimesSeen_ReloadSignal to 0
  NumTimesSeen_ReloadSignal=0;
	//Initialize PeriodInMicro to 0
  PeriodInMicro=0;
  
  // post the initial transition event
  ThisEvent.EventType = ES_INIT;
  CurrentState = InitializingIRReloadService;
  
  if (ES_PostToService(MyPriority, ThisEvent) == true)
  {
    return true;
  }
  else
  {
    return false;
  }
}

/****************************************************************************
 Function
     PostIRReloadService

 Parameters
     EF_Event ThisEvent , the event to post to the queue

 Returns
     boolean False if the Enqueue operation failed, True otherwise

 Description
     Posts an event to this state machine's queue
****************************************************************************/

// Posts an event to this state machine's queue
bool PostIRReloadService(ES_Event_t ThisEvent)
{
  return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
    RunIRReloadService

 Parameters
   ES_Event : the event to process

 Returns
   ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise

 Description
   Runs events for this state machine
****************************************************************************/

ES_Event_t RunIRReloadService(ES_Event_t ThisEvent)
{
	//Create a ReturnEvent variable
  ES_Event_t ReturnEvent;
  ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
	//Create a NextState variable
  static IRReloadState_t NextState;
	//Set NextState equal to CurrentState
  NextState=CurrentState;

  switch (CurrentState)
  {
    case InitializingIRReloadService:        // If current state is InitializingIRReloadService
    {
      if (ThisEvent.EventType == ES_INIT)    // only respond to ES_INIT
      {
        // now put the machine into the actual initial state (WaitingForReload)
        NextState = WaitingForReload;
      }
    }
    break;  

		//If the CurrentState is WaitingForReload
    case WaitingForReload:        
    {
			//If the EventType of ThisEvent is AT_RELOAD_STATION
      if (ThisEvent.EventType == AT_RELOAD_STATION) 
      {
        //restart no signal timer
        ES_Timer_InitTimer(RELOAD_TIMER, NO_SIGNAL);
        //reset NumTimesSeen_ReloadSignal counter
        NumTimesSeen_ReloadSignal =0;
        //set next state to ReloadSensing
        NextState = ReloadSensing;  
      } 
    }
    break;

		//If the CurrentState is ReloadSensing
    case ReloadSensing:        
    {
			//If the EventType of ThisEvent is DETECTED_RELOAD_SIGNAL
      if (ThisEvent.EventType == DETECTED_RELOAD_SIGNAL) //have seen the reload signal enough times
      {
        // call function that sets frequency of PWM pin PE4 to be twice the frequency of signal
        IRReloadSetPeriod(PeriodInMicro); 
        
        // post WAITING_FOR_BALL event to LolaGameMaster
        ES_Event_t Event2Post;
        Event2Post.EventType=WAITING_FOR_BALL;
        PostLolaGameMasterSM(Event2Post);        
        
        //set next state to WaitingForReload
        NextState = WaitingForReload;
      }
      //If this event is a RELOAD_TIMER timeout
      if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam ==RELOAD_TIMER) //have seen the reload signal enough times //removed only for testing put back!!
      {
        //post BAD_RELOAD_ALIGNMENT event to LolaGameMaster
        ES_Event_t Event2Post;
        Event2Post.EventType=BAD_RELOAD_ALIGNMENT;
        PostLolaGameMasterSM(Event2Post);
				
        //set next state to WaitingForReload
        NextState = WaitingForReload;
      }
    } 
   break; 
  }  
                                   // end switch on Current State
  CurrentState=NextState;
  return ReturnEvent;
}

//Interrupt Response Routine for the reload input capture
void IRReload_ISR(void)
{
 
// clear the source of the interrupt, the input capture event
HWREG(WTIMER0_BASE + TIMER_O_ICR) = TIMER_ICR_CBECINT; // clear by writing a one Timer 
// grab the captured value
ThisCapture = HWREG(WTIMER0_BASE + TIMER_O_TBR);
// Calculate current Period
CurrentPeriod = ThisCapture - LastCapture;
// Update lastCapture
LastCapture = ThisCapture;
  
//if current period is within range of reload signal
if ((CurrentPeriod > LastPeriod-Tolerance) && (CurrentPeriod < LastPeriod+Tolerance))
{
  NumTimesSeen_ReloadSignal++; // We saw reload signal , so increment our counter
  
  //if seen signal of interest enough times
  if(NumTimesSeen_ReloadSignal == 5)
  {
  //post DETECTED_RELOAD_SIGNAL event to LolaGameMaster
    ES_Event_t Event2Post;
    Event2Post.EventType = DETECTED_RELOAD_SIGNAL;
    PeriodInMicro = CurrentPeriod/TicksPerMicroSec; //so giving Period in microsec
    PostIRReloadService(Event2Post);
  }
}
else
{
  //havent seen any signal of interest so set zero number of times seen
  NumTimesSeen_ReloadSignal=0;
}

 //save last period
 LastPeriod=CurrentPeriod;

//restart the timer
   ES_Timer_InitTimer(RELOAD_TIMER, NO_SIGNAL);
}

void InitIRReloadInterrupt(void)
{
  // enable the clock for the timer (Wide Timer 0)
  HWREG(SYSCTL_RCGCWTIMER) |= SYSCTL_RCGCWTIMER_R0;
  
  // enable the clock to PortC
  HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R2;
  // can immediately start configuring the timer from here
  
  // make sure timer B is DISABLED before configuring
  HWREG(WTIMER0_BASE + TIMER_O_CTL) &= ~TIMER_CTL_TBEN;
  
  // set it up in 32bit wide (indiv, not concat) mode
  // STRANGE CONSTANT NAME ALERT - do not be alarmed
//  HWREG(WTIMER0_BASE + TIMER_O_CFG) = TIMER_CFG_16_BIT ; //this is set when IRBeaconServiceInterrupt initializes
  
  // use the full 32 bit count, init the interval load to full
  HWREG(WTIMER0_BASE + TIMER_O_TBILR) = 0xffffffff;
  
  // Timer B to capture mode (TBMR = 3, TBAMS = 0)
  // for edge time (TBCMR = 1) and up-counting (TBCDIR = 1)
  HWREG(WTIMER0_BASE + TIMER_O_TBMR) = 
  (HWREG(WTIMER0_BASE + TIMER_O_TBMR) & ~TIMER_TBMR_TBAMS) | (TIMER_TBMR_TBCDIR | TIMER_TBMR_TBCMR | TIMER_TBMR_TBMR_CAP);
  
  // set the event ot a rising edge - modify TBEVENT bits to GPTMCTL
  // Rising edge = 00, so clear the bits
  HWREG(WTIMER0_BASE + TIMER_O_CTL) &= ~TIMER_CTL_TBEVENT_M;
  
  // **************
  // SETUP THE PORT
  
  // alternate fxn for the PortC bit 5 (WT0CCP1)
  HWREG(GPIO_PORTC_BASE + GPIO_O_AFSEL) |= BIT5HI;
  
  // map bit 5's alt fxn to WT0CCP1
  // 7 is the mux value, 16 to shift over to the right nibble
  HWREG(GPIO_PORTC_BASE + GPIO_O_PCTL) = (HWREG(GPIO_PORTC_BASE + GPIO_O_PCTL) & 0xff0fffff) + (7<<20);
  
  // enable pin on PortC for digital I/O
  HWREG(GPIO_PORTC_BASE + GPIO_O_DEN) |= BIT5HI;
  
  // make pin5 on PortC into an input
  HWREG(GPIO_PORTC_BASE + GPIO_O_DIR) &= BIT5LO;
  
  // *********
  // INTERRUPT
  
  // back to the timer enable a local capture interrupt
  HWREG(WTIMER0_BASE + TIMER_O_IMR) |= TIMER_IMR_CBEIM;
  
  // enable Timer B in Wide Timer 0 interrupt in the NVIC
  // interrupt #95: EN2 @ Bit31 (#>>5 = ENx  :  #mod32 = Bit#)
  HWREG(NVIC_EN2) |= BIT31HI;

  // make sure interrupts enabled globally
  __enable_irq();
  
  // ****************
  // ENABLE THE TIMER
  
  // enable timer and enable it to be stopped by the debugger
  HWREG(WTIMER0_BASE + TIMER_O_CTL) |= (TIMER_CTL_TBEN | TIMER_CTL_TBSTALL);
  
  // start the no signal timer
  ES_Timer_InitTimer(RELOAD_TIMER, NO_SIGNAL);
  
}

// **********************************************************************
// PRIVATE FUNCTIONS //
// **********************************************************************