$title(ST8000A - STA3.M80) chip(Z80) sm si paginate pagewidth=132

	%include "sta.ver"

; 	File Name:	STA3.M80
;
;------->>> Revision History
;
;$Revision:   1.11  $
;    $Date:   14 Mar 1991 14:31:44  $
;     $Log:   D:\ST8A\STA_VCS\STA3.M8V  $
;  
;     Rev 1.11   14 Mar 1991 14:31:44
;  include default during entry for .0 and .5 from keypad
;  include toggle for either rx_dot5_on or tx_dot5_on
;  include bit test 8 for infinite loop
;  
;     Rev 1.10   05 Mar 1991 21:31:30
;  add routine to set the repeat flag when BIT_8 is selected
;  
;     Rev 1.9   23 Feb 1991  8:41:48
;  change the RTS/TXD state vector when in certain test modes
;  
;     Rev 1.8   22 Feb 1991 22:21:30
;  change T2, T3, and T4 so that they will load the MARK and SPACE
;  latches before the test begins
;  
;     Rev 1.7   22 Feb 1991  8:55:36
;  for T2, T3, and T4, turn ON keyline and tones at beginning
;  then off at the end.
;  
;     Rev 1.6   14 Feb 1991  9:48:30
;  add new assembly control file
;  
;     Rev 1.5   12 Feb 1991 23:19:30
;  minor text fixes
;  
;     Rev 1.4   12 Feb 1991 22:52:20
;  add a new flag to know when a 0 is pressed during number entry
;  previously, it would return CY for 0 or no keypress
;  
;     Rev 1.3   12 Feb 1991 13:20:24
;  use nmi timer for the enter key flash during bit tests...
;  
;     Rev 1.2   11 Feb 1991 22:27:10
;  change the 2nd-BIT-CHAN so that it shows the current settings for the
;  option switches.
;  
;     Rev 1.1   08 Feb 1991  8:16:24
;  add init for BIT MARK to force it into mark state
;  change BIT ALT to use the NMI interrupt instead of background loop
;  nmi runs at 4 times tx_baud rate
;  fix the low pass filter osc init at the end of the test
;  
;     Rev 1.0   03 Feb 1991 21:54:16
;  Initial revision.
;  
;  

; 	include sta.def
; 	include sta.ext
;
$nosi
	%include "sta.def"
	%include "sta.ext"

	%if	debug
	extern	rst_set
	extern	rst_show
	extern	rst_read
	extern	rst_send
	extern	rst_store
	extern	rst_setup
	extern	rst_misc
	%endif

	extern	control_switch_test
	extern	data_rts_state0
	extern	data_rts_test_off
	extern	enter_key_off
	extern	enter_key_on
	extern	enter_toggle_now
	extern	enter_toggle_test
	extern	modem_init
	extern	remote_off_state0
	extern	remote_off_state1
	extern	remote_state1
	extern	start_bit


$allpublic

	defseg	sta3, align=100h, class=code
	seg	sta3

;******************************************************************************
; keypad_process
;******************************************************************************
; keypad handler routines.
;
; the keypad handler is a state machine that processes the keypad entries
; as they arrive in the input buffer.  When called, the next keypress
; is stored in L, and the current state is stored in KEYPAD_STATE
;
; In most states, the available options are selected from a table of the
; valid keypresses at that point.
;
; At the end of each state, a RET will get us back
;
keypad_process:
	mov	a,l			; recover the character in ACC
	lhld	keypad_state		; read the state vector
	pchl				; and process the keypress



;******************************************************************************
; keypad_state0
;******************************************************************************
;
; in state 0, local mode is enabled, and remote mode is disabled.
; we look for selected keys and process them accordingly.
;
; when we get here, the valid key is in acc
;
keypad_state0:
	mov	c,a			; save the search key
	lxi	h,keypad_state0_jtable	; load a pointer to the state table
	mvi	a,key_judge		; set the function
	misc_rst			; call the function
	jnc	keypad_state0a		; if nc, a valid key was found
	ret				;   else return

; we found a match with the command table.
; jump to the routine address in hl
;
keypad_state0a:
	pchl				; hl has the routine address


keypad_state0_jtable:
	db	key_amh			; amh key
	dw	keypad_amh_state1	;  process amh key
	db	key_baud		; baud key
	dw	keypad_baud_state1	;  process baud key
	db	key_chan		; chan key
	dw	keypad_chan_state1	;  process chan key
	db	key_clear		; clear key
	dw	keypad_clear_state1	;  process clear key
	db	key_div			; div key
	dw	keypad_diversity_state1	;  process diversity key
	db	key_dot5		; 0.5 key
	dw	keypad_dot5_state1	;  process 0.5 key
	db	key_enter		; enter key
	dw	keypad_enter_state1	;  process the enter key
	db	key_fsk			; fsk key
	dw	keypad_fsk_state1	;  process the fsk key
	db	key_mark		; mark key
	dw	keypad_mark_state1	;  process the mark key
	db	key_mute		; mute key
	dw	keypad_mute_state1	;  process mute key
	db	key_ms			; mark/space key
	dw	keypad_ms_state1	;  process mark/space key
	db	key_norm		; norm key
	dw	keypad_norm_state1	;  process norm key
	db	key_space		; space key
	dw	keypad_space_state1	;  process the space key
	db	key_remote		; remote key
	dw	keypad_remote_state1	;  process remote key
	db	key_sync		; sync key
	dw	keypad_sync_state1	;  process the sync key
	db	key_2nd			; 2nd function key
	dw	keypad_2nd_state1	;  process 2nd key
	db	-1


;******************************************************************************
; keypad_number_input
;******************************************************************************
;
; utility routine for capturing keypad numbers for mark/space/baud
;
; we will read a 4 digit number from the keypad.
; if ENTER is pressed, return NC and the number in HL
; if CLEAR is pressed, reset modem to saved state and return to idle state
; if 0.5 is pressed, change the display from .0 to .5 or .5 to .0
;
keypad_input_msg0:
	db	'   ',' ' + 80h,'0'	; "    .0"
keypad_input_msg5:
	db	'   ',' ' + 80h,'5'	; "    .5"
keypad_input_blank_msg:
	db	'     '			; "      "

keypad_number_input:
	shld	return_address		; save the return address
	sta	display_fcn_save	; save the current window address

	mvi	a,0			; clear the number flag
	sta	keypad_number_flag	; to see if any key pressed

; we need to read the current dot5 setting to choose the correct
; initial message.  either "    .0"  or  "    .5"
;
	lda	channel			; read the channel number
	cpi	1			; if channel = 1 (RX)
	lda	rx_dot5_on		;     read the rx dot5 flag
	jz	keypad_number_inputa	;   then skip
	lda	tx_dot5_on		;   else read the tx dot5 flag
keypad_number_inputa:
	lxi	h,keypad_input_msg0	; point to the zero message
	ani	1			; if zero we are set for .0
	jz	keypad_number_input1	;   then skip and use .0
	lxi	h,keypad_input_msg5	; point to the .5 message

keypad_number_input1:
	lxi	d,display_buffer	; point to the buffer
	lxi	b,5			; save 5 chars
	ldir				; zap the message

	lxi	h,display_buffer	; show the initial display
	lda	display_fcn_save	; select the window
	show_rst			; and write the display

	lxi	h,keypad_number_state2	; load the next state
	shld	keypad_state

	ret


; here we have received one keypress.
; test to see if it is a number or a special key before including
; it in the buffer.
;
; test for ENTER key
;
keypad_number_state2:
	cpi	key_enter		; if this is not an enter key
	jnz	keypad_number_state2b	;   then skip

	call	enter_key_off		; turn off the enter key

; clear the current setting by blanking the display
;
	lxi	h,keypad_input_blank_msg ; blank the display
	lda	display_fcn_save	; select the window
	show_rst			; and write the display


; the enter key has been pressed.
; we need to convert the ascii string in display_buffer to binary
; then return that value to the routine that called us
;
	mvi	a,display_to_binary	; convert the string to binary
	misc_rst


; we have the new number in hl.
; if the number is 0000 or 1, then no number was entered
; if no number, return CY
; if number entered, return NC and number in DE
;
	xchg				; save the value in de
	mov	a,e			; read the low byte
	ani	0feh			; clear the LSB
	ora	d			; combine with upper byte
	jnz	keypad_number_state2a	; if new number is > 0, return NC

; look to see if any key was pressed
; if so, use the 0000 value
;
	lda	keypad_number_flag	; read the flag
	ana	a			; if flag is <> 0, then key pressed
	jnz	keypad_number_state2a	;   then return NC
	stc				;   else set CY

; return new value in DE
;
keypad_number_state2a:
	lhld	return_address		; recover the return address
	pchl				; and jump to that return address


; test for CLEAR key
;
keypad_number_state2b:
	cpi	key_clear		; if this is not a clear key
	jnz	keypad_number_state2c	;   then skip

