Mechanical Components

Mechanical Components

Chassis

Inspired by the classic design of traditional arcade machines, this chassis serves as the backbone of our game, housing all the essential components that bring it to life. It contains the LED display matrix, electronic components, rail mechanism, coin slot system, and the conveyor mechanism that drive the game's interactive features.

We laser cut ⅛” thick duron for each part of this design, using box joints to carefully align each component. This not only ensured perfect fit and stability but also allowed for easy assembly and disassembly throughout the build. This material was chosen for its cost-effectiveness and flexibility. Its durability and ease of handling allowed for multiple revisions, ensuring the final build was both functional and efficient. 

CAD Drawings of Chassis

Mechanical Components

Linear Rail

Our rail system consists of five key components: the rail, stoppers, slider, guides, and the limit switch holder (UFO). To streamline prototyping, we made the UFO and slider modular. This approach allowed us to print only the sections that needed improvement, rather than reprinting the entire assembly, saving time. Separating the parts in this way offers several advantages: it enables faster iteration, reduces material waste, and allows for easier customization and testing of individual components. The modular design also simplifies disassembly and testing of different limit switch attachments, making debugging and optimization more efficient.

CAD Drawings of Linear Rail

Mechanical Components

Steering Wheel

The steering wheel is designed in the shape of a UFO and is fastened atop a cylinder that rotates freely within a nested hollow cylinder. The wheel features a gap where a string sits, connecting it to two shoulder screws and the sliding UFO. This setup allows the rotational motion of the wheel to be converted into the horizontal motion of the sliding UFO, creating a smooth and responsive control mechanism.

CAD Drawing of Steering Wheel

Mechanical Components

Coin Slot Mechanism

This system is designed to guide a poker chip along a path that aligns between a constant Red LED and an IR LED. Two carefully positioned holes securely house the LEDs, effectively blocking external light and ensuring uninterrupted performance. This design maximizes the LEDs' functionality while minimizing interference from ambient light.

CAD Drawing of Coin Slot Mechanism

Mechanical Components

Conveyor Belt

Stretched between two shafts is a canvas adorned with hand-sewn acrylic astronauts and asteroids. Each asteroid is 0.125 inches thick, while each astronaut is 0.25 inches thick. This setup allows us to strategically activate one of the two limit switches, each with varying lengths. The canvas rotates around the two shafts, which are constructed by press-fitting duron circles onto a shaft and then wrapping them with a layer of corrugated cardboard to increase friction and ensure smooth rotation. Each shaft is securely mounted to the duron using 5mm bearings for added stability and durability.

Mechanical Components

Joystick

This mechanism uses a rubber band to keep the joystick in its default position, which is set to the furthest negative y position. This position corresponds to a conveyor speed of 0, ensuring the system remains stationary when the joystick is at rest.

CAD Drawing of Joystick

Electrical Components

Electrical Components

Motor (M1)

The motor drives the conveyor belt, which is essential for moving objects (such as astronauts) in the game. It is powered by a 5V supply and its speed is controlled via MOSFETs (Q1, Q2), which regulate the power sent to the motor based on input from the joystick. The motor’s operation is critical for gameplay, as it adjusts the speed of the conveyor in response to player commands

Joystick (J6)

The joystick is used solely to control the speed of the conveyor. It operates on a 3.3V supply and features two analog axes (VRx and VRy) and a switch (SW). The vertical axis (VRy) controls the speed of the conveyor, with the player pushing the joystick forward to increase speed. The microcontroller processes the joystick's analog input to adjust the motor's speed, allowing players to control how fast the conveyor moves during the game.

Electrical Components

IR Object Sensor

The IR object sensor is used to detect the presence of a coin inserted into the system. It operates on a 5V power supply and functions by emitting infrared light via an IR emitter. When an object, such as a coin, interrupts the infrared light beam, the light is reflected back to the sensor. The sensor detects this reflection and sends a digital signal to the microcontroller (PIC32) to indicate that a coin has been inserted. This provides a reliable and quick method for detecting coin insertion, allowing the system to trigger the appropriate actions, such as registering the coin or advancing to the next step in the process.Additionally, a large red LED is used to visually indicate the status of coin insertion. The LED turns off when the coin is successfully detected, providing clear feedback to the user that the coin has been processed.

Electrical Components

Limit Switches 

The limit switches are used to detect the presence of an astronaut or an asteroid within the game. When the UFO moves along its path, the limit switches are triggered as soon as an astronaut or asteroid makes contact with them. These switches send a digital signal to the microcontroller (PIC32), indicating the presence of the object. The microcontroller then responds accordingly, such as by registering the abduction of an astronaut or accounting for a collision with an asteroid. The limit switches ensure precise detection of these objects, enabling the game to react in real-time to the player's actions and interactions within the game environment.

Electrical Components

LED Display Module

The LED matrix display shows real-time game information, including the countdown timer and score. Powered by a 5V supply, it consists of a grid of LEDs controlled by the microcontroller (PIC32) through shift registers. The microcontroller updates the display to show the remaining time, score, and system status, using serial communication to efficiently control the LEDs.

Software Components

SoftWare Components – State Machine
SoftWare Components –  Display Service Pseudo Code
Define constants:
  ONE_SEC = 1000  // Timer duration in milliseconds

Define module-level variables:
  MyPriority - priority of this service
  inputText[64] - buffer for input text
  CountDownText[64] - buffer for countdown text
  ScoreText[64] - buffer for score text
  textLength - length of the current text
  StartGameCountDown - countdown value for game start
  MyScore - current game score
  textPointer[12], ScorePointer[12] - temporary buffers for formatting text
  GAMESTART - boolean indicating if the game has started
  currentState - current state of the service

Define static strings for different messages:
  ReadyTextPointer = "READY.."
  StartTextPointer = "LETS CRUSH IT!!"
  VictoryTextPointer = "CROWM MY KING!!"
  LoserTextPointer = "KEEP PUSHING!!"
  LongIdlePointer = "Restarting..."
  Coin12Pointer = "COIN: 1/2"

Function: InitDisplayerService(Priority)
  Set service priority to Priority
  Initialize currentState to NOT_GOSTATE
  Print "Starting DisplayerService..."
  Create an ES_INIT_DISPLAYER event
  Post the event to the service queue
  Return true if successful, otherwise false

Function: PostDisplayerService(ThisEvent)
  Post ThisEvent to the service queue using the stored priority
  Return true if successful, otherwise false

Function: RunDisplayerService(ThisEvent)
  Initialize ReturnEvent as ES_NO_EVENT
  Switch on ThisEvent.EventType:
    
    Case ES_INIT_DISPLAYER:
      Print "Displayer Service Initialized"

    Case ES_NEW_SCORE:
      Update MyScore with ThisEvent.EventParam
      Print the new score to console

    Case ES_READY_COUNTDOWN:
      Set StartGameCountDown from ThisEvent.EventParam (scaled down)
      Format textPointer with countdown value
      Format ScorePointer with current score
      If GAMESTART is false:
        Display the countdown number centered
        If countdown reaches zero:
          Set GAMESTART to true
          Print "Game started"
      Else if countdown is greater than zero:
        Combine countdown and score into CountDownText
        Display the combined text centered

    Case ES_NEW_INPUT_TEXT:
      Switch on ThisEvent.EventParam:
        Case READY:
          Copy ReadyTextPointer to inputText
        Case GO:
          Copy StartTextPointer to inputText
          Update currentState to GOSTATE
        Case COIN12:
          Copy Coin12Pointer to inputText
        Case END:
          If MyScore >= 50:
            Copy VictoryTextPointer to inputText
          Else:
            Copy LoserTextPointer to inputText
        Case IDLE:
          Copy LongIdlePointer to inputText
      Calculate textLength for inputText
      Display the inputText centered

    Case ES_TIMEUP:
      Clear inputText, CountDownText, ScoreText, textPointer, and ScorePointer
      Reset GAMESTART to false
      Reset currentState to NOT_GOSTATE
      Print "Game ended. Resetting display."

    Default:
      Do nothing

  Return ReturnEvent

Function: QueryDisplayerService()
  Return currentState
SoftWare Components –  Display Service Source Code
/****************************************************************************
 Module
   DisplayerService.c

 Description
   A service to display input text centered on the LED matrix display.

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

/*----------------------------- Include Files -----------------------------*/
#include "DisplayerService.h"
#include "DM_Display64.h"
#include "PIC32_SPI_HAL.h"
#include <string.h>
#include <stdio.h>

/*----------------------------- Module Defines ----------------------------*/
#define ONE_SEC 1000

/*---------------------------- Module Variables ---------------------------*/
static uint8_t MyPriority;
static char inputText[64];
static char CountDownText[64];
static char ScoreText[64];
static uint8_t textLength;
static uint16_t StartGameCountDown;
static uint16_t MyScore;

static char textPointer[12];
static char ScorePointer[12];

static char *ReadyTextPointer = "READY..";
static char *StartTextPointer = "LETS CRUSH IT!!";
static char *VictoryTextPointer = "CROWM MY KING!!";
static char *LoserTextPointer = "KEEP PUSHING!!";
static char *LongIdlePointer = "Restarting...";
static char *Coin12Pointer = "COIN: 1/2";

static bool GAMESTART = false;
static DisplayerState_t currentState;

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

/****************************************************************************
 Function
   InitDisplayerService

 Description
   Initializes the DisplayerService and prepares the display for centered text.
****************************************************************************/
bool InitDisplayerService(uint8_t Priority)
{
    MyPriority = Priority;
    currentState = NOT_GOSTATE;

    puts("\rStarting DisplayerService...\r");

    ES_Event_t ThisEvent = { .EventType = ES_INIT_DISPLAYER };
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
   PostDisplayerService

 Description
   Posts an event to this service's queue.
****************************************************************************/
bool PostDisplayerService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
   RunDisplayerService

 Description
   Handles events and displays the input text centered on the display.
****************************************************************************/
ES_Event_t RunDisplayerService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent = { .EventType = ES_NO_EVENT };

    switch (ThisEvent.EventType)
    {
        case ES_INIT_DISPLAYER:
            puts("Displayer Service Initialized\r");
            break;

        case ES_NEW_SCORE:
            MyScore = ThisEvent.EventParam;
            printf("New score received: %d\r\n", MyScore);
            break;

        case ES_READY_COUNTDOWN:
            StartGameCountDown = ThisEvent.EventParam / 10;
            sprintf(textPointer, "%02d", StartGameCountDown);
            sprintf(ScorePointer, "SCORE:%04d", MyScore);

            if (!GAMESTART)
            {
                strncpy(CountDownText, textPointer, sizeof(CountDownText) - 1);
                textLength = strlen(CountDownText);
                DM_CenterDisplayText(CountDownText, textLength, 2);

                if (StartGameCountDown == 0)
                {
                    GAMESTART = true;
                    puts("Game started in DisplayerService!\r");
                }
            }
            else if (StartGameCountDown > 0)
            {
                snprintf(CountDownText, sizeof(CountDownText), "%s %s", textPointer, ScorePointer);
                textLength = strlen(CountDownText);
                DM_CenterDisplayText(CountDownText, textLength, 5);
            }
            break;

        case ES_NEW_INPUT_TEXT:
            switch (ThisEvent.EventParam)
            {
                case READY:
                    strncpy(inputText, ReadyTextPointer, sizeof(inputText) - 1);
                    break;
                case GO:
                    strncpy(inputText, StartTextPointer, sizeof(inputText) - 1);
                    currentState = GOSTATE;
                    break;
                case COIN12:
                    strncpy(inputText, Coin12Pointer, sizeof(inputText) - 1);
                    break;
                case END:
                    strncpy(inputText, (MyScore >= 50) ? VictoryTextPointer : LoserTextPointer, sizeof(inputText) - 1);
                    break;
                case IDLE:
                    strncpy(inputText, LongIdlePointer, sizeof(inputText) - 1);
                    break;
                default:
                    break;
            }
            textLength = strlen(inputText);
            DM_CenterDisplayText(inputText, textLength, 5);
            break;

        case ES_TIMEUP:
            memset(inputText, 0, sizeof(inputText));
            memset(CountDownText, 0, sizeof(CountDownText));
            memset(ScoreText, 0, sizeof(ScoreText));
            memset(textPointer, 0, sizeof(textPointer));
            memset(ScorePointer, 0, sizeof(ScorePointer));
            GAMESTART = false;
            currentState = NOT_GOSTATE;
            puts("Game ended. Resetting display.\r");
            break;

        default:
            break;
    }

    return ReturnEvent;
}

