;***************************************************************************
;* BelliBot's first Brain :) - based on Atmels rc5uart for infrared controll
;* (c.) by B.F
;* thanks to many other resources on the internet
;* they may help me out
;*--------------------------------
;* File Name :"rc5uart.asm"
;* Title :RC5 IR Remote Control Decoder
;* Target MCU :AT90S2313
;*
;* DESCRIPTION
;* This Application note describes how to decode the frequently used
;* RC5 IR remote control protocol.
;*
;* The timing is adapted for 4 MHz crystal
;* This program is infact a mixing of the code for the rc5 communication
;* and a full duplex hardware UART
;*
;***************************************************************************
.include "2313def.inc"

;************ rc5 commands ********
.equ halt   = 54
.equ vor	= 28
.equ rueck 	= 48
.equ links	= 33
.equ rechts = 32
.equ speedp = 30
.equ speedm = 31
.equ beep   = 12
.equ light  = 53
.equ erku   = 61
;*************** Flag's in BotFlag ************ R25 ********
.equ  Dwn  = 0	; Flag0 = hinten microschalter
.equ  Rpt  = 1	; Flag1 = 
.equ  Acc  = 2	; Flag2 = 
.equ  aua  = 3	; Flag3 = Kollisionsflag inf.sensor !! - und interupt 1
.equ  aual = 4   ; linker sensor front
.equ  auar = 5	; rechter sensor front
;portd6 = input tsop infrared
.equ INPUT =6		;(PD6)
.equ SYS_ADDR =20 	;The system address
;**********************
.equ PZ = 6	; Bit6 portb fuer piezo

;**********************
.def S =R0 		; Storage for the Status Register
.def inttemp =R1 	; Temporary variable for ISR
.def ref1 =R2
.def ref2 =R3 		; Reference for timing
.def tick =R4		; time for tea every 16ms
.def stemp =R5		; SPEED TEMP INC_DEC VALUE
.def outzeit = R6    ; Auszeit
.def	RAND1		=R7	;Random number generator needs three
.def	RAND2		=R8	;bytes. This could just as well be
.def	RAND3		=R9	;SRAM, but it would be a little slower
.def	verz1		=R10	; merker fuer delay

.def temp =R16 		; Temporary variable
.def timerL =R17 	; Timing variable updated every 14 us
.def timerH =R18 	; Timing variable updated every 16 ms
.def system =R19 	; Address data received
.def command =R20	; Command received
.def bitcnt =R21 	; Counter
.def temp2=r22
.def M_reg = R23	; motor register BellBot
.def M_sp = R24
.def BotFlag =R25	; steuerflags fuer botis verhalten ( intelli )

;****************************************

.cseg
.org 0

    rjmp RESET          ;Reset Handler
    nop	;rjmp autsch       ;IRQ0 Handler
    rjmp autsch       	;IRQ1 Handler
    nop;rjmp TIM_CAPT1      ;Timer1 Capture Handler
    nop;rjmp TIM_COMP1      ;Timer1 Compare Handler
    nop;rjmp TIM_OVF1       ;Timer1 Overflow Handler
    rjmp TIM0_OVF       ;Timer0 Overflow Handler
    nop;rjmp UART_RXC       ;UART RX Complete Handler
    nop;rjmp UART_DRE       ;UDR Empty Handler
    nop;rjmp UART_TXC       ;UART TX Complete Handler
    nop;rjmp ANA_COMP       ;Analog Comparator Handler


;********************************************************************
;* "TIM0_OVF" - Timer/counter overflow interrupt handler
;*
;* The overflow interrupt increments the "timerL" and "timerH"
;* every 64us and 16,384us.
;*
;* Crystal Frequency is 4 MHz
;*
;* Number of words:7
;* Number of cycles:6 + reti
;* Low registers used:1
;* High registers used: 3
;* Pointers used:0
;********************************************************************
;.org OVF0addr

