Scenix Lib IO Dev Modem BELL_103_FULL_DUP_1_13.SRC
; ******************************************************************************
; Copyright © [01/25/1999] Scenix Semiconductor, Inc. All rights reserved.
;
;Scenix Semiconductor, Inc. assumes no responsibility or liability for
; the use of this [product, application, software, any of these products].
; Scenix Semiconductor conveys no license, implicitly or otherwise, under
; any intellectual property rights.
; Information contained in this publication regarding (e.g.: application,
; implementation) and the like is intended through suggestion only and may
; be superseded by updates. Scenix Semiconductor makes no representation
; or warranties with respect to the accuracy or use of these information,
; or infringement of patents arising from such use or otherwise.
;******************************************************************************
;
; Filename: bell_103_tx.src
;
; Author: Chris Fogelklou
; Applications Engineer
; Scenix Semiconductor Inc.
;
; Revision: 1.08
;
; Date: April 16, 1999.
;
; Part: SX28AC rev. 2.5
;
; Freq: 50Mhz
;
; Compiled using Parallax SX-Key software v1.0
;
; Version: 1.10
;
; Program Description: This simple program encodes an outgoing bell103 signal.
; This program only creates the answer frequencies, since it
; cannot dial out to originate.
;
; To use this program, connect the SX-DTMF-DEMO board to a phone
; line and to a PC. The communications settings are 300,N,8,1.
; Now, from a remote BELL103 modem, simply dial the modem's number.
; When you here the line ringing on the dialing modem, press a key
; in the comm window of the SX-modem-board. This should force the
; modem board off-hook and cause it to send out an answer tone for
; 3 seconds. Once the answer tone is sent, the modem board will
; begin modulating the state of the RS-232 pin onto the carrier.
; If the terminal program is set up correctly, you will be able to
; receive the sent characters on the remote modem.
;
; Revision History: 1.0 Tried for weeks to get FSK-receive to work. Finally got it
; working.
; 1.01 Tried to eliminate all unnecessary code...
; 1.04 Originate and answer modes both working. AT command set added.
; 1.10 Changed the fsk receive code so it is simpler to understand and
; uses less RAM.
;
; INPUTS:
; Received RS-232 characters on rs-232 rx_pin (ra.1)
; OUTPUTS:
; Received RS-232 characters on tx_pin (ra.2)
; FSK output on PPM_pin
; LED flashes (rb.0)
;
; RESOURCES:
; Program memory: TBD
; Data memory: TBD
; I/O Count: TBD
;
;******************************************************************************
; Device Directives
;******************************************************************************
SX28L_compiler
IFDEF SX28L_compiler
device SX28L,oscxt4,carryx ; 28-pin device, 4 pages, 8 banks of RAM
device turbo,stackx_optionx ; High speed oscillator, turbo mode,
; option register extend, 8-level stack
ELSE
device pins28,pages4,banks8,carryx ; 28-pin device, 1 pages, 8 banks of RAM
device oschs,turbo,optionx,stackx ; High speed oscillator, turbo mode,
ENDIF ; option register extend, 8-level stack
freq 50_000_000 ; default run speed = 50MHz
ID 'B103TX10' ; Version = 1.0
reset reset_entry ; JUMP to reset_entry label on reset
;******************************************************************************
; Watches (For Debug in SX_Key software V.1.0 +)
;******************************************************************************
watch fsk_answering,1,ubin
watch freq_acc_low,16,udec
watch freq_count_low,16,udec
watch sine_index,8,udec
watch D_to_A_val,8,udec
watch freq_acc_high,16,uhex
watch freq_count_high,8,uhex
watch freq_count_low,8,uhex
watch freq_count_high2,8,uhex
watch freq_count_low2,8,uhex
watch byte,1,fstr
watch byte,8,udec
watch curr_sine,8,sdec
watch sine_index,8,sdec
watch D_to_A_val,8,udec
watch PPM0_acc,8,udec
watch timer_flag,1,ubin
watch timer_l,16,uhex
watch temp,8,uhex
watch wreg,8,uhex
watch fsk_last_trans,8,udec
watch fsk_trans_avg_l,16,udec
watch fsk_avg_count,8,udec
watch fsk_trans_count,8,udec
watch fsk_glitch_acc,8,udec
watch fsk_high_byte,8,udec
watch fsk_average_index,8,udec
watch fsk_temp_trans,8,udec
watch fsk_processing_required1,1,ubin
watch fsk_processing_required2,1,ubin
watch fsk_carrier_detected,1,ubin
watch fsk_rb_past_state,8,ubin
;**************************************************************************
; Equates for common data comm frequencies
;**************************************************************************
f697_h equ $012 ; DTMF Frequency
f697_l equ $09d
f770_h equ $014 ; DTMF Frequency
f770_l equ $090
f852_h equ $016 ; DTMF Frequency
f852_l equ $0c0
f941_h equ $019 ; DTMF Frequency
f941_l equ $021
f1209_h equ $020 ; DTMF Frequency
f1209_l equ $049
f1336_h equ $023 ; DTMF Frequency
f1336_l equ $0ad
f1477_h equ $027 ; DTMF Frequency
f1477_l equ $071
f1633_h equ $02b ; DTMF Frequency
f1633_l equ $09c
;******************************************************************************
; Equates for FSK generation
;******************************************************************************
f2225_h equ $03b
f2225_l equ $06b
f2025_h equ $036
f2025_l equ $014
f1070_h equ $01c
f1070_l equ $093
f1270_h equ $021
f1270_l equ $0ea
f2100_h equ $038 ; 2100Hz Signifies LOW data in Bell202 Spec
f2100_l equ $015
;**************************************************************************
; Equates for certain baud rates:
;**************************************************************************
;baud_bit = 4 ;for 19200 baud
;start_delay = 16+8+1 ; " " "
;int_period = 163 ; " " "
; *** 2400 baud (for slower baud rates, increase the RTCC prescaler)
baud_bit = 7 ;for 2400 baud
start_delay = 128+64+1 ; " " "
fsk_start_delay = 128+96+1
int_period = 163 ; " " "
;******************************************************************************
; Pin Definitions (These definitions are for SX DTMF DEMO boards)
;******************************************************************************
PPM_pin equ ra.0 ; D/A output pin
rx_pin equ ra.1 ; RS-232 reception pin
tx_pin equ ra.2 ; RS-232 transmission pin
nothing equ ra.3 ; N/C
ra_dir_mask equ %11111010 ; sets up the I/O directions of port ra
ra_data_mask equ %11111111 ; sets up the output levels of the output pins on ra
led_pin equ rb.0 ; LED pin
rxa_pin equ rb.1 ; FSK receive pin
cntrl_1 equ rb.2 ; drive cntrl_1 low to disable the output of the LPF
ring equ rb.3 ; ring detection pin
hook equ rb.4 ; drive hook low to go off-hook
cntrl_3 equ rb.5 ; drive cntrl_3 low to disable the output of the HPF
rts equ rb.6 ; indicates to the SX that the PC wants to transmit data
cts equ rb.7 ; indicates to the PC that the SX is ready to receive data
rb_dir_mask equ %01101110 ; sets up the I/O directions of port rb
rb_data_mask equ %01011011 ; sets up the output levels of the output pins on ra
LPF_mask equ %01001110 ; when LPF is enabled, tristate cntrl 1 and put cntrl 3 low
HPF_mask equ %01101010 ; when HPF is enabled, tristate cntrl 3 and put cntrl 1 low
LPF_HPF_mask equ %01101110 ; when both filters are enabled, tristate cntrl 1 and cntrl 3
dtmf_in_pin equ rc.0
dtmf_fdbk_pin equ rc.1
AtoD_in_pin equ rc.2
AtoD_fdbk_pin equ rc.3
imp_450_pin equ rc.4
imp_600_pin equ rc.5
imp_750_pin equ rc.6
imp_900_pin equ rc.7
rc_dir_mask equ %11010101 ; sets up the I/O directions of port rc
rc_data_mask equ %00001111 ; sets up the output levels of the output pins on ra
;******************************************************************************
; Global Variables
;******************************************************************************
org $8 ; Global registers
flags ds 1
dtmf_gen_en equ flags.0 ; Signifies whether or not DTMF output is enabled
sine_gen_en equ flags.1
timer_flag equ flags.2
fsk_tx_en equ flags.3
fsk_rx_en equ flags.4 ; Enables the FSK receiver.
rx_flag equ flags.5
fsk_rx_flag equ flags.6
temp ds 1
task_switcher ds 1
ascii_index ds 1
command_index ds 1
;******************************************************************************
; Bank 0 Variables
;******************************************************************************
org $10
sine_gen_bank = $
freq_acc_low ds 1 ; 16-bit accumulator which decides when to increment the sine wave
freq_acc_high ds 1 ;
freq_count_low ds 1 ; 16-bit counter which decides which frequency for the sine wave
freq_count_high ds 1 ; freq_count = Frequency * 6.83671552
sine_index ds 1
sine_index2 ds 1 ; The velocity of the sin wave
freq_count_low2 ds 1 ; 16-bit counter which decides which frequency for the sine wave
freq_count_high2 ds 1 ; freq_count = Frequency * 6.83671552
freq_acc_high2 ds 1 ;
freq_acc_low2 ds 1 ; 16-bit accumulator which decides when to increment the sine wave
curr_sine ds 1 ; The current value of the imitation sin wave
curr_sine2 ds 1 ; The current value of the imitation sin wave
sine2_temp ds 1 ; This register is used to do a temporary shift/add register
PPM_bank = $
PPM0_acc ds 1 ; PPM accumulator
D_to_A_val ds 1 ; current PPM output
;******************************************************************************
; Bank 1 Variables
;******************************************************************************
org $30
timers = $
timer_l ds 1
timer_h ds 1
timer_hh ds 1
serial = $ ;UART bank
tx_high ds 1 ;hi byte to transmit
tx_low ds 1 ;low byte to transmit
tx_count ds 1 ;number of bits sent
tx_divide ds 1 ;xmit timing (/16) counter
rx_count ds 1 ;number of bits received
rx_divide ds 1 ;receive timing counter
rx_byte ds 1 ;buffer for incoming byte
rx_count2 ds 1 ;number of bits received
rx_divide2 ds 1 ;receive timing counter
rx_byte2 ds 1 ;buffer for incoming byte
string ds 1
byte ds 1
plus_count ds 1
;******************************************************************************
; Bank 2 Variables
;******************************************************************************
org $50 ;bank3 variables
fsk_receive_bank = $
fsk_transmit_bank = $
fsk_last_trans ds 1
fsk_trans_avg_l ds 1
fsk_trans_avg_h ds 1
fsk_avg_count ds 1
fsk_trans_count ds 1 ; This register counts the number of counts
; between transitions at the pin
fsk_rb_past_state ds 1 ; This register keeps track of the previous
; state of port RB, to watch for transitions
fsk_glitch_acc ds 1
fsk_average ds 1
fsk_high_byte ds 1
fsk_average_index ds 1
fsk_temp_trans ds 1
fsk_no_carrier_count ds 1
fsk_flags ds 1
fsk_answering equ fsk_flags.0
fsk_tx_bit equ fsk_flags.1
fsk_rx_bit equ fsk_flags.2
fsk_processing_required1 equ fsk_flags.3
fsk_processing_required2 equ fsk_flags.4
fsk_rx_bit_last equ fsk_flags.5
fsk_carrier_detected equ fsk_flags.6
fsk_answer_tone equ fsk_flags.7
;*************************************************************
; Bank 4, 5, 6, 7 (for ascii buffer, but can be reused.)
;*************************************************************
org $90
ascii_buffer = $
org $b0
ascii_buffer2 = $
org $d0
ascii_buffer3 = $
org $f0
ascii_buffer4 = $
;************************ Beginning of program space ***************************
;******************************************************************************
; Interrupt
org $0 ; The interrupt Service routine starts at location zero.
;
; With a retiw value of -163 and an oscillator frequency of 50MHz, this
; code runs every 3.26us.
;******************************************************************************
PPM_output
bank PPM_bank ; Update the PPM pin
clc
add PPM0_acc,D_to_A_val
snc
setb PPM_pin
sc
clrb PPM_pin
;******************************************************************************
FSK_output
jnb dtmf_gen_en,:dtmf_disabled
call @sine_generator1
jmp :task_switcher
:dtmf_disabled
snb sine_gen_en ; Output the frequencies set by the freq_count registers
call @sine_generator2
snb fsk_rx_en
call @fsk_receive
:task_switcher
inc task_switcher
mov w,task_switcher
and w,#$07
clc
jmp pc+w
jmp :fsk_process_1 ;0
jmp :fsk_process_2 ;1
jmp :fsk_process_3 ;2
jmp :fsk_transmit ;3
jmp :fsk_get_carrier;4
jmp do_timers ;5
jmp :transmit ;6
jmp :receive ;7
:fsk_process_1
call @FSK_RECEIVE_PROCESSING1
jmp do_timers
:fsk_process_2
call @FSK_RECEIVE_PROCESSING2
jmp do_timers
:fsk_process_3
call @FSK_RECEIVE_PROCESSING3
jmp do_timers
:fsk_transmit
snb fsk_tx_en
call @TRANSMIT_FSK ; into its corresponding frequencies
jmp do_timers
:fsk_get_carrier
call @FSK_GET_CARRIER
jmp do_timers
;**************************************************************************
:transmit
; This is an asynchronous RS-232 transmitter
; INPUTS:
; tx_divide.baud_bit - Transmitter only executes when this bit is = 1
; tx_high - Part of the data to be transmitted
; tx_low - Some more of the data to be transmitted
; tx_count - Counter which counts the number of bits transmitted.
; OUTPUTS:
; tx_pin - Sets/Clears this pin to accomplish the transmission.
;**************************************************************************
bank serial
clrb tx_divide.baud_bit ;clear xmit timing count flag
inc tx_divide ;only execute the transmit routine
STZ ;set zero flag for test
SNB tx_divide.baud_bit ; every 2^baud_bit interrupt
test tx_count ;are we sending?
JZ do_timers ;if not, go to :receive
clc ;yes, ready stop bit
rr tx_high ; and shift to next bit
rr tx_low ;
dec tx_count ;decrement bit counter
movb tx_pin,/tx_low.6 ;output next bit
jmp do_timers
;**************************************************************************
:receive
; This is an asynchronous receiver for RS-232 reception
; INPUTS:
; rx_pin - Pin which RS-232 is received on.
; OUTPUTS:
; rx_byte - The byte received
; rx_flag - Set when a byte is received.
;**************************************************************************
bank serial
movb c,rx_pin ;get current rx bit
test rx_count ;currently receiving byte?
jnz :rxbit ;if so, jump ahead
mov w,#9 ;in case start, ready 9 bits
sc ;skip ahead if not start bit
mov rx_count,w ;it is, so renew bit count
mov rx_divide,#start_delay ;ready 1.5 bit periods
:rxbit djnz rx_divide,:rxdone ;middle of next bit?
setb rx_divide.baud_bit ;yes, ready 1 bit period
dec rx_count ;last bit?
sz ;if not
rr rx_byte ; then save bit
snz ;if so
setb rx_flag ; then set flag
:rxdone
;**************************************************************************
do_timers
bank timers ; Update the timers
inc timer_l
snz
inc timer_h
snz
setb timer_flag
snz
inc timer_hh
setb led_pin
sb timer_h.6
clrb led_pin
;******************************************************************************
:ISR_DONE
; This is the end of the interrupt service routine. Now load 163 into w and
; perform a retiw to interrupt 163 cycles from the start of this one.
; (3.26us@50MHz)
;******************************************************************************
mov w,#-163 ;1 ; interrupt 163 cycles after this interrupt
retiw ;3 ; return from the interrupt
;******************************************************************************
; End of the Interrupt Service Routine
;******************************************************************************
;**************************************************************************
time_n_ticks
; This subroutine times 'w' ticks, and returns with a '1' in w when
; the specified time has timed out. Each tick is 213.647 ms.
; This subroutine uses the TEMP register
; INPUT w - # of milliseconds to delay for.
; OUTPUT Returns after n milliseconds.
;**************************************************************************
bank timers
test wreg
jz :check_time
clc
add w,timer_hh
mov temp,w
retw 0
:check_time
mov w,temp
xor w,timer_hh
sz
retw 0
retw 1
;******************************************************************************
reset_entry
; Program Starts Here on Power Up
;******************************************************************************
call @init
mov !option,#%00011111 ; enable wreg and rtcc interrupt
mov w,#_hello
call @send_string
main_2
_send_prompt mov w,#_CR
call @send_string
mov w,#_prompt ; send prompt
call @send_string
_cmd_loop
jnb rx_flag,$
clrb rx_flag
bank serial
mov byte,rx_byte
call @uppercase ; convert it to uppercase
stc
cje byte,#$20,_cmd_loop ; if it equals a space, ignore it.
stc
cje byte,#$0d,:enter ; if it equals a carriage return, parse the string.
mov w,byte ; if it does not resemble the above characters, echo it.
call @send_byte
stc
cje byte,#$08,:backspace ; if it equals a backspace, delete one character in the buffer.
call @buffer_push ; otherwise, store it
jmp _cmd_loop ; and come back for more.
:backspace
call @buffer_backspace
jmp _cmd_loop
:enter ; If the user presses enter, then parse the string.
;**************************************************************************
; String parser (Checks to see if buffer = any commands)
; -Checks contents of ascii buffer against any commands stored in ROM
; -If a command = the contents of the ascii buffer, a routine will be called
; -Each routine MUST perform a retw 0 on exit, or parse_string will not
; know that a routine has run and it should exit back to command mode.
; -Exits back to command mode when it detects a zero after the table look-up.
; -Outputs 'OK' if no commands are matched.
;**************************************************************************
parse_string
clr ascii_index ; Clear the index into the ascii buffer
clr command_index ; And the index into the commands
:loop call @buffer_get ; Get a vale from the buffer at ascii_index
call command_table ; Get a character from one of the commands
test wreg ; If the return value is 0, then this matched
jz :nothing ; the command and ran a routine. Exit.
bank serial
xor w,byte ; compare the command's character with the
jnz :not_equal ; buffer's character.
call @inc_ascii_index ; Increment the index into the buffer.
jmp :loop
:not_equal
inc command_index ; If the buffer did not equal the command,
clr ascii_index ; start from the beginning of a new command
stc
cjne command_index,#6,:loop ; and the buffer. (This number = # of commands)
:nothing mov w,#_CR
call @send_string
mov w,#_OK ; If we have checked all 4 commands, then this
call @send_string ; did not equal any so send an 'OK' message.
:done
bank ascii_buffer
clr ascii_index
clr ascii_buffer
jmp _send_prompt
;**************************************************************************
command_table
mov w,command_index
clc
add pc,w
jmp command_1
jmp command_2
jmp command_3
jmp command_4
jmp command_5
jmp command_6
;**************************************************************************
command_1 ; Dial command
mov w,ascii_index
add PC,w
retw 'A'
retw 'T'
retw 'D'
retw 'T'
jmp DIAL_MODE
;**************************************************************************
command_2 ; Hang up command
mov w,ascii_index
add PC,w
retw 'A'
retw 'T'
retw 'H'
jmp HANG_UP
;**************************************************************************
command_3 ; Initialize
mov w,ascii_index
add PC,w
retw 'A'
retw 'T'
retw 'Z'
jmp INITIALIZE
;**************************************************************************
command_4 ; Answer/ Auto answer
mov w,ascii_index
add PC,w
retw 'A'
retw 'T'
retw 'A'
jmp AUTO_ANSWER
;**************************************************************************
command_5 ; Data mode
mov w,ascii_index
add PC,w
retw 'A'
retw 'T'
retw 'O'
jmp FSK_IO
;**************************************************************************
command_6 ; Help
mov w,ascii_index
add PC,w
retw '?'
jmp HELP
;**************************************************************************
; END of String parser (Checks to see if buffer = any commands)
;**************************************************************************
HANG_UP
setb hook
retw 0
INITIALIZE
call @init
clr flags
retw 0
AUTO_ANSWER
jmp Answer
retw 0
HELP retw 0
;**************************************************************************
; Dial Mode:
; -Dials contents of ascii buffer, starting from location pointed
; to by ascii_index.
; -Responds to these commands:
; 0-9, *, # - Dials the specified number
; , - Pause for 2 seconds
; -Jumps to data mode after dialing.
;**************************************************************************
DIAL_MODE
mov w,#_CR
call @send_string
mov w,#_DIALING ; send Dialing
call @send_string
clrb hook
mov w,#255
call @delay_10n_ms
bank serial
:dial_loop call @buffer_get ; wait for an input character
call @uppercase ; convert it to uppercase
mov w,byte
snz
jmp :originate_mode
call @send_byte
cje byte,#',',:pause ; if the character = ',', pause for 2s
call @digit_2_index ; convert the ascii digit to an
; index value
call @load_frequencies ; load the frequency registers
call @dial_it ; dial the number for 60ms and return.
:inc call @inc_ascii_index ; increment the index into the table
jmp :dial_loop
:pause
mov w,#201 ; delay 2s
call @delay_10n_ms
jmp :inc
:originate_mode
;******************************************************************
; Go off-hook
;******************************************************************
mov m,#$0f
mov !rb,#HPF_mask ; Enable HPF and disable LPF
clrb cntrl_1
clr flags
bank fsk_transmit_bank
clrb fsk_answering
setb fsk_rx_en
setb fsk_tx_bit
setb sine_gen_en
setb fsk_tx_en
mov w,#140 ; wait 30 seconds for answer_tone
call time_n_ticks
:loop
; clr w
; call time_n_ticks
; test wreg
; jnz no_carrier
; bank fsk_receive_bank
; jnb fsk_answer_tone,:loop
jmp FSK_IO
Answer
clrb hook ; Go off-hook
mov m,#$0f
mov !rb,#LPF_mask ; Enable LPF and disable HPF
clrb cntrl_3
call @answer_tone ; Send out the answer tone for 3 seconds
bank fsk_transmit_bank ; Clear all the flags
clr flags
setb fsk_answering ; enable answering frequencies
setb fsk_tx_bit ; Set the tx_bit to output a high frequency
setb fsk_tx_en ; enable FSK transmit
setb sine_gen_en ; enable sine generation
mov w,#255
call @delay_10n_ms
mov w,#255
call @delay_10n_ms
bank fsk_receive_bank ; enable FSK receive
setb fsk_rx_en
FSK_IO
mov w,#47
call time_n_ticks
:loop
clr w
call time_n_ticks
test wreg
; jnz no_carrier
bank fsk_receive_bank
; jnb fsk_carrier_detected,:loop
mov w,#_DATA_MODE
call @send_string
mov w,#_prompt
call @send_string
clr plus_count
:loop2
bank fsk_receive_bank
; jnb fsk_carrier_detected,no_carrier
movb fsk_tx_bit,rx_pin ; move the rs-232 pin to the fsk_tx_bit
movb tx_pin,fsk_rx_bit ; and move the fsk_rx_bit to the rs-232 pin
jb rx_flag,:check_for_plus
jmp :loop2 ; jump here forever (ISR does all the work)
:check_for_plus
bank serial
clrb rx_flag
inc plus_count
mov w,#'+'
xor w,rx_byte
sz
clr plus_count
mov w,#3
xor w,plus_count
snz
retw 0
jmp :loop2
no_carrier
setb tx_pin
mov w,#255
call @delay_10n_ms
mov w,#_no_carrier
call @send_string
bank serial
:loop test tx_count
jz INITIALIZE
jmp :loop
org $200
;******************************************************************************
FSK_RECEIVE
;**************************************************************************
bank fsk_receive_bank ; switch to fsk_receive_bank of RAM
inc fsk_trans_count ; Increment the transition count
snz
dec fsk_trans_count ; If the result is zero, keep fsk_trans_count in range
clc
mov w,fsk_rb_past_state ; Check for a transition
xor w,rb
and w,#%00000010
snz
retp ; return if there has been no transition
xor fsk_rb_past_state,w ; save the new value of the FSK_pin
jb fsk_answering,:dont_double
sb fsk_rb_past_state.1
retp
:dont_double
clc
mov w,#-30
add w,fsk_trans_count
jnc :glitch
mov fsk_temp_trans,fsk_trans_count
clc
add fsk_trans_avg_l,w
snc
inc fsk_trans_avg_h
inc fsk_avg_count
clr fsk_trans_count
setb fsk_processing_required1
retp
:glitch ; Save any glitches in the glitch accumulator, to be added to
; the transition count before processing
clc
add fsk_glitch_acc,fsk_trans_count
retp
;**************************************************************************
FSK_RECEIVE_PROCESSING1 ; This code is not very speed critical and can
; run every so often in the ISR.
;**************************************************************************
bank fsk_receive_bank
sb fsk_processing_required1
retp
clrb fsk_processing_required1
setb fsk_processing_required2
retp
;**************************************************************************
FSK_RECEIVE_PROCESSING2 ; This code is not very speed critical and can
; run every so often in the ISR.
;**************************************************************************
;******************************************************************
; If no processing is required, exit
;******************************************************************
bank fsk_receive_bank ;1
sb fsk_processing_required2 ;1
retp ;1
clrb fsk_processing_required2 ;1
;******************************************************************
; Add the last transition time to this one, and divide by two.
; and also add the glitch accumulator.
;******************************************************************
clc
rr fsk_glitch_acc
clc
mov w,fsk_last_trans
add w,fsk_temp_trans
rr wreg
clc
add w,fsk_glitch_acc
clr fsk_glitch_acc
;******************************************************************
; Now compare the result to 130 for answer mode or to 145 for
; originate mode. Anything above this threshold is a "high" bit,
; and anything below this threshold is a "low" bit.
;******************************************************************
mov fsk_last_trans,w ;1
mov w,#-130 ;1
sb fsk_answering ;1
mov w,#-145 ;1
clc ;1
add w,fsk_last_trans ;1
setb fsk_rx_bit ;1
snc ;1
clrb fsk_rx_bit ;1;50
;3;53
mov fsk_last_trans,fsk_temp_trans
retp
;**************************************************************************
FSK_RECEIVE_PROCESSING3
;**************************************************************************
retp
bank fsk_receive_bank
sb fsk_rx_bit
jmp :rx_bit_low
:rx_bit_high
snb fsk_rx_bit_last
retp
setb fsk_rx_bit_last
mov w,#121
sb fsk_answering
mov w,#138
jmp :hysterises
:rx_bit_low
sb fsk_rx_bit_last
retp
clrb fsk_rx_bit_last
mov w,#144
sb fsk_answering
mov w,#152
:hysterises
mov fsk_last_trans,w
retp
;**************************************************************************
FSK_GET_CARRIER
;**************************************************************************
bank fsk_receive_bank
mov w,fsk_avg_count
sz
retp
inc fsk_avg_count
clrb fsk_answer_tone
clrb fsk_carrier_detected
jb fsk_answering,:low_freqs
mov w,#-135
clc
add w,fsk_trans_avg_h
jnc :get_answer_tone; If the average transition
; time is less than 138, error...
mov w,#-152
clc
add w,fsk_trans_avg_h
sc
setb fsk_carrier_detected
:get_answer_tone
mov w,#-142
clc
add w,fsk_trans_avg_h
jnc :no_answer_tone
mov w,#-148
clc
add w,fsk_trans_avg_h
sc
setb fsk_answer_tone
:no_answer_tone
clr fsk_trans_avg_h
clr fsk_trans_avg_l
retp
:low_freqs
mov w,#-118
clc
add w,fsk_trans_avg_h
jnc :no_carrier ; If the average transition
; time is less than 138, error...
mov w,#-145
clc
add w,fsk_trans_avg_h
sc
setb fsk_carrier_detected
:no_carrier clr fsk_trans_avg_h
clr fsk_trans_avg_l
retp
;**************************************************************************
TRANSMIT_FSK
;**************************************************************************
bank fsk_transmit_bank
jb fsk_answering,transmit_answer_tones
transmit_originate_tones
jnb fsk_tx_bit,:low_freq
:high_freq
bank sine_gen_bank
mov freq_count_high2,#f1270_h
mov freq_count_low2,#f1270_l
retp
:low_freq
bank sine_gen_bank
mov freq_count_high2,#f1070_h
mov freq_count_low2,#f1070_l
retp
transmit_answer_tones
jnb fsk_tx_bit,:low_freq
:high_freq
bank sine_gen_bank
mov freq_count_high2,#f2225_h
mov freq_count_low2,#f2225_l
retp
:low_freq
bank sine_gen_bank
mov freq_count_high2,#f2025_h
mov freq_count_low2,#f2025_l
retp
;**************************************************************************
answer_tone
;**************************************************************************
bank sine_gen_bank ; send out the answer tone for 3 seconds
clr curr_sine
mov freq_count_high2,#f2100_h
mov freq_count_low2,#f2100_l
setb sine_gen_en ; enable the FSK transmitter
mov w,#255
call @delay_10n_ms
mov w,#45
call @delay_10n_ms
retp
;**************************************************************************
org $300
;**************************************************************************
; String data (for RS-232 output) and tables
;**************************************************************************
_hello dw 13,10,'SX Modem V 4.0',13,10,0
_instructions dw '- ? For Help',0
_DIALING dw 'DIAL ',0
_ANSWERING dw 'ANSWERING ',0
_AUTO_ANSWER dw 'AUTO ANSWER ',13,10,0
_RING dw 'RING',13,10,0
_PROMPT dw 13,10,'>',0
_HANGING_UP dw 'HANG UP ',13,10,0
_ATDT dw 13,10,'ATDT=',0
_ATA dw 'ATA =',0
_ATH dw 'ATH =',0
_ATZ dw 'ATZ =',0
_ATO dw 'ATO =',0
_plus dw 13,10,'+++ =',0
_OK dw 'OK',13,10,0
_CR dw 13,10,0
_COMMAND_MODE dw 'COMMAND MODE',13,10,0
_DATA_MODE dw 13,10,'CONNECT 300',0
_no_carrier dw 13,10,'NO CARRIER',0
_INIT dw 'INIT',0
org $400 ; Miscellaneous subroutines
;**************************************************************************
buffer_push
; This subroutine pushes the contents of byte onto the 32-byte ascii buffer.
;**************************************************************************
bank serial ; Move the byte into the buffer
mov temp,byte
mov fsr,#ascii_buffer
clc
add fsr,ascii_index
mov indf,temp
; Increment index and keep it in range
call @inc_ascii_index
mov fsr,#ascii_buffer ; Null terminate the buffer.
clc
add fsr,ascii_index
clr indf
bank serial
retp
;**************************************************************************
;**************************************************************************
buffer_backspace
; This subroutine deletes one value of the buffer and decrements the index
;**************************************************************************
dec ascii_index
and ascii_index,#%01101111
mov fsr,#ascii_buffer
clc
add fsr,ascii_index
clr indf
bank serial
retp
;**************************************************************************
inc_ascii_index
; This subroutine increments the index into the buffer
;**************************************************************************
mov w,ascii_index
and w,#%00001111
xor w,#%00001111
jnz :not_on_verge
inc ascii_index
mov w,#16
clc
add w,ascii_index
and w,#$7f
mov ascii_index,w
retp
:not_on_verge
inc ascii_index
retp
;**************************************************************************
buffer_get
; This subroutine retrieves the buffered value at index
;**************************************************************************
mov fsr,#ascii_buffer
clc
add fsr,ascii_index
mov w,indf
bank serial
mov byte,w
retp
;**************************************************************************
delay_10n_ms
; This subroutine delays 'w'*10 milliseconds.
; This subroutine uses the TEMP register
; INPUT w - # of milliseconds to delay for.
; OUTPUT Returns after 10 * n milliseconds.
;**************************************************************************
mov temp,w
bank timers
:loop clrb timer_flag ; This loop delays for 10ms
mov timer_h,#$0f4
mov timer_l,#$004
jnb timer_flag,$
dec temp ; do it w-1 times.
jnz :loop
clrb timer_flag
retp
;**************************************************************************
delay_n_ms
; This subroutine delays 'w' milliseconds.
; This subroutine uses the TEMP register
; INPUT w - # of milliseconds to delay for.
; OUTPUT Returns after n milliseconds.
;**************************************************************************
mov temp,w
bank timers
:loop clrb timer_flag ; This loop delays for 1ms
mov timer_h,#$0fe
mov timer_l,#$0cd
jnb timer_flag,$
dec temp ; do it w-1 times.
jnz :loop
clrb timer_flag
retp
;**************************************************************************
zero_ram
; Subroutine - Zero all ram.
; INPUTS: None
; OUTPUTS: All ram locations (except special function registers) are = 0
;**************************************************************************
CLR FSR
:loop SB FSR.4 ;are we on low half of bank?
SETB FSR.3 ;If so, don't touch regs 0-7
CLR IND ;clear using indirect addressing
IJNZ FSR,:loop ;repeat until done
retp
;**************************************************************************
init
;**************************************************************************
mov m,#$0d
mov !ra,#$00 ; initialize all ports to CMOS levels
mov !rb,#$00
mov !rc,#$00
mov m,#$0f ; initialize the ports
mov !ra,#ra_dir_mask
mov ra,#ra_data_mask
mov !rb,#rb_dir_mask
mov rb,#rb_data_mask
mov !rc,#rc_dir_mask
mov rc,#rc_data_mask
setb hook ; go on hook.
setb led_pin ; turn on LED
clr flags ; Clear all flags
call zero_ram
retp
;**************************************************************************
; Subroutine - Get byte via serial port and echo it back to the serial port
; INPUTS:
; -NONE
; OUTPUTS:
; -received byte in rx_byte
;**************************************************************************
get_byte jnb rx_flag,$ ;wait till byte is received
clrb rx_flag ;reset the receive flag
bank serial
mov byte,rx_byte ;store byte (copy using W)
; & fall through to echo char back
;**************************************************************************
; Subroutine - Send byte via serial port
; INPUTS:
; w - The byte to be sent via RS-232
;**************************************************************************
send_byte bank serial
:wait test tx_count ;wait for not busy
jnz :wait ;
not w ;ready bits (inverse logic)
mov tx_high,w ; store data byte
setb tx_low.7 ; set up start bit
mov tx_count,#10 ;1 start + 8 data + 1 stop bit
RETP ;leave and fix page bits
;**************************************************************************
; Subroutine - Send string pointed to by address in W register
; INPUTS:
; w - The address of a null-terminated string in program
; memory
; OUTPUTS:
; outputs the string via. RS-232
;**************************************************************************
send_string bank serial
mov string,w ;store string address
:loop mov w,string ;read next string character
mov m,#3 ; with indirect addressing
iread ; using the mode register
mov m,#$F ;reset the mode register
test w ;are we at the last char?
snz ;if not=0, skip ahead
RETP ;yes, leave & fix page bits
call send_byte ;not 0, so send character
inc string ;point to next character
jmp :loop ;loop until done
;**************************************************************************
; Subroutine - Make byte uppercase
; INPUTS:
; byte - The byte to be converted
; OUTPUTS:
; byte - The uppercase byte
;**************************************************************************
uppercase stc
csae byte,#'a' ;if byte is lowercase, then skip ahead
RETP
stc
sub byte,#'a'-'A' ;change byte to uppercase
RETP ;leave and fix page bits
;**************************************************************************
; Subroutine - Disable the outputs
; Load DC value into PPM and disable the output switch.
;**************************************************************************
disable_o
bank PPM_bank ; input mode.
mov D_to_A_val,#128 ; put 2.5V DC on PPM output pin
retp
;**************************************************************************
org $600 ; These subroutines are on page 3.
;**************************************************************************
; DTMF transmit functions/subroutines
;**************************************************************************
;**************************************************************************
DTMF_TABLE ; DTMF tone constants
; This routine returns with the constant used for each of the frequency
; detectors.
; INPUT: w - Index into the table (0-15 value)
; OUTPUT: w - Constant at that index
;**************************************************************************
clc
jmp PC+w
retw f697_l
retw f697_h
retw f770_l
retw f770_h
retw f852_l
retw f852_h
retw f941_l
retw f941_h
retw f1209_l
retw f1209_h
retw f1336_l
retw f1336_h
retw f1477_l
retw f1477_h
retw f1633_l
retw f1633_h
;**************************************************************************
ASCII_TABLE ; Ascii value at index (0-15)
; INPUT: w - Index into the table (0-15 value)
; OUTPUT: w - Constant at that index
;**************************************************************************
clc
jmp PC+w
retw '1'
retw '2'
retw '3'
retw 'A'
retw '4'
retw '5'
retw '6'
retw 'B'
retw '7'
retw '8'
retw '9'
retw 'C'
retw '*'
retw '0'
retw '#'
retw 'D'
;**************************************************************************
index_2_digit
; This subroutine converts a digit from 0-9 or a '*' or a '#' to a table
; lookup index which can be used by the load_frequencies subroutine. To use
; this routine, pass it a value in the 'byte' register. No invalid digits
; are used. (A, B, C, or D)
;**************************************************************************
call ASCII_TABLE
retp
;**************************************************************************
digit_2_index
; This subroutine converts a digit from 0-9 or a '*' or a '#' to a table
; lookup index which can be used by the load_frequencies subroutine. To use
; this routine, pass it a value in the 'byte' register. No invalid digits
; are used. (A, B, C, or D)
;**************************************************************************
bank serial
clr temp
:loop
mov w,temp
call ASCII_TABLE
xor w,byte
jz :done
inc temp
jb temp.4,:done
jmp :loop
:done mov w,temp
retp
;**************************************************************************
load_frequencies
; This subroutine loads the frequencies using a table lookup approach.
; The index into the table is passed in the byte register. The DTMF table
; must be in the range of $400 to $500.
;**************************************************************************
mov temp,w
bank sine_gen_bank
mov w,>>temp
and w,#%00000110
call DTMF_TABLE
mov freq_count_low,w
mov w,>>temp
and w,#%00000110
inc wreg
call DTMF_TABLE
mov freq_count_high,w
rl temp
setb temp.3
mov w,temp
and w,#%00001110
mov temp,w
call DTMF_TABLE
mov freq_count_low2,w
mov w,temp
inc wreg
call DTMF_TABLE
mov freq_count_high2,w
retp
;**************************************************************************
dial_it ; This subroutine puts out whatever frequencies were loaded
; for 1000ms, and then stops outputting the frequencies.
;**************************************************************************
bank sine_gen_bank
clr sine_index
clr sine_index2
enable_o ; enable the output
mov w,#10
call @delay_10n_ms ; delay 30ms
setb dtmf_gen_en
mov w,#12
call @delay_10n_ms ; delay 100ms
clrb dtmf_gen_en
call @disable_o ; now disable the outputs
:end_dial_it retp
;**************************************************************************
sine_generator1 ;(Part of interrupt service routine)
; This routine generates a synthetic sine wave with values ranging
; from -32 to 32. Frequency is specified by the counter. To set the
; frequency, put this value into the 16-bit freq_count register:
; freq_count = FREQUENCY * 6.83671552 (@50MHz)
;**************************************************************************
bank sine_gen_bank
clc
add freq_acc_low,freq_count_low
add freq_acc_high,freq_count_high
sc
jmp :no_change
inc sine_index
mov w,sine_index
and w,#$1f
call sine_table
mov curr_sine,w ;1 ; add the velocity to sin
:no_change
;**************************************************************************
sine_generator2 ;(Part of interrupt service routine)
; This routine generates a synthetic sine wave with values ranging
; from -32 to 32. Frequency is specified by the counter. To set the
; frequency, put this value into the 16-bit freq_count register:
; freq_count = FREQUENCY * 6.83671552 (@50MHz)
;**************************************************************************
bank sine_gen_bank
clc
add freq_acc_low2,freq_count_low2
add freq_acc_high2,freq_count_high2
sc
jmp :no_change
inc sine_index2
mov w,sine_index2
and w,#$1f
call sine_table
mov curr_sine2,w
:no_change
mov D_to_A_val,curr_sine2 ; mov sin2 into PPM0
mov sine2_temp,w ; mov the high_frequency sin wave's current value
clc ; into a temporary register
snb sine2_temp.7 ; divide temporary register by four by shifting right
stc ; (for result = (0.25)(sin2))
rr sine2_temp
clc
snb sine2_temp.7
stc
mov w,>>sine2_temp
clc
add D_to_A_val,w ; (1.25)(sin2) = sin2 + (0.25)(sin2)
add D_to_A_val,curr_sine ; add the value of SIN into the PPM output
add D_to_A_val,#128 ; for result = PPM0 = 1.25*sin2 + 1*sin
retp ; return with page bits intact
;******************************************************************************
sine_table
; The values in this table can be changed to increase/decrease the amplitude of
; the output sine wave.
;******************************************************************************
clc
jmp pc+w
retw 0
retw 4
retw 8
retw 11
retw 14
retw 16
retw 18
retw 19
retw 20
retw 19
retw 18
retw 16
retw 14
retw 11
retw 8
retw 4
retw 0
retw -4
retw -8
retw -11
retw -14
retw -16
retw -18
retw -19
retw -20
retw -19
retw -18
retw -16
retw -14
retw -11
retw -8
retw -4
;**************************************************************************
;******************************************************************************
; Copyright © 1998 Scenix Semiconductor, Inc. All rights
; reserved.
;
; Scenix Semiconductor, Inc. assumes no responsibility or liability for
; the use of this [product, application, software, any of these products].
;
; Scenix Semiconductor conveys no license, implicitly or otherwise, under
; any intellectual property rights.
; Information contained in this publication regarding (e.g.: application,
; implementation) and the like is intended through suggestion only and may
; be superseded by updates. Scenix Semiconductor makes no representation
; or warranties with respect to the accuracy or use of these information,
; or infringement of patents arising from such use or otherwise.
;
; Scenix Semiconductor products are not authorized for use in life support
; systems or under conditions where failure of the product would endanger
; the life or safety of the user, except when prior written approval is
; obtained from Scenix Semiconductor.
;******************************************************************************
file: /Techref/scenix/lib/io/dev/modem/bell_103_full_dup_1_13.SRC, 45KB, , updated: 2002/12/12 08:23, local time: 2024/11/14 17:44,
|
| ©2024 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://linistepper.com/techref/scenix/lib/io/dev/modem/bell_103_full_dup_1_13.SRC"> scenix lib io dev modem bell_103_full_dup_1_13</A> |
Did you find what you needed?
|