This service is responsible for controlling the hourglass and more generally time the maximum duration for the user to complete all 6 actions. The Master Service might require at any time to reset the Hourglass Service. As this is a physical hourglass, resetting it means waiting for the sand to finish dropping. The service keeps track of the elapsed timer and determines when resetting if it is faster to wait in the current state or to flip the hourglass (for example, after 20 seconds, it will flip back the hourglass and wait only 20 seconds to reset. after 40 seconds it will wait 20 seconds in the current position).
# Constants
Create_constant DURATION_FLIPPING as 800 # milliseconds
Create_constant STEPS_FOR_RESET as 32
Create_constant DURATION_HOURGLASS as 64500 # milliseconds
Create_constant SPEED_HOURGLASS as 125 # out of 255
# Variables
Declare CurrentState as State
Declare positionIs0Not180 as bool
Declare reset_ticks as uint8_t
Function Flip:
Instantiate event
Set type of event to ES_MOVE_TO
If positionIs0Not180:
Set parameter of event to 180
Else:
Set parameter of event to 0
Endif
Post_to HourglassServo event
Set positionIs0Not180 to not positionIs0Not180
Endfunction
Function InitHourGlassService(uint8_t Priority):
# Initialize module variable
Set CurrentState to InitHourGlassState
Set positionIs0Not180 to true
Post_to HourglassServo ES_SET_SPEED with parameter SPEED_HOURGLASS
Post_to HourglassService ES_INIT
Endfunction
Function RunHourGlassService(event):
Set NextState to CurrentState
Switch CurrentState:
case InitHourGlassState:
If type of event is ES_INIT:
Set NextState to IdleHourGlass
Post_to HourglassServo ES_MOVE_TO with parameter 0
Endif
case IdleHourGlass:
If type of event is ES_HOURGLASS_START:
Call Flip()
Start_timer HourGlassTimer to DURATION_FLIPPING + DURATION_HOURGLASS
Start_timer HourGlassResetTimer to DURATION_FLIPPING + DURATION_HOURGLASS / STEPS_FOR_RESET
Set NextState to Timing
Set reset_ticks to 0
ElseIf type of event is ES_HOURGLASS_RESET:
Post_to MasterService ES_HOURGLASS_RESET_COMPLETED
Endif
case Timing: {
If type of event is ES_TIMEOUT and parameter is HourGlassResetTimer:
Set reset_ticks to reset_ticks + 1
Start_timer HourGlassResetTimer with duration DURATION_HOURGLASS / STEPS_FOR_RESET
ElseIf type of event is ES_TIMEOUT and parameter is HourGlassTimer:
Post_to ES_HOURGLASS_TIMEOUT
Set NextState to IdleHourGlass
ElseIf type of event is ES_HOURGLASS_RESET:
Instantiate durationResetIfFLip to DURATION_FLIPPING + (reset_ticks+1) * DURATION_HOURGLASS / STEPS_FOR_RESET
Instantiate durationResetIfNotFLip to (STEPS_FOR_RESET-reset_ticks) * DURATION_HOURGLASS / STEPS_FOR_RESET
If durationResetIfFLip < durationResetIfNotFLip:
Call Flip()
Start_timer HourGlassResetTimer with duration durationResetIfFLip
Else:
Start_timer HourGlassResetTimer with duration durationResetIfNotFLip
Endif
Set NextState to ResettingHourGlass
Endif
case ResettingHourGlass:
If type of event is ES_TIMEOUT and parameter is HourGlassResetTimer:
Post_to MasterService ES_HOURGLASS_RESET_COMPLETED
Set NextState to IdleHourGlass
Endif
Endswitch
Set CurrentState to NextState
Endfunction