You are on page 1of 9

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

Module
REFCommSM.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 "inc/hw_types.h"
#include "inc/hw_nvic.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ssi.h"

//user defined header files


#include "REFCommSM.h"
#include "GameMasterSM.h"
/*----------------------------- Module Defines ----------------------------*/
#define QUERY_TIME 300 //set QUERY_TIMER to be Timer 1 !

#define BitsPerNibble 4
#define CPSDVSR 50
#define SCR 55

//protocols defines
#define BIT02MASK 0x7 //0b111
#define BIT45MASK 0x30 //0b00110000
#define BIT2MASK 0x4 //0b100
#define W4S 0x0
#define FO 0x1 //0b001
#define PL 0x2 //0b010
#define TIE 0x3 //0b011
#define GO 0x4 //0b100
#define NOPO 0x00
#define REDPO 0x10 //0b00010000
#define BLUEPO 0x20 //0b00100000

/*---------------------------- Module Functions ---------------------------*/


static ES_Event_t DuringWait2Send( ES_Event_t Event);
static ES_Event_t DuringSPISendByte( ES_Event_t Event);

static void InitHW4SPI(void);


static void ReadFromREF(void);
static void WriteToREF(uint8_t QueryCommand[4]);
static ES_Event_t DecodeGameState(uint8_t bytes[4]);
static void PrintCurrentCommand(uint8_t bytes[4]);

/*---------------------------- 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 REFCommState_t CurrentState;
// with the introduction of Gen2, we need a module level Priority var as well
static uint8_t MyPriority;

static uint8_t QueryCommand[4] = {0x3f, 0x00, 0x00, 0x00};


static uint8_t CurrentGameState[4] = {0x00, 0xff, 0x00, 0x01};
static ES_Event_t LastEvent = {ES_NO_EVENT, 0};

/*------------------------------ Module Code ------------------------------*/


/****************************************************************************
Function
InitREFCommSM

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 InitREFCommSM ( uint8_t Priority )
{
ES_Event_t ThisEvent;

//init MyPriority using the passed-in parameter


MyPriority = Priority;
//init hardware for SPI
InitHW4SPI();

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

return true;
}

/****************************************************************************
Function
PostMasterSM
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 PostREFCommSM( ES_Event_t ThisEvent )
{
return ES_PostToService( MyPriority, ThisEvent);
}

/****************************************************************************
Function
RunMasterSM

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 RunREFCommSM( ES_Event_t CurrentEvent )
{
bool MakeTransition = false;/* are we making a state transition? */
REFCommState_t NextState = CurrentState;
ES_Event_t EntryEventKind = { ES_ENTRY, 0 };// default to normal entry to new
state
ES_Event_t ReturnEvent = { ES_NO_EVENT, 0 }; // assume no error

