You are on page 1of 12

/****************************************************************************

Module
GameMasterSM.c

Revision
2.0.1

Description
This is a template for the top level Hierarchical state machine

Notes

History
When Who What/Why
-------------- --- --------
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 "GameMasterSM.h"
#include "FaceOffSM.h"
#include "OffenseSM.h"
#include "DefenseSM.h"
#include "LEDs.h"
#include "DCMotor.h"
#include "ServoMotor.h"
#include "ColorSensor.h"

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


//test defines
//#define TEST

//Team color defines


#define RED 1
#define BLUE 0

#define ONE_SEC 1000


#define TW_SEC 20*ONE_SEC
#define TWO_SEC 2*ONE_SEC

#define Forward 0
#define Backward 1
#define CWTurn 2
#define CCWTurn 3
#define LeftMotor 0
#define RightMotor 1
/*---------------------------- Module Functions ---------------------------*/
static ES_Event_t DuringGameNotActive( ES_Event_t Event);
static ES_Event_t DuringFaceOff(ES_Event_t Event);
static ES_Event_t DuringOffense(ES_Event_t Event);
static ES_Event_t DuringDefense(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
#ifdef TEST
static int counter = 0;
#endif
static GameMasterState_t CurrentState;
// with the introduction of Gen2, we need a module level Priority var as well
static uint8_t MyPriority;
static uint16_t TEAM = RED; //set default team color to RED, TEAM should be a module
level static var to keep team color info
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitGameMasterSM

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
J. Edward Carryer, 02/06/12, 22:06
****************************************************************************/
bool InitGameMasterSM ( uint8_t Priority )
{
ES_Event_t ThisEvent;

//save our priority


MyPriority = Priority;

ThisEvent.EventType = ES_ENTRY;
// Start the Master State machine
StartGameMasterSM( ThisEvent );

return true;
}

/****************************************************************************
Function
PostGameMasterSM

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

/****************************************************************************
Function
RunGameMasterSM

Parameters
ES_Event: the event to process

Returns
ES_Event: an event to return

Description
the run function for the top level state machine
Notes
uses nested switch/case to implement the machine.
Author
J. Edward Carryer, 02/06/12, 22:09
****************************************************************************/
ES_Event_t RunGameMasterSM( ES_Event_t CurrentEvent )
{
//set MakeTransition to false by default
bool MakeTransition = false;
GameMasterState_t NextState = CurrentState; //set NestState to CurrentState
ES_Event_t EntryEventKind = { ES_ENTRY, TEAM };// instead of default to normal
entry to new state, we set param to TEAM and pass down to lower level SM
ES_Event_t ReturnEvent = { ES_NO_EVENT, 0 }; // assume no error, for top level
sm we always need a return event set to ES_NO_ERROR

// if (CurrentEvent.EventType == DEBUG_ENCODER)
// {
// printf("From RunGameMasterSM, Encoder Time: %d \r\n",
CurrentEvent.EventParam);
// }

switch ( CurrentState )
//CurrentState can be one of: GameNotActive, FaceOff, Offense, Defense
//EventType can be one of: EV_WAIT4START, EV_FACEOFF, EV_REDPO, EV_BLUEPO,
EV_GAMEOVER. Except the first one, all other
//events need to be responded in any of FaceOff, Offense, and Defense
{
case GameNotActive : // If current state is GameNotActive
// Execute During function for GameNotActive. ES_ENTRY & ES_EXIT are
// processed here allow the lowere level state machines to re-map
// or consume the event
CurrentEvent = DuringGameNotActive(CurrentEvent);
//process any events
if ( CurrentEvent.EventType != ES_NO_EVENT ) //If an event is active
{
switch (CurrentEvent.EventType)
{
case EV_WAIT2START : //If event is EV_WAIT2START
// Execute action function for GameNotActive, EV_WAIT2START
NextState = GameNotActive;//Decide next state to be GameNotActive
// for internal transitions, skip changing MakeTransition
MakeTransition = false; //mark that we are not taking a transition
// if transitioning to a state with history change kind of entry
EntryEventKind.EventType = ES_ENTRY_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_FACEOFF : //If event is EV_FACEOFF
// Execute action function for GameNotActive, EV_FACEOFF
NextState = FaceOff;//Decide next state to be FaceOff
// for internal transitions, skip changing MakeTransition
MakeTransition = true; //mark that we are taking a transition
#ifdef TEST
MakeTransition = false;
#endif
// if transitioning to a state with history change kind of entry
EntryEventKind.EventType = ES_ENTRY_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
#ifdef TEST
case ES_TIMEOUT:
if(CurrentEvent.EventParam == MOTOR_TIMER){
// if(counter == 1){
// LoadBall();
// }
// if(counter == 2){
// ChargeBall();
// }
// if(counter == 3){
// FireBall();
// }
// if(counter == 4){
// ResetBall();
// }
counter++;
printRPM();
NextState = GameNotActive;
MakeTransition = false;
ES_Timer_InitTimer(MOTOR_TIMER, 200);
}
break;
case EV_ANGLE_TARGET_REACHED:
//StopRobot();
printf("we turned 45 deg in GameMasterSM\n\r");
NextState = GameNotActive;
MakeTransition = false;
break;
// case EV_X_TARGET_REACHED:
// printf("we reached target \n\r");
// printRPM();
// StopRobot();
// NextState = GameNotActive;
// MakeTransition = false;
// break;
#endif
default:
;
}
}
break;
// repeat state pattern as required for other states
case FaceOff : // If current state is FaceOff
// Execute During function for FaceOff. ES_ENTRY & ES_EXIT are
// processed here allow the lowere level state machines to re-map
// or consume the event
CurrentEvent = DuringFaceOff(CurrentEvent);
//process any events
if ( CurrentEvent.EventType != ES_NO_EVENT ) //If an event is active
{
switch (CurrentEvent.EventType)
{
case EV_GAMEOVER : //If event is EV_GAMEOVER
// Execute action function for FaceOff, EV_GAMEOVER
NextState = GameNotActive;//Decide next state to be GameNotActive
// 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_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_REDPO : //If event is EV_REDPO
// Execute action function for FaceOff, EV_REDPO
//if we are TEAM RED, set NextState to Offense, otherwise set to
Defense
if(TEAM == RED){
NextState = Offense;
}else{
NextState = Defense;
}
// 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_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_BLUEPO : //If event is EV_BLUEPO
// Execute action function for FaceOff, EV_BLUEPO
//if we are TEAM BLUE, set NextState to Offense, otherwise set to
Defense
if(TEAM == BLUE){
NextState = Offense;
}else{
NextState = Defense;
}
// 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_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_FACEOFF : //If event is EV_FACEOFF
// Execute action function for FaceOff: EV_FACEOFF
NextState = FaceOff; //set NextState to FaceOff
// for internal transitions, skip changing MakeTransition
MakeTransition = false; //mark that we are not taking a transition
// if transitioning to a state with history change kind of entry
EntryEventKind.EventType = ES_ENTRY_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
default:
;
}
}
break;
// repeat state pattern as required for other states
case Offense : // If current state is Offense
// Execute During function for Offense. ES_ENTRY & ES_EXIT are
// processed here allow the lowere level state machines to re-map
// or consume the event
CurrentEvent = DuringOffense(CurrentEvent);
//process any events
if ( CurrentEvent.EventType != ES_NO_EVENT ) //If an event is active
{
switch (CurrentEvent.EventType)
{
case EV_GAMEOVER : //If event is EV_GAMEOVER
// Execute action function for Offense, EV_GAMEOVER
NextState = GameNotActive;//Decide NextState will be GameNotActive
// 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_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_REDPO : //If event is EV_REDPO
// Execute action function for Offense, EV_REDPO
//if we are TEAM RED, set NextState to Offense without transiting
state
if(TEAM == RED){
NextState = Offense;
MakeTransition = false;
}else{ //else set NextState to Defense with transiting state
NextState = Defense;
MakeTransition = true;
// ES_Timer_InitTimer(SHOTCLK, CurrentEvent.EventParam);
}
// for internal transitions, skip changing MakeTransition
// if transitioning to a state with history change kind of entry
EntryEventKind.EventType = ES_ENTRY_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_BLUEPO : //If event is EV_BLUEPO
// Execute action function for Offense, EV_BLUEPO
//if we are TEAM BLUE, set NextState to Offense without transiting
state
if(TEAM == BLUE){
NextState = Offense;
MakeTransition = false;
}else{ //else set NextState to Defense with transiting state
NextState = Defense; //Decide what the next state will be
MakeTransition = true;
// ES_Timer_InitTimer(SHOTCLK, CurrentEvent.EventParam);
}
// for internal transitions, skip changing MakeTransition
// if transitioning to a state with history change kind of entry
EntryEventKind.EventType = ES_ENTRY_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_FACEOFF : //If event is event one
// Execute action function for Offense: EV_FACEOFF
// for internal transitions, skip changing MakeTransition
//set NextState to FaceOff
NextState = FaceOff;
MakeTransition = true; //mark that we are taking a transition
// if transitioning to a state with history change kind of entry
EntryEventKind.EventType = ES_ENTRY_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
default:
;
}
}
break;
// repeat state pattern as required for other states
case Defense : // If current state is Defense
// Execute During function for Defense. ES_ENTRY & ES_EXIT are
// processed here allow the lowere level state machines to re-map
// or consume the event
CurrentEvent = DuringDefense(CurrentEvent);
//process any events
if ( CurrentEvent.EventType != ES_NO_EVENT ) //If an event is active
{
switch (CurrentEvent.EventType)
{
case EV_GAMEOVER : //If event is EV_GAMEOVE
// Execute action function for Defense, EV_GAMEOVER
NextState = GameNotActive;//Decide next state to be GameNotActive
// 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_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_REDPO : //If event is EV_REDPO
// Execute action function for Defense, EV_REDPO
//if we are TEAM RED, set NextState to Offense with transiting state
if(TEAM == RED){
NextState = Offense;
MakeTransition = true;
}else{ //else set NextState to Defense without transiting state
NextState = Defense;
MakeTransition = false;
}
// for internal transitions, skip changing MakeTransition
// if transitioning to a state with history change kind of entry
EntryEventKind.EventType = ES_ENTRY_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_BLUEPO : //If event is EV_BLUEPO
// Execute action function for Defense, EV_BLUEPO
//if we are TEAM BLUE, set NextState to Offense with transiting state
if(TEAM == BLUE){
NextState = Offense; //Decide what the next state will be
MakeTransition = true;
}else{ //else set NextState to Defense without transiting state
NextState = Defense; //Decide what the next state will be
MakeTransition = false;
}
// 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_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case EV_FACEOFF : //If event is EV_FACEOFF
// Execute action function for Defense, EV_FACEOFF
//set NextState to FaceOff
NextState = FaceOff;
// 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_HISTORY; //we will decide if we
need a history state or not
break;
// repeat cases as required for relevant events
case ES_TIMEOUT: //if event is ES_TIMEOUT
if(CurrentEvent.EventParam == SHOTCLK){
#ifdef TEST
printf("SHOTCLK timeout received\n\r");
#endif
//set NextState to FaceOff
NextState = FaceOff;
MakeTransition = true; //mark that we are making a transition
EntryEventKind.EventType = ES_ENTRY_HISTORY;
}
break;
default:
;
}
}
break;
}
// If we are making a state transition
if (MakeTransition == true)
{
// Execute exit function for current state
CurrentEvent.EventType = ES_EXIT;
RunGameMasterSM(CurrentEvent);

CurrentState = NextState; //Modify state variable

// Execute entry function for new state


// this defaults to ES_ENTRY
EntryEventKind.EventParam = TEAM;
RunGameMasterSM(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
StartGameMasterSM

Parameters
ES_Event CurrentEvent

Returns
nothing

Description
Does any required initialization for this state machine
Notes

Author
J. Edward Carryer, 02/06/12, 22:15
****************************************************************************/
void StartGameMasterSM ( ES_Event_t CurrentEvent )
{
// if there is more than 1 state to the top level machine you will need
// to initialize the state variable
//init CurrentState to GameNotActive
CurrentState = GameNotActive;

// 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
RunGameMasterSM(CurrentEvent);
return;
}

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

static ES_Event_t DuringGameNotActive( 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) )
{
// implement any entry actions required for this state machine

//Init and turn off LEDs


InitLEDs();
TurnOffLEDs();

//Init DCMotors
InitMotors();
StopRobot();

//Init Servo motors


InitServo();
DefaultBall();

#ifdef TEST
counter++;
printf("we are in GameNotActive\n\r");
//SetRobotDir(Forward);
//SetRobotSpeed(LeftMotor, 15);
//SetRobotSpeed(RightMotor, 15);
//SetTargetPosition(150, 150);

SetRobotDir(Forward);
SetRobotSpeed(LeftMotor, 13);
SetRobotSpeed(RightMotor, 15);
SetTargetHeading(0);
printRPM();
ES_Timer_InitTimer(MOTOR_TIMER, 200);
printf("finished\r\n");
#endif
// 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

//turn on game indicator


TurnOnYLED();
// grab team color info from GetTeamColor()
TEAM = GetTeamColor();
//printf(" TEAM color = %d\n\r", TEAM); //RED = 1, BLUE = 0
//set TEAM to corresponding COLOR
// Light up corresponding LED (red or blue)
if(TEAM == RED) TurnOnRLED();
else TurnOnBLED();

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

static ES_Event_t DuringFaceOff( 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) )
{
// implement any entry actions required for this state machine

// after that start any lower level machines that run in this state
StartFaceOffSM( 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
RunFaceOffSM(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 = RunFaceOffSM(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);
}
static ES_Event_t DuringOffense( 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) )
{
// implement any entry actions required for this state machine

// after that start any lower level machines that run in this state
StartOffenseSM( Event ); //Event.EventParam = TEAM
// 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
RunOffenseSM(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 = RunOffenseSM(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);
}

static ES_Event_t DuringDefense( 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) )
{
// implement any entry actions required for this state machine

// after that start any lower level machines that run in this state
StartDefenseSM( Event ); //Event.EventParam = TEAM
// 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
RunDefenseSM(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 = RunDefenseSM(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);
}

You might also like