; CPU configuration
; 	
	list P=16F84
	#include "p16f84.inc"
	__config _RC_OSC & _WDT_OFF & _PWRTE_ON

; Define variables at memory locations

; EEPROM DATA

EEPROM0		equ	H'00'	; non-volatile storage for code counter all codes

EEPROM1		equ	H'01'	; non-volatile storage for 1st digit of master code
EEPROM2		equ	H'02'	; non-volatile storage for 2nd digit of master code
EEPROM3		equ	H'03'	; non-volatile storage for 3rd digit of master code
EEPROM4		equ	H'04'	; non-volatile storage for 4th digit of master code
EEPROM5		equ	H'05'	; non-volatile storage for 5th digit of master code
EEPROM6		equ	H'06'	; non-volatile storage for 6th digit of master code
EEPROM7		equ	H'07'	; non-volatile storage for 7th digit of master code
EEPROM8		equ	H'08'	; non-volatile storage for 8th digit of master code
EEPROM9		equ	H'09'	; non-volatile storage for 9th digit of master code
EEPROM10	equ	H'0A'	; non-volatile storage for 10th digit of master code
EEPROM11	equ	H'0B'	; non-volatile storage for 11th digit of master code
EEPROM12	equ	H'0C'	; non-volatile storage for 12th digit of master code

EEPROM14	equ	H'0D'	; non-volatile storage for 1st digit of user code
EEPROM15	equ	H'0E'	; non-volatile storage for 2nd digit of user code
EEPROM16	equ	H'0F'	; non-volatile storage for 3rd digit of user code
EEPROM17	equ	H'10'	; non-volatile storage for 4th digit of user code
EEPROM18	equ	H'11'	; non-volatile storage for 5th digit of user code
EEPROM19	equ	H'12'	; non-volatile storage for 6th digit of user code
EEPROM20	equ	H'13'	; non-volatile storage for 7th digit of user code
EEPROM21	equ	H'14'	; non-volatile storage for 8th digit of user code
EEPROM22	equ	H'15'	; non-volatile storage for 9th digit of user code
EEPROM23	equ	H'16'	; non-volatile storage for 10th digit of user code
EEPROM24	equ	H'17'	; non-volatile storage for 11th digit of user code
EEPROM25	equ	H'18'	; non-volatile storage for 12th digit of user code

EEPROM26	equ	H'19'	; storage of instant input time
EEPROM27	equ	H'1A'	; storage of delayed input time
EEPROM28	equ	H'1B'	; storage of alarm output time
EEPROM29	equ	H'1C'	; storage of door lock open time
EEPROM30	equ	H'1D'	; not used
EEPROM31	equ	H'1E'	; storage of exit delay	
EEPROM32	equ	H'1F'	; alarm warning timer
EEPROM33	equ	H'20'	; keypad entry timeout

EEPROM34	equ	H'21'	; non-volatile storage for 1st digit of service code
EEPROM35	equ	H'22'	; non-volatile storage for 2nd digit of service code
EEPROM36	equ	H'23'	; non-volatile storage for 3rd digit of service code
EEPROM37	equ	H'24'	; non-volatile storage for 4th digit of service code
EEPROM38	equ	H'25'	; non-volatile storage for 5th digit of service code
EEPROM39	equ	H'26'	; non-volatile storage for 6th digit of service code
EEPROM40	equ	H'27'	; non-volatile storage for 7th digit of service code
EEPROM41	equ	H'28'	; non-volatile storage for 8th digit of service code
EEPROM42	equ	H'29'	; non-volatile storage for 9th digit of service code
EEPROM43	equ	H'2A'	; non-volatile storage for 10th digit of service code
EEPROM44	equ	H'2B'	; non-volatile storage for 11th digit of service code
EEPROM45	equ	H'2C'	; non-volatile storage for 12th digit of service code

EEPROM46	equ	H'2D'	; not used
EEPROM47	equ	H'2E'	; not used
EEPROM48	equ	H'2F'	; not used

EEPROM49	equ	H'30'	; bit 0=0 alarm mode (alternate arm/disarm on each keypad entry)
				; bit 0=1 keyless entry mode (armed on each keypad entry) 
				; bit 1=0 instant input normal
				; bit 1=1 egress switch on instant input
				; bit 2=0 door lock on armed only
				; bit 2=1 door lock on disarm only
				; bit 3=0 as per bit 2
				; bit 3=1 door lock on both arm and disarm 
				; bit 4=0 armed output on for armed
				; bit 4=1 armed output off for armed	
				
; RAM

STATUS_TMP 	equ 	H'0C'	; temp storage for status during interrupt
W_TMP		equ	H'10'	; temporary storage for w during interrupt
VALUE_1		equ 	H'11'	; key value storage			
VALUE_2		equ	H'12'	; value storage
	
TEMP_1		equ	H'17'	; temporary working storage
TEMP_2		equ	H'18'	; temp storage
TEMP_3		equ	H'19'	; temporary storage 
TIME_CNT1	equ	H'1A'	; counter for pulse count period
TIME_CNT2	equ	H'1B'	; counter for pulse count period
DEL_TMR		equ	H'1C'	; delayed input timer counter
INS_TMR		equ	H'1D'	; instant input timer counter
ALM_TMR		equ	H'1E'	; alarm out timer counter
DOOR_TMR	equ	H'1F'	; door lock timer
TMR_FLG		equ	H'20'	; timer flags, bit0 delay, bit1 alarm, bit2 door, bit3 tone	
				; bit4 LED flasher, bit5 delay timed out flag, bit6 alarm on
INS_FLG		equ	H'21'	; timer flags bit0 instant delay, bit 1 instant timed out, 
				; bit2 exit delay
INPUT_ST	equ	H'22'	; entry input level store
EX_DLY		equ	H'23'	; exit delay timer

KEY_NTR		equ	H'24'	; key entering counter
KEY_FLG		equ	H'25'	; key flags; 0 started, 1 no match master code, 2 no match user, 
				; 3 timer expired, 4 no match service, 5 entry complete
				; 6 flasher LED fully lit, 7 no match duress
KEY_TME		equ	H'26'	; keypad entry timer
KEY_STO		equ	H'27'	; keypad number store
WARN_TM		equ	H'28'	; warning timer
TAMPER		equ	H'29'	; tamper counter
TAMP_T		equ	H'2A'	; tamper timer			

H_BYTE		equ	H'2B'	; high byte
L_BYTE		equ	H'2C'	; low byte
REG_0		equ	H'2D'	; MSD of 5-digit BCD in right hand (low) nibble
REG_1		equ	H'2E'	; BCD number (packed BCD)
REG_2		equ	H'2F'	; BCD low order numbers
H_TEMP		equ	H'30'	; temporary register of high order binary result
L_TEMP		equ	H'31'	; temporary register of low order binary result	

