/**************************************************************************** Module EndGameFSM.c Revision 1.0.1 Description State machine for end of game behavior (both win and lose) Notes ****************************************************************************/ /*----------------------------- 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 "EndGameFSM.h" #include "Tot.h" #include "Crisis.h" #include "Cannon.h" #include "AirLeakLib.h" #include "Meteor.h" #include "PowerLib.h" #include "ArcadeFSM.h" #include "WelcomeFSM.h" /*----------------------------- Module Defines ----------------------------*/ #define WIN_DELAY 200 #define LOSE_DELAY 100 #define LED_MOD 5 #define MAX( a, b ) ( ( a > b) ? a : b ) #define OFF_DELAY 500 #define TOTAL_NUMBER_LED 8 //total number of LED per bank (8) #define LAST_LED TOTAL_NUMBER_LED //last LED is number 8, closer to the dome #define FIRST_LED_BANK 0 #define MIDDLE_LED_BANK 1 #define LAST_LED_BANK 2 #define CANNON_CENTER_POS 50 /*---------------------------- Module Functions ---------------------------*/ /* prototypes for private functions for this machine.They should be functions relevant to the behavior of this state machine */ /*---------------------------- Module Variables ---------------------------*/ // everybody needs a state variable, you may need others as well. // type of state variable should match htat of enum in header file static EndGameState_t CurrentState; // with the introductio n of Gen2, we need a module level Priority var as well static uint8_t MyPriority; // counter for blinking LEDs (win) or number of steps (lose) static uint16_t counter; // from 0-2, for cannon shooting fireworks static uint8_t position; // keeps track of whether LEDs/buzzer are on or off static bool ToggleOn = true; // true if cannon pos > 50, false if cannon pos < 50 // determines to which side the cannon falls static bool CannonDirection; /*------------------------------ Module Code ------------------------------*/ /**************************************************************************** Function InitEndGameFSM Parameters uint8_t : the priorty of this service Returns bool, false if error in initialization, true otherwise Description Saves away the priority, sets up the initial transition and does any other required initialization for this state machine Notes Author: Rachel Thomasson ****************************************************************************/ bool InitEndGameFSM(uint8_t Priority) { ES_Event_t ThisEvent; MyPriority = Priority; // put us into the Initial PseudoState CurrentState = InitPState_E; // post the initial transition event ThisEvent.EventType = ES_INIT; if (ES_PostToService(MyPriority, ThisEvent) == true) { return true; } else { return false; } } /**************************************************************************** Function PostEndGameFSM Parameters EF_Event_t ThisEvent , the event to post to the queue Returns boolean False if the Enqueue operation failed, True otherwise Description Posts an event to this state machine's queue Notes Author: Rachel Thomasson ****************************************************************************/ bool PostEndGameFSM(ES_Event_t ThisEvent) { return ES_PostToService(MyPriority, ThisEvent); } /**************************************************************************** Function RunEndGameFSM Parameters ES_Event_t : ES_INIT, End_Of_Game, ES_TIMEOUT, Tot_Inserted Returns ES_Event_t, ES_NO_EVENT if no error ES_ERROR otherwise Description Control events during End_Of_Game. Different LED pattern and actions for GAME_OVER and Win. Author: Rachel Thomasson ****************************************************************************/ ES_Event_t RunEndGameFSM(ES_Event_t ThisEvent) { ES_Event_t ReturnEvent; ReturnEvent.EventType = ES_NO_EVENT; // assume no errors switch (CurrentState) { case InitPState_E: // If current state is initial Psedudo State { if (ThisEvent.EventType == ES_INIT) // only respond to ES_Init { // now put the machine into the actual initial state CurrentState = Idle_E; } } break; case Idle_E: { switch (ThisEvent.EventType) { case End_Of_Game: { if (ThisEvent.EventParam == WIN) { // Start timer ES_Timer_InitTimer(ENDOFGAME_TIMER, WIN_DELAY); // initialize counter to number of LEDs (8) counter = TOTAL_NUMBER_LED; // initialize position to 0 position = FIRST_LED_BANK; // move cannon to the first position Cannon_MoveToBank(position); // set current state to HappyDance CurrentState = HappyDance; printf("Going into win mode \n\r"); } else if (ThisEvent.EventParam == GAME_OVER) { // start timer ES_Timer_InitTimer(ENDOFGAME_TIMER, LOSE_DELAY); // determine how far from upright the cannon currently is int8_t CannonPosFromUp; CannonPosFromUp = (CANNON_CENTER_POS - QueryCannonPosition()); // decide which way cannon should fall if (CannonPosFromUp > 0) { CannonDirection = true; // should fall to the right } else { CannonDirection = false; // should fall to the left } // set CannonPosFromUp to absolute value CannonPosFromUp = abs(CannonPosFromUp); // set counter = max of current gauge level or cannon position from upright counter = MAX(MAX(AirLeak_QueryGauge(), PowerLib_QueryGauge()), CannonPosFromUp); // set CurrentState to SadDance CurrentState = SadDance; printf("Going into sad mode \n\r"); } } break; default: ; } // end switch on CurrentEvent } break; case HappyDance: { switch (ThisEvent.EventType) { case ES_TIMEOUT: { if (counter > 0) { if (counter == TOTAL_NUMBER_LED) { // light up cannon LED Cannon_LED(On); } else{ Cannon_LED(Off); } // move LED away from dome by 1 Meteor_LightLEDBank(position, counter); // decrement counter by 1 counter--; // init timer ES_Timer_InitTimer(ENDOFGAME_TIMER, WIN_DELAY); } else if ( (counter == 0) && (position < (LAST_LED_BANK+1)) ) { // increment position position = position + 1; // move cannon to next position Cannon_MoveToBank(position); // reset counter counter = TOTAL_NUMBER_LED; if (position == (LAST_LED_BANK+1)) { // turn off all LEDs Meteor_ClearAll(); Crisis_Meteor(Off); Crisis_AirLeak(Off); Crisis_Power(Off); // wait a hot sec ES_Timer_InitTimer(ENDOFGAME_TIMER, OFF_DELAY); //I changed off_delay to zero for testing. It possibly may be interfering with existing timer? } else { // init timer ES_Timer_InitTimer(ENDOFGAME_TIMER, WIN_DELAY); } } else if (position == (LAST_LED_BANK+1)) { // post Go_Welcome_Mode to WelcomeFSM ES_Event_t NextEvent; NextEvent.EventType = Go_Welcome_Mode; PostWelcomeFSM(NextEvent); printf("Going into welcome mode \n\r"); // set CurrentState to Idle_E CurrentState = Idle_E; } } break; case Tot_Inserted: { Meteor_ClearAll(); Crisis_Meteor(Off); Crisis_AirLeak(Off); Crisis_Power(Off); CurrentState = Idle_E; } break; default: ; } // end switch on CurrentEvent } break; case SadDance: { switch (ThisEvent.EventType) { case ES_TIMEOUT: { if (counter == 0) { // post Go_Welcome_Mode to WelcomeFSM ES_Event_t NextEvent; NextEvent.EventType = Go_Welcome_Mode; PostWelcomeFSM(NextEvent); // set CurrentState to Idle_E CurrentState = Idle_E; printf("Going into welcome mode \n\r"); } else if (counter > 0) { // move cannon down uint16_t NewCannonPos = QueryCannonPosition(); if (CannonDirection == true) { NewCannonPos = NewCannonPos - 1; Cannon_ManualPosition(NewCannonPos); } else { NewCannonPos = NewCannonPos + 1; Cannon_ManualPosition(NewCannonPos); } // move gauges down AirLeak_MoveGauge(AirLeak_QueryGauge() - 1); PowerLib_MoveGauge(PowerLib_QueryGauge() - 1); if (ToggleOn) { // toggle LEDs touching the dome Meteor_LightLEDBank(FIRST_LED_BANK, LAST_LED); Meteor_LightLEDBank(MIDDLE_LED_BANK, LAST_LED); Meteor_LightLEDBank(LAST_LED_BANK, LAST_LED); // toggle indicator lights Crisis_Meteor(On); Crisis_AirLeak(On); Crisis_Power(On); // switch ToggleOn to False ToggleOn = false; } else { // toggle LEDs touching the dome Meteor_ClearAll(); // toggle indicator lights Crisis_Meteor(Off); Crisis_AirLeak(Off); Crisis_Power(Off); // switch ToggleOn to True ToggleOn = true; } // decrement counter counter = counter - 1; if (counter == 0) { // turn off all LEDs Meteor_ClearAll(); Crisis_Meteor(Off); Crisis_AirLeak(Off); Crisis_Power(Off); // wait a hot sec ES_Timer_InitTimer(ENDOFGAME_TIMER, OFF_DELAY); } else { // init timer ES_Timer_InitTimer(ENDOFGAME_TIMER, LOSE_DELAY); } } } break; case Tot_Inserted: { Meteor_ClearAll(); Crisis_Meteor(Off); Crisis_AirLeak(Off); Crisis_Power(Off); CurrentState = Idle_E; } break; default: ; } // end switch on CurrentEvent } break; default: ; } // end switch on Current State return ReturnEvent; } /*************************************************************************** private functions ***************************************************************************/