231a-af talkToArduino

From CSclasswiki
Jump to: navigation, search

The file can be accessed from here.
Return to Final Project Presentation.

;;; ; talkToArduino.asm
;;; ; Jessica Lin
;;; ; This program requires arduino-serial.c for handling the
;;; ; communication with an Arduino diecimila.
;;; ; 
;;; ; To assemble and run
;;; ;  nasm -f elf talkToArduino.asm
;;; ;  gcc -o arduino-serial  arduino-serial.c  talkToArduino.o
;;; ;  ./arduino-serial -b 9600 -p /dev/ttyUSB0
;;; ;

;;; ; ----------------------- EXTERN LABELS -----------------------
extern serialport_writebyte ; int function
	extern serialport_write	    ; int function
extern serialport_read_until ; int function
extern displayBuffer	     ; int function

extern buf
extern byte

%include "asm_io.inc"

%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,4
        mov             ebx,1
        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

;;; ; --- MACRO -----------------------------------------------
;;; ; 	createFile filename,  handle
%macro	createFile 2
	mov	eax,SYS_CREATE
	mov	ebx,%1
	mov	ecx, S_IRUSR|S_IWUSR|S_IXUSR
	int	0x80

	test	eax,eax
	jns	%%createfile
	print2  "Could not open file"
	mov	eax,SYS_EXIT
	mov	ebx,0
	int	0x80		; final system call

%%createfile:
	mov	%2,eax		; save handle
%endmacro
	

;;; ; --- MACRO -----------------------------------------------
;;; ; 	openFile filename, mode, handle
%macro	openFile 3
	mov	eax,SYS_OPEN
	mov	ebx,%1
	mov	ecx,%2
	mov	edx, S_IRUSR|S_IWUSR|S_IXUSR
	int	0x80

	test	eax,eax
	jns	%%readFile
	print2  "Could not open file"
	mov	eax,SYS_EXIT
	mov	ebx,0
	int	0x80		; final system call

%%readFile:
	mov	%3,eax		; save handle
%endmacro

;;; ; --- MACRO -----------------------------------------------
;;; ; 	readFile handle, buffer, buffer-length, number-bytes-read
%macro  readFile 4
	mov	eax,SYS_READ
	mov	ebx,%1		; file descriptor in bx
	mov	ecx,%2		; buffer address
	mov	edx,%3		; max number of bytes to read
	int	0x80
	mov	%4,eax		; save number bytes read
%endmacro

;;; ; --- MACRO -----------------------------------------------
;;; ; 	writeBuf handle, buffer, noBytesToWrite
%macro  writeFile 3
	mov	eax,SYS_WRITE
	mov	ebx,%1
	mov	ecx,%2
	mov	edx,%3
	int	0x80
%endmacro

;;; ; --- MACRO -----------------------------------------------
;;; ;     close   handle
%macro  close   1
        mov     eax,SYS_CLOSE
        mov     ebx,%1
	int     0x80
%endmacro


;;;  -------------------------
;;;  data segment
;;;  -------------------------
        section .data
msg1        db	"w d 13 1", 0
msg1len     equ	$-msg1

msg2        db	"w d 13 0", 0
msg2len     equ	$-msg2

msg3        db	"r a", 0
msg3len     equ	$-msg3

msg4        db	"w d 13 "
msg4val     db	" ", 0
msg4len     equ	$-msg4

home        db              27,"[2J" 	; clear the screen
            db              27,"[1;1H" 	; ansi sequence to bring
					; cursor at position 1,1
homeLen     equ             $-home

fileName    db  "data.txt",0
handle	    dd	0
noRead	    dd	0
	
timemsg	    db	" seconds remaining!", 0x00
tmsglen	    equ $-timemsg
leavemsg    db  "Time to go!", 0x00

