You are on page 1of 9

//This module contains the overarching state machine.

//It transitions from standby mode to game mode to


//celebration mode

// the common headers for C99 types


#include <stdio.h> //added
#include <stdint.h>
#include <stdbool.h>

// the headers to access the GPIO subsystem


#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "inc/hw_gpio.h"
#include "inc/hw_sysctl.h"

// the headers to access the TivaWare Library


#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "driverlib/gpio.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"

#include "BITDEFS.H"

#include "ES_Configure.h"
#include "EventCheckers.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "ES_ShortTimer.h"

#include "MarathonServiceSM.h"
#include "ShiftRegisterWrite.h"

#include "ADMulti.h"
#include "PWM16Tiva.h"

#define LED_WELCOME_TIMER_DURATION 125


#define RESET_TIMER_DURATION 3000
#define PAUSE_TIMER_DURATION 5000
#define IR_TIMER_DURATION 500
#define VOTE_TIMER_DURATION 250
#define NUM_PATTERNS 40
#define NUM_VOTE_PATTERNS 49
#define FAN_THRESHOLD 2000.0
#define MAX_ADC_COUNT 4095.0
#define DUTY_CYCLE_RANGE 75.0

#define PLAYER_START_LINE 0
#define PLAYER_FINISH_LINE 1
#define OPPONENT_START_LINE 2
#define OPPONENT_FINISH_LINE 3
#define FLAG_START_POSITION 4
#define FLAG_FINISH_POSITION 5
#define FAN_CHANNEL 0

#define STALL_PWM 0
#define FLAG_ON_PWM 80

//Non-buzzer motor channels


#define FAN_CHANNEL 0
#define PLAYER_CHANNEL 1
#define OPPONENT_CHANNEL 3
#define FLAG_CHANNEL 2

//Buzzer channels
#define BUTTON_1_CHANNEL 4
#define BUTTON_2_CHANNEL 5
#define BUTTON_3_CHANNEL 6
#define BUTTON_4_CHANNEL 7

#define NUM_MOTORS 8

static uint8_t MyPriority;


static MarathonServiceSMState_t CurrentState;

//Pattern that runs forever as the system waits for someone to interact
//with it
static uint16_t WelcomePatternBank[NUM_PATTERNS] = {
65535, 0, 65535, 0, 8, 12, 14, 15, 31, 287, 4383, 12575, 28959, 61727,
63775, 63903, 63967, 63999, 64511, 65535, 64511, 65023, 65503, 65471,
65407, 63487, 32767, 49151, 57343, 61439, 65279, 65519, 65534, 65533,
65531, 65527, 65535, 0, 65535, 0
};

static uint16_t VoteForUsPatternBank[NUM_VOTE_PATTERNS] = {


23130, 42405, 23130, 42405, 0, 6168, 15420, 32382, 65535, 59367,
50115, 33153, 0, 40965, 43605, 45045, 65535, 24570, 21930, 20490,
0, 65535, 65463, 65467, 65469, 64510, 64495, 64255, 60927, 56831, 48639,
32735, 63455, 65375, 0, 65535, 65463, 65467, 65469, 64510, 64495, 64255,
60927, 56831, 48639, 32735, 63455, 65375, 0
};

static uint8_t index;


static uint8_t LastLeverState;

//The last state of each coin sensor


static uint8_t LastPinStateD0;
static uint8_t LastPinStateD1;
static uint8_t LastPinStateD2;
static uint8_t LastPinStateD3;
static uint8_t LastPinStateF4;
static uint8_t LastPinStateD7;
static uint8_t LastPinStates;

static uint8_t NumVoteTimeouts;

static bool HandLEDsOn;

static void TurnOffHandLEDs()


{
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) &= BIT2LO;
}

bool InitializeMarathonServiceSM(uint8_t Priority)