/****************************************************************************
 Function
   QueryDisplayerService

 Description
   Returns the current state of the DisplayerService.
****************************************************************************/
DisplayerState_t QueryDisplayerService(void)
{
    return currentState;
}
SoftWare Components –  Display Service Header File
/* 
 * File:   DM_Display.h
 * Author: Ed
 *
 * Created on July 15, 2021, 11:54 AM
 * Updated 2023-10-18 Aligned DM_AddChar2DisplayBuffer
 */

#ifndef DM_DISPLAY_H
#define	DM_DISPLAY_H

/****************************************************************************
 Function
  DM_TakeInitDisplayStep

 Parameter
  None

 Returns
  bool: true when there are no more initialization steps to perform; false
        while there still more steps to be taken

 Description
  Initializes the MAX7219 4-module display performing 1 step for each call:
    First, bring put it in shutdown to disable all displays, return false
    Next fill the display RAM with Zeros to insure blanked, return false
    Then Disable Code B decoding for all digits, return false
    Then, enable scanning for all digits, return false
    The next setup step is to set the brightness to minimum, return false
    Copy our display buffer to the display, return false
    Finally, bring it out of shutdown and return true
   
Example
   while ( false == DM_TakeInitDisplayStep() )
   {} // note this example is for non-event-driven code
****************************************************************************/
bool DM_TakeInitDisplayStep( void );


/****************************************************************************
 Function
  DM_ClearDisplayBuffer

 Parameter
  None

 Returns
 Nothing (void)

 Description
  Clears the contents of the display buffer.
   
Example
   BDM_ClearDisplayBuffer();
****************************************************************************/
void DM_ClearDisplayBuffer( void );

/****************************************************************************
 Function
  DM_ScrollDisplayBuffer

 Parameter
  uint8_t: The number of Columns to scroll

 Returns
 Nothing (void)

 Description
  Scrolls the contents of the display buffer by the indicated number of 
  columns.
   
Example
   DM_ScrollDisplayBuffer(4);
****************************************************************************/
void DM_ScrollDisplayBuffer( uint8_t NumCols2Scroll);

/****************************************************************************
 Function
  DM_TakeDisplayUpdateStep

 Parameter
  None

 Returns
  bool: true when all rows have been copied to the display; false otherwise

 Description
  Copies the contents of the display buffer to the MAX7219 controllers 1 row
  per call.
   
Example
   while (false == DM_TakeDisplayUpdateStep())
   {} // note this example is for non-event-driven code
****************************************************************************/
bool DM_TakeDisplayUpdateStep( void );


/****************************************************************************
 Function
  DM_AddChar2DisplayBuffer

 Parameter
  unsigned char: The character to be added to the display
  
 Returns
  Nothing (void)

 Description
  Copies the bitmap data from the font file into the rows of the frame buffer
  at the right-most character position in the buffer  
   
Example
   DM_AddChar2DisplayBuffer('A');
****************************************************************************/
void DM_AddChar2DisplayBuffer( unsigned char Char2Display);

/****************************************************************************
 Function
  DM_PutDataIntoBufferRow

 Parameter
  uint32_t: The new row data to be stored in the display buffer
  uint8_t:  The row (0->7) into which the data will be stored.
  
 Returns
  bool: true for a legal row number; false otherwise

 Description
  Copies the raw data from the Data2Insert parameter into the specified row 
  of the frame buffer 
   
Example
   DM_PutDataInBufferRow(0x00000001, 0);
****************************************************************************/
bool DM_PutDataIntoBufferRow( uint64_t Data2Insert, uint8_t WhichRow);

/****************************************************************************
 Function
  DM_QueryRowData

 Parameter
  uint8_t: The row of the display buffer to be queried
  uint32_t *: pointer to variable to hold the data from the buffer 
  
 Returns
  bool: true for a legal row number; false otherwise

 Description
  copies the contents of the specified row of the frame buffer into the
 location pointed to by pReturnValue
   
Example
   DM_QueryRowData(0,&ReturnedValue);
****************************************************************************/
bool DM_QueryRowData( uint8_t RowToQuery, uint64_t * pReturnValue);

#endif	/* DM_DISPLAY_H */
SoftWare Components – Event CheckeR Pseudo code
### Module: EventCheckers

### Function: Check4Keystroke
- Purpose: Check for new keystroke inputs from the keyboard.
- Steps:
  1. If `IsNewKeyReady()`:
      - Create an event of type `ES_NEW_KEY` with `GetNewKey()` as parameter.
      - Post the event to all services.
      - Return `true`.
  2. Otherwise, return `false`.

---

### Function: Check4IRRiseFall
- Purpose: Detect changes in the state of the IR sensor for coin detection.
- Steps:
  1. Initialize `lastInputState` to `HI` (static variable).
  2. Read `SW1` as `currentInputState`.
  3. If `currentInputState` differs from `lastInputState`:
      - If `currentInputState` is `LO`:
          - Print "Coin detected!".
          - Create an event of type `ES_COININPUT` with the current time as parameter.
          - Post the event to `CoinInsertionService`.
          - Set `ReturnVal` to `true`.
      - Update `lastInputState` to `currentInputState`.
  4. Return `ReturnVal`.

---

### Function: CheckForJoystickSignal
- Purpose: Monitor joystick ADC values for significant changes.
- Steps:
  1. Initialize `LastJoystickValue` to `0` (static variable).
  2. Allocate `adcResults[MAX_CHANNELS]` array.
  3. If `ADC_ConfigAutoScan(JOYSTICK_ADC_CHANNEL)` fails, return `false`.
  4. Perform `ADC_MultiRead(adcResults)`.
  5. Store the result of channel 0 in `CurrentJoystickValue`.
  6. If `abs(CurrentJoystickValue - LastJoystickValue)` exceeds `CHANGE_THRESHOLD`:
      - Create and post an event `ES_JoystickUpdate` with `CurrentJoystickValue` to `JoyStickService`.
      - Create and post an event `ES_MOTOR_WORKING` with `CurrentJoystickValue` to `MotorService`.
      - Update `LastJoystickValue`.
      - Return `true`.
  7. Otherwise, return `false`.

---

### Function: Check4Switch1
- Purpose: Detect state changes on `LIMIT_SW1`.
- Steps:
  1. Initialize `lastInput1State` to `0` (static variable).
  2. Read `LIMIT_SW1` as `currentInput1State`.
  3. If `currentInput1State` differs from `lastInput1State`:
      - If `currentInput1State` is `LO`:
          - Print "Button1 PRESSED".
          - Create an event `ES_PersonPickedUp` with the current time as parameter.
          - Post the event to `ScoreService`.
          - Set `ReturnVal` to `true`.
      - Update `lastInput1State` to `currentInput1State`.
  4. Return `ReturnVal`.

---

### Function: Check4Switch2
- Purpose: Detect state changes on `LIMIT_SW2`.
- Steps:
  1. Initialize `lastInput2State` to `0` (static variable).
  2. Read `LIMIT_SW2` as `currentInput2State`.
  3. If `currentInput2State` differs from `lastInput2State`:
      - If `currentInput2State` is `LO`:
          - Print "Button2 PRESSED".
          - Create an event `ES_RockCollision` with the current time as parameter.
          - Post the event to `ScoreService`.
          - Set `ReturnVal` to `true`.
      - Update `lastInput2State` to `currentInput2State`.
  4. Return `ReturnVal`.
SoftWare Components – Event Checker Source Code
/****************************************************************************
 Module
   EventCheckers.c

 Description
   This module contains event checkers for various hardware inputs and conditions,
   using the Gen2 Events and Services Framework.

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

/*----------------------------- Include Files -----------------------------*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ES_Events.h"
#include "ES_Port.h"
#include "EventCheckers.h"
#include "PIC32_AD_Lib.h"
#include "ES_Timer.h"
#include "MotorService.h"
#include "JoyStickService.h"
#include "CoinInsertionService.h"
#include "ScoreService.h"

#include <stdint.h>
#include <stdbool.h>
#include <stdlib.h> // For abs function

/*----------------------------- Module Defines -----------------------------*/
#define SW1                 PORTAbits.RA2
#define HI                  1
#define LO                  0

#define JOYSTICK_ADC_CHANNEL BIT12HI
#define CHANGE_THRESHOLD     10
#define IDLE_THRESHOLD       900
#define MAX_CHANNELS         8

#define LIMIT_SW1            PORTAbits.RA4
#define LIMIT_SW2            PORTBbits.RB4

/*---------------------------- Module Variables ---------------------------*/
// None needed for this module

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

/****************************************************************************
 Function
     Check4Keystroke

 Description
     Checks for a new keystroke from the keyboard and posts an event if detected.

 Returns
     bool - true if a new key event was detected, false otherwise.
****************************************************************************/
bool Check4Keystroke(void)
{
    if (IsNewKeyReady())
    {
        ES_Event_t ThisEvent = { .EventType = ES_NEW_KEY, .EventParam = GetNewKey() };
        ES_PostAll(ThisEvent);
        return true;
    }
    return false;
}

/****************************************************************************
 Function
     Check4IRRiseFall

 Description
     Detects changes in the state of an IR sensor (e.g., coin detection) and posts
     an event if a change is detected.

 Returns
     bool - true if a change in state was detected, false otherwise.
****************************************************************************/
bool Check4IRRiseFall(void)
{
    static bool lastInputState = HI;
    bool currentInputState = SW1;
    bool ReturnVal = false;

    if (currentInputState != lastInputState)
    {
        if (currentInputState == LO)
        {
            DB_printf("Coin detected!\n");
            ES_Event_t CoinInputEvent = { .EventType = ES_COININPUT, .EventParam = ES_Timer_GetTime() };
            PostCoinInsertionService(CoinInputEvent);
            ReturnVal = true;
        }
        lastInputState = currentInputState;
    }
    return ReturnVal;
}