tvsec	    dd	0
tvusec	    dd	0
start	    dd  0		; time the program begins running
latest	    dd	0		; time at the last at/away computer switch
current	    dd	0		; current time
here	    dd	0		; how long user has been at computer
MAXHERE	    dd	60		; max length of time user can be at computer
gone	    dd	0		; how long user has been gone
MINGONE	    dd	15		; min length of time user must be away
oldal	    dd	'0'
TEMPTOTAL   dd	480		; will run for 8 minutes

        section .bss
MAXBUF	equ	100000
fbuffer resb	MAXBUF
	
;;;  -------------------------
;;;  code area
;;;  -------------------------
        section .text
        global  asm_main
asm_main:

	;; create file to store information
	createFile	fileName, [handle]

	call	timeofDay		; eax = # secs since epoch
	mov	dword[start], eax
	mov	dword[latest], eax
	mov	dword[current], eax

	mov	byte[fbuffer], 's'
	mov	byte[fbuffer+1], 't'
	mov	byte[fbuffer+2], 'a'
	mov	byte[fbuffer+3], 'r'
	mov	byte[fbuffer+4], 't'
	mov	byte[fbuffer+5], " "
	mov	dword[fbuffer+6], eax
	mov	byte[fbuffer+10], 0x0a

	writeFile	[handle], fbuffer, 11
	
	close		[handle]


.for:
	sub	eax, TEMPTOTAL
	cmp	eax, dword[start]
	je	.exit
	
 	call	readPin1	; get status of Pin 1 in al

	push	eax		; make space
	push	eax		; push status of Pin 1
	mov	eax, latest
	push	eax		; push address of latest time
	mov	eax, dword[current]
	push	eax		; push current time
	mov	eax, oldal
	push	eax		; push address of old al
	mov	eax, here
	push	eax		; push address of here counter
	mov	eax, gone
	push	eax		; push address of gone counter
	call	changeState
	pop	eax		; return status of Pin 1


	push	eax		; make space to store variable
	push	eax		; push status of Pin 1
	mov	eax, dword[current]
	push	eax		; push current time
	mov	eax, dword[latest]
	push	eax		; push latest time
	mov	eax, here
	push	eax		; push address of here counter
	mov	eax, gone
	push	eax		; push address of gone counter
	call	update		; updates time counters
	pop	eax

	call	setPin13	; set Pin 13 to value in al

	mov	eax, dword[here]
	push	eax			; push here time counter
	mov	eax, dword[gone]
	push	eax			; push gone time counter
	call	monitor

.time:	call	timeofDay
	cmp	eax, dword[current]
	je	.time
	
	mov	dword[current], eax

	call	print_nl

	jmp	.for

;;;  return to C program
.exit:
	ret

;;; ; ----------------------------------------------------------------
;;; ; copyMsg1: puts array whose address in eax  in external buffer
;;; ; 	      number of bytes shoudl be in ecx.
;;; ; ----------------------------------------------------------------
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

;;; ; ----------------------------------------------------------------
;;; ; delay 100 ms.
;;; ; ----------------------------------------------------------------
delay100ms:
	pushad

	mov	ecx, 100000000	; 200,000,000 cycles (assuming 2GHz)
.for	add	eax, 1	; 1 cycle
	loop	.for		; 1 cycle

	popad
	ret

;;; ; ----------------------------------------------------------------
;;; ; readPin1: sends the arduino a request for value of pins
;;; ;           if Pin1 < 100,
;;; ;		  al = '0'
;;; ;		else al = '1'
;;; ; ----------------------------------------------------------------
readPin1:
	mov	eax, msg3
	mov	ecx, msg3len	; "r a" read analog pins
	call	copyMsg		; now buf contains "r a"
	call	serialport_write

	call	serialport_read_until
	;;  	call	displayBuffer
	
	mov	al, [buf+8]
	cmp	al, 0x20
	je	.far
	mov	al,'1'
	jmp	.done
.far:	mov	al, '0'

.done:		
	ret

