  ;************************ Alarm.asm *****************************************
 ; Written by:	Mike Skypek
 ;		1787 Wiggins Circle
 ;		Conyers, Ga 30094
 
 ;
 ;This software is made available to Talking Electronics and may be used freely, without
 ;permission by the copyright owner, by indviduals for themselves.  
 ;
 ;
 ; Read this documentation first - it will be difficult to figure out what the 
 ; software does by reading the code.   Once you understand the functions this sofware
 ; performs, the code simply "explains" how it is done.
 ;
 ; This is the software creating a two-zone, two stage alarm for the PICLICK-1 module
 ; using a Microchip PIC16F628-04.  If you use a PIC16F628-20 or other processor with 
 ; a different speed, you will need to change the timer values associated with each function.
 ;
 ; A two zone alarm means the alarm has two seperate 'detection' circuits  and can 
 ; identify which circuit was triggered.  This alarm software uses RA1 and RA2 as 'detectors'.
 ; Currently this capability is used only to allow the operator to select whether the
 ; detector(s) on RA2 are ignored or processed.  This allows the operator to turn-off the 
 ; garage alarm for example but leave the toolbox alarm on. 
 ;
 ; Two stage means that the alarm recognizes when it has been triggered more than once
 ; and reacts differently.  "Warning/subdued" devices are tiggered the first time the
 ; alarm is set-off and then "Intruder/loud" devices are triggered everytime thereafter.
 ;----------------------------------------------------------------------------------
 ; Alarm is controlled by a push-switch. The Alarm powers-up in disarmed mode (off). 

 ; The possible modes are: Disarm, Enabled, Yellow, and Red.  The three commands
 ; that can be entered via the push-switch are:
 ;
 ; 1.  A double click while in any mode puts the alarm in Enabled mode (on).
 ;     Going into Enabled mode resets everything.  If already in Enabled mode - 
 ;     any clicks are counted toward triple clicks (see triple clicks later).
 ; 2.  Holding the control button for 3 seconds while in any mode puts it
 ;     back to disarm mode.  If already in disarm mode - nothing happens.
 ;     Going into disarm mode essential turns off all output/alarm devices and
 ;     disables the movement/intruder detection functions.
 ; 3.  Triple clicking is possible only while in Enabled mode, which causes 
 ;     the alarm to ignore the 2nd detection zone (RA2).  Triple clicking 
 ;     again causes the alarm to resume processing of 2nd motion detector.
 ;     Triple clicking in any mode other than Enable mode is interpreted
 ;     as a double click (see above) with an additional extraneous click.  
 
 ; After the alarm is enabled, the alarm can be triggered by RA1 or RA2.
 ; 	if triggered the first time - the alarm goes to Yellow Alert Mode. 
 ; 	if triggered the second time - the alarm goes to Red Alert Mode.
 ; 	if triggered anytime afterward the alarm stays in Red Alert Mode.
 
 ; The Alarm Status is displayed via LEDs.  They are like traffic lights, 
 ; with Red - Yellow - Green.
 ;	Green - Disabled (Okay to walk about freely)
 ;	Blinking sequence1 (Red, Yellow, Green) - Enabled with both detectors
 ;	Blinking sequence2 (Green, Yellow, Red) - Enabled only with RA1 detector 
 ;      Yellow - Alarm is on and has been triggered once.
 ;	Red - Alarm is on and has been triggered 2 or more times
 ;
 ; The program has a main loop which checks for a high on RA0 from
 ; the push-switch and for changes from the two motion detectors (Low to High 
 ; on RA1 or RA2). It then turns on appropriate flag-bits and sets
 ; timer values for functions that the isr (interrupt service routine) performs.

 ; The program uses an isr (interrupt service routine) that executes off TRM0 interrupts
 ; every 7.9 microseconds.  The isr performs all functions that are timed, 
 ; such as maintaining the debounce-on flag,  turning off various
 ; alarm components after certain time intervals have elapsed, giving someone who has
 ; entered the room time 40 seconds disable the alarm or giving someone who has 
 ;enabled the alarm 40 seconds to leave the room...
 ;
 ; To have the isr perform a function, the software generally sets the appropriate
 ; flag-bit and sets the appropriate variable with the number of 7.9 microseconds 
 ;interrupts that the isr is to perform that function.  The isr clears that flag-bit after the  ;function has been performed for the specified number of times.
 ;---------------------------------------------------------------------- 
 ; Alarm Input - RA0 thru RA2
 ;
 ;  RA0 -  Control switch which enables or disables alarm 
 ;  RA1 -  Motion Detector 1
 ;  RA2 -  Motion Detector 2 (can be turn-off by triple clicking in 'Enabled Mode')
 ;
 ; Alarm outputs - RA3, RB0 thru RB7
 ;
 ;  RA3 - Control power-on switch for power amplifier (used by voice messages)
 ;  RB0 - Green LED status light
 ;  RB1 - Yellow LED status light
 ;  RB2 - Red LED status light
 ;  RB3 - Strobe light - used everytime alarm is triggered
 ;  RB4 - Horn/Buzzer (Loud) - used only when entering or in red alert
 ;  RA5 - Siren Warning (subdued to moderate) - used only when entering yellow alert 
 ;  RA6 - Verbal Warning - used only when entering yellow alert (uses amplifier)
 ;  RB7 - Barking Dogs - used everytime alarm is triggered (uses amplifier)

