;PI7EHG-short-d - modified for Chris Towns

;NB to customise with own callsign see end of program

;Hardware details
;Clock uses 3.58MHz crystal
;RA0-4 are inputs
;	RA0,  This input for beacon off - use Mic/PTT
;	RA1,  This input for continuous tone
;	RA2,  This input for 45 seconds interrupted tone with morse ID
;	RA3,  This input for 45 seconds warble tone with morse ID
;	RA4	Not used here
;	RB0-3 are outputs
;	RB0	Tone bit - Square wave morse tone output - via attenuator to MIC input
;		The interrupt program toggles this bit if RB1 is set.	
;	RB1	Tone enable bit (controls interrupt & front panel LED - follows key envelope)
;		this output can be used to drive the key input for CW mode
;	RB2	High during ID transmission
;	RB3	Message in progress (to PTT line)
;----------------------------------------------

;Define processor configuration
	list    P=16F84, R=HEX, C=132
					;(P) processor=16f84,
					;(R) default radix is hexadecimal,
					;(C) 132 column listings,

	__CONFIG H'3FF9'		;Configure for XT Crystal clock, 
					; no watchdog, no start timer.
;-----------------------------------------------

;Define registers & data locations
RTCC    	equ     1h              ; F1 reg is counter/timer for interrupt (sets tone frequency)
PC     		equ     2h              ; F2 reg is program counter
STATUS  	equ     3h              ; F3 reg is STATUS Reg.
Port_A  	equ     5h              ; IO port assignments.
Port_B  	equ     6h
INTCON  	equ     0BH             ; interrupt control register
OPTREG		equ	81H		; option register
TRISA  		equ     85H             ; RA direction/tristate register
TRISB   	equ     86H             ; RB direction/tristate register

msg             equ     10H             ;message data byte
msg_ptr         equ     11H             ;address of message data byte
bitcount        equ     12H             ;number of times msg has been shifted
output_ctrl     equ     13H             ;output bits,0=output (tone),1=tone enable (envelope),
					;2=High for ID,3=message in progress (PTT),4-7 unused
w_save          equ     14H             ;temp store for W register
speed1		equ	15H		;delay loops
speed2		equ	16H
speed3		equ	17H
freq		equ	18H             ;adjust to set tone frequency
wpm		equ	1AH        	;adjust to set morse speed	      
t1		equ	1BH		;timer (/60)
t2		equ	1CH		;timer (/15)
beacon_type       equ     1DH             ;type of output defined (input bit store)
prev_beacon_type  equ     1EH             ;type of output previously defined 
					  ;(previous input bit store)
;------------------------------------------------

;Define constants
W       equ     0             ;pseudo destination, result in w.  
			      ;Note: w=0 is predefined
			      ;     also f=1 
same    equ     1             ;pseudo destination, back in source
Z       equ     2             ;zero bit in status register
C       equ     0             ;carry bit in status register
	      ;


;*************************************************************************

;Define program start addresses
	org     0                       ;reset address in 16F84

reset   goto init

	org     4
	goto interrupt
;==========================================================


;Interrupt routine - generates tone frequency when required
interrupt
	bcf INTCON,2			;clear RTCC interrupt flag
	movwf w_save                    ;save W register contents
	movf output_ctrl,W		;retrieve output_ctrl bits
	btfss output_ctrl,1		;check the tone enable bit
	goto end_interrupt		;exit if tone not enabled
	xorlw B'00000001'		;toggle tone output bit if tone enabled
	movwf output_ctrl		;save it back	

end_interrupt
	movwf Port_B			;write bits to the port
	movfw freq			;pre-load RTCC with freq value
	movwf RTCC			;  which controls time to next int
	movf w_save,W			;restore original W contents
	retfie

;==========================================================

;Main Program routine
init
	clrf output_ctrl		;start with everything disabled
	clrf msg
	clrf msg_ptr
	movlw H'01'			;set beacon type to mic
 	movwf beacon_type
	clrf prev_beacon_type
 	clrf bitcount
	clrf w_save
	clrf STATUS
	clrf Port_A
	clrf Port_B
	clrf RTCC
	movlw H'28'			;set tone freq
	movwf freq		
	movlw H'80'			;set wpm
	movwf wpm
	movlw H'00'			;set clock- divide by 256
	movwf speed1
	movlw H'00'			;set clock- divide by 256
	movwf speed2	
	movlw H'00'			;set clock- divide by 256
	movwf speed3	
	movlw H'00'			;set freq toggle counter - divide by 256
	movwf t1	
	clrw
	bsf STATUS,5  			;switch to page 1
	movlw H'00'			;all port B to o/p mode
	movwf TRISB			;      
	movlw H'1F'			;all port A pins to input mode
	movwf TRISA
	movlw B'10000000'		;no pull-ups,f/4 to RTCC,prescale 000
	movwf OPTREG
	bcf STATUS,5  			;switch to page 0
	movlw B'00100000'		;RTCC rollover int enabled (not global)
	movwf INTCON
	
