; March 26 2007 1725 PDT
; 
; checked counter init and reset numbers -- OK
;
; When the key is up   pin 6 (RC4)will be hi and pin 7 (RC3) will be low.
; When the key is down pin 6 will be low and     pin 7 will be hi.
;
; The TMARK (1 PPS)output pulse rise time is typically less than 2 nanoseconds
; and the pulse duration is typically 25.6 milliseconds. 25,600 INSTRUCTION CYCLES
;
;    SETUP PORTS
;     -----------   PORT A    ----------------------------------------
;	I/O	I	I	I	INTF	I	I
;	pins 	2*	3	4	11	12	13
;		RA5	RA4	RA3	RA2	RA1	RA0
;	TRISA	1	1	1	1	1	0	0x3F
;	IOCA	1	1	1	0	1	0	Ox3B
;	WPUA	1	1	0	0	1	0	0x33
;	msg#	4	3	2		1	time set
;	midx#		11101111		11111101
;	midx#	11011111	11110111
;
;     -----------   PORT C    ----------------------------------------
;	I/O	OUT	O	0	IN	I	I
;	pins	5	6	7	8    	9   	10
;		RC5	RC4	RC3	RC2  	RC1 	RC0
;	TRISC	0	0	0	1	1	1	0x07
;	KEYUP	0	1	0	0	0	0       0X10
;	kydown	0	0	1	0	0	0	0x08
;
;     ---------------------------------------------------------------			
;
;
P=16F630
		include P16F630.inc
		errorlevel  -302        ; suppress message 302 from list file
	    				; RC internal clock
	         __config 0x3184   	; watchdog timer off 
				    	; power-up timer on
	                            	; code protect   off
	         radix    hex 
;
;
dec5REG		equ	0x33		; increment bits ea 60 sec
TReg		equ	0x34		; keeps track of beacon mode T/R
LASTPA		equ	0x35
regC  		equ     0x36		; delay register
regD  		equ     0x37		; delay register
regE  		equ     0x38		; delay register
regF		equ	0x39		; CQ counter register
regT		equ	0x3A		; count 1 PPS
TEMP		equ	0x3B		; 
w_temp		equ	0x3C		;store a copy of W register while int
status_temp	equ	0x3D		;store a copy of Status Reg while int
midx		equ	0x3E		;store some bits for msg select
;
;
	ORG     0x00          	; startup address = 0000
	goto	start	
;
;---------------------------
;
;			store W and STATUS
;
	ORG     0x04       	; interrupt vector location
;
	MOVWF 	w_temp 		;copy W to temp register,
				;could be in either bank
	SWAPF 	STATUS,W 	;swap status to be saved into W
	BCF	STATUS,RP0 	;change to bank 0 regardless of
				;current bank
	MOVWF	status_temp 	;save status to bank 0 register
;
	GOTO	PER_INT
;
;---------------------------
;
;			PORTC INIT
;
start	CLRF 	STATUS 		; Bank0
	CLRF 	PORTC 		; Initialize PORTC by clearing output data latches
	BSF 	STATUS, RP0 	;   Bank1
	MOVLW 	0x07		;   Value used to initialize data direction
	MOVWF 	TRISC 		;   see notes ABOVE
	CLRF 	STATUS 		; Bank0
	MOVLW   0x10		; load key up data bits RC3 LOW,RC4 HIGH, into W
	MOVWF   PORTC		; output the key up data bits
;
	MOVLW	0x3C		; load 1 PPS reg
	MOVWF	regT		; with 60 decimal( might be 61 ?)
	MOVLW	0x05		;
	MOVWF	dec5REG		; set register to 5
;
;			PORTA INIT
;
	CLRF 	STATUS 		; Bank0
	CLRF 	PORTA 		; Initialize PORTA by clearing output data latches
	CLRF	CMCON		; clear the comparator register
	MOVLW	0x07		; TURN OFF COMPARATOR MODE OTHERWISE PIN 
	MOVWF	CMCON		; CAN'T BE READ AS INTERRUPT INPUT OF SWITCH		
	BSF 	STATUS, RP0 	;   Bank1
	CLRF	PIE1		;   disable tmr1 - other stuff we don't need
	MOVLW 	0x3F 		;   used to initialize data direction
	MOVWF 	TRISA 		;   See notes
	MOVLW	0x3B		;   IOCA register (is in bank1)
	MOVWF 	IOCA		;   set interrupt-on-change 
	BCF	OPTION_REG, 7	;   enable all weak pull-ups
	MOVLW	0x33		;   enable weak p/u on indiv pins
	MOVWF	WPUA		;   do it (enabled = 1)
	CLRF	PIE1		;   disable TMR0 int (bank 1)
	CLRF 	STATUS 		; Bank0
	CLRF	INTCON 		; Disable interrupts and clear some flags
	CLRF	PIR1 		; Clear all flag bits - bank 0