;------------------------------------------------------------------------------
	LIST   P=PIC16F628
	;include <P16F628.inc>
	__CONFIG _CP_OFF & _LVP_OFF & _PWRTE_OFF & _WDT_OFF & _INTRC_OSC_CLKOUT & _MCLRE_off & 	_BODEN_off

;Ports:

PORTA		equ 0x05
PORTB		equ 0x06

;All others:

CMCON		equ 0x1F
INTCON		equ 0x0B
INTF		equ 1
OPTION_REG	equ 0x81
PCL		equ 0x02
RP0		equ 5
RP1		equ 6
STATUS		equ 0x03
T0IF		equ 2
TMR0		equ 0x01
TRISA		equ 0x85
TRISB		equ 0x86
Z		equ 2



       ;Configuration Bits:

_BODEN_ON                    EQU     H'3FFF'
_BODEN_OFF                   EQU     H'3FBF'
_CP_ALL                      EQU     H'03FF'
_CP_75                       EQU     H'17FF'
_CP_50                       EQU     H'2BFF'
_CP_OFF                      EQU     H'3FFF'
_PWRTE_OFF                   EQU     H'3FFF'
_PWRTE_ON                    EQU     H'3FF7'
_WDT_ON                      EQU     H'3FFF'
_WDT_OFF                     EQU     H'3FFB'
_LVP_ON                      EQU     H'3FFF'
_LVP_OFF                     EQU     H'3F7F'
_MCLRE_ON                    EQU     H'3FFF'
_MCLRE_OFF                   EQU     H'3FDF'
_ER_OSC_CLKOUT               EQU     H'3FFF'
_ER_OSC_NOCLKOUT             EQU     H'3FFE'
_INTRC_OSC_CLKOUT            EQU     H'3FFD'
_INTRC_OSC_NOCLKOUT          EQU     H'3FFC'
_EXTCLK_OSC                  EQU     H'3FEF'
_LP_OSC                      EQU     H'3FEC'
_XT_OSC                      EQU     H'3FED'
_HS_OSC                      EQU     H'3FEE'



;----------- Misc variables
Alarm_state	equ 0x22	; Contains alarm state
Stat_sav	equ 0x24
W_sav		equ 0x25
tmr_Flg1	equ 0x27	; Register of  timer flags
tmr_Flg2	equ 0x28	; Register of more timer flags
Puls_flgs	equ 0X29	; Pulse LED flags
mi_Flgs		equ 0x2A	; miscellaneous flags
cnt_Clicks	equ 0x2C
tbl_i		equ 0x2D	; table index
;-------------Miscellaneous flags

flg_RAoff	equ 0	; Used to insure a double-click
flg_Zone2	equ 1	; Used to turn off motion detector (ZONE) 2
flg_Deboun	equ 2	; debouncing in progress

;-------------Alarm State flags (bit number)

flg_Dis		equ 0	; Set State of alarm = "disable"
flg_Ena    	equ 1	; Set State of alarm  = "enable"
flg_Yellow	equ 2	; Set State of alarm = "yellow alert"
flg_Red		equ 3	; Set state of alarm = "red alert"

;PORTA bits
bit_In		equ 0	;switch input
bit_Z1		equ 1	;motion detector (ZONE) 1
bit_Z2		equ 2	;motion detector (ZONE) 2
bit_Amp_On	equ 3	;power amplifier


;PORTB bits
bit_Red		equ 0	; red led
bit_Yel		equ 1
bit_Gre		equ 2
bit_Strobe	equ 3
bit_Buzz	equ 4
bit_Siren	equ 5
bit_Verb	equ 6	; verbal warning
bit_Dog		equ 7	; barking dog

;----------- Timer flags 