; the clear key was pressed.
; we need to ignore this string, and restore the last saved modem state
;
	call	modem_init		; restore the stored state
	lxi	h,keypad_state0		; set to the idle state
	shld	keypad_state		; store the next state pointer
	ret				; and return


; test for 0.5 key
;
keypad_number_state2c:
	cpi	key_dot5		; if this is not 0.5 key
	jnz	keypad_number_state2e	;   then skip

; the 0.5 key has been pressed.
; toggle the .5 display and the dot5_on flag
;
	lda	channel			; load the channel flag
	cpi	1			; if channel = 1 (RX)
	jz	keypad_number_state2c1	;    then skip

	lda	tx_dot5_on		; read the 0.5 flag
	xri	1			; flip that bit
	ani	1			; save one bit
	sta	tx_dot5_on		; store the revised value
	jmp	keypad_number_state2c2	; continue

keypad_number_state2c1:
	lda	rx_dot5_on		; read the 0.5 flag
	xri	1			; flip that bit
	ani	1			; save one bit
	sta	rx_dot5_on		; store the revised value

keypad_number_state2c2:
	ani	1			; if zero, we are set for .0
	mvi	a,'0'			;     set the default to .0
	jz	keypad_number_state2d	;   then use the default
	mvi	a,'5'			;   else set to .5
keypad_number_state2d:
	sta	display_buffer + 4	; store the new digit
	jmp	keypad_number_state2f	; show the new setting


; test to see if this is a number key
;
keypad_number_state2e:
	cpi	9 + 1			; if this key is > 9
	rnc				;   then ignore it

; here we have a valid number in ACC.
; shift the display to the left one digit and
; add the ascii numebr to the display buffer
; show the new number in the display buffer
;
	lhld	display_buffer + 1	; read digits 2 and 3
	shld	display_buffer		; shift them left one digit
	lhld	display_buffer + 3	; now, read digits 4 and 5
	ori	'0' + 80h		; make the character ascii, add period
	mov	h,a			; save this new digit
	mov	a,l			; remove the period from this digit
	ani	7fh			; save 7 bits
	mov	l,a			; restore the character
	shld	display_buffer + 2	; save these digits

	mvi	a,1			; set the number key pressed flag
	sta	keypad_number_flag	; so we know that a key was pressed

keypad_number_state2f:
	lxi	h,display_buffer	; now, show the new number
	lda	display_fcn_save	; read the window
	show_rst			; show it

	ret				; and return


;******************************************************************************
; keypad_off_state0
;******************************************************************************
;
; the remote port is active.  The only key that is active at this time
; on the keypad is REMOTE.  Ignore all other keys.
;
keypad_off_state0:
	cpi	key_remote		; if the keypad remote is pressed
	jz	local_on_entry		;   then turn ON keypad again
	ret				;   else return and ignore


;******************************************************************************
; keypad_amh_state1
;******************************************************************************
;
; the amh key has been pressed.
; we must read the current state of amh and toggle it
;
keypad_amh_state1:
	call	enter_key_on		; turn ON enter

	lda	rx_amh_on		; read the current setting
	ana	a			; if amh is off
	jz	keypad_amh_state1b	;   then turn it on

; here we have to turn amh OFF, clear the control bit
; and turn OFF the led
;
keypad_amh_state1a:
	mvi	l,0			; set the option for off
	mvi	a,setup_rx_amh		; set the function
	setup_rst			; call the function
	ret				; then exit

; here we have to turn amh ON, set the control bit
; and turn ON the led
;
keypad_amh_state1b:
	mvi	l,1			; set the option for off
	mvi	a,setup_rx_amh		; set the function
	setup_rst			; call the function
	ret				; then exit


;******************************************************************************
; keypad_baud_state1
;******************************************************************************
;
; this routine accepts a new baud rate for the selected channel.
;
; blank the display, then wait for numbers, enter, or clear.
; if no numbers are pressed, do not change the present value
; if numbers entered, use that value
; if clear pressed, return to the default setting
;
keypad_baud_state1:
	call	enter_key_on		; turn ON the enter

	lxi	h,keypad_baud_state2	; load a return address
	mvi	a,show_baud_ascii	; load the function
	call	keypad_number_input	; call the input routine
	ret

; if a new rate was entered, we will return here
; if NC, then a valid binary number is in de
; if CY, then just restore the old rate
;
keypad_baud_state2:
	jnc	keypad_baud_state2a	; NC means a valid rate * 2 is in hl

; a new freq was not loaded.  just restore the old display
;
	mvi	a,show_baud		; load the function type
	show_rst			; call the function

	lxi	h,keypad_state0		; set the idle state
	shld	keypad_state		; store the next state
	ret

; a new rate was entered.  since this value is 2 times what
; is needed for the rate, we must divide the value in de by 2
;
keypad_baud_state2a:
	xchg				; put the new freq in hl
	ana	a			; clear cy then divde hl/2
	rarr	h			; divide upper byte by 2
	rarr	l			; divide lower byte by 2
	lda	channel			; read the selected channel
	cpi	1			; if channel 1 is selected
	mvi	a,setup_rx_baud		;     set default to rx baud rate
	jz	keypad_baud_state2b	;   then skip
	mvi	a,setup_tx_baud		;   else set the tx baud rate
keypad_baud_state2b:
	setup_rst			; set the baud rate

	mvi	a,save_config		; save the configuration
	misc_rst

	mvi	a,show_baud		; now, show the rate
	show_rst			; call the function

	lxi	h,keypad_state0		; set the idle state
	shld	keypad_state		; store the next state
	ret


;******************************************************************************
; keypad_chan_state1
;******************************************************************************
;
; the channel key has been pressed.
; toggle to the other channel and save the new state immediately
;
keypad_chan_state1:

; read the current channel and toggle to the other channel
;
	lda	channel			; read the current channel
	cpi	1			; if this is channel 1
	mvi	l,2			;      load default of 2
	jz	keypad_chan_state1a	;   then use default chan 2
	mvi	l,1			;   else load to channel 1
keypad_chan_state1a:

; at this point, L has the new channel number
;
	mvi	a,setup_channel		; setup the channel - L has 1 or 2
	setup_rst			; call the function

	mvi	a,show_led_status	; update led status
	show_rst			; call the function

	mvi	a,show_channel		; and restore the front panel
	show_rst			; call the function

	mvi	a,show_freq		; show mark space
	show_rst			; call the function

	mvi	a,show_baud		; finally, show the baud
	show_rst			; call the function

	call	enter_key_off		; turn off the enter key

	mvi	a,save_config		; save the configuration
	misc_rst

	lxi	h,keypad_state0		; set to initial keypad state
	shld	keypad_state		; to read the next character

	ret				; and we are done...


;******************************************************************************
; keypad_clear_state1
;******************************************************************************
;
; when the clear key is pressed, re-read the contents of the eeprom memory
; and use them to init all parameters.
;
keypad_clear_state1:
	call	modem_init		; init the modem
	ret				; and return


;******************************************************************************
; keypad_diversity_state1
;******************************************************************************
;
; the div key has been pressed.
; we must read the current state of div and toggle it
;
keypad_diversity_state1:
	%if	diversity
; if DIVERSITY OPTION is installed, then turn ON the enter key and
; toggle the current setting.
;
	call	enter_key_on		; turn ON enter

	lda	rx_diversity_on		; read the current setting
	ana	a			; if diversity is off
	jz	keypad_diversity_state1b ;   then turn it on
	%endif

; here we have to turn diversity OFF, clear the control bit
; and turn OFF the led
;
keypad_diversity_state1a:
	mvi	l,0			; set the option for off
	mvi	a,setup_rx_diversity	; set the function
	setup_rst			; call the function
	ret				; then exit

	%if	diversity
; if DIVERSITY OPTION is installed, then we can turn it ON.
;
; here we have to turn diversity ON, set the control bit
; and turn ON the led
;
keypad_diversity_state1b:
	mvi	l,1			; set the option for off

	mvi	a,setup_rx_diversity	; set the function
	setup_rst			; call the function
	ret				; then exit
	%endif

;******************************************************************************
; keypad_dot5_state1
;******************************************************************************
;
; when the .5 key is pressed, we need to toggle the LSB of the selected
; channel MARK and SPACE frequencies, then show the new values.
;
keypad_dot5_state1:
	call	enter_key_on		; turn ON the enter key

; toggle the dot5_on flag
;
	lda	channel			; read the current channel
	cpi	1			; if this is channel 1 RX
	jz	keypad_dot5_state1a

