/****************************************************************************
Module
AudioService.c ~ PSEUDO CODE
* listens for the event ES_AUDIO_PLAY
* events should have parameters 1 (play happy noise) or 0 (play sad noise)
* pulls the audio pin low for the chip to play
* ASSUMING HAPPY ON RA3 and SAD ON RA4
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc final project
12/1/2023 mcc project report pseudo
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// include relevant header files
/*----------------------------- Module Defines ----------------------------*/
// define timer counts
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// save priority variable
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitAudioService
// Takes no parameters, returns nothing
****************************************************************************/
// init audio service function
{
// initialize priority value
// set the relevant pins as digital outputs
// set both pins high by default
// return boolean value for the framework
} // End of InitAudioService
/****************************************************************************
Function
// RunAudioService
// Takes an input event, returns errors if applicable
****************************************************************************/
// run audio function
{
// return event (local variable)
// local var ReturnValue initialized to ES_NO_EVENT
// listen for audio events
// if it's an audio event
{
// if happy audio requested
{
// set happy pin low
// timer until reset pin high
} // endif happy noise
// if sad audio requested
{
// set sad pin low
// timer until reset pin high
} // endif sad noise
// else invalid input
{
// print alert
} // end else (invalid audio)
} // endif audio event
// if timeout event
{
// set pins back to high
}
// return return value for the run function
} // end of run AudioService
/****************************************************************************
Function
// PostAudioService
// Takes no parameters, returns either a character or a '~' indicating failure
****************************************************************************/
// ^ see description
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
BeamService.c ~ PSEUDO CODE
Description
IR sensor detection
History
When Who What/Why
-------------- --- --------
11/2023 Team 11 final project 218a
12/1/2023 mcc project report
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// include relevant headers
/*----------------------------- Module Defines ----------------------------*/
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// variable for keeping track of previous beam state
// init as zero because we assume foot started outside (beam was unbroken)
/*------------------------------ Module Code ------------------------------*/
/***************************************************************************
Function
CheckBeamEvents
Parameters
None
Returns
True if event an event is posted
Description
event checker function for the IR beam
***************************************************************************/
// check beam function
{
// create boolean variable to return
// read the current state of the beam
// if the beam has changed (foot in or out)
{
// delay for noise check
// another check of beam state in case of noise
// if the beam has still changed (foot in or out)
{
// change the return boolean
// create an event to post
// if the beam is broken
{
// post a beam broken event to the SM
}
// otherwise
{
// post a beam (unbroken) event to the SM
}
}
// update the last beam state
}
// return the boolean
} // end of CheckBeamEvents
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*
/****************************************************************************
Module
DialService.c ~ PSEUDO
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc final project 218a
12/1/12023 mcc project report
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// include relevant header files
/*----------------------------- Module Defines ----------------------------*/
// define timer values
/*---------------------------- Module Functions ---------------------------*/
// event checker function prototype
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
// Data private to the module: LastDialState (array with one value)
// state machine steps
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function: InitDialService
(takes parameter priority, returns boolean when finished, does not error check)
****************************************************************************/
// init function
{
// save priority variable
// set the pin to be an input
// prepare to analog scan (AD library configure)
// use AD library to scan the pin into the variable
// send an event so the main state machine has the initial variable value
// (in case the user doesn't change the dial later)
// Set CurrentState to be waiting
// return boolean value
} // End of InitDialStatus
/****************************************************************************
Function: PostDialService (enqueues to this service)
****************************************************************************/
/****************************************************************************
Function: RunDialService
(takes an event posted to this service, returns no event assuming no errors)
****************************************************************************/
// run function
{
// create return event
// assume no errors (no event return)
// Local Variable: NextState
// Set NextState to CurrentState
// Based on the state of the CurrentState variable choose one of the following blocks of code:
{
// current state is waiting
{
// if the dial value changed
{
// start debounce rise timer
// change to dial debounce state
}
} // end of dial waiting
// current state is dial debounce
{
// if the dial changed again
{
// not done inputting - restart timer
// stay in the same state
}
// if the timer expires, assume input is done
{
// check if it's the dial timer
{
// done changing - post to main state machine with parameter of the current value
// reset for next time
} // endif checking correct timer
// else
{
// print an alert
}
}
} // end of dial debounce state
} // end of state switch
// move to next state
// return the return event
} // end Run Dial Service
/****************************************************************************
Function
// CheckDialEvents
// Takes no parameters, returns True if an event posted
// it's an event checker function
****************************************************************************/
// check events function
{
// assume no change (return boolean false)
// temporary var for storing the current dial value
// check the current pin value
// create variable for comparison between values
// if it has changed significantly enough
{
// update the return boolean
// post the event into this service to debounce
// update the last value variable (only if significantly changed)
}
// return the boolean
} // End of CheckDialEvents
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
NEW FUNCTIONS
for final project
AddProgressBar: adds a lit row to the display, according to input parameter
BordersOnly: illuminates only the outermost LEDs of the matrix
****************************************************************************/
/****************************************************************************
Function
DM_AddProgressBar
Parameters
uint8_t: which bar level are we currently at
Returns
None
Description
adds a lit row to the display, according to input parameter
****************************************************************************/
// DM_AddProgressBar
{
// initialize an appender row (0x00000001). this will be our starting point
// and what we use to bit shift left for each row
// shift left depending on which bar we are at
// append the new single LED to the each row
} // End of DM_AddProgressBar
/****************************************************************************
Function
DM_AddProgressBar
Parameters
None
Returns
None
Description
illuminates only the outermost LEDs of the matrix
****************************************************************************/
// DM_BordersOnly
{
// initialize a full top row border. all LEDs lit
// Update buffer and display with this row
// initialize partial borders. left- and right-most LEDs lit
// Update buffer and display with this row, only for the middle rows
// initialize a full bottom row border. all LEDs lit
// Update buffer and display with this row
} // End of DM_BordersOnly
/****************************************************************************
Module
FlashService.c ~ PSEUDO
* listens for the ES_FLASH event
* expects a parameter of 1-4 for which step to flash
History
When Who What/Why
-------------- --- --------
11/13/2023 mcc final project 218a
12/1/2023 mcc project report
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// include relevant header files
/*----------------------------- Module Defines ----------------------------*/
// define timer units
/*---------------------------- Module Functions ---------------------------*/
// helper function prototype for blinking
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
// state machine steps
// which step (LED) are we changing this time
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitFlash
// Takes no parameters, returns nothing
****************************************************************************/
// init function
{
// save the priority variable
// start in the first off state (on0)
// return boolean value
} // End of Init Flash
/****************************************************************************
Function: PostFlash (enqueues to this service)
****************************************************************************/
/****************************************************************************
Function: RunFlash (state machine that turns the specified light on and off)
****************************************************************************/
// run function
{
// return event local variable
// assume no errors (init as no event)
// Local Variables: NextState
// Set NextState to CurrentState
// check if we've got a flash event
{
// if flash LED event
{
// take the event parameter to select which LED to mess with
// if it's an invalid number, print an alert
} // end case flash event
// flash off event
{
// turn all the LEDs off
// stop the timer
// reset to first state
// update the state
} // end case flash off
// timeout event
{
// Based on the state of the CurrentState variable choose one of the following blocks of code:
{
// current state is LED is on
{
// restart the timer
// turn the LED off
// Set NextState to LED off
}
// current state is LED is off 1
{
// restart the timer
// turn the LED on
// Set NextState to LED on 1
}
// current state is LED is on 1
{
// restart the timer
// turn the LED off
// Set NextState to LED off 2
}
// current state is LED is off 2
{
// restart the timer
// turn the LED on
// Set NextState to LED on 2
}
// current state is LED is on 2
{
// restart the timer
// turn the LED off
// Set NextState to LED off 3
}
// current state is LED is off 3
{
// restart the timer
// turn the LED on
// Set NextState to LED on 3
}
// current state is LED is on 3
{
// DO NOT INIT THE TIMER (end of blink pattern)
// turn the LED on (and leave it on)
// cycle back to the beginning (on0) for next call
}
} // end case switch
// update state
} // end of if timeout case
} // end event type switch
} // end Run Flash
/****************************************************************************
Helper Function: BlinkerFunction (turns the indicated LED on or off)
****************************************************************************/
// blinker function
{
// if the WhichLED number is valid, latch the corresponding pin to the setting value (0 or 1)
// else print an error alert
}
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
GoButtonService.c ~ PSEUDO
* scans the go button for user input
* if a button is pressed, sends ES_BUTTON_DOWN
* parameter of 'g' for go
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc final project
12/1/2023 mcc project report
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// inlcude relevant header files
/*----------------------------- Module Defines ----------------------------*/
// define timer units
// define bounce time
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
// previous button states
// state machine steps
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitGoButton
// Takes no parameters, returns nothing
****************************************************************************/
// init function
{
// from template, save the priority variable
// set the buttons pin to be input
// sample the pin and assign original value
// Set CurrentState to be waiting
// return boolean value
} // End of InitGoButton
/****************************************************************************
Function: PostGoButton (enqueues to this service)
****************************************************************************/
/****************************************************************************
Function: RunGoButton (state machine that debounces the button signals)
****************************************************************************/
// run function
{
// return event local var
// assume no errors
// Local Variables: NextState
// Set NextState to CurrentState
// Based on the state of the CurrentState variable choose one of the following blocks of code:
{
// current state is waiting
{
// if a rise was detected
{
// start debounce rise timer
// Set NextState to DebouncingRise
}
// if a fall was detected
{
// start debounce fall timer
// Set NextState to DebouncingRise
}
} // end of waiting state
// current state is debouncing fall
{
// if a rise was detected
{
// it was bouncy, reset to waiting
}
// if timeout event
{
// it was a real button press, post about it to SM
// parameter g for go
// reset to waiting for next button press
}
} // end of debouncing fall state
// current state is debouncing rise
{
// if a fall was detected
{
// it was bouncy, reset to waiting
}
// if a timeout was detected
{
// it was a real button press, post about it to the SM
// parameter g for go
// reset to waiting for next button press
}
} // end of debouncing rise state
} // end case switch
// update the state machine state
} // end Run Go Button
/****************************************************************************
Function: CheckGoButton (event checker listening for changes in the buttons)
****************************************************************************/
// check button function
{
// local variables to return/post
// sample the current button state and store in temporary var
// if the go button has changed
{
// update the return variable
// if the button line is high
{
// post about the rise to this service
}
// else (button line is low)
{
// post about the fall to this service
}
// overwrite the previous button values
}
// return the boolean
} // End of CheckGoButton
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
LEDStepService.c ~ PSEUDO
* listens for the events ES_STEP1, ES_STEP2, ES_STEP3, ES_STEP4
* events should have paraemters 1 (on) or 0 (off)
* turns on/off the corresponding LEDs by writing the pins high/low
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc 218a final project
12/1/2023 mcc project report
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// include relevant header files
/*----------------------------- Module Defines ----------------------------*/
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitLEDStep
// Takes no parameters, returns nothing
****************************************************************************/
// init function
{
// save the priority variable
// set the relevant pins as digital outputs
// start them out off (latch zero)
// return boolean value
} // End of InitLEDStep
/****************************************************************************
Function
// RunLEDStep (takes event posted here, returns no event, assuming no errors)
****************************************************************************/
// run function
{
// return event for the framework
// event to post if there are errors
// assume no errors
// Based on the state of the ThisEvent variable switch
{
// if we're changing step 1's LED
{
// if turning LED on
{
// set pin high
} // endif
// if turning LED off
{
// set pin low
} // endif
// else invalid input
{
// print error alert
}
} // endif step 1
// ^^ same procedure for LEDs 2, 3, and 4
} // end of event switch
// return return event for the framework
} // end of run LED Step
/****************************************************************************
Function
// PostLEDStep
// Takes no parameters, returns either a character or a '~' indicating failure
****************************************************************************/
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
MatrixService.c ~ PSEUDO
Description
The matrix service controls the LED dot matrix
Notes
History
When Who What/Why
-------------- --- --------
(adapted from template)
11-2023 Team 11 218a final project
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// include relevant header files
/*----------------------------- Module Defines ----------------------------*/
// none
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// current state machine state
// with the introduction of Gen2, we need a module level Priority var as well
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitMatrixService
Parameters
uint8_t : the priorty of this service
Returns
bool, false if error in initialization, true otherwise
Description
saves priority, enters initial state machine state
****************************************************************************/
// InitMatrixService
{
// local variable for event posting
// save priority variable
// CurrentState is INIT_MATRIX
// post the initial transition event
// if the initial transition event is posted
{
// return true
}
// else (if event not posted)
{
// return false
}
} // End of InitMatrixService
/****************************************************************************
Function
PostMatrixService
Parameters
EF_Event_t ThisEvent , the event to post to the queue
Returns
boolean False if the Enqueue operation failed, True otherwise
Description
Posts an event to this state machine's queue
****************************************************************************/
// ^ see description
/****************************************************************************
Function
RunMatrixService
Parameters
ES_Event_t : the event to process
Returns
ES_Event_t, ES_NO_EVENT if no error ES_ERROR otherwise
Description
implements the state machine for the LED matrix
****************************************************************************/
// RunMatrixService
{
// local variable for event posting
// assume no errors
// keep track of bar count, start at 1
// local variable for the next state
// Based on the state of the CurrentState variable choose one of the following blocks of code:
{
// CurrentState is INIT_MATRIX
{
// if ThisEvent.EventType is ES_Init
{
// disable analog on all SPI pins
// stop and reset SPI by clearing ON
// set leader
// map SDO, SCK, SS pins
// map SDI pin (skip, no input)
// clear and receive buffer (skip)
// clear ENHBUF or set bit with ENHBUF
// set BRG
// clear SPIROV bit (skip)
// set MSTEN, CKE, CKP, MSSEN, FRMPOL
// enable SPI by setting ON
// initialize LED board
// start with empty bar with borders only
// done initializing, update CurrentState to IDLE_MATRIX
} // end of ES_Init event
} // end of INIT_MATRIX state
// CurrentState is IDLE_MATRIX
{
// Based on the type of the ThisEvent.EventType variable choose one of the following blocks of code:
{
// ThisEvent.EventType is ES_MATRIX_ADD_BAR
{
// add a bar to the matrix
// if all bars have been added
{
// reset bar count for next cycle
}
else
{
// move onto next bar by adding 1 to bar count
}
// update NextState to UPDATING_MATRIX
// post a ES_MATRIX_UPDATE_ROW event to MatrixService
} // end of ES_MATRIX_ADD_BAR event
// ThisEvent.EventType is ES_MATRIX_RESET
{
// reset matrix to just the borders
// reset bar count for next cycle
// update NextState to IDLE_MATRIX
} // end of ES_MATRIX_RESET event
} // end event switch
} // end idle matrix state
// CurrentState is UPDATING_MATRIX
{
// Based on the type of the ThisEvent.EventType variable choose one of the following blocks of code:
{
// ThisEvent.EventType is ES_MATRIX_UPDATE_ROW
{
// if matrix is done updating
{
// update NextState to IDLE_MATRIX
}
// if not done, keep on updating
{
// post a ES_MATRIX_UPDATE_ROW event
// update NextState to UPDATING_MATRIX
}
} // end of ES_MATRIX_UPDATE_ROW
// ThisEvent.EventType is ES_MATRIX_RESET
{
// reset matrix to just the borders
// reset bar count for next cycle
// update NextState to IDLE_MATRIX
} // end of ES_MATRIX_RESET event
} // end switch on event type
} // end UPDATING case
} // end switch on current state
// Set CurrentState to NextState
// return the event
} // end RunMatrixService
/****************************************************************************
Function
QueryMatrixService (adapted from QueryTemplateSM)
Parameters
None
Returns
TemplateState_t The current state of the Template state machine
Description
returns the current state of the Template state machine
****************************************************************************/
// ^ see description
/****************************************************************************
Module
MotorService.c ~ PSEUDO
Description
This service implements the state machine for the motors.
History
11-2023, Team 11, final project 218a
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// include relevant header files
/*----------------------------- Module Defines ----------------------------*/
// none
/*---------------------------- Module Functions ---------------------------*/
// none
/*---------------------------- Module Variables ---------------------------*/
// current state machine state
// with the introduction of Gen2, we need a module level Priority var as well
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitMotorService (adapted from InitTemplateFSM)
Parameters
uint8_t : the priorty of this service
Returns
bool, false if error in initialization, true otherwise
Description
Saves away the priority, sets up the initial transition and does any
other required initialization for this state machine
****************************************************************************/
// InitMotorService
{
// local variable for event posting
// save priority variable
// put us into the Initial PseudoState
// post the initial transition event
// if the initial transition event is posted
{
// return true
}
// else (if event not posted)
{
// return false
}
} // End of InitMotorService
/****************************************************************************
Function
PostMotorService
Parameters
EF_Event_t ThisEvent , the event to post to the queue
Returns
boolean False if the Enqueue operation failed, True otherwise
Description
Posts an event to this state machine's queue
****************************************************************************/
// ^ see description
/****************************************************************************
Function
RunMotorService
Parameters
ES_Event_t : the event to process
Returns
ES_Event_t, ES_NO_EVENT if no error ES_ERROR otherwise
Description
motor can be set to IDLE or SPINNING
****************************************************************************/
// RunMotorService
{
// local variable for event posting
// assume no errors
// Based on the state of the CurrentState variable choose one of the following blocks of code:
{
// CurrentState is INITMOTOR
{
// Based on the type of the ThisEvent.EventType variable choose one of the following blocks of code:
{
// ThisEvent.EventType is ES_INIT
{
// set pin RB11 to be output for both motors
// clear analog inputs
// configure 2 PWM outputs
// assign the channels to the timers
// set period of 50000, assuming 0.4 us per tick
// set period on timer
// map PWM output pins
// motors initialized to stop (0 pulse width)
// done initializing, put the machine into the IDLE state
} // end ES_INIT event
} // end event switch
} // end InitMotor state
// CurrentState is IDLE
{
// Based on the type of the ThisEvent.EventType variable choose one of the following blocks of code:
{
// ThisEvent.EventType is ES_MOTOR_START
{
// initialize DialValue from ThisEvent.EventParam
// initialize MaxDialValue to 1023
// find the duty cycle percentage from DialValue and MaxDialValue
// send command to motors to start using the duty cycle percentage
// update state to spinning
} // end ES_MOTOR_START event
// ThisEvent.EventType is ES_MOTOR_STOP
{
// stop (zero duty cycle)
// set the state to idle
} // end ES_MOTOR_STOP event
} // end event switch
} // end idle state
// CurrentState is SPINNING
{
// Based on the type of the ThisEvent.EventType variable choose one of the following blocks of code:
{
// ThisEvent.EventType is ES_MOTOR_START
{
// do nothing
} // end ES_MOTOR_START event
// ThisEvent.EventType is ES_MOTOR_STOP
{
// stop (zero duty cycle)
// set the state to idle
} // end ES_MOTOR_STOP event
} // end event switch
} // end spinning state
}
// return event for the framework
} // End of RunMotorService
/****************************************************************************
Function
QueryMotorService
Parameters
None
Returns
MotorState_t The current state of the Motor state machine
Description
returns the current state of the Motor state machine
****************************************************************************/
// ^ see description
/****************************************************************************
Module
MSC_SM.c (mobile shoe cleaner state machine) ~ PSEUDO
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc 218 final project
12/1/2023 mcc project report
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// include relvant header files
/*----------------------------- Module Defines ----------------------------*/
// define timer units
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority var
// state machine states
// keeping track of the dial value (static var)
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function: InitializeMSC_SM
Takes a priority number, returns True.
****************************************************************************/
// init function
{
// local var: event to post
// Print statement for monitoring (clear the screen)
// Initialize the MyPriority variable with the passed in parameter.
// Set CurrentState to be InitMSC_SM
// Post Event ES_Init to this service
// turn all LEDS off
// post the initialization event
// End of InitializeMSC_SM
}
/****************************************************************************
Function
PostMSC_SM
Parameters
ES_Event ThisEvent ,the event to post to the queue
Returns
bool false if the Enqueue operation failed, true otherwise
Description
Posts an event to this state machine's queue
****************************************************************************/
// see framework example
/****************************************************************************
Function
RunMSC_SM
Parameters
ES_Event : the event to process
Returns
ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise
****************************************************************************/
// run function
{
// return event for the framework
// assume no errors (return no event)
// Local Variables: NextState
// Set NextState to CurrentState
// Based on the state of the CurrentState variable choose one of the following blocks of code:
{
// CurrentState is initialization
{
// If ThisEvent is ES_Init
{
// turn on step 1 LED
// play the happy noise
// check if shoe already in
// read the current state of the beam
// if the beam is broken
{
// post a beam broken event to this SM
}
// init timer for 20s
// Set NextState to Welcome
} // Endif
} // End init state block
// CurrentState is welcome
{
// switch bassed on event type
{
// a button was pressed
{
// play sad noise
// flash step 1
// init timer for 20s
// stay in the same state
} // endif button pressed
// If ThisEvent is timeout
{
// play sad noise
// blink the step to remind
// init timer for 20s
// stay in the same state
} // endif timeout
// If ThisEvent is beam broken
{
// play happy noise
// turn LED 1 off and turn LED 2 on
// init timer
// Set NextState to WaitForSpeed
} // endif beam broken event
// user turned the dial
{
// init timer for 20s
// overrwite dial value static variable
// stay in same state
} // endif dial event
} // end of event type switch
} // End welcome state block
// CurrentState is WaitForSpeed
{
// switch on event type
{
// If ThisEvent is timeout
{
// play sad noise
// flash step 2
// init timer for 20s
// stay in the same state
} // endif timeout event
// if a button was pressed
{
// if it was the go button
{
// play sad noise
// flash step 2
// init timer for 20s
// stay in the same state
}
// if it was the speed button
{
// play happy noise
// turn LED 2 off and LED 3 on
// init timer for 20s
// switch to the wait for go state
}
} // endif button event
// if beam event (shoe removed)
{
// turn LED 2 off and turn LED 1 on
// flash step 1
// play sad noise
// init timer for 20s
// switch back to welcome
}
// if user turned the dial
{
// init timer for 20s
// overrwite dial value variable
// stay in same state
} // endif dial event
} // end event type switch
} // End wait for speed state block
// CurrentState is waiting for go button
{
// event type switch
{
// If ThisEvent is timeout
{
// play sad noise
// flash step 3
// init timer for 20s
// stay in the same state
} // endif timeout event
// if a button was pressed
{
// if it was the go button
{
// play happy noise
// start the motors
// (send event with parameter of dial value to motor service)
// start the matrix (send add bar event to matrix service)
// init timers
// (SM timer ~ cleaning lasts 30 sec)
// (matrix timer ~ add one bar per sec)
// turn LED 3 off
// move to the cleaning state
}
// if it was the speed button
{
// play sad noise
// flash step 3
// init timer for user input (20s)
// stay in the same state
}
} // endif button pressed event
// shoe removed (beam event)
{
// turn LED 3 off and LED 1 on
// play sad noise
// flash step 1
// init timer for 20s
// switch back to welcome state
} // endif beam
// if user turned the dial
{
// init timer for 20s
// play sad noise
// flash step 3
// overrwite dial value variable
// stay in same state
} // endif dial event
} // end of event type switch
} // End waiting for go state block
// CurrentState is cleaning
{
// event type switch
{
// timeout cleaning done
{
// switch on event parameter
{
// if cleaning timer is done
{
// turn on LED 4
// stop motor (post stop event to motor service)
// play happy noise
// init timer for 20s
// move to finished state
}
// if the matrix timer times out
{
// post another add bar event to matrix service
// init matrix timer (1 sec)
// stay in cleaning state
}
}
} // endif timeout event
// if a button is pressed
{
// play sad noise
// stay in the same state
} // endif button pressed
// if dial is turned
{
// play sad noise
// overrwite dial value variable for next run
// stay in the same state
} // endif dial event
// shoe removed (beam event)
{
// turn LED 1 back on
// stop motor event (post to motor service)
// reset matrix to empty progress bar
// (send reset event to the matrix service)
// flash LED step 1
// play sad noise
// init timer for 20s
// switch back to welcome
} // endif beam
} // end event type switch
} // End cleaning state block
// CurrentState is finished cleaning
{
// event type switch
{
// If ThisEvent is timeout
{
// if it's the main SM timer (foot in too long)
{
// play sad noise
// flash step 4
// init timer for 20s
}
// stay in the same state
} // endif timeout event
// if a button is pressed
{
// play sad noise
// flash step 4
// init timer for 20s
// stay in the same state
} // endif button pressed
// shoe removed (beam event)
{
// play happy noise
// turn off LED 4 and turn on LED 1
// reset matrix to empty progress bar
// (send reset event to matrix service)
// init timer for 20s
// switch back to welcome
} // endif beam
// user turned the dial
{
// init timer for 20s
// play sad noise
// flash step 4
// overrwite dial value variable
// stay in same state
} // endif dial event
} // end of event type switch
} // End finished state block
} // end switch on states
// set CurrentState to NextState
// return the local return event variable
} // End of RunMSC_SM
/****************************************************************************
Function: Audio Function
Parameters: 0 for sad noise, 1 for happy noise
Returns
none (posts to audio service)
****************************************************************************/
// audio helper function
{
// send an audio play event to the audio service
// with parameter of the noise type (0=sad, 1=happy)
} // end of Audio helper function
/****************************************************************************
Function: StepControl
(streamlines posting to the LED service)
****************************************************************************/
// LED step indicator helper function
{
// make sure no LEDs are flashing (send a flash off event)
// send event to turn LED on or off
// use boolean variable (on/off) for the parameter
}
/****************************************************************************
Function: FlashFunction
(streamlines posting to the flash service)
****************************************************************************/
// flash LED helper function
{
// send event to flash an LED
// (with a parameter of which LED to flash)
// init flash timer for first flash transition
}
/****************************************************************************
Module
SpeedButtonService.c ~ PSEUDO
* scans the speed button for user input
* if a button is pressed, sends ES_BUTTON_DOWN
* parameter of 's' for speed
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc 218a final project
12-1-2023 mcc project report
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// inlcude relevant header files
/*----------------------------- Module Defines ----------------------------*/
// define timer units
// define bounce timer
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
// previous button state variable
// state machine steps variable
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitSpeedButton
// takes the priority variable to save, returns true if initialized correctly (we assume no errors)
****************************************************************************/
// init function
{
// save the priority variable
// set the button pin to be input
// initialize the last speed button value
// idles high (hardcoded due to hardware issue)
// Set CurrentState to be waiting
// return boolean value
} // End of InitSpeedButton
/****************************************************************************
Function: PostSpeedButton (enqueues to this service)
****************************************************************************/
/****************************************************************************
Function: RunSpeedButton (state machine that debounces the button signals)
****************************************************************************/
// run function
{
// return event local variable
// assume no errors (no event)
// Local Variables: NextState
// Set NextState to CurrentState
// Based on the state of the CurrentState variable choose one of the following blocks of code:
{
// current state is waiting 2
{
// if a rise was detected
{
// start debounce rise timer
// Set NextState to DebouncingRise 2
}
// if a fall was detected
{
// start debounce fall timer
// Set NextState to DebouncingFall 2
}
} // end waiting 2 state
// current state is debouncing fall 2
{
// if a rise was detected
{
// it was bouncy, reset to waiting
}
// if a timeout happened
{
// it was a real button press, post about it
// parameter "s" for speed
// reset to waiting 2 for next button press
}
} // end debouncing fall 2 state
// current state is debouncing rise 2
{
=// if a fall was detected
{
// it was bouncy, reset to waiting
}
// if a timeout was detected
{
// it was a real button press, post about it
// parameter "s" for speed
// reset to waiting for next button press
}
} // end debouncing rise 2 state
} // end case switch
// update state machine state
} // end Run SpeedButton
/****************************************************************************
Function: CheckSpeedButton (event checker listening for changes in the buttons)
****************************************************************************/
// check speed button function
{
// local variables to return/post
// sample the current button states and store in temporary vars
// if the speed button has changed
{
// update the return value
// if the button line is high
{
// Post button event (rise detected) to this service
}
// else (button line is low)
{
// post button event (fall detected) to this service
}
// overwrite the previous button values
}
// return the boolean
} // End of Check Speed Button
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
ES_Configure.h
Description
This file contains macro definitions that are edited by the user to
adapt the Events and Services framework to a particular application.
Notes
History
When Who What/Why
-------------- --- --------
11/2023 Group 11 added services, events, checkers, and timers for final project
12/19/16 20:19 jec removed EVENT_CHECK_HEADER definition. This goes with
the V2.3 move to a single wrapper for event checking
headers
10/11/15 18:00 jec added new event type ES_SHORT_TIMEOUT
10/21/13 20:54 jec lots of added entries to bring the number of timers
and services up to 16 each
08/06/13 14:10 jec removed PostKeyFunc stuff since we are moving that
functionality out of the framework and putting it
explicitly into the event checking functions
01/15/12 10:03 jec started coding
*****************************************************************************/
#ifndef ES_CONFIGURE_H
#define ES_CONFIGURE_H
/****************************************************************************/
// The maximum number of services sets an upper bound on the number of
// services that the framework will handle. Reasonable values are 8 and 16
// corresponding to an 8-bit(uint8_t) and 16-bit(uint16_t) Ready variable size
#define MAX_NUM_SERVICES 16
/****************************************************************************/
// This macro determines that nuber of services that are *actually* used in
// a particular application. It will vary in value from 1 to MAX_NUM_SERVICES
#define NUM_SERVICES 9
/****************************************************************************/
// These are the definitions for Service 0, the lowest priority service.
// Every Events and Services application must have a Service 0. Further
// services are added in numeric sequence (1,2,3,...) with increasing
// priorities
// the header file with the public function prototypes
#define SERV_0_HEADER "GoButtonService.h"
// the name of the Init function
#define SERV_0_INIT InitGoButton
// the name of the run function
#define SERV_0_RUN RunGoButton
// How big should this services Queue be?
#define SERV_0_QUEUE_SIZE 5
/****************************************************************************/
// The following sections are used to define the parameters for each of the
// services. You only need to fill out as many as the number of services
// defined by NUM_SERVICES
/****************************************************************************/
// These are the definitions for Service 1
#if NUM_SERVICES > 1
// the header file with the public function prototypes
#define SERV_1_HEADER "MSC_SM.h"
// the name of the Init function
#define SERV_1_INIT InitializeMSC_SM
// the name of the run function
#define SERV_1_RUN RunMSC_SM
// How big should this services Queue be?
#define SERV_1_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 2
#if NUM_SERVICES > 2
// the header file with the public function prototypes
#define SERV_2_HEADER "MotorService.h"
// the name of the Init function
#define SERV_2_INIT InitMotorService
// the name of the run function
#define SERV_2_RUN RunMotorService
// How big should this services Queue be?
#define SERV_2_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 3
#if NUM_SERVICES > 3
// the header file with the public function prototypes
#define SERV_3_HEADER "SpeedButtonService.h"
// the name of the Init function
#define SERV_3_INIT InitSpeedButton
// the name of the run function
#define SERV_3_RUN RunSpeedButton
// How big should this services Queue be?
#define SERV_3_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 4
#if NUM_SERVICES > 4
// the header file with the public function prototypes
#define SERV_4_HEADER "AudioService.h"
// the name of the Init function
#define SERV_4_INIT InitAudioService
// the name of the run function
#define SERV_4_RUN RunAudioService
// How big should this services Queue be?
#define SERV_4_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 5
#if NUM_SERVICES > 5
// the header file with the public function prototypes
#define SERV_5_HEADER "DialService.h"
// the name of the Init function
#define SERV_5_INIT InitDialService
// the name of the run function
#define SERV_5_RUN RunDialService
// How big should this services Queue be?
#define SERV_5_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 6
#if NUM_SERVICES > 6
// the header file with the public function prototypes
#define SERV_6_HEADER "MatrixService.h"
// the name of the Init function
#define SERV_6_INIT InitMatrixService
// the name of the run function
#define SERV_6_RUN RunMatrixService
// How big should this services Queue be?
#define SERV_6_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 7
#if NUM_SERVICES > 7
// the header file with the public function prototypes
#define SERV_7_HEADER "LEDStepService.h"
// the name of the Init function
#define SERV_7_INIT InitLEDStepService
// the name of the run function
#define SERV_7_RUN RunLEDStepService
// How big should this services Queue be?
#define SERV_7_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 8
#if NUM_SERVICES > 8
// the header file with the public function prototypes
#define SERV_8_HEADER "FlashService.h"
// the name of the Init function
#define SERV_8_INIT InitFlashService
// the name of the run function
#define SERV_8_RUN RunFlashService
// How big should this services Queue be?
#define SERV_8_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 9
#if NUM_SERVICES > 9
// the header file with the public function prototypes
#define SERV_9_HEADER "BeamService.h"
// the name of the Init function
#define SERV_9_INIT InitBeamService
// the name of the run function
#define SERV_9_RUN RunBeamService
// How big should this services Queue be?
#define SERV_9_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 10
#if NUM_SERVICES > 10
// the header file with the public function prototypes
#define SERV_10_HEADER "TestHarnessService10.h"
// the name of the Init function
#define SERV_10_INIT InitTestHarnessService10
// the name of the run function
#define SERV_10_RUN RunTestHarnessService10
// How big should this services Queue be?
#define SERV_10_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 11
#if NUM_SERVICES > 11
// the header file with the public function prototypes
#define SERV_11_HEADER "TestHarnessService11.h"
// the name of the Init function
#define SERV_11_INIT InitTestHarnessService11
// the name of the run function
#define SERV_11_RUN RunTestHarnessService11
// How big should this services Queue be?
#define SERV_11_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 12
#if NUM_SERVICES > 12
// the header file with the public function prototypes
#define SERV_12_HEADER "TestHarnessService12.h"
// the name of the Init function
#define SERV_12_INIT InitTestHarnessService12
// the name of the run function
#define SERV_12_RUN RunTestHarnessService12
// How big should this services Queue be?
#define SERV_12_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 13
#if NUM_SERVICES > 13
// the header file with the public function prototypes
#define SERV_13_HEADER "TestHarnessService13.h"
// the name of the Init function
#define SERV_13_INIT InitTestHarnessService13
// the name of the run function
#define SERV_13_RUN RunTestHarnessService13
// How big should this services Queue be?
#define SERV_13_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 14
#if NUM_SERVICES > 14
// the header file with the public function prototypes
#define SERV_14_HEADER "TestHarnessService14.h"
// the name of the Init function
#define SERV_14_INIT InitTestHarnessService14
// the name of the run function
#define SERV_14_RUN RunTestHarnessService14
// How big should this services Queue be?
#define SERV_14_QUEUE_SIZE 3
#endif
/****************************************************************************/
// These are the definitions for Service 15
#if NUM_SERVICES > 15
// the header file with the public function prototypes
#define SERV_15_HEADER "TestHarnessService15.h"
// the name of the Init function
#define SERV_15_INIT InitTestHarnessService15
// the name of the run function
#define SERV_15_RUN RunTestHarnessService15
// How big should this services Queue be?
#define SERV_15_QUEUE_SIZE 3
#endif
/****************************************************************************/
// Name/define the events of interest
// Universal events occupy the lowest entries, followed by user-defined events
typedef enum
{
ES_NO_EVENT = 0,
ES_ERROR, /* 1 used to indicate an error from the service */
ES_INIT, /* 2 used to transition from initial pseudo-state */
ES_TIMEOUT, /* 3 signals that the timer has expired */
ES_SHORT_TIMEOUT, /* 4 signals that a short timer has expired */
/* User-defined events start here */
ES_NEW_KEY, /* 5 signals a new key received from terminal */
// BeamService
ES_IR_BEAM, /* 6 signals the IR beam is unbroken (shoe out) */
ES_IR_BREAK, /* 7 signals the IR beam is broken (shoe in) */
// DialService
ES_DIAL_CHANGED, /* 8 signals a user-selected new dial setting (debounced) */
ES_DIAL_DETECTED, /* 9 signals the dial is being rotated (not yet debounced)*/
// ButtonService
ES_BUTTON_DOWN, /* 10 a button is down (parameter s or g for which one) */
ES_BUTTON_UP, /* 11 a button is up (parameter s or g for which one) */
ES_GO_RISE_DETECTED, /* 12 go button rise (for debouncing) */
ES_GO_FALL_DETECTED, /* 13 go button fall (for debouncing) */
ES_SPEED_RISE_DETECTED, /* 14 speed button rise (for debouncing) */
ES_SPEED_FALL_DETECTED, /* 15 speed button fall (for debouncing) */
// MatrixService
ES_MATRIX_ADD_BAR, /* 16 signals the matrix to add a progress bar */
ES_MATRIX_UPDATE_ROW, /* 17 signals the display to update */
ES_MATRIX_RESET, /* 18 signals the matrix to reset */
// LEDStepService
ES_STEP1, /* 19 LED step 1 (please insert shoe) */
ES_STEP2, /* 20 LED step 2 (please select speed) */
ES_STEP3, /* 21 LED step 3 (please press go) */
ES_STEP4, /* 22 LED step 4 (please remove shoe) */
// AudioService
ES_AUDIO_PLAY, /* 23 signals the audio service to play (parameter which sound) */
// MotorService
ES_MOTOR_START, /* 24 to start the motors */
ES_MOTOR_STOP, /* 25 to stop the motors */
// FlashService
ES_FLASH_LED, /* 26 to blink an LED (parameter of which step) */
ES_FLASH_OFF /* 27 turn a blinking LED off (parameter of which step) */
}ES_EventType_t;
/****************************************************************************/
// These are the definitions for the Distribution lists. Each definition
// should be a comma separated list of post functions to indicate which
// services are on that distribution list.
#define NUM_DIST_LISTS 0
#if NUM_DIST_LISTS > 0
#define DIST_LIST0 PostTestHarnessService0, PostTestHarnessService0
#endif
#if NUM_DIST_LISTS > 1
#define DIST_LIST1 PostTestHarnessService1, PostTestHarnessService1
#endif
#if NUM_DIST_LISTS > 2
#define DIST_LIST2 PostTemplateFSM
#endif
#if NUM_DIST_LISTS > 3
#define DIST_LIST3 PostTemplateFSM
#endif
#if NUM_DIST_LISTS > 4
#define DIST_LIST4 PostTemplateFSM
#endif
#if NUM_DIST_LISTS > 5
#define DIST_LIST5 PostTemplateFSM
#endif
#if NUM_DIST_LISTS > 6
#define DIST_LIST6 PostTemplateFSM
#endif
#if NUM_DIST_LISTS > 7
#define DIST_LIST7 PostTemplateFSM
#endif
/****************************************************************************/
// This is the list of event checking functions
// new checkers: go and speed buttons, speed selection dial, and the IR beam
#define EVENT_CHECK_LIST Check4Keystroke, CheckGoButton, CheckSpeedButton, CheckDialEvents, CheckBeamEvents
/****************************************************************************/
// These are the definitions for the post functions to be executed when the
// corresponding timer expires. All 16 must be defined. If you are not using
// a timer, then you should use TIMER_UNUSED
// Unlike services, any combination of timers may be used and there is no
// priority in servicing them
#define TIMER_UNUSED ((pPostFunc)0)
#define TIMER0_RESP_FUNC TIMER_UNUSED
#define TIMER1_RESP_FUNC TIMER_UNUSED
#define TIMER2_RESP_FUNC TIMER_UNUSED
#define TIMER3_RESP_FUNC TIMER_UNUSED
#define TIMER4_RESP_FUNC TIMER_UNUSED
#define TIMER5_RESP_FUNC TIMER_UNUSED
#define TIMER6_RESP_FUNC TIMER_UNUSED
#define TIMER7_RESP_FUNC TIMER_UNUSED
#define TIMER8_RESP_FUNC PostDialService
#define TIMER9_RESP_FUNC PostAudioService
#define TIMER10_RESP_FUNC PostMSC_SM
#define TIMER11_RESP_FUNC PostFlashService
#define TIMER12_RESP_FUNC PostMSC_SM
#define TIMER13_RESP_FUNC PostSpeedButton
#define TIMER14_RESP_FUNC PostGoButton
#define TIMER15_RESP_FUNC TIMER_UNUSED
/****************************************************************************/
// Give the timer numbers symbolic names to make it easier to move them
// to different timers if the need arises. Keep these definitions close to the
// definitions for the response functions to make it easier to check that
// the timer number matches where the timer event will be routed
// These symbolic names should be changed to be relevant to your application
//#define SERVICE0_TIMER 15
#define GO_BTN_TIMER 14 /* go button debouncing timer */
#define SPEED_BTN_TIMER 13 /* speed button debouncing timer */
#define MSC_SM_TIMER 12 /* mobile shoe cleaner state machine timer */
#define FLASH_TIMER 11 /* LED flash module timer */
#define MATRIX_TIMER 10 /* progress bar timer (posts to SM) */
#define AUDIO_TIMER 9 /* audio module timer */
#define DIAL_TIMER 8 /* dial debouncing timer */
#endif /* ES_CONFIGURE_H */
/****************************************************************************
Module
AudioService.c
* listens for the event ES_AUDIO_PLAY
* events should have parameters 1 (play happy noise) or 0 (play sad noise)
* pulls the audio pin low for the chip to play
* ASSUMING HAPPY ON RA3 and SAD ON RA4 - UPDATE IF INCORRECT
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc final project
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "AudioService.h"
#include "dbprintf.h"
#include <stdint.h>
#include <stdbool.h>
/*----------------------------- Module Defines ----------------------------*/
// these times assume a 10.000mS/tick timing
#define ONE_SEC 1000
#define HALF_SEC (ONE_SEC / 2)
#define EGT_SEC (ONE_SEC / 8)
//#define TEST // for debugging
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitAudioService
// Takes no parameters, returns nothing
****************************************************************************/
bool InitAudioService(uint8_t Priority)
{
// from template - initialize value
MyPriority = Priority;
// set the relevant pins as digital outputs
// pins RB3 and RB4 (10 and 12)
TRISAbits.TRISA3 = 0;
TRISAbits.TRISA4 = 0;
// set pins high by default
LATAbits.LATA3 = 1; // set pin high
LATAbits.LATA4 = 1; // set pin high
#ifdef TEST
DB_printf(" init audio service \r\n"); // debug printing
#endif
// return boolean value
return true;
} // End of InitAudioService
/****************************************************************************
Function
// RunAudioService
// Takes an input event, returns errors if applicable
****************************************************************************/
ES_Event_t RunAudioService(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent; // local var to return
ReturnEvent.EventType = ES_NO_EVENT; // local var ReturnValue initialized to ES_NO_EVENT
// listen for audio events
if (ThisEvent.EventType == ES_AUDIO_PLAY)
{
#ifdef TEST
DB_printf(" audio requested \r\n"); // debug printing
#endif
if (ThisEvent.EventParam == 1) // happy audio requested
{
#ifdef TEST
DB_printf(" playing happy audio \r\n"); // debug printing
#endif
LATAbits.LATA3 = 0; // set pin low
ES_Timer_InitTimer(AUDIO_TIMER, EGT_SEC); // timer until reset pin high
} // endif happy noise
else if (ThisEvent.EventParam == 0) // sad audio requested
{
#ifdef TEST
DB_printf(" playing sad audio \r\n"); // debug printing
#endif
LATAbits.LATA4 = 0; // set pin low
ES_Timer_InitTimer(AUDIO_TIMER, EGT_SEC); // timer until reset pin high
} // endif sad noise
else // invalid input
{
#ifdef TEST
DB_printf(" audio error \r\n"); // debug printing
#endif
} // end else (invalid audio)
} // endif audio event
else if (ThisEvent.EventType == ES_TIMEOUT)
{
#ifdef TEST
DB_printf(" Audio timeout \r\n"); // debug print
#endif
// set pins back to high
LATAbits.LATA3 = 1; // set pin high
LATAbits.LATA4 = 1; // set pin high
}
return ReturnEvent; // return for the run function
} // end of run AudioService
/****************************************************************************
Function
// PostAudioService
// Takes no parameters, returns either a character or a '~' indicating failure
****************************************************************************/
bool PostAudioService(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
BeamService.c
Description
IR sensor detection
History
When Who What/Why
-------------- --- --------
11/2023 Team 11 final project 218a
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "BeamService.h"
#include "MSC_SM.h"
/*----------------------------- Module Defines ----------------------------*/
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// variable for keeping track of previous beam state
// init as zero because we assume foot started outside (beam was unbroken)
static bool LastBeamState = 0;
/*------------------------------ Module Code ------------------------------*/
/***************************************************************************
Function
CheckBeamEvents
Parameters
None
Returns
True if event an event is posted
Description
event checker function for the IR beam
***************************************************************************/
bool CheckBeamEvents(void)
{
bool ReturnVal = false; // for the return boolean
bool CurrentBeamState = PORTBbits.RB8; // read the current state of the beam
if (CurrentBeamState != LastBeamState) // if the beam has changed (foot in or out)
{
for (uint8_t x=0; x<100; x++){} // delay for noise check
bool SecondBeamState = PORTBbits.RB8; // another check in case of noise
if (SecondBeamState != LastBeamState) // if the beam has changed (foot in or out)
{
ReturnVal = true; // change the return value
ES_Event_t BeamEvent; // create an event to post
if (0 == CurrentBeamState)
{
// post a beam broken event
BeamEvent.EventType = ES_IR_BREAK;
PostMSC_SM(BeamEvent);
}
else
{
// post a beam (unbroken) event
BeamEvent.EventType = ES_IR_BEAM;
PostMSC_SM(BeamEvent);
}
}
// update the last beam state
LastBeamState = SecondBeamState;
}
return ReturnVal; // return the boolean
} // end of CheckBeamEvents
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
DialService.c
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc final project 218a
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "DialService.h"
#include "PIC32_AD_Lib.h"
#include "dbprintf.h"
/*----------------------------- Module Defines ----------------------------*/
// these times assume a 10.000mS/tick timing
#define ONE_SEC 1000
#define HALF_SEC (ONE_SEC / 2)
#define TEST // for debugging
/*---------------------------- Module Functions ---------------------------*/
bool CheckDialEvents(void); // event checker function
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
// Data private to the module: LastDialState (array with one value)
static uint32_t LastDial[1];
// state machine steps
static Dial_State_t CurrentState;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function: InitDialService
(takes parameter priority, returns boolean when finished, does not error check)
****************************************************************************/
bool InitDialService(uint8_t Priority)
{
// from template, priority to be assigned
MyPriority = Priority;
#ifdef TEST
DB_printf(" init dial service \r\n"); // debug printing
#endif
// set the pin to be an input
// RB3 aka Pin 7 aka Analog 5
TRISBbits.TRISB3 = 1; // declare it an input
ANSELBbits.ANSB3 = 1; // ENable analog output
// prepare to analog scan (AD library)
// function: bool ADC_ConfigAutoScan( uint16_t whichPins)
ADC_ConfigAutoScan(BIT5HI);
// use AD library to scan the pin into the variable
// function: void ADC_MultiRead(uint32_t *adcResults)
ADC_MultiRead(LastDial);
#ifdef TEST
DB_printf(" send initial dial read event \r\n"); // debug printing
DB_printf(" initial dial value %u \r\n", LastDial[0]); // debug printing
#endif
// send an event so the main state machine has the variable value
ES_Event_t DialEvent;
DialEvent.EventType = ES_DIAL_CHANGED;
DialEvent.EventParam = (uint16_t)LastDial[0];
PostMSC_SM(DialEvent);
// Set CurrentState to be waiting
CurrentState = Dial_Waiting;
// return boolean value
return true;
} // End of InitDialStatus
/****************************************************************************
Function: PostDialService (enqueues to this service)
****************************************************************************/
bool PostDialService(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function: RunDialService
(takes an event posted to this service, returns no event assuming no errors)
****************************************************************************/
ES_Event_t RunDialService(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
Dial_State_t NextState; // Local Variables: NextState
NextState = CurrentState; // Set NextState to CurrentState
// Based on the state of the CurrentState variable choose one of the following blocks of code:
switch (CurrentState)
{
case Dial_Waiting: // current state is waiting
{
if (ThisEvent.EventType == ES_DIAL_DETECTED) // if the dial value changed
{
#ifdef TEST
DB_printf(" dial detected, start debounce \r\n"); // debug printing
#endif
// start debounce rise timer
ES_Timer_InitTimer(DIAL_TIMER, HALF_SEC);
// change to debounce state
NextState = Dial_Debounce;
}
} // end of dial waiting
break;
case Dial_Debounce: // current state is dial debounce
{
if (ThisEvent.EventType == ES_DIAL_DETECTED) // if the dial changed again
{
#ifdef TEST
DB_printf(" dial detected again, still debouncing \r\n"); // debug printing
#endif
// not done inputting - restart timer
ES_Timer_InitTimer(DIAL_TIMER, HALF_SEC);
NextState = Dial_Debounce; // stay in the same state
}
else if (ThisEvent.EventType == ES_TIMEOUT) // if the timer expires, assume input is done
{
if (ThisEvent.EventParam == 8) // check if it's the dial timer
{
#ifdef TEST
DB_printf(" dial done, sending event \r\n"); // debug printing
#endif
// done changing - post to main state machine with parameter of the current value
ES_Event_t DialEvent;
DialEvent.EventType = ES_DIAL_CHANGED;
DialEvent.EventParam = LastDial[0];
PostMSC_SM(DialEvent);
// reset for next time
NextState = Dial_Waiting;
} // endif checking correct timer
else
{
DB_printf(" dial service wrong timer posting \r\n"); // debug printing
}
}
} // end of dial debounce state
break;
} // end of state switch
// move to next state
CurrentState = NextState;
// return the return event
return ReturnEvent;
} // end Run Dial Service
/****************************************************************************
Function
// CheckDialEvents
// Takes no parameters, returns True if an event posted
// it's an event checker function
****************************************************************************/
bool CheckDialEvents(void)
{
bool ReturnVal = false; // assume no change
// temporary var for storing the current value
uint32_t CurrentDial[1];
// check the current pin value
ADC_MultiRead(CurrentDial);
// variable for comparison between values
int32_t difference = CurrentDial[0] - LastDial[0];
// if it has changed significantly enough
if (20 <= abs(difference))
{
ReturnVal = true; // update the return boolean
// post the event into this service to debounce
ES_Event_t ThisEvent;
ThisEvent.EventType = ES_DIAL_DETECTED;
PostDialService(ThisEvent);
// update the last value variable (only if significantly changed)
LastDial[0] = CurrentDial[0];
}
return ReturnVal; // return the boolean
} // End of CheckDialEvents
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
DM_Display.c
Description
Source file for the Dot Matrix LED Hardware Abstraction Layer
used in ME218
History
When Who What/Why
-------------- --- --------
10/03/21 12:32 jec started coding
2023-10-18 klg Aligned DM_AddChar2DisplayBuffer
11-2023 Team 11 added progress bars and borders
*****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
#include <xc.h>
#include <stdbool.h>
#include "PIC32_SPI_HAL.h"
#include "DM_Display.h"
#include "FontStuff.h"
#include "dbprintf.h"
/*----------------------------- Module Defines ----------------------------*/
#define NumModules 4
#define NUM_ROWS 8
#define NUM_ROWS_IN_FONT 5
#define DM_START_SHUTDOWN 0x0C00
#define DM_END_SHUTDOWN 0x0C01
#define DM_DISABLE_CODEB 0x0900
#define DM_ENABLE_SCAN 0x0B07
#define DM_SET_BRIGHT 0x0A00
/*------------------------------ Module Types -----------------------------*/
// this union definition assumes that the display is made up of 4 modules
// 4 modules x 8 bits/module = 32 bits total
// this union allows us to easily scroll the whole buffer, using the uint32_t
// while picking out the individual bytes to send them to the controllers
typedef union{
uint32_t FullRow;
uint8_t ByBytes[NumModules];
}DM_Row_t;
typedef enum { DM_StepStartShutdown = 0, DM_StepFillBufferZeros,
DM_StepDisableCodeB, DM_StepEnableScanAll, DM_StepSetBrighness,
DM_StepCopyBuffer2Display, DM_StepEndShutdown
}InitStep_t;
/*---------------------------- Module Functions ---------------------------*/
static void sendCmd( uint16_t Cmd2Send );
static void sendRow( uint8_t RowNum, DM_Row_t RowData );
// new fns for 218a final project
void DM_AddProgressBar(uint8_t WhichBar);
void DM_BordersOnly(void);
/*---------------------------- Module Variables ---------------------------*/
// We make the display buffer from an array of these unions, one for each
// row in the display
static DM_Row_t DM_Display[NUM_ROWS];
// this is the state variable for tracking init steps
static InitStep_t CurrentInitStep = DM_StepStartShutdown;
// In order to keep up with the display at 10MHz, the bit reverse operation
// must be as fast as possible, hence the look-up table approach is the only
// solution that will work with the SPI at 10MHz
// This bit reversal table comes from
// https://stackoverflow.com/questions/746171/efficient-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c
// usage: BitReversedValue = BitReverseTable256[OriginalByteValue];
//
static const uint8_t BitReverseTable256[] =
{
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF
};
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
DM_TakeInitDisplayStep
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
****************************************************************************/
bool DM_TakeInitDisplayStep( void )
{
static uint8_t rowIndex = 0;
bool ReturnVal = false;
switch (CurrentInitStep)
{
case DM_StepStartShutdown:
// First, bring put it in shutdown to disable all displays
sendCmd(DM_START_SHUTDOWN);
CurrentInitStep++; // move on to next step
break;
case DM_StepFillBufferZeros:
// iterate thru all rows
for (uint8_t row = 0; row < NUM_ROWS; row++){
// in each row, set it to a full blank
DM_Display[row].FullRow = 0x00000000;
}
CurrentInitStep++; // move on to next step
break;
case DM_StepDisableCodeB:
// Next Disable Code B decoding for all digits
sendCmd(DM_DISABLE_CODEB);
CurrentInitStep++; // move on to next step
break;
case DM_StepEnableScanAll:
// Then, enable scanning for all digits
sendCmd(DM_ENABLE_SCAN);
CurrentInitStep++; // move on to next step
break;
case DM_StepSetBrighness:
// The next setup step is to set the brightness to minimum
sendCmd(DM_SET_BRIGHT);
CurrentInitStep++; // move on to next step
break;
case DM_StepCopyBuffer2Display: // copy our display buffer to the display
if (true == DM_TakeDisplayUpdateStep())
{
CurrentInitStep++; // move on to next step
}
else
{}
break;
case DM_StepEndShutdown:
// Finally, bring it out of shutdown (DM_END_SHUTDOWN)
sendCmd(DM_END_SHUTDOWN);
// let the caller know that we are done, reset
CurrentInitStep = 0; // move on to next step
ReturnVal = true;
break;
default:
break;
}
return ReturnVal;
}
/****************************************************************************
Function
DM_TakeDisplayUpdateStep
Description
Copies the contents of the display buffer to the MAX7219 controllers 1 row
per call.
****************************************************************************/
bool DM_TakeDisplayUpdateStep( void )
{
bool ReturnVal = false;
static int8_t WhichRow = 0;
// send the row for this call
sendRow(WhichRow, DM_Display[WhichRow]);
// increment the WhichRow variable for next time
WhichRow++;
// if we've got through all the rows, reset
if (WhichRow == NUM_ROWS)
{
ReturnVal = true; // show we are done
WhichRow = 0; // set up for next update
}
return ReturnVal;
}
/****************************************************************************
Function
DM_ScrollDisplayBuffer
Description
Scrolls the contents of the display buffer by the indicated number of
columns. Makes use of the FullRow member to scroll all modules at once
****************************************************************************/
void DM_ScrollDisplayBuffer( uint8_t NumCols2Scroll)
{
// my code :)
// iterate thru all the rows
for (uint8_t row = 0; row < NUM_ROWS; row++){
// scoot the data left
DM_Display[row].FullRow = DM_Display[row].FullRow << NumCols2Scroll;
}
};
/****************************************************************************
Function
DM_AddChar2DisplayBuffer
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
****************************************************************************/
void DM_AddChar2DisplayBuffer( unsigned char Char2Display)
{
// my code :) to loop thru rows in the font
DB_printf("Char2Disp:>>%c<<\n", Char2Display);
for (uint8_t row = 0; row < NUM_ROWS_IN_FONT; row++)
{
// for each row, copy data into buffer
DM_Display[row].ByBytes[0] |= getFontLine(Char2Display, row);
}
}
/****************************************************************************
Function
DM_ClearDisplayBuffer
Description
Clears the contents of the display buffer by filling it with zeros.
****************************************************************************/
void DM_ClearDisplayBuffer( void )
{
uint8_t rowIndex;
// Now fill the display RAM with Zeros to ensure blanked
// my code :) iterate thru all rows
for (uint8_t row = 0; row < NUM_ROWS; row++){
// in each row, set it to a full blank
DM_Display[row].FullRow = 0x00000000;
}
}
/****************************************************************************
Function
DM_PutDataIntoBufferRow
Description
Copies the raw data from the Data2Insert parameter into the specified row
of the frame buffer
****************************************************************************/
bool DM_PutDataIntoBufferRow( uint32_t Data2Insert, uint8_t WhichRow)
{
bool ReturnVal = true;
// test for legal row
if(WhichRow < NUM_ROWS && WhichRow >= 0){
// legal row, so stuff the data into the buffer
DM_Display[WhichRow].FullRow = Data2Insert; // put into BUFFER (aka DM_Display), not send
// old version
// DM_Row_t FormatData2Insert; // new union variable
// FormatData2Insert.FullRow = Data2Insert; // convert data type
// sendRow(WhichRow, FormatData2Insert); // send
}
else{
ReturnVal = false;
}
return ReturnVal;
}
/****************************************************************************
Function
DM_QueryRowData
Description
copies the contents of the specified row of the frame buffer into the
location pointed to by pReturnValue
****************************************************************************/
bool DM_QueryRowData( uint8_t RowToQuery, uint32_t * pReturnValue)
{
bool ReturnVal = true;
// test for legal row
if(RowToQuery <= NUM_ROWS){
// legal row, so grab the data from the buffer
uint32_t CopiedData = DM_Display[RowToQuery].FullRow; // read the data into a variable
*pReturnValue = CopiedData;
}
else{
ReturnVal = false;
}
}
//*********************************
// private functions
//*********************************
/****************************************************************************
Function
sendCmd
Description
Send a single command to all 4 modules and waits for the SS to rise to
indicate completion.
****************************************************************************/
static void sendCmd( uint16_t Cmd2Send )
{
uint8_t index;
for (index = 0; index <= (NumModules-2); index++)
{
SPIOperate_SPI1_Send16( Cmd2Send );
}
SPIOperate_SPI1_Send16Wait( Cmd2Send );
}
/****************************************************************************
Function
sendRow
Description
Sends a row of data to the 4-module cluster. Translates from the logical
row number to the MAX7219 row numbers (mirrors)
****************************************************************************/
static void sendRow( uint8_t RowNum, DM_Row_t RowData )
{
uint8_t index;
// The rows on the display are mirrored relative to the rows in the memory
RowNum = NUM_ROWS - (RowNum+1); // this will swap them top to bottom
// loop through, sending the first 3 values as fast as possible
for (index = 0; index <= (NumModules-2); index++)
{
SPIOperate_SPI1_Send16( ((((uint16_t)RowNum+1)<<8) |
BitReverseTable256[(RowData.ByBytes[index])]));
}
// then send the final byte and wait for the SS line to rise
SPIOperate_SPI1_Send16Wait(
((((uint16_t)RowNum+1)<<8) |
BitReverseTable256[(RowData.ByBytes[index])]));
}
/****************************************************************************
NEW FUNCTIONS
for final project
AddProgressBar: adds a lit row to the display, according to input parameter
BordersOnly: illuminates only the outermost LEDs of the matrix
****************************************************************************/
void DM_AddProgressBar(uint8_t WhichBar)
{
// start with rightmost LED
DM_Row_t appender;
appender.FullRow = 0x00000001;
// shift left depending on which bar we are at
appender.FullRow <<= WhichBar;
// append the new single LED to the existing row
for (uint8_t WhichRow = 0; WhichRow < NUM_ROWS; WhichRow++)
{
DM_Display[WhichRow].FullRow |= appender.FullRow;
}
}
void DM_BordersOnly(void)
{
// full top row border. all LEDs lit
DM_Row_t TopRow;
TopRow.FullRow = 0xFFFFFFFF;
sendRow(0, TopRow);
DM_Display[0].FullRow = TopRow.FullRow; // Update buffer as well as display
// partial borders. left- and right-most LEDs lit
DM_Row_t MiddleRow;
MiddleRow.FullRow = 0x80000001;
for (uint8_t rowIndex = 1; rowIndex < 7; rowIndex++)
{
sendRow(rowIndex, MiddleRow);
DM_Display[rowIndex].FullRow = MiddleRow.FullRow;
}
// full bottom row border. all LEDs lit
DM_Row_t BottomRow = TopRow;
sendRow(7, TopRow);
DM_Display[7].FullRow = BottomRow.FullRow;
}
/****************************************************************************
Module
FlashService.c
* listens for the ES_FLASH event
* expects a parameter of 1-4 for which step to flash
History
When Who What/Why
-------------- --- --------
11/13/2023 mcc final project 218a
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "FlashService.h"
#include "dbprintf.h"
/*----------------------------- Module Defines ----------------------------*/
// these times assume a 10.000mS/tick timing
#define ONE_SEC 1000
#define HALF_SEC (ONE_SEC / 2)
#define QTR_SEC (ONE_SEC / 2)
// #define TEST // for debugging
/*---------------------------- Module Functions ---------------------------*/
// helper function
void BlinkerFunction(uint8_t WhichLED, bool WhichSetting);
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
// state machine steps
static Flash_State_t CurrentState;
// which step (LED) are we changing this time
uint8_t ThisStepLED;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitFlash
// Takes no parameters, returns nothing
****************************************************************************/
bool InitFlashService(uint8_t Priority)
{
MyPriority = Priority; // save the variable
#ifdef TEST
DB_printf(" init LED flash service \r\n"); // debug printing
#endif
// start in the first off state
CurrentState = On0;
// return boolean value
return true;
} // End of Init Flash
/****************************************************************************
Function: PostFlash (enqueues to this service)
****************************************************************************/
bool PostFlashService(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function: RunFlash (state machine that turns the specified light on and off)
****************************************************************************/
ES_Event_t RunFlashService(ES_Event_t ThisEvent)
{
#ifdef TEST
DB_printf(" running flash, parameter: %u \r\n", ThisEvent.EventParam); // debug printing
#endif
ES_Event_t ReturnEvent; // return event local variable
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
Flash_State_t NextState; // Local Variables: NextState
NextState = CurrentState; // Set NextState to CurrentState
// check if we've got a flash event
switch (ThisEvent.EventType)
{
case ES_FLASH_LED: // flash LED event
{
#ifdef TEST
DB_printf(" assigning LED to flash \r\n"); // debug printing
#endif
// take the event parameter to select which LED to mess with
if (ThisEvent.EventParam == 1){
ThisStepLED = 1;
}
else if (ThisEvent.EventParam == 2){
ThisStepLED = 2;
}
else if (ThisEvent.EventParam == 3){
ThisStepLED = 3;
}
else if (ThisEvent.EventParam == 4){
ThisStepLED = 4;
}
else{
// invalid step number
DB_printf(" invalid LED Step input \r\n"); // debug print
}
} // end case flash event
break;
case ES_FLASH_OFF: // flash off event
{
#ifdef TEST
DB_printf(" flash deactivation \r\n"); // debug printing
#endif
// turn all the LEDs off
BlinkerFunction(1, 0);
BlinkerFunction(2, 0);
BlinkerFunction(3, 0);
BlinkerFunction(4, 0);
// stop the timer
ES_Timer_StopTimer(FLASH_TIMER);
NextState = On0; // reset to first state
CurrentState = NextState; // update the state
} // end case flash off
break;
case ES_TIMEOUT: // timeout event
{
// Based on the state of the CurrentState variable choose one of the following blocks of code:
switch (CurrentState)
{
case On0: // current state is LED is on
{
#ifdef TEST
DB_printf(" on0 state \r\n"); // debug printing
#endif
// restart the timer
ES_Timer_InitTimer(FLASH_TIMER, QTR_SEC);
// turn the LED off
BlinkerFunction(ThisStepLED, 0);
// Set NextState to LED off
NextState = Off1;
}
break;
case Off1: // current state is LED is off
{
#ifdef TEST
DB_printf(" off1 state \r\n"); // debug printing
#endif
// restart the timer
ES_Timer_InitTimer(FLASH_TIMER, QTR_SEC);
// turn the LED on
BlinkerFunction(ThisStepLED, 1);
// Set NextState to LED on
NextState = On1;
}
break;
case On1: // current state is LED is on
{
#ifdef TEST
DB_printf(" on1 state \r\n"); // debug printing
#endif
// restart the timer
ES_Timer_InitTimer(FLASH_TIMER, QTR_SEC);
// turn the LED off
BlinkerFunction(ThisStepLED, 0);
// Set NextState to LED off
NextState = Off2;
}
break;
case Off2: // current state is LED is off
{
#ifdef TEST
DB_printf(" off2 state \r\n"); // debug printing
#endif
// restart the timer
ES_Timer_InitTimer(FLASH_TIMER, QTR_SEC);
// turn the LED on
BlinkerFunction(ThisStepLED, 1);
// Set NextState to LED on
NextState = On2;
}
break;
case On2: // current state is LED is on
{
#ifdef TEST
DB_printf(" on2 state \r\n"); // debug printing
#endif
// restart the timer
ES_Timer_InitTimer(FLASH_TIMER, QTR_SEC);
// turn the LED off
BlinkerFunction(ThisStepLED, 0);
// Set NextState to LED off
NextState = Off3;
}
break;
case Off3: // current state is LED is off
{
#ifdef TEST
DB_printf(" off3 state \r\n"); // debug printing
#endif
// restart the timer
ES_Timer_InitTimer(FLASH_TIMER, QTR_SEC);
// turn the LED on
BlinkerFunction(ThisStepLED, 1);
// Set NextState to LED on
NextState = On3;
}
break;
case On3: // current state is LED is on
{
#ifdef TEST
DB_printf(" on3 state \r\n"); // debug printing
#endif
// DO NOT INIT THE TIMER (end of blink pattern)
// turn the LED on (and leave it on)
BlinkerFunction(ThisStepLED, 1);
// cycle back to the beginning for next call
NextState = On0;
}
break;
} // end case switch
// update state
CurrentState = NextState;
} // end of if timeout case
break;
} // end event type switch
} // end Run Flash
/****************************************************************************
Helper Function: BlinkerFunction (turns the indicated LED on or off)
****************************************************************************/
void BlinkerFunction(uint8_t WhichLED, bool WhichSetting)
{
if (WhichLED == 1) // step 1
{
LATBbits.LATB2 = WhichSetting;
}
else if (WhichLED == 2) // step 2
{
LATBbits.LATB4 = WhichSetting;
}
else if (WhichLED == 3) // step 3
{
LATBbits.LATB5 = WhichSetting;
}
else if (WhichLED == 4) // step 4
{
LATBbits.LATB10 = WhichSetting;
}
else
{
DB_printf(" blinker function error \r\n"); // debug printing
}
}
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
GoButtonService.c
* scans the go button for user input
* if a button is pressed, sends ES_BUTTON_DOWN
* parameter of 'g' for go
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc final project
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "GoButtonService.h"
#include "dbprintf.h"
/*----------------------------- Module Defines ----------------------------*/
// these times assume a 10.000mS/tick timing
#define ONE_SEC 1000
#define HALF_SEC (ONE_SEC / 2)
// measure this more accurately (internet said 50ms, we measured ~2ms)
// this value worked in real testing
#define BOUNCETIME 10
//#define TEST // for debugging
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
// previous button states
bool LastGoButton;
// state machine steps
static Go_Button_State_t CurrentState;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitGoButton
// Takes no parameters, returns nothing
****************************************************************************/
bool InitGoButton(uint8_t Priority)
{
// from template, save the priority variable
MyPriority = Priority;
// set the buttons pin to be input
// RB8 aka pin 17 is the go button
TRISAbits.TRISA2 = 1; // declare it an input
// sample the pin and assign original value
LastGoButton = PORTAbits.RA2;
// Set CurrentState to be waiting
CurrentState = Waiting;
#ifdef TEST
DB_printf(" init go button \r\n"); // debug printing
#endif
// return boolean value
return true;
} // End of InitGoButton
/****************************************************************************
Function: PostGoButton (enqueues to this service)
****************************************************************************/
bool PostGoButton(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function: RunGoButton (state machine that debounces the button signals)
****************************************************************************/
ES_Event_t RunGoButton(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent; // event to return
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
Go_Button_State_t NextState; // Local Variables: NextState
NextState = CurrentState; // Set NextState to CurrentState
// Based on the state of the CurrentState variable choose one of the following blocks of code:
switch (CurrentState)
{
case Waiting: // current state is waiting
{
if (ThisEvent.EventType == ES_GO_RISE_DETECTED) // if a rise was detected
{
// start debounce rise timer
ES_Timer_InitTimer(GO_BTN_TIMER, BOUNCETIME);
// Set NextState to DebouncingRise
NextState = DebouncingRise;
#ifdef TEST
DB_printf(" go waiting rise detected \r\n"); // debug printing
#endif
}
if (ThisEvent.EventType == ES_GO_FALL_DETECTED) // if a fall was detected
{
// start debounce fall timer
ES_Timer_InitTimer(GO_BTN_TIMER, BOUNCETIME);
// Set NextState to DebouncingRise
NextState = DebouncingFall;
#ifdef TEST
DB_printf(" go waiting fall detected \r\n"); // debug printing
#endif
}
} // end of waiting state
break;
case DebouncingFall: // current state is debouncing fall
{
if (ThisEvent.EventType == ES_GO_RISE_DETECTED) // if a rise was detected
{
// it was bouncy, reset to waiting
NextState = Waiting;
#ifdef TEST
DB_printf(" go false fall \r\n"); // debug printing
#endif
}
if (ThisEvent.EventType == ES_TIMEOUT) // if timeout event
{
// it was a real button press, post about it
ES_Event_t ButtonAlert;
ButtonAlert.EventType = ES_BUTTON_UP;
ButtonAlert.EventParam = 'g'; // g for go
#ifdef TEST
DB_printf(" go real fall \r\n"); // debug printing
#endif
PostMSC_SM(ButtonAlert); // post to the main state machine
// reset to waiting for next button press
NextState = Waiting;
}
} // end of debouncing fall state
break;
case DebouncingRise: // current state is debouncing rise
{
if (ThisEvent.EventType == ES_GO_FALL_DETECTED) // if a fall was detected
{
// it was bouncy, reset to waiting
NextState = Waiting;
#ifdef TEST
DB_printf(" go false rise \r\n"); // debug printing
#endif
}
if (ThisEvent.EventType == ES_TIMEOUT) // if a timeout was detected
{
// it was a real button press, post about it
ES_Event_t ButtonAlert;
ButtonAlert.EventType = ES_BUTTON_DOWN;
ButtonAlert.EventParam = 'g'; // g for go
#ifdef TEST
DB_printf(" go real rise \r\n"); // debug printing
#endif
PostMSC_SM(ButtonAlert); // post to the main state machine
// reset to waiting for next button press
NextState = Waiting;
}
} // end of debouncing rise state
break;
} // end case switch
// update the state machine state
CurrentState = NextState;
} // end Run Go Button
/****************************************************************************
Function: CheckGoButton (event checker listening for changes in the buttons)
****************************************************************************/
bool CheckGoButton(void)
{
// local variables to return/post
bool ReturnVal = false;
ES_Event_t ThisEvent;
// sample the current button state and store in temporary var
bool CurrentGoButton;
CurrentGoButton = PORTAbits.RA2;
// if the go button has changed
if (LastGoButton != CurrentGoButton)
{
#ifdef TEST
DB_printf(" go button changed \r\n"); // debug printing
#endif
ReturnVal = true; // update the return variable
if (CurrentGoButton == 1) // if the button line is high
{
// post about the rise
ThisEvent.EventType = ES_GO_RISE_DETECTED;
PostGoButton(ThisEvent);
}
else // else (button line is low)
{
// post about the fall
ThisEvent.EventType = ES_GO_FALL_DETECTED;
PostGoButton(ThisEvent);
}
// overwrite the previous button values
LastGoButton = CurrentGoButton;
}
// return the boolean
return ReturnVal;
} // End of CheckGoButton
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
LEDStepService.c
* listens for the events ES_STEP1, ES_STEP2, ES_STEP3, ES_STEP4
* events should have paraemters 1 (on) or 0 (off)
* turns on/off the corresponding LEDs by writing the pins high/low
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc 218a final project
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "LEDStepService.h"
#include "dbprintf.h"
/*----------------------------- Module Defines ----------------------------*/
//#define TEST // for debugging
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitLEDStep
// Takes no parameters, returns nothing
****************************************************************************/
bool InitLEDStepService(uint8_t Priority)
{
MyPriority = Priority; // save the priority variable
#ifdef TEST
DB_printf(" init LED step service \r\n"); // debug printing
#endif
// set the relevant pins as digital outputs
// pins RB2, RB4, RB5, RB10 (6, 11, 14, 21)
TRISBbits.TRISB2 = 0;
TRISBbits.TRISB4 = 0;
TRISBbits.TRISB5 = 0;
TRISBbits.TRISB10 = 0;
// start them out off
LATBbits.LATB2 = 0;
LATBbits.LATB4 = 0;
LATBbits.LATB5 = 0;
LATBbits.LATB10 = 0;
// return boolean value
return true;
} // End of InitLEDStep
/****************************************************************************
Function
// RunLEDStep (takes event posted here, returns no event, assuming no errors)
****************************************************************************/
ES_Event_t RunLEDStepService(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent; // for the framework
ES_Event_t ToPostEvent; // event to post if there are errors
ReturnEvent.EventType = ES_NO_EVENT; // local var ReturnValue initialized to ES_NO_EVENT
// Based on the state of the ThisEvent variable
switch (ThisEvent.EventType)
{
case ES_STEP1: // if we're changing step 1's LED
{
#ifdef TEST
DB_printf(" LED step 1 \r\n"); // debug printing
DB_printf(" step parameter: %u \r\n", ThisEvent.EventParam); // debug printing
#endif
if (ThisEvent.EventParam == 1) // turning LED on
{
#ifdef TEST
DB_printf(" LED #1 LIT \r\n"); // debug printing
#endif
LATBbits.LATB2 = 1; // set pin high
} // endif
else if (ThisEvent.EventParam == 0) // turning LED off
{
#ifdef TEST
DB_printf(" LED #1 DARK \r\n"); // debug printing
#endif
LATBbits.LATB2 = 0; // set pin low
} // endif
else // invalid input
{
DB_printf(" invalid LED Step 1 input \r\n"); // debug print
}
} // endif step 1
break;
case ES_STEP2: // if we're changing step 2's LED
{
#ifdef TEST
DB_printf(" LED step 2 \r\n"); // debug printing
#endif
if (ThisEvent.EventParam == 1) // turning LED on
{
#ifdef TEST
DB_printf(" LED #2 LIT \r\n"); // debug printing
#endif
LATBbits.LATB4 = 1; // set pin high
} // endif
else if (ThisEvent.EventParam == 0) // turning LED off
{
#ifdef TEST
DB_printf(" LED #2 DARK \r\n"); // debug printing
#endif
LATBbits.LATB4 = 0; // set pin low
} // endif
else // invalid input
{
DB_printf(" invalid LED Step 2 input \r\n"); // debug print
}
} // endif step 2
break;
case ES_STEP3: // if we're changing step 3's LED
{
#ifdef TEST
DB_printf(" LED step 3 \r\n"); // debug printing
#endif
if (ThisEvent.EventParam == 1) // turning LED on
{
#ifdef TEST
DB_printf(" LED #3 LIT \r\n"); // debug printing
#endif
LATBbits.LATB5 = 1; // set pin high
} // endif
else if (ThisEvent.EventParam == 0) // turning LED off
{
#ifdef TEST
DB_printf(" LED #3 DARK \r\n"); // debug printing
#endif
LATBbits.LATB5 = 0; // set pin low
} // endif
else // invalid input
{
DB_printf(" invalid LED Step 3 input \r\n"); // debug print
}
} // endif step 3
break;
case ES_STEP4: // if we're changing step 4's LED
{
#ifdef TEST
DB_printf(" LED step 4 \r\n"); // debug printing
#endif
if (ThisEvent.EventParam == 1) // turning LED on
{
#ifdef TEST
DB_printf(" LED #4 LIT \r\n"); // debug printing
#endif
LATBbits.LATB10 = 1; // set pin high
} // endif
else if (ThisEvent.EventParam == 0) // turning LED off
{
#ifdef TEST
DB_printf(" LED #4 DARK \r\n"); // debug printing
#endif
LATBbits.LATB10 = 0; // set pin low
} // endif
else // invalid input
{
DB_printf(" invalid LED Step 4 input \r\n"); // debug print
}
} // endif step 1
break;
} // end of event switch
return ReturnEvent; // return value for the framework
} // end of run LED Step
/****************************************************************************
Function
// PostLEDStep
// Takes no parameters, returns either a character or a '~' indicating failure
****************************************************************************/
bool PostLEDStepService(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
/****************************************************************************
Module
MatrixService.c
Description
The matrix service controls the LED dot matrix
Notes
History
When Who What/Why
-------------- --- --------
(adapted from template)
11-2023 Team 11 218a final project
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// Hardware
#include <xc.h>
// #include <proc/p32mx170f256b.h>
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "MatrixService.h"
#include "DM_Display.h"
#include "PIC32_SPI_HAL.h"
#include "FontStuff.h"
#include "dbprintf.h"
/*----------------------------- Module Defines ----------------------------*/
//#define TEST // for debugging
#define MATRIX_ACTIVE
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// state machine state
static MatrixState_t CurrentState;
// with the introduction of Gen2, we need a module level Priority var as well
static uint8_t MyPriority;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitMatrixService
Parameters
uint8_t : the priorty of this service
Returns
bool, false if error in initialization, true otherwise
Description
saves priority, enters initial state machine state
****************************************************************************/
bool InitMatrixService(uint8_t Priority)
{
// from template - initialize
ES_Event_t ThisEvent;
MyPriority = Priority;
#ifdef TEST
DB_printf(" init matrix service \r\n"); // debug printing
#endif
#ifndef MATRIX_ACTIVE
DB_printf(" matrix service inactive \r\n"); // debug printing
#endif
// put us into the Initial PseudoState
CurrentState = INIT_MATRIX;
// post the initial transition event
ThisEvent.EventType = ES_INIT;
if (ES_PostToService(MyPriority, ThisEvent) == true)
{
return true;
}
else
{
return false;
}
}
/****************************************************************************
Function
PostMatrixService
Parameters
EF_Event_t ThisEvent , the event to post to the queue
Returns
boolean False if the Enqueue operation failed, True otherwise
Description
Posts an event to this state machine's queue
****************************************************************************/
bool PostMatrixService(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunMatrixService
Parameters
ES_Event_t : the event to process
Returns
ES_Event_t, ES_NO_EVENT if no error ES_ERROR otherwise
Description
implements the state machine for the LED matrix
****************************************************************************/
ES_Event_t RunMatrixService(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
#ifdef MATRIX_ACTIVE
// keep track of columns, start at 1
static uint8_t BarIndex = 1;
// local variable for the next state
static MatrixState_t NextState;
switch (CurrentState)
{
case INIT_MATRIX: // If current state is initial Pseudo State
{
if (ThisEvent.EventType == ES_INIT) // only respond to ES_Init
{
#ifdef TEST
DB_printf(" matrix state: INIT_MATRIX, event: ES_INIT \r\n"); // debug printing
#endif
// disable analog on all SPI pins
SPISetup_BasicConfig(SPI_SPI1);
// stop and reset SPI by clearing ON
SPISetup_DisableSPI(SPI_SPI1);
// set leader
SPISetup_SetLeader(SPI_SPI1, SPI_SMP_MID);
// map SDO, SCK, SS pins
SPISetup_MapSSOutput(SPI_SPI1, SPI_RPA0);
SPISetup_MapSDOutput(SPI_SPI1, SPI_RPA1);
// map SDI pin (skip, no input)
// clear and receive buffer (skip)
// clear ENHBUF or set bit with ENHBUF
SPISetEnhancedBuffer(SPI_SPI1, true);
// set BRG
SPISetup_SetBitTime(SPI_SPI1, 100000000);
// clear SPIROV bit (skip)
// set MSTEN, CKE, CKP, MSSEN, FRMPOL
SPISetup_SetClockIdleState(SPI_SPI1, SPI_CLK_HI);
SPISetup_SetActiveEdge(SPI_SPI1, SPI_SECOND_EDGE);
SPISetup_SetXferWidth(SPI_SPI1, SPI_16BIT);
// enable SPI by setting ON
SPISetup_EnableSPI(SPI_SPI1);
// initialize LED board
while (false == DM_TakeInitDisplayStep()){}
// start with empty bar
DM_BordersOnly();
// now put the machine into the actual initial state
NextState = IDLE_MATRIX;
} // end es init event
} // end init matrix state
break;
case IDLE_MATRIX: // if the current state is idle
{
switch (ThisEvent.EventType)
{
case ES_MATRIX_ADD_BAR: // if we receive an add bar event
{
#ifdef TEST
DB_printf(" matrix state: IDLE_MATRIX, event: ADD_BAR, number: %u \r\n", BarIndex); // debug printing
#endif
DM_AddProgressBar(BarIndex); // add a bar
if (30 <= BarIndex) // all bars have been added
{
BarIndex = 1; // reset for next cycle
}
else
{
BarIndex++; // move onto next bar
}
// update state machine state
NextState = UPDATING_MATRIX;
// post a row update event
ES_Event_t newEvent;
newEvent.EventType = ES_MATRIX_UPDATE_ROW;
PostMatrixService(newEvent);
}
break;
case ES_MATRIX_RESET: // if we receive a reset event
{
#ifdef TEST
DB_printf(" matrix state: IDLE_MATRIX, event: RESET \r\n"); // debug printing
#endif
// use the borders only function in DM_Display
DM_BordersOnly(); // reset to just the borders
BarIndex = 1; // reset for next cycle
NextState = IDLE_MATRIX; // go back to idle state
}
break;
} // end event switch
} // end idle matrix state
break;
case UPDATING_MATRIX: // if the current state is updating
{
switch (ThisEvent.EventType)
{
case ES_MATRIX_UPDATE_ROW: // if we receive an update row event
{
#ifdef TEST
// DB_printf(" matrix state: UPDATING_MATRIX, updating row \r\n"); // extra debug printing
#endif
if (true == DM_TakeDisplayUpdateStep())
{
NextState = IDLE_MATRIX; // done updating, go back to start
}
else // not done, keep on updating
{
// post a row update event
ES_Event_t newEvent;
newEvent.EventType = ES_MATRIX_UPDATE_ROW;
PostMatrixService(newEvent);
NextState = UPDATING_MATRIX; // stay in same state
}
}
break;
case ES_MATRIX_RESET: // if we receive a reset event
{
#ifdef TEST
DB_printf(" matrix state: UPDATING_MATRIX, event: RESET \r\n"); // debug printing
#endif
BarIndex = 1; // reset for next cycle
// use the borders only function in DM_Display
DM_BordersOnly();
NextState = IDLE_MATRIX; // reset to idle state
}
break;
} // end switch on event type
} // end UPDATING case
break;
} // end switch on current state
// Set CurrentState to NextState
CurrentState = NextState;
#endif
// return value
return ReturnEvent;
} // end run matrix service
/****************************************************************************
Function
QueryMatrixService (adapted from QueryTemplateSM)
Parameters
None
Returns
TemplateState_t The current state of the Template state machine
Description
returns the current state of the Template state machine
Notes
Author
J. Edward Carryer, 10/23/11, 19:21
****************************************************************************/
MatrixState_t QueryMatrixService(void)
{
return CurrentState;
}
/****************************************************************************
Module
MotorService.c
Description
This service implements the state machine for the motors.
History
11-2023, Team 11, final project 218a
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
// Hardware
#include <xc.h>
// #include <proc/p32mx170f256b.h>
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "MotorService.h"
#include "PWM_PIC32.h"
#include "dbprintf.h"
#include <stdint.h>
#include <stdbool.h>
/*----------------------------- Module Defines ----------------------------*/
#define TEST // for debugging
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// state machine state
static MotorState_t CurrentState;
// with the introduction of Gen2, we need a module level Priority var as well
static uint8_t MyPriority;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
InitMotorServie (adapted from InitTemplateFSM)
Parameters
uint8_t : the priorty of this service
Returns
bool, false if error in initialization, true otherwise
Description
Saves away the priority, sets up the initial transition and does any
other required initialization for this state machine
Notes
Author
J. Edward Carryer, 10/23/11, 18:55
****************************************************************************/
bool InitMotorService(uint8_t Priority)
{
ES_Event_t ThisEvent; // local variable for event posting
MyPriority = Priority; // save priority variable
// put us into the Initial PseudoState
CurrentState = INITMOTOR;
// post the initial transition event
ThisEvent.EventType = ES_INIT;
if (ES_PostToService(MyPriority, ThisEvent) == true)
{
return true;
}
else
{
return false;
}
}
/****************************************************************************
Function
PostMotorService
Parameters
EF_Event_t ThisEvent , the event to post to the queue
Returns
boolean False if the Enqueue operation failed, True otherwise
Description
Posts an event to this state machine's queue
Notes
Author
J. Edward Carryer, 10/23/11, 19:25 (adapted)
****************************************************************************/
bool PostMotorService(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunMotorService
Parameters
ES_Event_t : the event to process
Returns
ES_Event_t, ES_NO_EVENT if no error ES_ERROR otherwise
Description
motor can be set to IDLE or SPINNING
Notes
uses nested switch/case to implement the machine.
Author
J. Edward Carryer, 01/15/12, 15:23 (adapted)
****************************************************************************/
ES_Event_t RunMotorService(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent; // local variable for event posting
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
#ifdef TEST
DB_printf(" **************************\r\n"); // debug print
DB_printf(" motor service event %u \r\n", ThisEvent.EventType); // debug print
DB_printf(" ************************** \r\n"); // debug print
#endif
switch (CurrentState)
{
case INITMOTOR: // If current state is initial Psedudo State
{
switch (ThisEvent.EventType)
{
case ES_INIT: // if we receive an init event
{
// set the pins to be outputs
// TRISBbits.TRISB9 = 0; // old h-bridge version
TRISBbits.TRISB11 = 0;
ANSELB = 0;
// how many PWM outputs to configure
PWMSetup_BasicConfig(2);
// assign the channels to the timers
PWMSetup_AssignChannelToTimer(2, _Timer2_);
// PWMSetup_AssignChannelToTimer(3, _Timer2_); // old h-bridge version
// set period
uint16_t Period_ticks = 50000; // 0.4 us per tick
PWMSetup_SetPeriodOnTimer(Period_ticks, _Timer2_);
// map PWM output pins
PWMSetup_MapChannelToOutputPin(2, PWM_RPB11);
// PWMSetup_MapChannelToOutputPin(3, PWM_RPB9); // old h-bridge version
// motors initialized to stop (0 pulse width)
PWMOperate_SetPulseWidthOnChannel(0, 2);
// PWMOperate_SetPulseWidthOnChannel(0, 3); // old h-bridge version
// now put the machine into the actual initial state
CurrentState = IDLE;
#ifdef TEST
DB_printf("Motors Init\r\n"); // debug print
#endif
} // end ES_INIT event
break;
} // end event type switch
} // end InitMotor state
break;
case IDLE: // if we're in the idle state
{
switch (ThisEvent.EventType)
{
case ES_MOTOR_START: // if we received start event
{
#ifdef TEST
DB_printf("idle state, motors starting\r\n"); // debug print
#endif
// prepare local variables
uint16_t DialValue = ThisEvent.EventParam;
uint16_t MaxDialValue = 1023;
// find the duty cycle percentage
uint8_t Percent;
Percent = (uint8_t)(80-((DialValue*80)/MaxDialValue)+20);
#ifdef TEST
DB_printf("Motors starting\r\n"); // debug print
DB_printf("Event Param: %d \r\n", DialValue); // debug print
DB_printf("Duty Cycle: %d \r\n", Percent); // debug print
#endif
// send command to motors to start
PWMOperate_SetDutyOnChannel(Percent, 2);
// update state to spinning
CurrentState = SPINNING;
} // end motor start event
break;
case ES_MOTOR_STOP: // if we receive a stop event (unexpected but for safety)
{
DB_printf("idle state - motors stopping\r\n"); // debug print
// stop (zero duty cycle)
PWMOperate_SetDutyOnChannel(0, 2);
// set the state to idle
CurrentState = IDLE;
} // end stop event
} // end event switch
} // end idle state
break;
case SPINNING: // if we're in the spinning state
{
switch (ThisEvent.EventType)
{
case ES_MOTOR_STOP: // if we receive a stop event
{
DB_printf("spinning state - motors stopping\r\n"); // debug print
// stop (zero duty cycle)
PWMOperate_SetDutyOnChannel(0, 2);
// set the state to idle
CurrentState = IDLE;
} // end stop event
break;
case ES_MOTOR_START: // if we received start event
{
#ifdef TEST
DB_printf("spinning state, motors already running \r\n"); // debug print
#endif
} // end motor start event
} // end event switch
} // end spinning state
break;
}
// return event for the framework
return ReturnEvent;
}
/****************************************************************************
Function
QueryMotorService
Parameters
None
Returns
MotorState_t The current state of the Motor state machine
Description
returns the current state of the Motor state machine
Notes
Author
J. Edward Carryer, 10/23/11, 19:21 (adapted)
****************************************************************************/
MotorState_t QueryMotorService(void)
{
return CurrentState;
}
/****************************************************************************
Module
MSC_SM.c (mobile shoe cleaner state machine)
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc 218 final project
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "TemplateFSM.h"
#include <xc.h>
#include <stdint.h>
#include <stdbool.h>
// for debug printing
#include "ES_Port.h"
#include "terminal.h"
#include "dbprintf.h"
// this module
#include "MSC_SM.h"
// from labs
#include "PIC32_SPI_HAL.h"
#include "DM_Display.h"
// other services
#include "SpeedButtonService.h"
#include "MotorService.h"
#include "MatrixService.h"
#include "LEDStepService.h"
#include "GoButtonService.h"
#include "FlashService.h"
#include "DialService.h"
#include "BeamService.h"
#include "AudioService.h"
/*----------------------------- Module Defines ----------------------------*/
// these times assume a 10.000mS/tick timing
#define ONE_SEC 1000
#define HALF_SEC (ONE_SEC / 2)
#define TWO_SEC (ONE_SEC * 2)
#define FIVE_SEC (ONE_SEC * 5)
#define TWTY_SEC (ONE_SEC * 20)
#define THRTY_SEC (ONE_SEC * 30)
#define TEST // for debugging
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority var
static uint8_t MyPriority;
static MSC_State_t CurrentState; // state machine states
static uint16_t DialValue; // keeping track of the dial value
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function: InitializeMSC_SM
Takes a priority number, returns True.
****************************************************************************/
bool InitializeMSC_SM(uint8_t Priority)
{
ES_Event_t ThisEvent; // event to post
// Print statement for monitoring
clrScrn();
#ifdef TEST
DB_printf(" init main state machine \r\n"); // debug printing
#endif
// Initialize the MyPriority variable with the passed in parameter.
MyPriority = Priority;
// Set CurrentState to be InitMSC_SM
CurrentState = InitMSC_SM;
// Post Event ES_Init to this service
ThisEvent.EventType = ES_INIT;
// all LEDS off
StepControl(ES_STEP1, 0);
StepControl(ES_STEP1, 2);
StepControl(ES_STEP1, 3);
StepControl(ES_STEP1, 4);
// post the initialization event
if (ES_PostToService(MyPriority, ThisEvent) == true)
{
return true;
}
else
{
return false;
}
// End of InitializeMSC_SM
}
/****************************************************************************
Function
PostMSC_SM
Parameters
ES_Event ThisEvent ,the event to post to the queue
Returns
bool false if the Enqueue operation failed, true otherwise
Description
Posts an event to this state machine's queue
****************************************************************************/
bool PostMSC_SM(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function
RunMSC_SM
Parameters
ES_Event : the event to process
Returns
ES_Event, ES_NO_EVENT if no error ES_ERROR otherwise
****************************************************************************/
ES_Event_t RunMSC_SM(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent; // local var event to return
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
MSC_State_t NextState; // Local Variables: NextState
NextState = CurrentState; // Set NextState to CurrentState
// Based on the state of the CurrentState variable choose one of the following blocks of code:
switch (CurrentState)
{
case InitMSC_SM: // CurrentState is initialization
{
if (ThisEvent.EventType == ES_INIT) // If ThisEvent is ES_Init
{
#ifdef TEST
DB_printf(" state machine, init state and event \r\n"); // debug printing
#endif
// turn on step 1 LED
StepControl(ES_STEP1, 1);
// play the happy noise
AudioFunction(1);
// check if shoe already in
bool CurrentBeamState = PORTBbits.RB8; // read the current state of the beam
if (0 == CurrentBeamState) // if beam is broken
{
// post a beam broken event
ES_Event_t BeamEvent;
BeamEvent.EventType = ES_IR_BREAK;
PostMSC_SM(BeamEvent);
}
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// Set NextState to Welcome
NextState = Welcome;
} // Endif
} // End init state block
break;
case Welcome: // CurrentState is welcome
{
switch(ThisEvent.EventType) // switch based on event type
{
case ES_BUTTON_DOWN: // a button was pressed
{
#ifdef TEST
DB_printf(" state machine, welcome state button event \r\n"); // debug printing
#endif
// play sad noise
AudioFunction(0);
// flash step 1
FlashFunction(1);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// stay in the same state
NextState = Welcome;
} // endif button pressed
break;
case ES_TIMEOUT: // If ThisEvent is timeout
{
#ifdef TEST
DB_printf(" state machine, welcome state timeout event \r\n"); // debug printing
#endif
// play sad noise
AudioFunction(0);
// blink the step to remind
FlashFunction(1);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// stay in the same state
NextState = Welcome;
} // endif timeout
break;
case ES_IR_BREAK: // If ThisEvent is beam broken
{
#ifdef TEST
DB_printf(" state machine, welcome state beam broken event \r\n"); // debug printing
#endif
// play happy noise
AudioFunction(1);
// turn LED 1 off and turn LED 2 on
StepControl(ES_STEP1, 0);
StepControl(ES_STEP2, 1);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// Set NextState to WaitForSpeed
NextState = WaitForSpeed;
} // endif beam broken event
break;
case ES_DIAL_CHANGED: // user turned the dial
{
#ifdef TEST
DB_printf(" state machine, welcome state, dial event \r\n"); // debug printing
DB_printf(" dial param value: %u \r\n", ThisEvent.EventParam); // debug printing
#endif
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// overrwite dial value variable
DialValue = ThisEvent.EventParam;
// stay in same state
NextState = Welcome;
} // endif dial event
break;
} // end of event type switch
} // End welcome state block
break;
case WaitForSpeed: // CurrentState is WaitForSpeed
{
switch (ThisEvent.EventType) // choose based on event type
{
case ES_TIMEOUT: // If ThisEvent is timeout
{
#ifdef TEST
DB_printf(" state machine, WfS state, timeout event \r\n"); // debug printing
#endif
// play sad noise
AudioFunction(0);
// flash step 2
FlashFunction(2);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// stay in the same state
NextState = WaitForSpeed;
} // endif timeout event
break;
case ES_BUTTON_DOWN: // if a button was pressed
{
#ifdef TEST
DB_printf(" state machine, WfS state, button event \r\n"); // debug printing
#endif
if ('g' == ThisEvent.EventParam) // if it was the go button
{
// play sad noise
AudioFunction(0);
// flash step 2
FlashFunction(2);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// stay in the same state
NextState = WaitForSpeed;
}
else if ('s' == ThisEvent.EventParam) // if it was the speed button
{
// play happy noise
AudioFunction(1);
// turn LED 2 off and LED 3 on
StepControl(ES_STEP2, 0);
StepControl(ES_STEP3, 1);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// switch to the wait for go state
NextState = WaitForGo;
}
} // endif button event
break;
case ES_IR_BEAM: // shoe removed
{
#ifdef TEST
DB_printf(" state machine, WfS state, beam event \r\n"); // debug printing
#endif
// turn LED 2 off and turn LED 1 on
StepControl(ES_STEP2, 0);
StepControl(ES_STEP1, 1);
// flash step 1
FlashFunction(1);
// play sad noise
AudioFunction(0);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// switch back to welcome
NextState = Welcome;
}
break;
case ES_DIAL_CHANGED: // user turned the dial
{
#ifdef TEST
DB_printf(" state machine, WfS state, dial event \r\n"); // debug printing
#endif
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// overrwite dial value variable
DialValue = ThisEvent.EventParam;
// stay in same state
NextState = WaitForSpeed;
} // endif dial event
break;
} // end event type switch
} // End wait for speed state block
break;
case WaitForGo: // CurrentState is waiting for go button
{
switch (ThisEvent.EventType)
{
case ES_TIMEOUT: // If ThisEvent is timeout
{
#ifdef TEST
DB_printf(" state machine, WfG state, timeout event \r\n"); // debug printing
#endif
// play sad noise
AudioFunction(0);
// flash step 3
FlashFunction(3);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// stay in the same state
NextState = WaitForGo;
} // endif timeout event
break;
case ES_BUTTON_DOWN: // if a button was pressed
{
#ifdef TEST
DB_printf(" state machine, WfG state, button event \r\n"); // debug printing
#endif
if ('g' == ThisEvent.EventParam) // if it was the go button
{
// play happy noise
AudioFunction(1);
// start the motors (send event with parameter of dial value)
ES_Event_t MotorEvent;
MotorEvent.EventType = ES_MOTOR_START;
MotorEvent.EventParam = DialValue;
PostMotorService(MotorEvent); // post to motor service
// start the matrix
ES_Event_t MatrixEvent;
MatrixEvent.EventType = ES_MATRIX_ADD_BAR;
PostMatrixService(MatrixEvent); // post to motor service
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, THRTY_SEC); // cleaning lasts 30 sec
ES_Timer_InitTimer(MATRIX_TIMER, ONE_SEC); // add one bar per sec
// turn LED 3 off
StepControl(ES_STEP3, 0);
// move to the cleaning state
NextState = Cleaning;
}
if ('s' == ThisEvent.EventParam) // if it was the speed button
{
// play sad noise
AudioFunction(0);
// flash step 3
FlashFunction(3);
// init timer for user input
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// stay in the same state
NextState = WaitForGo;
}
} // endif button pressed event
break;
case ES_IR_BEAM: // shoe removed
{
#ifdef TEST
DB_printf(" state machine, WfG state, beam event \r\n"); // debug printing
#endif
// turn LED 3 off and LED 1 on
StepControl(ES_STEP3, 0);
StepControl(ES_STEP1, 1);
// play sad noise
AudioFunction(0);
// flash step 1
FlashFunction(1);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// switch back to welcome
NextState = Welcome;
} // endif beam
break;
case ES_DIAL_CHANGED: // user turned the dial
{
#ifdef TEST
DB_printf(" state machine, WfG state, dial event \r\n"); // debug printing
#endif
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// play sad noise
AudioFunction(0);
// flash step 3
FlashFunction(3);
// overrwite dial value variable
DialValue = ThisEvent.EventParam;
// stay in same state
NextState = WaitForGo;
} // endif dial event
break;
} // end of event type switch
} // End waiting for go state block
break;
case Cleaning: // CurrentState is cleaning
{
switch (ThisEvent.EventType)
{
case ES_TIMEOUT: // timeout cleaning done
{
#ifdef TEST
// DB_printf(" state machine, cleaning state, timeout event \r\n"); // debug printing
#endif
switch (ThisEvent.EventParam)
{
case MSC_SM_TIMER: // if cleaning timer is done
{
// turn on LED 4
StepControl(ES_STEP4, 1);
// stop motor
ES_Event_t MotorEvent;
MotorEvent.EventType = ES_MOTOR_STOP;
PostMotorService(MotorEvent); // post to motor service
// play happy noise
AudioFunction(1);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// move to finished state
NextState = Finished;
}
break;
case MATRIX_TIMER: // if the matrix timer times out
{
// DB_printf(" timer matrix call \r\n"); // debug printing
// start the matrix
ES_Event_t MatrixEvent;
MatrixEvent.EventType = ES_MATRIX_ADD_BAR;
PostMatrixService(MatrixEvent); // post to motor service
// init timer
ES_Timer_InitTimer(MATRIX_TIMER, ONE_SEC);
// stay in cleaning state
NextState = Cleaning;
}
break;
}
} // endif timeout event
break;
case ES_BUTTON_DOWN: // if a button is pressed
{
#ifdef TEST
DB_printf(" state machine, cleaning state, button event \r\n"); // debug printing
#endif
// play sad noise
AudioFunction(0);
// stay in the same state
NextState = Cleaning;
} // endif button pressed
break;
case ES_DIAL_CHANGED: // if dial is turned
{
#ifdef TEST
DB_printf(" state machine, cleaning state, dial event \r\n"); // debug printing
#endif
// play sad noise
AudioFunction(0);
// overrwite dial value variable for next run
DialValue = ThisEvent.EventParam;
// stay in the same state
NextState = Cleaning;
} // endif dial event
break;
case ES_IR_BEAM: // shoe removed
{
#ifdef TEST
DB_printf(" state machine, cleaning state, beam event \r\n"); // debug printing
#endif
// turn LED 1 back on
StepControl(ES_STEP1, 1);
// stop motor
ES_Event_t MotorEvent;
MotorEvent.EventType = ES_MOTOR_STOP;
PostMotorService(MotorEvent); // post to motor service
// reset matrix to empty progress bar
ES_Event_t MatrixEvent;
MatrixEvent.EventType = ES_MATRIX_RESET;
PostMatrixService(MatrixEvent); // post to matrix service
// flash step 1
FlashFunction(1);
// play sad noise
AudioFunction(0);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// switch back to welcome
NextState = Welcome;
} // endif beam
break;
} // end event type switch
} // End cleaning state block
break;
case Finished: // CurrentState is finished cleaning
{
switch (ThisEvent.EventType)
{
case ES_TIMEOUT: // If ThisEvent is timeout
{
if (ThisEvent.EventParam == MSC_SM_TIMER) // if it's the main SM timer (foot in too long)
{
#ifdef TEST
DB_printf(" state machine, finished state, timeout event \r\n"); // debug printing
#endif
// play sad noise
AudioFunction(0);
// flash step 4
FlashFunction(4);
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
}
// stay in the same state
NextState = Finished;
} // endif timeout event
break;
case ES_BUTTON_DOWN: // if a button is pressed
{
#ifdef TEST
DB_printf(" state machine, finished state, timeout event \r\n"); // debug printing
#endif
// play sad noise
AudioFunction(0);
// flash step 4
FlashFunction(4);
// init timer for user input checking
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// stay in the same state
NextState = Finished;
} // endif button pressed
break;
case ES_IR_BEAM: // shoe removed
{
#ifdef TEST
DB_printf(" state machine, finished state, beam event \r\n"); // debug printing
#endif
// play happy noise
AudioFunction(1);
// turn off LED 4 and turn on LED 1
StepControl(ES_STEP4, 0);
StepControl(ES_STEP1, 1);
// reset matrix to empty progress bar
ES_Event_t MatrixEvent;
MatrixEvent.EventType = ES_MATRIX_RESET;
PostMatrixService(MatrixEvent); // post to matrix service
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// switch back to welcome
NextState = Welcome;
} // endif beam
break;
case ES_DIAL_CHANGED: // user turned the dial
{
#ifdef TEST
DB_printf(" state machine, finished state, dial event \r\n"); // debug printing
#endif
// init timer
ES_Timer_InitTimer(MSC_SM_TIMER, TWTY_SEC);
// play sad noise
AudioFunction(0);
// flash step 4
FlashFunction(4);
// overrwite dial value variable
DialValue = ThisEvent.EventParam;
// stay in same state
NextState = Finished;
} // endif dial event
break;
} // end of event type switch
} // End finished state block
break;
} // end switch on states
// Set CurrentState to NextState
CurrentState = NextState;
// Return ES_NO_EVENT
return ReturnEvent;
} // End of RunMSC_SM
/****************************************************************************
Function: Audio
Parameters: 0 for sad noise, 1 for happy noise
Returns
none (posts to audio service)
****************************************************************************/
void AudioFunction(uint8_t NoiseType)
{
ES_Event_t NoiseEvent;
NoiseEvent.EventType = ES_AUDIO_PLAY;
NoiseEvent.EventParam = NoiseType;
PostAudioService(NoiseEvent); // post to audio service
} // end of Audio helper function
/****************************************************************************
Function: StepControl
(streamlines posting to the LED service)
****************************************************************************/
void StepControl(ES_EventType_t EventType, bool state)
{
// make sure no LEDs are flashing
ES_Event_t FlashEvent;
FlashEvent.EventType = ES_FLASH_OFF;
PostFlashService(FlashEvent);
// send event to turn LED on or off
ES_Event_t StepEvent;
StepEvent.EventType = EventType;
StepEvent.EventParam = state;
PostLEDStepService(StepEvent); // post to LED service
}
/****************************************************************************
Function: FlashFunction
(streamlines posting to the flash service)
****************************************************************************/
void FlashFunction(uint8_t WhichLED)
{
// send event to flash an LED
ES_Event_t FlashEvent;
FlashEvent.EventType = ES_FLASH_LED;
FlashEvent.EventParam = WhichLED;
PostFlashService(FlashEvent);
// init timer for first flash transition
ES_Timer_InitTimer(FLASH_TIMER, ONE_SEC);
}
/****************************************************************************
Module
SpeedButtonService.c
* scans the speed button for user input
* if a button is pressed, sends ES_BUTTON_DOWN
* parameter of 's' for speed
History
When Who What/Why
-------------- --- --------
11/11/2023 mcc 218a final project
****************************************************************************/
/*----------------------------- Include Files -----------------------------*/
/* include header files for this state machine as well as any machines at the
next lower level in the hierarchy that are sub-machines to this machine
*/
#include "ES_Configure.h"
#include "ES_Framework.h"
#include "SpeedButtonService.h"
#include "dbprintf.h"
/*----------------------------- Module Defines ----------------------------*/
// these times assume a 10.000mS/tick timing
#define ONE_SEC 1000
#define HALF_SEC (ONE_SEC / 2)
// ~ measure this more accurately (internet said 50ms, we measured ~2ms)
// in actual testing, this value worked with our buttons
#define BOUNCETIME 10
//#define TEST // for debugging
/*---------------------------- Module Functions ---------------------------*/
/*---------------------------- Module Variables ---------------------------*/
// with the introduction of Gen2, we need a module level Priority variable
static uint8_t MyPriority;
// previous button states
bool LastSpeedButton;
// state machine steps
static Speed_Button_State_t CurrentState;
/*------------------------------ Module Code ------------------------------*/
/****************************************************************************
Function
// InitSpeedButton
// takes the priority variable to save, returns true if initialized correctly (we assume no errors)
****************************************************************************/
bool InitSpeedButton(uint8_t Priority)
{
// save the priority variable
MyPriority = Priority;
// set the button pin to be input
// RB12 aka pin 23 is the speed button
TRISBbits.TRISB12 = 1; // declare it an input
// initialize the last speed button value
// idles high (hardcoded due to hardware issue)
LastSpeedButton = 1;
// Set CurrentState to be waiting
CurrentState = Waiting2;
#ifdef TEST
DB_printf(" init speed button \r\n"); // debug printing
DB_printf(" speed button init val: %d \r\n", LastSpeedButton); // debug printing
#endif
// return boolean value
return true;
} // End of InitSpeedButton
/****************************************************************************
Function: PostSpeedButton (enqueues to this service)
****************************************************************************/
bool PostSpeedButton(ES_Event_t ThisEvent)
{
return ES_PostToService(MyPriority, ThisEvent);
}
/****************************************************************************
Function: RunSpeedButton (state machine that debounces the button signals)
****************************************************************************/
ES_Event_t RunSpeedButton(ES_Event_t ThisEvent)
{
ES_Event_t ReturnEvent;
ReturnEvent.EventType = ES_NO_EVENT; // assume no errors
Speed_Button_State_t NextState; // Local Variables: NextState
NextState = CurrentState; // Set NextState to CurrentState
// Based on the state of the CurrentState variable choose one of the following blocks of code:
switch (CurrentState)
{
case Waiting2: // current state is waiting
{
if (ThisEvent.EventType == ES_SPEED_RISE_DETECTED) // if a rise was detected
{
// start debounce rise timer
ES_Timer_InitTimer(SPEED_BTN_TIMER, BOUNCETIME);
#ifdef TEST
DB_printf(" speed timer init \r\n"); // debug printing
#endif
// Set NextState to DebouncingRise
NextState = DebouncingRise2;
#ifdef TEST
DB_printf(" speed waiting rise detected \r\n"); // debug printing
#endif
}
if (ThisEvent.EventType == ES_SPEED_FALL_DETECTED) // if a fall was detected
{
// start debounce fall timer
ES_Timer_InitTimer(SPEED_BTN_TIMER, BOUNCETIME);
#ifdef TEST
DB_printf(" speed waiting rise detected \r\n"); // debug printing
#endif
// Set NextState to DebouncingFall
NextState = DebouncingFall2;
#ifdef TEST
DB_printf(" speed waiting fall detected \r\n"); // debug printing
#endif
}
} // end waiting 2 state
break;
case DebouncingFall2: // current state is debouncing fall
{
if (ThisEvent.EventType == ES_SPEED_RISE_DETECTED) // if a rise was detected
{
// it was bouncy, reset to waiting
NextState = Waiting2;
#ifdef TEST
DB_printf(" speed false fall \r\n"); // debug printing
#endif
}
if (ThisEvent.EventType == ES_TIMEOUT) // if a timeout happened
{
#ifdef TEST
DB_printf(" speed timeout, param: %d \r\n", ThisEvent.EventParam); // debug printing
#endif
// it was a real button press, post about it
ES_Event_t ButtonAlert;
ButtonAlert.EventType = ES_BUTTON_UP;
ButtonAlert.EventParam = 's'; // s for speed
PostMSC_SM(ButtonAlert); // post to the main state machine
#ifdef TEST
DB_printf(" speed real fall \r\n"); // debug printing
#endif
// reset to waiting for next button press
NextState = Waiting2;
}
} // end debouncing fall 2 state
break;
case DebouncingRise2: // current state is debouncing rise
{
if (ThisEvent.EventType == ES_SPEED_FALL_DETECTED) // if a fall was detected
{
// it was bouncy, reset to waiting
NextState = Waiting2;
#ifdef TEST
DB_printf(" speed false rise \r\n"); // debug printing
#endif
}
if (ThisEvent.EventType == ES_TIMEOUT) // if a timeout was detected
{
#ifdef TEST
DB_printf(" speed timeout, param: %d \r\n", ThisEvent.EventParam); // debug printing
#endif
// it was a real button press, post about it
ES_Event_t ButtonAlert;
ButtonAlert.EventType = ES_BUTTON_DOWN;
ButtonAlert.EventParam = 's'; // s for speed
PostMSC_SM(ButtonAlert); // post to the main state machine
#ifdef TEST
DB_printf(" speed real rise \r\n"); // debug printing
#endif
// reset to waiting for next button press
NextState = Waiting2;
}
} // end debouncing rise 2 state
break;
} // end case switch
// update state machine state
CurrentState = NextState;
} // end Run SpeedButton
/****************************************************************************
Function: CheckSpeedButton (event checker listening for changes in the buttons)
****************************************************************************/
bool CheckSpeedButton(void)
{
// local variables to return/post
bool ReturnVal = false;
ES_Event_t ThisEvent;
// sample the current button states and store in temporary vars
bool CurrentSpeedButton;
CurrentSpeedButton = PORTBbits.RB12;
// if the speed button has changed
if (LastSpeedButton != CurrentSpeedButton)
{
#ifdef TEST
DB_printf(" speed button changed \r\n"); // debug printing
DB_printf(" speed button value: %d \r\n", CurrentSpeedButton); // debug printing
#endif
ReturnVal = true; // update the return value
if (CurrentSpeedButton == 1) // if the button line is high
{
// Post button event (rise detected) to this service
ThisEvent.EventType = ES_SPEED_RISE_DETECTED;
PostSpeedButton(ThisEvent);
}
else // else (button line is low)
{
// post button event (fall detected) to this service
ThisEvent.EventType = ES_SPEED_FALL_DETECTED;
PostSpeedButton(ThisEvent);
}
// overwrite the previous button values
LastSpeedButton = CurrentSpeedButton;
}
return ReturnVal; // return the boolean
} // End of Check Speed Button
/*------------------------------- Footnotes -------------------------------*/
/*------------------------------ End of file ------------------------------*/
Downloadable code may be found in the Google Drive folder above. The files may also be downloaded individually using the buttons below. In addition to these files, this project uses the ME218 Events and Services framework, the PWM library, the AD library, and the SPI HAL.