/****************************************************************************
 Module
   GameplayHSM.c

 Revision
   2.0.1

 Description
   This is the Gameplay module for ME 218B project for Team 3.  Implements a
   hierarchical state machine under the Gen2 Events and Services Framework.

 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 02/20/19       bibit   converted from template to project file
 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"

// this module's own header file
#include "GameplayHSM.h"

// next lowest level header files
#include "Gameplay_GameTasksSM.h"

// other modules
#include "MotorSM.h"
#include "PWM_Module.h"

#include "inc/hw_pwm.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_nvic.h"
#include "inc/hw_Timer.h"

#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/pwm.h"

/*----------------------------- Module Defines ----------------------------*/
// time for backing away from other robot before turning around
#define BackAwayTime 1000

/*---------------------------- Module Functions ---------------------------*/
static ES_Event_t DuringIdleState(ES_Event_t Event);
static ES_Event_t DuringGameTasksState(ES_Event_t Event);
static void StopConveyor(void);
static void StartConveyor(void);

/*---------------------------- 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 GameplayState_t CurrentState;

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

/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
 Function
     InitGameplayMasterSM

 Parameters
     uint8_t : the priority of this service

 Returns
     boolean, False if error in initialization, True otherwise

 Description
     Saves away the priority, and starts the top level state machine.  Also
     sets initial state for the conveyor motor.

 Notes

 Author
     Bibit Bianchini, 2/20/2019
****************************************************************************/
bool InitGameplayMasterSM(uint8_t Priority)
{
  ES_Event_t ThisEvent;
  MyPriority = Priority;  // save our priority

  // start with the conveyor motor stopped
  StopConveyor();

  ThisEvent.EventType = ES_ENTRY;

  // Start the Master State machine
  StartGameplayMasterSM(ThisEvent);

  return true;
}