/****************************************************************************
 Function
     CheckForJoystickSignal

 Description
     Checks for significant changes in joystick ADC values and posts events
     for joystick updates and motor operation.

 Returns
     bool - true if a significant joystick signal was detected, false otherwise.
****************************************************************************/
bool CheckForJoystickSignal(void)
{
    static uint16_t LastJoystickValue = 0;
    uint32_t adcResults[MAX_CHANNELS];
    bool SignalDetected = false;

    if (!ADC_ConfigAutoScan(JOYSTICK_ADC_CHANNEL))
        return false;

    ADC_MultiRead(adcResults);
    uint16_t CurrentJoystickValue = (uint16_t)adcResults[0];

    if (abs(CurrentJoystickValue - LastJoystickValue) > CHANGE_THRESHOLD)
    {
        ES_Event_t JoystickEvent = { .EventType = ES_JoystickUpdate, .EventParam = CurrentJoystickValue };
        PostJoyStickService(JoystickEvent);

        ES_Event_t MotorEvent = { .EventType = ES_MOTOR_WORKING, .EventParam = CurrentJoystickValue };
        PostMotorService(MotorEvent);

        SignalDetected = true;
        LastJoystickValue = CurrentJoystickValue;
    }
    return SignalDetected;
}

/****************************************************************************
 Function
     Check4Switch1

 Description
     Detects state changes on LIMIT_SW1 and posts an event if a button press
     is detected.

 Returns
     bool - true if a button press was detected, false otherwise.
****************************************************************************/
bool Check4Switch1(void)
{
    static bool lastInput1State = 0;
    bool currentInput1State = LIMIT_SW1;
    bool ReturnVal = false;

    if (currentInput1State != lastInput1State)
    {
        if (currentInput1State == LO)
        {
            DB_printf("Button1 PRESSED\n");
            ES_Event_t ThisEvent = { .EventType = ES_PersonPickedUp, .EventParam = ES_Timer_GetTime() };
            PostScoreService(ThisEvent);
            ReturnVal = true;
        }
        lastInput1State = currentInput1State;
    }
    return ReturnVal;
}

/****************************************************************************
 Function
     Check4Switch2

 Description
     Detects state changes on LIMIT_SW2 and posts an event if a button press
     is detected.

 Returns
     bool - true if a button press was detected, false otherwise.
****************************************************************************/
bool Check4Switch2(void)
{
    static bool lastInput2State = 0;
    bool currentInput2State = LIMIT_SW2;
    bool ReturnVal = false;

    if (currentInput2State != lastInput2State)
    {
        if (currentInput2State == LO)
        {
            DB_printf("Button2 PRESSED\n");
            ES_Event_t ThisEvent = { .EventType = ES_RockCollision, .EventParam = ES_Timer_GetTime() };
            PostScoreService(ThisEvent);
            ReturnVal = true;
        }
        lastInput2State = currentInput2State;
    }
    return ReturnVal;
}
SoftWare Components – Event Checker Wrapper
/****************************************************************************
 Module
     ES_EventCheckWrapper.h
 Description
     This is a wrapper header file for all of the header files that include
     prototypes for event checking functions.
 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 12/19/16 20:12 jec      Started coding
*****************************************************************************/

#ifndef ES_EventCheckWrapper_H
#define ES_EventCheckWrapper_H

// This is the header for the event checkers for the template project
#include "EventCheckers.h"

// Here you would #include the header files for any other modules that
// contained event checking functions

#endif  // ES_EventCheckWrapper_H
SoftWare Components – Event Checker Header file
/****************************************************************************
 Module
     EventCheckers.h
 Description
     header file for the event checking functions
 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 10/18/15 11:50 jec      added #include for stdint & stdbool
 08/06/13 14:37 jec      started coding
*****************************************************************************/

#ifndef EventCheckers_H
#define EventCheckers_H

// the common headers for C99 types
#include <stdint.h>
#include <stdbool.h>

// prototypes for event checkers

bool Check4Keystroke(void);
bool CheckForJoystickSignal(void);
bool Check4IRRiseFall(void);
bool Check4Switch1(void);
bool Check4Switch2(void);
#endif /* EventCheckers_H */
SoftWare Components – DM_Display pseudo Code
Define constants:
  NUM_ROWS = 8
  NumModules = 8
  DM_START_SHUTDOWN = 0x0C00
  DM_END_SHUTDOWN = 0x0C01
  DM_DISABLE_CODEB = 0x0900
  DM_ENABLE_SCAN = 0x0B07
  DM_SET_BRIGHT = 0x0A05

Define data structures:
  DM_Row_t - Union to represent rows of the display (64-bit or byte-by-byte).
  InitStep_t - Enum for initialization steps.

Global variables:
  DM_Display - Buffer to hold display data.
  CurrentInitStep - Tracks the current initialization step.

Function: DM_TakeInitDisplayStep()
  Perform the next initialization step based on CurrentInitStep:
    - Shutdown the display.
    - Clear the buffer.
    - Disable Code B decoding.
    - Enable digit scanning.
    - Set brightness.
    - Copy buffer data to display.
    - End shutdown and complete initialization.
  Return true if initialization is complete.

Function: DM_TakeDisplayUpdateStep()
  Update one row of the display using the buffer.
  Return true if all rows are updated.

Function: DM_ScrollDisplayBuffer(NumCols2Scroll)
  Shift all rows in DM_Display to the left by NumCols2Scroll.

Function: DM_AddChar2DisplayBuffer(Char2Display)
  Add bitmap data for Char2Display to the rightmost column of DM_Display.

Function: DM_ClearDisplayBuffer()
  Set all rows in DM_Display to zero.

Function: DM_PutDataIntoBufferRow(Data2Insert, WhichRow)
  Insert Data2Insert into the specified row of DM_Display.

Function: sendCmd(Cmd2Send)
  Send a command to all MAX7219 modules via SPI.

Function: sendRow(RowNum, RowData)
  Send a specific row of data to the MAX7219 display modules.

Additional text-related functions:
  - DM_CenterDisplayText
  - DM_DisplayScoreText
  Use these functions to manipulate and center text on the display.
SoftWare Components – DM_DisplayStarter64 source Code
/****************************************************************************
 Module
     DM_Display64.c
 Description
     Source file for the Dot Matrix LED Hardware Abstraction Layer (HAL) 
     used in ME218.
 Notes
     This module controls an 8x8 LED dot matrix display using the MAX7219.
 History
 When           Who     What/Why
 -------------- ---     --------
  10/03/21 12:32 jec    Started coding.
  2023-10-18    klg     Aligned DM_AddChar2DisplayBuffer.
****************************************************************************/

/*----------------------------- Include Files -----------------------------*/
#include <xc.h>
#include <stdbool.h>
#include "PIC32_SPI_HAL.h"
#include "DM_Display64.h"
#include "FontStuff.h"

/*----------------------------- Module Defines ----------------------------*/
#define NumModules 8
#define NUM_ROWS   8
#define NUM_ROWS_IN_FONT  3
#define DM_START_SHUTDOWN 0x0C00
#define DM_END_SHUTDOWN   0x0C01
#define DM_DISABLE_CODEB  0x0900
#define DM_ENABLE_SCAN    0x0B07
#define DM_SET_BRIGHT     0x0A05

/*---------------------------- Module Types ---------------------------*/
typedef union {
    uint64_t FullRow;
    uint8_t ByBytes[NumModules];
} DM_Row_t;

typedef enum {
    DM_StepStartShutdown = 0,
    DM_StepFillBufferZeros,
    DM_StepDisableCodeB,
    DM_StepEnableScanAll,
    DM_StepSetBrightness,
    DM_StepCopyBuffer2Display,
    DM_StepEndShutdown
} InitStep_t;

/*---------------------------- Module Variables ---------------------------*/
static DM_Row_t DM_Display[NUM_ROWS];
static InitStep_t CurrentInitStep = DM_StepStartShutdown;

/*---------------------------- Module Functions ---------------------------*/
static void sendCmd(uint16_t Cmd2Send);
static void sendRow(uint8_t RowNum, DM_Row_t RowData);

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

/****************************************************************************
 Function
  DM_TakeInitDisplayStep
 Description
  Initializes the MAX7219 display module, performing one step per call.
 Returns
  bool - true if initialization is complete, false otherwise.
****************************************************************************/
bool DM_TakeInitDisplayStep(void) {
    static uint8_t rowIndex = 0;
    bool ReturnVal = false;

    switch (CurrentInitStep) {
        case DM_StepStartShutdown:
            sendCmd(DM_START_SHUTDOWN);
            CurrentInitStep++;
            break;

        case DM_StepFillBufferZeros:
            DM_ClearDisplayBuffer();
            CurrentInitStep++;
            break;

        case DM_StepDisableCodeB:
            sendCmd(DM_DISABLE_CODEB);
            CurrentInitStep++;
            break;

        case DM_StepEnableScanAll:
            sendCmd(DM_ENABLE_SCAN);
            CurrentInitStep++;
            break;

        case DM_StepSetBrightness:
            sendCmd(DM_SET_BRIGHT);
            CurrentInitStep++;
            break;

        case DM_StepCopyBuffer2Display:
            if (DM_TakeDisplayUpdateStep()) {
                CurrentInitStep++;
            }
            break;

        case DM_StepEndShutdown:
            sendCmd(DM_END_SHUTDOWN);
            CurrentInitStep = DM_StepStartShutdown;
            ReturnVal = true;
            break;

        default:
            break;
    }

    return ReturnVal;
}

/****************************************************************************
 Function
  DM_TakeDisplayUpdateStep
 Description
  Updates the display row-by-row using the current buffer.
 Returns
  bool - true if all rows are updated, false otherwise.
****************************************************************************/
bool DM_TakeDisplayUpdateStep(void) {
    static int8_t WhichRow = 0;
    bool ReturnVal = false;

    sendRow(WhichRow, DM_Display[WhichRow]);
    WhichRow++;

    if (WhichRow == NUM_ROWS) {
        ReturnVal = true;
        WhichRow = 0;
    }

    return ReturnVal;
}

/****************************************************************************
 Function
  DM_ScrollDisplayBuffer
 Description
  Scrolls the contents of the display buffer left by the specified columns.
****************************************************************************/
void DM_ScrollDisplayBuffer(uint8_t NumCols2Scroll) {
    for (uint8_t row = 0; row < NUM_ROWS; row++) {
        DM_Display[row].FullRow <<= NumCols2Scroll;
    }
}

/****************************************************************************
 Function
  DM_AddChar2DisplayBuffer
 Description
  Adds a character to the rightmost position of the display buffer.
****************************************************************************/
void DM_AddChar2DisplayBuffer(unsigned char Char2Display) {
    for (uint8_t row = 0; row < NUM_ROWS; row++) {
        DM_Display[row].ByBytes[0] |= getFontLine(Char2Display, row);
    }
}

/****************************************************************************
 Function
  DM_ClearDisplayBuffer
 Description
  Clears the display buffer by setting all rows to zero.
****************************************************************************/
void DM_ClearDisplayBuffer(void) {
    for (uint8_t row = 0; row < NUM_ROWS; row++) {
        DM_Display[row].FullRow = 0;
    }
}

/****************************************************************************
 Function
  DM_PutDataIntoBufferRow
 Description
  Inserts data into a specific row of the display buffer.
 Returns
  bool - true if the operation is successful, false otherwise.
****************************************************************************/
bool DM_PutDataIntoBufferRow(uint64_t Data2Insert, uint8_t WhichRow) {
    if (WhichRow < NUM_ROWS) {
        DM_Display[WhichRow].FullRow = Data2Insert;
        return true;
    }
    return false;
}