;
	MOVLW	0xFE		; the first interrupt might be 1 PPS...
	MOVWF	midx		; so set midx register to zero NOW
;
	BSF	TReg, 0		; start beacon in T period
	BSF	INTCON, 3	; enable RAIF int
	BCF	INTCON, 0	; RAIF - Clear Flag Bit Just In Case
	BSF	INTCON, 4	; INTE - external Interrupt Enable (1=enable)
	BCF	INTCON, 5	; TIMER OVERFLOW INT ENABLE ( 1 = enable)
	BSF	INTCON, 6	; rising edge trigger ( 1 = enable)
	BSF	INTCON, 2	; RA port change interrupt enable FLAG bit
	BCF	INTCON, 1	; INTF - Clear Flag Bit Just In Case
	BSF	INTCON, 7	; GIE – Global interrupt enable (1=enable)
;	
;*************************************************************************
;
;  BEGIN MAIN LOOP
;    Start sending the message                          11111110
;					
send	BTFSS	midx,1		; skip next inst if bit is CLEAR
	GOTO	msg1		;	midx FD		11111101	 
	BTFSS	midx,3		; 
	GOTO	msg2		;	midx F7		11110111
	BTFSS	midx,4		;
	GOTO	msg3		;	midx EF		11101111	 
	BTFSS	midx,5		;
	GOTO	msg4		;	midx DF		11011111
	nop
;
;				 if no switches then fall through to here
;				 if a swich is closed, skip over msg,
;				 to msg1 - 4
;msg	
	GOTO 	send  		; RUNS ! but does nothing
;	
msg1	call 	dot
	GOTO 	send
;	
msg2	call	cq
	call	from
	call	grid
	call	longK
	call	dly10sec
	call	dly10sec
	call	dly10sec	
	GOTO 	send	
;
;	BEACON MESSAGE	
;	
msg3	BTFSS	TReg,0
	GOTO	send
	call	from
	call	grid
	call	key10
	GOTO	send	
;
msg4	
	GOTO	send
;
;  END MAIN LOOP
;
;*************************************************************************
;
;   INTERRUPT SERVICE ROUTINE
;
PER_INT 			; set on interrupt
	BTFSS 	INTCON, RAIF 	; PortA change on interrupt?
	GOTO 	isINTF	 	; Other interrupt
CLR_RAINTF
	MOVF 	PORTA, W 	; Move PortA value to the W register
	MOVWF 	TEMP 		; Need to save the PortA reading.
	XORWF	LASTPA, F 	; XOR last PortA value with the new
				; PortA value.
;
	BCF	INTCON, RAIF 	; Clear the RA interrupt flag.
	GOTO	brp		; Do task for INT on RA(x)
;				  begin reading pins
;
;---------------- - - - 1 PPS ROUTINE ----------------- - - - - - - - - -
; 
isINTF	BCF	INTCON,	INTF
;
	MOVLW	0x3C		; 60 decimal
	DECFSZ	regT, 1		; (1 PPS PIN 11) EXECUTE EVERY SECOND
	GOTO	RESTREG
	MOVWF	regT		; reload regT count
	DECFSZ 	dec5REG, 1	; through dec5REG for Z=1, then we do toggle.
	GOTO	RESTREG		; AFTER THE FIRST MINUTE, we need 4 more passes 	
	MOVLW	0x05
	MOVWF	dec5REG		; reset register to 5
	MOVLW	1		; define mask of which bits to toggle
	XORWF	TReg, 1		; do toggle, 5 min high, 5 min low 
	GOTO	RESTREG	
;
;---------------- -  Begin Reading PINS -------------- - - - - - - - - -
;
;	TEST PINS for change 
;	pins 	 2,   3,  4, --, 12   ,13 	pin 11 
;		ra5, ra4,ra3,---,ra1  ra0	is INTF
;
brp	MOVLW	0xFE		; assume NO pins are low, and fix it
	MOVWF	midx		; below if some are	
;
	BTFSC	LASTPA,0	;pin 13, ra0
	CALL	pin13C			
;
	BTFSC	LASTPA,1	;pin 12, ra1
	CALL	pin12C
;
;	RA2 used by INTF	 pin 11
;
	BTFSC	LASTPA,3	;pin 4, ra3
	CALL	pin4C
; 
	BTFSC	LASTPA,4	;pin 3, ra4
	CALL	pin3C
;
	BTFSC	LASTPA,5	;pin 2, ra5
	CALL	pin2C
