;  This program uses and external R2R ladder network to generate complete   
;  DTMF dial tones used for telphone dialing.                   
	
	device	pins28,pages4,banks8,turbo,optionx,oschs
;  use internal RC 4MHz for actual operation, oschs is used for debugging only
		reset	init
		org	8
WAVEABASE       ds	1	; Base address of sine A waveform
POINTERA        ds	1	; Pointer to current position in sine A
WAVEBBASE       ds	1	; Base address of sine B waveform
POINTERB        ds	1	; Pointer to current position in sine B
NEXTVALUE       ds	1	; Sum register to store Sine A + Sine B
SINECOUNT       ds	1	; LSB counter for time to output DTMF
SINECOUNTH      ds	1	; MSB counter for time to output DTMF
TEMP        	ds	1	; Temporary storage
ENDSINE         EQU     127    ; Value to show the end of a sine table

		org	0
;
; sinelookup                                   
; This is the look-up table for the (4 X 3) keypad matrix sine wave table. 
; There are (7) sine waves stored here and adding any two from the         
; matrix will product a DTMF signal for the appropriate key            

sinelookup      ; Used as address lable to call look-up table
	jmp	PC+w    ; Add sine offset to PC to jump into table
sineoffset      ; Used to calculate offset value address
sinerow1        ; Address for sine wave in row 1
	retw	     149
	retw         170
	retw         190
	retw         208
	retw         224
	retw         236
	retw         246
	retw         253
	retw         255
	retw         254
	retw         250
	retw         242
	retw         230
	retw         216
	retw         199
	retw         180
	retw         160
	retw         138
	retw         117
	retw          95
	retw          75
	retw          56
	retw          39
	retw          25
	retw          13
	retw           5
	retw           1
	retw           0
	retw           2
	retw           9
	retw          19
	retw          31
	retw          47
	retw          65
	retw          85
	retw         106
	retw         127  ; End of this sine wave
sinerow2        ; Address for sine wave in row 2
	retw         152
	retw         175
	retw         197
	retw         216
	retw         232
	retw         244
	retw         252
	retw         255
	retw         254
	retw         248
	retw         238
	retw         224
	retw         207
	retw         186
	retw         164
	retw         140
	retw         115
	retw          91
	retw          69
	retw          48
	retw          31
	retw          17
	retw           7
	retw           1
	retw           0
	retw           3
	retw          11
	retw          23
	retw          39
	retw          58
	retw          80
	retw         103
	retw         127  ; End of this sine wave
sinerow3        ; Address for sine wave in row 3
	retw         154
	retw         180
	retw         203
	retw         223
	retw         238
	retw         249
	retw         255
	retw         255
	retw         249
	retw         238
	retw         223
	retw         203
	retw         180
	retw         154
	retw         128
	retw         101
	retw          75
	retw          52
	retw          32
	retw          17
	retw           6
	retw           0
	retw           0
	retw           6
	retw          17
	retw          32
	retw          52
	retw          75
	retw         101
	retw         127  ; End of this sine wave
sinerow4        ; Address for sine wave in row 4
	retw         157
	retw         185
	retw         210
	retw         230
	retw         245
	retw         254
	retw         255
	retw         250
	retw         238
	retw         221
	retw         198
	retw         171
	retw         142
	retw         113
	retw          84
	retw          57
	retw          34
	retw          17
	retw           5
	retw           0
	retw           1
	retw          10
	retw          25
	retw          45
	retw          70
	retw          98
	retw         127  ; End of this sine wave
sinecolumna     ; Address for sine wave in column A
	retw         165
	retw         200
	retw         228
	retw         247
	retw         255
	retw         252
	retw         238
	retw         215
	retw         183
	retw         147
	retw         108
	retw          72
	retw          40
	retw          17
	retw           3
	retw           0
	retw           8
	retw          27
	retw          55
	retw          90
	retw         127  ; End of this sine wave
