; Simple Alarm System (Main Unit)
; Version 1.1 RC6
; (c)1997-2008
; Author: Kirill Yelizarov

; *** HOW TO MAKE ***
;1.Select desired processor in MPLAB
;2.Select IR receiver in _IR_REC
;3.Compile

;Possible processor selections:
;12C508, 12C508A, 12C509, 12C509A, 12CE518, 12CE519, 12F508, 12F509, 16F84, 16F84A
;PICs 16F84 and 16F84A are used for debug

;----------- S E L E C T --- Y O U R --- R E C E I V E R ----------- 
;Possible IR receiver selections:
_TBA_2800	EQU	.1	;_TBA_2800 - TBA 2800 (Micronas Intermetall GmbH http://www.intermetall.de)
_BRM_1020	EQU	.2	;_BRM_1020 - BRM-1020 (Bright LED Electronics Corp. http://www.brtled.com)
_TSOP_1738	EQU	.3	;_TSOP_1738 - TSOP-1738 (Vishay SemiconductorsGmbH http://www.vishay.com)
_TSOP_2156	EQU	.4	;_TSOP_2156 - TSOP-2156 (Vishay SemiconductorsGmbH http://www.vishay.com)
; 
_IR_REC		EQU	_TBA_2800	;IR receiver selection

;IR receiver logic output
_IR_NEG		EQU	.1	;Negative output when a pulse received
_IR_POS		EQU	.2	;Positive output when a pulse recieved
	IF	_IR_REC==_TBA_2800
_IR_PHASE	EQU	_IR_POS	;TBA2800 has negative output too
	ELSE
_IR_PHASE	EQU	_IR_NEG
	ENDIF
;-------------------------------------------------------------------

;Debug
_DEBUG		EQU	.0	;no debug, normal operation
;Debug levels for 16F84 and 16F84A only
;Some pins are used another way in debug mode 
;Check code before using this option
;_DEBUG		EQU	.1	;debug level #1 disable high timer
;_DEBUG		EQU	.2	;debug level #2 check IR receiver routine
;_DEBUG		EQU	.3	;debug level #3 check IR receiver routine and password
;_DEBUG		EQU	.4	;debug level #3 check IR receiver routine, password, and CRC

_12C508		EQU	.1
_12C508A	EQU	.2
_12C509		EQU	.3
_12C509A	EQU	.4
_12CE518	EQU	.5
_12CE519	EQU	.6
_16F84		EQU	.7
_16F84A		EQU	.8
_12F508		EQU	.9
_12F509		EQU	.10

	IFDEF	__12C508
	LIST	P=PIC12C508
	INCLUDE	p12c508.inc
_PIC_CPU	equ	_12C508
_PIC_MEM	equ	0x07
	ENDIF

	IFDEF	__12C508A
	LIST	P=PIC12C508A
	INCLUDE	p12c508a.inc
_PIC_CPU	equ	_12C508A
_PIC_MEM	equ	0x07
	ENDIF

	IFDEF	__12C509
	LIST	P=PIC12C509
	INCLUDE	p12c509.inc
_PIC_CPU	equ	_12C509
_PIC_MEM	equ	0x07
	ENDIF

	IFDEF	__12C509A
	LIST	P=PIC12C509A
	INCLUDE	p12c509a.inc
_PIC_CPU	equ	_12C509A
_PIC_MEM	equ	0x07
	ENDIF

	IFDEF	__12CE518
	LIST	P=PIC12CE518
	INCLUDE	p12ce518.inc
_PIC_CPU	equ	_12CE518
_PIC_MEM	equ	0x07
	ENDIF

	IFDEF	__12CE519
	LIST	P=PIC12CE519
	INCLUDE	p12ce519.inc
_PIC_CPU	equ	_12CE519
_PIC_MEM	equ	0x07
	ENDIF

	IFDEF	__12F508
	LIST	P=PIC12F508
	INCLUDE	p12f508.inc
_PIC_CPU	equ	_12F508
_PIC_MEM	equ	0x07
	ENDIF

	IFDEF	__12F509
	LIST	P=PIC12F509
	INCLUDE	p12f509.inc
_PIC_CPU	equ	_12F509
_PIC_MEM	equ	0x07
	ENDIF

	IFDEF	__16F84
	LIST	P=PIC16F84
	INCLUDE	p16f84.inc
_PIC_CPU	equ	_16F84
_PIC_MEM	equ	0x0c
	ENDIF

	IFDEF	__16F84A
	LIST	P=PIC16F84A
	INCLUDE	p16f84a.inc
_PIC_CPU	equ	_16F84A
_PIC_MEM	equ	0x0c
	ENDIF

	IFDEF	_PIC_CPU
	IFDEF	_IR_REC

	IF	(_PIC_CPU==_12C508)||(_PIC_CPU==_12C508A)||(_PIC_CPU==_12C509)||(_PIC_CPU==_12C509A)||(_PIC_CPU==_12CE518)||(_PIC_CPU==_12CE519)||(_PIC_CPU==_12F508)||(_PIC_CPU==_12F509)
	__CONFIG _IntRC_OSC & _WDT_OFF & _CP_OFF & _MCLRE_OFF
	ENDIF
	IF	(_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A)
	__CONFIG _XT_OSC & _WDT_OFF & _CP_OFF & _PWRTE_OFF
	ENDIF

	INCLUDE	"password.inc"

#define	OK		0x00
#define	Wait		0xff

#define	ACTIVATE	b'10000000'
#define	BEEP		b'00100000'
#define	LIGHT		b'00010000'
#define	UNLOCK		b'00000010'
#define	LOCK		b'00000001'

	IF 	(_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A)
#define	GPIO	PORTB
	ENDIF

#define	OutsidePin	GPIO,5	;two stage sensors (outside zone)
#define	InsidePin	GPIO,4	;two stage sensors (inside zone)
#define	IR		GPIO,3	;IR input pin
#define	Immob		GPIO,2	;immobilizer
#define	UnlockPin	GPIO,1	;doors lock unlock trigger
#define	LockPin		GPIO,0	;doors lock lock trigger

;----- Local DATA -----
	CBLOCK	_PIC_MEM
AlarmTris					;alarm TRIS register
	ENDC
#define	ArmLight	AlarmTris,7				;
#define	DisarmLight	AlarmTris,6
#define OutsideTris	AlarmTris,5
#define InsideTris	AlarmTris,4
#define	BatteryWeak	AlarmTris,3
#define	SilentMode	AlarmTris,2
#define UnlockTris	AlarmTris,1
#define LockTris	AlarmTris,0

	CBLOCK
AlarmFlags					;Alarm flags
	ENDC
#define	LockedFlag	AlarmFlags,7
#define	ArmedFlag	AlarmFlags,6
#define	AlarmInside	AlarmFlags,5
#define	AlarmOutside	AlarmFlags,4
#define AlarmMemory	AlarmFlags,3
#define	KillAll		AlarmFlags,2		;Kill all current tasks flag
#define	THO		AlarmFlags,1		;High Timer overflow flag
#define	ArmTrigger	AlarmFlags,0

	CBLOCK
LockUnlockSW		;Lock/Unlock switch flags
	ENDC
#define	UnlockSW_E	LockUnlockSW,7
#define	UnlockSW_F	LockUnlockSW,6
#define	UnlockSW_P	LockUnlockSW,5
#define	UnlockSW	LockUnlockSW,4
#define	LockSW_E	LockUnlockSW,3
#define	LockSW_F	LockUnlockSW,2
#define	LockSW_P	LockUnlockSW,1
#define	LockSW		LockUnlockSW,0

	CBLOCK
AlarmSW			;Inside and Outside zones flags & arm/disarm flags
	ENDC
#define	ArmBeep		AlarmSW,7
#define	OutsideSW_F	AlarmSW,6
#define	OutsideSW_P	AlarmSW,5
#define	OutsideSW	AlarmSW,4
#define	DisarmBeep	AlarmSW,3
#define	InsideSW_F	AlarmSW,2
#define	InsideSW_P	AlarmSW,1
#define	InsideSW	AlarmSW,0

	CBLOCK
TimerHigh					;High timer
IRStatus					;bits<7-0> IR pin samples with a 2us step
BitStatus					;bit<7> recieving data

Dig1						;password
Dig2
Dig3
Dig4
Dig5
Dig6
Dig7
Dig8
Dig9						;command and CRC

Out1Pin	
Out1Counter	
Out1Duration
Out2Pin	
Out2Counter	
Out2Duration
Out3Pin	
Out3Counter	
Out3Duration
	ENDC
_END_PIC_MEM	EQU	Out3Duration	;last RAM cell

;-------- ROM ---------
	org	0x00
	goto	Main

	IF	(_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A)
	org	0x04
	goto	Main
	ENDIF

;Get empty Output ------------------------------------------------------
GetEmptyOutput
	movlw	Out1Pin
	movwf	FSR
	btfss	INDF,7		;check for an empty output 1
	retlw	OK
	movlw	Out2Pin
	movwf	FSR
	btfss	INDF,7		;check for an empty output 2
	retlw	OK
	movlw	Out3Pin
	movwf	FSR
	btfss	INDF,7		;check for an empty output 3
	retlw	OK
	retlw	Wait

;Output Task ------------------------------------------------------------
Output
	movwf	FSR		;save OutXPin offset
	btfss	INDF,7		;check if output activated
	retlw	OK		;if not then return
	incf	FSR,F		;move offset to OutXCounter
	btfsc	KillAll		;check for a kill all command
	goto	StopOutput
	decfsz	INDF,F		;if zero not reached
	goto	$+2		;go to set output else release pin
	goto	StopOutput	;and branch to StopOutput to release pin
	decf	FSR,F		;move back to OutXPin
	comf	INDF,W		;move to W complement value of OutXPin
	andwf	AlarmTris,F	;clear the necessary bit in AlarmTris
	movf	AlarmTris,W	;and make the changes to tris itself
	iorlw	b'11001000'	;mask 3 system flags bits<7,6,3>
	andlw	b'11111011'	;mask 4th system flag bit<2>
	IF	(_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A)
	bsf	STATUS,RP0	;select bank1
	movwf	TRISB
	bcf	STATUS,RP0	;select bank0
	ENDIF
	IF	(_PIC_CPU==_12C508)||(_PIC_CPU==_12C508A)||(_PIC_CPU==_12C509)||(_PIC_CPU==_12C509A)||(_PIC_CPU==_12CE518)||(_PIC_CPU==_12CE519)||(_PIC_CPU==_12F508)||(_PIC_CPU==_12F509)
	tris	GPIO
	ENDIF
	incf	FSR,F		
	incf	FSR,F		;move to OutXDuration
	bcf	STATUS,C	;Clear Carry
	btfsc	INDF,7		;if bit 7 of OutXDuration set
	bsf	STATUS,C	;then set Carry
	rlf	INDF,F		;rotate OutXDuration
	btfsc	STATUS,C	;check Carry
	goto	RiseOutput	;if set then jump to RiseOutput
	decf	FSR,F
	decf	FSR,F		;move back to OutXPin
	comf	INDF,W		;move to W complement value of OutXPin
	andwf	GPIO,F		;clear the necessary bit in GPIO	
	retlw	OK
RiseOutput:
	decf	FSR,F
	decf	FSR,F		;move back to OutXPin
	movf	INDF,W		;move to W value of OutXPin
	iorwf	GPIO,F		;set the necessary bit in GPIO
	retlw	OK
StopOutput:
	decf	FSR,F		;move back to OutXPin
	bcf	INDF,7		;clear bit 7
	comf	INDF,W		;move to W complement value of OutXPin
	andwf	GPIO,F		;clear the necessary bit in GPIO
	movf	INDF,W		;move to W value of OutXPin
	iorwf	AlarmTris,F	;set the necessary bit in AlarmTris	
	movf	AlarmTris,W	;and make the changes to tris itself
	iorlw	b'11001000'	;mask 3 system flags bits<7,6,3>
	andlw	b'11111011'	;mask 4th system flag bit<2>
	IF 	(_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A)
	bsf	STATUS,RP0	;select bank1
	movwf	TRISB
	bcf	STATUS,RP0	;select bank0
	ENDIF
	IF 	(_PIC_CPU==_12C508)||(_PIC_CPU==_12C508A)||(_PIC_CPU==_12C509)||(_PIC_CPU==_12C509A)||(_PIC_CPU==_12CE518)||(_PIC_CPU==_12CE519)||(_PIC_CPU==_12F508)||(_PIC_CPU==_12F509)
	tris	GPIO
	ENDIF	
	retlw	OK

;Button Tester ------------------------------------------------------------
;this routine uses three flags (P, F and pressed button flag)
TestSwitch
	btfss	STATUS,Z	;check the button is pressed
	goto	ResetButton	;if not jump to ResetButton
	btfss	INDF,2		;check flag F state (First occurence)
	goto	SetButton
	btfsc	INDF,1		;check flag P state
	retlw	OK
	movlw	b'00000011'
	iorwf	INDF,F		;set P flag (Pressed condition) and button flag
	retlw	OK
SetButton:
	movlw	b'00000100'
	iorwf	INDF,F		;set F flag
	retlw	OK
ResetButton:
	movlw	b'11111001'
	andwf	INDF,F		;clear P, F flags (Button flag can be cleared in software only)
	retlw	OK

;Check IR input pin ---------------------------------------------------------
CheckIR
	btfss	TMR0,7
	goto	CheckIR
CheckZeroTMR:
	btfsc	TMR0,7
	goto	CheckZeroTMR

	decfsz	TimerHigh,F
	goto	SkipSetTH
	bsf	THO
SkipSetTH:

	clrf	IRStatus	
	IF	_IR_PHASE==_IR_NEG
	btfss	IR
	ELSE
	btfsc	IR
	ENDIF
	bsf	IRStatus,6
	nop
	nop
	nop
	nop
	IF	_IR_PHASE==_IR_NEG
	btfss	IR
	ELSE
	btfsc	IR
	ENDIF
	incf	IRStatus,F
	IF	_IR_PHASE==_IR_NEG
	btfss	IR
	ELSE
	btfsc	IR
	ENDIF
	incf	IRStatus,F
	IF	_IR_PHASE==_IR_NEG
	btfss	IR
	ELSE
	btfsc	IR
	ENDIF
	incf	IRStatus,F
	IF	_IR_PHASE==_IR_NEG
	btfss	IR
	ELSE
	btfsc	IR
	ENDIF
	incf	IRStatus,F
	IF	_IR_PHASE==_IR_NEG
	btfss	IR
	ELSE
	btfsc	IR
	ENDIF
	incf	IRStatus,F
	IF	_IR_PHASE==_IR_NEG
	btfss	IR
	ELSE
	btfsc	IR
	ENDIF
	incf	IRStatus,F
	btfsc	IRStatus,2	;Check at least 4 samples are high
	goto	PulseFound	;If IRStatus>3 then jump to PulseFound
	bsf	BitStatus,6	;Pause found then set pause flag
	incf	BitStatus,F	;else increase BitStatus (bit analyzer counter)
	btfsc	BitStatus,2	;check overflow condition
	goto	NoiseFound	;else noise found (overflow)
	retlw	OK		;It's not an overflow, normal return

PulseFound:
	nop
	IF	_IR_PHASE==_IR_NEG
	btfss	IR
	ELSE
	btfsc	IR
	ENDIF
	bsf	IRStatus,7
	movlw	.20
	btfss	IRStatus,6
	subwf	TMR0,F
	btfss	IRStatus,7
	addwf	TMR0,F
	btfss	BitStatus,7	;else check first pulse flag
	goto	FirstPulse	;if it is cleared then raise it and return
	btfss	BitStatus,6	;Was pause flag raised
	goto	FirstPulse	;if not then jump to FirstPulse (maybe this one is real)
	btfss	BitStatus,0	;check analyzer counter bit 0
	goto	Bit1Found	;This is a bit "1" in a message so jump to Bit1Found
	btfss	BitStatus,1	;check analyzer counter bit 1
	goto	Bit0Found	;This is a bit "0" in a message so jump to Bit0Found
	btfsc	BitStatus,5	;Start bit found
	goto	FirstPulse	;if it is set already then it's a noise or a real first pulse
	bsf	BitStatus,5	;enable Start Bit flag
	bsf	STATUS,C	;Start bit, once rotated through Dig0 it will stop incomming message
	goto	NextDigit
Bit1Found:
	btfss	BitStatus,5
	goto	FirstPulse	;If start bit is not set this maybe a real first pulse
	bsf	STATUS,C	;set incoming bit
	goto	NextDigit
Bit0Found:
	btfss	BitStatus,5
	goto	FirstPulse	;If start bit is not set this maybe a real first pulse
	bcf	STATUS,C	;clear incoming bit
NextDigit:
	movlw	b'10111000'
	andwf	BitStatus,F
	rlf	Dig9,F
	rlf	Dig8,F
	rlf	Dig7,F
	rlf	Dig6,F
	rlf	Dig5,F
	rlf	Dig4,F
	rlf	Dig3,F
	rlf	Dig2,F
	rlf	Dig1,F
	btfss	STATUS,C	;is start bit popped out
	retlw	OK		;if not then return

	IF	(_DEBUG==.2)&&((_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A))
	movf	Dig9,W
	andlw	b'00110000'
	movwf	Dig8
	rlf	Dig9,F
	rlf	Dig9,F
	rlf	Dig9,W
	andlw	b'00000011'
	iorwf	Dig8,W
	movwf	PORTB
	retlw	OK
	ENDIF

	movlw	PASS8		;time to check message
	xorwf	Dig8,W
	btfss	STATUS,Z
	goto	NoiseFound
	movlw	PASS7
	xorwf	Dig7,W
	btfss	STATUS,Z
	goto	NoiseFound
	movlw	PASS6
	xorwf	Dig6,W
	btfss	STATUS,Z
	goto	NoiseFound
	movlw	PASS5
	xorwf	Dig5,W
	btfss	STATUS,Z
	goto	NoiseFound
	movlw	PASS4
	xorwf	Dig4,W
	btfss	STATUS,Z
	goto	NoiseFound
	movlw	PASS3
	xorwf	Dig3,W
	btfss	STATUS,Z
	goto	NoiseFound
	movlw	PASS2
	xorwf	Dig2,W
	btfss	STATUS,Z
	goto	NoiseFound
	movlw	PASS1
	xorwf	Dig1,W
	btfss	STATUS,Z
	goto	NoiseFound
	
	IF	(_DEBUG==.3)&&((_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A))
	movf	Dig9,W
	andlw	b'00110000'
	movwf	Dig8
	rlf	Dig9,F
	rlf	Dig9,F
	rlf	Dig9,W
	andlw	b'00000011'
	iorwf	Dig8,W
	movwf	PORTB
	retlw	OK
	ENDIF

	movf	Dig9,W
	movwf	IRStatus		;save command and CRC
	andlw	b'11110000'		;cut CRC
	movwf	Dig9			;and place back to Dig9
	movlw	.72
	movwf	BitStatus		;this is CRC_Counter
	movlw	b'00110000'		;set poly (4bit CRC poly=10011)
CRCBit:
	bcf	STATUS,C
	rlf	Dig9,F
	rlf	Dig8,F
	rlf	Dig7,F
	rlf	Dig6,F
	rlf	Dig5,F
	rlf	Dig4,F
	rlf	Dig3,F
	rlf	Dig2,F
	rlf	Dig1,F
	btfsc	STATUS,C	
	xorwf	Dig1,F
	decfsz	BitStatus,F
	goto	CRCBit

	movf	IRStatus,W		;Check CRC
	movwf	Dig9
	andlw	b'00001111'
	swapf	Dig1,F
	xorwf	Dig1,W
	btfss	STATUS,Z
	goto	NoiseFound

	IF	(_DEBUG==.4)&&((_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A))
	movf	Dig9,W
	andlw	b'00110000'
	movwf	Dig8
	rlf	Dig9,F
	rlf	Dig9,F
	rlf	Dig9,W
	andlw	b'00000011'
	iorwf	Dig8,W
	movwf	PORTB
	retlw	OK
	ENDIF

	btfsc	IRStatus,7
	bsf	SilentMode
	btfsc	IRStatus,7
	bsf	ArmTrigger
	btfsc	IRStatus,5
	bsf	ArmTrigger
	btfsc	IRStatus,4
	bsf	BatteryWeak
	goto	NoiseFound

NoiseFound:
	clrf	BitStatus	;erase BitStatus
EraseMessage:
	clrf	Dig9		;erase message buffer
	clrf	Dig8
	clrf	Dig7
	clrf	Dig6
	clrf	Dig5
	clrf	Dig4
	clrf	Dig3
	clrf	Dig2
	clrf	Dig1	
	retlw	OK		;and return

FirstPulse:
	clrf	BitStatus	;erase BitStatus
	bsf	BitStatus,7
	goto	EraseMessage


;                 ------------ M A I N -------------
Main:
	clrf	STATUS
	IF	(_PIC_CPU==_12C508)||(_PIC_CPU==_12C508A)||(_PIC_CPU==_12C509)||(_PIC_CPU==_12C509A)||(_PIC_CPU==_12CE518)||(_PIC_CPU==_12CE519)||(_PIC_CPU==_12F508)||(_PIC_CPU==_12F509)
	movlw	b'11001000'	;Dissable weak pull-ups and wake up on pin change
	option			;and set Timer0 prescaller 1:1
	movlw	b'00111011'	;All pins are set as input on initialize except GP2
	tris	GPIO
	ENDIF
	IF	(_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A)
	movlw	b'00000000'
	movwf	INTCON		;disable interrupts
	movlw	b'10001000'	;disable weak pull-up on PortB
	bsf	STATUS,RP0	;select bank1
	movwf	OPTION_REG
	movlw	b'11111111'	;all pins are input
	movwf	TRISA
	movlw	b'11111011'	;except RB2
	movwf	TRISB
	bcf	STATUS,RP0	;select bank0
	ENDIF
	clrf	GPIO		;Reset GPIO

EraseRAM:
	movlw	_PIC_MEM
	movwf	FSR
EraseNext:
	clrf	INDF
	IF	(_PIC_CPU==_12C508)||(_PIC_CPU==_12C508A)||(_PIC_CPU==_12CE518)
	movlw	_END_PIC_MEM + b'11100000'
	ENDIF
	IF	(_PIC_CPU==_12C509)||(_PIC_CPU==_12C509A)||(_PIC_CPU==_12CE519)
	movlw	_END_PIC_MEM + b'11000000'
	ENDIF
	IF	(_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A)
	movlw	_END_PIC_MEM
	ENDIF
	xorwf	FSR,W
	btfsc	STATUS,Z
	goto	EndEraseRAM
	incf	FSR,F
	goto	EraseNext
EndEraseRAM:

	movlw	b'00110011'
	movwf	AlarmTris	;initiate tris register

	bsf	ArmedFlag	;Main unit always armed when powered on

	IF	((_DEBUG==.2)||(_DEBUG==.3)||(_DEBUG==.4))&&((_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A))
	bsf	STATUS,RP0	;select bank1
	movlw	b'11001100'	;set RB0,RB1,RB4,RB5 as output for debug output
	movwf	TRISB
	bcf	STATUS,RP0	;select bank0
DebugLevel2:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	goto	DebugLevel2 	;for debug only!!!!!!!!!!!!!!!!
	ENDIF

	clrf	TMR0

Loop:

; --------------- Input States ---------------------

CheckInsideZone:
	call	CheckIR			;!!!!!!!!!! Check IR input state
	btfss	InsideTris		;Check the inside zone trigger is set for input
	goto	EndCheckInsideZone
	movlw	AlarmSW			;save AlarmSW offset to FSR
	movwf	FSR
	bcf	STATUS,Z
	btfss	InsidePin		;check inside zone trigger condition
	bsf	STATUS,Z		;if level is low set Zero flag
	call	TestSwitch
EndCheckInsideZone:

CheckOutsideZone:
	call	CheckIR			;!!!!!!!!!! Check IR input state
	btfss	OutsideTris		;Check the outside zone trigger is set for input
	goto	EndCheckOutsideZone
	swapf	AlarmSW,F		;swap nibbles
	movlw	AlarmSW			;save AlarmSW offset to FSR
	movwf	FSR
	bcf	STATUS,Z
	btfss	OutsidePin		;check outside zone trigger condition
	bsf	STATUS,Z		;if level is low set Zero flag
	call	TestSwitch
	swapf	AlarmSW,F		;swap nibbles back
EndCheckOutsideZone:

CheckLockSW:
	call	CheckIR			;!!!!!!!!!! Check IR input state
	btfss	LockTris		;Check the lock switch is set for input
	goto	EndCheckLockSW
	movlw	LockUnlockSW		;save LockUnlockSW offset to FSR
	movwf	FSR
	bcf	STATUS,Z
	btfss	LockPin			;check Lock switch condition
	bsf	STATUS,Z		;if level is low set Zero flag
	call	TestSwitch
EndCheckLockSW:

CheckUnlockSW:
	call	CheckIR			;!!!!!!!!!! Check IR input state
	btfss	UnlockTris		;Check the unlock switch is set for input
	goto	EndCheckUnlockSW
	swapf	LockUnlockSW,F		;swap nibbles
	movlw	LockUnlockSW		;save LockUnlockSW offset to FSR
	movwf	FSR
	bcf	STATUS,Z
	btfss	UnlockPin		;check Unlock switch condition
	bsf	STATUS,Z		;if level is low set Zero flag
	call	TestSwitch
	swapf	LockUnlockSW,F		;swap nibbles back
EndCheckUnlockSW:

;------------ Alarm logic -------------
CheckFlags:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	btfsc	ArmedFlag	;Armed? 1-Armed 0-not
	goto	CheckToDisarm
CheckToArm:
	btfss	ArmTrigger
	goto	CheckArmFlag
	bsf	ArmedFlag	;System armed now
	bcf	InsideSW_P
	bcf	InsideSW_F
	bcf	InsideSW	;clear inside zone triggers
	bcf	OutsideSW_P
	bcf	OutsideSW_F
	bcf	OutsideSW	;clear outside zone triggers
	bcf	ArmTrigger	;clear lock flag
	bsf	KillAll		;Kill all current tasks
	btfss	SilentMode
	bsf	ArmBeep		;enable arm visualization
	bcf	SilentMode
	bsf	ArmLight	
	goto	Lock
CheckToDisarm:
	btfss	ArmTrigger
	goto	CheckArmFlag
	bcf	ArmedFlag	;System disarmed now
	bcf	ArmTrigger	;clear lock flag
	bsf	KillAll		;Kill all current tasks
	btfss	SilentMode
	bsf	DisarmBeep	;enable disarm visualization
	bcf	SilentMode
	bsf	DisarmLight
	goto	Unlock
CheckArmFlag:
	btfss	ArmedFlag
	goto	Disarmed

	bcf	Immob		;immobilizer relay off
	btfss	InsideSW	;inside trigger set?
	goto	CheckOutsideTrigger
	bcf	InsideSW
	bsf	AlarmInside	;Turn alarm inside zone on
CheckOutsideTrigger:
	btfss	OutsideSW	;outside trigger set?
	goto	CheckComplete
	bcf	OutsideSW
	bsf	AlarmOutside	;Turn alarm outside zone on
	goto	CheckComplete

Disarmed:
	bsf	Immob		;immobilizer relay on
	btfsc	InsideSW	;inside trigger set?
	bcf	AlarmMemory	;then clear memory	
	btfsc	LockedFlag	;Doors locked? 1-Doors locked 0-unlocked
	goto	CheckToUnlock
CheckToLock:
	btfss	LockSW		;Lock enabled?
	goto	CheckComplete
	btfsc	UnlockSW	;Check the unlock flag
	goto	CheckComplete	;Skip situation when both flags raised
Lock:
	bsf	LockSW_E	;if its a lock command set Lock enable flag
	bsf	LockedFlag	;Doors locked now
	goto	CheckComplete
CheckToUnlock:
	btfss	UnlockSW	;Unlock enabled?
	goto	CheckComplete
	btfsc	LockSW		;Check the lock flag
	goto	CheckComplete	;Skip situation when both flags raised
Unlock:
	bsf	UnlockSW_E	;if YES set Unlock enable flag
	bcf	LockedFlag	;Doors unlocked now
CheckComplete:
	bcf	LockSW		;clear lock flag
	bcf	UnlockSW	;clear unlock flag

; --------------------- Output States ------------------------

CheckOut1Pin:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	movlw	Out1Pin
	call	Output		;check output cell #1

CheckOut2Pin:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	movlw	Out2Pin
	call	Output		;check output cell #2

CheckOut3Pin:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	movlw	Out3Pin
	call	Output		;check output cell #3

	bcf	KillAll		;clear command

; -------------------- Set States ---------------------------

EnableInsideAlarm:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	btfss	AlarmInside	;Check inside zone alarm enable flag
	goto	EndEnableInsideAlarm
	call	GetEmptyOutput	;Find empty output cell
	xorlw	Wait		;check an empty output cell found
	btfsc	STATUS,Z
	goto	EndEnableInsideAlarm	;if not skip the rest and wait
	bcf	AlarmInside	;Clear alarm enable flag
	movlw	LIGHT+BEEP+ACTIVATE
	movwf	INDF
	incf	FSR,F
	movlw	.80		;duration 65ms*80=
	movwf	INDF
	incf	FSR,F
	movlw	b'11110000'
	movwf	INDF
	bcf	InsideSW_P
	bcf	InsideSW_F
	bsf	AlarmMemory
EndEnableInsideAlarm:

EnableOutsideAlarm:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	btfss	AlarmOutside	;Check outside zone alarm enable flag
	goto	EndEnableOutsideAlarm
	call	GetEmptyOutput	;Find empty output cell
	xorlw	Wait		;check an empty output cell found
	btfsc	STATUS,Z
	goto	EndEnableOutsideAlarm	;if not skip the rest and wait
	bcf	AlarmOutside	;Clear alarm enable flag
	movlw	BEEP+ACTIVATE
	movwf	INDF
	incf	FSR,F
	movlw	.8		;duration 65ms*4=260ms
	movwf	INDF
	incf	FSR,F
	movlw	b'10000000'	;beep duration 65ms*1=65ms
	movwf	INDF
	bcf	OutsideSW_P
	bcf	OutsideSW_F
EndEnableOutsideAlarm:

EnableBeep:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	btfsc	ArmBeep		;Check arm beep enable flag
	goto	Beep
	btfss	DisarmBeep	;Check disarm beep enable flag
	goto	EndEnableBeep
Beep:
	call	GetEmptyOutput	;Find empty output cell
	xorlw	Wait		;check an empty output cell found
	btfsc	STATUS,Z
	goto	EndEnableBeep	;if not skip the rest and wait
	movlw	BEEP+ACTIVATE
	movwf	INDF
	incf	FSR,F
	movlw	.8		;duration 65ms*8=520ms  (1 beep)
	btfsc	DisarmBeep
	movlw	.16		;duration 65ms*16=1040ms  (2 beeps)
	btfsc	AlarmMemory
	movlw	.24
	movwf	INDF
	incf	FSR,F
	movlw	b'11100000'	;beep duration 65ms*3=195ms
	movwf	INDF
	bcf	ArmBeep		;Clear beep enable flag
	bcf	DisarmBeep
EndEnableBeep:

DoorLock:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	btfsc	LockSW_E	;Check Lock enable flag
	goto	EnableDoorLock
	btfsc	UnlockSW_E	;Check unlock enable flag
	goto	EnableDoorLock
	goto	EndEnableDoorLock
EnableDoorLock:
	call	GetEmptyOutput	;Find empty output cell
	xorlw	Wait		;check an empty output cell found
	btfsc	STATUS,Z
	goto	EndEnableDoorLock	;if not skip the rest and wait
	movlw	LOCK+ACTIVATE
	btfsc	UnlockSW_E
	movlw	UNLOCK+ACTIVATE
	movwf	INDF		;
	bcf	LockSW_E	;Clear lock enable flag
	bcf	UnlockSW_E	;Clear unlock enable flag	
	incf	FSR,F
	movlw	0x02		;set duration 128ms
	movwf	INDF
	incf	FSR,F
	movlw	b'11000000'	;set bit map
	movwf	INDF
EndEnableDoorLock:

EnableLight:
	call	CheckIR		;!!!!!!!!!! Check IR input state
	btfsc	ArmLight	;Check light enable flag
	goto	Light
	btfss	DisarmLight
	goto	EndEnableLight
Light:
	call	GetEmptyOutput	;Find empty output cell
	xorlw	Wait		;check an empty output cell found
	btfsc	STATUS,Z
	goto	EndEnableLight	;if not skip the rest and wait
	movlw	LIGHT+ACTIVATE
	movwf	INDF		;
	incf	FSR,F
	movlw	.8		;duration 65ms*8=520ms  (1 blink)
	btfsc	DisarmLight
	movlw	.16		;duration 65ms*16=1040ms  (2 blinks)
	btfsc	AlarmMemory
	movlw	.24
	movwf	INDF
	incf	FSR,F
	movlw	b'11110000'
	btfsc	BatteryWeak
	movlw	b'11111111'
	movwf	INDF
	bcf	BatteryWeak
	bcf	ArmLight	;Clear light enable flag
	bcf	DisarmLight
EndEnableLight:

_Wait:
	IF	(_DEBUG==.1)&&((_PIC_CPU==_16F84)||(_PIC_CPU==_16F84A))
	goto	Loop		;for debug only!!!!!!!!!!!!!!!!
	ENDIF
	call	CheckIR		;!!!!!!!!!! Check IR input state
	btfss	THO
	goto	_Wait
	bcf	THO
	goto	Loop

	IF	(_PIC_CPU==_12C508)||(_PIC_CPU==_12C508A)||(_PIC_CPU==_12CE518)||(_PIC_CPU==_12F508)
	org	0x1ff
	movlw	b'01110000'	;set OSCCAL
	ENDIF

	IF	(_PIC_CPU==_12C509)||(_PIC_CPU==_12C509A)||(_PIC_CPU==_12CE519)||(_PIC_CPU==_12F509)
	org	0x3ff
	movlw	b'01110000'	;set OSCCAL
	ENDIF

	ELSE
	Error	"IR Receiver not selected. Check code"
	ENDIF
	ELSE
	Error	"Wrong PIC selected. [Configure]->[Select Device...]"
	ENDIF

	end