CODE_FG		equ	H'32'	; service code entry flags
TIM_FG		equ	H'33'	; service entry timer flags
OP_FG		equ	H'34'	; service entry option flag
ALT_FG		equ	H'35'	; service entry alter flag
KEY_NT		equ	H'36'	; key entering counter during service
CLSD_TM		equ	H'37'	; time switch can be closed before rechecking switches again
	
; preprogram EEPROM DATA
	
	ORG     2100			; start of master code section
	DE	0x03			; preset code counter to 4 (4-number code)
	DE	0x01, 0x00, 0x00, 0x00	; set master code 1,0,0,0
	DE	0x00, 0x00, 0x00, 0x00	; set master code 0,0,0,0
	DE	0x00, 0x00, 0x00, 0x00	; set master code 0,0,0,0					; 
	
	ORG	210D			; start of user code section
	DE	0x02, 0x00, 0x00, 0x00	; code 2,0,0,0 (4-number code)
	DE	0x00, 0x00, 0x00, 0x00	; set user code 0,0,0,0
	DE	0x00, 0x00, 0x00, 0x00	; set user code 0,0,0,0

	ORG	2119		        ; start of variables 
	DE	D'01', D'10'		; instant & delayed input
	DE      D'60', D'05' 		; alarm out & door open time
	DE	D'00', D'15'	        ; not used, exit delay
	DE      0x05, 0x05     	 	; alarm warning, keypad entry timeout

	ORG	2121			; start of service codes
	DE	0x03, 0x00, 0x00, 0x00	; service code 3,0,0,0
	DE	0x00, 0x00, 0x00, 0x00	; set service code 0,0,0,0
	DE	0x00, 0x00, 0x00, 0x00	; set service code 0,0,0,0

	ORG	212D			; start of duress codes
	DE	0x00, 0x00, 0x00	; coded for 000
	DE	0x00			; alarm mode, instant input

; define reset and interrupt vector start addresses

	org	0	  	; start at address 0000h
	goto	MAIN		; normal service routines from Reset vector
	org     4		; interrupt vector 0004h, start interrupt routine here
	goto	INTRUPT		; interrupt

; **********************************************************************************************
; lookup table for switches includes error code if more than one switch pressed.

SW_TBL1	addwf	PCL,f		; add value to program counter
	retlw	0xFF		; error code for switch read 0000 '4-switches pressed'
	retlw	0xFF		; error code for switch read 0001 '3-switches pressed'
	retlw	0xFF		; error code for switch read 0010 '3-switches pressed'	
	retlw	0xFF		; error code for switch read 0011 '2-switches pressed'	
	retlw	0xFF		; error code for switch read 0100 '3-switches pressed'
	retlw	0xFF		; error code for switch read 0101 '2-switches pressed'	
	retlw	0xFF		; error code for switch read 0110 '2-switches pressed'	
	retlw	0x03		; code for switch read       0111 '3'
	retlw	0xFF		; error code for switch read 1000 '3-switches pressed' 
	retlw	0xFF		; error code for switch read 1001 '2-switches pressed'
	retlw	0xFF		; error code for switch read 1010 '2-switches pressed'
	retlw	0x06		; code for switch read       1011 '6'
	retlw	0xFF		; error code for switch read 1100 '2-switches pressed'	
	retlw	0x09		; code for switch read       1101 '9'
	retlw	0x0B		; code for switch read 	     1110 '#'
	retlw	0xF0		; code for switch read       1111 'no switch pressed in column'

SW_TBL2	addwf	PCL,f		; add value to program counter
	retlw	0xFF		; error code for switch read 0000
	retlw	0xFF		; error code for switch read 0001
	retlw	0xFF		; error code for switch read 0010
	retlw	0xFF		; error code for switch read 0011
	retlw	0xFF		; error code for switch read 0100
	retlw	0xFF		; error code for switch read 0101
	retlw	0xFF		; error code for switch read 0110
	retlw	0x01		; code for switch read       0111 '1'
	retlw	0xFF		; error code for switch read 1000
	retlw	0xFF		; error code for switch read 1001
	retlw	0xFF		; error code for switch read 1010
	retlw	0x04		; code for switch read       1011 '4'
	retlw	0xFF		; error code for switch read 1100
	retlw	0x07		; code for switch read       1101 '7'
	retlw	0x0A		; code for switch read       1110 '*'
	retlw	0xF0		; code for switch read       1111 'no switch pressed in column'

SW_TBL3	addwf	PCL,f		; add value to program counter
	retlw	0xFF		; error code for switch read 0000
	retlw	0xFF		; error code for switch read 0001
	retlw	0xFF		; error code for switch read 0010
	retlw	0xFF		; error code for switch read 0011
	retlw	0xFF		; error code for switch read 0100
	retlw	0xFF		; error code for switch read 0101
	retlw	0xFF		; error code for switch read 0110
	retlw	0x02		; code for switch read       0111 '2'
	retlw	0xFF		; error code for switch read 1000
	retlw	0xFF		; error code for switch read 1001
	retlw	0xFF		; error code for switch read 1010
	retlw	0x05		; code for switch read       1011 '5'
	retlw	0xFF		; error code for switch read 1100
	retlw	0x08		; code for switch read       1101 '8'
	retlw	0x00		; code for switch read       1110 '0'
	retlw	0xF0		; code for switch read 	     1111 'no switch pressed'

; **********************************************************************************************

; start interrupt by saving w and status registers before altered by interrupt routine

INTRUPT	movwf	W_TMP		; w to w_tmp storage
	swapf	STATUS,w	; status to w
	movwf	STATUS_TMP	; status in status_tmp  
	bcf	STATUS,RP0	; select memory bank 0
	bcf	INTCON,T0IF	; TMR0 flag clear

; timer for delays

	movf	TMR0,w		; timer value	
	addlw	D'60'		; add to timer register 
	movwf	TMR0		; place in timer 
	
	incfsz	TIME_CNT1,f	; increase counter
	goto	BY_INC
	incf	TIME_CNT2,f	; increase ms counter
	
BY_INC	movf	TIME_CNT2,w	
	xorlw	0x08		; set for ~ 1 second
	btfss	STATUS,z	; if 8 then clear
	goto	TON_DRV		; check tone drive
	clrf	TIME_CNT1
	clrf	TIME_CNT2
	
	movf	CLSD_TM,w
	btfsc	STATUS,z
	goto	TIM_DEC
	decf	CLSD_TM,f	; closed switch monitor duration
		
TIM_DEC	movf	ALM_TMR,w
	btfsc	STATUS,z
	goto	DEL_DEC
	decfsz	ALM_TMR,f	; alarm out timer
	goto	DEL_DEC
	bcf	TMR_FLG,1	; alarm timeout flag