/****************************************************************************
 Function
  sendCmd
 Description
  Sends a command to all MAX7219 modules.
****************************************************************************/
static void sendCmd(uint16_t Cmd2Send) {
    for (uint8_t i = 0; i < (NumModules - 1); i++) {
        SPIOperate_SPI1_Send16(Cmd2Send);
    }
    SPIOperate_SPI1_Send16Wait(Cmd2Send);
}

/****************************************************************************
 Function
  sendRow
 Description
  Sends a single row of data to the MAX7219 display.
****************************************************************************/
static void sendRow(uint8_t RowNum, DM_Row_t RowData) {
    RowNum = NUM_ROWS - (RowNum + 1);
    for (uint8_t i = 0; i < (NumModules - 1); i++) {
        SPIOperate_SPI1_Send16((((uint16_t)(RowNum + 1)) << 8) |
                               BitReverseTable256[RowData.ByBytes[i]]);
    }
    SPIOperate_SPI1_Send16Wait((((uint16_t)(RowNum + 1)) << 8) |
                               BitReverseTable256[RowData.ByBytes[NumModules - 1]]);
}

/* Additional Text Manipulation Functions */
// These include DM_CenterDisplayText and other related functions for text alignment and updates.
SoftWare Components – DM_DisplayStarter64 Header file
/* 
 * File:   DM_Display.h
 * Author: Ed
 *
 * Created on July 15, 2021, 11:54 AM
 * Updated 2023-10-18 Aligned DM_AddChar2DisplayBuffer
 */

#ifndef DM_DISPLAY_H
#define	DM_DISPLAY_H

/****************************************************************************
 Function
  DM_TakeInitDisplayStep

 Parameter
  None

 Returns
  bool: true when there are no more initialization steps to perform; false
        while there still more steps to be taken

 Description
  Initializes the MAX7219 4-module display performing 1 step for each call:
    First, bring put it in shutdown to disable all displays, return false
    Next fill the display RAM with Zeros to insure blanked, return false
    Then Disable Code B decoding for all digits, return false
    Then, enable scanning for all digits, return false
    The next setup step is to set the brightness to minimum, return false
    Copy our display buffer to the display, return false
    Finally, bring it out of shutdown and return true
   
Example
   while ( false == DM_TakeInitDisplayStep() )
   {} // note this example is for non-event-driven code
****************************************************************************/
bool DM_TakeInitDisplayStep( void );


/****************************************************************************
 Function
  DM_ClearDisplayBuffer

 Parameter
  None

 Returns
 Nothing (void)

 Description
  Clears the contents of the display buffer.
   
Example
   BDM_ClearDisplayBuffer();
****************************************************************************/
void DM_ClearDisplayBuffer( void );

/****************************************************************************
 Function
  DM_ScrollDisplayBuffer

 Parameter
  uint8_t: The number of Columns to scroll

 Returns
 Nothing (void)

 Description
  Scrolls the contents of the display buffer by the indicated number of 
  columns.
   
Example
   DM_ScrollDisplayBuffer(4);
****************************************************************************/
void DM_ScrollDisplayBuffer( uint8_t NumCols2Scroll);

/****************************************************************************
 Function
  DM_TakeDisplayUpdateStep

 Parameter
  None

 Returns
  bool: true when all rows have been copied to the display; false otherwise

 Description
  Copies the contents of the display buffer to the MAX7219 controllers 1 row
  per call.
   
Example
   while (false == DM_TakeDisplayUpdateStep())
   {} // note this example is for non-event-driven code
****************************************************************************/
bool DM_TakeDisplayUpdateStep( void );


/****************************************************************************
 Function
  DM_AddChar2DisplayBuffer

 Parameter
  unsigned char: The character to be added to the display
  
 Returns
  Nothing (void)

 Description
  Copies the bitmap data from the font file into the rows of the frame buffer
  at the right-most character position in the buffer  
   
Example
   DM_AddChar2DisplayBuffer('A');
****************************************************************************/
void DM_AddChar2DisplayBuffer( unsigned char Char2Display);

/****************************************************************************
 Function
  DM_PutDataIntoBufferRow

 Parameter
  uint32_t: The new row data to be stored in the display buffer
  uint8_t:  The row (0->7) into which the data will be stored.
  
 Returns
  bool: true for a legal row number; false otherwise

 Description
  Copies the raw data from the Data2Insert parameter into the specified row 
  of the frame buffer 
   
Example
   DM_PutDataInBufferRow(0x00000001, 0);
****************************************************************************/
bool DM_PutDataIntoBufferRow( uint64_t Data2Insert, uint8_t WhichRow);

/****************************************************************************
 Function
  DM_QueryRowData

 Parameter
  uint8_t: The row of the display buffer to be queried
  uint32_t *: pointer to variable to hold the data from the buffer 
  
 Returns
  bool: true for a legal row number; false otherwise

 Description
  copies the contents of the specified row of the frame buffer into the
 location pointed to by pReturnValue
   
Example
   DM_QueryRowData(0,&ReturnedValue);
****************************************************************************/
bool DM_QueryRowData( uint8_t RowToQuery, uint64_t * pReturnValue);

#endif	/* DM_DISPLAY_H */
SoftWare Components – Scoring Service Pseudo Code
/****************************************************************************
 Module
   ScoreService.c

 Description
   Service for handling scoring operations, managing states, and reacting 
   to events under the Gen2 framework.

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

/*----------------------------- Include Files -----------------------------*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ScoreService.h"
#include "DisplayerService.h"
#include "dbprintf.h"

/*----------------------------- Module Defines ----------------------------*/
#define ONE_SEC 1000
#define IDLE_BUTTON1_TIME (ONE_SEC * 0.5)

/*---------------------------- Module Variables ---------------------------*/
static ScoreState_t CurrentState;  // Current state of the scoring service
static uint8_t MyPriority;         // Priority of the service
static uint16_t MyScore;           // Current score
static uint8_t Button1;            // Button 1 state
static uint8_t Button2;            // Button 2 state

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

/****************************************************************************
 Function
     InitScoreService

 Parameters
     uint8_t Priority - The service priority level

 Returns
     bool - true if initialization succeeds, false otherwise

 Description
     Initializes the scoring service and sets up initial states and variables.
****************************************************************************/
bool InitScoreService(uint8_t Priority)
{
    MyPriority = Priority;
    MyScore = 0;
    CurrentState = InitScoringState;

    // Configure buttons as inputs
    ANSELAbits.ANSA0 = 0;
    ANSELAbits.ANSA1 = 0;
    TRISAbits.TRISA4 = 1;
    TRISBbits.TRISB4 = 1;
    Button1 = PORTAbits.RA4;
    Button2 = PORTBbits.RB4;

    // Post initial event
    ES_Event_t ThisEvent = { .EventType = ES_INIT };
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     PostScoreService

 Parameters
     ES_Event_t ThisEvent - The event to post

 Returns
     bool - true if the event was successfully posted, false otherwise

 Description
     Posts an event to this service's queue.
****************************************************************************/
bool PostScoreService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     RunScoreService

 Parameters
     ES_Event_t ThisEvent - The event to process

 Returns
     ES_Event_t - ES_NO_EVENT if no errors, otherwise an error event

 Description
     Processes events and updates the state machine for scoring operations.
****************************************************************************/
ES_Event_t RunScoreService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent = { .EventType = ES_NO_EVENT };

    switch (CurrentState)
    {
        case InitScoringState:
            if (ThisEvent.EventType == ES_INIT)
            {
                // Remain in InitScoringState until further action
            }
            else if (ThisEvent.EventType == ES_GAME_START)
            {
                MyScore = 0;  // Reset score
                DB_printf("Game started, score reset to %u\n", MyScore);
                CurrentState = PendingState;

                // Notify DisplayerService of the new score
                ES_Event_t NewEvent = { .EventType = ES_NEW_SCORE, .EventParam = MyScore };
                PostDisplayerService(NewEvent);
            }
            break;

        case PendingState:
            if (ThisEvent.EventType == ES_RockCollision)
            {
                CurrentState = LosePointsState;
                if (MyScore > 0)
                {
                    MyScore -= 3;
                }
                else
                {
                    DB_printf("CANNOT GO BELOW ZERO.\n");
                }
                DB_printf("New Score = %u\n", MyScore);

                ES_Event_t NewEvent = { .EventType = ES_NEW_SCORE, .EventParam = MyScore };
                PostDisplayerService(NewEvent);
            }
            else if (ThisEvent.EventType == ES_PersonPickedUp)
            {
                CurrentState = AddPointsState;
                MyScore += 10;
                DB_printf("New Score = %u\n", MyScore);

                ES_Event_t NewEvent = { .EventType = ES_NEW_SCORE, .EventParam = MyScore };
                PostDisplayerService(NewEvent);
            }
            else if (ThisEvent.EventType == ES_TIMEUP)
            {
                CurrentState = InitScoringState;

                // Notify CountdownService of scoring termination
                ES_Event_t ScoreEndEvent = { .EventType = ES_SCORE_TERMINATE };
                PostCountdownService(ScoreEndEvent);

                DB_printf("### Scoring Terminates now. ###\n");
            }
            break;

        case LosePointsState:
            if (ThisEvent.EventType == ES_LosePoint)
            {
                CurrentState = PendingState;
            }
            else if (ThisEvent.EventType == ES_TIMEUP)
            {
                CurrentState = InitScoringState;

                ES_Event_t ScoreEndEvent = { .EventType = ES_SCORE_TERMINATE };
                PostCountdownService(ScoreEndEvent);

                DB_printf("### Scoring Terminates now. ###\n");
            }
            break;

        case AddPointsState:
            if (ThisEvent.EventType == ES_RockCollision)
            {
                CurrentState = PendingState;
            }
            else if (ThisEvent.EventType == ES_TIMEUP)
            {
                CurrentState = InitScoringState;

                ES_Event_t ScoreEndEvent = { .EventType = ES_SCORE_TERMINATE };
                PostCountdownService(ScoreEndEvent);

                DB_printf("### Scoring Terminates now. ###\n");
            }
            break;

        default:
            break;
    }

    return ReturnEvent;
}

/****************************************************************************
 Function
     QueryScoreService

 Parameters
     None

 Returns
     ScoreState_t - The current state of the scoring service

 Description
     Returns the current state of the scoring service.
****************************************************************************/
ScoreState_t QueryScoreService(void)
{
    return CurrentState;
}
SoftWare Components – Scoring Service Source Code
/****************************************************************************
 Module
   ScoreService.c

 Description
   Service for handling scoring operations, managing states, and reacting 
   to events under the Gen2 framework.

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

/*----------------------------- Include Files -----------------------------*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "ScoreService.h"
#include "DisplayerService.h"
#include "dbprintf.h"

/*----------------------------- Module Defines ----------------------------*/
#define ONE_SEC 1000
#define IDLE_BUTTON1_TIME (ONE_SEC * 0.5)

/*---------------------------- Module Variables ---------------------------*/
static ScoreState_t CurrentState;  // Current state of the scoring service
static uint8_t MyPriority;         // Priority of the service
static uint16_t MyScore;           // Current score
static uint8_t Button1;            // Button 1 state
static uint8_t Button2;            // Button 2 state

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

