/****************************************************************************
 Module
   Trigger.c

 Revision
   1.0.0

 Description
		UV Pulse (a service that implements a state machine)

****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for the framework and this service
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"

#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 "PWM8Tiva.h"
#include "PWMTiva.h"
#include "WaterGun.h"
#include "Trigger.h"

/*----------------------------- Module Defines ----------------------------*/
// these times assume a 1.000mS/tick timing
#define ONE_SEC 976
#define HALF_SEC (ONE_SEC/2)
#define TWO_SEC (ONE_SEC*2)
#define FIVE_SEC (ONE_SEC*5)

#define ALL_BITS (0xff<<2)
#define RECBIT GPIO_PIN_4
#define TRIGBIT GPIO_PIN_3
#define PORT_A_DATA HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS))

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

/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
static TrigState_t TrigState;

/*------------------------------ Module Code ------------------------------*/
/****************************************************************************/

bool InitTrigger(uint8_t Priority){
	MyPriority = Priority;
	// Initialize PWM
  //PWM8_TIVA_Init();
	PWM_TIVA_Init();
	//Initialize the port line to monitor the button
	HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R0;
	//Wait until port is ready
	while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R0) != SYSCTL_PRGPIO_R0) ;
	HWREG(GPIO_PORTA_BASE+GPIO_O_DEN) |= (TRIGBIT);
	//Set these bits as digital ins
	HWREG(GPIO_PORTA_BASE+GPIO_O_DIR) &= ~(TRIGBIT);
	if ((PORT_A_DATA & TRIGBIT) > 0) {
		TrigState = Trig_Pulled;
	} else {
		TrigState = Trig_Released;
	}
	return true;
}

bool PostTrigger( ES_Event ThisEvent ) {
	return ES_PostToService( MyPriority, ThisEvent);
}

bool CheckTrigPull(void) {
	static uint8_t LastTriggerPin = 0;
	//puts("Checking Trig\r\n");
	// Get current trigger state
	uint8_t CurrentTriggerPin = (PORT_A_DATA & TRIGBIT);
	// If Current trigger state is high and different from last state
	if ((CurrentTriggerPin > 0) && (CurrentTriggerPin != LastTriggerPin)) {
		// Post Trigger pressed event
			ES_Event ThisEvent;
			ThisEvent.EventType = ES_TRIGGER_PRESSED;
		  //printf("TRIGGER PRESSED EVENT SENT \r\n");
			PostTrigger(ThisEvent);
			LastTriggerPin = CurrentTriggerPin;
			// Return true
			return true;
	}
	// Set last trigger state to current trigger state
	LastTriggerPin = CurrentTriggerPin;
	// Return false
	return false;
}

bool CheckTrigRelease(void) {
	static uint8_t LastTriggerPin = 0;
	// Get current trigger state
	uint8_t CurrentTriggerPin = (PORT_A_DATA & TRIGBIT);
	
	// If Current trigger state is low and different from last state
	if ((CurrentTriggerPin == 0) && (CurrentTriggerPin != LastTriggerPin)) {
		// Post Trigger pressed event
			ES_Event ThisEvent;
			ThisEvent.EventType = ES_TRIGGER_RELEASED;
			PostTrigger(ThisEvent);
			LastTriggerPin = CurrentTriggerPin;
			// Return true
			return true;
	}
	// Set last trigger state to current trigger state
	LastTriggerPin = CurrentTriggerPin;
	// Return false
	return false;
}

ES_Event RunTrigger(ES_Event ThisEvent) {
	ES_Event ReturnEvent;
  ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
	// State machine based on current staterff
	switch (TrigState) {
		// If Trigger Pulled state
		case Trig_Pulled :
			// If Trigger has been released
			if (ThisEvent.EventType == ES_TRIGGER_RELEASED) {
				// Change state to debouncing
				TrigState = Trig_Debouncing;
				// Start Timer
				ES_Timer_InitTimer(TRIG_DB_TIMER, 10);
				//printf("Trigger Released\r\n");
			}
			break;
			// If Trigger Released state
		case Trig_Released :
			// If trigger is pressed
			if (ThisEvent.EventType == ES_TRIGGER_PRESSED) {
				//puts("trigger pressed\r\n");
				// Change state to debouncing
				TrigState = Trig_Debouncing;
				// Post Event
				PostWaterGun(ThisEvent);
				//PostPump(ThisEvent);
				//Start Timer
				ES_Timer_InitTimer(TRIG_DB_TIMER,10);
				//printf("Trigger Pulled\r\n");
			}
			break;
			// if Trigger debouncing state
		case Trig_Debouncing:
			// If timeout
			if (ThisEvent.EventType == ES_TIMEOUT) {
				// If trigger is currently pulled, set state to pulled
				if ((PORT_A_DATA & TRIGBIT) > 0) {
					TrigState = Trig_Pulled;
					// else set it to released
				} else {
					TrigState = Trig_Released;
				}
			}
			break;
	}
	return ReturnEvent;
}