TIM0_OVF:
	in S,sreg ; Store SREG
	push temp
	inc timerL ; Updated every 64us
	inc inttemp
	brne TIM0_OVF_exit
	inc timerH ; if 256th int inc timer
	dec tick	; TeaTime
TIM0_OVF_exit:
	pop temp
	out sreg,S ; Restore SREG
reti

;*********** sensor1 interupt routine *******************************
autsch:
	cli
	in S,sreg ; Store SREG
	push temp
	in BotFlag,PinD			; PortD einlesen - welcher sensor wars denn '?
	RCALL M_stop			; erstmal stop
	sbr BotFlag,1<<aua		; flag setzen

	pop temp
	out sreg,S ; Restore SREG
	sei
	reti
;**********delay 320msec.**********************************************************
delay:
	ldi	temp,0x00			; bit6 disaable ext interupt 1 on pind3
	out GIMSK,temp
	
sbi PORTB,7			;LED auge an
	; @ T/C0-Int. alle 16 ms
	;ldi   temp2,2	; äußeren Zähler laden
L1:
	
	;ldi   temp,0	; inneren Zähler laden
	mov   tick,verz1
L2:	mov temp2,tick
	;rcall serout
	sbis PIND,0	;  sbic - microschalter hinten / sbis if471 
	rjmp outdelay
	tst   tick	; Zählerstand = 0 ?
	brne  L2	; wenn nicht, weiter warten
	;dec   temp2
	;brne  L1
	
	cbi PORTB,7			;LED auge aus
outdelay:
	ldi	temp,0x80			; bit6 enable ext interupt 1 on pind3
	out GIMSK,temp
	
	ret		

;********************************************************************
;* Example program

;*
;* Initializes timer, ports and interrupts.

;********************************************************************
reset:
;INIT RAM
	ldi temp,low(RAMEND) 	;Initialize stackpointer for parts with SW stack
	out SPL,temp
	;ldi temp,high(RAMEND) 	; Commented out since 1200 does not have SRAM
	;out SPH,temp

;INIT TIMER0
	ldi temp,1 		;Timer/Counter 0 clocked at CK
	out TCCR0,temp
	ldi temp,1<<TOIE0 	;Enable Timer0 overflow interrupt
	out TIMSK,temp

;INIT FULL DUPLEX HARDWARE UART
        sbi             ucr,txen                ;enable UART transmitter
        sbi             ucr,rxen                ;enable UART receiver
        ldi             r16,25 ;set baud rate
        out             ubrr,r16
;INIT PORTB
	ser temp 		;PORTB as output
	out DDRB,temp
	;clr temp
	out PortB,temp	; alles nullen
;INIT PORTD
	clr  temp	; portd  input
	out  DDRD,temp
	ldi	 temp,0b01111001    	; PD0 - back switch
	out  PORTD,temp			; pullup on pd3 + pd4-pd6  pd3 interupt1 , pd6 infrarot,pd4+5 
					;sensor front l/r
; Init ext.Interupt for sensor
	ldi	temp,0x8			; interupt 1 falling edge
	out	MCUCR,temp
	ldi	temp,0x80			; bit6 enable ext interupt 1 on pind3
	out GIMSK,temp

;INIT PWM 
	ldi temp,10
	mov stemp,temp		; speed decrement value + -	