/****************************************************************************
 Function
     InitScoreService

 Parameters
     uint8_t Priority - The service priority level

 Returns
     bool - true if initialization succeeds, false otherwise

 Description
     Initializes the scoring service and sets up initial states and variables.
****************************************************************************/
bool InitScoreService(uint8_t Priority)
{
    MyPriority = Priority;
    MyScore = 0;
    CurrentState = InitScoringState;

    // Configure buttons as inputs
    ANSELAbits.ANSA0 = 0;
    ANSELAbits.ANSA1 = 0;
    TRISAbits.TRISA4 = 1;
    TRISBbits.TRISB4 = 1;
    Button1 = PORTAbits.RA4;
    Button2 = PORTBbits.RB4;

    // Post initial event
    ES_Event_t ThisEvent = { .EventType = ES_INIT };
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     PostScoreService

 Parameters
     ES_Event_t ThisEvent - The event to post

 Returns
     bool - true if the event was successfully posted, false otherwise

 Description
     Posts an event to this service's queue.
****************************************************************************/
bool PostScoreService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     RunScoreService

 Parameters
     ES_Event_t ThisEvent - The event to process

 Returns
     ES_Event_t - ES_NO_EVENT if no errors, otherwise an error event

 Description
     Processes events and updates the state machine for scoring operations.
****************************************************************************/
ES_Event_t RunScoreService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent = { .EventType = ES_NO_EVENT };

    switch (CurrentState)
    {
        case InitScoringState:
            if (ThisEvent.EventType == ES_INIT)
            {
                // Remain in InitScoringState until further action
            }
            else if (ThisEvent.EventType == ES_GAME_START)
            {
                MyScore = 0;  // Reset score
                DB_printf("Game started, score reset to %u\n", MyScore);
                CurrentState = PendingState;

                // Notify DisplayerService of the new score
                ES_Event_t NewEvent = { .EventType = ES_NEW_SCORE, .EventParam = MyScore };
                PostDisplayerService(NewEvent);
            }
            break;

        case PendingState:
            if (ThisEvent.EventType == ES_RockCollision)
            {
                CurrentState = LosePointsState;
                if (MyScore > 0)
                {
                    MyScore -= 3;
                }
                else
                {
                    DB_printf("CANNOT GO BELOW ZERO.\n");
                }
                DB_printf("New Score = %u\n", MyScore);

                ES_Event_t NewEvent = { .EventType = ES_NEW_SCORE, .EventParam = MyScore };
                PostDisplayerService(NewEvent);
            }
            else if (ThisEvent.EventType == ES_PersonPickedUp)
            {
                CurrentState = AddPointsState;
                MyScore += 10;
                DB_printf("New Score = %u\n", MyScore);

                ES_Event_t NewEvent = { .EventType = ES_NEW_SCORE, .EventParam = MyScore };
                PostDisplayerService(NewEvent);
            }
            else if (ThisEvent.EventType == ES_TIMEUP)
            {
                CurrentState = InitScoringState;

                // Notify CountdownService of scoring termination
                ES_Event_t ScoreEndEvent = { .EventType = ES_SCORE_TERMINATE };
                PostCountdownService(ScoreEndEvent);

                DB_printf("### Scoring Terminates now. ###\n");
            }
            break;

        case LosePointsState:
            if (ThisEvent.EventType == ES_LosePoint)
            {
                CurrentState = PendingState;
            }
            else if (ThisEvent.EventType == ES_TIMEUP)
            {
                CurrentState = InitScoringState;

                ES_Event_t ScoreEndEvent = { .EventType = ES_SCORE_TERMINATE };
                PostCountdownService(ScoreEndEvent);

                DB_printf("### Scoring Terminates now. ###\n");
            }
            break;

        case AddPointsState:
            if (ThisEvent.EventType == ES_RockCollision)
            {
                CurrentState = PendingState;
            }
            else if (ThisEvent.EventType == ES_TIMEUP)
            {
                CurrentState = InitScoringState;

                ES_Event_t ScoreEndEvent = { .EventType = ES_SCORE_TERMINATE };
                PostCountdownService(ScoreEndEvent);

                DB_printf("### Scoring Terminates now. ###\n");
            }
            break;

        default:
            break;
    }

    return ReturnEvent;
}

/****************************************************************************
 Function
     QueryScoreService

 Parameters
     None

 Returns
     ScoreState_t - The current state of the scoring service

 Description
     Returns the current state of the scoring service.
****************************************************************************/
ScoreState_t QueryScoreService(void)
{
    return CurrentState;
}
SoftWare Components – Countdown Service Pseudo Code
Initialize global variables:
  - `MyPriority`: Priority of the service
  - `CurrentState`: Current state of the CountdownService
  - `CountdownValue`: Countdown timer value (default: 61)

---

Function: InitCountdownService(Priority)
  - Set `MyPriority` to Priority.
  - Initialize `CurrentState` to `InitCountdown`.
  - Set `CountdownValue` to 61.
  - Post an `ES_INIT` event to the service queue.
  - Return true if successful, false otherwise.

---

Function: PostCountdownService(Event)
  - Post `Event` to the service queue.
  - Return true if successful, false otherwise.

---

Function: RunCountdownService(Event)
  - Initialize `ReturnEvent` as `ES_NO_EVENT`.

  Switch (CurrentState):
    Case `InitCountdown`:
      If Event.Type == `ES_INIT`:
        - Placeholder for any initialization logic.
      Else If Event.Type == `ES_GAME_START`:
        - Transition to `Waiting4AllServices2Terminate`.
        - Start milestone timer with `MILESTONE_PERIOD`.
        - Notify other services about game start if required.

    Case `Waiting4AllServices2Terminate`:
      If Event.Type == `ES_SCORE_TERMINATE` or `ES_MOTOR_TERMINATE`:
        - Check if all dependent services (Motor and Score) are in initial states:
          If both are in initial states:
            - Print "Motor and Scoring Services Stopped."
            - Post `ES_GAME_OVER` to all services.
            - Reset `CurrentState` to `InitCountdown`.

    Case `AllServicesCompleted`:
      - Do nothing; no further actions needed.

    Default:
      - Do nothing for unknown states.

  Return `ReturnEvent`.

---

Function: QueryCountdownService()
  - Return the current state (`CurrentState`) of the service.
SoftWare Components – Countdown Service Source Code
/****************************************************************************
 Module
   CountdownService.c

 Description
   Service for managing a countdown timer and coordinating state transitions
   based on events, adhering to the Gen2 framework template.

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

/*----------------------------- Include Files -----------------------------*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "CountdownService.h"
#include "MotorService.h"
#include "ScoreService.h"

/*----------------------------- Module Defines ----------------------------*/
#define MILESTONE_PERIOD 950 // Timer duration in milliseconds for countdown updates

/*---------------------------- Module Variables ---------------------------*/
// Current state of the CountdownService
static CountdownState_t CurrentState;

// Priority of this service
static uint8_t MyPriority;

// Countdown value
static uint8_t CountdownValue;

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

/****************************************************************************
 Function
     InitCountdownService

 Parameters
     uint8_t Priority - the priority of this service

 Returns
     bool - true if initialization was successful, false otherwise

 Description
     Initializes the CountdownService and sets up initial states and variables.
****************************************************************************/
bool InitCountdownService(uint8_t Priority)
{
    MyPriority = Priority;
    CurrentState = InitCountdown;
    CountdownValue = 61; // Initialize countdown value

    // Post the initial transition event
    ES_Event_t ThisEvent = { .EventType = ES_INIT };
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     PostCountdownService

 Parameters
     ES_Event_t ThisEvent - the event to post

 Returns
     bool - true if the event was successfully posted, false otherwise

 Description
     Posts an event to this state machine's queue.
****************************************************************************/
bool PostCountdownService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     RunCountdownService

 Parameters
     ES_Event_t ThisEvent - the event to process

 Returns
     ES_Event_t - ES_NO_EVENT if no errors, or another event otherwise

 Description
     Runs the state machine logic for the CountdownService.
****************************************************************************/
ES_Event_t RunCountdownService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent = { .EventType = ES_NO_EVENT }; // Default return value

    switch (CurrentState)
    {
        case InitCountdown:
            if (ThisEvent.EventType == ES_INIT)
            {
                // Placeholder for initialization actions
            }
            else if (ThisEvent.EventType == ES_GAME_START)
            {
                CurrentState = Waiting4AllServices2Terminate;

                // Start the milestone timer
                ES_Timer_InitTimer(MILESTONE_TIMER, MILESTONE_PERIOD);

                // TODO: Notify display service about game start (if required)
            }
            break;

        case Waiting4AllServices2Terminate:
            if (ThisEvent.EventType == ES_SCORE_TERMINATE || ThisEvent.EventType == ES_MOTOR_TERMINATE)
            {
                // Check if all required services have returned to their initial states
                if (QueryMotorService() == InitMotorState && QueryScoreService() == InitScoringState)
                {
                    DB_printf("#####Motor and Scoring Services Stopped.#####\n");

                    // Post game over event to all relevant services
                    ES_Event_t GameOverEvent = { .EventType = ES_GAME_OVER };
                    ES_PostAll(GameOverEvent);

                    // Reset state machine
                    CurrentState = InitCountdown;
                }
            }
            break;

        case AllServicesCompleted:
            // Final state; no actions needed
            break;

        default:
            break;
    }

    return ReturnEvent;
}

/****************************************************************************
 Function
     QueryCountdownService

 Parameters
     None

 Returns
     CountdownState_t - the current state of the CountdownService

 Description
     Returns the current state of the CountdownService.
****************************************************************************/
CountdownState_t QueryCountdownService(void)
{
    return CurrentState;
}
SoftWare Components – Countdown Service Header File
/****************************************************************************

  Header file for CountdownService
  based on the Gen2 Events and Services Framework

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

#ifndef CountdownService_H
#define CountdownService_H

// Event Definitions
#include "ES_Configure.h" /* gets us event definitions */
#include "ES_Types.h"     /* gets bool type for returns */

// typedefs for the states
// State definitions for use with the query function
typedef enum
{
  InitCountdown, CountdownUpdate, Waiting4AllServices2Terminate, AllServicesCompleted
} CountdownState_t;

// Public Function Prototypes
bool InitCountdownService(uint8_t Priority);
bool PostCountdownService(ES_Event_t ThisEvent);
ES_Event_t RunCountdownService(ES_Event_t ThisEvent);
CountdownState_t QueryCountdownService(void);

#endif /* CountdownService_H */
SoftWare Components – My Centered LED Pseudo Code
Initialize global variables:
  - `MyPriority`: Service priority
  - `GameCountDown`: Countdown timer for game (default: 60)
  - `StartGameCountDown`: Pre-game countdown (default: 4)
  - `GAMESTART`: Boolean indicating if the game has started
  - `CurrentState`: Current state of the LED service

---

Function: InitMyCenteredLEDService(Priority)
  - Set `MyPriority` to Priority.
  - Scale `GameCountDown` and `StartGameCountDown` by frequency.
  - Post an initial event (`ES_INIT_CENTRED`) to the service queue.
  - Return true if successful, false otherwise.

---

Function: PostMyCenteredLEDService(Event)
  - Post Event to the service queue.
  - Return true if successful, false otherwise.

---

