//#define WATER_RESERVOIR_TESTING
/****************************************************************************
 Module
   WaterReservoir.c

 Revision
   1.0.1 

 Description
		-Uses pins PA5, PA6, and PA7 on the Tiva to interface with a shift register that
			controls the numbers of water reservoir LEDs that are on
		-The number of LEDs in the water reservoir increment when the pump has passed
		a threshold. The number of LEDs in the water reservoir decrement when the players
		take a shot with the water 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 <stdlib.h>
#include "termio.h"

// include our own prototypes to insure consistency between header & 
// actual functionsdefinition
#include "WaterReservoir.h"
//include analog stuff
#include "ADMulti.h"

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

#define ALL_BITS (0xff<<2) //used for reading the hardware register values
#define MAX_POT_READING 4095
#define ONE_LED 700
#define TWO_LED (ONE_LED*2)
#define THREE_LED (ONE_LED*3)
#define FOUR_LED (ONE_LED*4)
#define FIVE_LED (ONE_LED*5)
#define SIX_LED (ONE_LED*6)
#define SEVEN_LED (ONE_LED*7)
#define EIGHT_LED (ONE_LED*8)

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

/* prototypes for private functions for this service.They should be functions
   relevant to the behavior of this service
*/
void turnOnLEDs (uint8_t LED_Data);
void ShiftClockPulse(void);
void RegisterClockPulse(void);

/*---------------------------- 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 WaterReservoirState_t CurrentState;
//static uint8_t numLEDs;
static uint32_t lastPotValue;
static uint32_t currentPotInputState[1];
static uint32_t isThreshold;
static bool spigotsOn = false;

/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitWaterReservoir

 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 transforming
		 the encoder data to the number of LEDs on in the water reservoir
		 -Complete this, and then all the other functions can then be used
		 
****************************************************************************/
bool InitWaterReservoir (uint8_t Priority){		//Takes a priority number, returns True. 
		//Create local variables
		MyPriority = Priority;
		ES_Event ThisEvent;
		
		puts("Beginning of init function\r\n");
		//Initialize the port lines to send out data to the shift register (make pins outputs)
		HWREG(SYSCTL_RCGCGPIO) |= SYSCTL_RCGCGPIO_R0; 	//Enable GPIO Port A
			while ((HWREG(SYSCTL_PRGPIO) & SYSCTL_PRGPIO_R0) != SYSCTL_PRGPIO_R0)
				;
		HWREG(GPIO_PORTA_BASE + GPIO_O_DEN) |= (GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7);	//Assign digital port to Pins PA5,6,7
		HWREG(GPIO_PORTA_BASE + GPIO_O_DIR) |= (GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7); 	//Set data data direction on Pins PA5,6,7 to be an output
		
		//Set CurrentState in state machine to InitialWaterReservoir
			CurrentState = InitialWaterReservoir;
			
		//Set counter for the number of LEDs that are on to be 0
			//numLEDs = 0;
			
	  //Initialize the potentiometer values
			ADC_MultiInit(1);
			ADC_MultiRead(currentPotInputState);
			lastPotValue = currentPotInputState[0];
			currentPotInputState[0] = 0;
			isThreshold = 0; //this keeps track of how many LEDs should be lit
			
		//Post ES_INIT event to the water reservoir queue (this service) to create the intial transition event
			ThisEvent.EventType = ES_INIT;
			PostWaterReservoir(ThisEvent);
			puts("ES_INIT posted \r\n");
			return true;
}//end InitWaterReservoir