DEL_DEC	movf	DEL_TMR,w
	btfsc	STATUS,z
	goto	INS_DEC
	decfsz	DEL_TMR,f	; delayed input timer
	goto	INS_DEC
	bcf	TMR_FLG,5	; delayed input timeout flag
INS_DEC	movf	INS_TMR,w
	btfsc	STATUS,z
	goto	EX_DEC
	decfsz	INS_TMR,f	; instant input timer
	goto	EX_DEC
	bcf	INS_FLG,1	; instant input timeout flag
EX_DEC	btfss	INS_FLG,2	; bypass if clear
	goto	DOR_DEC
	movf	EX_DLY,w
	btfsc	STATUS,z
	goto	DOR_DEC
	decfsz	EX_DLY,f	; exit delay timer
	goto	DOR_DEC
	bcf	INS_FLG,2	; exit delay timeout flag
TST_REC	movf	PORTB,w		; load portB
	andlw	B'00000011'	; get input levels
	movwf	INPUT_ST	; store
	call	DELTME		; delay to reduce glitch detection
	movf	PORTB,w		; check again
	andlw	B'00000011'
	xorwf	INPUT_ST,w	; are they the same
	btfss	STATUS,z	
	goto	TST_REC		; wait till inputs settle
DOR_DEC	movf	DOOR_TMR,w
	btfsc	STATUS,z
	goto	KEY_DEC
	decfsz	DOOR_TMR,f	; door lock timer
	goto	KEY_DEC		; 
	bcf	TMR_FLG,2	; door lock timer flag
	bcf	PORTA,0	
	
KEY_DEC	movf	KEY_TME,w
	btfsc	STATUS,z
	goto	ALM_DEC		; bypass if zero
	decfsz	KEY_TME,f	; keypad entry timer
	goto	ALM_DEC
	btfsc	KEY_FLG,6	; is service mode entered
	goto	TON_DRV
	clrf	KEY_FLG		; flags cleared
	clrf	KEY_NTR		; key entry counter

ALM_DEC	movf	ALM_TMR,w
	btfsc	STATUS,z
	goto	ALM_WNG
	decfsz	ALM_TMR,f	; alarm output timer
	goto	ALM_WNG
	bcf	TMR_FLG,1	; timed out
	bcf	PORTA,3		; alarm output low
	bcf	TMR_FLG,6	; alarm off
	bcf	TMR_FLG,3	; tone off
	bcf	TMR_FLG,0	; delay timer flag
	bcf	TMR_FLG,5	; delay timed out flag
	bcf	INS_FLG,0	; instant timer flag	
	bcf	INS_FLG,1	; instant timed out flag
TST_MR	movf	PORTB,w		; load portB
	andlw	B'00000011'	; get input levels
	movwf	INPUT_ST	; store
	call	DELTME		; delay to reduce glitch detection
	movf	PORTB,w		; check again
	andlw	B'00000011'
	xorwf	INPUT_ST,w	; are they the same
	btfss	STATUS,z	
	goto	TST_MR		; wait till inputs settle

ALM_WNG	movf	WARN_TM,w	; alarm warning timer
	btfsc	STATUS,z
	goto	TAMPR		; bypass if zero
	decfsz	WARN_TM,f	; warning alarm timer
	goto	TAMPR
	bsf	PORTA,3		; alarm on after warning time
	bcf	TMR_FLG,3	; tone off

TAMPR	movf	TAMP_T,w	; tamper timer
	btfsc	STATUS,z
	goto	TON_DRV
	decfsz	TAMP_T,f
	goto	TON_DRV
	clrf	TAMPER		; tamper counter
	
; piezo tone driver

TON_DRV	btfss	TMR_FLG,3	; is tone flag set
	goto	NO_TONE		; no tone required
	btfss	TIME_CNT1,1	; check bit of time counter
	goto	NO_TONE
	bsf	PORTA,2		; drive piezo
	goto	FLASH		; LED flasher
NO_TONE	bcf	PORTA,2		; piezo off

; LED flasher

FLASH	btfss	KEY_FLG,6	; if set then light fully
	goto	FLS_LED
	bcf	PORTA,4
	goto	RECLAIM
FLS_LED	btfss	TMR_FLG,4	; LED flasher flag
	goto	NO_FLSH
	btfsc	INS_FLG,2	; is exit delay in process
	goto	FAST_FL		; fast flash
	btfss	TIME_CNT2,1	; check bit in counter
	goto	NO_FLSH
	bcf	PORTA,4		; drive LED
	goto	RECLAIM
NO_FLSH bsf	PORTA,4		; LED off
 	goto	RECLAIM
FAST_FL	btfss	TIME_CNT2,0	; check bit in counter
	goto	NO_FLSH
	bcf	PORTA,4		; LED on
	
; end of interrupt reclaim w and status 

RECLAIM	swapf	STATUS_TMP,w	; status temp storage to w
	movwf	STATUS		; w to status register
	swapf	W_TMP,f		; swap upper and lower 4-bits in w_tmp
	swapf   W_TMP,w		; swap bits and into w register
	retfie			; return from interrupt

; ************************************************************************

; RESET		
; Set ports A & B

MAIN	clrf	TIME_CNT1	; clear time period counter
	clrf	TIME_CNT2	; counter for time period
	clrf	DEL_TMR		; delayed input timer counter
	clrf	INS_TMR		; instant input timer counter
	clrf	ALM_TMR		; alarm out timer counter
	clrf	DOOR_TMR	; door lock timer
	clrf	TMR_FLG		; timer flags
	clrf	INS_FLG		; flags;instant delay,instant timed out,exit delay
	clrf	INPUT_ST	; entry input level store
	clrf	EX_DLY		; exit delay timer
	clrf	KEY_NTR		; key entering counter
	clrf	KEY_FLG		; key flags
	clrf	KEY_TME		; keypad entry timer
	clrf	KEY_STO		; keypad number store
	clrf	WARN_TM		; warning timer
	clrf	TAMPER		; tamper counter
	clrf	TAMP_T		; tamper timer			
	clrf	KEY_NTR		; key entry counter
	bsf	STATUS,RP0	; select memory bank 1
	movlw	B'11110011'	; (RB0,1, 4-7 inputs input, RB2,3 outputs)
	movwf	TRISB		; port B data direction register
	movlw	B'00000000'	; 
	movwf	OPTION_REG	; TMRO prescaler no division, PORTB pullups enabled
	movlw   B'00000000'	; (RA0-RA4 outputs)
	movwf   TRISA		; A port data direction register
	bcf	STATUS,RP0	; select memory bank 0
	movlw	B'11111111'	; 1's 
	movwf	PORTB		; portB outputs high
	clrf	PORTA		; portA low

