;***************************************************************
;*                      Car Alarm System                       *
;*                 Power Relay & Central Lock                  *
;*                         Version 2                           *
;*                            1996                             *
;***************************************************************
	LIST	P=PIC16C84, R=HEX
	INCLUDE	"f:\mpasm\include\p16C84.inc"

	__CONFIG _XT_OSC & _WDT_OFF & _CP_OFF

;----- Port A bits -----

RelaySW		equ	4
DoorLock	equ	3
PowerOFF	equ	2
PowerON		equ	1
DoorUnlock	equ	0

;----- Port B bits -----

CloseSW		equ	5
OpenSW		equ	4
DataIn		equ	0

;----- PowerFlags bits -----

ON_Flag		equ	7
OFF_Flag	equ	6
LockFlag	equ	5
UnlockFlag	equ	4
DataFlag	equ	3
NullFlag	equ	0

;----- Password -----

PASS1		equ	0x03
PASS2           equ	0xc2
PASS3           equ	0xa7
PASS4           equ	0x4f
PASS5           equ	0xe9
PASS6           equ	0x85
PASS7           equ	0x6b
PASS8           equ	0x1d
                            
;----- Local DATA -----

DelayCountLow	equ	0x0c
DelayCountHi	equ	0x0d
Count		equ	0x0e
DataCount	equ	0x0f
PowerFlags	equ	0x10
OldPowerFlags	equ	0x11
TempW	       	equ	0x12
TempSTATUS	equ     0x13
DataCorrection	equ	0x14
Dig1		equ	0x15
Dig2		equ	0x16
Dig3            equ	0x17
Dig4            equ	0x18
Dig5		equ	0x19
Dig6		equ	0x1a
Dig7            equ	0x1b
Dig8            equ	0x1c

;----- CODE -----

	org	0

	goto	Start

;         ------------ I N T E R R U P T   R O U T I N E -------------

	org	0x04                    ;min3-max4 mks
        
	movwf	TempW           	;save W and STATUS
	movf	STATUS,W
	movwf	TempSTATUS

	btfss	INTCON,INTF
	goto	WatchSwitch
	clrf	Dig1
	clrf	Dig2
	clrf	Dig3
	clrf	Dig4
	clrf	Dig5
	clrf	Dig6
	clrf	Dig7
	clrf	Dig8

	movlw	0xc2
	call	IRDelay			;delay 194*3-1+5=586 mks
	call	IRDelay			;delay 194*3-1+5=586 mks

	nop
	nop
	clrf	DataCorrection	        ;reset correction 
	btfsc	PORTB,DataIn		;set correction -3 mks
	goto	RestoreIntFlag
	incf	DataCorrection,F
	btfsc	PORTB,DataIn		;set correction -2 mks
	goto	SetCorrection
	incf	DataCorrection,F
	btfsc	PORTB,DataIn		;set correction -1 mks
	goto	SetCorrection
	incf	DataCorrection,F
	btfsc	PORTB,DataIn		;set correction 0 mks delay 3 mks
	goto	SetCorrection
	incf	DataCorrection,F
	btfsc	PORTB,DataIn		;set correction +1 mks
	goto	SetCorrection
	incf	DataCorrection,F
	btfsc	PORTB,DataIn		;set correction +2 mks
	goto	SetCorrection
	goto	RestoreIntFlag

SetCorrection:
	movlw	0x7e			;~4 mks after start
	call	IRDelay			;delay 126*3-1+5=382 mks
	nop
	nop

	bsf	STATUS,C		;this STOP bit will end the loop
NextDigit:
	rrf	Dig8,F
	rrf	Dig7,F
	rrf	Dig6,F
	rrf	Dig5,F
	rrf	Dig4,F
	rrf	Dig3,F
	rrf	Dig2,F
	rrf	Dig1,F
	btfsc	STATUS,C		;check for STOP bit
	goto	Compare
	bsf	PowerFlags,NullFlag	;Set the null flag
RetryDigit:
	bcf	PowerFlags,DataFlag	;1 mks Reset bit read flag
	nop
	nop
	nop
	btfsc	PORTB,DataIn		;5th mks look for a bit
	bsf	PowerFlags,DataFlag	;Set if bit read

	movlw	0x05
	movwf	DataCount

