;***************************************************************
;*                      Car Alarm System                       *
;*                          Main Unit                          *
;*                         Version 01                          *
;*                            1996                             *
;***************************************************************
	LIST	P=PIC16C84, R=HEX
	INCLUDE	"f:\mpasm\include\p16C84.inc"

	__CONFIG _XT_OSC & _WDT_OFF & _CP_OFF

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

AlarmSW		equ	4
Relay		equ	3
Beep		equ	2
Lights		equ	1
LED		equ	0

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

HiJackSW	equ	7
IgnitionSW	equ	6
MainSW		equ	5
DelaySW		equ	4
AlarmON		equ	3
AlarmOFF	equ	2
Lock		equ	1
IRInp		equ	0

;----- AlarmFlags bits -----

OFF_Flag	equ	7
ON_Flag		equ	6
NullFlag	equ	5
IRFlag		equ	4
AlarmFlag	equ	3
IntrusionFlag	equ	2
DelayFlag	equ	1
BeepFlag	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
IRCount		equ	0x0f
AlarmFlags	equ	0x10
TempW	        equ	0x11
TempSTATUS	equ     0x12
IRCorrection    equ	0x13
Dig1		equ	0x14
Dig2		equ	0x15
Dig3            equ	0x16
Dig4            equ	0x17
Dig5		equ	0x18
Dig6		equ	0x19
Dig7            equ	0x1a
Dig8            equ	0x1b

;----- 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	IRCorrection            ;reset correction 
	btfsc	PORTB,IRInp		;set correction -3 mks
	goto	RestoreIntFlag
	incf	IRCorrection,F
	btfsc	PORTB,IRInp		;set correction -2 mks
	goto	SetCorrection
	incf	IRCorrection,F
	btfsc	PORTB,IRInp		;set correction -1 mks
	goto	SetCorrection
	incf	IRCorrection,F
	btfsc	PORTB,IRInp		;set correction 0 mks delay 3 mks
	goto	SetCorrection
	incf	IRCorrection,F
	btfsc	PORTB,IRInp		;set correction +1 mks
	goto	SetCorrection
	incf	IRCorrection,F
	btfsc	PORTB,IRInp		;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	AlarmFlags,NullFlag	;Set the null flag
RetryDigit:
	bcf	AlarmFlags,IRFlag	;1 mks Reset bit read flag
	nop
	nop
	nop
	btfsc	PORTB,IRInp		;5th mks look for a bit
	bsf	AlarmFlags,IRFlag	;Set if bit read

	movlw	0x05
	movwf	IRCount

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

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

	btfss	AlarmFlags,IRFlag
	goto	ResetFlag
	btfsc	AlarmFlags,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	AlarmFlags,NullFlag	;Error if an overflow flag already reset
	goto	RestoreIntFlag
	bcf	AlarmFlags,NullFlag
	goto	RetryDigit

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

	movlw	0x05
	movwf	IRCount

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

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

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

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

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

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

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

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

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

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

	btfsc	PORTB,IRInp		;805 mks
	goto	RestoreIntFlag

	movlw	0x05
	movwf	IRCount

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

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

	nop
	nop

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

	btfss	AlarmFlags,ON_Flag
	goto	TestOFF
	btfss	PORTA,AlarmSW
	goto	SetBeep                 ;Toggle beep flag
	bcf	AlarmFlags,OFF_Flag	;ON flag has the highest priority
	goto	SetAlarm

TestOFF:
	btfss	AlarmFlags,OFF_Flag
	goto    RestoreIntFlag
	btfsc	PORTA,AlarmSW
	goto	SetBeep                 ;Toggle beep flag

	movlw	0x32			;Set 50 ms delay
	call	SystemAlarm		;Beep and Lights for 100 ms
	bsf	PORTB,Lock     		;Set an open door relay
	movlw	0xff
	call	Delay                   ;wait for 512 ms
	call	Delay

	btfss	AlarmFlags,AlarmFlag 	;Another alarm if intrusion flag was set
	goto	SetAlarm
	movlw	0x32	    		;Set 50 ms delay
	call	SystemAlarm
	movlw	0xff
	call	Delay                   ;wait for 512 ms
	call	Delay

SetAlarm:
	movlw	0x32	    		;Set 50 ms delay
	call	SystemAlarm

	movlw	0x03
	movwf	IRCount	        	;Set 3 attempts to switch a distance relay

RetrySetAlarm:
	bsf	PORTA,Relay
	movlw	0xc8
	call	Delay		;wait for 200 ms

	btfsc	AlarmFlags,ON_Flag
	bsf	PORTB,AlarmON
	btfsc	AlarmFlags,OFF_Flag
	bsf	PORTB,AlarmOFF
	call	Delay		;wait for 200 ms

	bcf	PORTA,Relay
	call	Delay		;wait for 200 ms
	bcf	PORTB,AlarmON
	bcf	PORTB,AlarmOFF
                       
	btfss	AlarmFlags,ON_Flag
	goto	WatchOFF
	btfss	PORTA,AlarmSW
	goto	Main
	goto	WatchDone
