'{$STAMP BS2}

'										Date:	April 19, 2003
'										File: PL-DDS-ver3.bs2
'					Gary S. Kath
'					   N2OT
'
' This program will send a Morse Code Character given an ASCII character.  The program
'stores a special 8-bit code into the BasicStamp EEPROM for each of the characters.
'The special 8-bit code contains the Morse code for the character in the 5 MSBs
'and stores the number of dots/dashes in the Morse code for the remaining 3 LSBs.
'Characters with more than 5 dots/dashes are handled differently.

' The special codes are arranged in memory sequencially idential to the ASCII character set.
'When a ASCII character is passed to the Send routine it first subtracts 40 from the decimal
'equilvalent of the ASCII character.  This value is then a pointer address to the special code
'stored in the EEPROM.  The special character is retrieved from EEPROM and the Morse Code
'bits and number of dots/dashes are stripped off.

' For example to send the Morse Code character "C":
'the decimal value of the ASCII code "C" is 67.  67-40 = 27.  Retrieve the 27nd
'special character in EEPROM at address 27:  %01010100. The 3 LSBs: %100 = 4 indicate
'there will be 4 dots/dashes.  The 4 MSBs: %0101 is the Morse Code where a logic
'1 = dot and logic 0 = dash.
' 
'Once the Morse Code is retrieved the software checks each bit and then sends out the
'Morse Code.
'
'NOTE:  Characters must be in capital letters !!!!!!!!!
'
'***********************************************************************************************
'Declare variables & contants
DEFINE OSC 4					'set osc freq to 4 MHz
include "modedefs.bas"

SideTonePitch con 2500				'This constant set the pitch of the side tone
DitDuration con	37				'The duration of the dit is milliseconds
DahDuration	con DitDuration * 3		'The duration of the dah in milliseconds
SidetonePin	con 0					'Sidetone connected to this pin
LEDPin con 4					'LED connected to this pin
IDTimeOut con 9					'number of minutes to wait before sendin ID reminder

ASCII_Char var byte				'This is the ASCII Character to be sent
x var byte						'General purpose loop variable
y var word						'General purpose variable
Code var byte
NoOfDotsDashes var byte				'Variable containing number of dots/dashes in Morse Code
MorseCode var byte				'The Morse Code of the char where 1=dit, 0=dah
DitOrDah var byte
CodeStartEEAdr var word				'Address pointer to Morse Code in EEPROM
StrAddr var word
char var byte
result var word					'Temperature sensor result
TimeOutIncrement var  byte			'Keeps track of number of seconds mic PTT is pressed			'
PLToneFreq var word				'PL Tone frequency in Hertz
PLToneAdr var byte				'Adr of tone frequency in memory
Junk var word
IDTimeOutCounter	var  word			'Variable keeping track of number of minutes before ID
counter var word


DataP		con	2
Clock		con	1
Latch		con	3
				
'------------------------------------------------------------------------------------

'The following data values are stored in EEPROM.  Each byte contains
'the Morse Code and the number of dots & dashes of the ASCII character
'shown in the comments.  The right 3-bits of the byte tell how many
'dots & dashes in the Morse Code.  The left 5-bits is the Morse Code
'where 0=dash and 1=dot.  For example:
'	Y = 01000100 
'There are a few Morse Code characters that have more than 5 dots &
'dashes (i.e. ?, .). These are handled by "if" statements in the SendChar
'subroutine where if the right 3-bits = 110 then a dit is sent at the
'6th position and if the right 3-bits = 111 then a dah is sent at the 
'6th poistion

data %01001111, %01001111, %00000000, %00000000, %00110111				'()* + ,							',
data %01110101, %10101111, %01101101, %00000101, %10000101, %11000101		'-./012
data %11100101, %11110101, %11111101, %01111101, %00111101, %00011101		'345678
data %00001101, %00011110, %01010110, %00000000, %00000000, %00000000		'9:;<=>
data %11001110, %00000000									'?@	
data %10000010, %01110100, %01010100, %01100011, %10000001, %11010100		'ABCDEF
data %00100011, %11110100, %11000010, %10000100, %01000011, %10110100		'GHIJKL
data %00000010, %01000010, %00000011, %10010100, %00100100, %10100011		'MNOPQR
data %11100011, %00000001, %11000011, %11100100, %10000011, %01100100		'STUVWX
data %01000100, %00110100									'YZ

