/****************************************************************************
 Module
   LimitDebounce.c

 Description
   Debounces the LimitSwitch to notify LolaGameMaster that the front 
   of the robot has been hit

****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
   next lower level in the hierarchy that are sub-machines to this machine
*/
#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_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_DeferRecall.h"
#include "ES_Timers.h"
#include "ES_Events.h"

//Header File of the service
#include "LimitDebounce.h"
#include "LolaGameMaster.h"

/*----------------------------- Module Defines ----------------------------*/
#define DB_TIME 25

/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this machine.They should be functions
   relevant to the behavior of this state machine
*/

/*---------------------------- Module Variables ---------------------------*/

static LimitState_t CurrentState;
static uint8_t MyPriority;
static uint8_t LastLimitVal;
static uint8_t CurrentLimitVal;

/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitLimitDebounce

 Parameters
     uint8_t : the priorty 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

****************************************************************************/
bool InitLimitDebounce(uint8_t Priority)
{
  MyPriority = Priority;
  
  // init the port line to read in the button value (PF2)
  // Set up port F
  HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R5;
  // waiting for the peripheral to be ready
  while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R5) != SYSCTL_PRGPIO_R5)
  {
    ;
  }
  
  // set the direction of PF0 to digital output
  HWREG(GPIO_PORTF_BASE + GPIO_O_DEN) |= BIT0HI;
  HWREG(GPIO_PORTF_BASE + GPIO_O_DIR) &= BIT0LO;

  // Sample the limit switch and save the value as LastLimitVal
  LastLimitVal = HWREG(GPIO_PORTF_BASE + (GPIO_O_DATA + ALL_BITS)) & BIT0HI;
 
  // put us into the Initial State (Debouncing)
  CurrentState = Debouncing;
  
  // Init and Start LIMIT_DB timer
  ES_Timer_Init(ES_Timer_RATE_1mS);
  ES_Timer_InitTimer(LIMIT_DB, DB_TIME);
  
  return true;
}

/****************************************************************************
 Function
     PostLimitDebounce

 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
****************************************************************************/
bool PostLimitDebounce(ES_Event_t ThisEvent)
{
  return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
   CheckLimitEvents

 Parameters
   void

 Returns
   bool of true if event found, false if none

 Description
   Checks for limit switch presses
****************************************************************************/
bool CheckLimitEvents(void)
{
  bool ReturnVal = false;
  
  // Sample the limit switch
  CurrentLimitVal = (HWREG(GPIO_PORTF_BASE + (GPIO_O_DATA + ALL_BITS)) & (BIT0HI));

  //if the limit value has changed since the last check
  if (CurrentLimitVal != LastLimitVal)
  {
    ReturnVal = true;
		//If the limit switch is LO
    if (CurrentLimitVal == 0)
    {
			//Create an Event2Post variable
      ES_Event_t Event2Post;
			//Set the EventType to ES_LIMITDOWN
      Event2Post.EventType = ES_LIMITDOWN;
			//Post Event2Post to this service
      PostLimitDebounce(Event2Post);
    }
    else
    {
			//Create an Event2Post variable
      ES_Event_t Event2Post;
			//Set the Event2Post to ES_LIMITUP
      Event2Post.EventType = ES_LIMITUP;
			//Post Event2Post to this service
      PostLimitDebounce(Event2Post);
    }
  }
  
  // save current val to last val
  LastLimitVal = CurrentLimitVal;

  return ReturnVal;
}

/****************************************************************************
 Function
    RunLimitDebounce

 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 RunLimitDebounce(ES_Event_t ThisEvent)
{
	//Create a ReturnEvent variable
  ES_Event_t ReturnEvent;
  ReturnEvent.EventType = ES_NO_EVENT; // assume no errors

  switch (CurrentState)
  {
		//If the CurrentState is Debouncing
    case Debouncing:
    {
			//If ThisEvent is an ES_TIMEOUT
      if (ThisEvent.EventType == ES_TIMEOUT)
      {
				//Set the CurrentState to Ready2Sample
        CurrentState = Ready2Sample;
      }
    }
    break;

		//If the CurrentState is Ready2Sample
    case Ready2Sample:
    {
			//If ThisEvent is an ES_LIMITDOWN
      if (ThisEvent.EventType == ES_LIMITDOWN)
      {
        // Start the LIMIT_DB Timer
        ES_Timer_InitTimer(LIMIT_DB, DB_TIME);
        //Set the CurrentState to Debouncing
        CurrentState = Debouncing;
        
        // Post an ES_LimitSwitchHit event to LolaGameMaster
        ES_Event_t Event2Post;
        Event2Post.EventType = ES_LimitSwitchHit;
        PostLolaGameMasterSM(Event2Post);
      }
			//If ThisEvent is an ES_LIMITUP
      if (ThisEvent.EventType == ES_LIMITUP)
      {
        // Start LIMIT_DB Timer
        ES_Timer_InitTimer(LIMIT_DB, DB_TIME);
        //Set the CurrentState to Debouncing
        CurrentState = Debouncing;
        
        // Post an ES_LimitSwitchReleased event to LolaGameMaster
        ES_Event_t Event2Post;
        Event2Post.EventType = ES_LimitSwitchReleased;
        PostLolaGameMasterSM(Event2Post);
      }
    }
    break;
  } // end switch on Current State
  return ReturnEvent;
}

/***************************************************************************
 private functions
 ***************************************************************************/