Function: RunMyCenteredLEDService(Event)
  - Initialize `ReturnEvent` as `ES_NO_EVENT`.

  Switch (Event.Type):
    Case `ES_LONG_IDLE`:
      - Post `ES_NEW_INPUT_TEXT` with `IDLE` to the display service.
      - Post `ES_TIMEUP` to all services.
      - Reset countdown timers and set state to `IDLEState`.

    Case `ES_GAME_START`:
      - Clear display buffer.
      - Post `ES_READY_COUNTDOWN` to start the countdown timer.
      - Transition to `ReadyState`.

    Case `ES_TIMEOUT`:
      - If timer matches countdown:
        Switch (CurrentState):
          Case `ReadyState`:
            - Post `READY` to the display and transition to `CountDown`.
          Case `CountDown`:
            - Decrement countdown and post `ES_READY_COUNTDOWN`.
            - If game hasn't started and countdown < 10:
              - Post `GO` to the display, set game as started.
            - If countdown reaches 0:
              - Post `END` to the display and `ES_TIMEUP` to all services.
              - Reset timers and transition to `IDLEState`.

    Case `ES_READY_COUNTDOWN`:
      - Decrement `StartGameCountDown`.

  Return `ReturnEvent`.

---

Function: QueryMyCenteredLEDService()
  - Return `CurrentState`.
SoftWare Components – My Centered LED Source Code
/****************************************************************************
 Module
   MyCenteredLEDService.c

 Description
   A service to display input text centered on the LED matrix display.

 History
 When           Who     What/Why
 -------------- ---     --------
 11/12/24 14:30  You    Created the service for centered text display
****************************************************************************/

/*----------------------------- Include Files -----------------------------*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "MyCenteredLEDService.h"
#include "DM_Display64.h"
#include "DisplayerService.h"

/*----------------------------- Module Defines ----------------------------*/
#define GAMECOUNTDOWN 60
#define STARTGAMECOUNTDOWN 4
#define ONE_SEC 1000

/*---------------------------- Module Variables ---------------------------*/
static uint8_t MyPriority;
static uint16_t GameCountDown = GAMECOUNTDOWN;
static uint16_t StartGameCountDown = STARTGAMECOUNTDOWN;
static bool GAMESTART = false;
static LEDState_t CurrentState;

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

/****************************************************************************
 Function
     InitMyCenteredLEDService

 Description
     Initializes the service and prepares the display for centered text.
****************************************************************************/
bool InitMyCenteredLEDService(uint8_t Priority)
{
    MyPriority = Priority;
    GameCountDown *= 10;
    StartGameCountDown = StartGameCountDown * 10 - 1;

    puts("Starting MyCenteredLEDService\r");

    ES_Event_t ThisEvent = { .EventType = ES_INIT_CENTRED };
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     PostMyCenteredLEDService

 Description
     Posts an event to this service's queue.
****************************************************************************/
bool PostMyCenteredLEDService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
    RunMyCenteredLEDService

 Description
   Handles events and displays the input text centered on the display.
****************************************************************************/
ES_Event_t RunMyCenteredLEDService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent = { .EventType = ES_NO_EVENT };

    switch (ThisEvent.EventType) {
        case ES_LONG_IDLE:
            DB_printf("ES_LONG_IDLE received\n");

            ES_Event_t NewEvent = { .EventType = ES_NEW_INPUT_TEXT, .EventParam = IDLE };
            PostDisplayerService(NewEvent);

            ES_Event_t EndEvent = { .EventType = ES_TIMEUP };
            ES_PostAll(EndEvent);

            GameCountDown = GAMECOUNTDOWN * 10;
            StartGameCountDown = STARTGAMECOUNTDOWN * 10 - 1;
            GAMESTART = false;
            CurrentState = IDLEState;
            break;

        case ES_GAME_START:
            puts("Game start initiated\n");
            DM_ClearDisplayBuffer();

            ES_Event_t CountdownEvent = { .EventType = ES_READY_COUNTDOWN };
            ES_Timer_InitTimer(COUNTDOWM_TIMER, ONE_SEC);
            DB_printf("Starting the countdown\n");
            CurrentState = ReadyState;
            break;

        case ES_TIMEOUT:
            if (ThisEvent.EventParam == COUNTDOWM_TIMER) {
                switch (CurrentState) {
                    case ReadyState:
                        ES_Event_t ReadyEvent = { .EventType = ES_NEW_INPUT_TEXT, .EventParam = READY };
                        PostDisplayerService(ReadyEvent);
                        ES_Timer_InitTimer(COUNTDOWM_TIMER, ONE_SEC);
                        CurrentState = CountDown;
                        break;

                    case CountDown:
                        StartGameCountDown--;
                        ES_Event_t CountdownEvent = { .EventType = ES_READY_COUNTDOWN, .EventParam = StartGameCountDown };
                        PostDisplayerService(CountdownEvent);

                        if (!GAMESTART) {
                            ES_Timer_InitTimer(COUNTDOWM_TIMER, ONE_SEC / 10);
                            if (StartGameCountDown < 10) {
                                ES_Event_t GoEvent = { .EventType = ES_NEW_INPUT_TEXT, .EventParam = GO };
                                PostDisplayerService(GoEvent);
                                StartGameCountDown = GameCountDown + 10;
                                GAMESTART = true;
                            }
                        } else if (StartGameCountDown == 0) {
                            ES_Event_t EndEvent = { .EventType = ES_NEW_INPUT_TEXT, .EventParam = END };
                            PostDisplayerService(EndEvent);

                            ES_Event_t TimeUpEvent = { .EventType = ES_TIMEUP };
                            ES_PostAll(TimeUpEvent);

                            GameCountDown = GAMECOUNTDOWN * 10;
                            StartGameCountDown = STARTGAMECOUNTDOWN * 10 - 1;
                            GAMESTART = false;
                            CurrentState = IDLEState;
                        } else {
                            ES_Timer_InitTimer(COUNTDOWM_TIMER, ONE_SEC / 10);
                        }
                        break;

                    default:
                        break;
                }
            }
            break;

        case ES_READY_COUNTDOWN:
            StartGameCountDown--;
            break;

        default:
            break;
    }

    return ReturnEvent;
}

/****************************************************************************
 Function
     QueryMyCenteredLEDService

 Description
     Returns the current state of the service.
****************************************************************************/
LEDState_t QueryMyCenteredLEDService(void)
{
    return CurrentState;
}
SoftWare Components – My Centered LED Header file
/****************************************************************************
 Module
   MyCenteredLEDService.h

 Revision
   1.0.1

 Description
   Header file for the MyCenteredLEDService module. This service displays
   input text centered on the LED matrix display.

 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 11/12/24 14:30  You    Created the header file for centered text display
****************************************************************************/

#ifndef MY_CENTERED_LED_SERVICE_H
#define MY_CENTERED_LED_SERVICE_H
#define READY 1
#define GO 2
#define END 3



/*----------------------------- Include Files -----------------------------*/
#include "ES_Types.h"

/*----------------------------- Module Defines ----------------------------*/
typedef enum {
    IDLEState,
    ReadyState,
    CountDown,
    PostGoTransition,
    CountDownEnd,
} LEDState_t;


#define MAX_TEXT_LENGTH 32  // Maximum length of the input text
bool InitMyCenteredLEDService(uint8_t Priority);
bool PostMyCenteredLEDService(ES_Event_t ThisEvent);
ES_Event_t RunMyCenteredLEDService(ES_Event_t ThisEvent);

#endif /* MY_CENTERED_LED_SERVICE_H */
SoftWare Components – Joystick Service Pseudo Code
Define constants:
  - ONE_SEC = 1000

Define global variables:
  - CurrentState: Tracks the current state of the joystick service.
  - LatestJoystickValue: Stores the most recent joystick value.
  - MyPriority: Priority level assigned to this service.

---

Function: InitJoyStickService(Priority)
  - Save the provided Priority to MyPriority.
  - Print initialization message to indicate service start.
  - Configure hardware:
      - Set RB12 as an analog input.
  - Set CurrentState to `InitPState`.
  - Post an initial event (`ES_JOY_INIT`) to the service queue.
  - Return true if the event was successfully posted, false otherwise.

---

Function: PostJoyStickService(ThisEvent)
  - Post ThisEvent to the service queue using MyPriority.
  - Return true if the event was successfully posted, false otherwise.

---

Function: RunJoyStickService(ThisEvent)
  - Initialize ReturnEvent with `ES_NO_EVENT` as the default.
  
  Switch (CurrentState):
    Case InitPState:
      - If ThisEvent is `ES_JOY_INIT`:
          - Print a message indicating service initialization.
          - Transition CurrentState to `JoystickActive`.
    
    Case JoystickActive:
      - If ThisEvent is `ES_JOYSTICK_UPDATE`:
          - Update LatestJoystickValue with ThisEvent.EventParam.
          - Print the new joystick value.
          - If the displayer state is `GOSTATE` and the joystick value exceeds a threshold (1010):
              - Initialize a timer (`TIMEOUT_TIMER`) for 20 seconds.

      - Else If ThisEvent is `ES_TIMEOUT`:
          - If LatestJoystickValue exceeds the threshold (1010):
              - Create an `ES_LONG_IDLE` event.
              - Post the event to the displayer service.
              - Print a message indicating the idle event was triggered.

    Default:
      - Print an error message indicating an unknown state.

  Return ReturnEvent
SoftWare Components – Joystick Service Source Code
/****************************************************************************
 Module
   JoyStickService.c

 Description
   Service for handling joystick inputs and coordinating state transitions
   based on joystick events, adhering to the Gen2 Events and Services Framework.

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

/*----------------------------- Include Files -----------------------------*/
#include "JoyStickService.h"
#include <xc.h>
#include "DM_Display.h"
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "MotorService.h"
#include "DisplayerService.h"
#include "CoinInsertionService.h"

/*---------------------------- Module Defines ----------------------------*/
#define ONE_SEC 1000

/*---------------------------- Module Variables ---------------------------*/
// Current state of the joystick service
static JoyStickState_t CurrentState;

// Latest value read from the joystick
static uint16_t LatestJoystickValue;

// Priority of this service
static uint8_t MyPriority;

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

/****************************************************************************
 Function
     InitJoyStickService

 Parameters
     uint8_t Priority - the service priority level to be assigned

 Returns
     bool - true if initialization succeeds, false otherwise

 Description
     Initializes the joystick service, sets up hardware configurations, and 
     posts an initial event to indicate the service is ready.
****************************************************************************/
bool InitJoyStickService(uint8_t Priority)
{
    // Save the assigned priority for future event posting
    MyPriority = Priority;

    // Print initialization message
    puts("Initiating JoyStick Service, get ready to play\r\n");

    // Configure hardware: Set RB12 as analog input
    TRISBbits.TRISB12 = 1;
    ANSELBbits.ANSB12 = 1;

    // Set the initial state
    CurrentState = InitPState;

    // Post the initial transition event
    ES_Event_t ThisEvent = { .EventType = ES_JOY_INIT };
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     PostJoyStickService

 Parameters
     ES_Event_t ThisEvent - The event to post to the queue

 Returns
     bool - true if the event was successfully posted, false otherwise

 Description
     Posts an event to this service's queue.
****************************************************************************/
bool PostJoyStickService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     RunJoyStickService

 Parameters
     ES_Event_t ThisEvent - The event to process

 Returns
     ES_Event_t - ES_NO_EVENT if no errors, otherwise an error event

 Description
     Processes events and updates the state machine for joystick service.
****************************************************************************/
ES_Event_t RunJoyStickService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent = { .EventType = ES_NO_EVENT }; // Default return event

    switch (CurrentState)
    {
        case InitPState:
            if (ThisEvent.EventType == ES_JOY_INIT)
            {
                puts("Joystick Service Initialized\r\n");
                CurrentState = JoystickActive;
            }
            break;

        case JoystickActive:
            if (ThisEvent.EventType == ES_JOYSTICK_UPDATE)
            {
                // Update the latest joystick value and print it
                LatestJoystickValue = ThisEvent.EventParam;
                printf("Joystick Active - New Value: %d\r\n", LatestJoystickValue);

                // Check displayer state and joystick threshold
                if (QueryDisplayerService() == GOSTATE && LatestJoystickValue > 1010)
                {
                    ES_Timer_InitTimer(TIMEOUT_TIMER, ONE_SEC * 20);
                }
            }
            else if (ThisEvent.EventType == ES_TIMEOUT)
            {
                // Trigger an idle event if the joystick value exceeds a threshold
                if (LatestJoystickValue > 1010)
                {
                    ES_Event_t EndEvent = { .EventType = ES_LONG_IDLE };
                    PostMyCenteredLEDService(EndEvent);
                    printf("No movement detected! Triggering idle event.\r\n");
                }
            }
            break;

        default:
            puts("Unknown State\r\n");
            break;
    }

    return ReturnEvent;
}

