;***************************************************************
;*                      Car Alarm System                       *
;*                          Main Unit                          *
;*                        Version 02                           *
;*                            1997                             *
;*                   Low voltage immobilizer                   *
;*                   Full  Interrupt version                   *
;***************************************************************
	LIST	P=PIC16C84, R=HEX
	INCLUDE	"f:\mpasm\include\p16C84.inc"

	__CONFIG _XT_OSC & _WDT_OFF & _CP_OFF

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

AlarmSW		equ	4
DataOut		equ	3
Lights		equ	2
Beep		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
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

ALARM_TIME	equ	0x0a
ALARM_COUNT	equ	0x0a
BEEP_DELAY	equ	0x08
LIGHTS_DELAY	equ	0x06
LED_DELAY	equ	0x02
                            
;----- Local DATA -----

DelayCountLow	equ	0x0c
DelayCountHi	equ	0x0d
AlarmCount	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
TransmitCount	equ	0x1c
TransmitTimes	equ	0x1d
BeepDelay	equ	0x1e
LightsDelay	equ	0x1f
LedDelay	equ	0x20
AlarmTime	equ	0x21

;----- 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	WatchTimer
	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
        
	clrf	PORTA

	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
	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:
	btfsc	AlarmFlags,ON_Flag
	bsf	PORTB,AlarmON
	btfsc	AlarmFlags,OFF_Flag
	bsf	PORTB,AlarmOFF

	movlw	0x05			;make 5 transmitions (Delay 178 to 306 ms)
	movwf	TransmitTimes
NextTransmit:
	call	Transmit
	decfsz	TransmitTimes,F
	goto	NextTransmit

	bcf	PORTB,AlarmON
	bcf	PORTB,AlarmOFF
                       
	btfss	AlarmFlags,ON_Flag
	goto	WatchOFF
	btfss	PORTA,AlarmSW
	goto	RestoreIntFlag
	goto	WatchDone
WatchOFF:
	btfsc	PORTA,AlarmSW
	goto	RestoreIntFlag
WatchDone:

	movlw	0xff
	call	Delay		;wait for 256 ms

	decfsz	IRCount,F
	goto	RetrySetAlarm
	goto	RestoreIntFlag

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
	clrf	AlarmTime

RestoreIntFlag:
	bcf	INTCON,INTF

WatchTimer:
	btfss	INTCON,T0IF
	goto	WatchSwitch
	bcf	INTCON,T0IF     ;clear flag
	btfsc	PORTA,AlarmSW	;if Alarm is OFF skip the rest
	goto	WatchSwitch

	btfsc	AlarmFlags,IntrusionFlag ;Alarm if intrusion
	goto	Intrusion

	decf	LedDelay,F	        ;Decrement LED Delay
	btfss	STATUS,Z		;if Zero then 
	bcf	PORTA,LED	        ;clear LED and

	decfsz	AlarmTime,F		;If time not reached then out
	goto	WatchSwitch
	
	movlw	LED_DELAY
	movwf	LedDelay		;set LED Delay
	movlw	ALARM_TIME
	movwf	AlarmTime		;set Alarm Time
	bsf	PORTA,LED		;Turn LED ON
	goto	WatchSwitch
           
Intrusion:
	bsf	AlarmFlags,AlarmFlag    ;save intrusion
	bsf	PORTA,LED		;Turn ON LED

	decf	BeepDelay,F             ;Decrement BeepDelay
	btfss	STATUS,Z		;if Zero then 
	bcf	PORTA,Beep              ;clear Beep

	decf	LightsDelay,F           ;Decrement LightsDelay
	btfss	STATUS,Z		;if Zero then 
	bcf	PORTA,Lights            ;clear Beep
           
	decfsz	AlarmTime,F		;If time not reached then out
	goto	WatchSwitch
	
	movlw	BEEP_DELAY
	movwf	BeepDelay		;set Alarm Delay
	movlw	LIGHTS_DELAY
	movwf	LightsDelay		;set Lights Delay
	movlw	ALARM_TIME
	movwf	AlarmTime		;set Alarm Time
	btfss	AlarmFlags,BeepFlag	;Watch BeepFlag
	bsf	PORTA,Beep
	bsf	PORTA,Lights

	decfsz	AlarmCount,F		;If count not reached then out
	goto	WatchSwitch

	movlw	ALARM_COUNT
	movwf	AlarmCount			;set Alarm Count
	bcf	AlarmFlags,IntrusionFlag 	;clear intrusion flag
	bsf	INTCON,RBIF		 	;watch switches

WatchSwitch:
	btfss	INTCON,RBIF
	goto	RestoreStatus
	comf	PORTB,W		;read switches
	andlw	b'11110000'
	btfsc	STATUS,Z	;all switches open
	goto    RestoreStatus
	movlw	0x1e
	call	Delay
	comf	PORTB,W		;read switches again
	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
	clrf	AlarmTime

RestoreStatus:
	bcf	INTCON,RBIF
	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

Transmit                                                       
	movlw	0x0a
	call	Delay			;wait for 10 ms

	movlw	0x40
	movwf	TransmitCount			;64 bits transmition 

	bsf	PORTA,DataOut
	nop
	nop
	movlw	0x02
	call	IRDelay			;delay 2*3-1+5=10 mks
	bcf	PORTA,DataOut

	movlw	0xc4
	call	IRDelay			;delay	196*3-1+5=592 mks
	call	IRDelay			;delay	196*3-1+5=592 mks

NextDig:
	bsf	PORTA,DataOut
	bcf	STATUS,C
	rrf	Dig8,F
	rrf	Dig7,F
	rrf	Dig6,F
	rrf	Dig5,F
	rrf	Dig4,F
	rrf	Dig3,F
	rrf	Dig2,F
	rrf	Dig1,F
	nop
	nop
	nop
	nop
	bcf	PORTA,DataOut
        
	movlw	0x0a
	call	IRDelay			;delay 10*3-1+5=34

	btfss	STATUS,C
	goto	Send0

	movlw	0x84
	call	IRDelay			;delay 132*3-1+5=400 mks

Send0:
	movlw	0x71
	call	IRDelay			;delay 113*3-1+5=343 mks

	decfsz	TransmitCount,F
	goto	NextDig

	nop

	bsf	PORTA,DataOut
	nop
	nop
	movlw	0x02
	call	IRDelay			;delay 2*3-1+5=10 mks
	bcf	PORTA,DataOut

	movlw	0xc4                               
	call	IRDelay			;delay	196*3-1+5=592 mks
	call	IRDelay			;delay	196*3-1+5=592 mks

	bsf	PORTA,DataOut
	nop
	nop
	movlw	0x02
	call	IRDelay			;delay 2*3-1+5=10 mks
	bcf	PORTA,DataOut
	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
	movlw	ALARM_COUNT
	movwf	AlarmCount	;set Alarm Count
	clrf	BeepDelay
	clrf	LightsDelay
	clrf	LedDelay
	clrf	AlarmTime

	bsf	STATUS,RP0	;set bank 1
	movlw	b'00010000'     ;Port A
	movwf	TRISA
	movlw	b'11110011'	;Port B
	movwf	TRISB
	movlw	b'11010001'	;disable pull-up and enable timer0
	movwf	OPTION_REG
	bcf	STATUS,RP0	;set bank 0

	movlw	b'10111000'	;enable interrupts
	movwf	INTCON

Main:
	goto	Main

	org	0x3ff
	goto	Start		;Restart if got here

	end