; we have channel 2 selected - the TX channel
;
	lda	tx_dot5_on		; read the 0.5 flag
	xri	1			; flip that bit
	ani	1			; save one bit
	sta	tx_dot5_on		; store the revised value
	mov	b,a			; save the new flag in b

	lhld	tx_mark_freq		; read the transmit mark
	mov	a,l			; read the low byte
	ani	0feh			; clear LSB
	ora	b			; set the new 0.5 bit
	mov	l,a			; restore the mark freq
	mvi	a,setup_tx_mark		; and set the new transmit freq
	setup_rst

	lhld	tx_space_freq		; read the transmit space
	mov	a,l			; read the low byte
	ani	0feh			; clear LSB
	ora	b			; set the new 0.5 bit
	mov	l,a			; restore the space freq
	mvi	a,setup_tx_space	; and set the new transmit freq
	setup_rst

	mvi	a,show_freq		; update the front panel display
	show_rst			; call the routine
	ret				; and return


; we have channel 1 selected - the RX channel
;
keypad_dot5_state1a:
	lda	rx_dot5_on		; read the 0.5 flag
	xri	1			; flip that bit
	ani	1			; save one bit
	sta	rx_dot5_on		; store the revised value
	mov	b,a			; save the new flag in b

	lhld	rx_mark_freq		; read the transmit mark
	mov	a,l			; read the low byte
	ani	0feh			; clear LSB
	ora	b			; set the new 0.5 bit
	mov	l,a			; restore the mark freq
	mvi	a,setup_rx_mark		; and set the new transmit freq
	setup_rst

	lhld	rx_space_freq		; read the transmit space
	mov	a,l			; read the low byte
	ani	0feh			; clear LSB
	ora	b			; set the new 0.5 bit
	mov	l,a			; restore the space freq
	mvi	a,setup_rx_space	; and set the new transmit freq
	setup_rst

	mvi	a,show_freq		; update the front panel display
	show_rst			; call the routine
	ret				; and return


;******************************************************************************
; keypad_enter_state1
;******************************************************************************
;
; the enter key has been pressed.
; for now, just turn OFF the front panel led.
; eventually, we need to store the new configuration here.....
;
keypad_enter_state1:
	call	enter_key_off		; turn ON enter

	lda	config_changed		; read the changed flag
	ana	a			; if no change in parameters
	rz				;    then return
	mvi	a,save_config		;    else save configuration
	misc_rst			;         call the function

	ret				; and return


;******************************************************************************
; keypad_fsk_state1
;******************************************************************************
;
; the fsk key has been pressed.
; we must read the current state of fsk and toggle it
;
keypad_fsk_state1:
	call	enter_key_on		; turn ON enter

; here we have to turn rx fsk ON, clear the control bit
; and turn ON the led to show M/S for receiver
;
	mvi	l,0			; set the option for ON
	mvi	a,setup_rx_mode		; set the function
	setup_rst			; call the function
	ret				; then exit


;******************************************************************************
; keypad_mark_state1
;******************************************************************************
;
; this routine accepts a new mark rate for the selected channel.
;
; blank the display, then wait for numbers, enter, or clear.
; if no numbers are pressed, do not change the present value
; if numbers entered, use that value
; if clear pressed, return to the default setting
;
keypad_mark_state1:
	call	enter_key_on		; turn ON the enter

	lxi	h,keypad_mark_state2	; load a return address
	mvi	a,show_mark_ascii	; load the function
	call	keypad_number_input	; call the input routine
	ret

; if a new rate was entered, we will return here
; if NC, then a valid binary number is in de
; if CY, then just restore the old rate
;
keypad_mark_state2:
	jnc	keypad_mark_state2a	; NC means a valid rate * 2 is in hl

; a new freq was not loaded.  just restore the old display
;
	mvi	a,show_freq		; load the function type
	show_rst			; call the function

	lxi	h,keypad_state0		; set the idle state
	shld	keypad_state		; store the next state
	ret

; a new mark frequency is in DE.
; setup either TX or RX based on the current channel selection
;
keypad_mark_state2a:
	xchg				; put the new freq in hl

	lda	channel			; read the selected channel
	cpi	1			; if channel 1 is selected
	jz	keypad_mark_state2c	;   then process RX

; channel 2 TX is selected.
; we must see whether to use this new value for tx mark or tx center
;
	lda	show_center_on		; read the current flag
	ana	a			; if 0, then select tx mark
	jz	keypad_mark_state2b	;   then skip

; setup tx center
;
	mvi	a,setup_tx_center	; set the tx center
	setup_rst			; setup the new center
	jmp	keypad_mark_state2e	; display the new values

; setup tx mark
; we have to make sure that the .5 offset on the new space matches
; the current offset on mark.  the shift must be 1.0 hz increments
;
keypad_mark_state2b:
	mov	a,l			; read the low space value
	ani	1			; save only the .5 hz bit
	mov	c,a			; save this bit
	lda	tx_space_freq		; read the space freq
	ani	0feh			; clear the low bit
	ora	c			; combine with space .5 offset
	sta	tx_space_freq		; and restore the value

	mvi	a,setup_tx_mark		; set tx mark - hl has freq * 2
	setup_rst			; setup the new mark

	lhld	tx_space_freq		; now, setup space
	mvi	a,setup_tx_space	; set tx space - hl has freq * 2
	setup_rst			; setup the new mark

	jmp	keypad_mark_state2e	; display the new values


; channel 1 RX is selected.
; we must see whether to use this new value for tx mark or tx center
;
keypad_mark_state2c:
	lda	show_center_on		; read the current flag
	ana	a			; if 0, then select rx mark
	jz	keypad_mark_state2d	;   then skip

; setup rx center
;
	mvi	a,setup_rx_center	; set the rx center
	setup_rst			; setup the new center
	jmp	keypad_mark_state2e	; display the new values

; setup rx mark
; we have to make sure that the .5 offset on the new space matches
; the current offset on mark.  the shift must be 1.0 hz increments
;
keypad_mark_state2d:
	mov	a,l			; read the low space value
	ani	1			; save only the .5 hz bit
	mov	c,a			; save this bit
	lda	rx_space_freq		; read the space freq
	ani	0feh			; clear the low bit
	ora	c			; combine with space .5 offset
	sta	rx_space_freq		; and restore the value

	mvi	a,setup_rx_mark		; set tx mark - hl has freq * 2
	setup_rst			; setup the new space

	lhld	rx_space_freq		; now, setup space
	mvi	a,setup_rx_space	; set tx space - hl has freq * 2
	setup_rst			; setup the new mark


; show new mark and space
;
keypad_mark_state2e:
	mvi	a,save_config		; save the configuration
	misc_rst

	mvi	a,show_freq		; show the mark/space
	show_rst			; call the function

	lxi	h,keypad_state0		; set the idle state
	shld	keypad_state		; store the next state
	ret


;******************************************************************************
; keypad_mute_state1
;******************************************************************************
;
; the mute key has been pressed.
; we must read the current state of mute and toggle it
;
keypad_mute_state1:
	call	enter_key_on		; turn ON enter

	lda	tx_mute_on		; read the current setting
	ana	a			; if mute is off
	jz	keypad_mute_state1b	;   then turn it on

; here we have to turn mute OFF, clear the control bit
; and turn OFF the led
;
keypad_mute_state1a:
	mvi	l,0			; set the option for off
	mvi	a,setup_tx_mute		; set the function
	setup_rst			; call the function
	ret				; then exit

; here we have to turn mute ON, set the control bit
; and turn ON the led
;
keypad_mute_state1b:
	mvi	l,1			; set the option for off

	mvi	a,setup_tx_mute		; set the function
	setup_rst			; call the function
	ret				; then exit


;******************************************************************************
; keypad_norm_state1
;******************************************************************************
;
; return the selected channel to NORMAL.
;
keypad_norm_state1:
	call	enter_key_on		; turn ON enter

	lda	channel			; read the channel
	cpi	1			; if channel = 1 RX
	jz	keypad_norm_state1a	;   then set RX channel

; set channel 2 TX to normal shift
;
	mvi	l,0			; clear the flag
	mvi	a,setup_tx_reverse	; load the function
	setup_rst			; call the function

	jmp	keypad_norm_state1b	; now, turn OFF the led


; set channel 1 RX to normal shift
;
keypad_norm_state1a:
	mvi	l,0			; clear the flag
	mvi	a,setup_rx_reverse	; load the function
	setup_rst			; call the function

; in both cases, turn OFF the front panel led
;
keypad_norm_state1b:
	lxi	h,led_reverse_b		; point to the led
	mvi	a,show_led_off		; and turn OFF the led
	show_rst

	ret				; then return


;******************************************************************************
; keypad_ms_state1
;******************************************************************************
;
; change the display to mark/space, and update the display
; reset the keypad state pointer to idle state
;
keypad_ms_state1:
	mvi	a,0			; enable show mark/space
keypad_cent_state3_entry:
	sta	show_center_on		; save this flag

	mvi	a,show_freq		; now, show the new display
	show_rst

	call	enter_key_off		; turn off the enter key

	mvi	a,save_config		; save the configuration
	misc_rst

	lxi	h,keypad_state0		; reset to idle state
	shld	keypad_state		; store the next state

	ret				; and return