test_input
	call delay200ms			;give switch time to settle
	movf beacon_type,W		;
	movwf prev_beacon_type		;store new value for input
	btfsc beacon_type,0		;check input command lines
	goto mic			;microphone input, switch off tone
	btfsc beacon_type,1	
	goto cont_tone			;continuous tone
	btfsc beacon_type,2
	goto cw_tone			;tone plus ID, 60 seconds overall
	btfsc beacon_type,3	
	goto warble_tone		;tone plus ID, 60 seconds overall
	goto mic			;shouldn't be here, go to mic and check again later	

mic ;************************ clear outputs and switch off global int enable
	bcf output_ctrl,0		;clear the output bit
	bcf output_ctrl,1		;clear the tone enable bit
	bcf output_ctrl,2		;clear the volume bit
	bcf output_ctrl,3		;clear the PTT bit
	bcf INTCON,7			;clear global interrupt enable
	movf output_ctrl,w		;retrieve output_ctrl bits
	movwf Port_B			;write bits to the port
mic_loop
	call monitor
	btfss STATUS,Z			;skip if same as previous	
	goto test_input
	goto mic_loop
	
cont_tone ;****************** send continuous tone
	bsf INTCON,7			;global interrupt enable
	bsf output_ctrl,3		;set msg in progress indicator (PTT)
	bsf output_ctrl,1		;set the tone enable bit
	movlw H'28'
	movwf freq
cont_loop
	call monitor
	btfss STATUS,Z			;skip if same as previous	
	goto test_input	
	goto cont_loop

warble_tone ;****************** send warble tone with ID every minute
	bsf INTCON,7			;global interrupt enable
	bsf output_ctrl,3		;set msg in progress indicator (PTT)
	clrf	t1			;start with counter =0
	movlw H'28'			;set tone freq
	movwf freq
one_min_warble_loop
	bsf output_ctrl,1		;set the tone enable bit
	call monitor
	btfss STATUS,Z			;skip if same as previous	
	goto test_input	
	call delay200ms
	call toggle_freq   		;toggles freq every 200ms	
	decfsz t1,same			; for approx 50 secs
	goto one_min_warble_loop
	bcf output_ctrl,1		;clear the tone enable bit
	call delay200ms			;silence for 0.4sec
	call delay200ms
	call output_ID			;timer expired, send ID
	call delay200ms			;silence for 0.4sec
	call delay200ms
	goto one_min_warble_loop


cw_tone ;************** send cw tone with ID every minute
	movlw H'28'
	movwf freq
	bsf INTCON,7			;global interrupt enable
	bsf output_ctrl,3		;set msg in progress indicator (PTT)
cw_loop
	bsf output_ctrl,1		;set the tone enable bit
	call monitor
	btfss STATUS,Z			;skip if same as previous	
	goto test_input			;exits if input changed
	call delay10s			;tone output for 30secs
	call delay10s
	call delay10s
	bcf output_ctrl,1		;clear the tone enable bit
	call delay200ms			;silence for 0.4sec
	call delay200ms
	call output_ID			;send ID
	bcf output_ctrl,1		;clear the tone enable bit
	call delay200ms			;silence for 0.4sec
	call delay200ms
	goto cw_loop

;*********************************************************************************
;subroutines:
light 					;test purposes only - checks output portB,0-3
	movf output_ctrl,W		;retrieve output_ctrl bits
	iorlw H'0F'   			;invert tone bits
	movwf output_ctrl		;save it back	
	movwf Port_B			;write bits to the port
	return

;****************	

toggle_freq
	movlw H'28'			;check if freq H'28'
	subwf freq,W
	btfss STATUS,Z			;if freq is H'28', then set it to H'20'	
	goto freq28			;if not, set it to H'28'
	movlw H'20'			
	movwf freq
	return
freq28
	movlw H'28'		
	movwf freq
	return
;****************
monitor
	movf Port_A,w			;store input in beacon_type
	movwf beacon_type
	subwf prev_beacon_type,W	
	return				;returns with Z=0 if input changed

;*****************

delay200ms				;less than 200ms actually
	clrf speed1
	movlw H'D0'			;define delay setting
	movwf speed2
	movlw H'01'			;define delay setting
	movwf speed3
	goto delayloop	