sinecolumnb     ; Address for sine wave in column B
	retw         169
	retw         206
	retw         235
	retw         252
	retw         255
	retw         245
	retw         222
	retw         188
	retw         149
	retw         106
	retw          67
	retw          33
	retw          10
	retw           0
	retw           3
	retw          20
	retw          49
	retw          86
	retw         127  ; End of this sine wave
sinecolumnc     ; Address for sine wave in column C (double sine wave)
	retw         173
	retw         212
	retw         241
	retw         255
	retw         252
	retw         233
	retw         200
	retw         158
	retw         112
	retw          68
	retw          32
	retw           8
	retw           0
	retw           8
	retw          32
	retw          68
	retw         112
	retw         158
	retw         200
	retw         233
	retw         252
	retw         255
	retw         241
	retw         212
	retw         173
	retw         128
	retw          82
	retw          43
	retw          14
	retw           0
	retw           3
	retw          22
	retw          55
	retw          97
	retw         143
	retw         187
	retw         223
	retw         247
	retw         255
	retw         247
	retw         223
	retw         187
	retw         143
	retw          97
	retw          55
	retw          22
	retw           3
	retw           0
	retw          14
	retw          43
	retw          82
	retw         127  ; End of this sine wave

; This subroutine is used to calculate actual address in the sinelookup     
; table for two DTMF waveforms.  It is only called by setdtmfbase.  
; W is loaded with the key number and this routine returns the sinelookup     
; address of the sine waves.                           

sineaddress     ; Look-up table for sine address
		jmp pc+w ; Add to PC to jump into table
keyoffset
k1      retw        sinerow1-sineoffset       ; Offset for Row 1 sine wave
	retw        sinecolumna-sineoffset    ; Offset for Column A sine wave
k2      retw        sinerow1-sineoffset       ; Offset for Row 1 sine wave
	retw        sinecolumnb-sineoffset    ; Offset for Column A sine wave
k3      retw        sinerow1-sineoffset       ; Offset for Row 1 sine wave
	retw        sinecolumnc-sineoffset    ; Offset for Column A sine wave
k4      retw        sinerow2-sineoffset       ; Offset for Row 2 sine wave
	retw        sinecolumna-sineoffset    ; Offset for Column A sine wave
k5      retw        sinerow2-sineoffset       ; Offset for Row 2 sine wave
	retw        sinecolumnb-sineoffset    ; Offset for Column B sine wave
k6      retw        sinerow2-sineoffset       ; Offset for Row 2 sine wave
	retw        sinecolumnc-sineoffset    ; Offset for Column B sine wave
k7      retw        sinerow3-sineoffset       ; Offset for Row 3 sine wave
	retw        sinecolumna-sineoffset    ; Offset for Column B sine wave
k8      retw        sinerow3-sineoffset       ; Offset for Row 3 sine wave
	retw        sinecolumnb-sineoffset    ; Offset for Column B sine wave
k9      retw        sinerow3-sineoffset       ; Offset for Row 3 sine wave
	retw        sinecolumnc-sineoffset    ; Offset for Column C sine wave
k10     retw        sinerow4-sineoffset       ; Offset for Row 4 sine wave
	retw        sinecolumna-sineoffset    ; Offset for Column C sine wave
k11     retw        sinerow4-sineoffset       ; Offset for Row 4 sine wave
	retw        sinecolumnb-sineoffset    ; Offset for Column C sine wave
k12     retw        sinerow4-sineoffset       ; Offset for Row 4 sine wave
	retw        sinecolumnc-sineoffset    ; Offset for Column C sine wave
key1=k1-keyoffset   ; Calculation for sine addr for keypad 1    
key2=k2-keyoffset   ; Calculation for sine addr for keypad 2
key3=k3-keyoffset   ; Calculation for sine addr for keypad 3
key4=k4-keyoffset   ; Calculation for sine addr for keypad 4
key5=k5-keyoffset   ; Calculation for sine addr for keypad 5
key6=k6-keyoffset   ; Calculation for sine addr for keypad 6
key7=k7-keyoffset   ; Calculation for sine addr for keypad 7
key8=k8-keyoffset   ; Calculation for sine addr for keypad 8
key9=k9-keyoffset   ; Calculation for sine addr for keypad 9
keystar=k10-keyoffset   ; Calculation for sine addr for keypad *
key0=k11-keyoffset  ; Calculation for sine addr for keypad 0
keypound=k12-keyoffset  ; Calculation for sine addr for keypad #

