; KM4UL VERSION
;======== pic beacon 2  980702 petek ============
; (c) 1997 1998 by Peter Kerckhoff
; permission granted to copy for non-commercial use only
; all other rights reserved
; 
; 981004 changed sleep mode to lower current draw
;
; lines with a *** denote changes to the code to make 
; the program work with a 16c84 or 16f84 PIC 
; 
; header information, specify device type, hex numbers 
	list    p=12c508 
;	list    p=16f84		; *** change for 16f84 

	radix   hex 

; configuration word for programming (msb -> lsb) 
; MCLRE = 0 (internal reset) 
; CP = 1 (code protection off) 
; WDTE = 0 (watch dog timer disabled) 
; FOSC1, FOSC0 = 10 (internal 4MHz oscillator) 

	__config b'01010'	; *** comment out for 16f84 

; register equates 

w	equ	0x00 
f	equ	0x01 
pc	equ	0x02 
status	equ	0x03 
zerof	equ	0x02 
caryf	equ	0x00 
port	equ	0x06 

regbase	equ	0x07		; *** comment out for 16f84 
;regbase	equ	0x0c


send	equ	regbase		; the morse data to send
msgreg	equ	regbase+1	; msg string pointer
didah	equ	regbase+2	; on time for di's and dah's
delay1	equ	regbase+3	; delay rtn counters
delay2	equ	regbase+4	;
d100	equ	regbase+5	;
d250	equ	regbase+6	;
d5	equ	regbase+7	;
tonep	equ	regbase+8	; tone period (set by jumpers)
pert	equ	regbase+9	; tone duration
math	equ	regbase+0x0a	; for literal add, subtract


sw0	equ	0x00		; tone select inputs
sw1	equ	0x01		;
pwr	equ	0x02		; transmitter power
onoff	equ	0x03		; on/off input line
ook	equ	0x04		; OOK output line
tone	equ	0x05		; tone output

;--------------------------------------------------
; the 12c508 uses an automatic reset vector of 0x00
; location 0x1ff is used for the internal 4MHz calibration
; value and should not be used or changed
; when using a 16f84 for testing, the org can remain at
; 0x00 as the interrupt ability of the 16f84 isn't used
; so the interrupt vector is not needed

        org     0x00

;--------------------------------------------------
; OPTION register settings (msb -> lsb)
; enable wake-up on pin change (GPUWU = 0)
; disenable weak pullups (GPPU = 1)
; timer0 clock source internal (TOCS = 0)
; timer0 edge select l->h (TOSE = 0)
; prescaler assigned to timer0 (PSA = 0)
; prescaler select of 1:2 (PS2-PS0 = 000)

; gp0 - (in ) select line 0 (lsb)
; gp1 - (in ) select line 1 (msb)
; gp2 - (out) output power to transmitter, 1= on
; gp3 - (in ) on/off, 1= on, 0= off (sleep)
; gp4 - (out) OOK output, 0= off
; gp5 - (out) tone output, 0=off


start	movlw	b'01000000'	; option settings
	option
	movlw	b'11001011'	; port configure
	tris	port

; upon power up, play the ID message, then enter
; the locating beep loop.  During the locating beep
; loop the program checks for the on/off input bit set
; to off, if so, the processor goes to sleep, minimizing
; current draw

long	bsf	port,pwr	; turn the transmitter on
	call	w100mS		; wait 1/2 second
	call	w100mS		; for the transmitter to
	call	w100mS		; stabilize
	call	w100mS
	call	w100mS
	call	logmsg		; play ID message
	bcf	port,pwr	; turn transmitter off

; play the locating beep while keeping time and checking
; for the on/off command, the frequency of the locating
; beep toon is determined by the jumper (switch) settings
; the following code segment sets the half-period time
; for the tone rtn--
;	sw1	sw0	period	half	frequency
;	0	0	1350 uS	675 uS	740 Hz
;	0	1	1000 uS	500 uS	1 kHz
;	1	0	750 uS	375 uS	1.3 kHz
;	1	1	250 uS	500 uS	2 kHz
;
; note that 0=jumper installed, 1= NO jumper

	movlw	d'41'		; setup literal add
	movwf	math
	movlw	d'82'		; preset for 2kHz
	btfss	port,sw1	; test msb
	movlw	d'164'		; lower frequency
	btfss	port,sw0	; test lsb
	addwf	math,w		; lsb=0
	movwf	tonep		; save period count

; now do a similar thing but for the 100mS delay constant

	movlw	d'198'		; delay const for 2kHz
	btfss	port,sw1
	movlw	d'99'
	movwf	math		; save partial result
	clrw			; set w to zero
	btfss	port,sw0
	movlw	d'50'		; set for subtraction
	subwf	math,w		; math-w => w
	movwf	pert		; save 100mS constant

; main loop, produce a locating tone for 1 second out of every
; three, then at 5 minute intervals play the ID message

main5	movlw	d'100'		; 100 loops of 3 seconds each
	movwf	d5		; = 300/60 = 5 minutes