delay10s					
	clrf speed1
	movlw H'00'			;depends on define delay setting
	movwf speed2
	movlw H'2F'			;depends on define delay setting
	movwf speed3
	goto delayloop	
	
delay14m					
	clrf speed1
	movlw H'00'			;depends on define delay setting
	movwf speed2
	movlw H'D0'			;depends on define delay setting
	movwf speed3
	
delayloop
	decfsz speed1,same
	goto delayloop
	decfsz speed2,same
	goto delayloop
	decfsz speed3,same
	goto delayloop
	return	
;**********************

output_ID 
	bsf output_ctrl,2		;set output RB2
	movlw H'00'			;initialize table pointer
	call msg_loc
	movwf msg_ptr
	bsf INTCON,7			;global interrupt enable
	bsf output_ctrl,3		;set msg in progress indicator

msg_loop
	call msgtable			;read byte from message table
	movwf msg			;save in msg
	sublw H'FF'			;check if terminator char 'FF'
	btfsc STATUS,Z			;skip if not
	goto end_routine		;return via end_routine, if terminator
	movlw H'09'			;initialize bit shift counter
	movwf bitcount

bit_loop
	decfsz bitcount,same		;count shifts down to zero
	goto send_bit			;send bit if more to process
	incf msg_ptr,same		;otherwise try next message byte
	movf msg_ptr,w
	goto msg_loop

send_bit
	bcf STATUS,C			;clear carry and shift into LSB
	rlf msg,same
	btfss STATUS,C			;see if MSB in "msg" was set
	goto no_tone
	bsf output_ctrl,1		;set the tone enable bit

slow_down
	call delay
	goto bit_loop			;send next bit

no_tone
	bcf output_ctrl,1		;clear the tone enable bit
	goto slow_down

delay					;slow down to set bit time
	clrf speed1
	movfw wpm			;depends on defined wpm setting
	movwf speed2
delay_loop
	decfsz speed1,same
	goto delay_loop
	decfsz speed2,same
	goto delay_loop
	return

msg_loc
	addwf PC,same
	retlw msg_1 - msgtable - 1

msgtable
	addwf PC,same

msg_1     
	retlw   B'00000000'
	retlw   B'10111011'	;P
	retlw   B'10100010'	;
	retlw   B'10001110'	;I
	retlw   B'11101010'	;7
	retlw   B'10001000'	;E
	retlw   B'10101010'	;H
	retlw   B'00111011'	
	retlw   B'10100000'	;G
	retlw   B'00001011'	
	retlw   B'10111011'	;J
	retlw   B'10001110'
	retlw   B'11101110'	;O
	retlw   B'00101011'
	retlw   B'10111011'
	retlw   B'10001010'	;2
	retlw   B'11101110'	;2
	retlw   B'11100010'
	retlw   B'10101000'	;H
	retlw   B'11101010'	
	retlw   B'10000000'	;B
	retlw	B'11111111'	;end of message code

end_routine
	bcf output_ctrl,1			;clear tone enable bit
	bcf output_ctrl,2			;clear output RB2
	return
	
;********************************************************************
;INFORMATION

;To customise with own callsign- use text editor to assemble a string of binary code
;from the table below.  Then break up the string into eight bit bytes
;and put after a 'retlw   B' command.  For example:


;Split into eight bit bytes 
;101000 		(zeros added at end to pad out)
;11111111		(end of message code at end)

; ************************************************************************************
;DATA

;Morse Code in digital format for easy copying to text string

;A-10111000		N-11101000
;B-111010101000		O-11101110111000
;C-11101011101000	P-10111011101000
;D-1110101000		Q-1110111010111000
;E-1000			R-1011101000
;F-101011101000		S-10101000
;G-111011101000		T-111000
;H-1010101000		U-1010111000
;I-101000		V-101010111000
;J-1011101110111000	W-101110111000
;K-111010111000		X-11101010111000
;L-101110101000		Y-1110101110111000
;M-1110111000		Z-11101110101000

;1-10111011101110111000		6-11101010101000
;2-101011101110111000		7-1110111010101000
;3-1010101110111000		8-111011101110101000
;4-10101010111000		9-11101110111011101000
;5-101010101000			0-1110111011101110111000

;/-1110101011101000

;HEX values:
;0000=0	0001=1	0010=2	0011=3	0100=4	0101=5	0110=6	0111=7	
;1000=8	1001=9	1010=A	1011=B	1100=C	1101=D	1110=E	1111=F
;----------------------------------------------------------------

end