/****************************************************************************
 Function
     PostGameplayMasterSM

 Parameters
     ES_Event_t 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
     J. Edward Carryer, 10/23/11, 19:25
****************************************************************************/
bool PostGameplayMasterSM(ES_Event_t ThisEvent)
{
  return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
    RunGameplayMasterSM

 Parameters
   ES_Event_t: the event to process

 Returns
   ES_Event_t: an event to return

 Description
   the run function for the top level Gameplay state machine

 Notes
   uses nested switch/case to implement the machine

 Author
   Bibit Bianchini, 2/20/2019
****************************************************************************/
ES_Event_t RunGameplayMasterSM(ES_Event_t CurrentEvent)
{
  bool            MakeTransition = false; // are we making a state transition?
  GameplayState_t NextState = CurrentState;

  // default to normal entry to new state
  ES_Event_t  EntryEventKind = { ES_ENTRY, 0 };
  ES_Event_t  ReturnEvent = { ES_NO_EVENT, 0 }; // assume no error

  switch (CurrentState)
  {
    case IdleGame:       // If current state is Idle
    {
      // execute During function for Idle state. ES_ENTRY & ES_EXIT are
      // processed there to allow the lower level state machines to re-map or
      // consume the event
      CurrentEvent = DuringIdleState(CurrentEvent);

      // process any events
      if (CurrentEvent.EventType != ES_NO_EVENT)   // if an event is active
      {
        switch (CurrentEvent.EventType)
        {
          case GAME_STARTED: // if the game has started
          {
            // we want to move to GameTasks state
            NextState = GameTasks;

            // mark that we are taking a transition (for internal
            // transitions, skip changing MakeTransition)
            MakeTransition = true;

            // we do not want to enter GameTasks with history, so we will
            // leave the default to ES_ENTRY (make no change)
            //EntryEventKind.EventType = ES_ENTRY_HISTORY;
          }
          break;
        }
      }
    }
    break;

    case GameTasks:       // If current state is GameTasks
    {
      // execute During function for GameTasks state. ES_ENTRY & ES_EXIT are
      // processed there to allow the lower level state machines to re-map or
      // consume the event
      CurrentEvent = DuringGameTasksState(CurrentEvent);

      // process any events
      if (CurrentEvent.EventType != ES_NO_EVENT)   // if an event is active
      {
        switch (CurrentEvent.EventType)
        {
          case GAME_OVER: // if the game has ended
          {
            // we want to move to Idle state
            NextState = IdleGame;

            // mark that we are taking a transition (for internal
            // transitions, skip changing MakeTransition)
            MakeTransition = true;
          }
          break;
        }
      }
    }
    break;
  } // end of switch on CurrentState

  // if we are making a state transition
  if (MakeTransition == true)
  {
    // execute exit function for current state
    CurrentEvent.EventType = ES_EXIT;
    RunGameplayMasterSM(CurrentEvent);

    CurrentState = NextState; // modify state variable

    // execute entry function for new state (this defaults to ES_ENTRY)
    RunGameplayMasterSM(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 function
  return ReturnEvent;
}

/****************************************************************************
 Function
     StartGameplayMasterSM

 Parameters
     ES_Event_t CurrentEvent

 Returns
     none

 Description
     Does any required initialization for this state machine

 Notes

 Author
     Bibit Bianchini, 2/20/2019
****************************************************************************/
void StartGameplayMasterSM(ES_Event_t CurrentEvent)
{
  // initialize the CurrentState variable to start in Idle state
  CurrentState = IdleGame;

  // now we need to let the Run function init the lower level state machines
  // use LocalEvent to keep the compiler from complaining about unused var
  RunGameplayMasterSM(CurrentEvent);

  return;
}

/****************************************************************************
 Function
     QueryGameplayHSM

 Parameters
     None

 Returns
     GameplayState_t The current state of the state machine

 Description
     returns the current state of the Gameplay state machine

 Notes

 Author
     Bibit Bianchini, 2/23/2019
****************************************************************************/
GameplayState_t QueryGameplayHSM(void)
{
  return CurrentState;
}

/***************************************************************************
 private functions
 ***************************************************************************/
/****************************************************************************
 Function
     DuringIdleState

 Parameters
     ES_Event_t Event

 Returns
     ES_Event_t

 Description
     During function for the Idle state.  Processes ES_ENTRY and ES_EXIT
     events, but has no lower state machine to call.

 Notes

 Author
     Bibit Bianchini, 2/20/2019
****************************************************************************/
static ES_Event_t DuringIdleState(ES_Event_t Event)
{
  ES_Event_t ReturnEvent = Event; // assume no re-mapping or comsumption

  // process ES_ENTRY, ES_ENTRY_HISTORY & ES_EXIT events
  if ((Event.EventType == ES_ENTRY) ||
      (Event.EventType == ES_ENTRY_HISTORY))
  {
    // stop conveyor belt
    StopConveyor();

    // no lower state machines to start
  }
  else if (Event.EventType == ES_EXIT)
  {
    // no lower state machines to give the chance to clean up
    // start conveyor belt
    StartConveyor();
  }

  // this state machine doesn't have a lower state machine to run

  // 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;
}

/****************************************************************************
 Function
     DuringGameTasksState

 Parameters
     ES_Event_t Event

 Returns
     ES_Event_t

 Description
     During function for the GameTasks state.  Processes ES_ENTRY and ES_EXIT
     events, and calls lower state machines.

 Notes

 Author
     Bibit Bianchini, 2/20/2019
****************************************************************************/
static ES_Event_t DuringGameTasksState(ES_Event_t Event)
{
  ES_Event_t ReturnEvent = Event; // assume no re-mapping or comsumption

  // process ES_ENTRY, ES_ENTRY_HISTORY & ES_EXIT events
  if ((Event.EventType == ES_ENTRY) ||
      (Event.EventType == ES_ENTRY_HISTORY))
  {
    // no actions for entering this state

    // after that start the lower level machine that runs in this state
    StartGameTasksSM(Event);
  }
  else if (Event.EventType == ES_EXIT)
  {
    // on exit, give the lower levels a chance to clean up first
    RunGameTasksSM(Event);

    // no actions for exiting this state
  }
  else // do the 'during' function for this state
  {
    // run any lower level state machine
    ReturnEvent = RunGameTasksSM(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;
}

/****************************************************************************
 Collection of Functions
     StopConveyor
     StartConveyor

 Parameters
     none

 Returns
     none

 Description
     Stops/starts the conveyor belt.

 Notes

 Author
     Bibit Bianchini, 3/01/2019
****************************************************************************/
static void StopConveyor(void)
{
  // set the conveyor output pin low
  HWREG(GPIO_PORTF_BASE + (GPIO_O_DATA + ALL_BITS)) &= BIT0LO;
}

static void StartConveyor(void)
{
  // set the conveyor output pin high
  HWREG(GPIO_PORTF_BASE + (GPIO_O_DATA + ALL_BITS)) |= BIT0HI;
}

/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/