This service is responsible for displaying animations for the eyes of the cat.
Animations help the user understands if the cat appreciates the action of the user.
# Constants
Create_constant PATTERN_OPEN as 0
Create_constant PATTERN_CLOSED_LINE as 1
Create_constant PATTERN_HALF_BLINK as 2
Create_constant PATTERN_ANGRY as 3
Create_constant PATTERN_HALF_ANGRY as 4
Create_constant PATTERN_HAPPY as 5
Create_constant PATTERN_NIRVANA as 6
Create_constant PATTERN_HALF_NIRVANA as 7
Create_constant PATTERN_DOT as 8
Create_constant PATTERN_HEART as 9
Create_constant PATTERN_HALF_HEART as 10
Create_constant PATTERN_SAD as 11
Create_constant PATTERN_1_SAD as 12
Create_constant PATTERN_2_SAD as 13
Create_constant ANIM_OPEN_BLINKING as 0
Create_constant ANIM_SNEAKING as 1
Create_constant ANIM_WELCOME as 0
Create_constant ANIM_INACTIVE as 1
Create_constant ANIM_ACTIVE as 0
Create_constant ANIM_HAPPY as 3
Create_constant ANIM_ANGRY as 2
Create_constant ANIM_NIRVANA as 4
Create_constant ANIM_SAD as 5
Create_constant MAX_NB_STEPS_IN_ANIMATION as 10
Create_constant NB_PLAYS_ANGRY as 8
Create_constant NB_PLAYS_HAPPY as 3
Create_constant NB_PLAYS_SAD as 5
# Variables
Declare CurrentState as State
Declare animation as Animation_t
Declare animation_step as uint8_t
Declare animation_count as uint8_t
Declare index_animation as uint8_t
# Patterns
# Turned off LEDs are represented as 0
# Turned on LEDs are represented as 1
Instantiate uint8_t patterns[][8] as {
# PATTERN_OPEN
{ ,
████████ ,
██ ██ ,
██ ████ ██ ,
██ ████ ██ ,
██ ██ ,
████████ ,
},
# PATTERN_CLOSED_LINE
{ ,
,
,
,
████████████ ,
,
,
},
# PATTERN_HALF_BLINK
{ ,
,
████████████ ,
██ ████ ██ ,
██ ████ ██ ,
████████████ ,
,
},
# PATTERN_ANGRY
{ ██████ ,
██ ██,
██ ██,
██ ████ ██,
██ ████ ██,
██ ██,
██ ██ ,
████████ },
# PATTERN_HALF_ANGRY
{ ██████ ,
██ ██,
██ ██,
██ ████ ██,
██ ████ ██,
██ ██,
██ ██ ,
████████ },
# PATTERN_HAPPY
{ ,
,
████ ,
██ ██ ,
██ ██ ,
██ ██,
,
},
# PATTERN_NIRVANA
{ ██ ██ ██ ,
██ ████ ,
████ ,
████████████████,
████ ,
██ ████ ,
██ ██ ██ ,
██ ██ ██},
# PATTERN_HALF_NIRVANA
{ ,
██ ████ ,
████ ,
████████████ ,
████ ,
██ ████ ,
,
},
# PATTERN_DOT
{ ,
,
,
████ ,
████ ,
,
,
},
# PATTERN_HEART
{ ,
████ ████ ,
██ ██ ██ ,
██ ██ ,
██ ██ ,
██ ██ ,
██ ,
},
# PATTERN_HALF_HEART
{ ,
,
██████ ,
██ ██ ,
██ ██ ,
██ ,
,
},
# PATTERN_SAD
{ ,
██████,
██████ ,
██████ ,
██████ ,
██████ ,
██████ ,
},
# PATTERN_██_SAD
{ ,
,
██████████,
██████████ ,
██████████ ,
██████████ ,
,
},
# PATTERN_2_SAD
{ ,
,
,
██████████,
██████████ ,
,
,
},
}
# Animations
Instantiate Animation_t animations[] as {
# ANIM_OPEN_BLINKING
{4,
{PATTERN_OPEN,PATTERN_HALF_BLINK,PATTERN_CLOSED_LINE,PATTERN_HALF_BLINK},
{1000,80,80,80}},
# ANIM_SNEAKING
{8,
{PATTERN_CLOSED_LINE,PATTERN_HALF_BLINK,PATTERN_OPEN,PATTERN_HALF_BLINK,PATTERN_CLOSED_LINE,PATTERN_HALF_BLINK,PATTERN_OPEN,PATTERN_HALF_BLINK},
{3000,80,450,80,200,80,200,80}},
# ANIM_ANGRY
{4,
{PATTERN_HALF_ANGRY, PATTERN_ANGRY, PATTERN_HALF_ANGRY, PATTERN_ANGRY},
{80,80,80,80}},
# ANIM_HAPPY
{2,
{PATTERN_HAPPY, PATTERN_CLOSED_LINE},
{500,80}},
# ANIM_NIRVANA
{4,
{PATTERN_HEART, PATTERN_HALF_HEART, PATTERN_DOT, PATTERN_HALF_HEART},
{1000,80,80,80}},
# ANIM_SAD
{6,
{PATTERN_SAD, PATTERN_1_SAD, PATTERN_2_SAD, PATTERN_DOT, PATTERN_2_SAD, PATTERN_1_SAD},
{400,80,80,80,80,80}},
}
# An Animation is a serie of patterns associated to a timing
Define Animation_t:
uint8_t steps
uint8_t pattern[MAX_NB_STEPS_IN_ANIMATION];
uint16_t duration[MAX_NB_STEPS_IN_ANIMATION];
Enddefine
# Reverses a byte (LSB becomes MSB for example)
Function reverse(uint8_t b) {
Set b to (b & 0xF0) >> 4 | (b & 0x0F) << 4
Set b to (b & 0xCC) >> 2 | (b & 0x33) << 2
Set b to (b & 0xAA) >> 1 | (b & 0x55) << 1
Return b;
EndFunction
# Returns the byte corresponding to a given line of a given pattern
Function getPatternLine(uint8_t pattern_index, uint8_t line_num):
Return patterns[pattern_index][line_num]
EndFunction
# Given a pattern, set the pattern to the first display module and the mirrored pattern to thse second module
Function SetMirroredPattern(uint8_t pattern_index) {
For WhichRow from 0 to NUM_ROWS:
Set DM_Display[WhichRow].ByBytes[0] to getPatternLine(pattern_index, WhichRow)
Set DM_Display[WhichRow].ByBytes[1] to reverse(getPatternLine(pattern_index, WhichRow));
Endfor
Endfunction
# Initializes all variables to start displaying a given pattern
Function StartDisplayingPattern(uint8_t pattern_index):
Call SetMirroredPattern(pattern_index)
Post_to EyesService ES_EYES_SCROLL
Endfunction
# Initializes all variables ot start displaying a given animation
Function StartDisplayingAnim(uint8_t anim_index) {
Set animation to animations[anim_index]
Set animation_step to 0
Set animation_count to 0
Set index_animation to anim_index;
Call StartDisplayingPattern(animation.pattern[0])
Endfunction
Function InitEyesService:
# ===== SPI INIT =====#
Call SPISetup_BasicConfig(SPI_SPI1) # Clear the ON bit and set the basic configuration
Call SPISetup_SetLeader(SPI_SPI1,SPI_SMP_MID) # Set the master mode
SPI1BUF; # Clear the receive buffer in case there is anything more
Set ANSELA to 0 # Disable the analog function on all SPI pins (ANSEL A and B)
Set ANSELB to 0 # Disable the analog function on all SPI pins (ANSEL A and B)
Call SPISetup_MapSSOutput(SPI_SPI1, SPI_RPA0) # Set SS output
Call SPISetup_MapSDOutput(SPI_SPI1, SPI_RPA1) # Set SDO output
Call TRISBbits.TRISB14 = 0 # Set SCK output
Call SPISetup_SetXferWidth(SPI_SPI1, SPI_16BIT) # Set 16 bit transfer
Call SPISetup_SetActiveEdge(SPI_SPI1,SPI_SECOND_EDGE) # Set up CKE as 1
Call SPISetup_SetClockIdleState(SPI_SPI1,SPI_CLK_HI) # Set up CKP as 0
Call SPISetEnhancedBuffer(SPI_SPI1, true) # Set the enhanced buffer mode
Call SPISetup_SetBitTime(SPI_SPI1,10000) # Set up bit-clock to 100 Hz, 100 kHz = 10000 ns period
Call SPISetup_EnableSPI(SPI_SPI1) # Now enable the SPI operation
# Initialize FSM
Set CurrentState to InitEyesDisplay;
Post_to EyesService ES_INIT
Endfunction
Function RunEyesService(event):
Instantiate NextState to CurrentState
If type of event is ES_EYES_SET_ANIM:
If parameter of event < SizeOf(animations):
Call StartDisplayingAnim(ThisEvent.EventParam)
Set NextState to ScollingEyesDisplay
Else:
Raise Error "out of bounds"
Endif
Endif
Switch CurrentState:
case InitEyesDisplay:
If type of event is ES_INIT:
If not DM_TakeInitDisplayStep():
Post_to EyesService ES_INIT
Else:
Call StartDisplayingAnim(ANIM_OPEN_BLINKING)
Set NextState to ScollingEyesDisplay
Endif
Endif
case ScollingEyesDisplay:
If type of event is ES_EYES_SCROLL:
If not DM_TakeDisplayUpdateStep():
Post_to EyesService ES_EYES_SCROLL
Else:
Start_timer EyesAnimationYimer to animation.duration[animation_step]
Set animation_step to animation_step + 1
Set NextState to EyesDisplayWaitNextAnimationStep
If animation_step >= animation.nb_steps
Set animation_step to 0
Set animation_count to animation_count + 1
If index_animation is ANIM_HAPPY and animation_count >= NB_PLAYS_HAPPY:
Call StartDisplayingAnim(ANIM_OPEN_BLINKING);
Set NextState to ScollingEyesDisplay
ElseIf index_animation == ANIM_ANGRY and animation_count >= NB_PLAYS_ANGRY:
Call StartDisplayingAnim(ANIM_OPEN_BLINKING);
Set NextState to ScollingEyesDisplay
ElseIf index_animation is ANIM_SAD andanimation_count >= NB_PLAYS_SAD:
Call StartDisplayingAnim(ANIM_INACTIVE)
Set NextState to ScollingEyesDisplay
Endif
Endif
Endif
Endif
case EyesDisplayWaitNextAnimationStep:
If type of event is ES_TIMEOUT and parameter is EyesAnimationTimer:
Call StartDisplayingPattern(animation.pattern[animation_step])
Set NextState to ScollingEyesDisplay
Endif
Endswitch
Set CurrentState to NextState
Endfunction