/****************************************************************************
 Module
   GameChatHSM.c

 Revision
   2.0.1

 Description
   This is a template file for implementing state machines.

 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 02/20/17 10:14 jec      correction to Run function to correctly assign 
                         ReturnEvent in the situation where a lower level
                         machine consumed an event.
 02/03/16 12:38 jec      updated comments to reflect changes made in '14 & '15
                         converted unsigned char to bool where appropriate
                         spelling changes on true (was True) to match standard
                         removed local var used for debugger visibility in 'C32
                         commented out references to Start & RunLowerLevelSM so
                         that this can compile. 
 02/07/13 21:00 jec      corrections to return variable (should have been
                         ReturnEvent, not CurrentEvent) and several EV_xxx
                         event names that were left over from the old version
 02/08/12 09:56 jec      revisions for the Events and Services Framework Gen2
 02/13/10 14:29 jec      revised Start and run to add new kind of entry function
                         to make implementing history entry cleaner
 02/13/10 12:29 jec      added NewEvent local variable to During function and
                         comments about using either it or Event as the return
 02/11/10 15:54 jec      more revised comments, removing last comment in during
                         function that belongs in the run function
 02/09/10 17:21 jec      updated comments about internal transitions on During funtion
 02/18/09 10:14 jec      removed redundant call to RunLowerlevelSM in EV_Entry
                         processing in During function
 02/20/07 21:37 jec      converted to use enumerated type for events & states
 02/13/05 19:38 jec      added support for self-transitions, reworked
                         to eliminate repeated transition code
 02/11/05 16:54 jec      converted to implment hierarchy explicitly
 02/25/03 10:32 jec      converted to take a passed event parameter
 02/18/99 10:19 jec      built template from MasterMachine.c
 02/14/99 10:34 jec      Began Coding
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// Basic includes for a program using the Events and Services Framework
#include "ES_Configure.h"
//#include "ES_Framework.h"

/* include header files for this state machine as well as any machines at the
   next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.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/gpio.h"

#include "GameChatHSM.h"
#include "CommMasterHSM.h"
#include "Hardware.h"
#include "Constants.h"
#include "MasterSM.h"

/*----------------------------- Module Defines ----------------------------*/
// define constants for the states for this machine
// and any other local defines

#define ENTRY_STATE CommActive
#define NVIC_1TMRA_EN BIT0HI
#define REPORT_FREQ_M 0x0F
#define COMMAND_TYPE_M 0xF0

/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this machine, things like during
   functions, entry & exit functions.They should be functions relevant to the
   behavior of this state machine
*/
static ES_Event DuringCommActive( ES_Event Event );
static ES_Event DuringWaiting2MS( ES_Event Event );
static void GetReportResponseBytes(void);
static void GetStatusBytes (void);

/*---------------------------- Module Variables ---------------------------*/
// everybody needs a state variable, you may need others as well
static GameChatState_t CurrentState;
static uint8_t FreqReportCMD;
static uint8_t LastCommandSent;

//LOC info variables
static uint8_t CSG = 0;
static uint8_t GreenActiveArea = 0;
static uint8_t CSR = 0;
static uint8_t RedActiveArea = 0;
static uint8_t GreenScore = 0;
static uint8_t RedScore = 0;
static uint8_t GameStatus = 0;
static uint8_t ResponseReadyByte = 0;
static uint8_t Acknowledge = 0;
static uint8_t NextLocation = 0; 
static uint8_t Freq2Report = 0; 

/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
    RunTemplateSM

 Parameters
   ES_Event: the event to process

 Returns
   ES_Event: an event to return

 Description
   add your description here
 Notes
   uses nested switch/case to implement the machine.
 Author
   J. Edward Carryer, 2/11/05, 10:45AM
