231a-aj finalProject

From CSclasswiki
Jump to: navigation, search
;;; finalProject.asm
;;; Tonje Stolpestad

;;; To assemble and run
;;; nasm -f elf -F stabs finalProject.asm
;;; gcc -o finalProject serialFin.c asm_io.o finalProject.o
;;; ./finalProject -b 9600 -p /dev/ttyUSB0


%include "asm_io.inc"

;;-------------------------EXTERN LABELS----------------------------------------
extern counter			; counter for the heartbeat
extern serialport_writebyte	; int function
extern serialport_write		; int function
extern serialport_read_until	; int function
extern displayBuffer		; int function
	
extern buf	
extern byte	
	
;;; ---------------------------------------------------------
;;; FILE-RELATED CONSTANTS
;;; ---------------------------------------------------------
%assign SYS_EXIT	1
%assign	SYS_WRITE	4
%assign SYS_READ	3
%assign SYS_LSEEK	19
%assign SEEKSET		0
%assign	STDOUT		1
%assign SYS_OPEN        5
%assign SYS_CLOSE	6
%assign SYS_CREATE	8


%assign O_RDONLY	000000q
%assign O_WRONLY        000001q	
%assign O_RDWR          000002q
%assign O_CREAT		000100q

%assign S_IRUSR		00400q
%assign S_IWUSR		00200q
%assign S_IXUSR		00100q

;;; --- MACRO -----------------------------------------------
;;;     print           msg,length
%macro  print           2               ; %1 = address %2 = # of chars
        pushad                          ; save all registers
        mov             edx,%2
        lea             ecx,[%1]
        mov             eax,SYS_WRITE
        mov             ebx,STDOUT
        int             0x80
        popad                           ; restore all registers
%endmacro

;;; --- MACRO -----------------------------------------------
;;;     print2        "quoted string"
%macro  print2        1               ; %1 = immediate string,
        section .data
%%str   db              %1
%%strL  equ             $-%%str
        section .text
        print           %%str, %%strL
%endmacro

    ;; -------------------------
    ;; data segment
    ;; -------------------------
    section .data
	;; Number of seconds the program will run for 
	programLen dd 10 ; the program will run for 100 seconds
  ;  nameMsg	db	"Hello! Please enter your name: ",0x00
	;;nameAns	db	"231a-aj", 0x00
	ageMsg 		db	"Please enter your age:", 0x00
	ageAns		dd	0
	rhrMsg		db	"Please enter your resting heart rate:", 0x00
	rhrAns		dd	0
	maxHeart	dd	0
	restZone	dd	0
	energyZone	dd	0
	aerobicZone	dd	0
	anaerobicZone	dd	0
	
	;; Numbers used for the floating point opperations
	temp dd 123.45
	base dd 205.8
	firstMul dd 0.685
	restMul dd 0.6
	energyMul dd 0.7
	aerobicMul dd 0.8
	anaerobicMul dd 0.9

	;; To read the counter
	readMsg dd "r a", 0
	readMsgLen equ $-readMsg
	
	;;; the LED messages to pass to the arduino
	g1On	db	"w d 7 1", 0
	msgLen1	equ	$-g1On
	g1Off	db	"w d 7 0", 0
	g2On	db	"w d 6 1", 0
	g2Off	db	"w d 6 0", 0
	y1On	db	"w d 5 1", 0
	y1Off	db	"w d 5 0", 0
	y2On	db	"w d 4 1", 0
	y2Off	db	"w d 4 0", 0
	r1On	db	"w d 3 1", 0
	r1Off	db	"w d 3 0", 0
	r2On	db	"w d 2 1", 0
	r2Off	db	"w d 2 0", 0
	
	;; Variables used for file storage
	fileName db     "data.txt",0
	handle   dd     0
	noRead   dd     0               ; to store # of chars read from file
	msgLen 	dd 0 


    section .bss
	MAXBUF  equ     100000
	buffer  resb    MAXBUF          ; 100,000 bytes of storage
	bufInx	dd 	0