{
MyPriority = Priority;

//Set channels 0-7 for PWM


PWM_TIVA_Init(NUM_MOTORS);
//Initialize motor channels to have 0 PWM
PWM_TIVA_SetDuty( STALL_PWM, FAN_CHANNEL);
PWM_TIVA_SetDuty( STALL_PWM, FLAG_CHANNEL);
PWM_TIVA_SetDuty( STALL_PWM, PLAYER_CHANNEL);
PWM_TIVA_SetDuty( STALL_PWM, OPPONENT_CHANNEL);
PWM_TIVA_SetDuty( STALL_PWM, BUTTON_1_CHANNEL);
PWM_TIVA_SetDuty( STALL_PWM, BUTTON_2_CHANNEL);
PWM_TIVA_SetDuty( STALL_PWM, BUTTON_3_CHANNEL);
PWM_TIVA_SetDuty( STALL_PWM, BUTTON_4_CHANNEL);

//Initialize non-ADC and non-PWM pins


SR_InitForProject();

//Initialize pin for distance sensor and knob


ADC_MultiInit(2);

TurnOffHandLEDs();
HandLEDsOn = false;
NumVoteTimeouts = 0;
SR_Write16(0);
SR_WriteMapAllOff();
CurrentState = InitialState;
index = 0;

//Get initial state of lever pin


LastLeverState = (BIT5HI & HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA +
ALL_BITS)));

//Get initial state of each coin sensor pin


LastPinStates = HWREG(GPIO_PORTD_BASE + (GPIO_O_DATA + ALL_BITS));
LastPinStateD0 = BIT0HI;
LastPinStateD1 = BIT1HI;
LastPinStateD2 = BIT2HI;
LastPinStateD3 = BIT3HI;
LastPinStateF4 = BIT4HI;
LastPinStateD7 = BIT7HI;

//Set timer that determines length of each LED welcome pattern


ES_Timer_InitTimer(LED_WELCOME_TIMER, LED_WELCOME_TIMER_DURATION);

return true;
}

bool PostMarathonServiceSM(ES_Event ThisEvent)


{
return ES_PostToService(MyPriority, ThisEvent);
}

bool Check4Lever(void)
{
ES_Event ThisEvent;
ThisEvent.EventType = LEVER_PULLED;
uint8_t CurrentLeverState;
bool ReturnVal = false;

//Get current state of lever pin


CurrentLeverState = (BIT5HI & HWREG(GPIO_PORTA_BASE + (GPIO_O_DATA +
ALL_BITS)));

//If lever has just been pulled


if (CurrentLeverState != LastLeverState)
{
if (CurrentLeverState == BIT5HI)
{
PostMarathonServiceSM(ThisEvent);
LastLeverState = CurrentLeverState;
ReturnVal = true;
}
}
LastLeverState = CurrentLeverState;
return ReturnVal;
}

static uint8_t GetCurrentPinStates(void)


{
return HWREG(GPIO_PORTD_BASE + (GPIO_O_DATA + ALL_BITS));
}

bool Check4Fence(void)
{
bool ReturnVal = false;

//Get current state of each coin sensor pin


uint8_t CurrentPinStates = GetCurrentPinStates();
uint8_t CurrentPinStateD0 = (CurrentPinStates & BIT0HI);
uint8_t CurrentPinStateD1 = (CurrentPinStates & BIT1HI);
uint8_t CurrentPinStateD2 = (CurrentPinStates & BIT2HI);
uint8_t CurrentPinStateD3 = (CurrentPinStates & BIT3HI);
uint8_t CurrentPinStateF4 = ((HWREG(GPIO_PORTF_BASE + (GPIO_O_DATA +
ALL_BITS))) & (BIT4HI));
uint8_t CurrentPinStateD7 = (CurrentPinStates & BIT7HI);

//If a coin sensor has just been blocked


if ((CurrentPinStates != LastPinStates) || (CurrentPinStateF4 !=
LastPinStateF4))
{
ES_Event ThisEvent;
ThisEvent.EventType = FENCE_HIT;

if (CurrentPinStateD0 != LastPinStateD0)
{
if (CurrentPinStateD0 == 0)
{
ThisEvent.EventParam = PLAYER_FINISH_LINE;
ES_PostList00(ThisEvent);
ReturnVal = true;
}
}

if (CurrentPinStateD1 != LastPinStateD1)
{
if (CurrentPinStateD1 == 0)
{
ThisEvent.EventParam = PLAYER_START_LINE;
ES_PostList00(ThisEvent);
ReturnVal = true;
}
}

if (CurrentPinStateD2 != LastPinStateD2)
{
if (CurrentPinStateD2 == 0)
{
ThisEvent.EventParam = OPPONENT_FINISH_LINE;
ES_PostList00(ThisEvent);
ReturnVal = true;
}
}

if (CurrentPinStateD3 != LastPinStateD3)
{
if (CurrentPinStateD3 == 0)
{
ThisEvent.EventParam = OPPONENT_START_LINE;
ES_PostList00(ThisEvent);
ReturnVal = true;
}
}

if (CurrentPinStateF4 != LastPinStateF4)
{
if (CurrentPinStateF4 == 0)
{
ThisEvent.EventParam = FLAG_START_POSITION;
ES_PostList00(ThisEvent);
ReturnVal = true;
}
}

if (CurrentPinStateD7 != LastPinStateD7)
{
if (CurrentPinStateD7 == 0)
{
ThisEvent.EventParam = FLAG_FINISH_POSITION;
ES_PostList00(ThisEvent);
ReturnVal = true;
}
}
}

LastPinStates = CurrentPinStates;
LastPinStateD0 = CurrentPinStateD0;
LastPinStateD1 = CurrentPinStateD1;
LastPinStateD2 = CurrentPinStateD2;
LastPinStateD3 = CurrentPinStateD3;
LastPinStateF4 = CurrentPinStateF4;
LastPinStateD7 = CurrentPinStateD7;
return ReturnVal;
}

