#include <stdbool.h>
#include <stdint.h>
#include "DM_Display.h"
#include "PIC32_SPI_HAL.h"
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ES_DeferRecall.h"
#include "GameLogicFSM.h"
#include "DisplayService.h"
#include "GameLogicFSM.h"
#include "AvatarService.h"
#include "ObstacleService.h"
#include "dbprintf.h"
/*----------------------------- Module Defines ----------------------------*/
#define ONE_SEC 1000
#define GAME_DURATION 60
#define ASCII_NUM_OFFSET 48
/*---------------------------- Module Functions ---------------------------*/
/* prototypes for private functions for this service.They should be functions
relevant to the behavior of this service
*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
static LEDState_t CurrentState;
// global variables
int currentTimeLeft = GAME_DURATION;
// add a deferral queue for up to 3 pending deferrals +1 to allow for overhead
static ES_Event_t DeferralQueue[3 + 1];
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitTemplateService
Parameters
uint8_t : the priorty of this service
Returns
bool, false if error in initialization, true otherwise
Description
Saves away the priority, and does any
other required initialization for this service
Notes
Author
J. Edward Carryer, 01/16/12, 10:00
****************************************************************************/
bool InitDisplayService(uint8_t Priority)
{
ES_Event_t ThisEvent;
MyPriority = Priority;
CurrentState = LED_IDLE;
// initialize deferral queue for testing Deferal function
// ES_InitDeferralQueueWith(DeferralQueue, ARRAY_SIZE(DeferralQueue));
// post the initial transition event
ThisEvent.EventType = ES_INIT;
if (ES_PostToService(MyPriority, ThisEvent) == true)
{
return true;
}
else
{
return false;
}
}
/****************************************************************************
Function
PostTemplateService
Parameters
EF_Event_t ThisEvent ,the event to post to the queue
Returns
bool 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 PostDisplayService(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunTemplateService
Parameters
ES_Event_t : the event to process
Returns
ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise
Description
add your description here
Notes
Author
J. Edward Carryer, 01/15/12, 15:23
****************************************************************************/
ES_Event_t RunDisplayService(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
switch(CurrentState)
{
case LED_IDLE:
switch (ThisEvent.EventType)
{
case ES_INIT:
{
DB_printf("Display initialized.\n");
}
break;
case ES_ADD_CHAR:
{
uint8_t ch = (uint8_t)ThisEvent.EventParam;
// DB_printf("LEDService: ES_ADD_CHAR received with %c\r\n", ch);
// scroll one character width (4 columns)
DM_ScrollDisplayBuffer(4);
// add the new character to the rightmost module
DM_AddChar2DisplayBuffer(ch);
// advance to update display row by row
CurrentState = LED_WRITING;
ES_Event_t e = {
.EventType = ES_UPDATE_DISPLAY,
.EventParam = 0 // return to IDLE state
};
PostDisplayService(e);
// DB_printf("LEDService: posted ES_UPDATE_DISPLAY\r\n");
}
break;
case ES_CALIB_DONE:
{
DM_ClearDisplayBuffer();
DM_AddChar2DisplayBufferAtPos(15, 'H');
DM_AddChar2DisplayBufferAtPos(14, 'I');
DM_AddChar2DisplayBufferAtPos(13, 'T');
DM_AddChar2DisplayBufferAtPos(12, ':');
uint8_t currentHit_tens = currentHit / 10;
uint8_t currentHit_ones = currentHit % 10;
DM_AddChar2DisplayBufferAtPos(11, (unsigned char)(currentHit_tens + ASCII_NUM_OFFSET));
DM_AddChar2DisplayBufferAtPos(10, (unsigned char)(currentHit_ones + ASCII_NUM_OFFSET));
DM_AddChar2DisplayBufferAtPos(6, 'T');
DM_AddChar2DisplayBufferAtPos(5, 'I');
DM_AddChar2DisplayBufferAtPos(4, 'M');
DM_AddChar2DisplayBufferAtPos(3, 'E');
DM_AddChar2DisplayBufferAtPos(2, ':');
uint8_t currentTimeLeft_tens = currentTimeLeft / 10;
uint8_t currentTimeLeft_ones = currentTimeLeft % 10;
DM_AddChar2DisplayBufferAtPos(1, (unsigned char)(currentTimeLeft_tens + ASCII_NUM_OFFSET));
DM_AddChar2DisplayBufferAtPos(0, (unsigned char)(currentTimeLeft_ones + ASCII_NUM_OFFSET));
CurrentState = LED_WRITING;
ES_Event_t e = {
.EventType = ES_UPDATE_DISPLAY,
.EventParam = 1 // return to PLAYING state
};
PostDisplayService(e);
ES_Timer_InitTimer(DISPLAY_TIMER, ONE_SEC);
}
break;
default:
break;
}
break;
case LED_PLAYING:
switch (ThisEvent.EventType)
{
case ES_TIMEOUT:
{
if (ThisEvent.EventParam == DISPLAY_TIMER) {
if (currentTimeLeft == 0) // 60 second timeout
{
ES_Event_t e = {
.EventType = ES_GAMEOVER_TIMEOUT
};
PostGameLogicFSM(e);
PostAvatarService(e);
PostObstacleService(e);
// reset timer
currentTimeLeft = GAME_DURATION;
// print 'GAMEOVER' text
DM_ClearDisplayBuffer();
DM_AddChar2DisplayBufferAtPos(11, 'G');
DM_AddChar2DisplayBufferAtPos(10, 'A');
DM_AddChar2DisplayBufferAtPos(9, 'M');
DM_AddChar2DisplayBufferAtPos(8, 'E');
DM_AddChar2DisplayBufferAtPos(7, 'O');
DM_AddChar2DisplayBufferAtPos(6, 'V');
DM_AddChar2DisplayBufferAtPos(5, 'E');
DM_AddChar2DisplayBufferAtPos(4, 'R');
CurrentState = LED_WRITING;
e.EventType = ES_UPDATE_DISPLAY,
e.EventParam = 0; // return to IDLE state
PostDisplayService(e);
}
else
{
currentTimeLeft--;
int currentTimeLeft_tens = currentTimeLeft / 10;
// DB_printf("tens = %d\r\n", currentTimeLeft_tens);
int currentTimeLeft_ones = currentTimeLeft % 10;
// DB_printf("ones = %d\r\n\n", currentTimeLeft_ones);
DM_AddChar2DisplayBufferAtPos(1, (unsigned char)(currentTimeLeft_tens + ASCII_NUM_OFFSET));
DM_AddChar2DisplayBufferAtPos(0, (unsigned char)(currentTimeLeft_ones + ASCII_NUM_OFFSET));
CurrentState = LED_WRITING;
ES_Event_t e = {
.EventType = ES_UPDATE_DISPLAY,
.EventParam = 1 // return to PLAYING state
};
PostDisplayService(e);
ES_Timer_InitTimer(DISPLAY_TIMER, ONE_SEC);
}
}
}
break;
case ES_COLLISION_DETECTED:
{
currentHit++;
DB_printf("[Display Service] Current Hit: %d\n", currentHit);
int currentHit_tens = currentHit / 10;
int currentHit_ones = currentHit % 10;
DM_AddChar2DisplayBufferAtPos(11, (unsigned char)(currentHit_tens + ASCII_NUM_OFFSET));
DM_AddChar2DisplayBufferAtPos(10, (unsigned char)(currentHit_ones + ASCII_NUM_OFFSET));
CurrentState = LED_WRITING;
ES_Event_t e = {
.EventType = ES_UPDATE_DISPLAY,
.EventParam = 1 // return to PLAYING state
};
PostDisplayService(e);
}
break;
case ES_NO_INPUT_TIMEOUT:
{
// reset timer
currentTimeLeft = GAME_DURATION;
// print 'NO INPUT' text
DM_ClearDisplayBuffer();
DM_AddChar2DisplayBufferAtPos(11, 'N');
DM_AddChar2DisplayBufferAtPos(10, 'O');
DM_AddChar2DisplayBufferAtPos(9, ' ');
DM_AddChar2DisplayBufferAtPos(8, 'I');
DM_AddChar2DisplayBufferAtPos(7, 'N');
DM_AddChar2DisplayBufferAtPos(6, 'P');
DM_AddChar2DisplayBufferAtPos(5, 'U');
DM_AddChar2DisplayBufferAtPos(4, 'T');
CurrentState = LED_WRITING;
ES_Event_t e = {
e.EventType = ES_UPDATE_DISPLAY,
e.EventParam = 0 // return to IDLE state
};
PostDisplayService(e);
}
break;
default:
break;
}
break;
case LED_WRITING:
switch (ThisEvent.EventType)
{
case ES_ADD_CHAR:
{
if (ES_DeferEvent(DeferralQueue, ThisEvent))
{
DB_printf("LEDService: deferred ES_ADD_CHAR\r\n");
}
else
{
DB_printf("FAILED TO DEFER ES_ADD_CHAR!\r\n");
}
}
break;
case ES_UPDATE_DISPLAY:
// push exactly one more row
if (false == DM_TakeDisplayUpdateStep()) {
ES_Event_t e = {
.EventType = ES_UPDATE_DISPLAY,
.EventParam = ThisEvent.EventParam
};
PostDisplayService(e); // keep updating one row at a time
} else {
if (0 == ThisEvent.EventParam)
{
CurrentState = LED_IDLE;
// DB_printf("LEDService: update complete -> back to LED_IDLE\r\n");
if (true == ES_RecallEvents(MyPriority, DeferralQueue))
{
// DB_printf("LEDService: recalled ES_NEW_KEY\r\n");
}
}
else // (1 == ThisEvent.EventParam)
{
CurrentState = LED_PLAYING;
// DB_printf("LEDService: update complete -> back to LED_PLAYING\r\n");
}
}
break;
default:
break;
}
break;
}
return ReturnEvent;
}