DefaultPLToneEEAdr data %00000000								'Power up PL Tone

'--------------------------------------------------------------------------------------
'
'Place your messages here

F1 data "N2OT%"
F2 data "PL %"

'---------------------------------------------------------------------------------------
'---------------------------------------------------------------------------------------
Start:
	IDTimeOutCounter = 0
	junk = 0

' Send my call sign
	StrAddr = F1
	gosub SendMessageString
	pause 1000

'Get default PL Tone
	READ DefaultPLToneEEAdr, PLToneAdr
	gosub GetTone

'Turn on default PL Tone
	counter = (PLToneFreq * 200)/190			'calculate divider for ML2036 chip
	Shiftout DataP,Clock,lsbfirst,[counter\16]	'program ML2036
	pulsout Latch,1

'Send default PL Tone via CW message
	StrAddr = F2
	gosub SendMessageString
	gosub SendDigits
	pause 400
	junk = 0

Main:
									'Check if port 1 is logic low.  If so change the PL Tone
	if PORTB.7 = 0 then  ChangeTone
	if PORTB.6 = 0 then  ChangeTone
	if PORTA.1 = 0 then  MainContu2
	TimeOutIncrement= 0
MainContu1:
	pause 1000
	IDTimeOutCounter = IDTimeOutCounter + 1
	if IDTimeOutCounter/60 >= IDTimeOut then SendIDReminder
	goto Main

MainContu2:
	TimeOutIncrement = TimeOutIncrement + 1
	if TimeOutIncrement >= 60 then SendTimeOutReminder
	goto MainContu1
'*************************** Change Tone ******************************
'Increment to the next tone value.  When done save PLToneAdr in EEPROM
'**********************************************************************

ChangeTone:
	pause 500
	gosub GetTone
	gosub SendDigits
	pause 600
	if PORTB.7 = 0 then IncUP
	if PORTB.6 = 0 then IncDWN
	goto SaveToneAdr

IncUP:
	pause 10
	if PLToneAdr > 37 then ResetToMax
	PLToneAdr = PLToneAdr + 1
	goto ChangeTone

ResetToZero:
	PLToneAdr = 0
	goto ChangeTone

IncDWN:
	pause 10
	if PLToneAdr < 1 then ResetToZero
	PLToneAdr = PLToneAdr - 1
	goto ChangeTone

ResetToMax:
	PLToneAdr = 38
	goto ChangeTone


SaveToneAdr:					
	Junk = PLToneAdr 			
	WRITE DefaultPLToneEEAdr, Junk
	pause 200
	counter = (PLToneFreq * 200)/190			'calculate divider for ML2036 chip
	Shiftout DataP,Clock,lsbfirst,[counter\16]	'program ML2036
	pulsout Latch,1
	goto Start
	

'*******************************************************************************

'  Send ID Reminder after IDTimeOutCounter number of minutes
SendIDReminder:
	StrAddr = F1
	gosub SendMessageString
	IDTimeOutCounter = 0
	goto Main

SendTimeOutReminder:
	junk = junk + 1
	ASCII_Char = junk + 48
	gosub SendChar
	TimeOutIncrement = 0
	goto Main
'************************** GetTone *********************************************
'
'This subroutine will get PL Tone frequency give the PLToneAdr.  
'The tone is return in the variable PLToneFreq
'
'********************************************************************************
GetTone:
	If PLToneAdr > 12 then GetToneContu2
	Junk = PLToneAdr
	LOOKUP Junk, [0, 67, 72, 74, 77, 80, 83, 85, 89, 92, 95, 97, 100], PLToneFreq	
	goto GetToneDone
GetToneContu2:
	If PLToneAdr > 25 then GetToneContu3
	Junk = PLToneAdr - 13
	LOOKUP Junk, [104, 107, 111, 115, 119, 123, 127, 132, 137, 141, 146, 151, 157], PLToneFreq
	goto GetToneDone
GetToneContu3:
	Junk = PLToneAdr - 26	
	LOOKUP Junk, [162, 168, 174, 180, 186, 193, 204, 211, 218, 226, 234, 242, 250], PLToneFreq 

GetToneDone:
	return