flg_Clk		equ 0		;timer-1 flags
flg_Verb	equ 1
flg_Strobe	equ 2
flg_Buzz	equ 3
flg_Dog		equ 4
flg_Siren	equ 5
flg_Disarm	equ 6

flg_Waita	equ 0		;timer-2 flags
flg_Waitb	equ 1		;  " 	   "
flg_Trig	equ 2		;  "       "
flg_Amp_On	equ 4

;----------- Timer intervals
;- tmr register variables are decremented & processed during interrupt 
;  processing if it's corresponding flg is set in tmr_Flg1. Must use two register
;  variables to have intervals more a couple of seconds.

tmr_Clk 	equ 0x30	;time between control clicks
tmr_Deboun	equ 0x31	;Debounce interval
tmr_Blink	equ 0x32	;interval that a blinking LED in on 
tmr_Trig	equ 0x33	;interval that an alarm trigger must be active
tmr_Siren	equ 0x34	;Siren interval 

tmr_Buzz1	equ 0x35	;Buzzer interval 
tmr_Buzz2	equ 0x36	;Number of intervals Buzzer is "on"
tmr_Disarm1	equ 0x37
tmr_Dog1	equ 0x3A	;Barking Dogs warning interval 
tmr_Strobe1	equ 0x3C
tmr_Strobe2	equ 0x3D
tmr_Verb1	equ 0x3F	;Verbal warning interval 
tmr_Delay1	equ 0x42	;shared by the isr routines that delay
tmr_Delay2	equ 0x43	;triggering and enabling alarm
tmr_Amp_On1	equ 0x46	;amplifier remain-on interval
tmr_Amp_On2	equ 0x47
tmr_Rearm1	equ 0x48
tmr_Rearm2	equ 0x49
tmr_Rearm3	equ 0x4A
ExitDel1	equ 0x4B	;timing for duration of entry/exit beep
ExitDel2	equ 0x4C	;timing for duration of entry/exit beep

; The following constants are the number of 8 microseconds intervals or 2.1 second intervals allowed.   
lmt_Strobe2	equ 0x16	;2.1 second intervals for strobe light
lmt_Amp_On2	equ 0x20	;2.1 second intervals for amp to remain on

lmt_Disarm	equ 0xFF	;8 microsecond interval (2.1 seconds)
lmt_Blink	equ 0x7E	;8 microsecond intervals for one blink of the rotating LEDs
				; (7E = approximately one second)
lmt_Deboun	equ 0x20	;8 microsecond intervals to debounce (1/4 seconds)
lmt_Clk		equ 0xA0	;time when 2nd click becomes a double-click

;------------------------------------------------------------
	ORG	0
	GOTO	Main
	ORG	4		;interrupts always vector to here
	GOTO	isr

;----- Code Table for siren intervals (makes siren wail at uneven intervals)
;----- If you move the call to this table from the isr routine to another memory location or
;      move this table, check Microchip pub ANS556 to avoid some possible problems.
tableS	addwf	PCL,1
	retlw	0x0A0	; 1
	retlw	0x025	; 2
	retlw	0x0A0	; 3
	retlw	0x035	; 4
	retlw	0x0A0	; 5
	retlw	0x070	; 6
	retlw	0x020	; 7
	retlw	0x050	; 8
	retlw	0x0A0	; 9
	retlw	0x030	; A
	retlw	0x0A0	; B
	retlw	0x050	; C
	retlw	0x090	; D
	retlw	0x050	; E
	retlw	0x0A0	; F
	retlw	0x070	;10
	retlw	0x0A0	;11
	retlw	0x050	;12
	retlw	0x020	;13
	retlw	0x050	;14
	retlw	0x020	;15
	retlw	0x050	;16

;------Interrupt Service Routine (ISR).  Servicing TMR0 interrupts only.
;	This ISR allow the main program to turn on an output port, set up a 
;	counter	that specifies how many timer interrupts (7.9 microseconds intervals) a 
;	function is to remain on. 126 (0x07E) intervals is about 1 second.
;	This ISR is also used for other functions that need something done
;	after a certain time interval such as
;	- setting a 'debounce-off' flag
;	- implement a delay before enabling the alarm (to allow someone to leave)
;	- implement a delay before going to a Yellow or Red Alert mode.
;	- maintaining a time-out interval for "double clicks" on RA0 input, ....
;
isr	MOVWF	W_sav			; first save critical registers
	SWAPF	STATUS,W
	BCF	STATUS,RP0		; always change to bank 0 
	MOVWF 	Stat_sav
		
	BTFSS 	Alarm_state, flg_Dis	; is alarm disabled?
	GOTO 	isr_0			; no
	DECFSZ	tmr_Rearm3,1		; 
	GOTO	isr_0
	DECFSZ	tmr_Rearm2,1		; 
	GOTO	isr_0			; This code eventually enables the alarm 
	DECFSZ	tmr_Rearm1,1		; in a few hours.  I put this in because I
	GOTO	isr_0			; would get distracted and forget to enable
	CALL	Enable			; the alarm after I left the garage.