;******************************************************************************
; keypad_remote_state1
;******************************************************************************
;
; the remote key has been pressed.
; we must read the current state of remote and toggle it
;
keypad_remote_state1:
	lda	remote_port_on		; read the current setting
	ana	a			; if remote port is off
	jz	keypad_remote_state1c	;   then turn it on

; here we need to turn the remote port off
; and turn the keypad ON
;
local_on_entry:
keypad_remote_state1a:
	mvi	l,0			; set port flag to 0
	mvi	a,setup_remote_on	; load the function
	setup_rst			; call the function

; set the keypad state to the initial vector
;
	lxi	h,keypad_state0		; set the initial state vector
	shld	keypad_state		; store the new state vector

; and disable the remote port
;
	lda	remote_channel		; see if channel is selected
	ana	a			; if z, then no channel is selected
	lxi	h,remote_off_state0	;     set default to not selected
	jz	keypad_remote_state1b	;   then use the default
	lxi	h,remote_off_state1	;   else set to selected
keypad_remote_state1b:
	shld	remote_state		; store the new state vector

	call	enter_key_off		; turn off the enter key

	mvi	a,save_config		; save this configuration
	misc_rst			; call the function

	ret				; and return


; here we need to turn the remote port ON
; we need to turn ON the led and enable the remote port
;
remote_on_entry:
keypad_remote_state1c:
	mvi	l,1			; set select flag to 1
	mvi	a,setup_remote_on	; load the function
	setup_rst			; call the function

; we need to point the keypad handler at the idle or off routine
;
	lxi	h,keypad_off_state0	; set to the idle state
	shld	keypad_state		; set the new state vector

; if a remote port is currently selected, we need to set the remote
; port state to on-line mode.  if no remote port is selected, then
; we go to not selected mode.
;
	lda	remote_channel		; see if channel is selected
	ana	a			; if z, then no channel is selected
	lxi	h,remote_off_state0	;     set default to not selected
	jz	keypad_remote_state1d	;   then use the default
	lxi	h,remote_state1		;   else set to remote-selected
keypad_remote_state1d:
	shld	remote_state		; store the new state vector

	call	enter_key_off		; turn off the enter key

	mvi	a,save_config		; save this configuration
	misc_rst			; call the function

	ret				; and return


;******************************************************************************
; keypad_space_state1
;******************************************************************************
;
; this routine accepts a new space freq for the selected channel.
;
; blank the display, then wait for numbers, enter, or clear.
; if no numbers are pressed, do not change the present value
; if numbers entered, use that value
; if clear pressed, return to the default setting
;
keypad_space_state1:
	call	enter_key_on		; turn ON the enter

	lxi	h,keypad_space_state2	; load a return address
	mvi	a,show_space_ascii	; load the function
	call	keypad_number_input	; call the input routine
	ret

; if a new rate was entered, we will return here
; if NC, then a valid binary number is in de
; if CY, then just restore the old rate
;
keypad_space_state2:
	jnc	keypad_space_state2a	; NC means a valid freq * 2 is in hl

; a new freq was not loaded.  just restore the old display
;
	mvi	a,show_freq		; load the function type
	show_rst			; call the function

	lxi	h,keypad_state0		; set the idle state
	shld	keypad_state		; store the next state
	ret

; a new space frequency is in DE.
; setup either TX or RX based on the current channel selection
;
keypad_space_state2a:
	xchg				; put the new freq in hl

	lda	channel			; read the selected channel
	cpi	1			; if channel 1 is selected
	jz	keypad_space_state2c	;   then process RX

; channel 2 TX is selected.
; we must see whether to use this new value for tx space or tx shift
;
	lda	show_center_on		; read the current flag
	ana	a			; if 0, then select tx space
	jz	keypad_space_state2b	;   then skip

; setup tx shift
; since the shift can only be 1.0 hz increments, mask the low bit
;
	mov	a,l			; mask shift to 1 Hz change
	ani	0feh			; clear lower bit
	mov	l,a			; restore the shift
	mvi	a,setup_tx_shift	; set the tx shift
	setup_rst			; setup the new space
	jmp	keypad_space_state2e	; display the new values


; setup tx space
; we have to make sure that the .5 offset on the new space matches
; the current offset on mark.  the shift must be 1.0 hz increments
;
keypad_space_state2b:
	mov	a,l			; read the low space value
	ani	1			; save only the .5 hz bit
	mov	c,a			; save this bit
	lda	tx_mark_freq		; read the mark freq
	ani	0feh			; clear the low bit
	ora	c			; combine with space .5 offset
	sta	tx_mark_freq		; and restore the value

	mvi	a,setup_tx_space	; set tx space - hl has freq * 2
	setup_rst			; setup the new space

	lhld	tx_mark_freq		; now, setup mark
	mvi	a,setup_tx_mark		; set tx mark - hl has freq * 2
	setup_rst			; setup the new mark

	jmp	keypad_space_state2e	; display the new values


; channel 1 RX is selected.
; we must see whether to use this new value for tx space or tx shift
;
keypad_space_state2c:
	lda	show_center_on		; read the current flag
	ana	a			; if 0, then select rx space
	jz	keypad_space_state2d	;   then skip

; setup rx shift
; since the shift can only be 1.0 hz increments, mask the low bit
;
	mov	a,l			;   else mask shift to 1 Hz change
	ani	0feh			;        clear lower bit
	mov	l,a			;        restore the shift
	mvi	a,setup_rx_shift	;        set the rx shift
	setup_rst			; setup the new space
	jmp	keypad_space_state2e	; display the new values


; setup rx space
; we have to make sure that the .5 offset on the new space matches
; the current offset on mark.  the shift must be 1.0 hz increments
;
keypad_space_state2d:
	mov	a,l			; read the low space value
	ani	1			; save only the .5 hz bit
	mov	c,a			; save this bit
	lda	rx_mark_freq		; read the mark freq
	ani	0feh			; clear the low bit
	ora	c			; combine with space .5 offset
	sta	rx_mark_freq		; and restore the value

	mvi	a,setup_rx_space	; set rx space - hl has freq * 2
	setup_rst			; setup the new space

	lhld	rx_mark_freq		; now, setup mark
	mvi	a,setup_rx_mark		; set rx mark - hl has freq * 2
	setup_rst			; setup the new mark


; show new center and shift
;
keypad_space_state2e:
	mvi	a,save_config		; save the configuration
	misc_rst

	mvi	a,show_freq		; show the space/space
	show_rst			; call the function

	lxi	h,keypad_state0		; set the idle state
	shld	keypad_state		; store the next state
	ret


;******************************************************************************
; keypad_sync_state1
;******************************************************************************
;
; when the sync key is pressed, we toggle between SYNC ON and ASYNC.
;
; If currently SYNC ON, then turn off the led, and prompt for length
; in the BAUD window.  After accepting the new length, restore the display.
; If currently ASYNC, just turn SYNC ON and turn ON the LED.
;
async_prompt_msg:
	db	'L=  '

keypad_sync_state1:
	call	enter_key_on		; turn ON the enter key

	lda	rx_sync_on		; read the current sync setting
	cpi	1			; if sync = 1
	jz	keypad_sync_off		;   then turn sync off

; we need to turn sync ON
;
	mvi	a,show_baud		; make certain the baud rate is there
	show_rst			; call the function

	mvi	l,0			; turn ON sync
	mvi	a,setup_rx_sync_async	; load the function
	setup_rst			; call the function

	lxi	h,keypad_state0		; return to idle state
	shld	keypad_state		; set the next state

	ret				; and return	


; here we need to turn sync off, and turn ON ASYNC.
; first, turn OFF the led, then prompt for new length
;
keypad_sync_off:
	mvi	a,0			; clear the sync flag
	sta	rx_sync_on		; store the new state

; turn OFF the led
;
	lxi	h,led_sync_b		; point to the led
	mvi	a,show_led_off		; turn off the led
	show_rst			; call the function

; turn OFF the control lead
;
	lxi	h,ctrl_rsync_b		; point to the control lead
	mvi	a,set_control_clear	; turn off the lead
	set_rst				; call the function

; now, show the current length in the baud display
; this is the entry point for setting the length of the regen
; characters
;
keypad_regen_on_entry:
	lxi	h,async_prompt_msg	; load the message
	lxi	d,display_buffer	; point to the destination
	lxi	b,4			; zap the message
	ldir				; into the buffer

	lda	rx_async_length		; read the current length
	adi	'0'			; make it ascii
	sta	display_buffer + 2	; save it in the buffer

	lxi	h,display_buffer	; now show the message
	mvi	a,show_baud_ascii	; load the function
	show_rst			; call the function

	lxi	h,keypad_sync_state2	; load the next state
	shld	keypad_state		; set the next state

	ret				; then return

; we have received a keypress for the length.
; if this is ENTER, use the current setting and setup the port length
; if this is CLEAR, restore from eeprom
; if this is SYNC, start this process over again
; if this is a number 5 - 8, set the new length
;
keypad_sync_state2:
	cpi	key_enter		; if this is not an enter
	jnz	keypad_sync_state2a	;   then skip to the next test