fivel	bsf	port,pwr	; turn on the transmitter
	call	w100mS		; wait 200mS for
	call	w100mS		; transmitter to sabilize

; produce a tone for 1 second, 10 loops of 100mS

	bsf	port,ook	; turn on the OOK output

	movlw	d'10'		; setup for 10x100mS
	movwf	delay1

tnlop	movf	pert,w		; get 100mS constant
	movwf	d100		; based upon tone frequency
wtone	bsf	port,tone	; high cycle of tone
	movf	tonep,w		; get period constant
	movwf	d250
whight	decfsz	d250,f		; delay high period
	goto	whight
	bcf	port,tone	; low cycle of tone
	movf	tonep,w		; get period constant
	movwf	d250
wlowt	decfsz	d250,f		; delay low period
	goto	wlowt
	btfss	port,onoff	; test for on/off
	goto	gnite		; leave if off
	decfsz	d100,f		; done w/100mS?
	goto	wtone		; nope, loop

	decfsz	delay1,f	; done with 1 second?
	goto	tnlop		; nope, loop
	bcf	port,ook	; turn off OOK output
	bcf	port,pwr	; turn off transmitter

; delay 1.8 seconds (18 x 100mS)

	movlw	d'18'
	movwf	d250
d15	call	w100mS
	btfss	port,onoff	; test on/off bit
	goto	gnite		; leave if off
	decfsz	d250,f		; done 1.8 seconds?
	goto	d15		; nope, loop back

	decfsz	d5,f		; done 5 minutes?
	goto	fivel		; nope, loop back
	goto	long		; else play ID message

gnite	bcf	port,ook	; set outputs low
	bcf	port,pwr
	bcf	port,tone
	movlw	b'11111111'	; port configure
	tris	port		; to all input bits
	movf	port,w		; read all port bits
	sleep			; go to sleep

; this routine sends the message stored at msg in morse

logmsg	clrf	msgreg		; clear the message counter
playl	movf	msgreg,w	; get the message counter
	call	msg		; used to point to msg character
				; returned is morse equivalent
play	movwf	send		; save the morse character
	movlw	mEND		; is it the end flag?
	subwf	send,w
	btfss	status,zerof
	goto	morout		; no, so play it
	return			; yes, end, leave

;----------------------------------------------------
; morout
;	enter with the morse character to be transmitted
;	in the send register, this routine will toggle
;	an output line, simulating a morse code transmission
;
; check for a control word delay flag first, then do
; either the delay or start sending the cw
;
morout	movlw	mSpace		; is it a space (between words)
	subwf	send,w
	btfss	status,zerof
	goto	morlop		; not a space, go send didah
	call	w100mS		; space, wait 700mS
	call	w100mS		; for 12wpm cw
	call	w100mS		; 400mS here and another
	call	w100mS		; 300mS at mordn
	goto	mordn

; send the cw from the information stored in the send register
; Shift the eight bit register to the left, if the carry bit
; is 0 then send a di, if the carry bit is a 1 send a dah.
; When the send register = 1000 0000 then all bits have been
; sent.

morlop	movlw	0x01		; setup for di
	bcf	status,caryf	; make sure carry bit is clear
	rlf	send,f		; shift to get bit to send
	btfsc	status,caryf	; skip next instruction for di's
	iorlw	0x02		; 3x di = dah
	movwf	didah		; save didah time

morwat	movlw	d'198'		; loop for 100mS (12 wpm)
	movwf	d100
	bsf	port,ook	; turn on OOK output
wmors	bsf	port,tone	; turn on tone bit (high period)
	movlw	d'82'		; delay for 250 uS (2kHz)
	movwf	d250
whigh	decfsz	d250,f		; high period delay
	goto	whigh
	bcf	port,tone	; low period for tone bit
	movlw	d'82'
	movwf	d250
wlow	decfsz	d250,f		; low period delay
	goto	wlow
	decfsz	d100,f		; loop for 100mS
	goto	wmors

	decfsz	didah,f		; fall thru for di's
	goto	morwat		; or do again twice for dah's
	bcf	port,ook	; turn off OOK output
	call	w100mS		; delay between di-dahs

	movlw	b'10000000'	; check for end of data
	subwf	send,w
	btfss	status,zerof	; not equal, not end
	goto	morlop		; so continue with this character

mordn	call	w100mS		; delay between characters
	call	w100mS		; 300mS for 12wpm
	call	w100mS
	incf	msgreg,f	; move to next character (pointer)
	goto	playl		; loop for rest of message


;-----------------------------------------------------
; 100 mS delay rtn 

;w100mS return                  ; for testing in MPLAB 
                                ; comment the next w100mS 
                                ; and uncomment this one 
                                ; -- speeds things up :) 

w100mS  movlw   d'100'          ; 1 cycle 
        movwf   delay2          ; 1 cycle 

                                ; gets kinda funky here 
                                ; as there is a 1mS rtn 
                                ; built into the 100mS 
                                ; rtn (saving a sub call 
                                ; and stack space!) 