;;; ; ----------------------------------------------------------------
;;; ; SetPin13: sets pin 13 to the value '0' or '1' passed in al
;;; ; ----------------------------------------------------------------
setPin13:
	pushad

	mov	byte[msg4val], al	; and embed '0' or '1' at right place
	mov	eax, msg4
	mov	ecx, msg4len		; copy msg4 in buf
	call	copyMsg
	;;  	call    displayBuffer
	call	serialport_write 	; send message "w d 13 x" to arduino

	popad			 	; restore registers

	ret

;;; ; ----------------------------------------------------------------
;;; ; timeofDay: sets eax = current # seconds since Jan 1st, 1970
;;; ; ----------------------------------------------------------------
timeofDay:
	mov	eax, 78
	mov	ebx, tvsec
	mov	ecx, 0
	int 	0x80

	mov	eax, [tvsec]

	ret

;;; ; ----------------------------------------------------------------
;;; ; update: updates the time counters
;;; ; ----------------------------------------------------------------
update:
	push	ebp
	mov	ebp, esp

	sub	esp, 4

%define	return	dword[ebp+28]		; will push status of pin after
%define	pin	dword[ebp+24]		; status of pin1
%define	time	dword[ebp+20]		; current time
%define	latest	dword[ebp+16]		; latest time of at/away from computer
%define	near	dword[ebp+12]		; address of time counter
%define	far	dword[ebp+8]		; address of time counter
%define	diff	dword[ebp-4]		; difference = current - latest

	;; find difference between latest and current times
	push	eax
	mov	eax, time
	sub	eax, latest
	mov	diff, eax
	pop 	eax

	;; determines if user is at computer or not
	cmp	pin, '0'
	je	.notHere		; if user not at computer

	cmp	pin, '1'		
	je	.here			; if user at computer

	print2	"error!"
	call	print_nl
	jmp	.exit

.notHere:				; update "far" counter
	push	eax
	push	ebx
	mov	ebx, far
	mov	eax, diff
	mov	dword[ebx], eax		; far counter = difference in time
	pop 	ebx
	pop	eax
	jmp	.exit

.here:					; update "near" counter
	call	print_nl
	push	eax
	push	ebx
	mov	eax, near
	mov	ebx, diff
	mov	dword[eax], ebx		; near counter = difference in time
	pop 	ebx
	pop	eax
	
.exit:
	push	eax
	mov	eax, pin
	mov	return, eax
	pop	eax
	
	mov	esp, ebp
	pop	ebp
	ret 	20



;;; ; ----------------------------------------------------------------
;;; ; changeState: if user leaves/returns to computer
;;; ; ----------------------------------------------------------------
changeState:
	push	ebp
	mov	ebp, esp

%define	return	dword[ebp+32]		; will push status afterwards
%define	pin1	dword[ebp+28]		; status of pin 1
%define	lataddr	dword[ebp+24]		; adrress of latest time
%define	current	dword[ebp+20]		; current time
%define	oldaddr	dword[ebp+16]		; address of old status of pin 1
%define	near	dword[ebp+12]		; address of time counter
%define	far	dword[ebp+8]		; address of time counter

	push	eax
	push 	ebx
	mov	eax, oldaddr
        mov	ebx, [eax]
	cmp	ebx, pin1		; compare old al and new al
	je	.done

	;; set latest time to be current time
	mov	eax, lataddr		; eax = &latest
	mov	ebx, current		; ebx = current time
	mov	dword[eax], ebx		; latest time = current time

	;; resets value of old al (status of pin1)
	mov	eax, oldaddr		; eax = &oldal
	mov	ebx, pin1
	mov	dword[eax], ebx		; oldal = new al
	

	;; set both time counters to 0	
	mov	eax, near
	mov	dword[eax], 0
	mov	eax, far
	mov	dword[eax], 0

	;; record information in data.txt
	mov	eax, pin1
	push	eax
	mov	eax, current
	push 	eax
	call	writeToFile
	

.done:
	;; put status of pin1 status back in top spot	
	mov	eax, pin1
	mov	return, eax

	pop	ebx
	pop	eax
	pop	ebp
	ret	24