'********************** Send Message String **************************
'
'This routine will send a message string of ASCII characters in Morse Code.
'Prior to use the user must specify a pointer to the message string using
'the variable StrAddr.  The routine continues to send the characters until
'a "%" is reached in the message string.
'
'*********************************************************************

SendMessageString:
	READ StrAddr, ASCII_Char			'Retrieve a character 
	if ASCII_Char = "%" then SMScont1		'Check for if last character "%"
	gosub SendChar					'Send the Morse Code
	StrAddr = StrAddr + 1				'Advance to next character in string
	goto SendMessageString				'Continue until done
SMScont1:
return

'********************** Send Digits ******************
'
'This routine will send the Morse Code PL Tone digits one by one.
'Leading zero is removed.
'
'*********************************************************************

SendDigits:

	result = PLToneFreq/100
	if result = 0 then SendDigitsContu1
	ASCII_Char = result + 48
	gosub SendChar

SendDigitsContu1:
	result = (PLToneFreq//100)/10
	ASCII_Char = result + 48
	gosub SendChar

	result = (PLToneFreq//100)//10
	ASCII_Char = result + 48
	gosub SendChar
return

'**********************  SendChar ***********************************
'
'This subroutine will send the Morse code of the ASCII character
'in the variable x.  The routine handles . & ? in a special manner
'because the number of dots & dashes exceeds 5.  Since the 
'Morse Code characters are stored in the same order as ASCII characters,
'40 is subtracted from the ASCII character and this provides a
'pointer to the data in EEPROM of the Morse Code equivalent.
'The routine then retrieves this value strips off the Morse Code
'and the number of dots & dashes and then one by one shifts
'the bits to the left. Each time it checks if the bit is logic 1 
'which corresponds to a dit and logic 0 which corresponds to a dah.
'*********************************************************************

SendChar:

	if ASCII_Char = " " then Space		'Pause if space

	CodeStartEEAdr = ASCII_Char - 40		'Subtracting 40 from ASCII character results in
								'a pointer to the equivalent Morse code stored in EEPROM

	READ CodeStartEEAdr,Code			'Get Morse Code from EEPROM

	NoOfDotsDashes = Code & %00000111		'Strip off right 3-bits which equals number of dots & dashes
	MorseCode = Code &  %11111000			'Strip off left 5-bits which equals the Morse Code

StartSendChar:
	if NoOfDotsDashes = 0 then EndSendChar	'Check for invalid character
	if NoOfDotsDashes = 6 then SpecialCharDit	'Char with 6 dots/dashes and with dot at end
	if NoOfDotsDashes = 7 then SpecialCharDah	'Char with 6 dots/dashes and with dash at end

Begin:
	for x = 1 to NoOfDotsDashes			'Check left bit; if 1 send dit if 0 send dah	
		DitOrDah = MorseCode & %10000000
		If DitOrDah = 0 then contu0
		gosub SendDit
		goto contu1
	   contu0:
		gosub SendDah
	   contu1:
		pause ditDuration				'Pause between dot/dashes should be 1 dit duration
		MorseCode = MorseCode << 1		'Move bits left by 1 position and repeat 
	next

	pause ditDuration * 3				'Pause between characters should be 3 dit durations
	goto EndSendChar

SpecialCharDah:
	MorseCode = MorseCode & %11111000
	NoOfDotsDashes = 6
	goto Begin

SpecialCharDit:
	MorseCode = MorseCode | %00000100
	NoOfDotsDashes = 6
	goto Begin

Space:
	pause ditduration * 7				'Pause between words should be 7 bit durations

EndSendChar:

return


'**********************  SendDit ***********************************

'This routine will send a dit out pin LEDPin of duration DitDuration.  It also
'with send a tone of SideTonePitch to an AC coupled speaker connected to SidetonePin

'*******************************************************************

SendDit:
	low LEDPin
	FREQOUT SidetonePin,DitDuration,SideTonePitch
	high LEDPin
	return

'**********************  SendDah ***********************************

'This routine will send a dah out pin LEDPin of duration DahDuration.  It also
'with send a tone of SideTonePitch to an AC coupled speaker connected to SidetonePin

'*******************************************************************

SendDah:
	low LEDPin
	FREQOUT SidetonePin,DahDuration,SideTonePitch
	high LEDPin
	return


end

