User Tools

Site Tools


lab_6

Simon Lab

Overview

In this lab you will create the ECEN 330 version of the electronic Simon game. Electronic Simon, as you probably recall, is a game where the computer plays a sequence to you and you attempt to re-key in the sequence correctly. Correct attempts allow you to go on to attempt longer sequences. Electronic versions of Simon often combine colored lights with sound. For our lab, we will use the LCD/touch-pad to generate colored squares that the user will attempt to touch in the correct sequence (we won't use sound).

This lab will be implemented using four concurrent, synchronous state machines. As before, I will stipulate the file-names, function-names, and so forth to expose you to at least one good way to implement the game.

Objectives

  1. Learn how to implement a complex game using concurrent, synchronous state machines (new stuff).
  2. Learn effective ways to communicate between concurrent state machines (new stuff).
  3. Learn how state machines can be controlled by other state machines (new stuff).
  4. Learn how to handle global variables with functions (new stuff).
  5. Learn how to interlock state machines (new stuff).
  6. More practice programming in 'C'.
  7. More practice with the coding standard.

Simon Implementation Strategy

Simon is much more complex than Tic-Tac-Toe, so we need to look at how the game is played in detail so we can come up with good implementation strategies. Our Simon game, as shown in the video above, will use four colored regions on the LCD. The colored sequence will be shown using these colored regions and the user will attempt to follow the computer's sequence by touching the right sequence of colored regions.

Here is the organizational strategy that we will use:

  • Provide a set of display functions to draw the colored regions implemented in: simonDisplay.h/simonDisplay.c:
  • Use a buttonHandler state machine to handle drawing buttons and for detecting touches and time-outs.
  • Use a flashSequence state machine to flash the sequence that the user must attempt to mimic.
  • Use a verifySequence state machine to verify that the sequence of user touches matches the computer-generated sequence.
  • Use a simonControl state machine to control everything at the top level.

Milestones

You will complete this lab in three milestones:

  • Milestone 1: Implement the buttonHandler state machine and simonDisplay code. You pass off this milestone by demonstrating that your code works properly with the provided buttonHandler_runTest() code (it should look like the provided video). Also implement the globals code.
  • Milestone 2: Implement the flashSequence and verifySequence state machines. Demonstrate that these work properly by showing the TAs that your code models the behavior shown in the relevant video.
  • Milestone 3: Implement the top-level simonControl state machine so that you implement a Simon game with the the same behavior as shown in the demo video for the Simon game. Pass off your game to the TAs.

The figure below shows the “architecture” for the Simon game and shows how the state machines communicate with each other.

System Organization

The figure below shows the “architecture” of the Simon game. Starting at the far left, the simonControl state machine coordinates the operation of the other state machines to implement the Simon game. The simonControl state machine uses flashSequence()_enable() and flashSequence_disable() to control when the flashSequence state machine displays the color sequence to the user. simonControl then activates the verifySequence state machine to verify that the user correctly taps the color sequence. The related verifySequence_enable() and verifySequence_disable() functions are used to enable and disable the verifySequence state machine. The verifySequence state machine controls the buttonHandler state machine (again using buttonHandler_enable()/buttonHandler_disable() functions) to determine which colors the user has touched. All of the state machines use functions provided by either simonDisplay.h or display.h to interact with the LCD display/touch pad. Note that some of the function names have been abbreviated in the figure. Also, the figure does not show interactions between the state machines and global variables. This is discussed later in this document.

Controlling State Machines with Interlocks

You will need to use “interlocks” to control when state machines can start up. You need to use an interlock to prevent the state machine from “racing” through to a new state when you may not be ready. Using the flashSequence state machine as an example, you use flashSequence_enable() to start the machine. You can find out when it has finished “flashing the sequence” by calling flashSequence_completed(). If this function returns true, then you know that the state machine has completed its task. Next, you invoke flashSequence_disable() to turn off the state machine until you are ready to invoke it again. Invoking this function allows the flashSequence state machine to return to its initial state where it waits until you invoke flashSequence_enable() to enable the state machine to flash the next element of the sequence. Three of the state machines will require interlocks of this type: flashSequence, buttonHandler, and verifySequence. It is most effective and straightforward if you implement the interlocks in the same general way as shown in the figure below.

The interlock template as shown below will work with any state machine that requires interlocks to synchronize its operation with other state machines. As shown in the figure, assume the existence of some initial state and some final state. These states are not special states but are just the normal states that comprise your state machine. At startup, the state machine does not leave the initial state until a variable named enable is set to true (provide a _enable() function that sets an enable flag to true). Once the state machine reaches its final state, it stays in that final state until the enable variable is set to false (provide a _disable() to set the enable variable to false). If you design your state machines using this kind of interlock, you will find that it is straightforward to control them. If you don't use this enable()/disable() approach, it is difficult to keep the state machine from immediately commencing operation from the final state.

If you look closely at the flashSequence_runTest(), buttonHandler_runTest(), and verifySequence_runTest() routines, you will find that the code carefully exercises the interlock capability. Just look for the related _enable() and _disable() functions in the source code. If you study the code carefully, you will understand how these interlocks work.

There are a couple of things to keep in mind with this approach. If you are doing things that must only be done once in either the initial or final state, you may need to add additional states (one after the initial state, one before the final state), or perhaps you can meet the need with a Mealy action.


Individual Descriptions of Simon Modules with Helps and Suggestions

simonControl State Machine Code

As with other state machines, you must have a simonControl.h and a simonControl.c file. The .h file must contain at least the function prototypes of simonControl_init() and simonControl_tick(). simonControl provides the top-level control for the Simon Game and it coordinates the behavior of the other state machines to implement the Simon game. I don't provide any code for simonControl but you can watch the Simon demo video to see how things are supposed to work.


simonMain.c

This file will contain your main() function.


Requirements

  1. You must follow the coding standard.
  2. You are not allowed to use util_msDelay() in any of your code. You must implement delays using counters in your state machines.
  3. Adapt the flag-based interrupt code from the clock lab so you can use it similarly in this lab. Your game must use the flag-based interrupt approach as shown in the clock lab to call all of the tick methods of your state machines. Demonstrate correct functionality using the “interrupts_isrFlagGlobal” to know when to invoke tick functions. As before, you should not miss more than one interrupt.
  4. You can select a suitable delay for time-out and a speed for flashing the sequence.
  5. If the user selects the incorrect color or you detect a time-out, just display the longest sequence number correctly achieved (allowing enough time for the user to read the message) and go back to the starting screen (see the screen-shot below).
  6. 10% of your grade is based upon playability. To receive the entire 10% your game must work correctly with no observable bugs. Your game should be responsive and be fun to play.
  7. Source code is only graded after you completed the entire lab so it is due along with the last milestone.


Grading

  1. Milestone 1: 20%
  2. Milestone 2: 20%
  3. Milestone 3: 20%
  4. Playability: 10% - you receive this if game play is smooth, correct, responsive, no glitches, and does not allow cheating.
  5. Code Quality (adhering to the coding standard): 30%
  6. Subtract 10% from the total score if more than one interrupt is missed during game play (up to 20 missed interrupts total).
  7. Subtract 20% from the total score if more than 20 interrupts are missed during normal game play.

Submitting Source Code

Follow this procedure to submit your source code to learning-suite.

lab_6.txt · Last modified: 2019/04/10 11:41 by hutch