static void TurnOnHandLEDs()


{
HWREG(GPIO_PORTE_BASE + (GPIO_O_DATA + ALL_BITS)) |= BIT2HI;
}

ES_Event RunMarathonServiceSM(ES_Event ThisEvent)


{
ES_Event ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT;
MarathonServiceSMState_t NextState = CurrentState;
switch (CurrentState)
{
case InitialState:
{
if ((ThisEvent.EventType == ES_TIMEOUT) && (ThisEvent.EventParam
== LED_WELCOME_TIMER))
{
SR_WriteMapAllOff();
SR_Write16(WelcomePatternBank[index]);
if (index < NUM_PATTERNS)
{
index++;
}
else
{
index = 0;
}
ES_Timer_InitTimer(LED_WELCOME_TIMER,
LED_WELCOME_TIMER_DURATION);
}
if (ThisEvent.EventType == LEVER_PULLED)
{
ES_Timer_StopTimer(LED_WELCOME_TIMER);
index = 0;
uint8_t CurrentPinStates = GetCurrentPinStates();
uint8_t CurrentPinStateD1 = (CurrentPinStates & BIT1HI);
uint8_t CurrentPinStateD3 = (CurrentPinStates & BIT3HI);

//If either character did not properly reset, this block of


//code initiates another reset
if (((CurrentPinStateD1) != 0) || (CurrentPinStateD3 != 0))
{
if (CurrentPinStateD1 != 0)
{
MotorPlayerReverse();
}
if (CurrentPinStateD3 != 0)
{
MotorOpponentReverse();
}
}
//If the characters properly reset, start raising the flag
//(creative display of time)
else
{
MotorFlagUp();
SR_WriteMapAllOff();
NextState = GameplayState;
ES_Event ReturnEvent;
ReturnEvent.EventType = WELCOME_DONE;
ES_PostList02(ReturnEvent);
}
}
}
break;
case GameplayState:
{
//If game finishes
if (((ThisEvent.EventType == FENCE_HIT) &&
(ThisEvent.EventParam == PLAYER_FINISH_LINE))
|| ((ThisEvent.EventType == ES_TIMEOUT) &&
(ThisEvent.EventParam == GAME_TIMER)) ||
((ThisEvent.EventType == FENCE_HIT) &&
(ThisEvent.EventParam == OPPONENT_FINISH_LINE)))
{
if (((ThisEvent.EventType == FENCE_HIT) &&
(ThisEvent.EventParam == PLAYER_FINISH_LINE)) ||
((ThisEvent.EventType == FENCE_HIT) &&
(ThisEvent.EventParam == OPPONENT_FINISH_LINE)))
{
ES_Timer_StopTimer(GAME_TIMER);
}
NextState = TorchState;

//Initiate timer that determines duration of fan motor at


//certain PWM
ES_Timer_InitTimer(IR_TIMER, IR_TIMER_DURATION);

//Turn off game LEDs


SR_Write16(0);

//Turn on LEDs around distance sensor


TurnOnHandLEDs();

HandLEDsOn = true;
}
}
break;
case TorchState:
{
if ((ThisEvent.EventType == FENCE_HIT) &&
(ThisEvent.EventParam == FLAG_FINISH_POSITION))
{
ES_Timer_StopTimer(IR_TIMER);
SR_Write16(0);
NextState = PauseState;

//Turn on fan for PauseState


PWM_TIVA_SetDuty(FLAG_ON_PWM, FAN_CHANNEL);

//Turn off LEDs around distance sensor


TurnOffHandLEDs();

HandLEDsOn = false;
SR_Write16(0);

//Set timer that determines length of each vote pattern


ES_Timer_InitTimer(VOTE_TIMER, VOTE_TIMER_DURATION);
SR_Write16(VoteForUsPatternBank[NumVoteTimeouts]);
}
else if ((ThisEvent.EventType == ES_TIMEOUT) &&
(ThisEvent.EventParam == IR_TIMER))
{
if (!HandLEDsOn)
{
TurnOnHandLEDs();
HandLEDsOn = true;
}
else
{
TurnOffHandLEDs();
HandLEDsOn = false;
}
uint32_t results[2];
ADC_MultiRead(results);
ES_Timer_InitTimer(IR_TIMER, IR_TIMER_DURATION);
if (results[0] > FAN_THRESHOLD)
{
//Set PWM based on ADC count
double result = results[0];
double intermediate = (result - FAN_THRESHOLD) /
(MAX_ADC_COUNT - FAN_THRESHOLD);
double var = (1.0 / DUTY_CYCLE_RANGE);
double DC = (intermediate / var) + (100.0
DUTY_CYCLE_RANGE);
uint8_t DutyCycle = DC;
PWM_TIVA_SetDuty(DutyCycle, FAN_CHANNEL);
}
else
{
//Turn fan off if user is too far away
PWM_TIVA_SetDuty(0, FAN_CHANNEL);
}
}
//if user is away from system for too long, system resets
else if (ThisEvent.EventType == USER_DEPARTED)
{
PWM_TIVA_SetDuty(STALL_PWM, FAN_CHANNEL);
uint8_t CurrentPinStates = GetCurrentPinStates();
uint8_t CurrentPinStateD1 = (CurrentPinStates & BIT1HI);

//If player isn't at start of track, move player to start of


//track
if (CurrentPinStateD1 != 0)
{
MotorPlayerReverse();
}
MotorOpponentReverse();
MotorFlagDown();
SR_WriteMapAllOff();
NextState = ResetState;
TurnOffHandLEDs();
HandLEDsOn = false;
PWM_TIVA_SetDuty(STALL_PWM, FAN_CHANNEL);
}
}
break;
case PauseState:
{
if (((ThisEvent.EventType == ES_TIMEOUT) &&
(ThisEvent.EventParam == VOTE_TIMER)) && (NumVoteTimeouts ==
(NUM_VOTE_PATTERNS - 1)))
{
NextState = ResetState;
PWM_TIVA_SetDuty(0, FAN_CHANNEL);
uint8_t CurrentPinStates = GetCurrentPinStates();
uint8_t CurrentPinStateD1 = (CurrentPinStates & BIT1HI);

//If player isn't at start of track, move player to start of


//track
if (CurrentPinStateD1 != 0)
{
MotorPlayerReverse();
}
MotorOpponentReverse();
MotorFlagDown();
SR_Write16(0);

//Turn off map LEDs


SR_WriteMapAllOff();
}
else if ((ThisEvent.EventType == ES_TIMEOUT) &&
(ThisEvent.EventParam == VOTE_TIMER))
{
PWM_TIVA_SetDuty(FLAG_ON_PWM, FAN_CHANNEL);
NumVoteTimeouts++;
SR_Write16(VoteForUsPatternBank[NumVoteTimeouts]);
ES_Timer_InitTimer(VOTE_TIMER, VOTE_TIMER_DURATION);
}
}
break;
case ResetState:
{
//If flag is at initial position
if ((ThisEvent.EventType == FENCE_HIT) && (ThisEvent.EventParam
== FLAG_START_POSITION))
{
NextState = InitialState;
index = 0;
NumVoteTimeouts = 0;
LastLeverState = (BIT5HI & HWREG(GPIO_PORTA_BASE +
(GPIO_O_DATA + ALL_BITS)));
LastPinStates = HWREG(GPIO_PORTD_BASE + (GPIO_O_DATA +
ALL_BITS));
LastPinStateD0 = BIT0HI;
LastPinStateD1 = BIT1HI;
LastPinStateD2 = BIT2HI;
LastPinStateD3 = BIT3HI;
LastPinStateF4 = BIT4HI;
LastPinStateD7 = BIT7HI;
SR_Write16(0);

//Set timer that determines duration of each LED welcome


//pattern
ES_Timer_InitTimer(LED_WELCOME_TIMER,
LED_WELCOME_TIMER_DURATION);
}
}
break;
}
CurrentState = NextState;
return ReturnEvent;
}

You might also like