//#define SPIGOT_TESTING
/****************************************************************************
 Module
   Spigot.c

 Revision
   1.0.1 

 Description
		-Uses pins PF0, PF1, PF2, and PF3 on the Tiva
		-Users will rotate spigot knobs on the game console to turn the water flow on and off
		-The Tiva reads in the encoder values from two different spigot knobs and then
		determines if the knobs have been turned far enough to turn the water flow on and off.
		The information gathered from this module determines if the players can pump water
		and shoot the IR gun.
   
****************************************************************************/

//*----------------------------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 "Spigot.h"

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

#define ALL_BITS (0xff<<2) //used for reading the hardware register values
#define REVOLUTION 12	//24 detents in full revolution of rotary encoder

/*---------------------------- 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;
//Nomenclature: Spigot 1 is the water gun spigot; spigot 2 is the pump spigot
//							A refers to channel A; B refers to channel B
static SpigotState_t CurrentState;
static uint8_t lastEncoder1;	//changed after code was working
static uint8_t lastEncoder2;	//changed after code was working
static uint8_t counter1;		//encoder counter for water gun spigot //changed after code was working
static uint8_t counter2;		//encoder counter for pump spgiot	//changed after code was working
static uint8_t lastSpigot1;
static uint8_t currentSpigot1;
static uint8_t lastSpigot2;
static uint8_t currentSpigot2;
static bool startButtonPressed = false;


/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitSpigot

 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 capturing the
		 counts given off by the spigot encoders
		 -Complete this, and then all the other functions can then be used
		 
****************************************************************************/
bool InitSpigot (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 port line to receive encoder data (make pin an input)
		HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R5; 	//Enable GPIO Port F
		while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R5) != SYSCTL_PRGPIO_R5)
			;
		HWREG(GPIO_PORTF_BASE + GPIO_O_DEN) |= (GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4);	//Assign digital port to Pins PF0,1,2,3,4
		HWREG(GPIO_PORTF_BASE + GPIO_O_DIR) &= ~(GPIO_PIN_2 | GPIO_PIN_3);	//Set data direction on Pins PF2,3 to be inputs (aka set bits to 0) (reads in encoder counts)
		HWREG(GPIO_PORTF_BASE + GPIO_O_DIR) |= (GPIO_PIN_1 | GPIO_PIN_4); 	//Set data data direction on Pin PF1 and PF4 to be an output (turns on indicator LEDs)
		
	//Sample port line and use it to initialize the last input state variables for each pin
	//Nomenclature: Spigot 1 is the water gun spigot; spigot 2 is the pump spigot
	//							A refers to channel A; B refers to channel B
	
		//Set CurrentState in state machine to InitSpigot
		CurrentState = InitialSpigot;
		puts("CurrentState set to InitialSpigot for spigot state machine\r");
		
	//Set counters to 0
		counter1 = 0;
		counter2 = 0;
		puts("Counters set\r");
		
		lastSpigot1 = 0;
		lastSpigot2 = 0;
		
	//Initialize last encoder values to zero (both start low)
		lastEncoder1 = 0;
		lastEncoder2 = 0;
		puts("Last encoders set\r");
		
	//Post Event ES_Init to Spigot queue (this service)
		ThisEvent.EventType = ES_INIT; //post the initial transition event (ES_INIT) if this service implements a state machine
		PostSpigot(ThisEvent);
		puts("sent es init\r\n");
		return true;
}
//End of InitializeMorseElements