switch ( CurrentState )
{
case Wait2Send : // If current state is state one
// Execute During function for state one. ES_ENTRY & ES_EXIT are
// processed here allow the lowere level state machines to re-map
// or consume the event
CurrentEvent = DuringWait2Send(CurrentEvent);
//process any events
if ( CurrentEvent.EventType != ES_NO_EVENT ) //If an event is active
{
switch (CurrentEvent.EventType)
{
case ES_TIMEOUT : //If event is ES_TIMEOUT
// Execute action function for Wait2Send: ES_TIMEOUT
NextState = SPISendByte;//Decide the next state to be SPISendByte
// 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;
break;
// repeat cases as required for relevant events
default:;
}
}
break;
// repeat state pattern as required for other states
case SPISendByte : // If current state is state one
// Execute During function for state one. ES_ENTRY & ES_EXIT are
// processed here allow the lowere level state machines to re-map
// or consume the event
CurrentEvent = DuringSPISendByte(CurrentEvent);
//process any events
if ( CurrentEvent.EventType != ES_NO_EVENT ) //If an event is active
{
switch (CurrentEvent.EventType)
{
case SSI_EOT : //If event is SSI_EOT
// Execute action function for SPISendByte: SSI_EOT
//decode CurrentGameState and save the return event in CurrentEvent
CurrentEvent = DecodeGameState(CurrentGameState);
//if CurrentEvent is different from LastEvent
if(CurrentEvent.EventType != LastEvent.EventType){
//post CurrentEvent to GameMasterSM
PostGameMasterSM(CurrentEvent);
//update LastEvent to CurrentEvent
LastEvent.EventType = CurrentEvent.EventType;
}
//set NextState to Wait2Send
NextState = Wait2Send;//Decide what the next state will be
// 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;
break;
default:
;
// repeat cases as required for relevant events
}
}
break;
}
// If we are making a state transition
if (MakeTransition == true)
{
//Execute exit function for current state
CurrentEvent.EventType = ES_EXIT;
RunREFCommSM(CurrentEvent);

CurrentState = NextState; //Modify state variable

//Execute entry function for new state


//this defaults to ES_ENTRY
RunREFCommSM(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
StartMasterSM

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 StartREFCommSM ( 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 Wait2Send
CurrentState = Wait2Send;
// 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
RunREFCommSM(CurrentEvent);
return;
}

//SSI interrupt service


void EOTISR(void) {
//Disable interrupt
HWREG(NVIC_EN0) &= ~BIT7HI;
//read received bytes from REF
ReadFromREF();
//post SSI_EOT event to REFCommSM to handle it
ES_Event_t ThisEvent;
ThisEvent.EventType = SSI_EOT;
PostREFCommSM(ThisEvent);
}

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

static ES_Event_t DuringWait2Send( 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 QUERY_TIMER, the timer will time out after QUERY_TIME
ES_Timer_InitTimer(QUERY_TIMER, QUERY_TIME);
// 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
//write QueryCommand to register
WriteToREF(QueryCommand);
//enable interrupt
HWREG(NVIC_EN0) |= BIT7HI;
}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 DuringSPISendByte( 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
//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

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

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

static void InitHW4SPI(void) {


// Enable the clock to the GPIO port (PA 2-5)
HWREG(SYSCTL_RCGCGPIO)|= SYSCTL_RCGCGPIO_R0; // Port A
// Enable the clock to SSI module (SSI Module 0 Run Mode Clock)
HWREG(SYSCTL_RCGCSSI) |= SYSCTL_RCGCSSI_R0;
// Wait for the GPIO port to be ready
while ((HWREG(SYSCTL_RCGCGPIO) & SYSCTL_RCGCGPIO_R0) != SYSCTL_RCGCGPIO_R0);
// Program the GPIO to use the alternate functions on the SSI pins
HWREG(GPIO_PORTA_BASE+GPIO_O_AFSEL) |= (BIT2HI | BIT3HI | BIT4HI | BIT5HI);
// Set mux position in GPIOPCTL to select the SSI use of the pins
HWREG(GPIO_PORTA_BASE+GPIO_O_PCTL) =
(HWREG(GPIO_PORTA_BASE+GPIO_O_PCTL) & 0xff0000ff) +
(2<<(2*BitsPerNibble)) + (2<<(3*BitsPerNibble)) + (2<<(4*BitsPerNibble)) +
(2<<(5*BitsPerNibble));
// Program the Port A lines for digital I/O
HWREG(GPIO_PORTA_BASE+GPIO_O_DEN) |= (BIT2HI | BIT3HI | BIT4HI | BIT5HI); //
Program the required data directions on the port lines
HWREG(GPIO_PORTA_BASE+GPIO_O_DIR) |= (BIT2HI | BIT3HI | BIT5HI); // PA2, 3, 5
are outputs (PA2: SCK, PA3: slave select, PA4: MISO)
HWREG(GPIO_PORTA_BASE+GPIO_O_DIR) &= BIT4LO; // PA4 is an input
//If using SPI mode 3, program the pull-up on the clock line (PA2)
HWREG(GPIO_PORTA_BASE+GPIO_O_PUR) |= BIT2HI;
//Wait for the SSI0 to be ready
while((HWREG(SYSCTL_RCGCSSI) & SYSCTL_RCGCSSI_R0) != SYSCTL_RCGCSSI_R0);
//Make sure that the SSI is disabled before programming mode bits
HWREG(SSI0_BASE+SSI_O_CR1) &= ~SSI_CR1_SSE;
//Select master mode (MS) & TXRIS indicating End of Transmit (EOT)
HWREG(SSI0_BASE+SSI_O_CR1) &= ~SSI_CR1_MS; // Master is 0
HWREG(SSI0_BASE+SSI_O_CR1) |= SSI_CR1_EOT; // End of Transimit is 1
//Configure the SSI clock source to the system clock
HWREG(SSI0_BASE+SSI_O_CC) &= ~SSI_CC_CS_M; // select to sys clock
//Configure the clock pre-scaler to get 14KHz frequency (max: 961kHz)
HWREG(SSI0_BASE+SSI_O_CPSR) |= CPSDVSR; // 10 define in this module
//Configure clock rate (SCR), phase & polarity (SPH, SPO), mode (FRF), data size
(DSS)
HWREG(SSI0_BASE+SSI_O_CR0) |= SCR<<8; // 9 define in this module, SCR need to
shift
HWREG(SSI0_BASE+SSI_O_CR0) |= SSI_CR0_SPH; // second edge, SPH = 1
HWREG(SSI0_BASE+SSI_O_CR0) |= SSI_CR0_SPO; // idle at high, SPO = 1
HWREG(SSI0_BASE+SSI_O_CR0) &= ~SSI_CR0_FRF_M; // freescale SPI Frame Format
HWREG(SSI0_BASE+SSI_O_CR0) |= SSI_CR0_DSS_8; // data size is 8 bits
//Locally enable interrupts (TXIM in SSIIM)
HWREG(SSI0_BASE + SSI_O_IM) |= SSI_IM_TXIM; //Make sure that the SSI is enabled
for operation
HWREG(SSI0_BASE+SSI_O_CR1) |= SSI_CR1_SSE;
//Enable globally
__enable_irq();
}

static void ReadFromREF (void){


//read four bytes from SSI data register into CurrentGameState[4]
for (int i = 0; i < 4; i++){
CurrentGameState[i] = HWREG(SSI0_BASE + SSI_O_DR);
}
}

static void WriteToREF(uint8_t QueryCommand[4]){


//write four bytes in QueryCommand into SSI data register
for (int i = 0; i < 4; i++){
HWREG(SSI0_BASE + SSI_O_DR) = QueryCommand[i];
}
}

static ES_Event_t DecodeGameState(uint8_t bytes[4]){


//create a new event with event type as ES_NO_EVENT
ES_Event_t Event;
Event.EventType = ES_NO_EVENT;
//grab the third byte, save it into a varaible named SS
uint8_t SS = bytes[3]; //this is the game state byte
//grab the second byte, save it into a variable named SC
uint8_t SC = bytes[2]; ///this is the shot clock time remaining

//if bits0-2 are 0x0, set event type to EV_WAIT2START


if((SS & BIT02MASK) == W4S){
Event.EventType = EV_WAIT2START;
}
//if bits0-2 are 0x1, set event type to EV_FACEOFF
if((SS & BIT02MASK) == FO){
Event.EventType = EV_FACEOFF;
}
//if bits0-2 are 0x3, set event type to EV_FACEOFF
if((SS & BIT02MASK) == TIE){
Event.EventType = EV_FACEOFF;
}
//if bits0-2 are 0x4, set event type to EV_GAMEOVER
if((SS & BIT2MASK) == GO){
Event.EventType = EV_GAMEOVER;
}
//if bits0-2 are 0x2
if((SS & BIT02MASK) == PL){
//calculate shot clock time using SC
float HalfSC = SC*0.1*0.5;
//assign event parameter to half of shot clock time
Event.EventParam = HalfSC;

//if bits45 are 0x10, set event type to EV_REDPO


if((SS & BIT45MASK) == REDPO){
Event.EventType = EV_REDPO;
}
//if bits45 are 0x20, set event type to EV_BLUEPO
if((SS & BIT45MASK) == BLUEPO){
Event.EventType = EV_BLUEPO;
}
//if bits45 are 0x0, set event type to EV_NOPO
if((SS & BIT45MASK) == NOPO){
Event.EventType = EV_NOPO;
}
}
//return the event
return Event;
}

//static void PrintCurrentCommand(uint8_t bytes[4]){


// uint8_t SS = bytes[3];; //this is the byte that we care about
// //printf("SS = 0x%x\n\r", SS);
// if((SS & BIT02MASK) == W4S){
// printf("WAIT 2 START\n\r");
// }
//
// if((SS & BIT02MASK) == FO){
// printf("FACE OFF\n\r");
// }
//
// if((SS & BIT02MASK) == TIE){
// printf("TIE BREAK\n\r");
// }
//
// if((SS & BIT02MASK) == GO){
// printf("GAME OVER\n\r");
// }
//
// if((SS & BIT02MASK) == PL){
// if((SS & BIT45MASK) == REDPO){
// printf("RED in Poss\n\r");
// }
// if((SS & BIT45MASK) == BLUEPO){
// printf(" BLUE in Poss\n\r");
// }
// if((SS & BIT45MASK) == NOPO){
// printf("BLUE in Poss\n\r");
// }
// }
//}

You might also like