
; reads output from an 8870 DTMF decoder and controls a bank of relays.
; When a "*" is found, it operates an audio mute relay to prevent downstream
; equipment seeing the folowing tones. The relay releases after seeing a "#"
; or 5 seconds has elapsed, whichever happens sooner.
; Code sequences "*50#" through to "*55#" select one of six mutually exclusive
; relays. Code "*56#" and "*57#" switch one relay on and off respectively.
; Codes "*58#" and "*59#" switch a second relay on and off respectively, this
; relay will also switch off 5 minutes after *58#.
; Codes "*5A#" through "*5D#" are ignored.

; Note RB pin mapping (because of PCB layout) :

; RB	0	1	2	3	4	5	6	7
; relay	0	1	3	2	7	6	4	5


	list	r=hex,p=16c84

W	equ	0
same	equ	1

PCL	equ	02
STATUS	equ	03
PORT_A	equ	05
PORT_B	equ	06
INTCON	equ	0B
OPTREG	equ	01
TRIS_A	equ	05
TRIS_B	equ	06

relays	equ	10
mfcode	equ	11
cntdown	equ	12
timeout	equ	13
slocnt1	equ	14
slocnt2	equ	15

	org 0000			;tell assembler to start at 000H

init	goto start

	org 0004			;interrupt vector

rtc_interrupt
	decfsz slocnt1,same		;decrement 1st prescaler
	goto rtc_int_1
	decfsz slocnt2,same		;decrement 2nd prescaler
	goto rtc_int_1
	bcf relays,4			;turn relay 6 off
	bcf PORT_B,4
rtc_int_1
	decfsz cntdown,same		;count down and skip next if = 0
	goto counting			;still counting if not reached zero
	bsf timeout,0			;set timed out bit
	bcf INTCON,2			;clear interrupt flag
	retfie				;return

counting
	bcf timeout,0			;clear timed out bit
	bcf INTCON,2			;clear interrupt flag
	retfie				;return

; subroutines

wait_strobe
	btfsc timeout,0			;see if timed out
	goto set_z			;set Z flag if timeout ocurred
	btfss PORT_A,4			;see if Strobe is active on RA4
	goto wait_strobe		;loop until it is
	movfw PORT_A			;retreive the code from the 8870
	movwf mfcode			;store it in mfcode
	bcf mfcode,4			;ensure strobe isn't seen as data
	bcf STATUS,2			;return with Z=0 if tone decoded
	return

set_z	bsf STATUS,2			;return with Z=1 if timed out waiting
	return

wait_no_strobe
	btfsc PORT_A,4			;see if strobe is active on RA4
	goto wait_no_strobe		;loop until it isn't
	return

start_timer
	movlw H'44'			;software prescaler for 5 seconds
	movwf cntdown
	return

start_slo_timer
	movlw H'10'			;set relay 6 auto turn off counters
	movwf slocnt2			;to (16 * 256 * RTC interrupt) = 5 mins
	clrf slocnt1
	return



; Start of setup and decode routines:


start	movlw B'00100000'		;select register page 1
	movwf STATUS

	clrf TRIS_B			;set all port B pins to output mode
	movlw B'00011111'		;set all port A pins to input mode
	movwf TRIS_A

	movlw B'10000111'
	movwf OPTREG			;sets: 	pull-up on port B OFF
					;	RTCC counts internal clock
					;	prescaler connected to RTCC
					;	prescaler divides by 256
					;	(other bits unimportant)

	clrw				;clear the working register
	movwf STATUS			;switch back to register page 0
	clrf PORT_B			;all outputs off
	bsf PORT_B,0			;default to relay 0=ON at start up
	clrf relays
	clrf timeout
	movlw B'10100000'
	movwf INTCON			;global and RTCC interrupts enabled

decode	call wait_no_strobe		;start running when no tone present
	bcf PORT_B,5			;ensure audio isn't muted
	clrf timeout			;set timeout condition until later
	call wait_strobe		;wait for a tone to be received
	movlw H'0B'			;0B is the code for DTMF "*"
	subwf mfcode,W			;set zero flag if "*" was received
	btfsc STATUS,2			;skip next if it was not a "*"
	goto got_star
	goto decode			;look for another one

got_star
	call start_timer		;start time-out timer
	bsf PORT_B,5			;enable mute relay
	call wait_no_strobe		;wait for second tone
	call wait_strobe
	btfsc STATUS,2			;abort if timed out
	goto decode

	movlw H'05'
	subwf mfcode,W                  ;set zero flag if second tone was 5
	btfsc STATUS,2			;skip next if it was not a 5
	goto got_5
	goto get_#			;wait for # to end invalid sequence

; to reach here, the tone sequence "*5" has been found, now decode request
; according to the third tone but don't action it until a "#" is seen.

got_5	call wait_no_strobe
	call wait_strobe		;wait for third tone
	btfsc STATUS,2			;abort if timed out
	goto decode

	call wait_no_strobe		;wait for tone to finish
	movf mfcode,W			;pick up keyed digit
	addwf PCL,same			;jump ahead to vector
	goto decode			;5D (mf code 0000)
	goto got_51
	goto got_52
	goto got_53
	goto got_54
	goto got_55
	goto got_56
	goto got_57
	goto got_58
	goto got_59
	goto got_50
	goto decode			;*
	goto decode			;#
	goto decode			;5A
	goto decode			;5B
	goto decode			;5C (mf code 1111)

got_50	movlw B'11110000'		;mask to keep toggle bits & mute
	andwf relays,same		;clear bits 3,2,1,0
	bsf relays,0			;set bit 0
	goto get_#

got_51	movlw B'11110000'		;mask to keep toggle bits & mute
	andwf relays,same		;clear bits 3,2,1,0
	bsf relays,1			;set bit 1
	goto get_#

got_52	movlw B'11110000'		;mask to keep toggle bits & mute
	andwf relays,same		;clear bits 3,2,1,0
	bsf relays,3			;set bit 3
	goto get_#

got_53	movlw B'11110000'		;mask to keep toggle bits & mute
	andwf relays,same		;clear bits 3,2,1,0
	bsf relays,2			;set bit 2
	goto get_#

got_54	bsf relays,7			;set bit 7 ON
	goto get_#

got_55	bcf relays,7			;set bit 7 OFF
	goto get_#

got_56	bsf relays,6			;set bit 6 ON
	goto get_#

got_57	bcf relays,6			;set bit 6 OFF
	goto get_#

got_58	bsf relays,4			;set bit 4 ON
	call start_slo_timer		;start the auto turn off counter
	goto get_#

got_59	bcf relays,4			;set bit 4 OFF

get_#	call wait_strobe		;wait for 4th tone
	btfsc STATUS,2			;abort if timed out
	goto decode

	movlw H'0C'			;0C is the DTMF code for "#"
	subwf mfcode,W			;if # received set Z flag
	btfsc STATUS,2			;skip next if not a #
	goto got_#
	call wait_no_strobe
	goto get_#			;only # is valid, loop until found
					;or timeout

got_#   call wait_no_strobe		;wait for the tone to finish
	movfw relays			;use the "relays" variable to set RB
	movwf PORT_B
	goto decode			;all done, check for new sequence

	retlw '('
	retlw 'C'
	retlw ')'
	retlw 'G'
	retlw 'W'
	retlw '6'
	retlw 'B'
	retlw 'W'
	retlw 'X'

	end