isr_0   BTFSS	mi_Flgs, flg_Deboun 	; Debouncing?
	GOTO	isr_1			; no
	DECFSZ	tmr_Deboun,1		; time up?
	GOTO	isr_2			; no
	BCF	mi_Flgs, flg_Deboun	; Turn off "debounce in progress" flag

isr_1	BTFSS   tmr_Flg1, flg_Clk 	; looking for a double click?
	GOTO	isr_2	
	DECFSZ	tmr_Clk,1		; count down
	GOTO	isr_2
	BCF	tmr_Flg1, flg_Clk	; yes - time is up

isr_2	BTFSS	tmr_Flg1, flg_Verb	; verbal warning timer on? 
	GOTO	isr_3			; no
	DECFSZ	tmr_Verb1,1		;
	GOTO	isr_3			; 
	BCF	tmr_Flg1, flg_Verb
	BCF	PORTB, bit_Verb		; turn off verbal warning

isr_3	BTFSS	tmr_Flg1, flg_Strobe	; strobe light timer on?
	GOTO	isr_4			; no
	DECFSZ	tmr_Strobe1,1
	GOTO	isr_4
	DECFSZ	tmr_Strobe2,1		; count-down reached?
	GOTO	isr_4
	BCF	tmr_Flg1, flg_Strobe
	BCF	PORTB, bit_Strobe	; turn off strobe

isr_4	BTFSS	tmr_Flg1, flg_Buzz 	; Buzzer/Horn handling ?
	GOTO	isr_5			; no
	DECFSZ	tmr_Buzz1,1
	GOTO	isr_5
	MOVLW	0x10			; buzzer/horn bit
	XORWF	PORTB,1			; reverse PORTB Buzzer State
	MOVLW	0x0FF			; set buzzer-on interval
	BTFSS	PORTB, bit_Buzz		; is buzzer on?
	MOVLW	0x080			; yes, set buzzer-off interval
	MOVWF	tmr_Buzz1		; 
	DECFSZ	tmr_Buzz2,1		; count down times buzzer is turned on and off 
	GOTO	isr_5			; limit not reached 
	BCF	tmr_Flg1, flg_Buzz 	;
	BCF	PORTB, bit_Buzz		; turn off buzzer

isr_5	BTFSS	tmr_Flg1, flg_Dog	; Barking dogs handling? (Amplifier should be on)
	GOTO	isr_6
	DECFSZ	tmr_Dog1,1
	GOTO	isr_6
	BCF	tmr_Flg1, flg_Dog
	BCF	PORTB, bit_Dog		; turn off barking dogs

isr_6	BTFSS	tmr_Flg1, flg_Siren	; Siren handling?
	GOTO	isr_7			; no
	DECFSZ	tmr_Siren, 1
	GOTO	isr_7
	MOVLW	0x20			; Siren bit
	XORWF	PORTB,1			; Reverse PORTB Siren State
	MOVF	tbl_i,0			; 
	CALL	tableS			; Call Siren table
	MOVWF	tmr_Siren		; set siren interval timer
	DECFSZ	tbl_i,1	
	GOTO	isr_7
	BCF	tmr_Flg1, flg_Siren
	BCF	PORTB, bit_Siren	; turn off siren
	
isr_7	BTFSS	tmr_Flg1, flg_Disarm	; Disarm?
	GOTO	isr_8
	DECFSZ	tmr_Disarm1,1		; has switch been closed long enough?
	GOTO	isr_8
	BCF	tmr_Flg1, flg_Disarm	; yes - we have a Disarm command
	CALL	SetDis			
	MOVLW	0xFF			; give user 2.1 seconds to release
	MOVWF	tmr_Deboun		; switch after Disarm is triggered 
	BSF	mi_Flgs, flg_Deboun	; before more RA0 inputs are processed