****************************************************************************/
ES_Event RunGameChatSM( ES_Event CurrentEvent )
{
   bool MakeTransition = false;/* are we making a state transition? */
   GameChatState_t NextState = CurrentState;
   ES_Event EntryEventKind = { ES_ENTRY, 0 };// default to normal entry to new state
   ES_Event ReturnEvent = CurrentEvent; // assume we are not consuming event

   switch ( CurrentState )
   {
       case CommActive :       // If current state is state one
         // Execute During function for state one. ES_ENTRY & ES_EXIT are
         // processed here allow the lower level state machines to re-map
         // or consume the event
         CurrentEvent = DuringCommActive(CurrentEvent);
         //process any events
         if ( CurrentEvent.EventType != ES_NO_EVENT ) //If an event is active
         {
            switch (CurrentEvent.EventType)
            {
               case ES_RESPONSE_READY : //If event is event one
                  // Execute action function for state one : event one
                  NextState = Waiting2MS;//Decide what the next state will be
                  // for internal transitions, skip changing MakeTransition
                  MakeTransition = true; //mark that we are taking a transition
                  // if transitioning to a state with history change kind of entry
                  EntryEventKind.EventType = ES_ENTRY;
                  // optionally, consume or re-map this event for the upper
                  // level state machine
                  ReturnEvent.EventType = ES_NO_EVENT;
                  break;
                // repeat cases as required for relevant events
            }
         }else // Current Event is now ES_NO_EVENT. Correction 2/20/17 
         {     //Probably means that CurrentEvent was consumed by lower level
            ReturnEvent = CurrentEvent; // in that case update ReturnEvent too.
         }
				break;
				// repeat state pattern as required for other states
				
				 case Waiting2MS :       // If current state is state one
         // Execute During function for state one. ES_ENTRY & ES_EXIT are
         // processed here allow the lower level state machines to re-map
         // or consume the event
         CurrentEvent = DuringWaiting2MS(CurrentEvent);
         //process any events
         if ( CurrentEvent.EventType != ES_NO_EVENT ) //If an event is active
         {
            switch (CurrentEvent.EventType)
            {
               case ES_2MS_TIMEOUT : //If event is event one
                  // Execute action function for state one : event one
                  NextState = CommActive;//Decide what the next state will be
                  // for internal transitions, skip changing MakeTransition
                  MakeTransition = true; //mark that we are taking a transition
                  // if transitioning to a state with history change kind of entry
                  EntryEventKind.EventType = ES_ENTRY;
                  // optionally, consume or re-map this event for the upper
                  // level state machine
                  ReturnEvent.EventType = ES_NO_EVENT;
                  break;
                // repeat cases as required for relevant events
            }
         }else // Current Event is now ES_NO_EVENT. Correction 2/20/17 
         {     //Probably means that CurrentEvent was consumed by lower level
            ReturnEvent = CurrentEvent; // in that case update ReturnEvent too.
         }
       break;

    }
    //   If we are making a state transition
    if (MakeTransition == true)
    {
       //   Execute exit function for current state
       CurrentEvent.EventType = ES_EXIT;
       RunGameChatSM(CurrentEvent);

       CurrentState = NextState; //Modify state variable

       //   Execute entry function for new state
       // this defaults to ES_ENTRY
       RunGameChatSM(EntryEventKind);
     }
     return(ReturnEvent);
}
/****************************************************************************
 Function
     StartGameChatSM

 Parameters
     None

 Returns
     None

 Description
     Does any required initialization for this state machine
 Notes

 Author
     J. Edward Carryer, 2/18/99, 10:38AM
****************************************************************************/
void StartGameChatSM ( ES_Event CurrentEvent )
{
   // to implement entry to a history state or directly to a substate
   // you can modify the initialization of the CurrentState variable
   // otherwise just start in the entry state every time the state machine
   // is started
   if ( ES_ENTRY_HISTORY != CurrentEvent.EventType )
   {
        CurrentState = Waiting2MS;
		 printf("current state = waiting 2 ms");
   }
   // call the entry function (if any) for the ENTRY_STATE
   RunGameChatSM(CurrentEvent);
}

/****************************************************************************
 Function
     QueryTemplateSM

 Parameters
     None

 Returns
     TemplateState_t The current state of the Template state machine

 Description
     returns the current state of the Template state machine
 Notes

 Author
     J. Edward Carryer, 2/11/05, 10:38AM
****************************************************************************/
GameChatState_t QueryTemplateSM ( void )
{
   return(CurrentState);
}

/***************************************************************************
 private functions
 ***************************************************************************/

