/****************************************************************************
 Module
   CommunicationsMaster.c

 Revision
   2.0.1

 Description
   This is for the top level Communications Hierarchical state machine

 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 02/16/18 12:30 ra       edited for ME218b project
 02/20/17 14:30 jec      updated to remove sample of consuming an event. We 
                         always want to return ES_NO_EVENT at the top level 
                         unless there is a non-recoverable error at the 
                         framework level
 02/03/16 15:27 jec      updated comments to reflect small 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
                         removed Microwave specific code and replaced with generic
 02/08/12 01:39 jec      converted from MW_MasterMachine.c
 02/06/12 22:02 jec      converted to Gen 2 Events and Services Framework
 02/13/10 11:54 jec      converted During functions to return Event_t
                         so that they match the template
 02/21/07 17:04 jec      converted to pass Event_t to Start...()
 02/20/07 21:37 jec      converted to use enumerated type for events
 02/21/05 15:03 jec      Began Coding

****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* 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 "CommunicationsMaster.h"

#include <string.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdint.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"  
#include "driverlib/gpio.h"

#include "inc/hw_pwm.h"
#include "inc/hw_nvic.h"
#include "inc/hw_timer.h"

#include "inc/tm4c123gh6pm.h" // Define PART_TM4C123GH6PM in project
#include "inc/hw_ssi.h" 

//header file for other Services
#include "LolaGameMaster.h"

//header files for lower levels 
#include "ByteTransfer.h" 

//helper file
#include "SPI.h"

/*----------------------------- Module Defines ----------------------------*/
#define COM_TIME 200

/*---------------------------- Module Functions ---------------------------*/
static ES_Event_t DuringComWaiting( ES_Event_t Event);
static ES_Event_t DuringComXmitting( ES_Event_t Event);
/*---------------------------- Module Variables ---------------------------*/
// everybody needs a state variable, though if the top level state machine
// is just a single state container for orthogonal regions, you could get
// away without it
static CommunicationsMaster_State_t CurrentState;

static uint8_t GameStatus= 0; // 0 = waiting, 1 = faceoff, 2 = playing, 3 = tiebreak, 4 = gameover

// with the introduction of Gen2, we need a module level Priority var as well
static uint8_t MyPriority;

static uint8_t CurPosessionByte;

/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitMasterSM

 Parameters
     uint8_t : the priorty of this service

 Returns
     boolean, False if error in initialization, True otherwise

 Description
     Saves away the priority,  and starts
     the top level state machine
 Notes

 Author
     R. Adenekan
****************************************************************************/
bool InitComMasterSM ( uint8_t Priority )
{
	//Create a ThisEvent variable
  ES_Event_t ThisEvent;

  MyPriority = Priority;  // save our priority

	//Set the EventType of ThisEvent to ES_ENTRY
  ThisEvent.EventType = ES_ENTRY;
  
  //we should initialize the SPI module in main
  
  // start COM_TIMER to query itself
  ES_Timer_InitTimer(COM_TIMER,COM_TIME);  //start 100ms timer
    
  // Start the ComMaster State machine
  StartComMasterSM( ThisEvent );

  return true;
}

/****************************************************************************
 Function
     PostMasterSM

 Parameters
     ES_Event ThisEvent , the event to post to the queue

 Returns
     boolean False if the post operation failed, True otherwise

 Description
     Posts an event to this state machine's queue
 Notes

 Author
    R. Adenekan
****************************************************************************/
bool PostComMasterSM( ES_Event_t ThisEvent )
{
  return ES_PostToService( MyPriority, ThisEvent);
}