isr_8	BTFSS	tmr_Flg2, flg_Waita	; Waiting to set off alarm
	GOTO	isr_9			; no
	DECFSZ	tmr_Delay1,1		; wait several seconds in case someone
	GOTO	isr_9			; entered to turn off alarm.
	DECFSZ	tmr_Delay2,1		; count-down reached?
	GOTO	isr_9			; no
	BCF	tmr_Flg2, flg_Waita
	CALL 	Beep
	BTFSS 	Alarm_state, flg_Yellow	
	GOTO	isr_8a
	CALL	SetYel			; yellow alert
	GOTO	isr_9
isr_8a	BTFSC 	Alarm_state, flg_Red	
	CALL	SetRed			; red alert

isr_9	; If the alarm is in "enabled" mode, then blink lights from 
	; from top to bottom (or bottom to top if Zone 2 is disabled)
	BTFSS 	Alarm_state, flg_Ena ; is alarm in enabled mode?
	GOTO	isr_10		; no
	DECFSZ	tmr_Blink,1	; time to blink a different color? 
	GOTO	isr_10		; no
	BTFSS	tmr_Flg2, flg_Waitb  ; Are we waiting to enable alarm?
	GOTO	isr_9a		; no	
	MOVLW	b'00000100'	; set green as default color
	BTFSC	PORTB, bit_Gre	; was PortB green led already on?
	MOVLW	b'00000000'	; no then set W = no leds 
	IORWF	PORTB, 1	; update PORTB with new LED display	
	GOTO	isr_9z	
isr_9a	BTFSS	mi_Flgs,flg_Zone2 ; Zone 2 disabled?
	GOTO	isr_9b		; no reverse order lights blink
	MOVLW	b'00000100'	; set green as default color
	BTFSC	PORTB, bit_Gre	; was PortB green led already on?
	MOVLW	b'00000010'	; then set W =  yellow led 
	BTFSC	PORTB, bit_Yel	; was PortB yellow led already on?
	MOVLW	b'00000001'	; then set W =  Red
	GOTO 	isr_9z
isr_9b	MOVLW	b'00000100'	; Blink lights in reverse order of isr_9
	BTFSC	PORTB, bit_Gre	; was PortB green led already on?
	MOVLW	b'00000001'	; then set W =  Red
	BTFSC	PORTB, bit_Red	; was PortB yellow led already on?
	MOVLW	b'00000010'	; then set W =  yellow led 
isr_9z	BCF	PORTB, bit_Gre
	BCF	PORTB, bit_Yel
	BCF	PORTB, bit_Red
	IORWF	PORTB, 1	; update PORTB with new LED display
	MOVLW	lmt_Blink
	MOVWF	tmr_Blink	; Reset count-down timer 

isr_10	; Allow time for someone to leave before clearing flg_Waitb.
	; All motion detector input is ignored until flg_Waitb is clear.
	BTFSS	tmr_Flg2, flg_Waitb	; Flag set?
	GOTO	isr_11			; no
	DECFSZ	tmr_Delay1, 1		; wait for another interrupt?
	GOTO	isr_11			; yes
	DECFSZ	tmr_Delay2, 1		; yet some more?
	GOTO	isr_11			; yes
	BCF	tmr_Flg2, flg_Waitb	; clear flag
	
isr_11	NOP ; not used

isr_12	; Power off the amplifier after the specified time.

	BTFSS	tmr_Flg2, flg_Amp_On	; Is amplifier on?
	GOTO	isr_13			; no
	DECFSZ	tmr_Amp_On1,1
	GOTO	isr_13
	DECFSZ	tmr_Amp_On2,1
	GOTO	isr_13
	BCF	tmr_Flg2, flg_Amp_On
	BSF	PORTA, bit_Amp_On	; turn off amplifier

isr_13	BCF	INTCON,T0IF
	BCF	INTCON,INTF
	SWAPF	Stat_sav,W
	MOVWF	STATUS		; restore status (and Bank used at time of interrupt)
	SWAPF	W_sav,F	
	SWAPF 	W_sav,W		; restore w without changing status
	RETFIE	


Beep	BSF	PORTB,4	
	MOVLW	0x80
	MOVWF	ExitDel2
Beep1	DECFSZ	ExitDel1
	GOTO 	Beep1
	DECFSZ	ExitDel2
	GOTO 	Beep1
	BCF	PORTB,4
	RETURN
	

;---------Main program - Setup
Main	CLRF	PORTA		; clear Port A
	MOVLW	0x07		; turn comparators off and enable
	MOVWF	CMCON		; pins for I/O functions
	CLRF	PORTB		; clear Port B
	BCF	STATUS, RP1
	BSF	STATUS,	RP0		; select bank 1
	MOVLW	b'00000111'		; RA0, RA1, RA2 = input
	MOVWF	TRISA ^ 0x080
	CLRF	TRISB ^ 0x080		; Port B - all output
	CLRWDT				; clear WDT and prescaler
	MOVLW	b'00000100'		; prescaler (1:32)
