;Firmware for the avr in the GWEMeter-setup.
;Copyright 2006 Jeroen Domburg <gwemeter@jeroen.ietsmet.nl>. This
;software is licensed under the GPL.

;We're using a tiny2313 here.
.device ATTiny2313
;You might want to include the ATTiny2313-definitions included with
;your assembler. I use gavrasm, which doesn't need them.

;The fuses should be configured as follows:
;FUSE_L=0xcf
;FUSE_H=0xdf

;Port declarations

;PortB
.equ led1	=	7
.equ ldr1	=	6
.equ led2	=	5
.equ ldr2	=	4
.equ led3	=	3
.equ ldr3	=	2
.equ led4	=	1
.equ ldr4	=	0

;Port D
.equ ind1	=	2
.equ ind2	=	3
.equ ind3	=	4
.equ ind4	=	5

.def a1		=	r1
.def a2		=	r2
.def a3		=	r3
.def b1		=	r4
.def b2		=	r5
.def b3		=	r6
.def c1		=	r7
.def c2		=	r8
.def c3		=	r9
.def d1		=	r10
.def d2		=	r11
.def d3		=	r12
.def temp	=	R16 	;The temp register
.def temp2	=	R17 	;Second temp register
.def temp3	=	R18
.def tha	=	r19
.def thb	=	r20
.def thc	=	r21
.def thd	=	r22
.def oldon	=	r23

	rjmp start		; reset vector
	reti			; External Int 0 not enabled
	reti			; External Int 1 not enabled
	reti			; Timer 1 Capture Int not enabled
	reti			; Timer 1 Compare match A Int not enabled
	reti			; Timer 1 Overflow Int not enabled
	reti			; Timer 0 Overflow Int not enabled
	reti			; UART ReceiveInt
	reti			; UART Date Reg Empty Int not enabled
	reti			; UART tx'ed Int Not enabled
	reti			; Anacomp interrupt Not enabled


start:
	ldi temp,RAMEND		; top of memory
	out SPL,temp		; init stack pointer
	ldi temp,0b010101010	; Port B direction options
	out DDRB,temp		; Setup port direction
	ldi temp,0b00111100	; Port D direction options
	out DDRD,temp		; Setup port direction

;Configure uart
	ldi temp,0b011000
	out ucsrb,temp
	ldi temp,0b0110
	out ucsrc,temp
	ldi temp,high(10)
	out ubrrh,temp
	ldi temp,low(10)
	out ubrrl,temp

;Wait till the router has booted completely and the program that reads out
;the uC is running. We know that because that program sends the magic string
; 'M4g1c!' on start.
wait4magic:
	ldi temp,0b0000
	out portd,temp
	rcall getchar
	cpi temp,'M'
	brne wait4magic
	ldi temp,0
	out portd,temp
	rcall getchar
	cpi temp,'4'
	brne wait4magic
	sbi portd,ind1
	rcall getchar
	cpi temp,'g'
	brne wait4magic
	sbi portd,ind2
	rcall getchar
	cpi temp,'1'
	brne wait4magic
	sbi portd,ind3
	rcall getchar
	cpi temp,'c'
	brne wait4magic
	rcall getchar
	sbi portd,ind4
	cpi temp,'!'
	brne wait4magic

	clr a1
	clr a2
	clr a3
	clr b1
	clr b2
	clr b3
	clr c1
	clr c2
	clr c3
	clr d1
	clr d2
	clr d3

mainloop:
	;Got a command?
	sbic ucsra,7
	 rjmp recvcmd ;Yes -> handle it.

;Counting stuff
	ldi temp2,0

	cbi portd,ind1
	ldi temp,1<<led1
	rcall readraw
	cp temp,tha
	brlo notset1
	ori temp2,0b1
	sbi portd,ind1
notset1:
	cbi portd,ind2
	ldi temp,1<<led2
	rcall readraw
	cp temp,thb
	brlo notset2
	ori temp2,0b10
	sbi portd,ind2
notset2:
	cbi portd,ind3
	ldi temp,1<<led3
	rcall readraw
	cp temp,thc
	brlo notset3
	ori temp2,0b100
	sbi portd,ind3
notset3:
	cbi portd,ind4
	ldi temp,1<<led4
	rcall readraw
	cp temp,thd
	brlo notset4
	ori temp2,0b1000
	sbi portd,ind4
notset4:
	
	mov temp3,oldon
	mov oldon,temp2
	eor temp3,temp2
	and temp3,temp2
	
	ldi temp2,0
	ldi temp,1
	sbrs temp3,0
	 rjmp notadd1
	add a1,temp
	adc a2,temp2
	adc a3,temp2
notadd1:
	sbrs temp3,1
	 rjmp notadd2
	add b1,temp
	adc b2,temp2
	adc b3,temp2
notadd2:
	sbrs temp3,2
	 rjmp notadd3
	add c1,temp
	adc c2,temp2
	adc c3,temp2
notadd3:
	sbrs temp3,3
	 rjmp notadd4
	add d1,temp
	adc d2,temp2
	adc d3,temp2
notadd4:

	rjmp mainloop