;
	MOVF 	TEMP, w 	; Move the PortA read value to the
	MOVWF 	LASTPA 		; register LASTPA
;
	GOTO RESTREG
;
;
;--------------------------------------------------------------------
;
pin13C	MOVLW	0x3c		; ZERO the 5 min registers
	BTFSS	PORTA, 0	; ignore rising edge
	MOVWF	regT		;
	MOVLW	0x05		; set to start value
	MOVWF	dec5REG		;
	BSF	TReg, 0		; start beacon in T period	
	RETURN
;
pin12C	MOVLW	B'11111101'	; write midx while pin grounded
	BTFSS	PORTA, 1	; not on rising edge interrupt
	MOVWF	midx		; SET REG midx to 11111101  msg1
	RETURN
;
pin4C	MOVLW	B'11110111'	; write midx while pin grounded
	BTFSS	PORTA, 3	; not on rising edge interrupt
	MOVWF	midx		; SET REG midx to 11110111  msg2
	RETURN
;
pin3C	MOVLW	B'11101111'	; write midx while pin grounded
	BTFSS	PORTA, 4	; not on rising edge interrupt
	MOVWF	midx		; SET REG midx to 11101111  msg3
	RETURN
;
pin2C	MOVLW	B'11011111'	; write midx while pin grounded
	BTFSS	PORTA, 5	; not on rising edge interrupt
	MOVWF	midx		; SET REG midx to 11011111  msg4
;
	MOVLW	B'11111110'	; not changed above, so must be
	BTFSS	midx, 0		; no pins grounded - set midx to FE
	MOVWF	midx		; 
	RETURN			; 
;
;---------------------------------------------------------------------
;
RESTREG	SWAPF 	status_temp,W	; swap STATUS_TEMP register into
				; W, sets bank to original state
	MOVWF	STATUS 		; move W into STATUS register
	SWAPF	w_temp,F 	; swap W_TEMP with F
	SWAPF	w_temp,W 	; swap W_TEMP into W
	RETFIE 			; Return from interrupt
;
;   END INTERRUPT SERVICE ROUTINES
;
;**********************************************************************
;
; DOT LENGTH SUBROUTINE
;                                                                            
dot     MOVLW   0x08		; load key down data bits
        MOVWF   PORTC      	; output the key down data bits
        CALL    dly100     	; key down for 100 msec
        MOVLW   0x10		; load key up data bits
        MOVWF   PORTC     	; output the key up data bits
        CALL    dly100      	; key up for 100 msec
        RETURN              	; 
;
; Dash length subroutine
;
dash   	MOVLW   0x08		; load key down data bits
        MOVWF   PORTC		; output the key down data bits
        CALL    dly300		; key down for 300 msec
        MOVLW   0x10 		; load key up data bits
        MOVWF   PORTC		; output the key up data bits
        CALL    dly100		; key up for 100 msec
        RETURN              	; 
;
; Keydown subroutine
;
key10	movlw   0x08 		; load key down data bits
        movwf   PORTC		; output the key down data bits
        call    dly10sec	; key down for 10 seconds
        movlw   0x16 		; load key up data bits
        movwf   PORTC		; output the key up data bits
        call    dly600		; key up for 600 msec
        call    dly100		; key up for 100 msec
        RETURN			; 
;
key30	movlw   0x08 		; load key down data bits
        movwf   PORTC		; output the key down data bits
        call    dly10sec	; key down for 30 seconds
	call    dly10sec	;
	call    dly10sec	;
        movlw   0x16 		; load key up data bits
        movwf   PORTC		; output the key up data bits
        call    dly600		; key up for 600 msec
        call    dly100		; key up for 100 msec
        RETURN
; 
; For key down 9 seconds
;
dly10sec
	clrf    regC
        movlw   0x63        	; 63h = 99 decimal
        movwf   regE
wait9   movlw   0x82        	; 82h = 130 decimal
        movwf   regD
wait8   decfsz  regC, F     	; 3 clock cycles x 256 = 768 uS
        goto    wait8
        decfsz  regD, F      	; 768 x 180 = 139008 * .789 = 109.677312 mS
        goto    wait8
        decfsz  regE, F    	; 109.677312 x 99 = 10858.053888 mS
        goto    wait9
        RETURN
;
; 100 MSEC DELAY ROUTINE (for dot and dash length routines)
;
dly700	MOVLW   0x82        	; 0x82 = 130 decimal-- change here
        MOVWF   regD
wait7   DECFSZ  regC, F     	
        GOTO    wait7		; each 100 increment in this subroutine
        DECFSZ  regD, F		; is dependent on the length of the clock      	
        GOTO    wait7		; period