static ES_Event DuringCommActive( ES_Event Event)
{
    ES_Event ReturnEvent = Event; // assume no re-mapping or consumption

    // process ES_ENTRY, ES_ENTRY_HISTORY & ES_EXIT events
    if ( (Event.EventType == ES_ENTRY) ||
         (Event.EventType == ES_ENTRY_HISTORY) )
    {
        // implement any entry actions required for this state machine
        printf("entered comm active state \n\r");
        // after that start any lower level machines that run in this state
        //StartLowerLevelSM( Event );
        // repeat the StartxxxSM() functions for concurrent state machines
        // on the lower level

    }
    else if ( Event.EventType == ES_EXIT )
    {
        // on exit, give the lower levels a chance to clean up first
        //RunLowerLevelSM(Event);
        // repeat for any concurrently running state machines
        // now do any local exit functionality
				
				//get the last command sent
				uint8_t LastCommandSent = GetCurrentCommand();
				uint8_t LastCommandType = (LastCommandSent & COMMAND_TYPE_M);
				//based on last command sent, print relevant information to the terminal
				switch (LastCommandType) {
					//case gamestatus command
					case GameStatusCMD:
						//get the latest information about game status
					  
						GetStatusBytes();
						printf("Status = %01X | Green:  Shooting? %01X active goal %02X	Score	%02X \n\r", GameStatus, CSG, GreenActiveArea, GreenScore );	
						printf("Status = %01X | Red:    Shooting? %01X active goal %02X	Score	%02X \n\r", GameStatus, CSR, RedActiveArea, RedScore );
						break;
					
					case SendReportCMD:
						//print frequency reported to LOC
						printf("Reported Frequency to LOC: %d \n\r", Freq2Report);
						break;
					
					case QueryResponseCMD:
						//get the latest response ready bytes
						GetReportResponseBytes();
							if(ResponseReadyByte == ReportResponseNOTReady ){
								printf("Response Not Ready \n\r");
							}
							else if(ResponseReadyByte == ReportResponseReady){
								ES_Event Event;
								switch (Acknowledge) {
									case ACK:
										printf("Response Ready. ACK! \n\r");
									  Event.EventType = ES_ACK;
										break; 
									case NACK:
										Event.EventType = ES_NACK;
										printf("Response Ready. NACK! \n\r");
										break; 
									case INACTIVE:
										Event.EventType = ES_INACTIVE;
										printf("Response Ready. INACTIVE! \n\r");
										break; 
								}
								PostMasterSM(Event);
							}
							else {
								printf("Invalid response: %02X \n\r", ResponseReadyByte);
							}
								
//						printf("Reponse %01X | Green: shoot? %01X	active goal %03X	score %05X \n\r", GameStatus, CSG, GreenActiveArea, GreenScore );
//						printf("frequency report command %d \n\r",FreqReportCMD);
						break; 
      }
    }else
    // do the 'during' function for this state
    {
        // run any lower level state machine
        // ReturnEvent = RunLowerLevelSM(Event);
      
        // repeat for any concurrent lower level machines
			
			//if event type of Event is ES_QUERY and event param is game status command, the transmit the game status command to LOC
      if (Event.EventType == ES_QUERY && Event.EventParam ==  GameStatusCMD){
				SPI_Transmit(GameStatusCMD);
				printf("about to transfer game status cmd \n\r");
				}
			//else if event is ES_SEND_REPORT
			else if(Event.EventType == ES_SEND_REPORT){
				//printf("Sending Report\n\r");
				//AND the frequency with report frequency mask to clear upper bits and OR with SendReportCMD to add 4 MSBs for LOC command type
				FreqReportCMD = ((Event.EventParam & REPORT_FREQ_M) | SendReportCMD);
				SPI_Transmit(FreqReportCMD);
				//Storing Reported Frequency in Freq2Report
				Freq2Report = ( Event.EventParam & REPORT_FREQ_M );
				printf("Freq2Report: %i\n\r", Freq2Report);
			}
			//else if event is ES_
        // do any activity that is repeated as long as we are in this state
    }
    // return either Event, if you don't want to allow the lower level machine
    // to remap the current event, or ReturnEvent if you do want to allow it.
    return(ReturnEvent);
}

static ES_Event DuringWaiting2MS( ES_Event Event)
{
    ES_Event ReturnEvent = Event; // assume no re-mapping or consumption

    // process ES_ENTRY, ES_ENTRY_HISTORY & ES_EXIT events
    if ( (Event.EventType == ES_ENTRY) ||
         (Event.EventType == ES_ENTRY_HISTORY) )
    {
        // implement any entry actions required for this state machine
        
        // after that start any lower level machines that run in this state
        //StartLowerLevelSM( Event );
        // repeat the StartxxxSM() functions for concurrent state machines
        // on the lower level
		//	printf("*******************************************************");
			   printf("entered waiting 2ms state \n\r");

				//start the 2ms timer 
				HWREG( TIMER0_BASE+TIMER_O_CTL ) |= (TIMER_CTL_TAEN | TIMER_CTL_TASTALL);
    }
    else if ( Event.EventType == ES_EXIT )
    {
			   printf("exiting waiting 2ms state \n\r");
        // on exit, give the lower levels a chance to clean up first
        //RunLowerLevelSM(Event);
        // repeat for any concurrently running state machines
        // now do any local exit functionality
      
    }else
    // do the 'during' function for this state
    {
        // run any lower level state machine
        // ReturnEvent = RunLowerLevelSM(Event);
      
        // repeat for any concurrent lower level machines
      
        // do any activity that is repeated as long as we are in this state
    }
    // return either Event, if you don't want to allow the lower level machine
    // to remap the current event, or ReturnEvent if you do want to allow it.
    return(ReturnEvent);
}