; the enter key has been pressed.
; load the current setting and setup the port
; save this new configuration
;
	call	enter_key_off		; turn off the enter key

; clear the display window
;
	lxi	h,keypad_input_blank_msg ; blank the display
	mvi	a,show_baud_ascii	; load the function
	show_rst			; call the function

; save this new configuration
;
	mvi	a,save_config		; save this configuration
	misc_rst			; call the function

	mvi	a,show_baud		; restore the configuration
	show_rst

	lxi	h,keypad_state0		; reset to the idle state
	shld	keypad_state
	ret


; test for CLEAR key
;
keypad_sync_state2a:
	cpi	key_clear		; if this is not clear
	jnz	keypad_sync_state2b	;   then skip

; the CLEAR key was pressed.
;
	call	modem_init		; restore the eeprom state

	lxi	h,keypad_state0		; restore the idle state
	shld	keypad_state
	ret				; and return


; test for SYNC key
;
keypad_sync_state2b:
	cpi	key_sync		; if sync key is pressed
	jz	keypad_sync_state1	;   then let's do it again


; test for a number between 5 and 8
;
	cpi	5			; if the number is less than 5
	rc				;   then return
	cpi	8 + 1			; if the number is greater than 8
	rnc				;   then return

; we have received a valid number, so show that number in the display
; and store the number in the length variable
;
	sta	rx_async_length		; save this length
	ori	'0'			; make the number ascii
	sta	display_buffer + 2	; save it in the display buffer

	lxi	h,display_buffer	; now, show the new value
	mvi	a,show_baud_ascii	; load the function
	show_rst			; call the function

; setup the new regen length
;
	lda	rx_async_length		; read the length
	mov	l,a			; put that length in l
	mvi	a,setup_rx_sync_async	; load the function
	setup_rst			; call the function

	ret				; and return


;******************************************************************************
; keypad_2nd_state1
;******************************************************************************
;
; the second key has been pressed.  we must wait for the next key to
; see what function is selected.
;
; if a key is pressed without a valid second function, the process will do
; nothing and return to the idle state
;
keypad_2nd_state1:
	lxi	h,keypad_2nd_state2	; load the next state
	shld	keypad_state		; store the next state
	ret				; and return

; we have received the next key after a 2nd keypress.
; test this key to see if it is valid, and process.
; if not valid, just return to idle state.
; if another 2nd is pressed, just wait here
;
keypad_2nd_state2:
	mov	c,a			; save the keypress in c
	lxi	h,keypad_2nd_jtable	; load a pointer to the key table
	mvi	a,key_judge		; set the function
	misc_rst			; call the function
	jnc	keypad_2nd_state2a	; if nc, we have a valid function
	lxi	h,keypad_state0		;   else load idle state
	shld	keypad_state		;        store the next state
	ret				; and return

; we have a valid key.
; jump to the routine
;
keypad_2nd_state2a:
	pchl				; hl has the routine

keypad_2nd_jtable:
	db	key_bit			; bit key
	dw	keypad_bit_state3	;  process the bit key
	db	key_cent		; center/shift key
	dw	keypad_cent_state3	;  process the center key
	db	key_chan		; chan
	dw	keypad_chan_state3	;  process the chan key
	db	key_hold		; hold key
	dw	keypad_hold_state3	;  process the hold key
	db	key_mkonly		; mark only key
	dw	keypad_mkonly_state3	;  process mark only key
	db	key_regen		; regen key
	dw	keypad_regen_state3	;  process regen key
	db	key_rev			; reverse key
	dw	keypad_rev_state3	;  process reverse key
	db	key_sponly		; space only key
	dw	keypad_sponly_state3	;  process space only key
	db	key_2nd			; 2nd function key
	dw	keypad_2nd_state3	;  process the second key
	db	-1


;******************************************************************************
; keypad_bit_state3
;******************************************************************************
;
; the BIT was pressed, so wait for either the test number or
; and ENTER key.
;
; we have several valid bit tests that depend on the next key pressed.
;	ENTER  = full BIT test - pass 1 to start_bit
;	1      = full BIT test - pass 1 to start_bit
;	2      = constant MARK tone
;	3      = constant SPACE tone
;	4      = alternating MARK/SPACE at tx baud rate
;	5      = loopback  0 dBm
;	6      = loopback -20 dBm
;	7      = loopback -40 dBm
;	8      = continuous BIT test
;	9      = BIT test menu (remote port only)
;	.5     = remote port echo 'E'
;	remote = send QBF to remote port 't'
;	chan   = show current internal settings 'C'
;
keypad_bit_msg:
	db	'bit '

keypad_bit_state3:
	call	enter_key_on		; turn ON enter

	mvi	a,1			; set the default test to BIT
	sta	temp_key		; save this default test

	lxi	h,keypad_bit_msg	; zap a message to display buffer
	lxi	d,display_buffer	; destination in buffer
	lxi	b,4			; four characters
	ldir				; zap

	lxi	h,display_buffer	; point to the buffer
	mvi	a,show_baud_ascii	; show the ascii string
	show_rst			; call the function

	lxi	h,keypad_bit_state4	; load the next state
	shld	keypad_state		; store the next state
	ret				; and exit


; if ACC is a number between 1 and 9, save the character and wait for enter
; if ENTER, look to see what test to perform.
; if any other character, ignore it.
; if clear, return to idle
;
keypad_bit_state4:
	cpi	key_enter		; if this key is enter
	jz	keypad_bit_state4b	;   then jump to the test

; if the clear key is pressed, return to idle
; do not do a test.
;
	cpi	key_clear		; if this key is not clear
	jnz	keypad_bit_state4a	;   then skip

; clear key was pressed
;
	mvi	a,show_baud		;   else update the baud display
	show_rst			;        call the function

	call	enter_key_off		;        turn off the enter key

	lxi	h,keypad_state0		;        set to the idle state
	shld	keypad_state		;        set the next state vector
	ret				;        and return


keypad_bit_state4a:
	ana	a			; if key = 0
	rz				;   then ignore it
	mov	c,a			; save this character
	cpi	8 + 1			; if key <= 8
	jc	keypad_bit_state4_cont	;   then use the key

	mvi	c,'E'			; set character to E
	cpi	key_dot5		; if equal 0.5 - for echo
	jz	keypad_bit_state4_cont	;   then use it

	mvi	c,'C'			; set character to c
	cpi	key_chan		; if equal chan - show config
	jz	keypad_bit_state4_cont	;   then use it

	mvi	c,'r'			; set character to remote
	cpi	key_remote		; if not equal remote
	rnz				;   then return


; here we have a valid key from 1 to 7
;
keypad_bit_state4_cont:
	sta	temp_key		; save this keypress
	mov	a,c			; recover the display character
	sta	display_buffer + 3	; save in display buffer

	lxi	h,display_buffer	; point to the buffer
	mvi	a,show_baud_ascii	; show the ascii string
	show_rst			; call the function

	ret				; and return


; we have received an ENTER.  read the last key and
; send it to the bit test.
;
;
keypad_bit_state4b:

; the other tests are internal tests
; once started, the test remains until another keypress is received
; which terminates the test.
;
;	1      = internal bit test
;	2      = constant MARK tone
;	3      = constant SPACE tone
;	4      = alternating MARK/SPACE at tx baud rate
;	5      = loopback  0 dBm
;	6      = loopback -20 dBm
;	7      = loopback -40 dBm
;	0.5    = remote port echo test
;	remote = qbf test
;	chan   = current internal switch status
;
	lxi	h,keypad_bit_state5	; load the idle state
	shld	keypad_state		; set the next state pointer

; choose the test
;
	lda	temp_key		; read the test routine
	mov	c,a			; save it in c for judge
	lxi	h,keypad_bit_jtable	; load the table start
	mvi	a,key_judge		; load the function
	misc_rst			; call the function
	jc	keypad_bit_state5	; if not valid, terminate the test

; we have a valid command key
;
	lda	temp_key		; read the current test selection
	sta	bit_test_active		; and save it
	pchl				; jump to the routine


; bit command table
;
keypad_bit_jtable:
	db	1			; if this is bit test
	dw	start_bit		;   then do internal bit
	db	2			; if constant mark
	dw	keypad_bit_state4c	;   then do it
	db	3			; if constant mark
	dw	keypad_bit_state4d	;   then do it
	db	4			; if alternating mark/space
	dw	keypad_bit_state4e	;   then do it
	db	5			; if loopback enable 0 dBm
	dw	keypad_bit_state4f	;   then do it
	db	6			; if loopback enable -20 dBm
	dw	keypad_bit_state4g	;   then do it
	db	7			; if loopback enable -45 dBm
	dw	keypad_bit_state4h	;   then do it
	db	8			; if set for repeated BIT
	dw	keypad_bit_state4i	;   then do it
	db	key_dot5		; if echo test
	dw	keypad_bit_dot5		;   then do it
	db	key_remote		; if remote QBF
	dw	keypad_bit_remote	;   then do it
	db	key_chan		; if channel
	dw	keypad_bit_chan		;   then show the internal status
	db	-1