;;; numbers for the delay
tvsec       dd  	0, 0
tvsec2      dd  	0, 0
startTime 	dd 0

    ;; -------------------------
    ;; code area
    ;; -------------------------
    section .text
    global  asm_main
    
	asm_main:       
	
	;; This part asks the user about their age. It is used to compute the maximum heartRate
	mov eax, ageMsg
	call print_string ; calls the function in the asm_io
	call read_int ; calls the function in asm_io
	mov [ageAns], eax
	mov ebx, [msgLen] ;moves the buffer index into ebx
	mov [buffer + ebx], eax ;adds the answer into the buffer to later be written into the file
	add dword[msgLen], 4  ; increment msgLen by a double  word
	
	;; this basically repeats the process above, this time asking for the resting heart rate. d
	mov eax, rhrMsg
	call print_string
	call read_int
	mov [rhrAns], eax
	mov ebx, [msgLen]
	mov [buffer + ebx], eax
	add dword[msgLen], 4

	;; We do some calculations to find the max heartRate and the different zones
	call cheat		; short cut using my specific numbers
	call stopNow	; turn all of the LEDs on so we can see what happens later
	
mainLoop:
	
	;Delay to give the arduino time to get a decent measurement
				;the delay will be 10 seconds
	mov     eax, 78         ; system call: get time of day
    mov     ebx, tvsec      ; address of buffer for secs/usecs
    mov     ecx, 0          ; NULL for timezone
    int     0x80

	mov eax, [tvsec]
	mov [startTime], eax 	; mov the current time into startTime, this is the start time of our delay
	add dword[startTime], 10	; add ten to the startTime, this si now the end time of our delay
delayLoop:
	mov     eax, 78         ; system call: get time of day
    mov     ebx, tvsec      ; address of buffer for secs/usecs
    mov     ecx, 0          ; NULL for timezone
    int     0x80

	mov eax, [tvsec]

	cmp eax, [startTime] 	;compares the current time to the end of the delay
	jl delayLoop			;if it is less we loop again



	;; Get the counter from the external c program. 
	mov eax, readMsg
	mov ecx, readMsgLen
	call copyMsg
	call serialport_write 		;call function in serialFin.c
	call serialport_read_until	;call function in serialFin.c

	mov eax, [counter] ; counter is a variable in the c program

	;; calculate the current bmp
	mov ebx, 6
	imul ebx ; multiply by six because we want the beats per minute, eax now contains the current bmp

	;Saves the current bmp in  the buffer so that it can be written to the file
	mov ebx, [msgLen]
	mov [buffer + ebx], eax
	add dword[msgLen], 4 
	
	;compare to the diffrent zones, and call the function to light the LEDs
	;the numbers used are a percentage of the difference between the max heart rate and the resting heart rate
	cmp eax, [maxHeart] 
	jge stop	;if it is more than the max heart rate you are in danger and need to stop
	cmp eax, [anaerobicZone]
	jge red		; 90%-100%is considered the red line zone. 
	cmp eax, [aerobicZone]
	jge ana		;80%-90% is considered the anaerobic zone
	cmp eax, [energyZone]
	jge aer		;70%-80% is considered the aerobic zone
	cmp eax, [restZone]
	jge ene		;60%-70% is considered the energy efficient zone
	call resting	;anything below 60% is considered resting
done:
	mov eax, [programLen] ;programLen is how many times the main loop should loop
	dec eax
	cmp eax, 0  		; if we hit 0, our training is over
	je trainingover
	mov [programLen], eax
	jmp mainLoop ;if we do not hit  0 we loop again
trainingover:
	;;;     createFile( fileName,  [handle] )
    mov     eax, fileName
    push    eax
    mov     eax, handle
    push    eax
    call    createFile
	;;;		writefile 
    push    dword[handle]
    push    dword buffer
    mov     eax, [msgLen]
    push    eax
    call    writeFile
	;;;     close( [handle] )
    push    dword [handle]
    call    close

        ;; return to C program
	
        ret


;; bits used to call functions
stop:
	call stopNow
	jmp done
red: 
	call redLine
	jmp done
ana:
	call anaerobic
	jmp done
aer: 
	call aerobic
	jmp done
ene: 
	call energy
	jmp done
;;;----------------------------------
;;;	FUNCTIONS
;;;----------------------------------




;;; ----------------------------------------------------------------
;;; copyMsg: puts array whose address in eax  in external buffer
;;; 	      number of bytes shoudl be in ecx.
;;;		made by D. Thiebaut
;;; ----------------------------------------------------------------

copyMsg:
	pushad
	mov	esi, eax	; source buffer
	mov	edi, buf	; destination buffer in C program
.for	mov	al, [esi]
	mov	[edi], al
	inc	esi
	inc	edi
	loop	.for
	popad
	ret
;;;----------------------------------
;;; sendMsg: sends the message in eax
;;;	registers modified: ecx
;;;----------------------------------
sendMsg:
	mov	ecx, msgLen1
  	call	copyMsg                     ;create copy of the message in eax in buf, in C prog
  	call	serialport_write           ;call function in C prog
	ret

	
