//#define TEST
/****************************************************************************
 Module
   WaterGun.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 "Flame.h"
#include "WaterReservoir.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
*/
static void UV_Start_Pulse(void);
static void UV_Stop_Pulse(void);

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

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

bool InitWaterGun(uint8_t Priority){
	MyPriority = Priority;
	// Initialize PWM
  PWM_TIVA_Init();
		// Set 500 Hz frequency
	PWM_TIVA_SetFreq(500, 1);
	// Set current state to WG_Idle before spigot is turned on
	WGState = WG_Idle;
	//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) |= (RECBIT);
	//Set these bits as digital ins
	HWREG(GPIO_PORTA_BASE+GPIO_O_DIR) &= ~(RECBIT);
	return true;
}

static void UV_Start_Pulse(void) {
	// Set duty cycle to 50% to start pulse
	PWM_TIVA_SetDuty(50, 2);
}

static void Start_Motor(void) {
	PWM_TIVA_SetDuty(50, 3);
}

static void Stop_Motor(void) {
	PWM_TIVA_SetDuty(0, 3);
}

static void UV_Stop_Pulse(void) {
	// Set duty cycle to 0% to stop pulse
	PWM_TIVA_SetDuty(0, 2);
}

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

bool CheckPulse(void) {
	static uint8_t LastPulseState = 0;
	static uint16_t LastPulseTime = 0;
	
	//Get current state of phototransistor pin
	uint8_t CurrentPulseState = (PORT_A_DATA & RECBIT);
	
	// If state is high and different from last state
	if ((CurrentPulseState > 0) && (CurrentPulseState != LastPulseState)) {
		// Get current Time
		uint16_t CurrentTime = ES_Timer_GetTime();
		// If last 2 pulses less than 4 ms apart
		if ((CurrentTime - LastPulseTime) < 4) {
			//Post event shot detected
			ES_Event ThisEvent;
			ThisEvent.EventType = ES_FLAME_HIT;
			PostWaterGun(ThisEvent);
			PostFlame(ThisEvent);
			printf("Shot Detected\r\n");
		}
		// Set last pulse time and state to current values
		LastPulseTime = CurrentTime;
		LastPulseState = CurrentPulseState;
		return true;
	}
	// Set last pulse state to current value
	LastPulseState = CurrentPulseState;
	return false;
}

ES_Event RunWaterGun(ES_Event ThisEvent) {
	ES_Event ReturnEvent;
  ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
	// State machine based on current state
	switch (WGState) {
		// If WG_Ready2Shoot
		case WG_Ready2Shoot :
			// If event is trigger pressed
			if ((ThisEvent.EventType == ES_TRIGGER_PRESSED) && (CheckWater())) {
				printf("Firing\r\n");
				// Start Pulse
				UV_Start_Pulse();
				// Decrement LED
				DecrementLED();
				// Start Pulse Timer
				ES_Timer_InitTimer(PULSE_TIMER, 100);
				// Set current state to WG_Shooting
				WGState = WG_Shooting;
				// Else if event is spigot off
			} else if (ThisEvent.EventType == ES_SPIGOT_OFF) {
				// Set current state to WG_Idle
				WGState = WG_Idle;
			} 
			else if ((ThisEvent.EventType == ES_GAME_RESET) || (ThisEvent.EventType == ES_GAME_TIMER_OUT)) {
				// Set current state to WG_Idle
				WGState = WG_Idle;
			}
			break;
			// If WG_Shooting
		case WG_Shooting :
			// If event is pulse timer timeout
			if (ThisEvent.EventType == ES_TIMEOUT) {
				// stop pulsing
				UV_Stop_Pulse();
				// set current state to WG_Ready2Shoot
				WGState = WG_Ready2Shoot;
				// else if event is shot detected
			} else if (ThisEvent.EventType == ES_FLAME_HIT) {
				// stop pulse
				UV_Stop_Pulse();
				Start_Motor();
				//empty water reservoir
				EmptyReservoir();
				// change current state to WG_Hit
				WGState = WG_Hit;
				//PostFlame(ThisEvent);
				// Else if event is spigot off
			} else if (ThisEvent.EventType == ES_SPIGOT_OFF) {
				// stop pulse
				UV_Stop_Pulse();
				// set current state to WG_Idle
				WGState = WG_Idle;
			} 
			else if ((ThisEvent.EventType == ES_GAME_RESET) || (ThisEvent.EventType == ES_GAME_TIMER_OUT)) {
				// Set current state to WG_Idle
				WGState = WG_Idle;
			}
			break;
			// if WG_Hit
		case WG_Hit:
			// if event is pulse timer timeout
			if (ThisEvent.EventType == ES_TIMEOUT) {
				// change state to WG_Ready2Shoot
				WGState = WG_Ready2Shoot;
				Stop_Motor();
				// else if event is spigot off
			} else if (ThisEvent.EventType == ES_SPIGOT_OFF) {
				// set current state to WG_Idle
				WGState = WG_Idle;
				Stop_Motor();
			} 
			else if ((ThisEvent.EventType == ES_GAME_RESET) || (ThisEvent.EventType == ES_GAME_TIMER_OUT)) {
				// Set current state to WG_Idle
				WGState = WG_Idle;
			}
			break;
			// if state is WG_Idle
		case WG_Idle:
			// only respond to both spigots on
			if (ThisEvent.EventType == ES_BOTH_SPIGOTS_ON) {
				// set current state to WG_Ready2Shoot
				WGState = WG_Ready2Shoot;
			}
			break;
	}
	return ReturnEvent;
}

#ifdef TEST
/* test Harness for testing this module */
#include "termio.h"

int main(void)
{
	// Set the clock to run at 40MhZ using the PLL and 16MHz external crystal
	SysCtlClockSet(SYSCTL_SYSDIV_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN
			| SYSCTL_XTAL_16MHZ);
  // initialize the timer sub-system and console I/O
  _HW_Timer_Init(ES_Timer_RATE_1mS);
	TERMIO_Init();
	//clrScrn();
  InitWaterGun(1);
	UV_Start_Pulse();
	Motor_Start(); 0
	
		for(;;)
	  ;
    
    return 0;
}
#endif