//One shot timer for 2ms timeout. this is on timer 0A&B
void SafetyTimerInit (void) {
	printf("initing the safety timer\r\n");
	
  //Start by enabling the clock to the timer (Timer 0)
	HWREG(SYSCTL_RCGCTIMER) |= SYSCTL_RCGCTIMER_R0;	
	while( (HWREG( SYSCTL_PRTIMER ) & SYSCTL_PRTIMER_R0 ) != SYSCTL_PRTIMER_R0 );

	//make sure that timer (Timer A&B) is disabled before configuring
	HWREG( TIMER0_BASE+TIMER_O_CTL ) &= ~(TIMER_CTL_TAEN | TIMER_CTL_TBEN);
	
	//set it up in 32bit wide mode
	HWREG( TIMER0_BASE+TIMER_O_CFG) = TIMER_CFG_32_BIT_TIMER;
	HWREG( TIMER0_BASE+TIMER_O_TAILR ) = CLOCK_FULL_LOAD;

	//set up timer A in 1-shot mode 
	HWREG(TIMER0_BASE+TIMER_O_TAMR) = 
		(HWREG(TIMER0_BASE+TIMER_O_TAMR) & ~TIMER_TAMR_TAMR_M) | 
		TIMER_TAMR_TAMR_1_SHOT;
	
	//set timeout
	HWREG(TIMER0_BASE+TIMER_O_TAILR) = (SAFETY_TIME*TicksPerMS);
	
	//enable a local timeout interrupt
	HWREG(TIMER0_BASE+TIMER_O_IMR) |= TIMER_IMR_TATOIM; 
	
	//enable Timer 0 interrupt in the NVIC
	//it is interrupt number 19 so appears in EN0 at bit 19
	HWREG(NVIC_EN0) |= BIT19HI;
	
	// Change priority of interrupt to 2 (highest) 
	HWREG( NVIC_PRI4 ) = (HWREG( NVIC_PRI4 ) & ~NVIC_PRI4_INT19_M) +
		(PRIORITY_2 << NVIC_PRI4_INT19_S); 
	
	//make sure interrupts are enabled globally
	__enable_irq();
	
	//start timner by enabling it and enablign the timer to stall while stopped by the debugger
	HWREG(TIMER0_BASE+TIMER_O_CTL) |= (TIMER_CTL_TAEN | TIMER_CTL_TASTALL);
}

//ISR for 2ms safety dance timer 
void SafetyTimerISR (void) {
	//printf("2ms Comm lockout safety timer expired \n\r");
  //printf("*************************my asterisks******************************\n\r");
	//clear source of interrupt
	HWREG(TIMER0_BASE+TIMER_O_ICR) = TIMER_ICR_TATOCINT;
	//post the 2ms timeout event to switch states to comm active 
	ES_Event ThisEvent;
	ThisEvent.EventType = ES_2MS_TIMEOUT;
  PostCommMasterSM(ThisEvent);
	printf("2 ms timeout posted \n\r");
}	

//get frequency report command 
uint8_t GetFreqReportCMD (void){
	//return current command, called by game chat lower level sm 
	return FreqReportCMD;
}

/****************************************************************************
 Function
    GetStatusBytes

 Parameters
   none

 Returns
   none

 Description
   pulls the game status information into GameChat from CommMaster
 Notes
    
 Author
   Drew Bell, 2/28/05, 10:45AM
****************************************************************************/
void GetStatusBytes (void) {

	//get the latest status bytes received from the LOC 
	CSG = GetCSG();
	GreenActiveArea = GetGreenActiveArea();
	CSR = GetCSR();
	RedActiveArea = GetRedActiveArea();
	GreenScore = GetGreenScore ();
	RedScore = GetRedScore();
	GameStatus = GetGameStatus();

}

/****************************************************************************
 Function
    GetReportStatusBytes

 Parameters
   none

 Returns
   none

 Description
   pulls the report response information into GameChat from CommMaster
 Notes
    
 Author
   Drew Bell, 2/28/05, 10:45AM
****************************************************************************/
void GetReportResponseBytes(void) {
	//get the latest report response bytes received from the LOC
	ResponseReadyByte	= GetResponseReadyByte();
	Acknowledge = GetAcknowledge();
	NextLocation = GetNextLocation();	
}

//CurrentCommand = GetCurrentCommand();