WatchOFF:
	btfsc	PORTA,AlarmSW
	goto	Main
WatchDone:

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

	decfsz	IRCount,F
	goto	RetrySetAlarm
	goto	Main

SetBeep:
	movlw	b'00000001'     ;toggle beep flag
	xorwf	AlarmFlags,F
	movlw	0x64            ;set delay for 100 ms
	call	SystemAlarm
	movlw	b'00111111'
	andwf   AlarmFlags,F    ;reset ON and OFF flags
	goto	RestoreIntFlag

BadCode:
	bsf	AlarmFlags,IntrusionFlag ;Set an intrusion flag for bad code

RestoreIntFlag:
	bcf	PORTB,Lock	;Turn off the open lock relay
	bcf	INTCON,INTF

WatchSwitch:
	btfss	INTCON,RBIF
	goto	RestoreStatus
	movf	PORTB,W		;read switches
	bcf	INTCON,RBIF	;reset flag
	andlw	b'11110000'
	btfsc	STATUS,Z	;all switches open
	goto    RestoreStatus
	movlw	0x1e
	call	Delay
	movf	PORTB,W		;read switches again
	bcf	INTCON,RBIF     ;reset flag
	andlw	b'11110000'
	btfsc	STATUS,Z	;a less than 30 ms pulse was detected
	goto    RestoreStatus

	bsf	AlarmFlags,IntrusionFlag ;Set an intrusion if some switches closed

RestoreStatus:
	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	IRCount		;delay W*3-1+5 mks
DelayStart:
	decfsz	IRCount,F
	goto	DelayStart
	return


SystemAlarm       
	btfss	AlarmFlags,BeepFlag
	bsf	PORTA,Beep
	bsf	PORTA,Lights
	call	Delay
	call	Delay
	bcf	PORTA,Beep
	bcf	PORTA,Lights
	return


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

Start:
	clrf	PORTA
	clrf	PORTB
	clrf	EEDATA
	clrf	EEADR
	clrf	AlarmFlags

	bsf	STATUS,RP0	;set bank 1
	movlw	b'00010000'     ;Port A
	movwf	TRISA
	movlw	b'11110001'	;Port B
	movwf	TRISB
	movlw	b'11111111'	;disable pull-up
	movwf	OPTION_REG
	bcf	STATUS,RP0	;set bank 0

Main:
	clrf	PORTA		;clear Port A
	movlw	b'00000001'
	andwf	AlarmFlags,F	;Reset everything but BeepFlag

	btfss	PORTA,AlarmSW
	goto	ON_Set
	goto	OFF_Set

OFF_Set:
	movlw	b'10010000'	;enable interrupts
	movwf	INTCON
OFF_Loop:
	goto	OFF_Loop

ON_Set:
	movlw	0x0a
	movwf	Count		;set alarm count for 10
	movlw	b'10011000'	;enable interrupts
	movwf	INTCON
	bsf	INTCON,RBIF	;watch switches
ON_Loop:
	movlw   0x64		;Make LED blink twice per second
	bsf	PORTA,LED			
	btfsc	AlarmFlags,IntrusionFlag	
	goto	Intrusion			
	call	Delay           		
	bcf	PORTA,LED			
	call	Delay				
	bsf	PORTA,LED			
	btfsc	AlarmFlags,IntrusionFlag
	goto	Intrusion		
	call	Delay			
	bcf	PORTA,LED		
	movlw   0xff
	call	Delay			
	call	Delay			
	movlw   0xbc
	call	Delay           	
	goto	ON_Loop

Intrusion:
	bcf	INTCON,RBIE		;disable switch interrupt
	bsf	AlarmFlags,AlarmFlag    ;save intrusion
	bcf	AlarmFlags,DelayFlag

	btfsc	PORTB,HiJackSW
	bsf	AlarmFlags,DelayFlag

	movlw	0xfa		
	call	SystemAlarm

	btfss	PORTB,HiJackSW
	bcf	AlarmFlags,DelayFlag

	btfss	AlarmFlags,BeepFlag 	
	bsf	PORTA,Beep	
	call	Delay		
	bcf	PORTA,Beep

	btfss	PORTB,HiJackSW      
        goto	SkipHiJack
        btfss	AlarmFlags,DelayFlag
	goto	SkipHiJack
	bsf	AlarmFlags,OFF_Flag
        goto	TestOFF
SkipHiJack:
	call	Delay		

	decfsz	Count,F
	goto	Intrusion
	bcf	AlarmFlags,IntrusionFlag ;clear intrusion flag
	goto	ON_Set

	org	0x3ff
	goto	Start		;Restart if got here

	end