/****************************************************************************
 Function
    RunComMasterSM

 Parameters
   ES_Event: the event to process

 Returns
   ES_Event: an event to return

 Descriptionf
   the run function for the top level state machine 
 Notes
   uses nested switch/case to implement the machine.
 Author
   R. Adenekan
****************************************************************************/
ES_Event_t RunComMasterSM( ES_Event_t CurrentEvent )
{
   bool MakeTransition = false;/*We are not making a state transition */
	 //Set the NextState equal to the CUrrentState
   CommunicationsMaster_State_t NextState = CurrentState;
   ES_Event_t EntryEventKind = { ES_ENTRY, 0 };// default to normal entry to new state
   ES_Event_t ReturnEvent = { ES_NO_EVENT, 0 }; // assume no error

    switch ( CurrentState )
   {
       case (ComWaiting) :       // If current state is ComWaiting
         // No During function for ComWaiting 
        CurrentEvent = DuringComWaiting(CurrentEvent);
                 
       //process any events
         if ( CurrentEvent.EventType != ES_NO_EVENT ) //If an event is active
         {
            switch (CurrentEvent.EventType)
            {
							//If the Event.Type is an ES_TIMEOUT
               case (ES_TIMEOUT):
                  if (CurrentEvent.EventParam == COM_TIMER) //If COM_TIMER Timeout
                  {
                   // No actions to execute for ComWaiting
									 //Set the NextState to ComXmitting
                  NextState = ComXmitting;
                  MakeTransition = true; //mark that we are taking a transition
                 // start COM_TIMER to query itself
                  ES_Timer_InitTimer(COM_TIMER,COM_TIME);   //reset 100ms timer
                  break;
                  }
            }
          }
         break;
          
        case (ComXmitting) : //If event is ComXmitting
          CurrentEvent = DuringComXmitting(CurrentEvent);
          //process events
          if (CurrentEvent.EventType !=ES_NO_EVENT) //If an event is active
          { 
              switch (CurrentEvent.EventType)
              {
                case ES_READY2WRITE : //case ES_READY2WRITE  If there are no commands (ready2write)'
								//Set NextState to ComWaiting
                  NextState = ComWaiting;
                  MakeTransition = true; //mark that we are taking a transition
                   break;
             }
          }
         break; 
    }
		
    //   If we are making a state transition
    if (MakeTransition == true)
    {
       //Execute exit function for current state
       CurrentEvent.EventType = ES_EXIT;
      //Run state machine for clean up
       RunComMasterSM(CurrentEvent);
      //Set CurrentState to NextState
       CurrentState = NextState; 
       // Execute entry function for new state
       // this defaults to ES_ENTRY
       RunComMasterSM(EntryEventKind);
     }
   // in the absence of an error the top level state machine should
   // always return ES_NO_EVENT, which we initialized at the top of func
   return(ReturnEvent);
}
/****************************************************************************
 Function
     StartComMasterSM

 Parameters
     ES_Event CurrentEvent

 Returns
     nothing

 Description
     Does any required initialization for this state machine
 Notes

 Author
     R. Adenekan, 02/06/12, 22:15
****************************************************************************/
void StartComMasterSM ( ES_Event_t CurrentEvent )
{
  //Initalize the CurrentState to ComWaiting
  CurrentState = ComWaiting;
  //Run ComMaster with the CurrentEvent
  RunComMasterSM(CurrentEvent);
  return;
}

/****************************************************************************
 Function
     GetGameStatus

 Parameters	
		 None
 Returns
     GameStatus variable

 Description
     Query function that returns the current state of the game
 Notes

 Author
     R. Adenekan, 02/06/12, 22:15
****************************************************************************/

uint8_t GetGameStatus(void)
{
	//Return GameStatus
  return GameStatus;
}

/****************************************************************************
 Function
     GetCurrentPosession

 Parameters	
		 None
 Returns
     CurPosessionByte

 Description
     Query function that returns the current team posession
 Notes

 Author
     R. Adenekan, 02/06/12, 22:15
****************************************************************************/

    // Getter functions for the Current posession
    uint8_t GetCurrentPosession(void)
      {
        if (CurPosessionByte==0x01) //red  
          {
            return 1;
          }
          else
          {
            return 0; //blue
          }
      }