;	MOVLW	b'00000001' ; ----------- prescaler - for debugging only
	MOVWF	OPTION_REG ^ 0x080	; TMR0 interrupts = 6 microseconds apart
	BCF	STATUS, RP0	; bank 0
	CLRF	TMR0		; clear Timer0 register
	CALL	SetDis		; startup in disabled mode
	MOVLW	0xA0		; set GIE <7> and T0IE <5>
	MOVWF	INTCON		; enable Interrupts
	CLRF	mi_Flgs		; miscellaneous flags	
	BSF	mi_Flgs,flg_RAoff ; Set button released flag
	
;------------ Main program - Loop
Loop
	BTFSC	mi_Flgs, flg_Deboun	; debounce in progress?
	GOTO 	M_look 	 		; yes - skip RA0 input processing
	BTFSS 	tmr_Flg1, flg_Disarm	; disarm in progress?
	GOTO 	Check			; no - do normal RA0 input processing
	BTFSS 	PORTA,0 		; still in progress?
	GOTO 	Check1			; no - do normal RA0 input processing
	Call	Deboun			; Yes - debounce here to implement a 'sampling' effect
	GOTO	M_look			; skip RA0 input processing

Check	; Main Loop  -  Check for command input (commands entered via the momentary switch)
	BTFSC	PORTA,0			; check RA0  (command input)
	GOTO 	Input			; RA0 is high so go process it
Check1	BTFSC	mi_Flgs,flg_RAoff	; RA0 is low -  just released?
	GOTO	M_look			; No - it has been low
	CALL	Deboun			; Debounce  
	BSF	mi_Flgs,flg_RAoff	; Set "RA0 is low" flag
	BCF 	tmr_Flg1, flg_Disarm	; turn any off disarm-in-progress
	GOTO 	M_look

Input	; Main Loop  -  Process command input.
	BTFSS	mi_Flgs,flg_RAoff	; just turned on?
	GOTO	Input3			; no - this can happen only on 2nd click of a double-click
	CALL	Deboun			; Yes - so debounce it
	BCF	mi_Flgs,flg_RAoff	; Set "RA0 is high" flag
	BTFSS	Alarm_state,flg_Ena	; is alarm enabled?
	GOTO	Input1			; No
	INCF	cnt_Clicks,1		; ---
	MOVLW	0x03			; ---	number Clicks = 3 
	SUBWF	cnt_Clicks,0		; ---    while in enabled mode?
	BTFSS	STATUS,Z		; ---
	GOTO	Input4			; 
	MOVLW	b'00000010'		;
	XORWF	mi_Flgs,flg_Zone2	; reverse Zone2 enabled/disabled status
	CLRF	cnt_Clicks
	GOTO	Input4			; 	
Input1	BTFSS	tmr_Flg1, flg_Clk	; were we waiting for a double click?
	GOTO	Input2			; no
	CALL	Enable
	GOTO	M_look
Input2	MOVLW	lmt_Clk			; get double-click interval
	MOVWF	tmr_Clk
	BSF	tmr_Flg1, flg_Clk	; start the double click timer
Input3	BTFSC 	Alarm_state, flg_Dis	; is alarm already disabled?
	GOTO 	Loop			; yes, 
Input4	MOVLW	lmt_Disarm		; start 'disarm-in-progress'
	MOVWF	tmr_Disarm1
	BSF	tmr_Flg1, flg_Disarm	; start the disable command timer

M_look	; Main Loop  -  looks for input from the motion detectors.
	BTFSC 	Alarm_state, flg_Dis	; is alarm disabled?
	GOTO 	Loop			; yes - don't look for an intruder
	BTFSC	tmr_Flg2, flg_Waita	; giving someone time to enter & turn off alarm?
	GOTO	Loop			; 	
	BTFSC	tmr_Flg2, flg_Waitb	; giving someone time to enable & leave room?
	GOTO	Loop			; yes		
	BTFSC	tmr_Flg2, flg_Trig	; already processing a motion trigger?
	GOTO	Loop			; yes
	BTFSC 	tmr_Flg1, flg_Strobe 	; is strobe light on ?
	GOTO	Loop			; yes, let existing alarm complete
	BTFSC	mi_Flgs,flg_Zone2	; is zone-2 disabled?
	GOTO	M_Look1			; yes - check zone-1
	BTFSC	PORTA,bit_Z2		; zone-2 low? (normally low)
	GOTO	M_trig			; zone-2 detected		
