Created
June 20, 2012 06:01
-
-
Save nlguillemot/2958369 to your computer and use it in GitHub Desktop.
CSC 230 Assignment 3 - Treadmill
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@ CSC230 Spring 2012 -- Treadmill program | |
@ Author: Nicolas Guillemot | |
@ Student ID number: V00695164 | |
@ Global constants for physics | |
@ default value for weight | |
.equ DFT_WEIGHT, 100 @ lbs | |
@ minimum value for weight (see WeightMax for maximum) | |
.equ WEIGHT_MIN, 50 @ lbs | |
@ default value for target speed | |
.equ DFT_TARGET_SPEED, 20 @ .1 decimal fixed point. mph | |
@ minimum value for target speed | |
.equ TARGET_SPEED_MIN, 0 @ .1 decimal fixed point. mph | |
@ maximum value for target speed | |
.equ TARGET_SPEED_MAX, 150 @ .1 decimal fixed point. mph | |
@ Global constants for graphics | |
@ time interval in milliseconds at which screen is redrawn | |
.equ REDRAW_TIME, 100 @ ms | |
@ time interval in milliseconds at which lyrics are scrolled by one character | |
.equ LYRICS_TIME, 200 @ ms | |
@ row where lyrics are displayed | |
.equ LYRICS_ROW, 1 | |
@ Global constants for travel information | |
@ time interval in milliseconds at which speed is updated in running state | |
.equ SPEED_UPDATE_INTERVAL, 100 @ ms | |
@ time for delay between flicker of LEDs during running states | |
.equ LED_FLICKER_INTERVAL, 100 @ ms | |
@ .1f mphs increased per speed update interval in running state | |
.equ RUNNING_SPEED_INCR, 1 @ dmph | |
@ 1.f mphs increased per speed update interval in shutdown state | |
.equ SHUTDOWN_SPEED_INCR, 5 @ dmph | |
@ 1.f mphs increased per speed update interval in pausing state | |
.equ PAUSING_SPEED_INCR, 1 @ dmph | |
@ Global constants for button indices. Note indices, not bitmasks. | |
@ black buttons | |
.equ PAUSE_KEY, 0x1 | |
.equ EMERGENCY_STOP_KEY, 0x0 | |
@ blue buttons | |
.equ START_KEY, 0x0 | |
.equ RESET_KEY, 0x1 | |
.equ SPEED_DOWN_2_KEY, 0x4 | |
.equ SPEED_DOWN_1_KEY, 0x5 | |
.equ SPEED_UP_1_KEY, 0x6 | |
.equ SPEED_UP_2_KEY, 0x7 | |
.equ WEIGHT_DOWN_2_KEY, 0x8 | |
.equ WEIGHT_DOWN_1_KEY, 0x9 | |
.equ WEIGHT_UP_1_KEY, 0xA | |
.equ WEIGHT_UP_2_KEY, 0xB | |
.equ SWITCH_OFF_KEY, 0xF | |
@ Global constants for SSD states | |
.equ SSD_OFF, 0x00 | |
.equ SSD_PAUSING, 0xC7 | |
.equ SSD_PAUSED, 0xD7 | |
.equ SSD_RUNNING, 0xC3 | |
.equ SSD_STOPPED, 0x8A | |
.equ SSD_SHUTDOWN, 0xAB | |
@ Global constants for LED states bit patterns | |
.equ LED_NONE, 0x0 | |
.equ LED_RIGHT, 0x1 | |
.equ LED_LEFT, 0x2 | |
.equ LED_BOTH, 0x3 | |
@ Global constants for screen dimensions | |
.equ SCREEN_WIDTH, 40 | |
.equ SCREEN_HEIGHT, 15 | |
@ Global constants for HUD stuff positioning | |
@ row at which informations begins being displayed | |
.equ INFORMATION_BEGIN, 2 | |
@ row at which button information begins being displayed | |
.equ BUTTON_INFO_BEGIN, 9 | |
@ maximum width of an info string such as "Weight: 100" | |
.equ INFO_WIDTH, 22 | |
@ size of the indentation after a number like weight and the units | |
.equ INFO_INDENT_WIDTH, 2 | |
@ Software interrupts for embest board | |
@ ends the execution of the program | |
.equ SWI_Exit, 0x11 | |
@ stores current ticks in r0 in milliseconds | |
.equ SWI_GetTicks, 0x6d | |
@ stores bitset of pressed blue buttons in r0 | |
.equ SWI_CheckBlue, 0x203 | |
@ stores the bitset of pressed black buttons in r0 | |
.equ SWI_CheckBlack, 0x202 | |
@ sets state of SSD to value in r0 | |
.equ SWI_SetSEG8, 0x200 | |
@ sets state of LEDs to value in r0 | |
.equ SWI_SetLED, 0x201 | |
@ clears the LCD screen | |
.equ SWI_BlankLCD, 0x206 | |
@ prints string in r2 to coordinate (r0, r1) | |
.equ SWI_PrintString, 0x204 | |
@ prints string in r1 to file handle in r0 | |
.equ SWI_PutString, 0x69 | |
@ prints character in r0 to stdout | |
.equ SWI_PutCharacter, 0x0 | |
@ stdout | |
.equ Stdout, 0x1 | |
.section .rodata | |
@ lookup table to convert integers offsets to digit characters | |
DigitToCharacterLookup: | |
.ascii "0123456789" | |
@ strings used to display the HUD | |
TreadmillHeaderString: | |
.asciz "Treadmill--Nicolas Guillemot,V00695164" | |
ButtonInfoDisplayString1: | |
.asciz "Buttons: Pause, STOP!" | |
ButtonInfoDisplayString2: | |
.asciz "Keys: Start, Reset, --, --" | |
ButtonInfoDisplayString3: | |
.asciz " Sp -2, Sp -1, Sp +1, Sp +2" | |
ButtonInfoDisplayString4: | |
.asciz " Wt -2, Wt -1, Wt +1, Wt +2" | |
ButtonInfoDisplayString5: | |
.asciz " --, --, --, Off" | |
.align | |
ButtonInfoDisplayStrings: | |
.word ButtonInfoDisplayString1, ButtonInfoDisplayString2 | |
.word ButtonInfoDisplayString3, ButtonInfoDisplayString4 | |
.word ButtonInfoDisplayString5, 0 | |
WeightString: | |
.asciz "Weight:" | |
LbsString: | |
.asciz "lbs" | |
TargetSpeedString: | |
.asciz "Target speed:" | |
ActualSpeedString: | |
.asciz "Actual speed:" | |
MphString: | |
.asciz "mph" | |
TimeString: | |
.asciz "Time:" | |
SecondsString: | |
.asciz "seconds" | |
DistanceString: | |
.asciz "Distance:" | |
MilesString: | |
.asciz "miles" | |
EnergyString: | |
.asciz "Energy:" | |
CaloriesString: | |
.asciz "Calories" | |
GoodbyeString: | |
.asciz "*** Treadmill program shutting down! ***" | |
ArrowString: | |
@ arrow pointing down used in some debug printing stuff | |
.asciz "|\nv\n" | |
.align | |
CurrentLyricsBufferLen: | |
.word SCREEN_WIDTH | |
eyeofthetiger0: | |
.asciz "Risin' up, back on the street" | |
eyeofthetiger1: | |
.asciz "Did my time, took my chances" | |
eyeofthetiger2: | |
.asciz "Went the distance" | |
eyeofthetiger3: | |
.asciz "Now I'm back on my feet" | |
eyeofthetiger4: | |
.asciz "Just a man and his will to survive" | |
eyeofthetiger5: | |
.asciz "So many times, it happens too fast" | |
eyeofthetiger6: | |
.asciz "You trade your passion for glory" | |
eyeofthetiger7: | |
.asciz "Don't lose your grip on the dreams of the past" | |
eyeofthetiger8: | |
.asciz "You must fight just to keep them alive" | |
eyeofthetiger9: | |
.asciz "It's the eye of the tiger" | |
eyeofthetiger10: | |
.asciz "It's the thrill of the fight" | |
eyeofthetiger11: | |
.asciz "Risin' up to the challenge" | |
eyeofthetiger12: | |
.asciz "Of our rival" | |
eyeofthetiger13: | |
.asciz "And the last known survivor" | |
eyeofthetiger14: | |
.asciz "Stalks his prey in the night" | |
eyeofthetiger15: | |
.asciz "And he's watching us all with the" | |
eyeofthetiger16: | |
.asciz "Eye of the tiger" | |
eyeofthetiger17: | |
.asciz "Face to face, out in the heat" | |
eyeofthetiger18: | |
.asciz "Hangin' tough, stayin' hungry" | |
eyeofthetiger19: | |
.asciz "They stack the odds" | |
eyeofthetiger20: | |
.asciz "Still we take to the street" | |
eyeofthetiger21: | |
.asciz "For the kill with the skill to survive" | |
eyeofthetiger22: | |
.asciz "It's the eye of the tiger" | |
eyeofthetiger23: | |
.asciz "It's the thrill of the fight" | |
eyeofthetiger24: | |
.asciz "Risin' up to the challenge" | |
eyeofthetiger25: | |
.asciz "Of our rival" | |
eyeofthetiger26: | |
.asciz "And the last known survivor" | |
eyeofthetiger27: | |
.asciz "Stalks his prey in the night" | |
eyeofthetiger28: | |
.asciz "And he's watching us all with the" | |
eyeofthetiger29: | |
.asciz "Eye of the tiger" | |
eyeofthetiger30: | |
.asciz "Risin' up straight to the top" | |
eyeofthetiger31: | |
.asciz "Had the guts, got the glory" | |
eyeofthetiger32: | |
.asciz "Went the distance" | |
eyeofthetiger33: | |
.asciz "Now I'm not gonna stop" | |
eyeofthetiger34: | |
.asciz "Just a man and his will to survive" | |
eyeofthetiger35: | |
.asciz "It's the eye of the tiger" | |
eyeofthetiger36: | |
.asciz "It's the thrill of the fight" | |
eyeofthetiger37: | |
.asciz "Risin' up to the challenge" | |
eyeofthetiger38: | |
.asciz "Of our rival" | |
eyeofthetiger39: | |
.asciz "And the last known survivor" | |
eyeofthetiger40: | |
.asciz "Stalks his prey in the night" | |
eyeofthetiger41: | |
.asciz "And he's watching us all with the" | |
eyeofthetiger42: | |
.asciz "Eye of the tiger" | |
eyeofthetiger43: | |
.asciz "The eye of the tiger" | |
eyeofthetiger44: | |
.asciz "The eye of the tiger" | |
eyeofthetiger45: | |
.asciz "The eye of the tiger" | |
eyeofthetiger46: | |
.asciz "The eye of the tiger" | |
.align | |
eyeofthetigerLyrics: | |
.word eyeofthetiger0 | |
.word eyeofthetiger1 | |
.word eyeofthetiger2 | |
.word eyeofthetiger3 | |
.word eyeofthetiger4 | |
.word eyeofthetiger5 | |
.word eyeofthetiger6 | |
.word eyeofthetiger7 | |
.word eyeofthetiger8 | |
.word eyeofthetiger9 | |
.word eyeofthetiger10 | |
.word eyeofthetiger11 | |
.word eyeofthetiger12 | |
.word eyeofthetiger13 | |
.word eyeofthetiger14 | |
.word eyeofthetiger15 | |
.word eyeofthetiger16 | |
.word eyeofthetiger17 | |
.word eyeofthetiger18 | |
.word eyeofthetiger19 | |
.word eyeofthetiger20 | |
.word eyeofthetiger21 | |
.word eyeofthetiger22 | |
.word eyeofthetiger23 | |
.word eyeofthetiger24 | |
.word eyeofthetiger25 | |
.word eyeofthetiger26 | |
.word eyeofthetiger27 | |
.word eyeofthetiger28 | |
.word eyeofthetiger29 | |
.word eyeofthetiger30 | |
.word eyeofthetiger31 | |
.word eyeofthetiger32 | |
.word eyeofthetiger33 | |
.word eyeofthetiger34 | |
.word eyeofthetiger35 | |
.word eyeofthetiger36 | |
.word eyeofthetiger37 | |
.word eyeofthetiger38 | |
.word eyeofthetiger39 | |
.word eyeofthetiger40 | |
.word eyeofthetiger41 | |
.word eyeofthetiger42 | |
.word eyeofthetiger43 | |
.word eyeofthetiger44 | |
.word eyeofthetiger45 | |
.word eyeofthetiger46 | |
.word 0 | |
@ maximum value in lbs for weight setting | |
WeightMax: | |
.word 350 | |
@ maximum value of timer in milliseconds. Used to handle wraparound. | |
TimerMax: | |
.word 32767 | |
@ A state is defined as a list of function pointers in the following order. | |
@ Note that unimplemented functions can be substituted with a no-op function. | |
@ ExampleState: | |
@ flow callbacks: | |
@ OnEnter, OnUpdate, OnRedraw, OnLeave | |
@ black button callbacks: | |
@ OnPause, OnEmergencyStop | |
@ blue button callbacks: | |
@ OnStart, OnReset | |
@ OnSpeedDown2, OnSpeedDown1, OnSpeedUp1, OnSpeedUp2 | |
@ OnWeightDown2, OnWeightDown1, OnWeightUp1, OnWeightUp2 | |
@ OnOff | |
StateRTTIOffset: | |
@ byte offset of RTTI string for state | |
.word 68 | |
.align | |
@ Placeholder state | |
NoOpState: | |
@ flow callbacks: | |
.word no_op, no_op, no_op, no_op | |
@ black button callbacks: | |
.word no_op, no_op | |
@ blue button callbacks: | |
.word no_op, no_op | |
.word no_op, no_op, no_op, no_op | |
.word no_op, no_op, no_op, no_op | |
.word no_op | |
@ RTTI | |
.asciz "NoOpState" | |
.align | |
@ Final things which are done before the machine is turned off | |
ExitingState: | |
@ flow callbacks: | |
.word exiting_on_enter, exiting_on_update, draw_exiting_hud, no_op | |
@ black button callbacks: | |
.word no_op, no_op | |
@ blue button callbacks: | |
.word no_op, no_op | |
.word no_op, no_op, no_op, no_op | |
.word no_op, no_op, no_op, no_op | |
.word no_op | |
@ RTTI | |
.asciz "ExitingState" | |
.align | |
@ duration in milliseconds of exiting state | |
ExitingDuration: | |
.word 3000 | |
.align | |
@ Initial state of the machine | |
StoppedState: | |
@ flow callbacks: | |
.word stopped_on_enter, no_op, draw_hud, no_op | |
@ black button callbacks: | |
.word no_op, no_op | |
@ blue button callbacks: | |
.word stopped_on_start, reset_stats | |
.word lower_speed_2, lower_speed_1, increase_speed_1, increase_speed_2 | |
.word weight_down_2, weight_down_1, weight_up_1, weight_up_2 | |
.word stopped_on_off | |
@ RTTI | |
.asciz "StoppedState" | |
.align | |
@ State when user is running on treadmill at normal operation | |
RunningState: | |
@ flow callbacks: | |
.word running_on_enter, running_on_update, draw_hud, no_op | |
@ black button callbacks: | |
.word running_on_pause, running_on_emergency_stop | |
@ blue button callbacks | |
.word no_op, no_op | |
.word lower_speed_2, lower_speed_1, increase_speed_1, increase_speed_2 | |
.word no_op, no_op, no_op, no_op | |
.word no_op | |
@ RTTI | |
.asciz "RunningState" | |
.align | |
@ State when the treadmill is quickly stopping when responding to emergency stop | |
ShutdownState: | |
@ flow callbacks: | |
.word shutdown_on_enter, shutdown_on_update, draw_hud, no_op | |
@ black button callbacks: | |
.word no_op, no_op | |
@ blue button callbacks: | |
.word no_op, no_op | |
.word no_op, no_op, no_op, no_op | |
.word no_op, no_op, no_op, no_op | |
.word no_op | |
@ RTTI | |
.asciz "ShutdownState" | |
.align | |
@ Intermediary state during which the state is slowing down for a pause | |
PausingState: | |
@ flow callbacks: | |
.word pausing_on_enter, pausing_on_update, draw_hud, no_op | |
@ black button callbacks: | |
.word no_op, pausing_on_emergency_stop | |
@ blue button callbacks: | |
.word pausing_on_start, no_op | |
.word no_op, no_op, no_op, no_op | |
.word no_op, no_op, no_op, no_op | |
.word no_op | |
@ RTTI | |
.asciz "PausingState" | |
.align | |
@ State reached from the PausingState where the machine is temporarily not traveling | |
PausedState: | |
@ flow callbacks: | |
.word paused_on_enter, no_op, draw_hud, no_op | |
@ black button callbacks: | |
.word no_op, no_op | |
@ blue button callbacks: | |
.word paused_on_start, paused_on_reset | |
.word no_op, no_op, no_op, no_op | |
.word no_op, no_op, no_op, no_op | |
.word paused_on_off | |
@ RTTI | |
.asciz "PausedState" | |
.align | |
@ Order in which black buttons are polled ending with -1 | |
BlackButtonUpdateList: | |
.word PAUSE_KEY, EMERGENCY_STOP_KEY, -1 | |
@ Order in which blue buttons are polled ending with -1 | |
BlueButtonUpdateList: | |
.word START_KEY, RESET_KEY, SPEED_DOWN_2_KEY | |
.word SPEED_DOWN_1_KEY, SPEED_UP_1_KEY, SPEED_UP_2_KEY | |
.word WEIGHT_DOWN_2_KEY, WEIGHT_DOWN_1_KEY, WEIGHT_UP_1_KEY | |
.word WEIGHT_UP_2_KEY, SWITCH_OFF_KEY, -1 | |
.text | |
@ Purpose: | |
@ Asks hardware for the value of the current ticks. | |
@ Returns: | |
@ Current ticks in r0 masked to 15 bits. | |
@ Notes: | |
@ Ticks are counted in milliseconds. | |
@ Ticks are stored as a 15 bit value, so their maximum value is ~32 seconds. | |
@ The ticks are masked to 15 bits to ensure same behaviour on ARMSim#, which uses a 32bit timer. | |
@ Assumptions allowed: | |
@ The value of no other register than r0 and r3 are changed. | |
get_ticks: | |
@ function prologue | |
stmfd sp!, {lr} | |
swi SWI_GetTicks | |
mov r3, r0 | |
ldr r0, =TimerMax | |
ldr r0, [r0] | |
and r0, r3, r0 | |
@ functino epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Purpose: | |
@ Asks hardware for blue button bitset lookup table, | |
@ which is used to determine if buttons are pressed. | |
@ Returns: | |
@ Blue button bitset in r0. | |
@ Assumptions allowed: | |
@ The value of no other register than r0 is changed. | |
get_blue_buttons_state: | |
swi SWI_CheckBlue | |
bx lr | |
@ Purpose: | |
@ Asks hardware for black button bitset lookup table, | |
@ which is used to determine if buttons are pressed. | |
@ Returns: | |
@ Black button bitset in r0. | |
@ Assumptions allowed: | |
@ The value of no other register than r0 is changed. | |
get_black_buttons_state: | |
swi SWI_CheckBlack | |
bx lr | |
@ Purpose: | |
@ Check if a button is being pressed. | |
@ Parameters: | |
@ r0 : index of button to check. | |
@ r1 : contains bitset of button states. | |
@ Preconditions: | |
@ r0 is an integer in the range of valid buttons. | |
@ Returns: | |
@ Sets r0 to zero if not pressed, non-zero if pressed. | |
is_button_pressed: | |
mov r3, #1 | |
and r0, r1, r3, LSL r0 | |
bx lr | |
@ Purpose: | |
@ Changing the appearance of the SSD (Seven Segment Display) | |
@ Parameters: | |
@ r0 : Pattern to switch to | |
set_ssd_pattern: | |
swi SWI_SetSEG8 | |
bx lr | |
@ Purpose: | |
@ Changing the state of the LEDs. | |
@ This also resets the timer for the flickering of LEDs during traveling states. | |
@ Parameters: | |
@ r0 : the bitset representing the new state | |
set_led_pattern: | |
ldr r3, =LEDState | |
str r0, [r3] | |
swi SWI_SetLED | |
@ reset flicker accumulator as described by specification | |
ldr r3, =LEDFlickerUpdateAccumulator | |
mov r0, #0 | |
str r0, [r3] | |
bx lr | |
@ Purpose: | |
@ Calculating the length of a string | |
@ Parameters: | |
@ r0 : pointer to null terminated ascii string | |
@ Returns: | |
@ string length in r0 without counting trailing '\0' | |
string_length: | |
mov r3, #0 | |
string_length_loop: | |
@ get current character | |
ldrb r2, [r0, r3] | |
@ if is null terminator, found end of string. | |
cmp r2, #0 | |
beq string_length_end | |
add r3, r3, #1 | |
bal string_length_loop | |
string_length_end: | |
mov r0, r3 | |
bx lr | |
@ Purpose: | |
@ Copying one string null terminated string into another string which is not necessarily null terminated. | |
@ Parameters: | |
@ r0 : pointer to target string | |
@ r1 : pointer to source string | |
string_copy: | |
string_copy_loop: | |
ldrb r3, [r1], #1 | |
strb r3, [r0], #1 | |
@ stop reading at null terminator | |
cmp r3, #0 | |
beq string_copy_end | |
bal string_copy_loop | |
string_copy_end: | |
bx lr | |
@ Purpose: | |
@ Copying one string null terminated string into another string which is not necessarily null terminated up to n characters | |
@ Parameters: | |
@ r0 : pointer to destination string | |
@ r1 : pointer to source string | |
@ r2 : number of characters to copy | |
string_n_copy: | |
string_n_copy_loop: | |
cmp r2, #0 | |
ble string_n_copy_end | |
ldrb r3, [r1], #1 | |
strb r3, [r0], #1 | |
@ stop reading at null terminator or n reached | |
cmp r3, #0 | |
beq string_n_copy_end | |
sub r2, r2, #1 | |
bal string_n_copy_loop | |
string_n_copy_end: | |
bx lr | |
@ Purpose: | |
@ Copying an array of bytes to another. | |
@ Parameters: | |
@ r0 : pointer to destination buffer | |
@ r1 : pointer to source buffer | |
@ r2 : number of bytes to read from source | |
memory_copy: | |
sub r2, r2, #1 | |
memory_copy_loop: | |
cmp r2, #0 | |
blt memory_copy_end | |
ldrb r3, [r1, r2] | |
strb r3, [r0, r2] | |
sub r2, r2, #1 | |
bal memory_copy_loop | |
memory_copy_end: | |
bx lr | |
@ Purpose: | |
@ Writing a byte consecutively in memory | |
@ Parameters: | |
@ r0 : pointer to start of memory | |
@ r1 : size of memory to write to in bytes | |
@ r2 : byte to write | |
memory_set: | |
sub r1, r1, #1 | |
memory_set_loop: | |
cmp r1, #0 | |
blt memory_set_end | |
strb r2, [r0, r1] | |
sub r1, r1, #1 | |
bal memory_set_loop | |
memory_set_end: | |
bx lr | |
@ Code taken from http://www.virag.si/2010/02/simple-division-algorithm-for-arm-assembler/ | |
@ Accessed March 12 2012 | |
@ Authored by Jernej Virag, and slightly modified by me (Nicolas Guillemot). | |
@ Purpose: | |
@ Providing a way to divide integers due to lack of instruction for it in target ARM platform. | |
@ The implementation is naive. Not to be used for performance sensitive code. | |
@ Parameters: | |
@ r1 : divided | |
@ r2 : divisor | |
@ Returns: | |
@ If divisor is 0, return value is not valid. | |
@ Otherwise, r0 will contain the result of the division | |
divide_integer: | |
@ function prologue | |
stmfd sp!, {r4,r5,lr} | |
@ local variables: | |
@ r4: keep track of divided | |
@ r5: keep track of divisor | |
mov r4, r1 | |
mov r5, r2 | |
cmp r2, #0 | |
beq divide_integer_end | |
@ check for divide by zero! | |
mov r0, #0 @ clear r0 to accumulate result | |
mov r3, #1 @ set bit 0 in r3, which will be | |
@ shifted left then right | |
divide_integer_start: | |
cmp r2, r1 | |
movls r2, r2, LSL #1 | |
movls r3, r3, LSL #1 | |
bls divide_integer_start | |
@ shift r2 left until it is about to | |
@ be bigger than r1 | |
@ shift r3 left in parallel in order | |
@ to flag how far we have to go | |
divide_integer_next: | |
cmp r1, r2 @ carry set if r1>r2 (don't ask why) | |
subcs r1, r1, r2 @ subtract r2 from r1 if this would | |
@ give a positive answer | |
addcs r0, r0, r3 @ and add the current bit in r3 to | |
@ the accumulating answer in r0 | |
movs r3, r3, LSR #1 @ Shift r3 right into carry flag | |
movcc r2, r2, LSR #1 @ and if bit 0 of r3 was zero, also | |
@ shift r2 right | |
bcc divide_integer_next @ If carry not clear, r3 has shifted | |
@ back to where it started, and we | |
@ can end | |
divide_integer_end: | |
@ function epilogue | |
ldmfd sp!, {r4,r5,lr} | |
bx lr | |
@ Purpose: | |
@ Finding the result of an integer modulo operation. | |
@ Parameters: | |
@ r1 : divided | |
@ r2 : divisor | |
@ Returns: | |
@ result of divided % divisor in r0. | |
@ If divisor is 0, return value is not valid. | |
mod_integer: | |
@ function prologue | |
stmfd sp!, {r4,r5,lr} | |
@ local variables: | |
@ r4: divided passed in | |
@ r5: divisor passed in | |
mov r4, r1 | |
mov r5, r2 | |
@ divided % divisor = divided - (divided/divisor) * divisor | |
mov r1, r4 | |
mov r2, r5 | |
bl divide_integer | |
mov r3, r0 | |
mul r0, r3, r5 | |
sub r0, r4, r0 | |
@ function epilogue | |
ldmfd sp!, {r4,r5,lr} | |
bx lr | |
@ Purpose: | |
@ Write an integer to a string with right alignment. | |
@ Parameters: | |
@ r0 : integer to convert | |
@ r1 : radix | |
@ r2 : string buffer to write to | |
@ r3 : size of buffer | |
@ top of stack: index of decimal point for fixed point OR -1 for no decimal point | |
@ Returns: | |
@ writes NON-NULL TERMINATED string to END OF buffer in r2. | |
@ note that if you pass in the full length of the actual buffer as r3, your string will not be null terminated!!! | |
@ Preconditions: | |
@ size of buffer passed in big enough to write the number in base radix in it. | |
int_to_string: | |
@ function prologue | |
stmfd sp!, {r4,r5,r6,fp,lr} | |
mov fp, sp | |
@ Allocate stack and store input arguments | |
sub sp, sp, #20 | |
str r0, [fp, #-4] @ integer to convert | |
str r1, [fp, #-8] @ radix | |
str r2, [fp, #-12] @ buffer | |
str r3, [fp, #-16] @ size of buffer | |
ldr r3, [fp, #20] @ decimal position | |
str r3, [fp, #-20] | |
@ local variables | |
@ r4: int i; | |
@ r5: int m; | |
@ r6: int x; | |
@ int i = 0; | |
mov r4, #0 | |
@ int x = integer_to_convert; | |
ldr r6, [fp, #-4] | |
@ do { | |
int_to_string_loop: | |
@ if (i == decimal_point_position) | |
ldr r3, [fp, #-20] | |
cmp r4, r3 | |
bne int_to_string_handled_point | |
@ { | |
@ buf[buflen - i - 1] = '.'; | |
ldr r3, [fp, #-16] | |
sub r3, r3, r4 | |
sub r3, r3, #1 | |
ldr r2, [fp, #-12] | |
mov r1, #46 | |
strb r1, [r2, r3] | |
@ i++; | |
add r4, r4, #1 | |
@ continue; | |
bal int_to_string_loop | |
@ } | |
int_to_string_handled_point: | |
@ m = x % r; | |
mov r1, r6 | |
ldr r2, [fp, #-8] @ get radix | |
bl mod_integer | |
mov r5, r0 @ store back result | |
@ x = x / r; | |
mov r1, r6 | |
ldr r2, [fp, #-8] @ get radix | |
bl divide_integer | |
mov r6, r0 @ store back result | |
@ buf[buflen - i - 1] = digits[m] | |
ldr r3, [fp, #-12] @ get buffer | |
ldr r2, [fp, #-16] @ get buflen | |
sub r2, r2, r4 | |
sub r2, r2, #1 | |
ldr r1, =DigitToCharacterLookup | |
ldrb r1, [r1, r5] | |
strb r1, [r3, r2] | |
add r4, r4, #1 | |
@ } while (x != 0 || decimal_point_position >= i - 1); | |
cmp r6, #0 | |
bne int_to_string_loop | |
ldr r3, [fp, #-20] | |
sub r2, r4, #1 | |
cmp r3, r2 | |
bge int_to_string_loop | |
@ function epilogue | |
mov sp, fp | |
ldmfd sp!, {r4,r5,r6,fp,lr} | |
bx lr | |
@ Purpose: | |
@ Reprints a string such as "Weight: 100 lbs" | |
@ Parameters: | |
@ r0 : Pointer to null terminated string for information name ("Weight:") | |
@ r1 : Number to print for the information (100) | |
@ r2 : Pointer to null terminated string for name of units | |
@ r3 : Position of decimal point or -1 if none | |
@ top of stack : Buffer where the string will be reprinted | |
@ Preconditions: | |
@ target buffer has size at least SCREEN_WIDTH | |
print_information_string: | |
@ function prologue | |
stmfd sp!, {r4-r8,fp,lr} | |
mov fp, sp | |
@ extra space on the stack is allocated for the passed in value to int_to_string | |
sub sp, sp, #4 | |
@ local variables: | |
@ r4 : pointer to information name string | |
@ r5 : number to print | |
@ r6 : pointer to units string | |
@ r7 : position of decimal point | |
@ r8 : pointer to target buffer | |
mov r4, r0 | |
mov r5, r1 | |
mov r6, r2 | |
mov r7, r3 | |
ldr r8, [fp, #28] | |
@ clear target string with spacebar character | |
mov r0, r8 | |
mov r1, #SCREEN_WIDTH | |
mov r2, #32 | |
bl memory_set | |
@ write information name to target buffer | |
mov r0, r4 | |
bl string_length | |
mov r2, r0 | |
mov r0, r8 | |
mov r1, r4 | |
bl memory_copy | |
@ write number in number space | |
mov r0, r5 | |
mov r1, #10 | |
mov r2, r8 | |
mov r3, #INFO_WIDTH | |
mov ip, r7 | |
str ip, [fp, #-4] | |
bl int_to_string | |
@ write units after indent with null terminator | |
mov r3, #INFO_WIDTH | |
add r3, r3, #INFO_INDENT_WIDTH | |
add r0, r8, r3 | |
mov r1, r6 | |
bl string_copy | |
@ function epilogue | |
mov sp, fp | |
ldmfd sp!, {r4-r8,fp,lr} | |
bx lr | |
@ Purpose: | |
@ Initialize state machine with default state | |
initialize_state_machine: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ Clear the buffer for the lyrics | |
ldr r0, =CurrentLyricsBuffer | |
ldr r1, =CurrentLyricsBufferLen | |
ldr r1, [r1] | |
mov r2, #0 | |
bl memory_set | |
@ reset data and display info | |
bl reset_stats | |
@ set default state of state machine | |
ldr r3, =StoppedState | |
ldr r2, =CurrentState | |
str r3, [r2] | |
@ call OnEnter function of state | |
ldr r2, [r3] | |
mov lr, pc | |
bx r2 | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Purpose: | |
@ Deinitialize the state machine to cleanly exit | |
deinitialize_state_machine: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ call OnLeave function of state | |
ldr r3, =CurrentState | |
ldr r3, [r3] | |
ldr r3, [r3, #12] | |
mov lr, pc | |
bx r3 | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Purpose: | |
@ Being able to know the name of a state at runtime using RTTI (RunTime Type Information) | |
@ Parameters: | |
@ r0 : pointer to state | |
print_state_typeinfo: | |
@ function prologue | |
stmfd sp!, {lr} | |
ldr r3, =StateRTTIOffset | |
ldr r3, [r3] | |
@ get string pointer | |
add r1, r0, r3 | |
@ print to stdout | |
mov r0, #Stdout | |
swi SWI_PutString | |
mov r0, #10 | |
swi SWI_PutCharacter | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Purpose: | |
@ Switch the state of the state machine | |
@ Parameters: | |
@ r0 : Pointer to the new state | |
@ Preconditions: | |
@ State machine is initialized | |
switch_state: | |
@ function prologue | |
stmfd sp!, {r4,lr} | |
@ local variables: | |
@ r4: pointer to new state | |
mov r4, r0 | |
@ print old state | |
ldr r0, =CurrentState | |
ldr r0, [r0] | |
bl print_state_typeinfo | |
@ call OnLeave on old state | |
ldr r3, =CurrentState | |
ldr r3, [r3] | |
ldr r3, [r3, #12] | |
mov lr, pc | |
bx r3 | |
@ change CurrentState to new state | |
ldr r3, =CurrentState | |
str r4, [r3] | |
@ print arrow | |
mov r0, #Stdout | |
ldr r1, =ArrowString | |
swi SWI_PutString | |
@ print new state | |
ldr r0, =CurrentState | |
ldr r0, [r0] | |
bl print_state_typeinfo | |
@ call OnEnter on new state | |
ldr r3, =CurrentState | |
ldr r3, [r3] | |
ldr r3, [r3] | |
mov lr, pc | |
bx r3 | |
@ function epilogue | |
ldmfd sp!, {r4,lr} | |
bx lr | |
@ Purpose: | |
@ Changing the weight of the user while taking into account maximum and minimum weights. | |
@ Parameters: | |
@ r0 : the target weight | |
set_weight: | |
@ function prologue | |
stmfd sp!, {fp,lr} | |
mov fp, sp | |
sub sp, sp, #4 | |
@ clamp value between WEIGHT_MIN and WeightMax | |
cmp r0, #WEIGHT_MIN | |
movlt r0, #WEIGHT_MIN | |
ldr r3, =WeightMax | |
ldr r3, [r3] | |
cmp r0, r3 | |
movgt r0, r3 | |
@ store in memory | |
ldr r3, =Weight | |
str r0, [r3] | |
@ reprint string | |
ldr r0, =WeightString | |
ldr r1, =Weight | |
ldr r1, [r1] | |
ldr r2, =LbsString | |
mov r3, #-1 | |
ldr ip, =WeightLineBuffer | |
str ip, [fp, #-4] | |
bl print_information_string | |
@ function epilogue | |
mov sp, fp | |
ldmfd sp!, {fp,lr} | |
bx lr | |
@ Purpose: | |
@ Shortcut for incrementing or decrementing weight | |
@ Parameters: | |
@ r0 : difference in weight | |
incr_weight: | |
@ function prologue | |
stmfd sp!, {lr} | |
ldr r3, =Weight | |
ldr r2, [r3] | |
add r2, r2, r0 | |
mov r0, r2 | |
bl set_weight | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Purpose: | |
@ Changing the target speed while taking into account max/min speeds. | |
@ Parameters: | |
@ r0 : the target speed | |
set_target_speed: | |
@ function prologue | |
stmfd sp!, {fp,lr} | |
mov fp, sp | |
sub sp, sp, #4 | |
@ clamp value between TARGET_SPEED_MIN and TARGET_SPEED_MAX | |
cmp r0, #TARGET_SPEED_MIN | |
movlt r0, #TARGET_SPEED_MIN | |
cmp r0, #TARGET_SPEED_MAX | |
movgt r0, #TARGET_SPEED_MAX | |
@ store in memory | |
ldr r3, =TargetSpeed | |
str r0, [r3] | |
@ reprint string | |
ldr r0, =TargetSpeedString | |
ldr r1, =TargetSpeed | |
ldr r1, [r1] | |
ldr r2, =MphString | |
mov r3, #1 | |
ldr ip, =TargetSpeedLineBuffer | |
str ip, [fp, #-4] | |
bl print_information_string | |
@ function epilogue | |
mov sp, fp | |
ldmfd sp!, {fp,lr} | |
bx lr | |
@ Purpose: | |
@ Shortcut for incrementing or decrementing target speed | |
@ Parameters: | |
@ r0 : difference in target speed | |
incr_target_speed: | |
@ function prologue | |
stmfd sp!, {lr} | |
ldr r3, =TargetSpeed | |
ldr r2, [r3] | |
add r2, r2, r0 | |
mov r0, r2 | |
bl set_target_speed | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Purpose: | |
@ Changing the value of the actual speed | |
@ Parameters: | |
@ r0 : the new actual speed | |
set_actual_speed: | |
@ function prologue | |
stmfd sp!, {fp,lr} | |
mov fp, sp | |
sub sp, sp, #4 | |
@ clamp value between TARGET_SPEED_MIN and TARGET_SPEED_MAX | |
cmp r0, #TARGET_SPEED_MIN | |
movlt r0, #TARGET_SPEED_MIN | |
cmp r0, #TARGET_SPEED_MAX | |
movgt r0, #TARGET_SPEED_MAX | |
@ store value | |
ldr r3, =ActualSpeed | |
str r0, [r3] | |
@ reprint string | |
ldr r0, =ActualSpeedString | |
ldr r1, =ActualSpeed | |
ldr r1, [r1] | |
ldr r2, =MphString | |
mov r3, #1 | |
ldr ip, =ActualSpeedLineBuffer | |
str ip, [fp, #-4] | |
bl print_information_string | |
@ function epilogue | |
mov sp, fp | |
ldmfd sp!, {fp,lr} | |
bx lr | |
@ Purpose: | |
@ Changing the value of the time | |
@ Parameters: | |
@ r0 : the new time in .1f fixed point | |
set_time: | |
@ function prologue | |
stmfd sp!, {fp,lr} | |
mov fp, sp | |
sub sp, sp, #4 | |
@ store value | |
ldr r3, =Time | |
str r0, [r3] | |
@ reprint string | |
ldr r0, =TimeString | |
ldr r1, =Time | |
ldr r1, [r1] | |
ldr r2, =SecondsString | |
mov r3, #1 | |
ldr ip, =TimeLineBuffer | |
str ip, [fp, #-4] | |
bl print_information_string | |
@ function epilogue | |
mov sp, fp | |
ldmfd sp!, {fp,lr} | |
bx lr | |
@ Purpose: | |
@ Changing the value of the distance | |
@ Parameters: | |
@ r0 : the new distance | |
set_distance: | |
@ function prologue | |
stmfd sp!, {fp,lr} | |
mov fp, sp | |
sub sp, sp, #4 | |
@ store value | |
ldr r3, =Distance | |
str r0, [r3] | |
@ reprint string | |
ldr r0, =DistanceString | |
ldr r1, =Distance | |
ldr r1, [r1] | |
ldr r2, =MilesString | |
mov r3, #6 | |
ldr ip, =DistanceLineBuffer | |
str ip, [fp, #-4] | |
bl print_information_string | |
@ function epilogue | |
mov sp, fp | |
ldmfd sp!, {fp,lr} | |
bx lr | |
@ Purpose: | |
@ Changing the value of the energy | |
@ Parameters: | |
@ r0 : the new energy | |
set_energy: | |
@ function prologue | |
stmfd sp!, {fp,lr} | |
mov fp, sp | |
sub sp, sp, #4 | |
@ store value | |
ldr r3, =Energy | |
str r0, [r3] | |
@ reprint string | |
ldr r0, =EnergyString | |
ldr r1, =Energy | |
ldr r1, [r1] | |
ldr r2, =CaloriesString | |
mov r3, #6 | |
ldr ip, =EnergyLineBuffer | |
str ip, [fp, #-4] | |
bl print_information_string | |
@ function epilogue | |
mov sp, fp | |
ldmfd sp!, {fp,lr} | |
bx lr | |
@ Purpose: | |
@ to simplify explanation, this whole description assumes milliunits. | |
@ but if you pass in something else than 1000, you can get another conversion | |
@ such as 100 converts centiunits to units. | |
@ remember it's all relative... | |
@ Takes a value in memory where the units are milliunits | |
@ takes out as many full units as it can from them | |
@ and stores them in the other location in memory | |
@ where the units are just units. | |
@ This was made to simplify the update_travel function... | |
@ function is called to simplify set_time stuff | |
@ Parameters: | |
@ r0 : pointer to word measured in milliunits | |
@ r1 : pointer to word measured in units | |
@ r2 : pointer to function to set units | |
@ if r2 is 0, units will be set with a simple str | |
@ r3 : factor to multiply for unit conversion (eg 1000) | |
@ Returns: | |
@ r0 : 1 if units actually changed, 0 if not | |
convert_unit_base: | |
@ function prologue | |
stmfd sp!, {r4-r8,lr} | |
@ local variables: | |
@ r4: consistent pointer to source word | |
@ r5: consistent pointer to target word | |
@ r6: holds result of division | |
@ r7: consistent pointer to setting function | |
@ r8: consistent value of conversion | |
mov r4, r0 | |
mov r5, r1 | |
mov r7, r2 | |
mov r8, r3 | |
@ convert packs of 1000 milliunits in units | |
ldr r1, [r4] | |
mov r2, r8 | |
bl divide_integer | |
@ if no packs can be taken out, just return | |
cmp r0, #0 | |
beq convert_unit_base_end | |
mov r6, r0 | |
@ add removed units to target units | |
ldr r2, [r5] | |
add r2, r2, r6 | |
@ Either call function if defined or just simple store | |
cmp r7, #0 | |
streq r2, [r5] | |
movne r0, r2 | |
movne lr, pc | |
bxne r7 | |
@ remove milliunits from source | |
ldr r1, [r4] | |
mov r2, r8 | |
mul r0, r2, r6 | |
sub r1, r1, r0 | |
str r1, [r4] | |
@ prepare return value | |
mov r0, #1 | |
convert_unit_base_end: | |
@ function epilogue | |
ldmfd sp!, {r4-r8,lr} | |
bx lr | |
@ Purpose: | |
@ Encapsulating the common behaviour of travelling on the treadmill. | |
@ This will update the data for the time, distance, and energy. | |
@ It is meant to be called in the OnUpdate of states where the treadmill is rolling. | |
@ Note that this accumulates the data in units more accurate than what is actually displayed, to work with few milliseconds of delta time. | |
@ Parameters: | |
@ r0: the delta time | |
@ Development notes: Solutions to problems for too small units | |
@ Delta distance for tiny delta time too small to be felt | |
@ Solution: Accumulate delta distance in nano miles | |
@ Then store back when representable in micro miles | |
@ Time on HUD displayed in seconds, not milliseconds | |
@ Solution: Accumulate in milliseconds | |
@ Then store back in seconds | |
@ Energy also increments too small in one dt | |
@ Solution: Accumulate energy in nano calories | |
@ Then store back when representable in micro calories | |
@ note: 0.1 mph = 28 nanomiles / millisecond | |
@ note: R = 80 * W * V | |
@ where R is Calories/millisecond | |
@ W is lbs | |
@ V is .1 fixed point mph | |
update_travel: | |
@ function prologue | |
stmfd sp!, {r4,lr} | |
@ local variables: | |
@ r4: stored passed in delta time | |
mov r4, r0 | |
@ increment accumulator for time and store back | |
ldr r3, =TravelTime | |
ldr r2, [r3] | |
add r2, r2, r4 | |
str r2, [r3] | |
@ increment accumulator for distance | |
@ calculate dp (nanomiles) = dt * V * 28 | |
@ where V is in .1 fixed point mph | |
mov r3, #28 | |
ldr r2, =ActualSpeed | |
ldr r2, [r2] | |
mul r1, r2, r3 @ r1 = V * 28 | |
mul r1, r4, r1 @ r1 = dt * (V * 28) | |
@ accumulate and store back in TravelDistance | |
ldr r3, =TravelDistance | |
ldr r2, [r3] | |
add r2, r2, r1 | |
str r2, [r3] | |
@ increment accumulator for energy | |
@ calculate current rate | |
ldr r3, =Weight | |
ldr r3, [r3] | |
ldr r2, =ActualSpeed | |
ldr r2, [r2] | |
mov r1, #80 | |
mul r1, r2, r1 @ r1 = V * 80 | |
mul r1, r3, r1 @ r1 = W * (V*80) | |
@ r1 now contains rate. now calculate and store back | |
mul r1, r4, r1 @ calculate delta energy | |
ldr r3, =TravelEnergy | |
ldr r2, [r3] | |
add r2, r2, r1 @ accumulate delta energy | |
str r2, [r3] | |
@ now need to drop the accumulated values in the actual memory | |
@ convert packs of 1000ms in TravelTime to ds in Time | |
ldr r0, =TravelTime | |
ldr r1, =Time | |
ldr r2, =set_time | |
mov r3, #100 | |
bl convert_unit_base | |
@ convert packs of 1000 nanomiles to micromiles | |
ldr r0, =TravelDistance | |
ldr r1, =Distance | |
ldr r2, =set_distance | |
mov r3, #1000 | |
bl convert_unit_base | |
@ convert packs of 1000 nanocalories to microcalories | |
ldr r0, =TravelEnergy | |
ldr r1, =Energy | |
ldr r2, =set_energy | |
mov r3, #1000 | |
bl convert_unit_base | |
@ function epilogue | |
ldmfd sp!, {r4,lr} | |
bx lr | |
@ Purpose: | |
@ update actual speed to tend toward a certain target speed | |
@ Parameters: | |
@ r0 : delta time | |
@ r1 : value to tend to | |
@ r2 : increment of time required for an update | |
@ r3 : increment of speed per update | |
update_actual_speed: | |
@ function prologue | |
stmfd sp!, {r4-r8,lr} | |
@ local variables: | |
@ r4: delta time | |
@ r5: value to tend to | |
@ r6: increment of time required for an update | |
@ r7: pointer to accumulator | |
@ r8: increment of speed per update | |
mov r4, r0 | |
mov r5, r1 | |
mov r6, r2 | |
ldr r7, =SpeedUpdateAccumulator | |
mov r8, r3 | |
@ accumulate time and store back | |
ldr r2, [r7] | |
add r2, r2, r4 | |
str r2, [r7] | |
@ check if enough time accumulated | |
ldr r3, [r7] | |
cmp r3, r6 | |
blt update_actual_speed_end | |
@ if so, update speed to get close to actual speed and reset timer | |
@ reset accumulator | |
mov r2, #0 | |
str r2, [r7] | |
@ get target/actual speeds and compare | |
mov r3, r5 | |
ldr r2, =ActualSpeed | |
ldr r2, [r2] | |
cmp r3, r2 | |
@ handle different cases | |
@ if TargetSpeed == ActualSpeed, don't do anything | |
beq update_actual_speed_end | |
blt update_actual_speed_decr | |
bgt update_actual_speed_incr | |
@ if TargetSpeed > ActualSpeed, increment ActualSpeed | |
update_actual_speed_incr: | |
ldr r3, =ActualSpeed | |
ldr r2, [r3] | |
add r2, r2, r8 | |
mov r0, r2 | |
bl set_actual_speed | |
bal update_actual_speed_end | |
@ if TargetSpeed < ActualSpeed, decrement ActualSpeed | |
update_actual_speed_decr: | |
ldr r3, =ActualSpeed | |
ldr r2, [r3] | |
sub r2, r2, r8 | |
mov r0, r2 | |
bl set_actual_speed | |
update_actual_speed_end: | |
@ function epilogue | |
ldmfd sp!, {r4-r8,lr} | |
bx lr | |
@ Purpose: | |
@ Updating the state of LEDs while they are asked to flicker by various states. | |
@ Parameters: | |
@ r0 : delta time from update | |
@ r1 : time accumulated necessary for flicker | |
@ r2 : flicker mode: | |
@ mode 0: flicker left and right | |
@ mode 1: flicker both on both off | |
update_led_flicker: | |
@ function prologue | |
stmfd sp!, {r4-r6,lr} | |
@ local variables: | |
@ r4: delta time | |
@ r5: time accumulated necessary for flicker | |
@ r6: flicker mode | |
mov r4, r0 | |
mov r5, r1 | |
mov r6, r2 | |
@ accumulate time and store back | |
ldr r3, =LEDFlickerUpdateAccumulator | |
ldr r2, [r3] | |
add r2, r2, r4 | |
str r2, [r3] | |
@ If accumulated enough, flicker LED and reset accumulator | |
ldr r3, =LEDFlickerUpdateAccumulator | |
ldr r3, [r3] | |
cmp r3, r5 | |
blt update_led_flicker_dont_flicker_LED | |
@ this code only read if it's time for the LED to flicker | |
ldr r3, =LEDFlickerUpdateAccumulator | |
mov r0, #0 | |
str r0, [r3] | |
ldr r3, =LEDState | |
ldr r3, [r3] | |
@ pick new LED state and set it | |
cmp r6, #0 | |
beq update_led_flicker_left_right | |
cmp r6, #1 | |
beq update_led_flicker_both_none | |
update_led_flicker_left_right: | |
cmp r3, #LED_NONE | |
moveq r0, #LED_LEFT | |
beq update_led_flicker_selected_led_state | |
cmp r3, #LED_LEFT | |
moveq r0, #LED_RIGHT | |
beq update_led_flicker_selected_led_state | |
cmp r3, #LED_RIGHT | |
moveq r0, #LED_LEFT | |
beq update_led_flicker_selected_led_state | |
update_led_flicker_both_none: | |
cmp r3, #LED_NONE | |
moveq r0, #LED_BOTH | |
beq update_led_flicker_selected_led_state | |
cmp r3, #LED_LEFT | |
moveq r0, #LED_NONE | |
beq update_led_flicker_selected_led_state | |
cmp r3, #LED_RIGHT | |
moveq r0, #LED_NONE | |
beq update_led_flicker_selected_led_state | |
update_led_flicker_selected_led_state: | |
bl set_led_pattern | |
update_led_flicker_dont_flicker_LED: | |
@ function epilogue | |
ldmfd sp!, {r4-r6,lr} | |
bx lr | |
@ Purpose: | |
@ Updating the scrolling lyrics of eye of the tiger | |
@ Parameters: | |
@ r0 : delta time in ms | |
update_tiger: | |
@ function prologue | |
stmfd sp!, {r4,r5,lr} | |
@ local variables: | |
@ r4: temporary | |
@ r5: temporary | |
@ update accumulator and store back | |
ldr r3, =LyricsAccumulator | |
ldr r2, [r3] | |
add r2, r2, r0 | |
str r2, [r3] | |
@ update offset/lyrics if necessary | |
ldr r3, =LyricsAccumulator | |
ldr r3, [r3] | |
cmp r3, #LYRICS_TIME | |
blt dont_update_tiger | |
@ reset timer | |
ldr r3, =LyricsAccumulator | |
mov r2, #0 | |
str r2, [r3] | |
@ update offset and store back | |
ldr r3, =CurrentLyricsOffset | |
ldr r2, [r3] | |
add r2, r2, #1 | |
str r2, [r3] | |
@ if offset out of bounds, increment current line | |
ldr r3, =CurrentLyrics | |
ldr r3, [r3] | |
ldr r3, [r3] | |
mov r0, r3 | |
bl string_length | |
add r0, r0, #SCREEN_WIDTH | |
add r0, r0, #1 | |
ldr r3, =CurrentLyricsOffset | |
ldr r3, [r3] | |
cmp r3, r0 | |
blt dont_update_tiger_line | |
@ increment current line of lyrics and restart if necessary | |
ldr r3, =CurrentLyricsOffset | |
mov r2, #0 | |
str r2, [r3] | |
ldr r3, =CurrentLyrics | |
ldr r2, [r3] | |
add r2, r2, #4 | |
str r2, [r3] | |
ldr r3, =CurrentLyrics | |
ldr r3, [r3] | |
ldr r3, [r3] | |
cmp r3, #0 | |
bne dont_restart_lyrics | |
ldr r3, =CurrentLyrics | |
ldr r2, =eyeofthetigerLyrics | |
str r2, [r3] | |
dont_restart_lyrics: | |
dont_update_tiger_line: | |
@ copy new state of line to buffer | |
@ clear buffer | |
ldr r0, =CurrentLyricsBuffer | |
ldr r1, =CurrentLyricsBufferLen | |
ldr r1, [r1] | |
mov r2, #32 @ space ascii | |
bl memory_set | |
@ copy new letters over | |
@ calculate offset in buffer properly | |
ldr r2, =CurrentLyricsBufferLen | |
ldr r2, [r2] | |
ldr r1, =CurrentLyricsOffset | |
ldr r1, [r1] | |
sub r2, r2, r1 | |
cmp r2, #0 | |
bge update_tiger_right | |
blt update_tiger_left | |
@ string is to the right of the start of the screen | |
update_tiger_right: | |
ldr r0, =CurrentLyricsBuffer | |
add r0, r0, r2 | |
ldr r1, =CurrentLyrics | |
ldr r1, [r1] | |
ldr r1, [r1] | |
ldr r2, =CurrentLyricsOffset | |
ldr r2, [r2] | |
mov r5, r2 | |
mov r4, r0 | |
mov r0, r1 | |
bl string_length | |
mov r2, r5 | |
cmp r0, r2 | |
movlt r2, r0 | |
mov r0, r4 | |
bl memory_copy | |
bal update_tiger_end_right_left | |
@ string is to the left of the start of the screen | |
update_tiger_left: | |
ldr r2, =CurrentLyricsOffset | |
ldr r2, [r2] | |
ldr r1, =CurrentLyrics | |
ldr r1, [r1] | |
ldr r1, [r1] | |
add r1, r1, r2 | |
ldr r0, =CurrentLyricsBufferLen | |
ldr r0, [r0] | |
sub r1, r1, r0 | |
mov r0, r1 | |
bl string_length | |
mov r2, r0 | |
ldr r0, =CurrentLyricsBuffer | |
bl memory_copy | |
update_tiger_end_right_left: | |
@ replace null terminator of copied string with empty space | |
@ null terminate | |
ldr r3, =CurrentLyricsBuffer | |
ldr r2, =CurrentLyricsBufferLen | |
sub r2, r2, #1 | |
mov r1, #0 | |
strb r1, [r3, r2] | |
dont_update_tiger: | |
@ function epilogue | |
ldmfd sp!, {r4,r5,lr} | |
bx lr | |
@ No-op used as a placeholder for unimplemented function pointers | |
no_op: | |
bx lr | |
@ Bring settings back to default settings | |
reset_stats: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ reset accumulators for travel | |
mov r3, #0 | |
ldr r2, =TravelDistance | |
str r3, [r2] | |
ldr r2, =TravelTime | |
str r3, [r2] | |
ldr r2, =TravelEnergy | |
str r3, [r2] | |
@ reset Weight | |
mov r0, #DFT_WEIGHT | |
bl set_weight | |
@ reset target speed | |
mov r0, #DFT_TARGET_SPEED | |
bl set_target_speed | |
@ reset actual speed | |
mov r0, #0 | |
bl set_actual_speed | |
@ reset time | |
mov r0, #0 | |
bl set_time | |
@ reset distance | |
mov r0, #0 | |
bl set_distance | |
@ reset energy | |
mov r0, #0 | |
bl set_energy | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Lower speed by 0.5 mph | |
lower_speed_2: | |
@ function prologue | |
stmfd sp!, {lr} | |
mov r0, #-5 | |
bl incr_target_speed | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Lower speed by 0.1 mph | |
lower_speed_1: | |
@ function prologue | |
stmfd sp!, {lr} | |
mov r0, #-1 | |
bl incr_target_speed | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Increase speed by 0.1 mph | |
increase_speed_1: | |
@ function prologue | |
stmfd sp!, {lr} | |
mov r0, #1 | |
bl incr_target_speed | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Increase speed by 0.5 mph | |
increase_speed_2: | |
@ function prologue | |
stmfd sp!, {lr} | |
mov r0, #5 | |
bl incr_target_speed | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Lower weight by 10 | |
weight_down_2: | |
@ function prologue | |
stmfd sp!, {lr} | |
mov r0, #-10 | |
bl incr_weight | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Lower weight by 5 | |
weight_down_1: | |
@ function prologue | |
stmfd sp!, {lr} | |
mov r0, #-5 | |
bl incr_weight | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Increase weight by 5 | |
weight_up_1: | |
@ function prologue | |
stmfd sp!, {lr} | |
mov r0, #5 | |
bl incr_weight | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Increase weight by 10 | |
weight_up_2: | |
@ function prologue | |
stmfd sp!, {lr} | |
mov r0, #10 | |
bl incr_weight | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Draw the HUD which displays session info | |
draw_hud: | |
@ function prologue | |
stmfd sp!, {r4-r6,lr} | |
@ local variables registers: | |
@ r4: pointer to current string | |
@ r5: current x | |
@ r6: current y | |
@ set header data | |
ldr r4, =TreadmillHeaderString | |
mov r5, #0 | |
mov r6, #0 | |
@ print header | |
mov r0, r5 | |
mov r1, r6 | |
mov r2, r4 | |
swi SWI_PrintString | |
@ print lyrics | |
mov r0, #0 | |
mov r1, #LYRICS_ROW | |
ldr r2, =CurrentLyricsBuffer | |
swi SWI_PrintString | |
@ print information strings | |
ldr r4, =InformationLineBuffers | |
@ current column to write to (always 0) | |
mov r0, #0 | |
@ current row to write to | |
mov r1, #INFORMATION_BEGIN | |
@ current index of iteration | |
mov r3, #0 | |
draw_hud_print_information_loop: | |
@ get current string | |
ldr r2, [r4, r3, LSL #2] | |
cmp r2, #0 | |
beq draw_hud_print_information_end | |
@ print the current row | |
swi SWI_PrintString | |
@ increment current row and index | |
add r3, r3, #1 | |
add r1, r1, #1 | |
bal draw_hud_print_information_loop | |
draw_hud_print_information_end: | |
@ print footer | |
ldr r4, =ButtonInfoDisplayStrings | |
@ current column to write to (always 0) | |
mov r0, #0 | |
@ current row to write to | |
mov r1, #BUTTON_INFO_BEGIN | |
@ current index of iteration | |
mov r3, #0 | |
draw_hud_print_footer_loop: | |
@ get current string | |
ldr r2, [r4, r3, LSL #2] | |
cmp r2, #0 | |
beq draw_hud_print_footer_end | |
@ print the current row | |
swi SWI_PrintString | |
@ increment current row and index | |
add r3, r3, #1 | |
add r1, r1, #1 | |
bal draw_hud_print_footer_loop | |
draw_hud_print_footer_end: | |
@ function epilogue | |
ldmfd sp!, {r4-r6,lr} | |
bx lr | |
@ Special case where the HUD draws the goodbye message | |
draw_exiting_hud: | |
mov r0, #0 | |
mov r1, #7 @ middle of the screen | |
ldr r2, =GoodbyeString | |
swi SWI_PrintString | |
bx lr | |
@ Purpose: | |
@ sets the current state to passed in state if the actual speed is 0 | |
@ may also depend on the target speed | |
@ Parameters: | |
@ r0 : 1 if target speed must also be zero to stop. anything else otherwise. | |
@ r1 : pointer to state to switch to if condition is true | |
switch_state_if_zero_speed: | |
@ function prologue | |
stmfd sp!, {r4,lr} | |
@ local variables: | |
@ r4: pointer to state to switch to if condition is true | |
mov r4, r1 | |
@ if r0 is 1 then target speed must be 0 to stop | |
cmp r0, #1 | |
bne stop_if_zero_speed_disregard_target | |
ldr r3, =TargetSpeed | |
ldr r3, [r3] | |
cmp r3, #0 | |
bne stop_if_zero_speed_dont_stop | |
stop_if_zero_speed_disregard_target: | |
ldr r3, =ActualSpeed | |
ldr r3, [r3] | |
cmp r3, #0 | |
bne stop_if_zero_speed_dont_stop | |
@ passed tests so switch state to selected state | |
mov r0, r4 | |
bl switch_state | |
stop_if_zero_speed_dont_stop: | |
@ function epilogue | |
ldmfd sp!, {r4,lr} | |
bx lr | |
@ Called when the exiting state is entered | |
exiting_on_enter: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ clear screen | |
swi SWI_BlankLCD | |
@ turn off LEDs | |
mov r0, #LED_NONE | |
bl set_led_pattern | |
@ turn off SSD | |
mov r0, #SSD_OFF | |
bl set_ssd_pattern | |
@ reset shutdown timer | |
ldr r0, =ExitingStateTimer | |
mov r3, #0 | |
str r3, [r0] | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called at each update of the exit state. | |
@ delta time in ms stored in r0 | |
exiting_on_update: | |
@ accumulate delta time on timer | |
ldr r3, =ExitingStateTimer | |
ldr r2, [r3] | |
add r2, r2, r0 | |
@ store accumulated time back in timer | |
str r2, [r3] | |
@ if has accumulated enough time, set program running flag to false. | |
ldr r1, =ExitingDuration | |
ldr r1, [r1] | |
cmp r2, r1 | |
ldrge r1, =IsProgramRunning | |
movge r0, #0 | |
strge r0, [r1] | |
bx lr | |
@ Called when the stopped state is entered | |
stopped_on_enter: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ set SSD to proper pattern | |
mov r0, #SSD_STOPPED | |
bl set_ssd_pattern | |
@ set LED to proper pattern | |
mov r0, #LED_NONE | |
bl set_led_pattern | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the start button is pressed in the stopped state | |
stopped_on_start: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ See if target speed is non-zero | |
ldr r3, =TargetSpeed | |
ldr r3, [r3] | |
cmp r3, #0 | |
@ target speed non-zero, switch to running state | |
ldrne r0, =RunningState | |
blne switch_state | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the off button is pressed in the stopped state | |
stopped_on_off: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ go to exiting state | |
ldr r0, =ExitingState | |
bl switch_state | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the running state is entered | |
running_on_enter: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ set SSD to proper pattern | |
mov r0, #SSD_RUNNING | |
bl set_ssd_pattern | |
@ set LED to proper pattern | |
mov r0, #LED_LEFT | |
bl set_led_pattern | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called at each update of the running state. | |
@ delta time in ms stored in r0 | |
running_on_update: | |
@ function prologue | |
stmfd sp!, {r4,lr} | |
@ local variables: | |
@ r4: passed in delta time | |
mov r4, r0 | |
@ update travel info from delta time | |
mov r0, r4 | |
bl update_travel | |
@ update lyrics info from delta time | |
mov r0, r4 | |
bl update_tiger | |
@ update actual speed to match target speed | |
mov r0, r4 | |
ldr r1, =TargetSpeed | |
ldr r1, [r1] | |
mov r2, #SPEED_UPDATE_INTERVAL | |
mov r3, #RUNNING_SPEED_INCR | |
bl update_actual_speed | |
@ update led flickering | |
mov r0, r4 | |
mov r1, #LED_FLICKER_INTERVAL | |
mov r2, #0 | |
bl update_led_flicker | |
@ stop if target speed = actual speed = 0 | |
mov r0, #1 | |
ldr r1, =StoppedState | |
bl switch_state_if_zero_speed | |
@ function epilogue | |
ldmfd sp!, {r4,lr} | |
bx lr | |
@ Called when the emergency stop button is pressed in running state | |
running_on_emergency_stop: | |
@ function prologue | |
stmfd sp!, {lr} | |
ldr r0, =ShutdownState | |
bl switch_state | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the pause button is pressed in running state | |
running_on_pause: | |
@ function prologue | |
stmfd sp!, {lr} | |
ldr r0, =PausingState | |
bl switch_state | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the shutdown state is entered | |
shutdown_on_enter: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ set SSD to proper pattern | |
mov r0, #SSD_SHUTDOWN | |
bl set_ssd_pattern | |
@ set LED to proper pattern | |
mov r0, #LED_NONE | |
bl set_led_pattern | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the shutdown state updates | |
@ delta time in ms stored in r0 | |
shutdown_on_update: | |
@ function prologue | |
stmfd sp!, {r4,lr} | |
@ local variables: | |
@ r4: passed in delta time | |
mov r4, r0 | |
@ update travel info from delta time | |
mov r0, r4 | |
bl update_travel | |
@ update lyrics info from delta time | |
mov r0, r4 | |
bl update_tiger | |
@ update actual speed to tend toward 0 | |
mov r0, r4 | |
mov r1, #0 | |
mov r2, #SPEED_UPDATE_INTERVAL | |
mov r3, #SHUTDOWN_SPEED_INCR | |
bl update_actual_speed | |
@ update led flickering | |
mov r0, r4 | |
mov r1, #LED_FLICKER_INTERVAL | |
mov r2, #1 | |
bl update_led_flicker | |
@ stop when actual speed reaches 0 regardless of target | |
mov r0, #0 | |
ldr r1, =StoppedState | |
mov r2, #1 | |
bl switch_state_if_zero_speed | |
@ function epilogue | |
ldmfd sp!, {r4,lr} | |
bx lr | |
@ Called when the pausing state is entered | |
pausing_on_enter: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ set SSD to proper pattern | |
mov r0, #SSD_PAUSING | |
bl set_ssd_pattern | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the pausing state updates | |
@ delta time is passed in to r0 | |
pausing_on_update: | |
@ function prologue | |
stmfd sp!, {r4,lr} | |
@ local variables: | |
@ r4: delta time | |
mov r4, r0 | |
@ update travel info from delta time | |
mov r0, r4 | |
bl update_travel | |
@ update lyrics info from delta time | |
mov r0, r4 | |
bl update_tiger | |
@ slow down actual speed by 0.1mph per 0.1 seconds | |
mov r0, r4 | |
mov r1, #0 | |
mov r2, #SPEED_UPDATE_INTERVAL | |
mov r3, #PAUSING_SPEED_INCR | |
bl update_actual_speed | |
@ update led flickering | |
mov r0, r4 | |
mov r1, #LED_FLICKER_INTERVAL | |
mov r2, #0 | |
bl update_led_flicker | |
@ go to Paused state if actual speed is 0 | |
mov r0, #0 | |
ldr r1, =PausedState | |
bl switch_state_if_zero_speed | |
@ function epilogue | |
ldmfd sp!, {r4,lr} | |
bx lr | |
@ Called when the emergency stop button is pressed while pausing | |
pausing_on_emergency_stop: | |
@ function prologue | |
stmfd sp!, {lr} | |
ldr r0, =ShutdownState | |
bl switch_state | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the start button is pressed while pausing | |
pausing_on_start: | |
@ function prologue | |
stmfd sp!, {lr} | |
ldr r0, =RunningState | |
bl switch_state | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the paused state is entered | |
paused_on_enter: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ turn on LEDs | |
mov r0, #LED_BOTH | |
bl set_led_pattern | |
@ set SSD to proper pattern | |
mov r0, #SSD_PAUSED | |
bl set_ssd_pattern | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the start button is pressed during the paused state | |
paused_on_start: | |
@ function prologue | |
stmfd sp!, {lr} | |
ldr r0, =RunningState | |
bl switch_state | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the reset button is pressed during the paused state | |
paused_on_reset: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ reset statistics | |
bl reset_stats | |
@ switch state | |
ldr r0, =StoppedState | |
bl switch_state | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
@ Called when the off button is pressed during the paused state | |
paused_on_off: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ switch state to exiting | |
ldr r0, =ExitingState | |
bl switch_state | |
@ function epilogue | |
ldmfd sp!, {lr} | |
bx lr | |
.global _start | |
_start: | |
@ function prologue | |
stmfd sp!, {lr} | |
@ local variable registers: | |
@ r4: pointer to pointer to current state | |
@ r5: previous time | |
@ r6: delta time | |
@ r7: temporary for button bitset | |
@ r8: temporary for button iterator | |
@ r9: accumulator for redraw time | |
@ initialize local variables in registers | |
@ pointer to current state | |
ldr r4, =CurrentState | |
@ previous time initialized to time at start of program | |
bl get_ticks | |
mov r5, r0 | |
@ delta time initialized to 0 | |
mov r6, #0 | |
@ redraw accumulator initialized to 0 | |
mov r9, #0 | |
@ self explanatory | |
bl initialize_state_machine | |
main_loop_start: | |
@ check if program end was requested | |
ldr r3, =IsProgramRunning | |
ldr r3, [r3] | |
cmp r3, #0 | |
beq main_loop_end | |
@ poll black buttons and handle events | |
bl get_black_buttons_state | |
mov r7, r0 | |
@ start current index | |
mov r8, #0 | |
black_button_poll_start: | |
@ check for end of list | |
ldr r3, =BlackButtonUpdateList | |
ldr r3, [r3, r8, LSL #2] | |
cmp r3, #-1 | |
beq black_button_poll_end | |
@ check if button pressed | |
mov r0, r3 | |
mov r1, r7 | |
bl is_button_pressed | |
@ if pressed, load corresponding function pointer and call the function | |
cmp r0, #0 | |
beq black_button_poll_incr | |
ldr r3, [r4] | |
add r3, r3, #16 | |
ldr r3, [r3, r8, LSL #2] | |
mov lr, pc | |
bx r3 | |
black_button_poll_incr: | |
@ increment current index and loop | |
add r8, r8, #1 | |
bal black_button_poll_start | |
black_button_poll_end: | |
@ poll blue buttons and handle events | |
bl get_blue_buttons_state | |
mov r7, r0 | |
@ start current index | |
mov r8, #0 | |
blue_button_poll_start: | |
@ check for end of list | |
ldr r3, =BlueButtonUpdateList | |
ldr r3, [r3, r8, LSL #2] | |
cmp r3, #-1 | |
beq blue_button_poll_end | |
@ check if button pressed | |
mov r0, r3 | |
mov r1, r7 | |
bl is_button_pressed | |
@ if pressed, load corresponding function pointer and call the function | |
cmp r0, #0 | |
beq blue_button_poll_incr | |
ldr r3, [r4] | |
add r3, r3, #24 | |
ldr r3, [r3, r8, LSL #2] | |
mov lr, pc | |
bx r3 | |
blue_button_poll_incr: | |
@ increment current index and loop | |
add r8, r8, #1 | |
bal blue_button_poll_start | |
blue_button_poll_end: | |
@ update delta time | |
@ get current time and store in r3 | |
bl get_ticks | |
mov r3, r0 | |
@ check if need to modify formula to handle timer wraparound | |
cmp r3, r5 | |
subge r6, r3, r5 | |
ldr r0, =TimerMax | |
ldr r0, [r0] | |
sublt r6, r0, r5 | |
addlt r6, r6, r3 | |
@ store current time in previous time | |
mov r5, r3 | |
@ call OnUpdate on current state | |
ldr r3, [r4] | |
ldr r3, [r3, #4] | |
@ store delta time in r0 | |
mov r0, r6 | |
mov lr, pc | |
bx r3 | |
@ update redraw accumulator | |
add r9, r9, r6 | |
@ handle redraw event if accumulated enough | |
cmp r9, #REDRAW_TIME | |
blt main_loop_dont_redraw | |
@ reset accumulator | |
mov r9, #0 | |
@ call OnRedraw on current state | |
ldr r3, [r4] | |
ldr r3, [r3, #8] | |
mov lr, pc | |
bx r3 | |
main_loop_dont_redraw: | |
@ restart main loop | |
bal main_loop_start | |
main_loop_end: | |
@ deinit state machine | |
bl deinitialize_state_machine | |
@ function epilogue | |
ldmfd sp!, {lr} | |
@ absolute end of program | |
swi SWI_Exit | |
bx lr | |
.data | |
.align | |
@ Flag used to denote a program end request | |
IsProgramRunning: | |
.word 1 | |
SpeedUpdateAccumulator: | |
@ Used to accumulate time to handle increase in speed. | |
.word 0 | |
LEDFlickerUpdateAccumulator: | |
@ Used to accumulate time to flicker LEDs | |
.word 0 | |
@ Variables of the state machine: | |
CurrentState: | |
@ Pointer to current state initialized to NULL | |
.word 0 | |
LEDState: | |
@ Remembers the state of the LED | |
.word LED_NONE | |
TravelTime: | |
@ To be used by update_travel | |
@ Time accumulated while traveling in milliseconds | |
.word 0 | |
TravelDistance: | |
@ To be used by update_travel | |
@ Distance accumulated while traveling in nanomiles | |
.word 0 | |
TravelEnergy: | |
@ To be used by update_travel | |
@ Energy accumulated while traveling in nanocalories | |
Weight: | |
@ lbs | |
.word DFT_WEIGHT | |
WeightLineBuffer: | |
@ Buffer for line to print on screen for weight | |
.skip SCREEN_WIDTH | |
.align | |
TargetSpeed: | |
@ .1 decimal fixed point Mph. | |
.word DFT_TARGET_SPEED | |
TargetSpeedLineBuffer: | |
@ Buffer for line to print on screen for target speed | |
.skip SCREEN_WIDTH | |
.align | |
ActualSpeed: | |
@ .1 decimal fixed point. Mph. | |
.word 0 | |
ActualSpeedLineBuffer: | |
@ Buffer for line to print on screen for actual speed | |
.skip SCREEN_WIDTH | |
.align | |
Time: | |
@ .1 decimal fixed point. Seconds. | |
.word 0 | |
TimeLineBuffer: | |
@ Buffer for line to print on screen for time | |
.skip SCREEN_WIDTH | |
.align | |
Distance: | |
@ .6 decimal fixed point. Miles. | |
.word 0 | |
DistanceLineBuffer: | |
@ Buffer for line to print on screen for distance | |
.skip SCREEN_WIDTH | |
.align | |
Energy: | |
@ .6 decimal fixed point. Calories. | |
.word 0 | |
EnergyLineBuffer: | |
@ Buffer for line to print on screen for energy | |
.skip SCREEN_WIDTH | |
.align | |
InformationLineBuffers: | |
@ List of strings to display stats with | |
.word WeightLineBuffer | |
.word TargetSpeedLineBuffer | |
.word ActualSpeedLineBuffer | |
.word TimeLineBuffer | |
.word DistanceLineBuffer | |
.word EnergyLineBuffer | |
.word 0 | |
@ Lyrics of the eye of the tiger to boil the blood of the runner | |
LyricsAccumulator: | |
@ accumulates time to offset lyrics each x ms | |
.word 0 | |
CurrentLyricsOffset: | |
@ offset of start of letters from the right of the screen as they scroll | |
.word 0 | |
CurrentLyrics: | |
@ pointer to current line of lyrics | |
.word eyeofthetigerLyrics | |
CurrentLyricsBuffer: | |
@ buffer to store current state of lyrics plus null terminator | |
.skip SCREEN_WIDTH | |
.align | |
@ Data for specific states | |
ExitingStateTimer: | |
@ Used to accumulate time and shut off the machine after displaying the message | |
.word 0 | |
.end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment