/**************************************************************************** Module Gameplay_GameTasksSM.c Revision 2.0.1 Description This is a sub state machine (2nd level) called GameTasks within 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/21/19 bibit converted from template to project file 02/27/17 09:48 jec another correction to re-assign both CurrentEvent and ReturnEvent to the result of the During function this eliminates the need for the prior fix and allows the during function to-remap an event that will be processed at a higher level. 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 "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_ssi.h" #include "inc/hw_Timer.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 */ // this module's header file #include "Gameplay_GameTasksSM.h" // this module's lower level header files #include "Gameplay_GameTasks_CollectBallsSM.h" #include "Gameplay_GameTasks_DumpRecyclingSM.h" #include "Gameplay_GameTasks_DumpTrashSM.h" // include necessary connections for test harness #include "GP_MapKeys.h" // other modules #include "BeaconSense.h" #include "GameControlService.h" #include "MotorSM.h" #include "GameplayHSM.h" #include "ServoModule.h" /*----------------------------- Module Defines ----------------------------*/ // define constants for the states for this machine // and any other local defines #define ENTRY_STATE CollectBalls /*---------------------------- 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_t DuringCollectBalls(ES_Event_t Event); static ES_Event_t DuringDumpRecycling(ES_Event_t Event); static ES_Event_t DuringDumpTrash(ES_Event_t Event); /*---------------------------- Module Variables ---------------------------*/ // everybody needs a state variable, you may need others as well static GameTasksState_t CurrentState; static uint16_t BeaconRearFreq; /*------------------------------ Module Code ------------------------------*/ /**************************************************************************** Function RunGameTasksSM Parameters ES_Event_t: the event to process Returns ES_Event_t: an event to return Description run function for the GameTasks state machine Notes uses nested switch/case to implement the machine. Author Bibit Bianchini, 2/21/2019 ****************************************************************************/ ES_Event_t RunGameTasksSM(ES_Event_t CurrentEvent) { bool MakeTransition = false; // making a state transition? GameTasksState_t NextState = CurrentState; // default to normal entry to new state ES_Event_t EntryEventKind = { ES_ENTRY, 0 }; ES_Event_t ReturnEvent = CurrentEvent; // assume we don't consume event switch (CurrentState) { case CollectBalls: // If current state is CollectBalls { // Execute During function for CollectBalls. ES_ENTRY & ES_EXIT are // processed here to allow the lower level state machines to re-map or // consume the event ReturnEvent = CurrentEvent = DuringCollectBalls(CurrentEvent); // process any events if (CurrentEvent.EventType != ES_NO_EVENT) // if an event is active { switch (CurrentEvent.EventType) { case RECYCLE_FULL: // if our robot has reached max recycle capacity { // we want to move to DumpRecycling state NextState = DumpRecycling; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter DumpRecycling with history, so we will // leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } break; case TRASH_FULL: // if our robot has reached max trash capacity { // we want to move to DumpTrash state NextState = DumpTrash; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter DumpTrash with history, so we will // leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } break; case START_DUMPING: // if there is only enough time left to dump { // if we have any recycling balls, then we want to do that first. // we will have to query the BallSortingService: if (HowManyRecyclingBalls() > 0) { // we want to move to DumpRecycling state NextState = DumpRecycling; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter DumpRecycling with history, so we // will leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } // otherwise, if we have trash balls, then we will want to dump // trash. we will have to query the BallSortingService: else if (HowManyTrashBalls() > 0) { // we want to move to DumpTrash state NextState = DumpTrash; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter DumpTrash with history, so we // will leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } // otherwise, even if there is little time left, we don't have to // dump because our robot is empty; we will stay in CollectBalls } break; } } } break; // end switch on CurrentState case for CollectBalls case DumpRecycling: // If current state is DumpRecycling { // Execute During function for DumpRecycling. ES_ENTRY & ES_EXIT are // processed here to allow the lower level state machines to re-map or // consume the event ReturnEvent = CurrentEvent = DuringDumpRecycling(CurrentEvent); // process any events if (CurrentEvent.EventType != ES_NO_EVENT) // if an event is active { switch (CurrentEvent.EventType) { case RECYCLING_CHANGE: // if the recycling center has changed { // we want to exit and re-enter our DumpRecycling state NextState = DumpRecycling; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter DumpRecycling with history, so we will // leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } break; case RECYCLE_EMPTY: // if we emptied our recycling { // if we still have no trash balls, then we don't want to go to // DumpTrash and would instead CollectBalls. Ask // BallSortingService: if (HowManyTrashBalls() == 0) { // we want to move to CollectBalls state NextState = CollectBalls; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter CollectBalls with history, so we // will leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } // if we still have a good bit of time left in the game, then we // want to go back to collecting balls, regardless of if we have // trash balls or not. Ask GameControl service: else if (QueryGameControl() == GameOn) { // we want to move to CollectBalls state NextState = CollectBalls; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter CollectBalls with history, so we // will leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } // the last case is that we have little time left in the game and // we have trash balls to dump. In this case, we want to go to // DumpTrash. else { // we want to move to DumpTrash state NextState = DumpTrash; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter DumpTrash with history, so we // will leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } } break; } } } break; // end switch on CurrentState case for DumpRecycling case DumpTrash: // If current state is DumpTrash { // Execute During function for DumpTrash. ES_ENTRY & ES_EXIT are // processed here to allow the lower level state machines to re-map or // consume the event ReturnEvent = CurrentEvent = DuringDumpTrash(CurrentEvent); // process any events if (CurrentEvent.EventType != ES_NO_EVENT) // if an event is active { switch (CurrentEvent.EventType) { case TRASH_EMPTY: // if we emptied our trash { // if we still have no recycling balls, then we don't want to go // to DumpRecycling and would instead CollectBalls. Ask // BallSortingService: if (HowManyRecyclingBalls() == 0) { // we want to move to CollectBalls state NextState = CollectBalls; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter CollectBalls with history, so we // will leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } // if we still have a good bit of time left in the game, then we // want to go back to collecting balls, regardless of if we have // recycling balls or not. Ask GameControl service: else if (QueryGameControl() == GameOn) { // we want to move to CollectBalls state NextState = CollectBalls; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter CollectBalls with history, so we // will leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } // the last case is that we have little time left in the game and // we have recycling balls to dump. In this case, we want to go // to DumpRecycling. else { // we want to move to DumpRecycling state NextState = DumpRecycling; // mark that we are taking a transition (for internal // transitions, skip changing MakeTransition) MakeTransition = true; // we do not want to enter DumpRecycling with history, so we // will leave the default to ES_ENTRY (make no change) //EntryEventKind.EventType = ES_ENTRY_HISTORY; // consume this event for the upper state machines ReturnEvent.EventType = ES_NO_EVENT; } } break; } } } break; // end switch on CurrentState case for DumpTrash } // if we are making a state transition if (MakeTransition == true) { // Execute exit function for current state CurrentEvent.EventType = ES_EXIT; RunGameTasksSM(CurrentEvent); CurrentState = NextState; // Modify state variable // Execute entry function for new state (this defaults to ES_ENTRY) RunGameTasksSM(EntryEventKind); } return ReturnEvent; } /**************************************************************************** Function StartGameTasksSM Parameters None Returns None Description Does any required initialization for this state machine Notes Author Bibit Bianchini, 2/21/2019 ****************************************************************************/ void StartGameTasksSM(ES_Event_t 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 (CurrentEvent.EventType != ES_ENTRY_HISTORY) { CurrentState = ENTRY_STATE; } // call the entry function (if any) for the ENTRY_STATE RunGameTasksSM(CurrentEvent); } /**************************************************************************** Function QueryGameTasksSM Parameters None Returns GameTasksState_t The current state of the state machine Description returns the current state of the GameTasks state machine Notes Author Bibit Bianchini, 2/21/2019 ****************************************************************************/ GameTasksState_t QueryGameTasksSM(void) { return CurrentState; } /**************************************************************************** Collection of Functions QueryBeaconRearFreq SetBeaconRearFreq Parameters None uint16_t : the frequency Returns uint16_t : the frequencies None Description Returns the frequencies that the beacon detector should be looking for, or allows you to set the frequency. Notes Author Bibit Bianchini, 2/25/2019 ****************************************************************************/ uint16_t QueryBeaconRearFreq(void) { return BeaconRearFreq; } void SetBeaconRearFreq(uint16_t NewFreq) { BeaconRearFreq = NewFreq; } /*************************************************************************** private functions ***************************************************************************/ /**************************************************************************** Function DuringCollectBalls Parameters ES_Event_t Event Returns ES_Event_t Description During function for the CollectBalls state. Processes ES_ENTRY and ES_EXIT events, and calls lower state machines. Notes Author Bibit Bianchini, 2/21/2019 ****************************************************************************/ static ES_Event_t DuringCollectBalls(ES_Event_t Event) { ES_Event_t 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)) { // if we got in here with history, it is because we avoided a robot. // now, we don't want to go deeper with history, so we will change the // event to be ES_ENTRY only Event.EventType = ES_ENTRY; // post MOTOR_COMMAND with EventParam FORWARD ES_Event_t PostEvent; PostEvent.EventType = MOTOR_COMMAND; PostEvent.EventParam = FORWARD; PostMotorSM(PostEvent); // now start any lower level machines that run in this state StartCollectBallsSM(Event); } else if (Event.EventType == ES_EXIT) { // on exit, give the lower levels a chance to clean up first RunCollectBallsSM(Event); // no tasks to do for exit from CollectBalls } else // do the 'during' function for this state { // run any lower level state machine ReturnEvent = RunCollectBallsSM(Event); // 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; } /**************************************************************************** Function DuringDumpRecycling Parameters ES_Event_t Event Returns ES_Event_t Description During function for the DumpRecycling state. Processes ES_ENTRY and ES_EXIT events, and calls lower state machines. Notes Author Bibit Bianchini, 2/21/2019 ****************************************************************************/ static ES_Event_t DuringDumpRecycling(ES_Event_t Event) { ES_Event_t 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)) { // if we got in here with history, it is because we avoided a robot. // now, we don't want to go deeper with history, so we will change the // event to be ES_ENTRY only Event.EventType = ES_ENTRY; // start turning clockwise ES_Event_t PostEvent; PostEvent.EventType = MOTOR_COMMAND; PostEvent.EventParam = CW; PostMotorSM(PostEvent); // set BeaconRearFreq to north landfill beacon frequency BeaconRearFreq = NorthLandfillFreq; // enable interrupts for rear beacon sensor EnableRearBeaconInterrupts(); // now start any lower level machines that run in this state StartDumpRecyclingSM(Event); } else if (Event.EventType == ES_EXIT) { // on exit, give the lower levels a chance to clean up first RunDumpRecyclingSM(Event); // no tasks to do for exit from DumpRecycling } else // do the 'during' function for this state { // run any lower level state machine ReturnEvent = RunDumpRecyclingSM(Event); // 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; } /**************************************************************************** Function DuringDumpTrash Parameters ES_Event_t Event Returns ES_Event_t Description During function for the DumpTrash state. Processes ES_ENTRY and ES_EXIT events, and calls lower state machines. Notes Author Bibit Bianchini, 2/21/2019 ****************************************************************************/ static ES_Event_t DuringDumpTrash(ES_Event_t Event) { ES_Event_t 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)) { // if we got in here with history, it is because we avoided a robot. // now, we don't want to go deeper with history, so we will change the // event to be ES_ENTRY only Event.EventType = ES_ENTRY; // start turning clockwise ES_Event_t PostEvent; PostEvent.EventType = MOTOR_COMMAND; PostEvent.EventParam = CW; PostMotorSM(PostEvent); // set BeaconRearFreq based on which team we are if (GetOurLandfillFreq() == NorthLandfillFreq) { // then we want to drive to the east recycling center BeaconRearFreq = EastRecyclingFreq; } else { // otherwise we want to drive to the west recycling center BeaconRearFreq = WestRecyclingFreq; } // enable interrupts for rear beacon sensor EnableRearBeaconInterrupts(); // now start any lower level machines that run in this state StartDumpTrashSM(Event); } else if (Event.EventType == ES_EXIT) { // on exit, give the lower levels a chance to clean up first RunDumpTrashSM(Event); // no tasks to do for exit from DumpTrash } else // do the 'during' function for this state { // run any lower level state machine ReturnEvent = RunDumpTrashSM(Event); // 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; } /*------------------------------- Footnotes -------------------------------*/ /*------------------------------ End of file ------------------------------*/