; set constant mark
;
keypad_bit_mark_msg:
	db	31h,01h,01h,01h		; set display to mark

remote_bit_mark:
keypad_bit_state4c:
	lxi	h,keypad_bit_mark_msg	; load a string
	mvi	a,show_baud_string	; load the string output function
	show_rst			; call the function

	lxi	h,ctrl_txdrev_b		; clear the reverse bit for MARK
	mvi	a,set_control_clear	; load the function
	set_rst				; call the function

; before we return, turn ON keyline and turn OFF mute.
; the tones are turned ON even if MUTE is ON - this is a test mode
;
keypad_bit_tones:
	mvi	l,1			; turn ON keyline
	mvi	a,setup_keyline		; load keyline function
	setup_rst			; call the function

	lxi	h,ctrl_mute_b		; load a pointer to the mute
	mvi	a,set_control_clear	; load the clear bit function
	set_rst				; call the function

; we will load the saved mark and space constants always, even tho the
; tones may already be active.  If MUTE is ON, then these latches
; will be set to 0000h
;
	lhld	tx_mark_save		; read the mark constant
	shld	tx_mark_mw		; latch the mark constant
	lhld	tx_space_save		; read the space constant
	shld	tx_space_mw		; latch the space constant

; we also set a state vector for the keyline test to disable RTS and
; TXD input
;
	lxi	h,data_rts_test_off	; load the idle address
	shld	data_rts_state		; save this state

	ret


; set constant space
;
keypad_bit_space_msg:
	db	38h,08h,08h,08h		; set display to space

remote_bit_space:
keypad_bit_state4d:
	lxi	h,keypad_bit_space_msg	; load a string
	mvi	a,show_baud_string	; load the string output function
	show_rst			; call the function

	lxi	h,ctrl_txdrev_b		; load the reverse bit
	mvi	a,set_control_set	; load the function
	set_rst				; call the function

	jmp	keypad_bit_tones	; and turn ON keyline and tones


; send alternating mark/space at tx baud rate
;
; here we will load the nmi timer with a value equal to the data
; rate * 4 and toggle the tx_reverse_b when it times out
; test delay_timer_flag for the time out
;
keypad_bit_alt_msg:
	db	'Alt '			; set display to alt

; start the alternating test.
; the toggling is handled in the nmi interrupt routine.
;
remote_bit_alt:
keypad_bit_state4e:
	lxi	h,keypad_bit_alt_msg	; load a string
	mvi	a,show_baud_ascii	; load the string output function
	show_rst			; call the function


; first, calc the data rate based on tx_baud
; it must be 4 times the data rate
;	K = 6,144,000 / (4 * data rate)
;	K = 32 * (48,000 / data rate)
;
	lxi	h,48000			; load dividend
	lbcd	tx_baud			; load tx baud rate
	mvi	a,divide_hl_bc		; load the divide function
	misc_rst			; call the function

	dad	h			; hl * 2
	dad	h			; hl * 4
	dad	h			; hl * 8
	dad	h			; hl * 16
	dad	h			; hl * 32
	mvi	a,set_nmi_clock		; set the nmi timer to data rate
	set_rst				; call the function

	mvi	a,1			; init the bit rate counter
	sta	alt_test_count		; set the initial count

	lxi	h,ctrl_nmiena_b		; now, enable nmi
	mvi	a,set_control_set	; load the function
	set_rst				; call the function

	jmp	keypad_bit_tones	; and turn ON keyline and tones


; set loopback 0 dBm
;
keypad_bit_lp1_msg:
	db	'LP 1'

remote_bit_lp1:
keypad_bit_state4f:
	lxi	h,keypad_bit_lp1_msg	; point to a message
	mvi	e,1			; load the loop function number

keypad_bit_entry:
	mvi	a,show_baud_ascii	; show the message
	show_rst

	xchg				; load the loop function
	mvi	a,set_loopback		; load the function
	set_rst				; call the function

	ret

; set loopback -20 dBm
;
keypad_bit_lp2_msg:
	db	'LP 2'

remote_bit_lp2:
keypad_bit_state4g:
	lxi	h,keypad_bit_lp2_msg	; point to a message
	mvi	e,2			; load the loop function number
	jmp	keypad_bit_entry


; set loopback -45 dBm
;
keypad_bit_lp3_msg:
	db	'LP 3'

remote_bit_lp3:
keypad_bit_state4h:
	lxi	h,keypad_bit_lp3_msg	; point to a message
	mvi	e,3			; load the loop function number
	jmp	keypad_bit_entry


; start the repeated BIT test.
; these tests will repeat until a failure or until manually terminated.
;
; we have to pass the BIT test a 1 in the ACC to start the BIT test.
;
remote_bit_repeat:
keypad_bit_state4i:

; set the repeat flag in high RAM.
; the flag is stored here so that the memory test will not trash it
;
	mvi	a,1			; set the flag
	sta	bit_repeat_flag		; set the repeat flag to 1

	mvi	a,8			; select the automatic BIT mode
	jmp	start_bit		; jump to the bit routine


; this routine will toggle the enter key led if the delay timer
; has expired.  This routine ensures that the enter key will toggle
; during some keypad test modes.
;
keypad_bit_enter_test:
	lda	delay_timer_flag	; read the timer flag
	ana	a			; if the flag is > 0
	rnz				;   then return

; flip the led and set the delay timer for the next interval
;
	call	enter_toggle_now	; toggle the enter led

	lxi	h,timer_delay_bit	; set the toggle delay
	mvi	a,setup_timeout		; load the timer function
	setup_rst			; call the function

	ret


; echo all characters from remote port
;
keypad_bit_echo_msg:
	db	'Echo'

keypad_bit_dot5:
	lxi	h,keypad_bit_echo_msg	; load a string
	mvi	a,show_baud_ascii	; load the ascii output function
	show_rst			; call the function

keypad_bit_dot5_lp:
	out	sanity_iow		; keep the timer going
	call	keypad_bit_enter_test	; test for toggling bit

	mvi	a,read_remote_buffer	; load the read function
	read_rst			; read the buffer
	jc	keypad_bit_dot5_lp1	; if no character, test keypad

	mvi	a,send_remote_char	; send a remote character
	send_rst			; call the function

keypad_bit_dot5_lp1:
	mvi	a,read_keypad_buffer	; look for keys
	read_rst			; call the function
	jc	keypad_bit_dot5_lp	; if no key, skip

	jmp	keypad_bit_state5	; if keypress, exit


; send QBF message to the remote port
;
keypad_bit_qbf_msg:
	db	'Port'

qbf_msg: db	'THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG\'S BACK'
	db	' 0123456789',cr,lf
	db	0

keypad_bit_remote:
	lxi	h,keypad_bit_qbf_msg	; load a string
	mvi	a,show_baud_ascii	; load the ascii output function
	show_rst			; call the function

keypad_bit_remote1:
	out	sanity_iow		; keep the timer going
	call	keypad_bit_enter_test	; toggle the enter led

	lxi	h,qbf_msg		; load the qbf message
	mvi	a,send_remote_ascii	; load the send function
	send_rst			; read the buffer

	mvi	a,read_keypad_buffer	; look for keys
	read_rst			; call the function
	jc	keypad_bit_remote1	; if no key, skip

	jmp	keypad_bit_state5	; if keypress, exit


; show the internal switch settings on the front panel.
; with each enter key press, continue to the next setting
;
keypad_bit_unit_msg:
	db	'Unit '
keypad_bit_unit_msg1:
	db	'4   '
keypad_bit_blank_msg:
	db	'     '


; in the first state, show the unit number
;
keypad_bit_chan:
	lxi	h,keypad_bit_unit_msg	; load the unit message
	mvi	a,show_mark_ascii	; load the function
	show_rst			; output the message

; clear the display line to show current setting
;
	lxi	h,keypad_bit_blank_msg	; point to the message
	lxi	d,display_buffer	; point to the buffer
	lxi	b,5			; save 5 chars
	ldir				; zap the message

	lxi	h,keypad_bit_unit_msg1	; load switch number message
	mvi	a,show_baud_ascii	; load the function
	show_rst			; output the message

; continue to update the switch display until a key is pressed
;
keypad_bit_chan1a:
	out	sanity_iow		; keep the timer going
	call	keypad_bit_enter_test	; toggle the enter key

	call	control_switch_test	; read the switches

	lda	unit_address		; read the unit address
	sta	display_buffer		; save this number

	lxi	h,display_buffer	; point to the unit number
	mvi	a,show_space_ascii	; show the ascii string
	show_rst			; call the function


; when a keypress arrives, we continue to the next state
;
	mvi	a,read_keypad_buffer	; read input keypad buffer
	read_rst			; call the function
	jc	keypad_bit_chan1a	; loop no chars present
	jmp	keypad_bit_chan2	; skip to the next test