/***************************************************************************
 private functions
 ***************************************************************************/
	static ES_Event_t DuringComWaiting( ES_Event_t Event)
{
    ES_Event_t ReturnEvent = Event; // assme no re-mapping or comsumption

    // process ES_ENTRY, ES_ENTRY_HISTORY & ES_EXIT events
    if ( (Event.EventType == ES_ENTRY) ||
         (Event.EventType == ES_ENTRY_HISTORY) )
    {
      // if there's a difference in the previous and current response bytes
      if(GetCurrentByte3() != GetPreviousByte3())
      {
        // GAME STATUS
        // Masked Byte 3 to just have Game Status information
        uint8_t CurGameStatusByte = (GetCurrentByte3() & 0x07);   // Current
        uint8_t PreGameStatusByte = (GetPreviousByte3() & 0x07);  // Previous
        
        // Check to see if the game status has changed
        if(CurGameStatusByte != PreGameStatusByte)
        {
          // Checking to see what Game Status we changed to
          if(CurGameStatusByte == 0x01)
          {
            GameStatus = 1;
            // Post FACE_OFF to LolaGameMaster
            ES_Event_t  Event2Post; 
            Event2Post.EventType = FACE_OFF;
            PostLolaGameMasterSM(Event2Post);
          }
          else if(CurGameStatusByte == 0x02)
          {
            GameStatus = 2;
            // Post READY_TO_PLAY to LolaGameMaster
            ES_Event_t Event2Post;
            Event2Post.EventType=READY_TO_PLAY;
            PostLolaGameMasterSM(Event2Post);
          }
          else if(CurGameStatusByte == 0x03)
          {
            GameStatus = 3;
            // Post TIE_BREAK to LolaGameMaster
            ES_Event_t Event2Post;
            Event2Post.EventType=TIE_BREAK;
            PostLolaGameMasterSM(Event2Post);            
          }
          // Special mask for this because bits 0,1 vary
          else if((CurGameStatusByte & 0x04) == 0x04)
          {
            GameStatus = 4;
            // Post GAME_OVER to LolaGameMaster
            ES_Event_t Event2Post;
            Event2Post.EventType=GAME_OVER;
            PostLolaGameMasterSM(Event2Post);            
          }
          else
          {
            GameStatus = 0;
          }
        }
        
        // POSESSION
        // Shifted Byte 3 by 4 (to move our important info), then masked for posession information
        CurPosessionByte = ((GetCurrentByte3() >> 4) & 0x03);  // Current  
        uint8_t PrePosessionByte = ((GetPreviousByte3() >> 4) & 0x03); // Previous
        
        // Check to see if the posession has changed
        if(CurPosessionByte != PrePosessionByte)
        {
          ES_Event_t Event2Post;
					//Post CHANGE_POSESSION to LolaGameMaster
          Event2Post.EventType=CHANGE_POSESSION;
          PostLolaGameMasterSM(Event2Post);
        }
      }
    }
    else if ( Event.EventType == ES_EXIT )
    {      
    }else
    {
    }
    // 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_t DuringComXmitting( ES_Event_t Event)
{
    ES_Event_t ReturnEvent = Event; // assme no re-mapping or comsumption

    // process ES_ENTRY, ES_ENTRY_HISTORY & ES_EXIT events
    if ( (Event.EventType == ES_ENTRY) ||
         (Event.EventType == ES_ENTRY_HISTORY) )
    {
				//Start lower level ByteTransfer state machine
        StartByteTransferSM( Event );
    }
    else if ( Event.EventType == ES_EXIT )
    {
        ///Run lower level ByteTransfer state machine
        RunByteTransferSM(Event);     
    }
		else
    {
       //Set the ReturnEvent equal to the return from RunByteTransferSM
       ReturnEvent = RunByteTransferSM(Event);
    }
    // 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);
}
f