d100ms  movlw   d'197'          ; 1 cycle           ---+ 
        movwf   delay1          ; 1 cycle              | 
d1ms2   goto    $+1             ; 2 cycles (x 197)     | 
        decfsz  delay1,f        ; 1 cycle  (x 197)     | 
        goto    d1ms2           ; 2 cycles (x 197)     | 
                                ; 3 + 197 x 5 = 988    | 
        goto    $+1             ; = 990                |  
        goto    $+1             ; = 992             ---+ 

        decfsz  delay2,f        ; 1 cycle 
        goto    d100ms          ; 2 cycles, = 995 

; setup cycles 2 + 1 for fall thru = 3 
; interior cycles = 100 x 995 = 99500 
; = 99503 uS (99.503 mS) 
; the calling rtn eats up 2 more and the return eats 
; two cycles, = 99507uS, need to eat up 493 uS to 
; give a precise 100mS delay 
; also gives us an approximate 500uS delay

w500uS  movlw   d'122'          ; 1 cycle 
        movwf   delay1          ; 1 cycle 
d101ms  nop                     ; 1 cycle x 122 
        decfsz  delay1,f        ; 1 cycle x 122 
        goto    d101ms          ; 2 cycles x 122 

; 2 + 1 + 4 x 122 = 491 uS 

        goto    $+1             ; waste 2 more cycles 
                                ; for 493 uS, add in 
                                ; the call (2uS) and 
                                ; return (2uS) for 
        return                  ; a grand total of 100mS 


;=========================================================== 
; message area 
; 
;       call the rtns with the message character number in 
;       w, returned is the morse coded in w 
; 
;       the four messages are msg01, msg02, msg03, and msg04 
;       use the following examples for coding up the message 
;       patterns.  Fundamentally the code starts with a 
;       addwf to move to the correct retlw command.  The 
;       return commands pass back the coded morse.  To use 
;       a letter, preceed the letter with a 'm'. 
; 
;       for example, to transmit CQ as message 1... 
; 
;       msg01   addwf   pc,f 
;               retlw   mC 
;               retlw   mQ 
;               retlw   mSpace  (optional space) 
;               retlw   mEND    (required end) 
; 
;       the morse is transmitted in 12wpm (100mS for a dit) 
;       dashes are 3 times as long as a dit.  Between dits 
;       and dahs is silence a dit in length.  A silence 3 
;       dits in length is automatically inserted between 
;       letters.  A silence of 7 dits in length can be added 
;       between words by using the mSpace character 
; 
 
; messages programmed 
;       KB0YRQ telemetry beacon 

msg	addwf   pc,f            ; KB0YRQ telemetry beacon
	retlw   mK 
        retlw   mM 
        retlw   m4 
        retlw   mU 
        retlw   mL 
        retlw   mSpace 
        retlw   mT 
        retlw   mE 
        retlw   mL 
        retlw   mE 
        retlw   mM 
        retlw   mE 
        retlw   mT 
        retlw   mY 
        retlw   mSpace 
        retlw   mB 
        retlw   mE 
        retlw   mA 
        retlw   mC 
        retlw   mO 
        retlw   mN 
        retlw   mEND 

; equates for morse characters 
; specify the coded characters by using 'm' followed 
; by the letter you want to send the coded form of 
; morse is based in... 0 = dit, 1 = dash, roll out 
; the bits, when 0x80 remains the code is done 
; this Morse Code storage rtn was published in _BYTE_ 
; October 1976, pg. 36 in an article by L. Krakauer 

mA      equ     0x60 
mB      equ     0x88 
mC      equ     0xa8 
mD      equ     0x90 
mE      equ     0x40 
mF      equ     0x28 
mG      equ     0xd0 
mH      equ     0x08 
mI      equ     0x20 
mJ      equ     0x78 
mK      equ     0xb0 
mL      equ     0x48 
mM      equ     0xe0 
mN      equ     0xa0 
mO      equ     0xf0 
mP      equ     0x68 
mQ      equ     0xd8 
mR      equ     0x50 
mS      equ     0x10 
mT      equ     0xc0 
mU      equ     0x30 
mV      equ     0x18 
mW      equ     0x70 
mX      equ     0x98 
mY      equ     0xb8 
mZ      equ     0xc8 

m0      equ     0xfc 
m1      equ     0x7c 
m2      equ     0x3c 
m3      equ     0x1c 
m4      equ     0x0c 
m5      equ     0x04 
m6      equ     0x84 
m7      equ     0xc4 
m8      equ     0xe4 
m9      equ     0xf4 

mPeriod equ     0x56 
mComma  equ     0xce 
mQuest  equ     0x32 
mEqual  equ     0x8c 
mColon  equ     0xe2 
mSemi   equ     0xaa 
mSlash  equ     0x94 
mDash   equ     0x86 

mSpace  equ     0x01    ; space between words 
mEND    equ     0x00    ; end of the info 

        end