; 
;                               
;  This subroutine is used to calculate the offset address for           
;  the two sine waves to be sent and initialize the WAVEABASE and WABEBBASE  
;  file registers.  The key number (key0 - key9 or keystar or keypound) is   
;  loaded into W before this routine is called.  Next, the DTMF for that     
;  key is sent to the R2R ladder through portB.     

senddtmf
	mov	TEMP,w          ; Initialize temp with key number
	call    sineaddress     ; Get the address for sine wave a for this key
	mov	WAVEABASE,w     ; Initialize sine wave A base address     
	swap	WAVEABASE 	; swap WAVEABASE so that Z bit is not effected
	mov	POINTERA,w      ; Initialize sine wave A pointer address
	mov	w,++TEMP	; Now we get the second sine wave address...
	call    sineaddress     ; Get the address for sine wave b for this key                
	mov	WAVEBBASE,w     ; Initialize sine wave B base address
	swap    WAVEBBASE       ; swap WAVEBBASE so that Z bit is not effected
	mov     POINTERB,w      ; Initialize sine wave B pointer address
	
	mov	SINECOUNTH,#20h  ; Initialize loop counter to 32
loopsine2cyc
	jmp     loopsine    ; Waste two cycles to maintain 35 cycle loop count
loopsine    
		mov	w,POINTERA      ; Place sine wave address into W
		call    sinelookup      ; Look-up first sine wave
		mov     NEXTVALUE,w     ; Place first sine wave into NEXTVALUE
		xor	w,#ENDSINE      ; Update Z bit
		mov	w,<>WAVEABASE    ; Restore to beginning of sine wave
		snz		        ; Skip if not at end of sine wave
		mov     POINTERA,W      ; Restore start address if at end of sine
		inc     POINTERA        ; Move to the next place in the wave
		mov     w,POINTERB      ; Place sine wave address into W
		call    sinelookup      ; Look-up second sine wave
		add     NEXTVALUE,w     ; Add second sine wave into NEXTVALUE
		xor	w,#ENDSINE      ; Update Z bit
		mov	w,<>WAVEBBASE   ; Pointer of sine wave beginneing -> W
		snz		        ; Skip if not at end of sine wave
		mov     POINTERB,w      ; Restore start address if at end of sine
		inc     POINTERB        ; Move to next place in the wave
	
		mov	w,>>NEXTVALUE   ; Divide by 2, Place output into PORTB
		mov     rb,w         	; Update PORTB with new R2R value
		jmp     waste2cyc       ; Waste (2) cycles for 35 total
waste2cyc
		decsz  SINECOUNT        ; Skip if we are done
		jmp    loopsine2cyc     ; Do it again! (add 2 cycles as well) 
		decsz  SINECOUNTH      	; Skip if we are done
		jmp    loopsine        	; Do it again! 
		retw      0             ; Return from sine output
; This code is used to initialize.  
; PORTB is set to zero and all pins are set to outputs                           

init	clr	rb       ; Init output latches for port B to 0
	clr	w        ; Clear W register
	mov	!rb,#0   ; Set all of PORT B to outputs

; test all possible keys in the keypad 

testallkeys       
	mov	w,#key1        ; Place key "1" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#key2        ; Place key "2" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#key3        ; Place key "3" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#key4        ; Place key "4" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#key5        ; Place key "5" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#key6        ; Place key "6" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#key7        ; Place key "7" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#key8        ; Place key "8" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#key9        ; Place key "9" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#keystar     ; Place key "*" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#key0        ; Place key "0" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	mov	w,#keypound    ; Place key "#" address into W
	call    senddtmf    ; Transmit DTMF tone for this key
	jmp    testallkeys ; jump back and do it again!
	        