pwmini:	clr	M_sp		; first clear all registers
	out	tccr1a,M_sp
	out	tccr1b,M_sp
	out	tcnt1h,M_sp		; Remember: always M_spite hi-byte first ! 
	out	tcnt1l,M_sp
	out	ocr1ah,M_sp
	out	ocr1al,M_sp

	ldi	M_sp,$81		; now select pwm mode (8-bit, non inverted)...
	out	tccr1a,M_sp
	ldi	M_sp,$02		; ... and the right clock
	out	tccr1b,M_sp
	
	
	ldi M_sp,80         		; halbe kraft vorraus 
	out	ocr1al,M_sp		; write new pwm-value (hi-byte doesn't care - 8 bit only)
	
	rcall Init_Random	
	
	clr  temp
	mov BotFlag,temp
	ldi	temp,0xC0		; lösche evtl.interup anforderung ;Flankentriggerung'die aufgetreten sein könnte
	out GIFR,temp
	sei 				;Enable global interrupt
	

;**********************************************


main:
		
	sbrc  BotFlag,aua	; Skip, wenn collision.Flag gelöscht
	rcall  Flucht		; Sprung, wenn Flag gesetzt
	
 	rcall detect 		;Call RC5 detect routine
	
	cpi system,SYS_ADDR 	;Responds only at the specified address, alter this variable to use other system adres
	brne release
	andi command,0x3F 	;Remove control bit



	
	CPI command,halt
	BRNE x1
	RCALL M_stop
x1:	
	CPI command,vor
	BRNE x2
	RCALL M_vor
x2:	
	CPI command,rueck
	BRNE x3
	RCALL M_rueck
x3:	
	CPI command,links
	BRNE x4
	RCALL M_links
x4:	
	CPI command,rechts
	BRNE x5
	RCALL M_rechts
x5:	
	CPI command,speedp
	BRNE x6
	RCALL M_spPlus
x6:	
	CPI command,speedm
	BRNE x7
	RCALL M_spMinus
x7:	
	CPI command,beep
	BRNE x8
	RCALL M_beep
	
x8:	CPI command,light
	BRNE x9
	RCALL M_Light

x9:	CPI command,erku
	BRNE x10
	RCALL M_erku

x10:	nop
	rjmp main
release:
	clr command 		;Clear command
				; do a littelbit somthing
	
	;**************************************************
	;* here is the place for write your own code ******
	;**************************************************

	sbis PIND,0		;test the rear sensor
	RCALL Flucht03
	nop
	

	rjmp main
;******************* Flucht ******************************************
Flucht:
	ldi   temp,60	; 
	mov   verz1,temp ; Tea time
	; - welcher sensor wars denn '?
	sbrs  BotFlag,auar
	rjmp Flucht01				; rechter sensor low
	sbrs BotFlag,aual
	rjmp Flucht02				; linker sensor low
	sbrs BotFlag,Dwn			; hinterer sensor
	rjmp Flucht03

	cbr   BotFlag,1<<aua
	RCALL M_Light
	RCALL M_rueck
	RCALL delay
	RCALL M_Light
	RCALL M_rechts
	RCALL delay
	RCALL M_Light
	RCALL M_rueck
	RCALL delay
	RCALL M_Light
	RCALL M_links
	RCALL delay
	RCALL M_L_out    ; Licht bleibt an
	RCALL M_vor
	
	ret


Flucht01:	; rechter sensor
	cbr   BotFlag,1<<aua
	RCALL M_beep
	;RCALL M_stop			; erstmal stop	
	RCALL M_rueck
	RCALL delay
	RCALL M_rechts
	RCALL delay
	RCALL M_vor
	
	ret

Flucht02:	; linker sensor
	cbr   BotFlag,1<<aua
	RCALL M_beep
	;RCALL M_stop			; erstmal stop		
	RCALL M_rueck
	RCALL delay
	RCALL M_links
	RCALL delay
	RCALL M_vor
	
	ret

Flucht03:	; hinterer sensor
	cbr   BotFlag,1<<aua
	RCALL M_beep
	RCALL M_stop			; erstmal stop		
	RCALL M_Light
	RCALL delay
	RCALL M_vor
	
	ret

	

;******************* Motorsteuerung BellBot**************************
;*
;*
;********************************************************************

M_stop:
		clr temp
		out	ocr1al,temp		; write new pwm-value (hi-byte doesn't care - 8 bit only)
		out PortB,temp	; alles nullen
		ret
M_vor:		
		out	ocr1al,M_sp		; write new pwm-value (hi-byte doesn't care - 8 bit 
		LDI M_reg,0b00000110
		out PORTB,M_reg
		ret
M_rueck:		
		out	ocr1al,M_sp		; write new pwm-value (hi-byte doesn't care - 8 bit 
		LDI M_reg,0b00010001
		out PORTB,M_reg
		ret
M_links:
		
		LDI M_reg,0b00000101
		out PORTB,M_reg	
		ret
M_rechts:	
		LDI M_reg,0b00010010
		out PORTB,M_reg
		ret
M_spPlus:
		;ldi temp3,10
		add M_sp,stemp		; speicher fuer increment value for speed + -
		out	ocr1al,M_sp		; write new pwm-value (hi-byte doesn't care - 8 bit 	
		ret
M_spMinus:
		sub M_sp,stemp
		out	ocr1al,M_sp		; write new pwm-value (hi-byte doesn't care - 8 bit 	
		ret
		
M_beep:		rcall peep				; Beep Beep
		ret

M_Light:	sbis PORTB,7
		rjmp M_L_out
		cbi PORTB,7				;toggle Light on/off
		ret
M_L_out:	sbi PORTB,7
		ret


;********************************************************************
;* "detect" - RC5 decode routine
;*
;* This subroutine decodes the RC5 bit stream applied on PORTD
;* pin "INPUT".

;*
;* If success: The command and system address are
;* returned in "command" and "system".
;* Bit 6 of "command" holds the toggle bit.
;*
;* If failed: $FF in both "system" and "command"
;*
;* Crystal frequency is 4MHz
;*
;* Number of words:72
;* Low registers used: 3
;* High registers used: 6
;* Pointers used: 0
;********************************************************************
detect:
	clr inttemp 		; Init Counters
	clr timerH
detect1:
	clr timerL
detect2:
	cpi timerH,8 		;If line not idle within 131ms
	brlo dl1
	rjmp fault 		;then exit
dl1:
	cpi timerL,55 		;If line low for 3.5ms
	brge start1 		;then wait for start bit
	sbis PIND,INPUT 	;If line is
	rjmp detect1 		;low - jump to detect1
	rjmp detect2 		;high - jump to detect2
start1:
	cpi timerH,8 		;If no start bit detected
	brge fault 		;within 130ms then exit
	sbic PIND,INPUT 	;Wait for start bit
rjmp start1
	clr timerL 		;Measure length of start bit
start2:
	cpi timerL,17 		;If startbit longer than 1.1ms,
	brge fault 		;exit
	sbis PIND,INPUT
	rjmp start2 		;Positive edge of 1st start bit
	mov temp,timerL 	;timer is 1/2 bit time

	clr timerL
	mov ref1,temp
	lsr ref1
	mov ref2,ref1
	add ref1,temp 		;ref1 = 3/4 bit time
	lsl temp
	add ref2,temp 		;ref2 = 5/4 bit time

start3:
	cp timerL,ref1 		;If high period St2 > 3/4 bit time
	brge fault 		;exit
	sbic PIND,INPUT 	;Wait for falling edge start bit 2
	rjmp start3
	clr timerL
	ldi bitcnt,12 ;Receive 12 bits
	clr command
	clr system

sample:
	cp timerL,ref1 		;Sample INPUT at 1/4 bit time
	brlo sample
	sbic PIND,INPUT
	rjmp bit_is_a_1 	;Jump if line high

bit_is_a_0:
	clc 			;Store a ’0’
	rol command
	rol system
;Synchronize timing

bit_is_a_0a:

	cp timerL,ref2 		;If no edge within 3/4 bit time
	brge fault 		;exit
	sbis PIND,INPUT 	;Wait for rising edge
	rjmp bit_is_a_0a 	;in the middle of the bit
	clr timerL
	rjmp nextbit

bit_is_a_1:

	sec 			;Store a ’1’
	rol command
	rol system
;Synchronize timing

bit_is_a_1a:

	cp timerL,ref2 		;If no edge within 3/4 bit time
	brge fault 		;exit
	sbic PIND,INPUT 	;Wait for falling edge
	rjmp bit_is_a_1a 	;in the middle of the bit
	clr timerL

nextbit:
	dec bitcnt 		;If bitcnt > 0
	brne sample 		;get next bit
;All bits sucessfully received!
	mov temp,command 	;Place system bits in "system"
	rol temp
	rol system
	rol temp
	rol system
	bst system,5 		;Move toggle bit
	bld command,6 		;to "command"
;Clear remaining bits

	andi command,0b01111111
	andi system,0x1F
	ret
fault:
	ser command 		;Both "command" and "system"
	ser system 		;0xFF indicates failure
	ret
;******************************************************************
Init_Random:
	ldi	TEMP,$AA	;Init the random number generator 
	mov	RAND1,TEMP	;since a 00,00,00 state will not 
	mov	RAND2,TEMP	;progress.
	mov	RAND3,TEMP	;
	ret
;********************** Random Number *****************************
;* for random action maybe , not used yet ! works fine
;******************************************************************
Random:
	;Maximal legnth 19 bit shift register sequence,
	push	R16		;Make workspace
	push	R17		;

	;  RAND3    RAND2    RAND1
	;22222111 11111110 00000000
	;43210987 65432109 87654321

	mov	R16,RAND1	;Make copy
	mov	R17,RAND3	;Make copy

	;clc			;not needed, because we will overwrite bit 0 later
	rol	RAND1		;Shift the bits D7->Carry
	rol	RAND2		;Carry->D0 D7->Carry
	rol	RAND3		;Carry->D0 D7->Carry, but that will be fixed.

	;Now we have to Xor the bits to see what
	;goes in to bit 1

	rol	R17		;Move bit 19->20
	andi	R17,$08		;Important that D1,0 be zero

	andi	R16,$13		;Mask out irrelevants, protecting bit 19
	or	R17,R16		;Get bits 5->21 2->18 1->17

	andi	R17,$18		;Nuke bits 18,17
	lsr	R17		;19->19 5->20
	lsr	R17		;19->18 5->19
	lsr	R17		;19->17 5->18

	eor	R17,R16		;First xor, result in R17 (5x2 in 02 and 19x1 in 01)
	mov	R16,R17		;Make a copy
	ror	R16		;Move the 5x2 result to 01
	andi	R17,$01		;Mask off everything else
	andi	R16,$01		;in both
	eor	R17,R16		;
	brne	D_One		;If one, do that, else 

D_Zero:	
	;Set a zero in the lsb of the low byte
	mov	R16,RAND1	;Get the low byte
	andi	R16,$FE		;Make the LSB zero
	mov	RAND1,R16	;Put it back
	Rjmp	D_Exit		;Bye bye

D_One:	
	;Set a one in the lsb of the low byte
	mov	R16,RAND1	;Get the low byte
	ori	R16,$01		;Make the LSB one
	mov	RAND1,R16	;Put it back

D_Exit:
	pop	R17		;Put everything back where I got it.
	pop	R16		;
	ret


;******************************************************************
; Ton erzeugung 4khz fuer piezo
;******************************************************************

;***Tactile feedback note generation routine*****************
;***provides a 4 kHz TONE to the piezo sounder for 5 ms*****
	
peep:		clr temp2		
tactile:	cbi PORTB,PZ		;turn on piezo
		ldi temp,210		;for a short time
t1again:	dec temp
		brne t1again
		sbi PORTB,PZ		;turn on piezo
		ldi temp,210		;for a short time
t2again:	dec temp
		brne t2again
		inc temp2
		cpi temp2,250		;is half second up
		brne tactile
	
		ret

;******************************************************************
serout:

	out             udr,temp2	        ;load UART data register
	;out PORTB,command

serout1:
        sbis            usr,udre                ;if UART data register empty bit is clear
        rjmp            serout1                 ;       loop back
                                                ;else return
        ret

serin:
        sbis            usr,rxc                 ;if UART Receive Complete bit is clear
        rjmp            serin                   ;       loop back
        in              r16,udr                 ;else get received byte in r16
        ret                                     ;and return