This service is responsible for the coordination of all the services and tracking the current state of the cat. After booting up, the first press of the button on the cat's belly will trigger a welcome introduction. Then a second press will actually start the game. The Master Service will then generates actions for the user to complete, and call the concerned services to activate them. It will then either receive a confirmation message affirming that the user completed the task and in that case, it will bring the cat closer to Nirvana, or stop the action after some time. To give the user some feedback, the Master Service will show some eye animations, turn on and off some LEDs, play some sound, wag the cat's tail and maybe dispense a chocolate.
# Constants
Create_constant DELAY_BLINK as 400 # milliseconds
Create_constant DELAY_WELCOME as 13500 # milliseconds
Create_constant DELAY_MAX_INACTIVE as 30000 # milliseconds
Create_constant DELAY_BETWEEN_TASKS as 2700 # milliseconds
Create_constant DELAY_NIRVANA as 10500 # milliseconds
Create_constant TAIL_SPEED_WELCOME as 140 # out of 255
Create_constant TAIL_SPEED_ACTIVE as 100 # out of 255
Create_constant TAIL_SPEED_NIRVANA as 220 # out of 255
Create_constant TAIL_SPEED_HAPPY as 190 # out of 255
Create_constant DELAY_TO_FEED as 8000 # milliseconds
Create_constant DELAY_TO_PET as 15000 # milliseconds
Create_constant DELAY_TO_PAW as 12000 # milliseconds
Create_constant NB_TASKS_TO_COMPLETE as 6
# Variables
Declare CurrentState as State
Instantiate stateLED to 0
Instantiate lastTask to 0
Instantiate currentTask to 0
Instantiate sequence[] to {2,1,2,1,3,1,3,2,1,3,1}
Instantiate pos_in_sequence to 0
Instantiate tasks_completed to 0
# Display a given animation
Function DisplayAnim(uint8_t animation_index):
Post_to EyesService ES_EYES_SET_ANIM with parameter animation_index
Endfunction
# Flips the hourglass
Function StartHourglass:
Post_to HourGlassService ES_HOURGLASS_START
Endfunction
# Resets the hourglass
Function ResetHourglass:
Post_to HourGlassService ES_HOURGLASS_RESET
Endfunction
# Starts to wag the tail
Function StartTail:
ES_Event_t event
event.EventType = ES_TAIL_START_OSCILLATING
PostServoTailService(event)
Endfunction
# Sets the wagging speed of the tail
Function SetTailSpeed(uint8_t tail_speed):
Post_to TailService ES_TAIL_SET_SPEED with parameter tail_speed
Endfunction
# Stops the wagging of the tail
Function StopTail:
Post_to TailService ES_TAIL_MOVE_TO with parameter 90
Endfunction
# Sets the Petting service as active
Function ActivatePettingService:
Post_to PressureSensorService ES_PETTING_ACTIVATE
Endfunction
# Sets the Feeding service as active
Function ActivateFeedingService:
Post_to FeedingService ES_FEEDING_ACTIVATE
Endfunction
# Sets the Pawmoving service as active
Function ActivatePawMovingService:
Post_to PawMovingService ES_PAWMOVING_ACTIVATE
Endfunction
# Dispenses a chocolate
Function Dispense:
Post_to DispenserService ES_DISPENSE
Endfunction
# Send a signal to the second PIC to play an audio (or turn on an LED)
Function PlayAudio(uint8_t audio):
Post_to SignalSendingService ES_PLAY_AUDIO with parameter audio
Endfunction
# Turns on the next progress LED
Function IncreaseLED:
Post_to SignalSendingService ES_PLAY_AUDIO with parameter 11
Endfunction
# Used when the user does an action to reset the inactive timer
Function SetMasterActive:
Post_to MasterService ES_DOING_STUFF
Endfunction
# Resets the Inactive timer
Function ResetInactiveTimer:
Stop_timer InactiveTimer
Start_timer InactiveTimer with duration DELAY_MAX_INACTIVE
Endfunction
# Sends a signal to the second PIC to control the state LED
Function SetStateLED:
Post_to SignalSendingService ES_PLAY_AUDIO with parameter 13 - stateLED
Endfunction
# Blinks the state LED
Function BlinkStateLED:
Call SetStateLED()
Set stateLED to 1 - stateLED
Start_timer BlinkTimer with duration DELAY_BLINK
Endfunction
# Do all the necessary steps to go to reset
Function ResetMaster(bool reset_hg):
Post_to ALL_SERVICES ES_FAIL
Set pos_in_sequence to 0
Set tasks_completed to 0
Set lastTask to 0
Set currentTask to 0
Call StopTail()
If reset_hg:
Call ResetHourglass()
Set CurrentState to ResettingMaster
Call DisplayAnim(ANIM_INACTIVE)
Set stateLED to 0
Else:
Set CurrentState to BeforeWelcome
Call DisplayAnim(ANIM_SAD)
Set stateLED to 1
Endif
Call SetStateLED()
Call PlayAudio(15) # Turns off all the LEDs
Endfunction
# Do all the necessary steps to go to inactive
Function GoToInactive(bool reset_anim):
Post_to ALL_SERVICES ES_FAIL
Set pos_in_sequence to 0
Set tasks_completed to 0
Set lastTask to 0
Set currentTask to 0
If reset_anim:
Call DisplayAnim(ANIM_INACTIVE)
Endif
Call StopTail()
Start_timer BlinkTimer with duration DELAY_BLINK
Call PlayAudio(14) # Stops all the songs
Call PlayAudio(15) # Turns off all the LEDs
Endfunction
Function InitMasterService:
Set BUTTON_TRIS to 1 # Input
Set pos_in_sequence to 0 # Sets the first action to do by the user
Call PlayAudio(14) # Stops all the songs
Call PlayAudio(15) # Turns off all the LEDs
# Posts the initial transition in 2 seconds
Set CurrentState to InitMasterState
Start_timer MasterTimer with duration 2000
Endfunction
Function RunMasterService(event):
Instantiate NextState to CurrentState
If type of event is ES_TIMEOUT and parameter is InactiveTimer:
Call ResetMaster(true)
Return
Endif
Switch CurrentState:
case InitMasterState:
If type of event is ES_TIMEOUT:
Set NextState to BeforeWelcome
Call PlayAudio(AUDIO_HAPPY)
Call DisplayAnim(ANIM_INACTIVE)
Call StopTail()
Call ResetHourglass()
Endif
case BeforeWelcome:
If type of event is ES_BUTTON_PRESSED:
Set NextState to WelcomeState
Post_to MasterService ES_START_WELCOMING
Endif
case WelcomeState:
If type of event is ES_START_WELCOMING:
Call PlayAudio(AUDIO_WELCOME)
Call DisplayAnim(ANIM_WELCOME)
Call SetTailSpeed(TAIL_SPEED_WELCOME)
Call StartTail()
Set stateLED to 0
Call SetStateLED()
Start_timer MasterTimer with duration DELAY_WELCOME
ElseIf type of event is ES_TIMEOUT and parameter is MasterTimer:
Set NextState to InactiveMaster
Call GoToInactive(false)
Endif
case InactiveMaster:
If type of event is ES_BUTTON_PRESSED:
Call PlayAudio(AUDIO_PET_ME)
Set stateLED to 1
Call SetStateLED()
Call StartHourglass()
Call DisplayAnim(ANIM_ACTIVE)
Call SetTailSpeed(TAIL_SPEED_ACTIVE)
Call StartTail()
Set NextState to InBetweenTasks
Call ResetInactiveTimer()
Start_timer MasterEndTaskTimer with duration DELAY_BETWEEN_TASKS
ElseIf type of event is ES_TIMEOUT and parameter is BlinkTimer:
Call BlinkStateLED()
Endif
case ResettingMaster:
If type of event is ES_HOURGLASS_RESET_COMPLETED:
Set NextState to InactiveMaster
Call GoToInactive(true)
Endif
case StartingTask:
If type of event is ES_HOURGLASS_TIMEOUT:
Call ResetMaster(false)
Set NextState to BeforeWelcome
ElseIf type of event is ES_GENERATE_NEW_TASK:
If tasks_completed >= NB_TASKS_TO_COMPLETE:
Set NextState to Nirvana
Post_to MasterService ES_NIRVANA_REACHED
Else:
Set currentTask to lastTask
Set currentTask to sequence[pos_in_sequence]
Set pos_in_sequence to pos_in_sequence + 1
If pos_in_sequence >= sizeof(sequence):
Set pos_in_sequence to 0
Endif
If currentTask is 1:
Call PlayAudio(AUDIO_HUNGRY)
Start_timer MasterEndTaskTimer with duration DELAY_TO_FEED
Post_to FeedingService ES_FEEDING_ACTIVATE
ElseIf currentTask is 2:
Call PlayAudio(AUDIO_PET_ME)
Start_timer MasterEndTaskTimer with duration DELAY_TO_PET
Post_to PressureSensorService ES_PETTING_ACTIVATE
ElseIf currentTask is 3:
Call PlayAudio(AUDIO_LET_ME_PET_YOU)
Start_timer MasterEndTaskTimer with duration DELAY_TO_PAW
Post_to PawMovingService ES_PAWMOVING_ACTIVATE
Endif
Set NextState to WaitingForTask
Call SetTailSpeed(TAIL_SPEED_ACTIVE)
Endif
Endif
case WaitingForTask:
If type of event is ES_HOURGLASS_TIMEOUT:
Call ResetMaster(false)
Set NextState to BeforeWelcome
ElseIf type of event is ES_TIMEOUT and parameter is MasterEndTaskTimer:
Set NextState to StartingTask
Set lastTask to currentTask
Post_to ALL_SERVICES ES_FAIL # Stops all task services
Post_to MasterService ES_GENERATE_NEW_TASK # Generate a new task to complete
ElseIf type of event is ES_DOING_STUFF:
Call ResetInactiveTimer()
ElseIf (type of event is ES_FEEDING_COMPLETED and currentTask is 1)
or (type of event is ES_PETTING_COMPLETED and currentTask is 2)
or (type of event is ES_PAWMOVING_COMPLETED and currentTask is 3):
Set tasks_completed to tasks_completed + 1
If currentTask is not 1:
Call PlayAudio(AUDIO_HAPPY)
Endif
Call IncreaseLED()
Set lastTask to currentTask
Stop_timer MasterEndTaskTimer
Set NextState to InBetweenTasks
ES_Timer_InitTimer(MasterEndTaskTimer, DELAY_BETWEEN_TASKS)
Call ResetInactiveTimer()
# Display happiness
Call DisplayAnim(ANIM_HAPPY)
Call SetTailSpeed(TAIL_SPEED_HAPPY)
# Stops all task services
Post_to ALL_SERVICES ES_FAIL
Endif
case InBetweenTasks:
If type of event is ES_HOURGLASS_TIMEOUT:
Call ResetMaster(false)
Set NextState to BeforeWelcome
ElseIf type of event is ES_TIMEOUT and parameter is MasterEndTaskTimer:
Set NextState to StartingTask
# Generate a new task to complete
Post_to MasterService ES_GENERATE_NEW_TASK
Endif
case Nirvana:
If type of event is ES_NIRVANA_REACHED:
Call PlayAudio(AUDIO_NIRVANA)
Call DisplayAnim(ANIM_NIRVANA)
Call SetTailSpeed(TAIL_SPEED_NIRVANA)
Call Dispense()
Start_timer MasterEndTaskTimer with duration DELAY_NIRVANA
ElseIf type of event is ES_TIMEOUT and parameter is MasterEndTaskTimer:
Call Call ResetMaster(true)
Set NextState to BeforeWelcome
Endif
Endswitch
Set CurrentState to NextState
Endfunction