;Proto:
;Get& clear current counters
; >G <a1 <a2 <a3 <b1 <b2 <b3 <c1 <c2 <c3 <d1 <d2 <d3
;Get thresholds
; >t <tha <thb <thc <thd
;Set thresholds
; >T >tha >thb >thc >thd
;Get a raw sample
; >R <samplea <sampleb <samplec <sampled
;Calibrate a channel
; >C >['1'-'4'] .... >dummy <min <max
	
getcounters:
	mov temp,a1
	rcall putchar
	mov temp,a2
	rcall putchar
	mov temp,a3
	rcall putchar
	mov temp,b1
	rcall putchar
	mov temp,b2
	rcall putchar
	mov temp,b3
	rcall putchar
	mov temp,c1
	rcall putchar
	mov temp,c2
	rcall putchar
	mov temp,c3
	rcall putchar
	mov temp,d1
	rcall putchar
	mov temp,d2
	rcall putchar
	mov temp,d3
	rcall putchar
	clr a1
	clr a2
	clr a3
	clr b1
	clr b2
	clr b3
	clr c1
	clr c2
	clr c3
	clr d1
	clr d2
	clr d3
	rjmp mainloop


recvcmd:
	;Got serial command.
	in temp,udr
	cpi temp,'G'
	breq getcounters
	cpi temp,'t'
	breq getthresh
	cpi temp,'T'
	breq setthresh
	cpi temp,'R'
	breq readval
	cpi temp,'C'
	breq calibrate
	cpi temp,'!'
	breq pingack
	ldi temp,'?'
	rcall putchar
	rjmp mainloop
	
pingack:
	ldi temp,'~'
	rcall putchar
	rjmp mainloop
	
getthresh:
	mov temp,tha
	rcall putchar
	mov temp,thb
	rcall putchar
	mov temp,thc
	rcall putchar
	mov temp,thd
	rcall putchar
	rjmp mainloop
	
setthresh:
	rcall getchar
	mov tha,temp
	rcall getchar
	mov thb,temp
	rcall getchar
	mov thc,temp
	rcall getchar
	mov thd,temp
	rjmp mainloop
	
readval:
	ldi temp,1<<led1
	rcall readraw
	rcall putchar
	ldi temp,1<<led2
	rcall readraw
	rcall putchar
	ldi temp,1<<led3
	rcall readraw
	rcall putchar
	ldi temp,1<<led4
	rcall readraw
	rcall putchar
	rjmp mainloop

calibrate:
	rcall getchar
	ldi temp2,0
	cpi temp,'1'
	brne notcal1
	ldi temp2,1<<led1
notcal1:
	cpi temp,'2'
	brne notcal2
	ldi temp2,1<<led2
notcal2:
	cpi temp,'3'
	brne notcal3
	ldi temp2,1<<led3
notcal3:
	cpi temp,'4'
	brne notcal4
	ldi temp2,1<<led4
notcal4:
	cpi temp2,0
	breq notcal
	
	mov temp,temp2
	;temp2=max, temp3=min
	ldi temp2,0
	ldi temp3,255
calloop:
	push temp
	rcall readraw
	cp temp,temp2
	brlo calnh
	mov temp2,temp	
calnh:
	cp temp,temp3
	brsh calnl
	mov temp3,temp	
calnl:
	pop temp
	sbis ucsra,7
	 rjmp calloop	
	in temp,udr
	mov temp,temp2
	rcall putchar
	mov temp,temp3
	rcall putchar
notcal:
	rjmp mainloop
	
	
;Measure an indication for the amount of light on the phototransistor. This
;works by discharging the capacitor, enabling the led, tristating the capacitor-
;output and waiting till the voltage rises enough for the input to become a 
;logical '1'. The time that we've been waiting will be in temp.
readraw:
	push temp2
	push temp3
	mov temp3,temp
	;Make the led-pin as wel as the capacitor-pin an output
	mov temp2,temp
	lsr temp
	or temp2,temp
	out ddrb,temp2
	;Capacitor pin to '0', led on.
	ldi temp,0
	out portb,temp
	
	;Wait for the capacitor to discharge
	ldi temp,0
waitdischarge:
	nop
	dec temp
	brne waitdischarge
	
	;Tristate the capacitor pin & enable the led
	out ddrb,temp3
	ldi temp,0
	out portb,temp
	
	;Wait for the input to become '1' again.
	ldi temp,-1
waitcharge:
	inc temp
	;Temp mustn't overflow and warp around: better to bail out before.
	cpi temp,255
	breq chargeovf
	
	;Internal waitloop.
	cpi temp,50
	brlo notwaitlonger
	ldi temp2,65
	rjmp waitcharge2
notwaitlonger:
	ldi temp2,20
waitcharge2:
	dec temp2
	brne waitcharge2
	
	;Is it '1' already?
	in temp2,pinb
	lsl temp2
	and temp2,temp3
	cpi temp2,0
	breq waitcharge

chargeovf:
	ldi temp2,0
	out ddrb,temp2
	out portb,temp2
	
	pop temp3
	pop temp2
	ret


;Sends a char to the serial port
putchar:
	sbis ucsra,5
	 rjmp putchar
	out udr,temp
	ret

;Receives a char from the serial port.
getchar:
	sbis ucsra,7
	 rjmp getchar
	in temp,udr
	ret