M_Look1	BTFSS	PORTA,bit_Z1		; Zone-1 high?  (normally low)
	GOTO	Loop		
	

M_trig	CALL 	Alrm_go			; Zone 1 or 2 detected
	GOTO	Loop

;	Subroutines -	Logic in the Main Loop was simplified by moving code that performed a
;			well-defined function to a subroutine.  Sometimes that is the sole
; 			purpose of a subroutine, and, in fact does not shorten the program or
;			improve anything but readability.

Enable					;----Subroutine -  Enable/Reset the alarm
	
	CLRF	4Eh			;clear flag file 
	CLRF	cnt_Clicks		
	CLRF	tmr_Flg1
	CLRF	tmr_Flg2
	CLRF	PORTB			; clear Port B - stop all alarms
	BSF	PORTA, bit_Amp_On	; turn off amplifier

	MOVLW	0x00
	MOVWF	INTCON			;turn off interrupts

	MOVLW	30h			;number of beeps/flashes
	MOVWF	4Dh
Exit	BSF 	06,2			;turn on green LED
	BSF	06,4			;turn on beeper
	CALL	Del2			;short delay
	BCF	06,4			;turn off beeper
	CALL	Del1			;call long delay
	BCF	06,2	
	CALL	Del1
	
	BTFSS	4Eh,0
	GOTO 	Exit1
	BCF	4Eh,0			;reset the flag
	GOTO	Exit2	


Exit1	DECFSZ	4Dh,1
	GOTO 	Exit
Exit2	MOVLW	0x0A0
	MOVWF	INTCON			;turn on interrupts
	CLRF	tmr_Delay1		; set delay
	MOVLW	0x03			; wait another 2 seconds to enable	
	MOVWF	tmr_Delay2
	CLRF	Alarm_state		; 
	BSF 	Alarm_state, flg_Ena	; Set alarm to enabled mode
	BCF	tmr_Flg2,flg_Waita
	BSF	tmr_Flg2,flg_Waitb
	RETURN


Del1	MOVLW	0A0h			;long delay
	MOVWF	4Bh			;file to decrement
Del1A	NOP
	MOVLW	2Ch			;allow 3 beeps before button detected
	SUBWF	4Dh,0	
	BTFSC	03,0			;test carry flag. Will be set if more
	GOTO	Del1B
	BTFSC	05,0
	BSF	4E,0			;button has been detected- flag it
Del1B	DECFSZ	4C,1	
	GOTO 	Del1A
	DECFSZ	4B,1
	GOTO 	Del1A
	RETURN


Del2	MOVLW	20h			;short delay
	MOVWF	4Bh			;file to decrement
Del2A	NOP
	MOVLW	2Ch			;allow 3 beeps before button detected
	SUBWF	4Dh,0	
	BTFSC	03,0			;test carry flag. Will be set if more
	GOTO	Del2B
	BTFSC	05,0
	BSF	4E,0			;button has been detected- flag it
Del2B	DECFSZ	4C,1	
	GOTO 	Del2A
	DECFSZ	4B,1
	GOTO 	Del2A
	RETURN



;-----  Subroutine - Turn on Alarm - Set delay time and flags for isr routine.
Alrm_go	CALL	Beep
	BCF	PORTB, bit_Gre
	BCF	PORTB, bit_Red
	BCF	PORTB, bit_Yel
	BTFSS 	Alarm_state, flg_Ena	; previously triggered?
	GOTO	Alrm_r			; yes
	CLRF	Alarm_state
	BSF	Alarm_state, flg_Yellow
	BSF	PORTB, bit_Yel		; set LEDs to yellow alert
	GOTO 	Alrm_z
Alrm_r	CLRF	Alarm_state
	BSF	Alarm_state, flg_Red
	BSF	PORTB, bit_Red		; set LEDs to Red alert

Alrm_z	CLRF	4Eh			;clear flag file 

	MOVLW	0x00
	MOVWF	INTCON			;turn off interrupts

	MOVLW	30h			;48 beeps/flashes for entry
	MOVWF	4Dh
	BCF	06,1			;clear orange LED

Entry	BSF 	06,0			;turn on red LED
	BSF	06,4			;turn on beeper
	CALL	Del2			;short delay
	BCF	06,4			;turn off beeper
	CALL	Del2			;short delay
	BSF	06,4			;turn on beeper
	CALL	Del2			;short delay
	BCF	06,4			;turn off beeper
	CALL	Del1			;call long delay
	BCF	06,0	
	CALL	Del1	

	BTFSS	4Eh,0			;test button-detect flag 
	GOTO 	Entry1
	BCF	4Eh,0			;clear button-detect flag in delay routine
	GOTO	Entry2	