/****************************************************************************
 Function
     PostWaterReservoir

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

/****************************************************************************
 Function
     RunWaterReservoir

 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 waterReservoir

****************************************************************************/
ES_Event RunWaterReservoir(ES_Event ThisEvent){
	//Returns ES_NO_Event
	ES_Event ReturnEvent;
	ReturnEvent.EventType = ES_NO_EVENT;
	//Local variables
	WaterReservoirState_t NextState;
	uint32_t newPotValue;
	uint32_t potDifference = 0;
	static uint8_t LED_Data = 0;
	//Set NextState to CurrentState
	NextState = CurrentState;
	
	switch(CurrentState)
	{
	//--------------------------------------------
		case InitialWaterReservoir:
			//turn all LEDs off
			turnOnLEDs(0);
			isThreshold = 0;
			if(ThisEvent.EventType == ES_INIT)
			{
				NextState = WaitingForGameStart;
			}
		break; //end InitialWaterReservoir block
		
	//--------------------------------------------
		case WaitingForGameStart:
			if(ThisEvent.EventType == ES_GAME_START)
			{
				NextState = WaitingForSpigots;
			}
		break;
			
	//--------------------------------------------
		case WaitingForSpigots:
			puts("I'm back in waiting for spigots\r\n");
			if (ThisEvent.EventType == ES_BOTH_SPIGOTS_ON)
			{
				spigotsOn = true; //guard condition for turning leds on/off
				puts("spigotsOn set to true\r\n");
				ES_Timer_InitTimer(PUMP_TIMER, 100);
				NextState = WaitingForLever;
			}
		break; //end WaitingForSpigots block
		
	//--------------------------------------------
		case WaitingForLever:
			//puts("In waiting for lever state\r\n");
			if(ThisEvent.EventType == ES_GAME_RESET)
			{
				spigotsOn = false; //guard condition for turning leds on/off
				puts("spigotsOn set to false by restart\r\n");
				//turn off all LEDs using the shift register
				turnOnLEDs(0);
				isThreshold = 0;
				NextState = WaitingForGameStart;
			}
			else if(ThisEvent.EventType == ES_GAME_TIMER_OUT)
			{
				spigotsOn = false; //guard condition for turning leds on/off
				puts("spigotsOn set to false by time out\r\n");
				//turn off all LEDs using the shift register
				turnOnLEDs(0);
				isThreshold = 0;
				NextState = WaitingForGameStart;
			}
			else if ((ThisEvent.EventType == ES_TIMEOUT) && (spigotsOn)) {
				//sample pot by reading 
				//newPotValue = currentPotInputState[0];
				ADC_MultiRead(currentPotInputState);
				newPotValue = currentPotInputState[0];
				//printf("newPotValue = %d\r\n", newPotValue);
				//read absolute value of the difference
				// Added 20 tic band to reduce changes due to noise
				if(newPotValue > (lastPotValue + 20))
				{
					potDifference = newPotValue - lastPotValue;
				}
				else if(lastPotValue > (newPotValue + 20))
				{
					potDifference = lastPotValue - newPotValue;
				}
				//potDifference = abs(newPotValue - lastPotValue);
				//variable += difference
				if (isThreshold < EIGHT_LED) {
					isThreshold += potDifference;
				}
				//printf("IsThreshVal: %d\r\n", isThreshold);
				//if threshold met, next next LED on
				if (isThreshold > EIGHT_LED)
				{
					//turn on eight LEDs with shift register
					LED_Data = 0xff; //11111111
					turnOnLEDs(LED_Data);
				}
				else if(isThreshold > SEVEN_LED)
				{
					//turn on seven LEDs with shift register
					LED_Data = 0x7f; //01111111
					turnOnLEDs(LED_Data);
				}
				else if(isThreshold > SIX_LED)
				{
					//turn on six LEDs with shift register
					LED_Data = 0x3f; //00111111
					turnOnLEDs(LED_Data);
				}
				else if(isThreshold > FIVE_LED)
				{
					//turn on five LEDs with shift register
					LED_Data = 0x1f; //00011111
					turnOnLEDs(LED_Data);
				}
				else if(isThreshold > FOUR_LED)
				{
					//turn on four LEDs with shift register
					LED_Data = 0x0f; //00001111
					turnOnLEDs(LED_Data);
				}
				else if(isThreshold > THREE_LED)
				{
					//turn on three LEDs with shift register
					LED_Data = 0x07; //00000111
					turnOnLEDs(LED_Data);
				}
				else if(isThreshold > TWO_LED)
				{
					//turn on two LEDs with shift register 
					LED_Data = 0x03; //00000011
					turnOnLEDs(LED_Data);
				}
				else if(isThreshold > ONE_LED)
				{
					//turn on one LED with shift register
					LED_Data = 0x01; //00000001
					turnOnLEDs(LED_Data);
				}
				else if(isThreshold < ONE_LED)
				{
					LED_Data = 0;
					turnOnLEDs(LED_Data);
				}
				else
				{
					//do nothing
				}
				lastPotValue = newPotValue;
				ES_Timer_InitTimer(PUMP_TIMER, 100);
				NextState = WaitingForLever;
			}
		break; //end WaitingForLever block
			
	//--------------------------------------------
	} //end of switch statement
	
	CurrentState = NextState;
	//Return ES_NO_EVENT
	return ReturnEvent;
} //end of RunWaterReservoir state machine function

void DecrementLED(void) 
{
	isThreshold -= ONE_LED;
	return;
}

bool CheckWater(void) 
{
	if (isThreshold > ONE_LED) {
		return true;
	} else{
		return false;
	}
}

void EmptyReservoir(void)
{
	isThreshold = 0;
}

//***************************************************************
//Private helper functions!
//***************************************************************

//***************************************************************
// turnOnLEDs
//		-Uses shift register to turn on the LEDs
//***************************************************************
void turnOnLEDs (uint8_t LED_Data)
{
	//Write the bits to the shift register
	uint8_t mask = BIT7HI;
	for (int i = 0; i < 8; i++) {
		if ((LED_Data & mask)!= 0) {
				HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) |= GPIO_PIN_5;
		}else{
				HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~GPIO_PIN_5;
		}
		//Shift over one space
		ShiftClockPulse();
		LED_Data = LED_Data<<1;
	}
	//Transfer information to the circuit
	RegisterClockPulse();
} //end of turnOnLEDs

//***************************************************************
// ShiftClockPulse
//***************************************************************
void ShiftClockPulse(void){
	//Shift Clock Port: PA6
  HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) |= GPIO_PIN_6; //set high
  HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~GPIO_PIN_6;	//set low
}

//***************************************************************
// RegisterClockPulse
//***************************************************************
void RegisterClockPulse(void){
	//Register Clock Port: PA7
  HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) |= GPIO_PIN_7;
  HWREG(GPIO_PORTA_BASE+(GPIO_O_DATA + ALL_BITS)) &= ~GPIO_PIN_7;
}