; check if default values required (must have 3,6,9 and # pressed on keypad
; and instant and delayed inputs low (RB0 and RB1) at power on)
	
	movf	PORTB,w		; check portB inputs
	andlw	0xF3		; only high bits and RB0 and RB1
	xorlw	0x00		; check if switches pressed and RB0 and RB1 low
	btfss	STATUS,z
	goto	INIT		; not default required

; load defaults
	
	clrf	VALUE_1		; counter
	movlw	EEPROM1		; initial EEPROM location
	movwf	EEADR
CL_AGN	movlw	0x00		; clear all EEPROM locations then add in values
	call	EWRITE
	incf	EEADR,f
	incf	VALUE_1,f	; next
	movf	VALUE_1,w
	xorlw	D'50'		; cleared all yet
	btfss	STATUS,z
	goto	CL_AGN		
	movlw	EEPROM0		; code counter
	movwf	EEADR
	movlw	0x03		; 4-codes
	call	EWRITE
	movlw	EEPROM1		; master code
	movwf	EEADR
	movlw	0x01		; 1
	call	EWRITE
	movlw	EEPROM14	; user code
	movwf	EEADR
	movlw	0x02		; 2
	call	EWRITE
	movlw	EEPROM34	; service code
	movwf	EEADR
	movlw	0x03		; 3
	call	EWRITE
	movlw	EEPROM26	; instant input
	movwf	EEADR
	movlw	D'01'		; 1s 
	call	EWRITE
	incf	EEADR,f		; delayed input
	movlw	D'10'		; 10s 
	call	EWRITE
	incf	EEADR,f		; alarm output time
	movlw	D'60'		; 60s 
	call	EWRITE
	incf	EEADR,f		; door lock open time
	movlw	D'05'		; 5s 
	call	EWRITE
	incf	EEADR,f		; not used so next EEPROM
	incf	EEADR,f		; exit delay
	movlw	D'15'		; 15s 
	call	EWRITE
	incf	EEADR,f		; alarm warning delay
	movlw	D'05'		; 5s 
	call	EWRITE
	incf	EEADR,f		; keypad entry timeout
	movlw	D'05'		; 5s
	call	EWRITE
HAL_T	nop
	goto	HAL_T		; halt and wait here till reset 

; initial armed mode

INIT	bsf	TMR_FLG,4	; flasher
	movlw	EEPROM49	; alarm/keypad entry mode, instant/egress input
	call	EEREAD		; 
	movwf	TEMP_1
	btfsc	TEMP_1,4	; if bit 4 set then armed output off
	goto	CLR_ON
	bsf	PORTA,1		; armed output on
	goto	LED_ON
CLR_ON	bcf	PORTA,1
LED_ON	bsf	PORTA,4		; LED flasher output high

; initial check instant and delayed input

TST_AGN	movf	PORTB,w		; load portB
	andlw	B'00000011'	; get input levels
	movwf	INPUT_ST	; store
	call	DELTME		; delay to reduce glitch detection
	movf	PORTB,w		; check again
	andlw	B'00000011'
	xorwf	INPUT_ST,w	; are they the same
	btfss	STATUS,z	
	goto	TST_AGN		; wait till inputs settle

; interrupts are go

	bsf	INTCON,T0IE	; timer overflow interrupt
	bsf	INTCON,GIE	; allow global interrupts
	
; check if armed and if so are the delayed or instant inputs triggered.

CYCLE	btfsc	KEY_FLG,6	; is service mode selected
	goto	KY_PAD

; check egress input

CK_EG	movlw	EEPROM49	; alarm/keypad entry mode, instant/egress input
	call	EEREAD		; get current master code
	movwf	TEMP_1
	btfss	TEMP_1,1	; if bit 1 set egress mode
	goto	CK_IN
	btfsc	PORTB,1		; check instant input
	goto	CK_IN
	call	DELTME		; delay
	btfss	PORTB,1		; check instant input
	goto	ARM		; arm on egress
	
; check inputs only when armed

CK_IN	btfss	TMR_FLG,4	; flasher flag (also armed flag)
	goto	KY_PAD		; not armed check switches on keypad

; check exit delay

	btfsc	INS_FLG,2	; if set bypass
	goto	KY_PAD
	
; wait for instant input time
	
	btfsc	TEMP_1,1	; if set then check delayed input
	goto	DEL_IN		; bypass instant input as it is set as an egress input
INS_AGN	movf	PORTB,w		; load portB
	andlw	B'00000010'	; get instant input
	movwf	TEMP_1		; store
	call	DELTME		; delay to reduce glitch detection
	movf	PORTB,w		; check again
	andlw	B'00000010'
	xorwf	TEMP_1,w	; are they the same
	btfss	STATUS,z	
	goto	INS_AGN		; wait till inputs settle

; compare with last input measurement

	movf	INPUT_ST,w
	andlw	B'00000010'	; get previous instant value
	xorwf	TEMP_1,w
	btfsc	STATUS,z	; if zero then the same as last time
	goto	INS_CK
	btfsc	INS_FLG,0	; if set already
	goto	INS_CK

; set instant input flags and timer

	movlw	EEPROM26	; instant input time
	call	EEREAD		; get value from EEPROM	
	movwf	INS_TMR		; set instant input delay timer
	movf	INS_TMR,w
	btfsc	STATUS,z	; if zero increase by one so timer will reset in interrupt
	incf	INS_TMR,f
	bsf	INS_FLG,0	; set instant input timer flag	
	bsf	INS_FLG,1	; instant delay timed out flag
	goto	DEL_IN

INS_CK	btfss	INS_FLG,0	; is instant input timer flag set
	goto	DEL_IN
	btfss	INS_FLG,1	; is instant input timed out flag set
	goto	ALARM

; wait for delayed input time

DEL_IN	movf	PORTB,w		; load portB
	andlw	B'00000001'	; get delayed input
	movwf	TEMP_1		; store
	call	DELTME		; delay to reduce glitch detection
	movf	PORTB,w		; check again
	andlw	B'00000001'
	xorwf	TEMP_1,w	; are they the same
	btfss	STATUS,z	
	goto	DEL_IN		; wait till inputs settle

; compare with last measurement

	movf	INPUT_ST,w
	andlw	B'00000001'	; get previous delayed value
	xorwf	TEMP_1,w
	btfsc	STATUS,z	; if zero then the same as last time
	goto	DEL_Y		; check if timer set for delayed input
	btfsc	TMR_FLG,0	; is delayed input flag set
	goto	DEL_Y
	