;;;----------------------------------
;;; stopNow: lights up all the LEDs to
;;;		indicate that the user is going
;;;		over their max heart rate
;;; registers modified: eax, ecx
;;;----------------------------------
stopNow:
	;; turn all the LEDs on
	mov eax, g1On
	call sendMsg
	mov eax, g2On
	call sendMsg
	mov eax, y1On
	call sendMsg
	mov eax, y2On
	call sendMsg
	mov eax, r1On
	call sendMsg
	mov eax, r2On
	call sendMsg
	ret
;;;----------------------------------
;;; redLine: lights up all  but one of the LEDs to
;;;		indicate that the user is in 
;;		the red line zone
;;; registers modified: eax, 
;;;----------------------------------
redLine:
	;; turn all but one red on
	mov eax, g1On
	call sendMsg
	mov eax, g2On
	call sendMsg
	mov eax, y1On
	call sendMsg
	mov eax, y2On
	call sendMsg
	mov eax, r1On
	call sendMsg
	mov eax, r2Off
	call sendMsg
	ret
;;;----------------------------------
;;; anaerobic: lights up the green and yellow the LEDs to
;;;		indicate that the user is in
;;;		teh anaerobic zone
;;; registers modified: eax, 
;;;----------------------------------
anaerobic:
	;; turn yellow and green on
	mov eax, g1On
	call sendMsg
	mov eax, g2On
	call sendMsg
	mov eax, y1On
	call sendMsg
	mov eax, y2On
	call sendMsg
	mov eax, r1Off
	call sendMsg
	mov eax, r2Off
	call sendMsg
	ret
;;;----------------------------------
;;; aerobic: lights up the green and one yellow LEDs to
;;;		indicate that the user is in
;;;		the aerobic zone
;;; registers modified: eax, 
;;;----------------------------------
aerobic:
	;; turn green and one yellow on
	mov eax, g1On
	call sendMsg
	mov eax, g2On
	call sendMsg
	mov eax, y1On
	call sendMsg
	mov eax, y2Off
	call sendMsg
	mov eax, r1Off
	call sendMsg
	mov eax, r2Off
	call sendMsg
	ret
;;;----------------------------------
;;; engergy: lights up the green LEDs to
;;;		indicate that the user is in the
;;;		energy efficient zone
;;; registers modified: eax, 
;;;----------------------------------
energy:
	;; turn the green on
	mov eax, g1On
	call sendMsg
	mov eax, g2On
	call sendMsg
	mov eax, y1Off
	call sendMsg
	mov eax, y2Off
	call sendMsg
	mov eax, r1Off
	call sendMsg
	mov eax, r2Off
	call sendMsg
	ret
;;;----------------------------------
;;; resting: lights up one green LED to
;;;		indicate that the user is resting
;;; registers modified: eax, 
;;;----------------------------------
resting:
	;; turn one green on
	mov eax, g1On
	call sendMsg
	mov eax, g2Off
	call sendMsg
	mov eax, y1Off
	call sendMsg
	mov eax, y2Off
	call sendMsg
	mov eax, r1Off
	call sendMsg
	mov eax, r2Off
	call sendMsg
	ret
;;; ---------------------------------------------------------
;;; sleep: assuming a 2 GHz processor, the instruction
;;;        for: loop for  should take 1 cycle to execute
;;;        since the processor goes through 2E09 cycles 
;;;        per second, loading ecx with 2000000000 before
;;;        the loop should yield something in the order of
;;;        a second delay.
sleep:  push    ecx
        mov     ecx, 2000000000
.for    loop    .for
        pop     ecx
        ret


	
;;; --------------------------------------------------------------
;;; readFile( handle, buffer, buffer_length, number_bytes_read )
;;; reads bytes into buffer.  At most buffer_length bytes are
;;; read.  Number of bytes read are stored in dword number_bytes_read.
;;; Written by D. Thiebaut

readFile:
        push    ebp
        mov     ebp, esp
        
%define rf_handle dword [ebp+20]
%define rf_buffer dword [ebp+16]
%define rf_len    dword [ebp+12]
%define rf_bytes  dword [ebp+8]
        
        pushad
        
	mov	eax,SYS_READ
        mov     ebx, rf_handle
        mov     ecx, rf_buffer
        mov     edx, rf_bytes
	int	0x80
        mov     ebx, rf_bytes   ; get the address of variable
        mov     [ebx], eax      ; put # bytes read in it
        
        popad
        pop     ebp
        ret     4*4

;;; --------------------------------------------------------------
;;; close( handle )
;;; closes the file
;;; written by D. Thiebaut
close:  push    ebp
        mov     ebp, esp
        pushad
        