; in this state we show the two valid channel addresses
;
keypad_bit_chan_msg:
	db	'ChAn '
keypad_bit_chan2:
	lxi	h,keypad_bit_chan_msg	; load the chan message
	mvi	a,show_mark_ascii	; load the function
	show_rst			; output the message

	lxi	h,keypad_bit_unit_msg1	; load the chan message
	mvi	a,show_baud_ascii	; load the function
	show_rst			; output the message

keypad_bit_chan2a:
	out	sanity_iow		; keep the timer going
	call	keypad_bit_enter_test	; toggle the enter key

	call	control_switch_test	; look for switch changes

	lxi	h,unit_address_chan1	; point to the channel strings
	lxi	d,display_buffer	; destination is display buffer
	lxi	b,5			; move 5 characters
	ldir				; done
	mvi	a,'-'			; load a separator
	sta	display_buffer + 2	; save that

	lxi	h,display_buffer	; show the channel numbers
	mvi	a,show_space_ascii	; load the function
	show_rst			; call the function

; when a keypress arrives, we continue to the next state
;
	mvi	a,read_keypad_buffer	; read input keypad buffer
	read_rst			; call the function
	jc	keypad_bit_chan2a	; loop no chars present
	jmp	keypad_bit_chan3	; skip to the next test


; here we show the current port speed
;
keypad_baud_msg:
	db	'19200'
	db	'9600 '
	db	'4800 '
	db	'2400 '
	db	'1200 '
	db	'600  '
	db	'300  '
	db	'110  '
	db	'38400'


keypad_bit_port_msg:
	db	'Port '
keypad_bit_port_msg1:
	db	'3   '

keypad_bit_chan3:
	lxi	h,keypad_bit_port_msg	; load the port message
	mvi	a,show_mark_ascii	; load the function
	show_rst			; output the message

	lxi	h,keypad_bit_port_msg1	; load the port message
	mvi	a,show_baud_ascii	; load the function
	show_rst			; output the message

keypad_bit_chan3a:
	out	sanity_iow		; keep the timer going
	call	keypad_bit_enter_test	; toggle the enter key

	in	baud_ior		; read the switch
	cma				; complement the bits
	mvi	b,8			; load the number of loops
	lxi	h,keypad_baud_msg	; point to the table
	lxi	d,5			; load offset for each entry

keypad_port_rate_loop:
	add	a			; shift left
	jc	keypad_port_rate_found	; nc means we found it
	dad	d			; point to the next message
	djnz	keypad_port_rate_loop	; and loop

keypad_port_rate_found:
	mvi	a,show_space_ascii	; load the function
	show_rst			; call the function

; when a keypress arrives, we continue to the next state
;
	mvi	a,read_keypad_buffer	; read input keypad buffer
	read_rst			; call the function
	jc	keypad_bit_chan3a	; loop no chars present
	jmp	keypad_bit_chan4	; skip to the next test


; show the remote port data type
;
keypad_rs232_on:
	db	'rS232'
keypad_mil188_on:
	db	'188  '
keypad_bit_port_msg2:
	db	'J7  '

keypad_bit_chan4:
	lxi	h,keypad_bit_port_msg	; load the port message
	mvi	a,show_mark_ascii	; load the function
	show_rst			; output the message

	lxi	h,keypad_bit_port_msg2	; load the port message
	mvi	a,show_baud_ascii	; load the function
	show_rst			; output the message

keypad_bit_chan4a:
	out	sanity_iow		; keep the timer going
	call	keypad_bit_enter_test	; toggle the enter key

	lxi	h,keypad_rs232_on	; load default to RS232
	in	input_ior		; read the input buffer
	ani	input_remtype_b		; if 0, this is rs232
	jz	keypad_port_type	;    then use default
	lxi	h,keypad_mil188_on	;    else load mil message
keypad_port_type:
	mvi	a,show_space_ascii	; show in baud space
	show_rst

; when a keypress arrives, we continue to the next state
;
	mvi	a,read_keypad_buffer	; read input keypad buffer
	read_rst			; call the function
	jc	keypad_bit_chan4a	; loop no chars present
	jmp	keypad_bit_chan5	; skip to the next test


; show the data port data type
;
keypad_bit_data_msg:
	db	'dAtA '
keypad_bit_data_msg1:
	db	'J2  '

keypad_bit_chan5:
	lxi	h,keypad_bit_data_msg	; load the port message
	mvi	a,show_mark_ascii	; load the function
	show_rst			; output the message

	lxi	h,keypad_bit_data_msg1	; load the port message
	mvi	a,show_baud_ascii	; load the function
	show_rst			; output the message

keypad_bit_chan5a:
	out	sanity_iow		; keep the timer going
	call	keypad_bit_enter_test	; toggle the enter key

	lxi	h,keypad_rs232_on	; load default to RS232
	in	input_ior		; read the input buffer
	ani	input_txdtype_b		; if 0, this is rs232
	jz	keypad_data_type	;    then use default
	lxi	h,keypad_mil188_on	;    else load mil message
keypad_data_type:
	mvi	a,show_space_ascii	; show in baud space
	show_rst

; when a keypress arrives, we continue to the next state
;
	mvi	a,read_keypad_buffer	; read input keypad buffer
	read_rst			; call the function
	jc	keypad_bit_chan5a	; loop no chars present
	jmp	keypad_bit_chan6	; skip to the next test


; show the keyline delay
;
; keypad_show_delay will show the contents of ACC as two decimal digits
;
keypad_bit_delay_msg:
	db	'dELAY'
keypad_bit_delay_msg1:
	db	'1-2 '

keypad_show_delay:
	cma				; complement the bits
	mov	c,a			; save acc
	rrc				; get the upper digit first
	rrc
	rrc
	rrc				; done
	ani	0fh			; save low four bits
	adi	'0'			; convert to ascii
	cpi	'9' + 1			; if number is <= 9
	jc	keypad_show_delay1	;   then skip - it is ok
	mvi	a,'_'			;   else load an error
keypad_show_delay1:
	mov	m,a			; and save it
	inx	h			; increment the pointer
	mov	a,c			; recover the next digit
	ani	0fh			; mask upper bits
	adi	'0'			; make it ascii
	cpi	'9' + 1			; if number is <= 9
	jc	keypad_show_delay2	;   then skip - it is ok
	mvi	a,'_'			;   else load an error
keypad_show_delay2:
	mov	m,a			; save it
	inx	h			; and increment the pointer
	mvi	m,' '			; and add one space
	ret

keypad_bit_chan6:
	lxi	h,keypad_bit_delay_msg	; load the delay message
	mvi	a,show_mark_ascii	; load the function
	show_rst			; output the message

	lxi	h,keypad_bit_delay_msg1	; load the switch
	mvi	a,show_baud_ascii	; load the function
	show_rst

keypad_bit_chan6a:
	out	sanity_iow		; keep the timer going
	call	keypad_bit_enter_test	; toggle the enter key

	lxi	h,display_buffer	; point to the destination
	lda	delay1_mr		; load address of upper switch
	call	keypad_show_delay	; show upper two digits
	lda	delay0_mr		; load address of upper switch
	call	keypad_show_delay	; show lower two digits

	lxi	h,display_buffer	; show the delay setting
	mvi	a,show_space_ascii	; load the function
	show_rst

; when a keypress arrives, we continue to the next state
;
	mvi	a,read_keypad_buffer	; read input keypad buffer
	read_rst			; call the function
	jc	keypad_bit_chan6a	; loop no chars present


; a key has been pressed to end the test.
; disable all tests and return to idle state
;
keypad_bit_state5:
	mvi	a,0			; clear the bit active flag
	sta	bit_test_active		; no test is active

	mvi	l,0			; turn off all loopback
	mvi	a,set_loopback		; load the function
	set_rst				; call the function


; turn OFF keyline and tones
;
	mvi	l,0			; turn ON keyline
	mvi	a,setup_keyline		; load keyline function
	setup_rst			; call the function

	lxi	h,ctrl_mute_b		; load a pointer to the mute
	mvi	a,set_control_set	; load the clear bit function
	set_rst				; call the function

; if tx mute is enabled, then clear the tx mark and space latches
;
	lda	tx_mute_on		; read the mute flag
	cpi	1			; if mute <> 1, mute is OFF
	jnz	keypad_bit_state5a	;   then skip the tone off

; tx mute is ON, so turn off the tones.
;
	lxi	h,0000h			; load the 0000 value
	shld	tx_mark_mw		; clear the mark latch
	shld	tx_space_mw		; and the space latch

; restore tx normal/reverse bit
;
keypad_bit_state5a:
	lda	tx_reverse_on		; read the normal/reverse flag
	mov	l,a			; load l
	mvi	a,setup_tx_reverse	; load the function
	setup_rst			; call the function