Entry1	DECFSZ	4Dh,1
	GOTO 	Entry
Entry2	MOVLW	0x0A0
	MOVWF	INTCON			;turn on interrupts
	MOVLW 	0x0FF			; Set delay time for two extra seconds
	MOVWF	tmr_Delay1		
	MOVLW	0x02
	MOVWF	tmr_Delay2	
	BCF	tmr_Flg2, flg_Waitb 	;clear exit delay flag
	BSF	tmr_Flg2, flg_Waita	; Set entry delay flag
	BCF	PORTA, bit_Amp_On	; turn on amp (Yes - turn it off to turn amp on)
	CLRF	tmr_Amp_On1		; Set 'Power-on' flag & timer	
	MOVLW	lmt_Amp_On2
	MOVWF	tmr_Amp_On2
	BSF	tmr_Flg2, flg_Amp_On
	RETURN

;--------Subroutine -   Go to Yellow Alert
SetYel	CLRF	tmr_Strobe1		; length of time strobe is to remain on
	MOVLW	lmt_Strobe2
	MOVWF	tmr_Strobe2
	BSF 	tmr_Flg1, flg_Strobe	; flag interrupt service routine (ISR) to handle
	BSF 	PORTB, bit_Strobe	; turn on strobe light.			

	MOVLW	0x01
	MOVWF	tmr_Siren		; time interval to turn Siren on
	MOVLW	0x015
	MOVWF	tbl_i			; set table index - defines 'wailing' intervals
	BSF	tmr_Flg1, flg_Siren	; TMR0 interrupts to handle siren
	
	MOVLW	0x040			; 'verbal warning' needs only a pulse to trigger it
	MOVWF	tmr_Verb1
	BSF	tmr_Flg1, flg_Verb	; tmr0 interrupts will handle verbal warning
	BSF	PORTB, bit_Verb		; start verbal warning (amp should be powered up)

	MOVLW	0x040			; 'barking dog' needs only a pulse to trigger it
	MOVWF	tmr_Dog1		;
	BSF	tmr_Flg1, flg_Dog	; set timer
	BSF	PORTB, bit_Dog		; start barking
	RETURN

;--------Subroutine - Go to Red Alert
SetRed	CLRF	tmr_Strobe1		; length of time strobe is to remain on
	MOVLW	lmt_Strobe2
	MOVWF	tmr_Strobe2
	BSF 	tmr_Flg1, flg_Strobe	; flag 'strobe' ISR handling
	BSF 	PORTB, bit_Strobe	; turn on strobe light.			

	MOVLW	6			; start with short pulse (Load Buzzer)
	MOVWF	tmr_Buzz1		; 
	MOVLW	19			; number of pulses to generate
	MOVWF	tmr_Buzz2		; count-down timer
	BSF 	tmr_Flg1, flg_Buzz 	; so tmr0 interrupts will handle buzzer
	BCF 	PORTB, bit_Buzz		; start with buzzer off
	
	MOVLW	0x040			; barking dog module needs 
	MOVWF	tmr_Dog1		; only need a pulse to start it
	BSF	tmr_Flg1, flg_Dog	; set timer
	BSF	PORTB, bit_Dog		; start barking (amp should be powered up by now)
	RETURN

;---------------- Subroutine - Set Alarm Disabled
SetDis	MOVLW	1
	MOVWF	Alarm_state		; set Alarm state to disabled
	CLRF	tmr_Flg1		; turn off anything that is on
	CLRF	tmr_Flg2		; turn off anything that is on
	CLRF	cnt_Clicks
	MOVLW	b'00000010'		; turn on ORANGE LED
	MOVWF	PORTB
	BSF	PORTA, bit_Amp_On	; turn off amplifier
	MOVLW	0x0FF
	MOVWF	tmr_Rearm1		
	MOVWF	tmr_Rearm2		; Set automatic re-arm alarm timer to 4 hours
	MOVLW	0x01A			; 9 minutes intervals per count here
	MOVWF	tmr_Rearm3
	RETURN	

;--------------- Subroutine - Turn on Debounce
Deboun	MOVLW	lmt_Deboun
	MOVWF	tmr_Deboun		; set Debounce interval
	BSF	mi_Flgs, flg_Deboun	; start the Debounce timer
	RETURN

	END
