;**** T I T L E    R C 5 T I N Y L A M P    ***************************************
;*
;* Title		:RC5TinyLamp 
;* Version		:1.0
;* Date			:00.05.31
;* Last updated		:00.08.19
;* Target		:ATTiny22 
;* Crystal frequency	:1Mhz intern oscillator
;*
;* Support		:J.v.Boxtel
;* Support E-mail	:boxteldoelen@hetnet.nl
;*
;* Code Size		:149 words 
;* Low Register Usage	:5 
;* High Register Usage	:11 
;* Interrupt Usage	:
;* Based on 		:avr410 rc5, avr100 EEprom access, RC5Lamp
;*
;* DESCRIPTION
;* This Application switch a lamp on/off with RC5 if
;* system and lamp_nr are correct
;* system and lamp_nr are can be change with the "learn_button"
;* pB2 (pin7) is IRinput, pB3 (pin2) is learn button, pB0 (pin5) is output
;* pB3 learbutton open=normal groud=learn
;* pB1 (pin6) ext interrupt 
;***************************************************************************

.include "tn22def.inc"

	.equ INPUT 	 =2	 ;PB2 input for ir reciever

	.def S 		 =R0	 ;Storage for the Status Register
	.def inttemp     =R1	 ;Temporary variable for ISR
	.def ref1	 =R2	 ;Reference for timing
	.def ref2	 =R3 	 ;Reference for timing
	.def EEdrd       =R4	 ;read data byte from EEprom
	.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 SYS_ADDR	 =R22	 ;Systen addres to respond on
	.def LAMP_NR	 =R23	 ;Lamp number to respond on
	.def EEard       =R24	 ;address to read from
	.def EEdwr	 =R25	 ;data byte to write to EEPROM
	.def EEawr	 =R26	 ;address byte to write to

.cseg
.org 0

	rjmp reset

;********************************************************************
;* "TIM0_OVF" - Timer/counter overflow interrupt handler
;*
;* The overflow interrupt increments the "timerL" and "timerH"
;* every 64us and 16,384us.
;*
;* Crystal Frequency is 1 MHz
;*
;* Number of words:
;* 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
	inc timerL 		; Updated every 64us
	inc inttemp		;   4 MHz clock
	inc timerL 		; Updated every 64us
	inc inttemp		;   3 MHz clock
	inc timerL 		; Updated every 64us
	inc inttemp		;   2 MHz clock
	inc timerL 		; Updated every 64us
	inc inttemp		;   1 MHz clock
	brne TIM0_OVF_exit

	inc timerH 		; if 256th int inc timer

     TIM0_OVF_exit:
	out sreg,S 		; Restore SREG
	reti

reset:
	ldi temp,1 		;Timer/Counter 0 clocked at CK
	out TCCR0,temp		;  Timer counter 0 prescaler
	ldi temp,1<<TOIE0 	;Enable Timer0 overflow interrupt
	out TIMSK,temp		;  set timer interrupt mask
	ldi temp,0x01 		;PORTB 0 as output
	out DDRb,temp		;  set direction
	ldi temp,15		;load 15 for init pullup on pB1,pB2;pB3 
	out portb,temp		;  and set defaul lamp off after reset
	
	ldi temp,ramend		;init stack pointer
	out spl,temp		;  ram_end to spl
	
	sei 			;Enable global interrupt

main:	
	rcall detect		;Call RC5 detect routine
	
	cpi command,0xFF	;If no or wrong code return to main
	breq main
	
	in temp,pinb		;learbutton test
	andi temp,$08		;  test pb3 only (learnbutton)
	cpi temp,$08		;  high then main1
	breq main1		
    
     	   
	mov	EEdwr,system	;store new system addres in EEprom
	ldi	EEawr,$00	;  at addres 00
	rcall	EEWrite		;  store system in EEPROM location $0000

	andi command,0x3F	;remove toggle bit
	mov	EEdwr,command	;store new command in EEprom
	ldi	EEawr,$01	;  at addres $0001
	rcall	EEWrite		;  store command in EEPROM location $0001
		
    main1:	
	rcall readin		;readin the system-addres and lamp_nr
	
	cp system,sys_addr	;correct addres? else return to main
	brne main
	
	andi command,0x3F	;remove toggle bit
	cp command,lamp_nr	;correct lamp nr? else return to main
	brne main
	
invert:
	brts invert1		;if T bit is 0 then lamp on
	set			;set t bit (lamp on code)
	cbi $18,0		;port pin low =lamp on
	rjmp wait 		;jump to wait
     invert1:			;if t bit is 1 then lamp off
   	clt			;clear t bit (lamp off code)
   	sbi $18,0		;set pin high
     wait:
	rcall detect		;Call RC5 detect routine and
	cpi command,0xFF	;   wait until button is released
	brne wait		;
  	rjmp main		;
	
readin:
	ldi	EEard,$00	;load addres
	rcall	EERead		;read address $00 (System addres)
	mov	sys_addr,EEdrd	;load system addres
	
	ldi	EEard,$01	;load addres
	rcall	EERead		;read address $01 (command number)
	mov	lamp_nr,EEdrd	;command mumber is lamp number
	
	ret
	
;***************************************************************************
;* 
;* EERead
;*
;* This subroutine waits until the EEPROM is ready to be programmed, then
;* reads the register variable "EEdrd" from address "EEardh:EEard"
;*
;* Number of words	:1200 ; 5 + return
;*			:8515 ; 6 + return
;* Number of cycles	:1200 ; 8 + return (if EEPROM is ready)
;*			:8515 ; 9 + return (if EEPROM is ready)
;* Low Registers used	:1 (EEdrd)
;* High Registers used:	:2 (EEard,EEardh)
;*
;***************************************************************************


EERead:
	sbic	EECR,EEWE	;if EEWE not clear
	rjmp	EERead		;    wait more
	out	EEAR,EEard	;output address for 1200


	sbi	EECR,EERE	;set EEPROM Read strobe
				;This instruction takes 4 clock cycles since
				;it halts the CPU for two clock cycles
	in	EEdrd,EEDR	;get data
	ret

EEWrite:
	sbic	EECR,EEWE	;if EEWE not clear
	rjmp	EEWrite		;    wait more

	out	EEARL,EEawr	;output address low 

	out	EEDR,EEdwr	;output data
	sbi 	EECR,EEMWE	;  set master write enable
	sbi	EECR,EEWE	;  set EEPROM Write strobe
				;  This instruction takes 4 clock cycles since
				;  it halts the CPU for two clock cycles
	ret


;********************************************************************
;* "detect" - RC5 decode routine
;*
;* This subroutine decodes the RC5 bit stream applied on PORTB
;* 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
;********************************************************************
detect0:			;only for test
	ldi command,0x7
	ldi system,0x05
	ret
	
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 PINB,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 PINB,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 PINB,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 PINB,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 PINB,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 PINB,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 PINB,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

	andi command,0b01111111
	andi system,0x1F
	ret

     fault:
	ser command 		;Both "command" and "system"
	ser system 		;0xFF indicates failure
	ret

	.eseg
	.org 0
table:
	.db $00,$04	;KTV1, button 4 default settings