; reset nmi
;
	mvi	a,init_timer1		; load the function
	misc_rst			; call the function

	lhld	rx_baud			; read the rx baud rate
	mvi	a,setup_rx_baud		; setup rx baud rate
	setup_rst			; call the function

	lhld	tx_baud			; read the tx baud rate
	mvi	a,setup_tx_baud		; setup tx baud rate
	setup_rst			; call the function

; restore mark/space
;
	mvi	a,show_freq		; restore mark/space or center/shift
	show_rst

; restore the baud display
;
	mvi	a,show_baud		; restore the baud display
	show_rst			; call the function

	call	enter_key_off		; turn OFF the enter key

; reset the state vector for testing RTS and TXD
;
	lxi	h,data_rts_state0	; load the initial state
	shld	data_rts_state		; save this state vector

	lxi	h,keypad_state0		; now, load the idle state
	shld	keypad_state		; set the next state
	ret


;******************************************************************************
; keypad_cent_state3
;******************************************************************************
;
; change the display to center/shift, show the new display
; reset the keypad state pointer to idle state.
;
keypad_cent_state3:
	mvi	a,1			; enable show center/shift
	jmp	keypad_cent_state3_entry ; and continue processsing


;******************************************************************************
; keypad_chan_state3
;******************************************************************************
;
; copy the mark/space/baud/hold/rev settings from the currently selected
; channel to the other channel.  this is an easy way to make certain that
; the two channels are set the same.
;
; start of the routine
;
keypad_chan_state3:
	call	enter_key_on		; turn ON enter

	lda	channel			; read the selected channel
	cpi	1			; if channel 1 is selected
	jz	keypad_chan_state3a	;   then skip to receive channel

; here the mod channel 2 is selected.
; we need to copy the channel 1 settings into channel 2.
; 
	call	copy_ch2_to_ch1		; copy the tx params to rx
	jmp	keypad_chan_state3b	; continue

; here the demod channel 1 is selected.
; we need to copy the channel 1 settings into channel 2.
; 
keypad_chan_state3a:
	call	copy_ch1_to_ch2		; copy the rx params to tx

keypad_chan_state3b:
	lxi	h,keypad_state0		; return to idle state
	shld	keypad_state		; set the next state
	ret				; then return


; utility routines for the copy commands
; we need to copy the channel 2 settings into channel 1.
; 
copy_ch2_to_ch1:
	lhld	tx_mark_freq		; read the transmit mark
	mvi	a,setup_rx_mark		; and set the new receive mark
	setup_rst

	lhld	tx_space_freq		; read the transmit space
	mvi	a,setup_rx_space	; and set the new receive space
	setup_rst

	lhld	tx_baud			; read the tx baud rate
	mvi	a,setup_rx_baud		; setup rx baud
	setup_rst			; set the baud rate

	lda	tx_hold_on		; read the tx hold state
	mov	l,a			; load l with the new state
	mvi	a,setup_rx_hold		; load the function l has state
	setup_rst			; call the function

	lda	tx_reverse_on		; read the tx reverse state
	mov	l,a			; load l with the new state
	mvi	a,setup_rx_reverse	; load the function l has state
	setup_rst			; call the function

	lda	tx_dot5_on		; read the tx dot5 flag
	sta	rx_dot5_on		; set the rx dot5 flag
	ret

; we need to copy the channel 1 settings into channel 2.
; 
copy_ch1_to_ch2:
	lhld	rx_mark_freq		; read the receive mark
	mvi	a,setup_tx_mark		; and set the new transmit mark
	setup_rst

	lhld	rx_space_freq		; read the receive space
	mvi	a,setup_tx_space	; and set the new transmit space
	setup_rst

	lhld	rx_baud			; read the rx baud rate
	mvi	a,setup_tx_baud		; setup tx baud
	setup_rst			; set the baud rate

	lda	rx_hold_on		; read the rx hold state
	mov	l,a			; load l with the new state
	mvi	a,setup_tx_hold		; load the function l has state
	setup_rst			; call the function

	lda	rx_reverse_on		; read the rx reverse state
	mov	l,a			; load l with the new state
	mvi	a,setup_tx_reverse	; load the function l has state
	setup_rst			; call the function

	lda	rx_dot5_on		; read the rx dot5 flag
	sta	tx_dot5_on		; set the tx dot5 flag
	ret


;******************************************************************************
; keypad_hold_state3
;******************************************************************************
;
; toggle the hold for the selected channel
;
keypad_hold_state3:
	call	enter_key_on		; turn ON enter

	lda	channel			; read the channel
	cpi	1			; if channel = 1 RX
	jz	keypad_hold_state3b	;   then set RX channel

; toggle channel 2 TX hold state
;
	mvi	l,1			; set the default to hold ON
	lda	tx_hold_on		; read the hold state
	ana	a			; if zero
	jz	keypad_hold_state3a	;   then use the default
	mvi	l,0			;   else turn hold OFF
keypad_hold_state3a:

	mvi	a,setup_tx_hold		; load the function l has state
	setup_rst			; call the function

	lda	tx_hold_on		; load acc with the new state
	jmp	keypad_hold_state3d	; now, turn ON the led


; toggle channel 1 RX hold state
;
keypad_hold_state3b:
	mvi	l,1			; set the default to hold ON
	lda	rx_hold_on		; read the hold state
	ana	a			; if zero
	jz	keypad_hold_state3c	;   then use the default
	mvi	l,0			;   else turn hold OFF
keypad_hold_state3c:

	mvi	a,setup_rx_hold		; load the function l has state
	setup_rst			; call the function

	lda	rx_hold_on		; load acc with the new state


; in either case set the new front panel led
;
keypad_hold_state3d:
	ana	a			; if new state is 0
	mvi	a,show_led_off		;     set default to led off
	jz	keypad_hold_state3e	;   then turn the led off
	mvi	a,show_led_on		;   else turn the led ON
keypad_hold_state3e:
	lxi	h,led_hold_b		; point to the led
	show_rst

	lxi	h,keypad_state0		; return to idle state
	shld	keypad_state		; set the next state

	ret				; then return






;******************************************************************************
; keypad_mkonly_state3
;******************************************************************************
;
; set channel 1 to mark only state.
;
keypad_mkonly_state3:
	call	enter_key_on		; turn ON enter

	mvi	l,1			; select rx mark only mode
	mvi	a,setup_rx_mode		; load the function
	setup_rst			; call the function

	lxi	h,keypad_state0		; reset to initial state
	shld	keypad_state

	ret				; and return


;******************************************************************************
; keypad_regen_state3
;******************************************************************************
;
; toggle the regen state
; if ON, then setup the regen port
; if OFF, just disable the port
;
keypad_regen_state3:
	call	enter_key_on		; arm the enter key

	lda	rx_regen_on		; load the flag
	cpi	0			; if regen is OFF
	jz	keypad_regen_state3b	;   then turn it ON

; turn REGEN OFF
;
keypad_regen_state3a:
	mvi	l,0			; set the flag for disable
	mvi	a,setup_rx_regen	; load the function
	setup_rst			; call the function

	lxi	h,keypad_state0		; reset to the initial state
	shld	keypad_state		; save the next state
	ret				; then return


; turn REGEN ON
;
keypad_regen_state3b:
	mvi	l,1			; set the flag to enable regen
	mvi	a,setup_rx_regen	; load the function
	setup_rst			; call the function

	jmp	keypad_regen_on_entry	; exit thru a routine to set length



;******************************************************************************
; keypad_rev_state3
;******************************************************************************
;
; set the selected channel to REVERSE
;
keypad_rev_state3:
	call	enter_key_on		; turn ON enter

	lda	channel			; read the channel
	cpi	1			; if channel = 1 RX
	jz	keypad_rev_state3a	;   then set RX channel

; set channel 2 TX to reverse shift
;
	mvi	l,1			; set the flag
	mvi	a,setup_tx_reverse	; load the function
	setup_rst			; call the function

	jmp	keypad_rev_state3b	; now, turn ON the led


; set channel 1 RX to reverse shift
;
keypad_rev_state3a:
	mvi	l,1			; set the flag
	mvi	a,setup_rx_reverse	; load the function
	setup_rst			; call the function

; in both cases, turn ON the front panel led
;
keypad_rev_state3b:
	lxi	h,led_reverse_b		; point to the led
	mvi	a,show_led_on		; and turn OFF the led
	show_rst

	lxi	h,keypad_state0		; return to idle state
	shld	keypad_state		; set the next state

	ret				; then return


;******************************************************************************
; keypad_sponly_state3
;******************************************************************************
;
; set channel 1 to mark only state.
;
keypad_sponly_state3:
	call	enter_key_on		; turn ON enter

	mvi	l,2			; select rx space only mode
	mvi	a,setup_rx_mode		; load the function
	setup_rst			; call the function

	lxi	h,keypad_state0		; reset to initial state
	shld	keypad_state

	ret				; and return


;******************************************************************************
; keypad_2nd_state3
;******************************************************************************
;
; we received another 2nd.
; do nothing but wait for another key
;
keypad_2nd_state3:
	ret


	end