/****************************************************************************
 Function
     PostSpigot

 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 PostSpigot( ES_Event ThisEvent )
{
  return ES_PostToService( MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     CheckSpigotEvents

 Parameters
     none

 Returns
     boolean true if an event was posted

 Description
		 -This function tests for rising and falling edges from each encoder.
			For each spigot edge, the counter for that spigot is incremented or
			decremented. If the counter reaches a certain value, an event is posted
			stating that either both spigots are off, one spigot is on, or both spigots
			are on
		 
****************************************************************************/
bool CheckSpigotEvents(void){
	
	//Create local variables
	bool ReturnVal = false;
	static uint8_t LastCounterSum = 0;
		
	//Only check for spigot events if the start button has been pressed
	if(startButtonPressed)
	{
	
			//More local variables
			uint8_t CurrentInputSpig1A;
			uint8_t CurrentInputSpig2A;
			uint8_t currentEncoder1;
			uint8_t currentEncoder2;
			ES_Event ThisEvent;
			currentSpigot1 = 0;
			currentSpigot2 = 0;
		
		//Get the current input states from the input lines
		CurrentInputSpig1A = HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) & (GPIO_PIN_2); //ISOLATE PIN F2 and read it
		CurrentInputSpig2A = HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) & (GPIO_PIN_3); //ISOLATE PIN F3 and read it
		
		//Use the reads for each of the spigot encoder pins to determine how far each spigot has turned
		
		//printf("Pin 0: %d\r\n", CurrentInputSpig1A);
		
		//---------------------------------
		//Test if Spigot1 is on
		if(((CurrentInputSpig1A & BIT2HI) != 0))	//if 1A signal is high
		{
			//puts("here");
			currentEncoder1 = 1;								//1A is high...
			if(currentEncoder1 != lastEncoder1) //...and the current and last encoder states don't match
			{
				counter1++;												//...then increment the counter for spigot1
				//puts("1: INCREMENT\r\n");
				lastEncoder1 = currentEncoder1;		//set last encoder state to current encoder state for preparation for next loop through code
			}
		}
		if(((CurrentInputSpig1A & BIT2HI) == 0))	//if 1A signal is low
		{
			currentEncoder1 = 0;										//If 1A signal is low, don't alter the counter
			lastEncoder1 = currentEncoder1;					//set last encoder state to current encoder state for preparation for next loop through code
		}
		
		//---------------------------------
		//Test if Spigot2 is on
		if(((CurrentInputSpig2A & BIT3HI) != 0))	//if 2A signal is high
		{
			//puts("here");
			currentEncoder2 = 1;								//2A is high...
			if(currentEncoder2 != lastEncoder2) //...and the current and last encoder states don't match
			{
				counter2++;												//...then increment the counter for spigot2
				//puts("2: INCREMENT\r\n");
				lastEncoder2 = currentEncoder2;		//set last encoder state to current encoder state for preparation for next loop through code
			}
		}
		if(((CurrentInputSpig2A & BIT3HI) == 0))	//if 2A signal is low
		{
			currentEncoder2 = 0;										//If 2A signal is low, don't alter the counter
			lastEncoder2 = currentEncoder2;					//set last encoder state to current encoder state for preparation for next loop through code
		}
		//---------------------------------
		
		//printf("Counter 1: %d\r\n",counter1); //for debugging: comment out
		//printf("\t\t\tCounter 2: %d\r\n",counter2); //for debugging: comment out
		
	
		if((counter1 >= REVOLUTION) && (counter2 < REVOLUTION)) //check if spigot 1 is on
		{
			//turn on LED indicator so user knows to stop turning spigot1
			//HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_1);
			currentSpigot1 =1;
			if(currentSpigot1 != lastSpigot1)
			{
				ThisEvent.EventType = ES_SPIGOT1_ON;
				PostSpigot(ThisEvent);
				lastSpigot1 = currentSpigot1;
				ReturnVal = true;
			}
		}
		if((counter2 >= REVOLUTION) && (counter1 < REVOLUTION)) //check if spigot 2 is on
		{
			//turn on LED indicator so user knows to stop turning spigot2
			//HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_4);
			currentSpigot2 =1;
			if(currentSpigot2 != lastSpigot2)
			{
				ThisEvent.EventType = ES_SPIGOT2_ON;
				PostSpigot(ThisEvent);
				lastSpigot2 = currentSpigot2;
				ReturnVal = true;
			}
		}
		
		//Check to see if both of the spigots are completely on. If they are, send an event out to pump, spigot, and watergun state machines
		//If Spigot1 counter value > REVOLUTION (aka 24 counts), then send an event that says spigot A is on
		if((counter1 >= REVOLUTION) && (counter2 >= REVOLUTION) && ((counter1 + counter2)!= LastCounterSum)) //if both spigots are on
			{
				ThisEvent.EventType = ES_BOTH_SPIGOTS_ON;
				//puts("Spigot Post");
				PostSpigot(ThisEvent);
				PostWaterReservoir(ThisEvent);
				PostWaterGun(ThisEvent);
				ReturnVal = true;
			}
			
}
	LastCounterSum = counter1 + counter2;