dly600	MOVLW   0x82        	; 0x82 = 130  decimal-- change here 		
        MOVWF   regD		; Use of an external RC with 220 pF and 6K8 
wait6   DECFSZ  regC, F		; resistor gives approx 2 uS clock period. 
        GOTO    wait6		; For a 4 MHz (the default) of the internal
        DECFSZ  regD, F		; calibrated oscillator, 016h should be changed 
        GOTO    wait6		; to 82h in seven places.
dly500	MOVLW   0x82        	; 0x82 = 130  decimal-- change here 
        MOVWF   regD		
wait5   DECFSZ  regC, F		; = 3F84 @ 2007h     	
        GOTO    wait5		; FOSC2:FOSC0 = 100 for 4 MHZ internal osc.
        DECFSZ  regD, F      	
        GOTO    wait5
dly400	MOVLW   0x82        	; 0x82 = 130  decimal-- change here 		       	
        MOVWF   regD
wait4   DECFSZ  regC, F     	
        GOTO    wait4
        DECFSZ  regD, F      	
        GOTO    wait4
dly300	MOVLW   0x82        	; 0x82 = 130  decimal-- change here        	
        MOVWF   regD
wait3   DECFSZ  regC, F     	
        GOTO    wait3
        DECFSZ  regD, F      	
        GOTO    wait3
dly200	MOVLW   0x82        	; 0x82 = 130  decimal-- change here        	
        MOVWF   regD
wait2   DECFSZ  regC, F     	
        GOTO    wait2
        DECFSZ  regD, F      	
        GOTO    wait2
dly100	MOVLW   0x82        	; 0x82 = 130  decimal-- change here        	
        MOVWF   regD
wait1   DECFSZ  regC, F     	
        GOTO    wait1
        DECFSZ  regD, F      	
        GOTO    wait1
;	
        RETURN
;
; send cq three times then DE
;
cq	movlw   03h        	; 3 decimal
        movwf   0x23		; put 3 in register F
cq1	call    dash		; letter C
        call    dot
        call    dash        
        call    dot       
        call    dly200		; character spacing
        call    dash		; letter Q
        call    dash
        call    dot         
        call    dash
        call    dly600		; word spacing
        decfsz  0x23, F		; quit looping when 0Fh register = 0
	goto	cq1
;
from	call    dash		; D
        call    dot
        call	dot
        call	dly200		; char spacing
        call	dot		; E
        call    dly600		; word spacing
;
; there is no return here, there is never a case when DE is not followed
; by callsign, so we just let it fall through.
;
callsign
;        		
        call    dash		; letter K
	call    dot 
        call    dash
        call    dly200		; character spacing
        call    dash		; number D
        call    dot
        call    dot
        call    dly200		; character spacing
        call    dash		; number 7
        call    dash
        call    dot
        call    dot
        call    dot
        call    dly200		; character spacing
        call    dash		; letter T
        call    dly200		; character spacing
        call    dot		; letter S
        call    dot
        call    dot
        call    dly200		; character spacing
        call    dly600		; word spacing
	RETURN
;
grid    call    dash        	; letter C
        call    dot
        call    dash
        call    dot
        call    dly200      	; character spacing
        call    dash        	; letter N
        call    dot
        call    dly200      	; character spacing
        call    dash        	; number 8
        call    dash
        call    dash
        call    dot
        call    dot
        call    dly200      	; character spacing
        call    dash        	; number 7
        call    dash
        call    dot
        call    dot
        call    dot
        call    dly200      	; character spacing
        call    dot         	; letter U
        call    dot
        call    dash
        call    dly200      	; character spacing
        call    dot         	; letter I
	call	dot
	call	dly600		; word spacing
	RETURN
;
; my call kd7ts starts with a K, so this is an attempt to clarify
; that this is the end of a transmission. Calls beginning with W, A
; or N would cause less confusion. Not an issue for beacon message.
;
longK	movlw   0x01		; load key down data bits
        movwf   PORTC       	; output the key down data bits
        call    dly600     	; key down for 600 msec
        movlw   0x02		; load key up data bits
        movwf   PORTC      	; output the key up data bits
        call    dly100      	; key up for 100 msec    	; 
;
 	movlw   0x01		; load key down data bits
        movwf   PORTC       	; output the key down data bits
        call    dly100     	; key down for 100 msec
        movlw   0x02		; load key up data bits
        movwf   PORTC      	; output the key up data bits
        call    dly100      	; key up for 100 msec
;
	movlw   0x01		; load key down data bits
        movwf   PORTC 		; output the key down data bits
        call    dly600		; key down for 600 msec
        movlw   0x02 		; load key up data bits
        movwf   PORTC 		; output the key up data bits
        RETURN
;
        end