; set delay input flags and timer

	movlw	EEPROM27	; delayed input time
	call	EEREAD		; get value from EEPROM 	
	movwf	DEL_TMR		; set input delay timer
	movf	DEL_TMR,w
	btfsc	STATUS,z	; if zero increase by one so timer will reset in interrupt
	incf	DEL_TMR,f
	bsf	TMR_FLG,0	; set delayed input timer flag
	bsf	TMR_FLG,5	; delay timed out flag
	goto	KY_PAD
	
DEL_Y	btfss	TMR_FLG,0	; is delayed input timer flag set
	goto	KY_PAD
	btfss	TMR_FLG,5	; is delayed input timed out flag set
	goto	ALARM
	goto	KY_PAD	
	
; alarm output 

ALARM	btfsc	TMR_FLG,6	; is alarm on
	goto	KY_PAD
	movlw	EEPROM28	; alarm output time
	call	EEREAD		; read value
	movwf	ALM_TMR		; set alarm timer
	movf	ALM_TMR,w
	btfsc	STATUS,z	; if zero increase by one so timer will reset in interrupt
	incf	ALM_TMR,f
	bsf	TMR_FLG,1	; alarm timer flag cleared after timer duration
	bsf	TMR_FLG,6	; alarm on flag  	
	bsf	TMR_FLG,3	; alarm tone		
	movlw	EEPROM32
	call	EEREAD
	movwf	WARN_TM
	movf	WARN_TM,w
	btfsc	STATUS,z	; if zero increase by one so timer will reset in interrupt
	incf	WARN_TM,f	

KY_PAD	bsf	PORTB,2		; RB2 high
	bsf	PORTB,3		; RB3 high
	movlw	D'05'		; delay time
	call	DELT_1		; time for high before reading
	movf	PORTB,w		; look at RB7-RB4
	andlw	B'11110000'	; mask out RB3-RB0
	movwf	TEMP_2		; temporary store
	swapf	TEMP_2,w	; swap upper and lower nibbles
	call	SW_TBL1		; switch table
	movwf	TEMP_1
	xorlw	0xFF		; check if error 
	btfsc	STATUS,z
	goto	ERR
	movf	TEMP_1,w	; check if no switch
	xorlw	0xF0		; no switch pressed
	btfss	STATUS,z
	goto	NEW_SW		; new switch pressed
	
	bcf	PORTB,2		; check next column
	movlw	D'05'		; delay time
	call	DELT_1		; time for column to go low
	movf	PORTB,w		; look at RB7-RB4
	andlw	B'11110000'	; mask out RB3-RB0
	movwf	TEMP_2		; temporary store

; check if switch closed if RB2 high if so wrong switch detected
	
	bsf	PORTB,2		; column high
	movlw	D'05'		; delay time
	call	DELT_1		; time for column to go high
	movf	PORTB,w
	andlw	0xF0		; check RB7-RB4
	xorlw	0xF0		; if F0 then all switches open
	btfss	STATUS,z	
	goto	KY_PAD		; not correct switch so check again

; switch correct so continue

	bcf	PORTB,2		; check next column
	swapf	TEMP_2,w	; swap upper and lower nibbles
	call	SW_TBL2		; switch table
	movwf	TEMP_1
	xorlw	0xFF		; check if error 
	btfsc	STATUS,z
	goto	ERR
	movf	TEMP_1,w	; check if no switch
	xorlw	0xF0		; no switch pressed
	btfss	STATUS,z
	goto	NEW_SW		; new switch pressed
	
	bsf	PORTB,2
	bcf	PORTB,3		; third column low
	movlw	D'05'		; delay time
	call	DELT_1		; 
	movf	PORTB,w		; look at RB7-RB4
	andlw	B'11110000'	; mask out RB3-RB0
	movwf	TEMP_2		; temporary store

; check if switch closed if RB3 high if so wrong switch detected
	
	bsf	PORTB,3		; column high
	movlw	D'05'		; delay time
	call	DELT_1		; time for column to go high
	movf	PORTB,w
	andlw	0xF0		; check RB7-RB4
	xorlw	0xF0		; if F0 then all switches open
	btfss	STATUS,z	
	goto	KY_PAD		; not correct switch so check again

; switch correct so continue

	bcf	PORTB,3		; check next column
	swapf	TEMP_2,w	; swap upper and lower nibbles
	call	SW_TBL3		; switch table
	movwf	TEMP_1
	xorlw	0xFF		; check if error 
	btfsc	STATUS,z
	goto	ERR
	movf	TEMP_1,w	; check if no switch
	xorlw	0xF0		; no switch pressed
	btfsc	STATUS,z
	goto	CYCLE		;  

NEW_SW	bsf	TMR_FLG,3	; tone flag drive tone for short time
	movlw	D'50'		; delay time
	call	DELT_1		; delay for switch debounce and tone duration
	bcf	TMR_FLG,3	; tone off
	
; check if first key of code is entered
	
	btfsc	KEY_FLG,6	; is service mode entered
	goto	SVCE_MD
	btfsc	KEY_FLG,0	; started flag
	goto	CODE_X
	movlw	EEPROM33	; keypad entry timeout
	call	EEREAD		; get value
	movwf	KEY_TME		; keypad entry timer
	movf	KEY_TME,w
	btfsc	STATUS,z	; if zero increase by one so timer will reset in interrupt
	incf	KEY_TME,f
	clrf	KEY_FLG
	bsf	KEY_FLG,0	; set started flag
	bsf	KEY_FLG,3	; timer expiry flag
	clrf	KEY_NTR		; clear entering counter

; check if tamper timer started
	
	movf	TAMP_T,f	; look at value
	btfss	STATUS,z	; if zero then load
	goto	CODE_X
	movlw	D'90'		; 90 seconds (change for different tamper time)
	movwf	TAMP_T
	clrf	TAMPER		; set counter to zero
 
; do comparison with codes

CODE_X	movf	TEMP_1,w	; entered code
	xorlw	0x0B		; # key reset code entry
	btfss	STATUS,z
	goto	CK_MST		; check master
	clrf	KEY_FLG		; clear key entry flags
	goto	CK_OP		; wait for switch to open

CK_MST	movlw	EEPROM1		; master code
	addwf	KEY_NTR,w	; get current code position
	call	EEREAD		; get current master code
	xorwf	TEMP_1,w	; compare entered code with stored
	btfss	STATUS,z	; if zero then the same
	bsf	KEY_FLG,1	; set no master match flag

	movlw	EEPROM14	; user code
	addwf	KEY_NTR,w	; to address of current code
	call	EEREAD		; get user code value
	xorwf	TEMP_1,w	; compare codes
	btfss	STATUS,z
	bsf	KEY_FLG,2	; set no user code match

	movlw	EEPROM34	; service code
	addwf	KEY_NTR,w	; to address of current code
	call	EEREAD		; get user code value
	xorwf	TEMP_1,w	; compare codes
	btfss	STATUS,z
	bsf	KEY_FLG,4	; set no service code match

	movlw	EEPROM23	; start of duress code (last 3 digits of 12-digit user code)
	addwf	KEY_NTR,w	; add to address
	call	EEREAD
	xorwf	TEMP_1,w	; compare codes
	btfss	STATUS,z	
	bsf	KEY_FLG,7	; set no duress match	