StartCorrection:			;Delay 35+DataCorrection mks
	movf	DataCount,W		;for T=400 mks delay 38 mks
	subwf	DataCorrection,W
	btfsc	STATUS,C
	goto	AddCorrection
AddCorrection:
	decfsz	DataCount,F
	goto	StartCorrection
	nop

	movlw   0x6e
	call	IRDelay			;Delay 110*3-1+5=334 mks

	btfss	PowerFlags,DataFlag
	goto	ResetFlag
	btfsc	PowerFlags,NullFlag	;If flag is clear it was "1"
	goto	Set0
	nop
	bsf	STATUS,C		;Set an overflow flag to read "1"
	goto	NextDigit
Set0:
	bcf	STATUS,C		;Reset an overflow flag to read "0"
	goto	NextDigit

ResetFlag:
	movlw   0x02
	call	IRDelay			;Delay 2*3-1+5=10 mks

	btfss	PowerFlags,NullFlag	;Error if an overflow flag already reset
	goto	RestoreIntFlag
	bcf	PowerFlags,NullFlag
	goto	RetryDigit

Compare:
	nop                             ;401th mks
	nop
	nop
	nop
	btfsc	PORTB,DataIn		;405th mks watch for clear bit
	goto	RestoreIntFlag

	movlw	0x05
	movwf	DataCount

StartCorrection1:			;Delay 35+DataCorrection mks
	movf	DataCount,W		;for T=400 mks delay 38 mks
	subwf	DataCorrection,W
	btfsc	STATUS,C
	goto	AddCorrection1
AddCorrection1:
	decfsz	DataCount,F
	goto	StartCorrection1
	nop

	movlw	PASS8
	xorwf	Dig8,W
	btfss	STATUS,Z
	goto	RestoreIntFlag

	movlw	PASS7
	xorwf	Dig7,W
	btfss	STATUS,Z
	goto	RestoreIntFlag

	movlw	PASS6
	xorwf	Dig6,W
	btfss	STATUS,Z
	goto	RestoreIntFlag

	movlw	PASS5
	xorwf	Dig5,W
	btfss	STATUS,Z
	goto	RestoreIntFlag

	movlw	PASS4
	xorwf	Dig4,W
	btfss	STATUS,Z
	goto	RestoreIntFlag

	movlw	PASS3
	xorwf	Dig3,W
	btfss	STATUS,Z
	goto	RestoreIntFlag

	movlw	PASS2
	xorwf	Dig2,W
	btfss	STATUS,Z
	goto	RestoreIntFlag

	movf	Dig1,W
	andlw	b'00001111'
	xorlw	PASS1
	btfss	STATUS,Z
	goto	RestoreIntFlag

	movlw	0x6a			;480 mks
	call	IRDelay			;delay 106*3-1+5=322 mks
	nop
	nop

	btfsc	PORTB,DataIn		;805 mks
	goto	RestoreIntFlag

	movlw	0x05
	movwf	DataCount

StartCorrection2:			;Delay 35+DataCorrection mks
	movf	DataCount,W		;for T=400 mks delay 38 mks
	subwf	DataCorrection,W
	btfsc	STATUS,C
	goto	AddCorrection2
AddCorrection2:
	decfsz	DataCount,F
	goto	StartCorrection2
	nop

	movlw	0x75
	call	IRDelay			;delay 117*3-1+5=355 mks

	nop
	nop

	btfss	PORTB,DataIn		;5th mks look for a STOP bit
	goto	RestoreIntFlag
        
	movlw	b'11000000'
	andwf	Dig1,W
	btfsc	STATUS,Z
	goto	RestoreIntFlag
	iorwf   PowerFlags,F		;Save a valid function (ON/OFF)

	clrf	PORTA
                        
	btfss	PowerFlags,ON_Flag
	goto	TestOFF
	btfsc	PORTA,RelaySW
	goto	RestoreIntFlag
TestOFF:
	btfss	PowerFlags,OFF_Flag
	goto	TestDone
	bcf	PowerFlags,ON_Flag	;OFF_Flag has the highest priority
	btfss	PORTA,RelaySW
	goto	RestoreIntFlag