return ReturnVal;	
}	//End of CheckSpigotEvents  

	/****************************************************************************
 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 Spigot

Note
The EventType field of ThisEvent will be one of: ES_INIT, ES_BOTH_SPIGOTS_ON, GAME_RESET

****************************************************************************/
ES_Event RunSpigot(ES_Event ThisEvent){
	//Returns ES_NO_Event
	ES_Event ReturnEvent;
	ReturnEvent.EventType = ES_NO_EVENT; // assume no errors ...THIS GOES AT BOTTOM OF FUNCTION??
	//Local variables
	SpigotState_t NextState;
	//Set NextState to CurrentState
	NextState = CurrentState;
	
	//puts("Inside the run function\r\n"); //for debugging: comment out
	//Based on the state of the CurrentState variable, choose one of the following blocks of code: 
	switch(CurrentState)
	{
		//------------------------------------
		case InitialSpigot:
			if(ThisEvent.EventType == ES_INIT)
			{
				HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_1);
				HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_4);
				//puts("in initial spigot going to no spigots on\r\n");
				NextState = WaitingForGameStartSpigots;
				//puts("Spigot state machine currently in InitialSpigot\r\n");
			}
			break; //end InitalSpigot block
		
		//------------------------------------
		case WaitingForGameStartSpigots:
			if(ThisEvent.EventType == ES_GAME_START)
			{
				puts("start event found\r\n");
				startButtonPressed = true; //this is used as guard condition on the spigot event checker so you can't
																	//turn the spigots on before the start button has been pressed
				NextState = NoSpigotsOn;
			}
		break; //end of WaitingForGameStartSpigot
			
		//------------------------------------
		case NoSpigotsOn:
			//puts("Spigot state machines currently in NoSpigotsOn\r\n");
			//turn off LED indicator so user knows they need to turn the spigots on
			//puts("in no spigots on going to both spigots on\r\n");
			//HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_1);
			if(ThisEvent.EventType == ES_SPIGOT1_ON)
			{
				puts("Spigot 1 on posted\r\n");
				NextState = OneSpigotOn;
				//puts("Spigot state machine currently in BothSpigotsOn\r\n");
				//turn on LED indicator #1 so user knows to stop turning spigot1
				HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_1);
			}
			if(ThisEvent.EventType == ES_SPIGOT2_ON)
			{
				NextState = OneSpigotOn;
				puts("Spigot 2 on posted\r\n");
				//turn on LED indicator #2 so user knows to stop turning spigot2
				HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_4);
			}
		break; //end NoSpigotsOn block
			
		//------------------------------------
		case OneSpigotOn:
			if(ThisEvent.EventType == ES_BOTH_SPIGOTS_ON)
			{
				//turn on LED indication #2
				HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_1);
				HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) |= (GPIO_PIN_4);
				NextState = BothSpigotsOn;
			}
			if(ThisEvent.EventType == ES_GAME_RESET)
			{
				//turn off LED indicator #1
				HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_1 | GPIO_PIN_4);
				
				//set all counters and booleans back to their initial states
				counter1 = 0;
				counter2 = 0;
				lastSpigot1 = 0;
				lastSpigot2 = 0;
				lastEncoder1 = 0;
				lastEncoder2 = 0;
				currentSpigot1 = 0;
				currentSpigot2 = 0;
				//set event checker guard back to false so it can't check for spigot events unless the start
				//button has been pressed again
				startButtonPressed = false;
				NextState = WaitingForGameStartSpigots;
			}
		break;
			
		//------------------------------------
		case BothSpigotsOn:
			if(ThisEvent.EventType == ES_GAME_RESET)
			{;
				//turn off LED indicator so user knows they need to turn the spigots on
				HWREG(GPIO_PORTF_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~(GPIO_PIN_1 | GPIO_PIN_4);
				//set counters back to zero
				counter1 = 0;
				counter2 = 0;
				lastSpigot1 = 0;
				lastSpigot2 = 0;
				lastEncoder1 = 0;
				lastEncoder2 = 0;
				currentSpigot1 = 0;
				currentSpigot2 = 0;
				//set event checker guard back to false so it can't check for spigot events unless the start
				//button has been pressed again
				startButtonPressed = false;
				NextState = WaitingForGameStartSpigots;
			}
		break; //end BothSpigotsOn block
		//------------------------------------
	}
		CurrentState = NextState;
		//Return ES_NO_EVENT
		return ReturnEvent; //this was defined at the top of the function
}	//End of RunMorseElementsSM function	
	
/*------------------------------ TEST HARNESS ------------------------------*/
#ifdef SPIGOT_TESTING
int main(void)
{
	TERMIO_Init();
	puts("This is the test harness for Spigot\r\n");
	bool initialization;
	initialization = InitSpigot(MyPriority);
	bool test;
	while(true)
	{
		//puts("here\r\n");
		test = CheckSpigotEvents();
	}
}
#endif /*MORSE_ELEMENTS_TESTING */