;;; ; ----------------------------------------------------------------
;;; ; monitor: monitors how long the user has been at the computer
;;; ; ----------------------------------------------------------------
monitor:
	push	ebp
	mov	ebp, esp

%define	here	dword[ebp+12]
%define	gone	dword[ebp+8]

	;; 	call	clrScreen
	cmp	here, 0
	je	.gone

.here:
	push	eax
	mov	eax, dword[MAXHERE]
	cmp	eax, here
	
	ja	.hereLow

	mov	eax, leavemsg
	call	print_string
	call	print_nl
	;; 	print2	0x07			; this SHOULD make console beep
	pop	eax
	jmp	.done
	
.hereLow:
	sub	eax, here
	call	print_int
	mov	eax, timemsg
	call	print_string
	call	print_nl
	pop	eax
	jmp	.done

.gone:
	push	eax
	mov	eax, dword[MINGONE]
	cmp	eax, gone
	ja	.goneLow

	print2	"You can come back now!"
	call	print_nl
	pop	eax
	jmp	.done

.goneLow:
	sub	eax, gone
	call	print_int
	mov	eax, timemsg
	call	print_string
	call	print_nl
	pop	eax
	jmp	.done
	
.done:	pop	ebp
	ret	8

;;; ; ----------------------------------------------------------------
;;; ; clrScreen:  clears the screen and brings the cursor
;;; ; to "home" position.  This is done by using ANSI sequences
;;; ; that, when sent to the screen, do not actually print
;;; ; anything, but instead modify different things, such as
;;; ; the position of the cursor, the contents of the screen,
;;; ; or other screen-related properties.  All ansi sequences
;;; ; start with Ascii 27, which is the ESCape character.
;;; ; ----------------------------------------------------------------	
clrScreen:
        pushad		; save all registers

        mov             eax,4
        mov             ebx,1
        lea             ecx,[home]
        mov             edx,homeLen
        int             0x80

        popad		; restore all registers
        ret

;;; ; ----------------------------------------------------------------
;;; ; writeToFile: writes the current state change to data.txt
;;; ; 		   having difficulties writing to the file
;;; ; ----------------------------------------------------------------
writeToFile:
	push	ebp
	mov	ebp, esp

%define pin1	dword[ebp+12]
%define	time	dword[ebp+8]

	;; store current contents of file in fbuffer
        openFile        fileName, O_RDWR,  [handle]
	readFile        [handle], fbuffer, MAXBUF, [noRead]
        close           [handle]
	push	eax
	push	ebx
	mov	eax, [noRead]
	call	print_int
	call	print_nl

	cmp	pin1, '0'
	jne	.present

.disappeared:
	mov	byte[fbuffer+eax], 'l'
	mov	byte[fbuffer+eax+1], 'e'
	mov	byte[fbuffer+eax+2], 'f'
	mov	byte[fbuffer+eax+3], 't'
	mov	byte[fbuffer+eax+4], " "
	mov	ebx, time
	mov	dword[fbuffer+eax+5], ebx
	mov	byte[fbuffer+eax+9], 0x0a
	add	eax, 10
	mov	ebx, eax
	jmp	.done

.present:
	mov	byte[fbuffer+eax], 'r'
	mov	byte[fbuffer+eax+1], 'e'
	mov	byte[fbuffer+eax+2], 't'
	mov	byte[fbuffer+eax+3], 'u'
	mov	byte[fbuffer+eax+4], 'r'
	mov	byte[fbuffer+eax+5], 'n'
	mov	byte[fbuffer+eax+6], 'e'
	mov	byte[fbuffer+eax+7], 'd'
	mov	byte[fbuffer+eax+8], " "
	mov	ebx, time
	mov	dword[fbuffer+eax+9], ebx
	mov	byte[fbuffer+eax+13], 0x0a
	add	eax, 14
	mov	ebx, eax

.done:
        createFile      fileName, [handle]
        writeFile       [handle], fbuffer, ebx
        close           [handle]
	
	pop	ebp
	ret	8