/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
SoftWare Components – Joystick Service Header File
/****************************************************************************

  Header file for Test Harness Service0
  based on the Gen 2 Events and Services Framework

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

#ifndef MyJoyStickService_H
#define MyJoyStickService_H

#include <stdint.h>
#include <stdbool.h>
#include "ES_Events.h"
#include "ES_Port.h"                // needed for definition of REENTRANT
#include "PIC32_SPI_HAL.h"
#include "DM_Display.h"


// Public Function Prototypes
typedef enum
{
    InitPState,
    WaitingForUpdate,
    JoystickActive
} JoyStickState_t;

//static JoyStickState_t CurrentState = InitPState;
bool InitJoyStickService(uint8_t Priority);
bool PostJoyStickService(ES_Event_t ThisEvent);
ES_Event_t RunJoyStickService(ES_Event_t ThisEvent);

#endif /* ServTemplate_H */
SoftWare Components – Coin Insertion Pseudo Code
Define constants:
  ONE_SEC = 1000
  FIVE_SEC = ONE_SEC * 5

Define module-level variables:
  CurrentCoinState - to track the current state of the coin insertion process
  MyPriority - to store the priority of this service

Function: InitCoinInsertionService(Priority)
  Disable analog functionality on Port A
  Set TRIS register for RA2 as input
  Set service priority to Priority
  Set initial state to InitPCoinState
  Create an initialization event ES_COIN_INIT
  Post the event to the service queue
  Return true if successful, otherwise false

Function: PostCoinInsertionService(ThisEvent)
  Post ThisEvent to the service queue using the stored priority
  Return true if successful, otherwise false

Function: RunCoinInsertionService(ThisEvent)
  Initialize ReturnEvent as ES_NO_EVENT
  Switch(CurrentCoinState):
    Case InitPCoinState:
      If ThisEvent is ES_COIN_INIT:
        Transition to WaitForCoin1 state
        Print "Coin: 0 / 2" to console or display
    Case WaitForCoin1:
      If ThisEvent is ES_COININPUT:
        Start DebouncingTimer for 0.2 seconds
        Start CoinPendingTimer for 5 seconds
      Else if ThisEvent is ES_TIMEOUT from DebouncingTimer:
        Transition to WaitForCoin2 state
        Print "Coin: 1 / 2" to console or display
      Else if ThisEvent is ES_TIMEOUT from CoinPendingTimer:
        Print "Coin: 0 / 2" to console or display
    Case WaitForCoin2:
      If ThisEvent is ES_COININPUT:
        Print "Coin: 2 / 2. Game Start!" to console or display
        Create an ES_GAME_START event with the current time
        Post the event to all services
        Transition to GameInProgress state
      Else if ThisEvent is ES_TIMEOUT from CoinPendingTimer:
        Transition to WaitForCoin1 state
        Print "Coin: 0 / 2" to console or display
    Case GameInProgress:
      If ThisEvent is ES_GAME_OVER:
        Transition to WaitForCoin1 state
        Print "Game Finished. Coin: 0 / 2" to console or display
    Default:
      Do nothing
  Return ReturnEvent

Function: QueryCoinInsertionService()
  Return the current state (CurrentCoinState)
SoftWare Components – Coin Insertion Source Code
/****************************************************************************
 Module
   CoinInsertionService.c

 Description
   Implements a flat state machine for handling coin insertion events using 
   the Gen2 Events and Services Framework.

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

/*----------------------------- Include Files -----------------------------*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "CoinInsertionService.h"

/*----------------------------- Module Defines ----------------------------*/
#define ONE_SEC 1000
#define FIVE_SEC (ONE_SEC * 5)

/*---------------------------- Module Variables ---------------------------*/
static CoinState_t CurrentCoinState;
static uint8_t MyPriority;

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

/****************************************************************************
 Function
     InitCoinInsertionService

 Parameters
     uint8_t Priority - the priority of this service

 Returns
     bool - true if successful, false otherwise

 Description
     Initializes the coin insertion service, setting the initial state and
     posting an initialization event.
****************************************************************************/
bool InitCoinInsertionService(uint8_t Priority)
{
    ANSELA = 0;  // Disable analog on Port A
    TRISAbits.TRISA2 = 1;

    MyPriority = Priority;
    CurrentCoinState = InitPCoinState;

    ES_Event_t ThisEvent = { .EventType = ES_COIN_INIT };
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     PostCoinInsertionService

 Parameters
     ES_Event_t ThisEvent - the event to post

 Returns
     bool - true if successful, false otherwise

 Description
     Posts an event to this service's queue.
****************************************************************************/
bool PostCoinInsertionService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     RunCoinInsertionService

 Parameters
     ES_Event_t ThisEvent - the event to process

 Returns
     ES_Event_t - ES_NO_EVENT if no errors, otherwise an error event

 Description
     Runs the state machine for handling coin insertion events.
****************************************************************************/
ES_Event_t RunCoinInsertionService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent = { .EventType = ES_NO_EVENT };

    switch (CurrentCoinState)
    {
        case InitPCoinState:
            if (ThisEvent.EventType == ES_COIN_INIT)
            {
                CurrentCoinState = WaitForCoin1;
                DB_printf("Coin: 0 / 2\n");
                // TODO: Send "Coin: 0/2" to display
            }
            break;

        case WaitForCoin1:
            if (ThisEvent.EventType == ES_COININPUT)
            {
                ES_Timer_InitTimer(DebouncingTimer, ONE_SEC * 0.2);
                ES_Timer_InitTimer(CoinPendingTimer, FIVE_SEC);
            }
            else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == DebouncingTimer)
            {
                CurrentCoinState = WaitForCoin2;
                DB_printf("Coin: 1 / 2\n");
                // TODO: Send "Coin: 1/2" to display
            }
            else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == CoinPendingTimer)
            {
                DB_printf("Coin: 0 / 2\n");
                // TODO: Send "Coin: 0/2" to display
            }
            break;

        case WaitForCoin2:
            if (ThisEvent.EventType == ES_COININPUT)
            {
                DB_printf("Coin: 2 / 2. Game Start!\n");
                // TODO: Send "Coin: 2/2" or a welcome message to display

                ES_Event_t GameStartEvent = { .EventType = ES_GAME_START, .EventParam = ES_Timer_GetTime() };
                ES_PostAll(GameStartEvent);

                CurrentCoinState = GameInProgress;
            }
            else if (ThisEvent.EventType == ES_TIMEOUT && ThisEvent.EventParam == CoinPendingTimer)
            {
                CurrentCoinState = WaitForCoin1;
                DB_printf("Coin: 0 / 2\n");
                // TODO: Send "Coin: 0/2" to display
            }
            break;

        case GameInProgress:
            if (ThisEvent.EventType == ES_GAME_OVER)
            {
                CurrentCoinState = WaitForCoin1;
                DB_printf("Game Finished. Coin: 0 / 2\n");
                // TODO: Send "Coin: 0/2" to display
            }
            break;

        default:
            break;
    }

    return ReturnEvent;
}

/****************************************************************************
 Function
     QueryCoinInsertionService

 Parameters
     None

 Returns
     CoinState_t - the current state of the coin insertion state machine

 Description
     Returns the current state of the coin insertion state machine.
****************************************************************************/
CoinState_t QueryCoinInsertionService(void)
{
    return CurrentCoinState;
}
SoftWare Components – Coin Insertion Header File
/****************************************************************************

  Header file for template Flat Sate Machine
  based on the Gen2 Events and Services Framework

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

#ifndef COINSERVICE_H
#define COINSERVICE_H_H

// Event Definitions
#include "ES_Configure.h" /* gets us event definitions */
#include "ES_Types.h"     /* gets bool type for returns */

#include <stdint.h>
#include <stdbool.h>
#include "ES_Events.h"
#include "ES_Port.h"                // needed for definition of REENTRANT
#include "PIC32_SPI_HAL.h"
#include "DM_Display.h"

#define COIN12 10

// typedefs for the states
// State definitions for use with the query function
typedef enum
{
  InitPCoinState, WaitForCoin1, WaitForCoin2,
  GameInProgress
}CoinState_t;

// Public Function Prototypes

bool InitCoinInsertionService(uint8_t Priority);
bool PostCoinInsertionService(ES_Event_t ThisEvent);
ES_Event_t RunCoinInsertionService(ES_Event_t ThisEvent);
CoinState_t QueryCoinInsertionService(void);

#endif /* FSMTemplate_H */
SoftWare Components – Autoscrolling Pseudo Code
Initialize global variables:
  - `MyPriority`: Priority of the service.
  - `idx`: Index for scrolling text (default: 0).
  - `str`: String to display ("STANFORD ").
  - `strlen`: Length of the string.

---

Function: InitAutoScrollingService(Priority)
  - Save `Priority` to `MyPriority`.
  - Post an `ES_INIT_AUTOLED` event to the service queue.
  - Return true if the event is posted successfully, false otherwise.

---

Function: PostAutoScrollingService(Event)
  - Post `Event` to the service queue.
  - Return true if the event is posted successfully, false otherwise.

---

Function: RunAutoScrollingService(Event)
  - Initialize `ReturnEvent` as `ES_NO_EVENT`.

  Switch (Event.Type):
    Case `ES_INIT_AUTOLED`:
      - Start a timer (`SERVICE2_TIMER`) for HALF_SEC.
      - Print initialization message.

    Case `ES_TIMEOUT`:
      If `Event.Param` is `SERVICE2_TIMER`:
        - Check if the end of the string is reached:
          If yes, reset `idx` to 0.
        - Restart the timer with HALF_SEC duration.
        - Create a new event (`ES_NEW_CHAR2PRINT`) with the next character in the string.
        - Post the event to `MyLEDService`.
        - Print the scrolling text.
      - If `QueryMyCenteredLEDService()` returns `CountDown`:
        - Stop the timer.

    Case `ES_GAME_START`:
      - Stop the timer.
      - Print message indicating scrolling is stopped for the game.

    Case `ES_GAME_OVER`:
      - Reset `idx` to 0.
      - Post an `ES_INIT_AUTOLED` event to restart scrolling.

    Default:
      - Do nothing.

  Return `ReturnEvent`.
