/****************************************************************************
Module
GameFSM.c
Revision
1.0.1
Description
This is a template file for implementing flat state machines under the
Gen2 Events and Services Framework.
Notes
History
When Who What/Why
-------------- --- --------
01/15/12 11:12 jec revisions for Gen2 framework
11/07/11 11:26 jec made the queue static
10/30/11 17:59 jec fixed references to CurrentEvent in RunTemplateSM()
10/23/11 18:20 jec began conversion from SMTemplate.c (02/20/07 rev)
****************************************************************************/
/*----------------------------- 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 "GameFSM.h"
#include "dbprintf.h"
#include "CoinSlotChecker.h"
#include "ButtonEventChecker.h"
#include "PIC32_AD_Lib.h"
#include "LEDService.h"
#include "PrintService.h"
#include "DM_Display.h"
#include "PIC32_SPI_HAL.h"
#include <xc.h>
#include "GenerateSequenceService.h"
#include "ES_Events.h"
#include "RecInputService.h"
#include "ButtonModule.h"
#include "TimersLED.h"
#include "PWM_PIC32.h"
/*----------------------------- Module Defines ----------------------------*/
#define ONE_SEC 1000
#define HALF_SEC (ONE_SEC / 2)
#define TWO_SEC (ONE_SEC * 2)
#define FIVE_SEC (ONE_SEC * 5)
#define TWENTY_SEC (ONE_SEC * 20)
#define SIXTY_SEC (ONE_SEC * 60)
/*---------------------------- 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 GAMEState_t CurrentState;
// with the introduction of Gen2, we need a module level Priority var as well
static uint8_t MyPriority;
static uint8_t CoinCounter;
static int OutputSeqArr[10];
static uint8_t userindex;
static uint16_t OutputSeqIndex;
static uint8_t difficulty = 4;
extern uint16_t score;
extern uint8_t LEDTimerCounter;
static uint8_t Insert1Timeout;
static bool Inactivity;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitTemplateFSM
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
J. Edward Carryer, 10/23/11, 18:55
****************************************************************************/
bool InitGameFSM(uint8_t Priority)
{
ES_Event_t ThisEvent;
MyPriority = Priority;
// put us into the Initial PseudoState
CurrentState = InitPState;
// post the initial transition event
ThisEvent.EventType = ES_INIT;
if (ES_PostToService(MyPriority, ThisEvent) == true)
{
return true;
}
else
{
return false;
}
}
/****************************************************************************
Function
PostTemplateFSM
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
J. Edward Carryer, 10/23/11, 19:25
****************************************************************************/
bool PostGameFSM(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunTemplateFSM
Parameters
ES_Event_t : the event to process
Returns
ES_Event_t, ES_NO_EVENT if no error ES_ERROR otherwise
Description
add your description here
Notes
uses nested switch/case to implement the machine.
Author
J. Edward Carryer, 01/15/12, 15:23
****************************************************************************/
ES_Event_t RunGameFSM(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
switch (CurrentState)
{
case InitPState: // If current state is initial Psedudo State
{
if (ThisEvent.EventType == ES_INIT) // only respond to ES_Init
{
// this is where you would put any actions associated with the
// transition from the initial pseudo-state into the actual
// initial state
// now put the machine into the actual initial state
clrScrn();
CoinCounter = 0;
//Initializes Coin Slot Checker
TRISBbits.TRISB4= 1;
InitCoinSlotChecker();
//Initializes Button Event Checker
TRISBbits.TRISB2 = 1;
ANSELBbits.ANSB2= 0;
//InitButtonEventChecker();
//Initializes JoyStick Event Checker
ADC_ConfigAutoScan((BIT11HI|BIT12HI));
//Initializes the LED
TRISAbits.TRISA2 = 0;
//Counts the inputs user has entered
userindex = 0;
//Keeps track of output sequence index
OutputSeqIndex = 0;
//Initializes Shift Register
SPI_Module_t SPI_2 = SPI_SPI2;
uint32_t clockPeriod = 100000;
DB_printf("ENTERING");
if ((SPISetup_BasicConfig(SPI_2)) &&
(SPISetup_SetLeader(SPI_2, SPI_SMP_MID)) &&
(SPISetup_SetBitTime(SPI_2, clockPeriod)) &&
(SPISetup_MapSDOutput(SPI_2, SPI_RPB11)) &&
(SPISetup_SetClockIdleState(SPI_2, SPI_CLK_LO)) &&
(SPISetup_SetActiveEdge(SPI_2, SPI_FIRST_EDGE)) &&
(SPISetup_SetXferWidth(SPI_2, SPI_8BIT)) &&
(SPISetEnhancedBuffer(SPI_2, 1)) &&
(SPISetup_EnableSPI(SPI_2)))
{
DB_printf("Timers LED Shift Register Initialized");
};
//Sets up Latch Pins for Shift Register
TRISBbits.TRISB8 = 0;
TRISBbits.TRISB9 = 0;
TRISBbits.TRISB11 = 0;
TRISBbits.TRISB15 = 0;
//SPI2CON = 0;
SPI2CONbits.MSSEN = 0;
SPI2CONbits.MSTEN = 1;
SPI2CONbits.SMP = 0;
SPI2CONbits.SSEN = 0;
// SPI2CONbits.ON = 1;
LATBbits.LATB8 = 1;
LATBbits.LATB9 = 0;
SPI2BUF;
SPI2BUF = 0b00111111;
LATBbits.LATB9 = 1;
for (int i = 0; i < 3000; i++){}
LATBbits.LATB9 = 0;
LATBbits.LATB9 = 1;
for (int i = 0; i < 3000; i++){}
LATBbits.LATB9 = 0;
Insert1Timeout = 5;
Inactivity = false;
DB_printf("Game State Machine Initiated v. 3.0 at %s \r\n",__TIME__);
ThisEvent.EventType = IDLING;
PostGameFSM(ThisEvent);
CurrentState = Idle;
}
}
break;
case Idle: // If current state is state one
{
switch (ThisEvent.EventType)
{
case IDLING:
{
DB_printf("Insert1Timeout: %d\r\n",Insert1Timeout);
if ((LEDTimerCounter == 10 || LEDTimerCounter == 11) && score > 10)
{
ThisEvent.EventType = ES_MESSAGE;
ThisEvent.EventParam = ES_CONGRATS;
PostLEDService(ThisEvent);
}
else if ((LEDTimerCounter == 10 || LEDTimerCounter == 11) && score < 10)
{
ThisEvent.EventType = ES_MESSAGE;
ThisEvent.EventParam = ES_DEFEAT;
PostLEDService(ThisEvent);
}
else if ((LEDTimerCounter < 15 && Inactivity == true)|| Insert1Timeout < 4 )
{
DB_printf("Checking");
if (LEDTimerCounter <= 12){
DB_printf("Changing to 13");
LEDTimerCounter = 13;
}
ThisEvent.EventType = ES_MESSAGE;
ThisEvent.EventParam = ES_MESSAGE;
PostLEDService(ThisEvent);
DB_printf("Insert1Timeout = %d\r\n",Insert1Timeout);
}
else
{
Insert1Timeout = 5;
ES_Timer_StopTimer(LED_TIMER);
ES_Timer_StopTimer(COIN_TIMER);
LEDTimerCounter = 0;
Inactivity = false;
ThisEvent.EventType = ES_MESSAGE;
ThisEvent.EventParam = ES_INSERT2;
PostLEDService(ThisEvent);
}
//DB_printf("LEDTimer Counter: %d\r\n",LEDTimerCounter);
PWMOperate_SetPulseWidthOnChannel(6500,1);
PWMOperate_SetPulseWidthOnChannel(6500,2);
PWMOperate_SetPulseWidthOnChannel(6500,3);
PWMOperate_SetPulseWidthOnChannel(6500,4);
difficulty = 4;
SPI2BUF;
SPI2BUF = 0b00111111;
LATBbits.LATB9 = 1;
for (int i = 0; i < 3000; i++){}
LATBbits.LATB9 = 0;
LATBbits.LATB9 = 1;
for (int i = 0; i < 3000; i++){}
LATBbits.LATB9 = 0;
}
break;
case ES_TIMEOUT:
{
LEDTimerCounter = 0;
DB_printf("Insufficient Tokens \r\n");
CurrentState = Idle;
CoinCounter = 0;
ThisEvent.EventType = IDLING;
PostGameFSM(ThisEvent);
DB_printf("Insert 1 Time Before: %d\r\n", Insert1Timeout);
Insert1Timeout++;
DB_printf("Insert 1 Time After: %d\r\n", Insert1Timeout);
ES_Timer_InitTimer(COIN_TIMER, FIVE_SEC);
}
break;
case COIN_INSERT: //If event is event one
{
CoinCounter++; //Increments Coin Counter by 1
DB_printf("Coin Counter: %d\r\n",CoinCounter);
//Updates LED Matrix that 1 more coin needs to be inserted
ThisEvent.EventType = ES_MESSAGE;
ThisEvent.EventParam = ES_INSERT1;
PostLEDService(ThisEvent);
if(CoinCounter == 2)
{
score = 0;
ES_Timer_StopTimer(COIN_TIMER);
DB_printf("Game Initialized \r\n");
ThisEvent.EventType = GAME_START;
PostGameFSM(ThisEvent);
CurrentState = OutputSeq;
CoinCounter = 0;
LEDTimerCounter = 0;
Insert1Timeout = 5;
}else
{
ES_Timer_InitTimer(COIN_TIMER, TWENTY_SEC);
Insert1Timeout = 0;
}
}
break;
default:
break;
}
}
break;
// repeat state pattern as required for other states
case OutputSeq:
{
switch(ThisEvent.EventType)
{
case GAME_OVER:
{
DB_printf("Game Over\r\n");
CurrentState = Idle;
ThisEvent.EventType = IDLING;
PostGameFSM(ThisEvent);
}
break;
case ES_TIMEOUT:
{
DB_printf("Game Over\r\n");
}
break;
case GAME_START:
{
ThisEvent.EventType = ES_INIT;
PostPrintService(ThisEvent);
ThisEvent.EventType = ES_MESSAGE;
ThisEvent.EventParam = ES_DISPLAY_SCORE;
PostLEDService(ThisEvent);
DB_printf("Game Starting...\r\n");
DB_printf("Current State: %d\r\n",CurrentState);
// LED initialization sequence
CurrentState = OutputSeq;
ThisEvent.EventType = PLAY_SEQUENCE;
PostGameFSM(ThisEvent);
ThisEvent.EventType = GAME_START;
PostTimersLED(ThisEvent);
}
break;
case PLAY_SEQUENCE:
{
userindex = 0;
OutputSeqIndex = 0;
DB_printf("Playing Sequence...\r\n");
ThisEvent.EventType = PLAY_SEQUENCE;
ThisEvent.EventParam = difficulty; //Change to size based on difficulty
PostGenSeqService(ThisEvent);
CurrentState = OutputSeq;
//Code programming servos would be added
//ThisEvent.EventType = RECORD_INPUT;
//PostGameFSM(ThisEvent);
}
break;
case EXPECTED_SEQUENCE:
{
OutputSeqArr[OutputSeqIndex] = ThisEvent.EventParam;
CurrentState = OutputSeq;
//DB_printf("OutputSeqIndex: %d OutputSeqArr: %d\r\n", OutputSeqIndex, OutputSeqArr[OutputSeqIndex]);
if(OutputSeqIndex == difficulty - 1)//Change to size based on difficulty;
{
//DB_printf("Entering RecInputService\r\n");
CurrentState = Wait4Input;
ThisEvent.EventType = WAITING_INPUT;
PostRecInputService(ThisEvent);
PostGameFSM(ThisEvent);
}
OutputSeqIndex++;
}
break;
default:
break;
}
}
break;
case Wait4Input:
{
switch(ThisEvent.EventType)
{
case GAME_OVER:
{
DB_printf("Game Over\r\n");
CurrentState = Idle;
ThisEvent.EventType = IDLING;
PostGameFSM(ThisEvent);
DB_printf("Score: %d\r\n",score);
}
break;
case ES_TIMEOUT:
{
Inactivity = true;
DB_printf("Back to IDLE\r\n");
CurrentState = Idle;
ThisEvent.EventType = IDLING;
PostGameFSM(ThisEvent);
}
break;
case PLAY_SEQUENCE:
{
//DB_printf("TEST\r\n");
CurrentState = Idle;
ThisEvent.EventType = IDLING;
PostGameFSM(ThisEvent);
}
case WAITING_INPUT:
{
ES_Timer_InitTimer(COIN_TIMER, TWENTY_SEC);
}
break;
case RECORD_INPUT:
{
DB_printf("Recording Input....\r\n");
uint16_t RecordedInput = ThisEvent.EventParam;
if(RecordedInput == OutputSeqArr[userindex])
{
//IMPLEMENT DIFFICULT CHANGES
DB_printf("Correct Input\r\n"); //IMPLEMENT MOTOR MOVEMENT
ThisEvent.EventType = ES_MESSAGE;
ThisEvent.EventParam = ES_UPDATING_SCORE;
PostLEDService(ThisEvent);
}
else
{
DB_printf("Incorrect Input \r\n");
ThisEvent.EventType = PLAY_SEQUENCE;
PostGameFSM(ThisEvent);
CurrentState = OutputSeq;
}
userindex++;
if(userindex == OutputSeqIndex)
{
difficulty++;
ThisEvent.EventType = PLAY_SEQUENCE;
PostGameFSM(ThisEvent);
CurrentState = OutputSeq;
}
}
break;
default:
break;
}
}
break;
default:
break;
} // end switch on Current State
return ReturnEvent;
}
/****************************************************************************
Function
QueryTemplateSM
Parameters
None
Returns
TemplateState_t The current state of the Template state machine
Description
returns the current state of the Template state machine
Notes
Author
J. Edward Carryer, 10/23/11, 19:21
****************************************************************************/
GAMEState_t QueryGameFSM(void)
{
return CurrentState;
}
/***************************************************************************
private functions
***************************************************************************/