//#define FLAME_TESTING
/****************************************************************************
 Module
   Flame.c

 Revision
   1.0.1 

 Description
		-Uses pins PB0, PB1, PB2, and PB3 on Tiva
		-When the phototransister has been "hit" by the water gun, one red LED on the
		flame cutout will turn off. If the players don't extinguish all of the red LEDs
		before the game timer ends, a blower fan will turn on to simulate fire in SF.
		If the players successfully extinguish all of the LEDs, a celebration will start.
   
****************************************************************************/

//*----------------------------Include Files--------------------------------/
// this will pull in the symbolic definitions for events, which we will want
// to post in response to detecting events
#include "ES_Configure.h"
// this will get us the structure definition for events, which we will need
// in order to post events in response to detecting events
#include "ES_Events.h"
// if you want to use distribution lists then you need those function 
// definitions too.
#include "ES_PostList.h"
// This include will pull in all of the headers from the service modules
// providing the prototypes for all of the post functions
#include "ES_ServiceHeaders.h"
// this test harness for the framework references the serial routines that
// are defined in ES_Port.c
#include "ES_Port.h"

#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"
#include "ES_Types.h"     /* gets bool type for returns */

#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 <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "termio.h"

// include our own prototypes to insure consistency between header & 
// actual functionsdefinition
#include "Flame.h"

/*----------------------------- Module Defines ----------------------------*/

#define ALL_BITS (0xff<<2) //used for reading the hardware register values

/*---------------------------- Module Functions ---------------------------*/

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

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

static uint8_t MyPriority;

static FlameState_t CurrentState;
static uint8_t counter;		//keeps track of how many LEDs are on


/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitFlame

 Parameters
     (uint8_t)  priority number

 Returns
		 (boolean) true if success, false if otherwise

 Description
		 -Does all the initializations of the port lines and data structures internal
		 to the module that are necessary to prepare the module to begin controlling the
		 flame LEDs
		 -Complete this, and then all the other functions can then be used
		 
****************************************************************************/
bool InitFlame (uint8_t Priority){		//Takes a priority number, returns True. 

	//Create local variables
	MyPriority = Priority;	//Initialize the MyPriority variable with the passed in parameter
	ES_Event ThisEvent;
	
	//Initialize the Tiva port lines to send out a signal (make pins outputs)
	//Port F (LEDs)
	HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R1; 	//Enable GPIO Port B
		while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R1) != SYSCTL_PRGPIO_R1)
			;
		HWREG(GPIO_PORTB_BASE + GPIO_O_DEN) |= (GPIO_PIN_0 |GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);	//Assign digital port to Pins PB0,1,2,3
		HWREG(GPIO_PORTB_BASE + GPIO_O_DIR) |= (GPIO_PIN_0 |GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3); 	//Set data data direction on Pin PF1 to be an output (turn on LEDs)

	//Port D (Fan)
	HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R3; 	//Enable GPIO Port D
		while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R3) != SYSCTL_PRGPIO_R3)
			;
		HWREG(GPIO_PORTD_BASE + GPIO_O_DEN) |= (GPIO_PIN_3 | GPIO_PIN_0 | GPIO_PIN_1);	//Assign digital port to Pins PD3
		HWREG(GPIO_PORTD_BASE + GPIO_O_DIR) |= (GPIO_PIN_3 | GPIO_PIN_0 | GPIO_PIN_1); 	//Set data data direction on Pin PD3 to be an output (turn fan on/off)
		
		//Set CurrentState in state machine to InitialFlame
		CurrentState = InitialFlame;
		
		//initialize counter to 4, which means all 4 LEDs are on
		counter = 4;
		
		//Set blower fan to off initially
		HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_3);
		HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_1 );
		
		//Pose Event ES_INIT to Flame queue
		ThisEvent.EventType = ES_INIT;
		PostFlame(ThisEvent);
		puts("Es init posted\r\n");
		return true;
}
//End of InitializeMorseElements