SoftWare Components – Autoscrolling Source Code
/****************************************************************************
 Module
   AutoScrollingService.c

 Description
   Service for managing auto-scrolling text on an LED display.

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

/*----------------------------- Include Files -----------------------------*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "MyLEDService.h"
#include "AutoScrollingService.h"
#include "MyCenteredLEDService.h"
#include "DM_Display.h"

/*----------------------------- Module Defines ----------------------------*/
#define ONE_SEC 1000
#define HALF_SEC (ONE_SEC / 2)

/*---------------------------- Module Variables ---------------------------*/
static uint8_t MyPriority;
static uint8_t idx = 0;
static char str[] = "STANFORD ";
static uint8_t strlen = sizeof(str);

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

/****************************************************************************
 Function
     InitAutoScrollingService

 Parameters
     uint8_t Priority - Priority of this service.

 Returns
     bool - true if initialization is successful, false otherwise.

 Description
     Initializes the service and posts the initial transition event.
****************************************************************************/
bool InitAutoScrollingService(uint8_t Priority)
{
    MyPriority = Priority;
    ES_Event_t ThisEvent = { .EventType = ES_INIT_AUTOLED };

    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     PostAutoScrollingService

 Parameters
     ES_Event_t ThisEvent - Event to post to the queue.

 Returns
     bool - true if the event was posted successfully, false otherwise.

 Description
     Posts an event to this service's queue.
****************************************************************************/
bool PostAutoScrollingService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
    RunAutoScrollingService

 Parameters
   ES_Event_t ThisEvent - Event to process.

 Returns
   ES_Event_t - ES_NO_EVENT if no errors, otherwise another event.

 Description
   Handles events to manage auto-scrolling text and coordinates with other services.
****************************************************************************/
ES_Event_t RunAutoScrollingService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent = { .EventType = ES_NO_EVENT };

    switch (ThisEvent.EventType)
    {
        case ES_INIT_AUTOLED:
            ES_Timer_InitTimer(SERVICE2_TIMER, HALF_SEC);
            printf("AutoScrollingService Initialized.\n");
            break;

        case ES_TIMEOUT:
            if (ThisEvent.EventParam == SERVICE2_TIMER)
            {
                if (idx == strlen - 1)
                {
                    idx = 0;
                }

                ES_Timer_InitTimer(SERVICE2_TIMER, HALF_SEC);
                ES_Event_t NextCharEvent = { .EventType = ES_NEW_CHAR2PRINT, .EventParam = str[idx++] };
                PostMyLEDService(NextCharEvent);
                printf("Scrolling text: %s\n", str);
            }

            if (QueryMyCenteredLEDService() == CountDown)
            {
                ES_Timer_StopTimer(SERVICE2_TIMER);
            }
            break;

        case ES_GAME_START:
            ES_Timer_StopTimer(SERVICE2_TIMER);
            printf("Scrolling stopped for game start.\n");
            break;

        case ES_GAME_OVER:
            idx = 0;
            ES_Event_t RestartEvent = { .EventType = ES_INIT_AUTOLED };
            PostAutoScrollingService(RestartEvent);
            break;

        default:
            break;
    }

    return ReturnEvent;
}
SoftWare Components – Autoscrolling Header File
/****************************************************************************
 Module
     EventCheckers.h
 Description
     header file for the event checking functions
 Notes

 History
 When           Who     What/Why
 -------------- ---     --------
 10/18/15 11:50 jec      added #include for stdint & stdbool
 08/06/13 14:37 jec      started coding
*****************************************************************************/

#ifndef EventCheckers_H
#define EventCheckers_H

// the common headers for C99 types
#include <stdint.h>
#include <stdbool.h>

// prototypes for event checkers

bool Check4Keystroke(void);
bool CheckForJoystickSignal(void);
bool Check4IRRiseFall(void);
bool Check4Switch1(void);
bool Check4Switch2(void);
#endif /* EventCheckers_H */
SoftWare Components – MOtor Service Pseudo Code
### Motor Service Pseudo Code

1. **Initialization (InitMotorService)**:
   - Set priority and initial state (`InitMotorState`).
   - Configure PWM on RB3 for motor control:
       - Set RB3 as digital output.
       - Initialize PWM library and map to Timer2.
       - Set PWM frequency to 50 Hz.
   - Initialize PWM duty cycle to 0%.
   - Post an `ES_MOTOR_INIT` event to signal readiness.

2. **Posting Events (PostMotorService)**:
   - Post incoming events to the Motor Service queue.

3. **Run State Machine (RunMotorService)**:
   - Handle events based on the current state:
     - **InitMotorState**:
       - On `ES_MOTOR_INIT`, transition to `MotorActiveState`.
       - On `ES_GAME_START`, start a 6-second timer for motor operation.
       - On `ES_TIMEOUT`, transition to `MotorActiveState`.
     - **MotorActiveState**:
       - On `ES_MOTOR_WORKING`, process joystick value:
         - Clamp value between 0 and 1024.
         - Map to a duty cycle percentage (0-100%).
         - Set PWM duty cycle.
       - On `ES_TIMEUP`:
         - Stop motor by setting PWM duty cycle to 0%.
         - Post `ES_MOTOR_TERMINATE` event to `CountdownService`.
         - Reset to `InitMotorState`.

4. **Query Current State (QueryMotorService)**:
   - Return the current state of the Motor Service.
SoftWare Components – MOtor Service Source Code
/****************************************************************************
 Module
   MotorService.c

 Description
   Service for controlling motor operations using PWM and handling state 
   transitions based on events, adhering to the Gen2 Events and Services Framework.

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

/*----------------------------- Include Files -----------------------------*/
#include "MotorService.h"
#include <xc.h>
#include "DM_Display.h"
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "PWM_PIC32.h"

/*----------------------------- Module Defines ----------------------------*/
#define ONE_SEC 1000

/*---------------------------- Module Variables ---------------------------*/
static MotorState_t CurrentMotorState;  // Current state of the Motor Service
static uint8_t MyPriority;             // Priority of this service

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

/****************************************************************************
 Function
     InitMotorService

 Parameters
     uint8_t Priority - the service priority level to be assigned

 Returns
     bool - true if initialization succeeds, false otherwise

 Description
     Initializes the motor service, sets up PWM configurations, and posts 
     an initial event to indicate readiness.
****************************************************************************/
bool InitMotorService(uint8_t Priority)
{
    MyPriority = Priority;
    puts("Initiating Motor Service...\r\n");

    // Configure RB3 as digital output for PWM
    TRISBbits.TRISB3 = 0;  // Set RB3 as output
    ANSELBbits.ANSB3 = 0;  // Set RB3 as digital
    CurrentMotorState = InitMotorState;

    // Initialize the PWM library
    if (!PWMSetup_BasicConfig(1) ||
        !PWMSetup_AssignChannelToTimer(1, _Timer2_) ||
        !PWMSetup_SetFreqOnTimer(50, _Timer2_) ||
        !PWMSetup_MapChannelToOutputPin(1, PWM_RPB3))
    {
        puts("PWM initialization failed\r\n");
        return false;
    }

    // Set initial PWM duty cycle to 0%
    PWMOperate_SetDutyOnChannel(0, 1);

    // Post the initial motor initialization event
    ES_Event_t ThisEvent = { .EventType = ES_MOTOR_INIT };
    if (ES_PostToService(MyPriority, ThisEvent))
    {
        puts("Motor Service initialized successfully!\r\n");
        return true;
    }
    return false;
}

/****************************************************************************
 Function
     PostMotorService

 Parameters
     ES_Event_t ThisEvent - The event to post to the queue

 Returns
     bool - true if the event was successfully posted, false otherwise

 Description
     Posts an event to the Motor Service's queue.
****************************************************************************/
bool PostMotorService(ES_Event_t ThisEvent)
{
    return ES_PostToService(MyPriority, ThisEvent);
}

/****************************************************************************
 Function
     RunMotorService

 Parameters
     ES_Event_t ThisEvent - The event to process

 Returns
     ES_Event_t - ES_NO_EVENT if no errors, otherwise another event

 Description
     Processes events and updates the state machine for the Motor Service.
****************************************************************************/
ES_Event_t RunMotorService(ES_Event_t ThisEvent)
{
    ES_Event_t ReturnEvent = { .EventType = ES_NO_EVENT };

    switch (CurrentMotorState)
    {
        case InitMotorState:
            if (ThisEvent.EventType == ES_MOTOR_INIT)
            {
                puts("Motor Service Initialized\r\n");
                CurrentMotorState = MotorActiveState;
            }
            else if (ThisEvent.EventType == ES_GAME_START)
            {
                DB_printf("Motor Start!\n");
                ES_Timer_InitTimer(MOTOR_TIMER, ONE_SEC * 6);
            }
            else if (ThisEvent.EventType == ES_TIMEOUT)
            {
                DB_printf("Motor Timeout Received!\n");
                CurrentMotorState = MotorActiveState;
            }
            break;

        case MotorActiveState:
            if (ThisEvent.EventType == ES_MOTOR_WORKING)
            {
                uint16_t joystickValue = ThisEvent.EventParam;

                // Clamp joystick value to maximum range
                if (joystickValue > 1024)
                {
                    joystickValue = 1024;
                }

                // Map joystick value (0-1024) to duty cycle (0-100%)
                uint8_t dutyCycle = ((1024 - joystickValue) * 100) / 1024;
                printf("Setting PWM Duty Cycle: %d%%\r\n", dutyCycle);

                // Set the duty cycle on PWM Channel 1
                if (!PWMOperate_SetDutyOnChannel(dutyCycle, 1))
                {
                    puts("Failed to set PWM duty cycle\r\n");
                }
            }
            else if (ThisEvent.EventType == ES_TIMEUP)
            {
                PWMOperate_SetDutyOnChannel(0, 1);

                // Post motor termination event
                ES_Event_t NewEvent = { .EventType = ES_MOTOR_TERMINATE, .EventParam = ES_Timer_GetTime() };
                DB_printf("### Motor Service Terminated ###\n");
                PostCountdownService(NewEvent);

                CurrentMotorState = InitMotorState;
            }
            break;

        default:
            puts("Unknown Motor State\r\n");
            break;
    }

    return ReturnEvent;
}

/****************************************************************************
 Function
     QueryMotorService

 Parameters
     None

 Returns
     MotorState_t - the current state of the Motor Service

 Description
     Returns the current state of the Motor Service.
****************************************************************************/
MotorState_t QueryMotorService(void)
{
    return CurrentMotorState;
}
SoftWare Components – MOtor Service Header File
/****************************************************************************

  Header file for Test Harness Service0
  based on the Gen 2 Events and Services Framework

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

#ifndef MyMotorService_H
#define MyMotorService_H

#include <stdint.h>
#include <stdbool.h>
#include "ES_Events.h"
#include "ES_Port.h"                // needed for definition of REENTRANT
#include "PIC32_SPI_HAL.h"
#include "DM_Display.h"


// Public Function Prototypes
typedef enum {
    InitMotorState,
    MotorActiveState
} MotorState_t;

bool InitMotorService(uint8_t Priority);
bool PostMotorService(ES_Event_t ThisEvent);
ES_Event_t RunMotorService(ES_Event_t ThisEvent);
MotorState_t QueryMotorService(void);

#endif /* ServTemplate_H */