%define cl_handle dword [ebp+8]
        
        mov	eax,SYS_CLOSE
	mov	ebx,cl_handle
	int	0x80

        popad
        pop     ebp
        ret     4

	
;;; --------------------------------------------------------------
;;; createFile( filename,  handle )
;;; creates a file whose name is pointed to by filename, and puts
;;; the handle in the dword variable handle.
;;; Does not modify registers.
;;;	written by D. Thiebaut
createFile:     
        push    ebp
        mov     ebp, esp
        pushad
        
%define cf_fileName dword[ebp+12]
%define cf_handle   dword[ebp+8]
        
	mov	eax,SYS_CREATE
	mov	ebx,cf_fileName
	mov	ecx, S_IRUSR|S_IWUSR|S_IXUSR
	int	0x80

	test	eax,eax
	jns	.fileOk
	print2  "Could not create file"
	mov	eax,SYS_EXIT
	mov	ebx,0
	int	0x80		; final system call

.fileOk:
        mov     ebx, cf_handle
        mov     [ebx], eax

.done:  popad                   ; restore registers
        pop     ebp
        ret     8

;;; --------------------------------------------------------------
;;; openFile( filename, handle )
;;; opens a file for reading, puts handle in dword whose address
;;; is passed in stack.
;;; Does not modify the registers, but modifies flags.
;;; written by D. Thiebaut
openFile:
        push    ebp	
        mov     ebp, esp
        pushad
        
%define of_fileName dword[ebp+12]
%define of_handle   dword[ebp+8]
        
	mov	eax,SYS_OPEN
	mov	ebx, of_fileName
	mov	ecx, O_RDONLY
	mov	edx, S_IRUSR|S_IWUSR|S_IXUSR
	int	0x80

	test	eax,eax
	jns	.fileOk
        print2  "Error opening file"
        mov     eax, SYS_EXIT
        mov     ebx, 1
        int     0x80

.fileOk:
        mov     ebx, of_handle
	mov	[ebx], eax	; save handle
        
.done:  popad                   ; restore registers
        pop     ebp
        ret     8
	
;;; --------------------------------------------------------------
;;; writeFile( handle, buffer, bufferLen )
;;; writes bufferLen bytes stored in buffer to file whose handle
;;; is in "handle"
;;; written by D. Thiebaut
writeFile:
        push    ebp
        mov     ebp, esp
        pushad

%define wf_handle [ebp+16]
%define wf_buffer [ebp+12]
%define wf_len    [ebp+8]
        
	mov	eax,SYS_WRITE
	mov	ebx,wf_handle
	mov	ecx,wf_buffer
	mov	edx,wf_len
	int	0x80

        popad
        pop     ebp
        ret     3*4


;;; ---------------------------------------------
;;; floatCompute: computes the different zones and 
;;;			max heart rate using floating point
;;;	registers modified: eax, ebx, 
;;;----------------------------------------------

floatCompute:	
	;; Calculate max heart rate
	fild dword[ageAns]
	fld dword[firstMul]	;load 0.685 into the stack
	fmul st0, st1 ; multiply temp and firstMul
	fchs	; changes the sign of what is on the stack
	fld dword[base] ; adds 205.8 to the stack
	fadd st0, st1 ; add the two together
	fistp dword[maxHeart] ; get the answer back out and it is an integer
	
	
	;; calculate the different zones
	mov ebx, [maxHeart]
	mov eax,[rhrAns]
	sub ebx, eax
	mov [temp], ebx
	fld dword[temp]
	fld dword[restMul]
	fmul st0, st1
	fistp dword[restZone]
	mov [temp], ebx
	fld dword[temp]
	fld dword[energyMul]
	fmul st0, st1
	fistp dword[energyZone]
	mov [temp], ebx
	fld dword[temp]
	fld dword[aerobicMul]
	fmul st0, st1
	fistp dword[aerobicZone]
	mov [temp], ebx
	fld dword[temp]
	fld dword[anaerobicMul]
	fmul st0, st1
	fistp dword[anaerobicZone]
	 ret


;;; -------------------------------------
;;; cheat: a short cut to get around all 
;;;		the floating point operations of 
;;;		floatcompute
;;;-------------------------------------
cheat:
	;; takes the precalculated values for me (ie T. Stolpestad) and uses those
	mov dword[maxHeart],191
	mov dword[restZone], 138
	mov dword[energyZone], 151
	mov dword[aerobicZone],164
	mov dword[anaerobicZone], 177
	ret