/****************************************************************************
 Function
     PostFlame

 Parameters
     ES_Event ThisEvent ,the event to post to the queue

 Returns
     bool false if the queue operation failed, true otherwise

 Description
     Posts an event to this state machine's queue
 Notes
****************************************************************************/
bool PostFlame( ES_Event ThisEvent )
{
  return ES_PostToService( MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     CheckFlameEvents

 Parameters
     none

 Returns
     boolean true if an event was posted

 Description
		 -This function tests to see if the phototransistor has been "hit" by the
			IR water gun. If it has, it decrements the number of red LEDs that are lit
			on the flame. If the players don't extinguish all of the LEDs by the end of
			the game, a blower fan will turn on to simulate a fire in SF. If the players
			do successfully quench the flames, a celebration begins.
		 
****************************************************************************/
bool CheckFlameEvents(void){
	//Create local variables
	
	bool ReturnVal = false;
	
	//If the LED counter is 0, all of the LEDs have been extinguished and the players win
	if(counter == 0)
	{
		//ES_Event ThisEvent;
		//ThisEvent.EventType = ES_ALL_FLAME_OFF;
		//Post this to a distribution list for every part of the game that has to react to a win event
		//DIST_LIST_0(ThisEvent);
	}
	
	return ReturnVal;
}	//End CheckFlameEvents

/****************************************************************************
 Function
     RunSpigot

 Parameters
     ES_Event ThisEvent ,the event to determine which part of the
		 switch statement to operate in

 Returns
     ES_Event ES_NO_EVENT

 Description
     Implements the state machine for Flame

Note
The EventType field of ThisEvent will be one of: ES_INIT, ES_GAME_RESET, ES_GAME_TIMER_OUT, ES_FLAME_HIT

****************************************************************************/
ES_Event RunFlame(ES_Event ThisEvent){
	//Returns ES_NO_Event
	ES_Event ReturnEvent;
	ReturnEvent.EventType = ES_NO_EVENT;
	//Local variables
	FlameState_t NextState;
	//Set NextState to CurrentState
	NextState = CurrentState;
	//puts("inside run\r\n");
	
	switch(CurrentState)
	{
		//------------------------------
		case InitialFlame:
			if(ThisEvent.EventType == ES_INIT)
			{
				//puts("inside initialFlame\r\n");
				//turn on all red LEDs on the flame
				HWREG(GPIO_PORTB_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
				NextState = WaitingForStart;
			}
			break; //end InitialFlame block
			
		//-------------------------------
		case WaitingForStart:
			if(ThisEvent.EventType == ES_GAME_START)
			{
				//puts("inside WaitingForStart\r\n");
				NextState = AllLEDsOn;
			}
		break; //end WaitingForStart block
			
		//------------------------------
		case AllLEDsOn:
			//puts("inside AllLEDsOn\r\n");
			//printf("Counter: %d\r\f", counter);
			if(ThisEvent.EventType == ES_FLAME_HIT)
				{
					//If flame was hit, decrement counter and turn one LED off (PB0)
					HWREG(GPIO_PORTB_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_0); //turn off first LED (PB0)
					counter--; //counter changes from 4 to 3
					//printf("Counter: %d\r\f", counter);
					NextState = SubsetLEDsOn;
				}
			if(ThisEvent.EventType == ES_GAME_TIMER_OUT)
				{
					//start blower fan
					HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_3);
					NextState = SameStateLEDs;
					printf ("\r\n sent SM to SameStateLEDs FROM ALLLEDsOn\r\n");
				}
			break; //end AllLEDsOn block
		
		//-------------------------------
		case SubsetLEDsOn:
			//puts("Inside SubsetLEDsOn\r\n");
			if((ThisEvent.EventType == ES_FLAME_HIT) && (counter > 0)) //as long as more than one LED is lit, do this
			{
				//Turn a specific LED off based on the value of the counter
				if(counter == 3)
					{
						HWREG(GPIO_PORTB_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_1); //turn off second LED (PB1)
						counter--; //counter changes from 3 to 2
						//printf("Counter: %d\r\f", counter); //prints 2
						//Stay in this state
						NextState = SubsetLEDsOn;
					}
				else if(counter == 2)
					{
						HWREG(GPIO_PORTB_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_2); //turn off third LED (PB2)
						counter--;	//counter changes from 2 to 1
						//printf("Counter: %d\r\f", counter);
						//Stay in this state?
						NextState = SubsetLEDsOn;
					}

			//If there's only one LED on, the next time the flame is hit, send it to the NoLEDsOn state
			else if((ThisEvent.EventType == ES_FLAME_HIT) && (counter == 1))
				{
					HWREG(GPIO_PORTB_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_3); //turn off fourth and final LED (PB3)
					counter--;	//counter changes from 1 to 0
					//printf("Counter: %d\r\f", counter);
					ThisEvent.EventType = ES_ALL_FLAME_OFF;
					PostServo(ThisEvent);
					PostResetButton(ThisEvent);
					//turn ON external 5 HI line
				  HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_0);
					HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_1);
					printf("\r\n THE PD0 PIN WENT HI \r\n");
					NextState = NoLEDsOn;
				} //End if
			}
			if(ThisEvent.EventType == ES_GAME_TIMER_OUT)
				{
					//start blower fan
						HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_3);
						NextState = SameStateLEDs;
					printf ("\r\n sent SM to SameStateLEDs from SUBSET LEDS ON\r\n");
				}
			break; // end SubsetLEDsOn state
		
		//-----------------------------------
		case NoLEDsOn:
			//puts("Inside NoLEDsOn\r\n");
			if(ThisEvent.EventType == ES_GAME_RESET)
			{
				//turn all LEDs on
				HWREG(GPIO_PORTB_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
				//set counter back to 4
				counter = 4;
				//printf("Counter set back to: %d\r\f", counter);
				//send state machine to AllLEDsOn state
				//turn off external 5 HI line
				HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_0);
				HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_1);
				NextState = WaitingForStart;
			}
			break; //end NoLEDsOn stateh
			
		//-----------------------------------
		case SameStateLEDs:
			if(ThisEvent.EventType == ES_GAME_RESET)
			{
				//turn blower fan off
				HWREG(GPIO_PORTD_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_3);
				puts("Inside SameStateLEDs\r\n");
				//turn all LEDs on
				HWREG(GPIO_PORTB_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3);
				//set counter back to 4
				counter = 4;
				//printf("Counter set back to: %d\r\f", counter);
				//send state machine to AllLEDsOn state
				NextState = WaitingForStart;
			}
			break; //end SameStateLEDs state
			
		//-----------------------------------
	}
	CurrentState = NextState;
	//Return ES_NO_EVENT
	return ReturnEvent;
}	//End of RunFlame function