; check if reached code counter value

	movlw	EEPROM0		; code entry (counter)
	call	EEREAD		; get code counter value
	xorwf	KEY_NTR,w	; counter of key entry
	btfsc	STATUS,z	; if z is 1 then equal
	bsf	KEY_FLG,5	; set counter equal flag
	
; next key
	
NXT_KY	incf	KEY_NTR,f	; next code key
	
; wait for switch to open

CK_OP	movlw	0x02
	movwf	CLSD_TM		; check switches for 2 seconds max
CL_OP	movf	CLSD_TM,w	; look at timer
	btfsc	STATUS,z
	goto	DR_SS		; continue if timeout to duress entry check
	movf	PORTB,w		; look at switches
	andlw	0xF0		; check RB7-RB4
	xorlw	0xF0		; if F0 then all switches open
	btfss	STATUS,z	
	goto	CL_OP		; switch still closed
	bcf	TMR_FLG,3	; tone off
	movlw	D'05'		; delay time
	call	DELT_1		; delay for switch debounce
	movf	PORTB,w		; look at switches
	andlw	0xF0		; check RB7-RB4
	xorlw	0xF0		; if F0 then all switches open
	btfss	STATUS,z	; continue if switches open	
	goto	CL_OP		; switch still closed

; check if duress (three 0's entered)
	
DR_SS	movf	KEY_NTR,w	; key entry counter
	xorlw	0x03		; three entries
	btfss	STATUS,z	
	goto	CK_ES		; not three entries so bypass
	btfsc	KEY_FLG,7	; if set not equal 
	goto	CK_ES
	clrf	KEY_FLG
	goto	SND_ALM
	
; check if counter entry flag is set and if codes correct
	
CK_ES	btfss	KEY_FLG,5	; entry complete flag
	goto	CYCLE

	btfss	KEY_FLG,1	; if clear then correct master code
	goto	MASTER
	btfss	KEY_FLG,2	; if clear then correct user code
	goto	USER
	btfss	KEY_FLG,4	; if clear then correct service code
	goto	SERVCE
	clrf	KEY_FLG		; flags cleared

; check if number of incorrect codes entered within timer period is 4
	
	incf	TAMPER,f	; next tamper value 
	movf	TAMPER,w
	sublw	0x04		; compare with 4 (change for more tampering entering value)
	btfss	STATUS,c	; 
	goto	SND_ALM
	goto	CYCLE

; wait for switch off

CLOSD	movlw	0x02
	movwf	CLSD_TM		; check switches for 2 seconds max
CLO_D	movf	CLSD_TM,w	; look at timer
	btfsc	STATUS,z
	return			; return after timeout
	movf	PORTB,w		; look at switches
	andlw	0xF0		; check RB7-RB4
	xorlw	0xF0		; if F0 then all switches open
	btfss	STATUS,z	
	goto	CLO_D		; switch still closed
	bcf	TMR_FLG,3	; tone off
	movlw	D'50'		; delay time
	call	DELT_1		; delay for switch debounce
	movf	PORTB,w		; look at switches
	andlw	0xF0		; check RB7-RB4
	xorlw	0xF0		; if F0 then all switches open
	btfss	STATUS,z	
	goto	CLO_D		; switch still closed
	return			; return if open

; error wait for key to open

ERR	goto	CK_OP		

; sound alarm on duress entry or tamper action
	
SND_ALM	clrf	TAMPER		; tamper counter
	clrf	TAMP_T		; tamper timer
	clrf	KEY_FLG
	clrf	KEY_NTR		; clear entering counter
	btfsc	TMR_FLG,6	; is alarm on
	goto	CYCLE
	movlw	EEPROM28	; alarm output time
	call	EEREAD		; read value
	movwf	ALM_TMR		; set alarm timer
	movf	ALM_TMR,w
	btfsc	STATUS,z	; if zero increase by one so timer will reset in interrupt
	incf	ALM_TMR,f
	movlw	0x01
	movwf	WARN_TM		; warning duration, cleared on next seconds interrupt
	bsf	TMR_FLG,1	; alarm timer flag cleared after timer duration
	bsf	TMR_FLG,6	; alarm on flag  	
	bsf	TMR_FLG,3	; alarm tone
	bsf	PORTA,3		; alarm on 
	bsf	TMR_FLG,4	; flasher flag

; check armed output
	
	movlw	EEPROM49	; alarm/keypad entry mode, instant/egress input
	call	EEREAD		; 
	movwf	TEMP_1
	btfsc	TEMP_1,4	; if bit 4 set then armed output off
	goto	RET_RN
	bsf	PORTA,1		; armed output on
	goto	CYCLE
RET_RN	bcf	PORTA,1
	goto	CYCLE

; master/user code entered
	
MASTER
USER	clrf	TAMPER		; tamper counter
	clrf	TAMP_T		; tamper timer
	clrf	KEY_FLG		; key flags
	clrf	KEY_TME		; key entry timer
	clrf	WARN_TM		; alarm warning timer
	bcf	PORTA,0		; door striker off

; check if alarm or keypad entry mode

	movlw	EEPROM49	; options alarm/keypad entry mode, instant/egress input etc
	call	EEREAD		; 
	movwf	TEMP_1
	btfsc	TEMP_1,0	; if zero then alarm mode
	goto	ARM
	btfss	TMR_FLG,4	; check if armed or unarmed
	goto	ARM
	clrf	TMR_FLG		; all flags off
	btfsc	TEMP_1,4	; if bit 4 set then armed output on
	goto	ONE_SET
	bcf	PORTA,1		; armed output off
	goto	ALM_OF
ONE_SET	bsf	PORTA,1
ALM_OF	bcf	PORTA,3		; alarm off

; check for door lock options
	
	btfsc	TEMP_1,3	; check if door lock on both arm/disarm
	goto	D_LOK		; door lock
	btfsc	TEMP_1,2	; door lock required on disarm
	goto	D_LOK
	bcf	PORTA,0		; door striker off
	goto	CYCLE

ARM	clrf	TMR_FLG		; all flags off
	clrf	INS_FLG
	bsf	TMR_FLG,4	; flasher flag
	btfsc	TEMP_1,4	; if bit 4 set then armed output off
	goto	ONE_CLR
	bsf	PORTA,1		; armed output on
	goto	ALM_ON
ONE_CLR	bcf	PORTA,1
ALM_ON	bcf	PORTA,3		; alarm off
	
; set exit delay
	
S_DLY	movlw	EEPROM31	; exit delay
	call	EEREAD
	movwf	EX_DLY
	movf	EX_DLY,w
	btfsc	STATUS,z	; if zero increase by one so timer will reset in interrupt
	incf	EX_DLY,f
	bsf	INS_FLG,2	; exit delay flag
		
; check for door lock options

	btfsc	TEMP_1,3	; check if door lock on both arm/disarm
	goto	D_LOK		; door lock
	btfsc	TEMP_1,2	; door lock required on arm
	goto	CYCLE

; set door lock and open timer

D_LOK	bsf	PORTA,0		; door lock on
	movlw	EEPROM29	; door lock open time
	call	EEREAD
	movwf	DOOR_TMR
	movf	DOOR_TMR,w
	btfsc	STATUS,z	; if zero increase by one so timer will reset in interrupt
	incf	DOOR_TMR,f
	bsf	TMR_FLG,2	; door timer flag
	goto	CYCLE

; service routines
	
SERVCE	clrf	TAMPER		; tamper counter
	clrf	TAMP_T		; tamper timer
	clrf	KEY_TME
	bcf	INTCON,GIE	; stop global interrupts
	clrf	KEY_FLG		; flags cleared
	bsf	KEY_FLG,6	; flasher LED on without flash
	bsf	INTCON,GIE	; allow global interrupts
	bcf	PORTA,4		; flasher LED lit
	clrf	CODE_FG		; code flags
	clrf	TIM_FG		; timer flags
	clrf	OP_FG		; option flags
	clrf	ALT_FG		; alter flag
	clrf	KEY_NT		; key enter counter
	call	CLOSD
	goto	CYCLE
SVCE_MD	btfsc	ALT_FG,0	; is alter flag set
	goto 	ALTR
	clrf	TAMPER		; tamper counter
	clrf	TAMP_T		; tamper timer
	movf	TEMP_1,w	; key 
	xorlw	0x0B		; key # pressed
	btfsc	STATUS,z	; if # end service mode
	goto	SRV_END
	bsf	ALT_FG,0	; set alter flag
	clrf	KEY_NT		; key entering counter
	movf	TEMP_1,w	; key
	xorlw	0x01		; key 1
	btfsc	STATUS,z
	bsf	CODE_FG,0	; master code entry flag
	movf	TEMP_1,w	; key
	xorlw	0x02		; key 2
	btfsc	STATUS,z
	bsf	CODE_FG,1	; user code entry flag
	movf	TEMP_1,w	; key
	xorlw	0x03		; key 3
	btfsc	STATUS,z
	bsf	CODE_FG,2	; service code entry flag
	movf	TEMP_1,w	; key
	xorlw	0x04		; key 4
	btfsc	STATUS,z
	bsf	TIM_FG,0	; delayed input time flag
	movf	TEMP_1,w	; key
	xorlw	0x05		; key 5
	btfsc	STATUS,z
	bsf	TIM_FG,1	; instant input time flag
	movf	TEMP_1,w	; key
	xorlw	0x06		; key 6
	btfsc	STATUS,z
	bsf	TIM_FG,2	; door lock time flag
	movf	TEMP_1,w	; key
	xorlw	0x07		; key 7
	btfsc	STATUS,z
	bsf	TIM_FG,3	; exit time flag
	movf	TEMP_1,w	; key
	xorlw	0x08		; key 8
	btfsc	STATUS,z
	bsf	TIM_FG,4	; alarm time flag
	movf	TEMP_1,w	; key
	xorlw	0x09		; key 9
	btfsc	STATUS,z
	bsf	TIM_FG,5	; alarm warning time flag
	movf	TEMP_1,w	; key
	xorlw	0x00		; key 0
	btfsc	STATUS,z
	bsf	TIM_FG,6	; keypad entry time flag
	movf	TEMP_1,w	; key
	xorlw	0x0A		; key *
	btfsc	STATUS,z
	bsf	OP_FG,0		; option flag
	bcf	INTCON,GIE	; stop global interrupts
	clrf	KEY_FLG
	bsf	KEY_FLG,6	; service flag
	bsf	INTCON,GIE	; allow global interrupts
	call	CLOSD
	goto	CYCLE
 
SRV_END	clrf	TAMPER		; tamper counter
	clrf	TAMP_T		; tamper timer
	clrf	KEY_TME		; key entry timer
	clrf	KEY_FLG		; return from service
	clrf	KEY_NTR
	clrf	ALT_FG
	call	CLOSD
	goto	CYCLE
SRV_OUT	bcf	INTCON,GIE	; stop global interrupts
	clrf	KEY_FLG
	bsf	KEY_FLG,6
	bsf	INTCON,GIE	; allow global interrupts
	clrf	TAMPER		; tamper counter
	clrf	TAMP_T		; tamper timer
	clrf	KEY_TME		; key entry timer
	call	CLOSD
	goto	CYCLE

ALTR	btfss	ALT_FG,0	; if set continue
	goto	SRV_END
	btfsc	CODE_FG,0	; master code flag
	goto	MSTR_S		; master service code
	btfsc	CODE_FG,1	
	goto	USR_S		; user service code
	btfsc	CODE_FG,2
	goto	SVC_S		; service code
	btfsc	TIM_FG,0	; timer flags
	goto	DLY_S		; delay timer value
	btfsc	TIM_FG,1	
	goto	INS_S		; instant timer value
	btfsc	TIM_FG,2
	goto	DOR_S		; door lock timer
	btfsc	TIM_FG,3
	goto	EX_S		; exit delay timer
	btfsc	TIM_FG,4	; 
	goto	ALM_S		; alarm timer
	btfsc	TIM_FG,5	
	goto	ALW_S		; alarm warning timer
	btfsc	TIM_FG,6	
	goto	KY_S		; keypad entry timer
	btfsc	OP_FG,0		; 
	goto	OPT_S		; options
	goto	SRV_END

OUT_I	movf	KEY_NT,w
	btfss	STATUS,z	; if zero do not decrement
	decf	KEY_NT,f	; reduce as one too many after #	
OUT_S	movlw	EEPROM0		; code counter value
	movwf	EEADR
	movf	KEY_NT,w	; number of entries
DEC_BY	call	EWRITE		; store
	goto	SRV_END		; end service routine

; service codes

SVC_S	movlw	EEPROM34	; start of service codes
	addwf	KEY_NT,w
	movwf	EEADR		; address
	movf	TEMP_1,w	; key value
	xorlw	0x0B		; #
	btfsc	STATUS,z
	goto	OUT_I		; write entry value and exit service
	movf	TEMP_1,w	; key value
	call	EWRITE		; write new key value to EEPROM 
	movf	KEY_NT,w
	xorlw	D'11'		; check if 12 entries
	btfsc	STATUS,z	; is the same then out
	goto	OUT_S
	incf	KEY_NT,f
	goto	SRV_OUT		; service continue with next key

; master codes

MSTR_S	movlw	EEPROM1		; start of master codes
	addwf	KEY_NT,w
	movwf	EEADR		; address
	movf	TEMP_1,w	; key value
	xorlw	0x0B		; #
	btfsc	STATUS,z
	goto	SRV_END		; exit service
	movf	TEMP_1,w	; key value
	call	EWRITE		; write new key value to EEPROM 
	movf	KEY_NT,w
	xorlw	D'11'		; check if 12 entries
	btfsc	STATUS,z	; is the same then out
	goto	SRV_END
	incf	KEY_NT,f
	goto	SRV_OUT		; continue with next key entry

; user service code

USR_S	movlw	EEPROM14	; start of user codes
	addwf	KEY_NT,w
	movwf	EEADR		; address
	movf	TEMP_1,w	; key value
	xorlw	0x0B		; #
	btfsc	STATUS,z
	goto	SRV_END		; exit service
	movf	TEMP_1,w	; key value
	call	EWRITE		; write new key value to EEPROM 
	movf	KEY_NT,w
	xorlw	D'11'		; check if 12 entries
	btfsc	STATUS,z	; is the same then out
	goto	SRV_END
	incf	KEY_NT,f
	goto	SRV_OUT		; continue with next key entry	

; timer values

DLY_S	movlw	EEPROM27	; delayed input timer value
	goto	NTR_CK
ALM_S	movlw	EEPROM28	; alarm timer
	goto	NTR_CK	
DOR_S	movlw	EEPROM29	; door lock timer
	goto	NTR_CK		;
INS_S	movlw	EEPROM26	; instant timer value
	goto	NTR_CK
EX_S	movlw	EEPROM31	; exit delay timer
	goto	NTR_CK
ALW_S	movlw	EEPROM32	; alarm warning timer
	goto	NTR_CK
KY_S	movlw	EEPROM33	; keypad entry timer
	goto	NTR_CK
OPT_S	movlw	EEPROM49	; options
 	goto	NTR_CK
	
NTR_CK	movwf	EEADR
	movf	KEY_NT,w 	; entry count
	btfss	STATUS,z	; if zero store
	goto	SEC_NTR		; second entry value
FIR_NTR	movf	TEMP_1,w	; key value
	xorlw	0x0B		; #
	btfsc	STATUS,z
	goto	SRV_END		; exit service
	movf	TEMP_1,w
	movwf	REG_2		; store value
	call	EWRITE
	incf	KEY_NT,f
	goto	SRV_OUT		; continue with next key entry
SEC_NTR movf	TEMP_1,w	; key value
	xorlw	0x0B		; #
	btfsc	STATUS,z
	goto	SRV_END		; exit service
	movf	TEMP_1,w	; key value
	xorlw	0x0A		; *
	btfsc	STATUS,z
	goto	SRV_END		; exit service
	swapf	REG_2,w		; place first number in higher nibble
	iorwf	TEMP_1,w	; second number included
	movwf	REG_2
	call	BCD_BIN		; convert decimal (packed BCD) to binary
	movf	L_BYTE,w	; binary value
	call	EWRITE
	goto	SRV_END		; exit service

;+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

; SUBROUTINES

; delay time 

DELTME	movlw	D'20'		; set delay period 
DELT_1	movwf	VALUE_1		; VALUE_1 = w
	movlw	D'255'		; set delay period value 2 
LP_1	movwf	VALUE_2		; VALUE_2 = w
LP_2	decfsz	VALUE_2,f	; decrease VALUE_2, skip if zero
	goto 	LP_2
	decfsz	VALUE_1,f	; decrease VALUE_1, skip if zero
	goto	LP_1
	return	

; subroutine to read EEPROM memory

EEREAD	movwf 	EEADR		; indirect special function register
	bsf 	STATUS,RP0	; select memory bank 1
	bsf	EECON1,RD	; read EEPROM
RD_RD	nop
	btfsc	EECON1,RD	; skip if RD low (read complete)
	goto 	RD_RD		; wait for low RD (read RD)	
	bcf	STATUS,RP0	; select bank 0
	movf	EEDATA,w	; EEPROM value in w
	return

; subroutine to write to EEPROM

EWRITE	movwf	EEDATA		; data register
	bcf	INTCON,GIE	; disable interrupts
	bsf	STATUS,RP0	; select bank 1
	bsf	EECON1,WREN	; enable write
	movlw	0x55		; place 55H in w for write sequence
	movwf 	EECON2 		; write 55H to EECON2
	movlw 	0xAA		; AAH to w
	movwf	EECON2		; write AA to EECON2
	bsf	EECON1,WR	; set WR bit and begin write sequence
	bcf	EECON1,WREN	; clear WREN bit
WRITE	btfsc	EECON1,WR	; skip if write complete WR=0 when write complete
	goto 	WRITE		; not written yet
	bcf	EECON1,EEIF	; clear write interrupt flag 
	bcf	STATUS,RP0	; select bank 0
	bsf	INTCON,GIE	; enable interrupts
	return

; subroutine to convert from BCD to binary

BCD_BIN clrf	REG_0		; high BCD number (not using this byte)
	clrf	REG_1		; middle BCD number (not using this byte)
	clrf	H_BYTE		; high order binary result
	movf	REG_0,w
	andlw	0x0F		; mask high nibble
	movwf	L_BYTE 
	call	TIMES_A
	swapf	REG_1,w
	call	TIMES_B
	movf	REG_1,w
	call	TIMES_B
	swapf	REG_2,w
	call	TIMES_B
	movf	REG_2,w
	andlw	0x0F
	addwf	L_BYTE,f
	btfsc	STATUS,c
	incf	H_BYTE,f
	return		

TIMES_B	andlw	0x0F
	addwf	L_BYTE,f
	btfsc	STATUS,c
	incf	H_BYTE,f
TIMES_A	bcf	STATUS,c
	rlf	L_BYTE,w	; times 2
	movwf	L_TEMP
	rlf	H_BYTE,w
	movwf	H_TEMP
; times 8
	bcf	STATUS,c
	rlf	L_BYTE,f		
	rlf	H_BYTE,f
	bcf	STATUS,c
	rlf	L_BYTE,f		
	rlf	H_BYTE,f
	bcf	STATUS,c
	rlf	L_BYTE,f		
	rlf	H_BYTE,f
; to mult by 10
	movf	L_TEMP,w
	addwf	L_BYTE,f
	btfsc	STATUS,c
	incf	H_BYTE,f
	movf	H_TEMP,w
	addwf	H_BYTE,f
	return

	end