TestDone:
	movlw	0x03
	movwf	DataCount	        	;Set 3 attempts to switch a distance relay
RetrySetPower:
	movlw	0xff                 
	btfsc	PowerFlags,ON_Flag
	bsf	PORTA,DoorUnlock
	btfsc	PowerFlags,OFF_Flag
	bsf	PORTA,DoorLock
	call	Delay                   ;wait for 256ms
	btfsc	PowerFlags,ON_Flag
	bsf	PORTA,PowerON
	btfsc	PowerFlags,OFF_Flag
	bsf	PORTA,PowerOFF
	call	Delay                   ;wait for 256ms
	clrf	PORTA

	btfss	PowerFlags,ON_Flag
	goto	WatchOFF
	btfsc	PORTA,RelaySW
	goto	RestoreIntFlag
	goto	RelayNotSet
WatchOFF:
	btfss	PORTA,RelaySW
	goto	RestoreIntFlag
RelayNotSet:

	movlw	0xff
	call	Delay                   ;wait for 512ms
	call	Delay                   

	decfsz	DataCount,F
	goto	RetrySetPower

RestoreIntFlag:
	bcf	INTCON,INTF    
	movf	PORTB,F
	goto	RestoreStatus

WatchSwitch:
	btfss	INTCON,RBIF
	goto	RestoreStatus
	comf	PORTB,W		;read switches
	bcf	INTCON,RBIF	;reset flag
	andlw	b'00110000'
	btfsc	STATUS,Z	;all switches open
	goto    RestoreStatus
	movlw	0x64
	call	Delay
	comf	PORTB,W		;read switches again
	bcf	INTCON,RBIF     ;reset flag
	andlw	b'00110000'
	btfsc	STATUS,Z	;a less than 100 ms pulse was detected
	goto    RestoreStatus
 	xorlw	b'00110000'
	btfsc	STATUS,Z
	goto	RestoreStatus
	xorlw	b'00110000'
	iorwf   PowerFlags,F	;Save a valid function (Lock/Unlock)
	xorwf	OldPowerFlags,W
	btfsc	STATUS,Z
	goto	RestoreStatus
	btfss	PORTA,RelaySW
	goto	RestoreStatus
	movlw	0xff                 
	btfsc	PowerFlags,UnlockFlag
	bsf	PORTA,DoorUnlock
	btfsc	PowerFlags,LockFlag
	bsf	PORTA,DoorLock
	call	Delay           ;wait for 512ms
	call	Delay                   
	clrf	PORTA
	movf	PowerFlags,W
	movwf	OldPowerFlags
	
RestoreStatus:
	bcf	INTCON,RBIF
	clrf	PowerFlags
	movf	TempSTATUS,W	;Restore W and STATUS
	movwf	STATUS
	movf	TempW,W
	retfie


;         ------------ S U B R O U T I N E S -------------

Delay   			;W mks delay with 4MHz oscilator
	movwf	DelayCountHi
	clrf	DelayCountLow
DelayLoop:
	nop
	incfsz	DelayCountLow,F
	goto	DelayLoop
	decfsz	DelayCountHi,F
	goto	DelayLoop
	return


IRDelay
	movwf	DataCount		;delay W*3-1+5 mks
DelayStart:
	decfsz	DataCount,F
	goto	DelayStart
	return


;                 ------------ M A I N -------------

Start:
	clrf	PORTA
	clrf	PORTB
	clrf	EEDATA
	clrf	EEADR
	clrf	PowerFlags
	clrf	OldPowerFlags

	bsf	STATUS,RP0	;set bank 1
	movlw	b'00010000'     ;Port A
	movwf	TRISA
	movlw	b'11111111'	;Port B
	movwf	TRISB
	movlw	b'11111111'	;disable pull-up
	movwf	OPTION_REG
	bcf	STATUS,RP0	;set bank 0
	
	movf	PORTB,F
	movlw	b'10011000'	;enable interrupts
	movwf	INTCON

Loop:
	goto	Loop


	org	0x3ff
	goto	Start		;Restart if got here

	end