/*	morse.c		07.01.2008 08:11

	addendum to SAQrx by Roland Froehlich

-------------------------------------------------------------
. "KLKLKL "
, "LLKKLL "
: "LLLKKK "
; "LKLKLK "
? "KKLLKK "
- "LKKKKL "
( "LKLLK "
) "LKLLKL "
' "KLLLLK "
= "LKKKL "
+ "KLKLK "
/ "LKKLK "
@ "KLLKLK "

Ää "KLLKL "
Öö "LLLK "
Üü "KKLL "
ß  "KKKLLKK "
CH "LLLL "
ÀÅ "KLKL "


È "KLKKL "
É "KKLKK "
Ñ "LLKLL "

Ø
ø
÷
{|}~
!"#$%&'()*+,-./
:;<=>?@
[\]^_`a
-------------------------------------------------------------


Punctuation Mark	Morse
Fullstop (period)				"KLKLKL "  ,
Comma							"LLKKLL "  ,
Colon							"LLLKKK "  ,
Question mark (query)			"KKLLKK "  ,
Apostrophe						"KLLLLK "  ,
Hyphen							"LKKKKL "  ,
Slash ("/")						"LKKLK  "  ,
Brackets (parentheses)			"LKLLKL "  ,
Quotation marks					"KLKKLK "  ,
At sign							"KLLKLK "  ,
Equals sign						"LKKKL  "  ,
                                                
Prosign	Morse                                   
AR, End of message				"KLKLK  "  ,
AS, Wait						"KLKKK  "  ,
BT (or TV), Break in the text	"LKKKL  "  ,
CL, Going off the air ("clear")	"LKLKKLKK ",
SK, End of transmission			"KKKLKL "  ,


Punctuation Mark	Morse
Full-stop (period)	di-dah-di-dah-di-dah
Comma	dah-dah-di-di-dah-dah
Colon	dah-dah-dah-di-di-dit
Question mark (query)	di-di-dah-dah-di-dit
Apostrophe	di-dah-dah-dah-dah-dit
Hyphen	dah-di-di-di-di-dah
Slash ("/")	dah-di-di-dah-dit
Brackets (parentheses)	dah-di-dah-dah-di-dah
Quotation marks	di-dah-di-di-dah-dit
At sign	di-dah-dah-di-dah-dit
Equals sign	dah-di-di-di-dah

Prosign	Morse
AR, End of message	di-dah-di-dah-dit
AS, Wait	di-dah-di-di-dit
BT (or TV), Break in the text	dah-di-di-di-dah
CL, Going off the air ("clear")	dah-di-dah-di-di-dah-di-dit
SK, End of transmission	di-di-di-dah-di-dah


Other Phrases	Abbreviation
Over	K
Roger	R
See you later	CUL
Be seeing you	BCNU
You're	UR
Signal report	RST
Best regards	73
Love and kisses	88

Q Code	Meaning
QSL	I acknowledge receipt
QSL?	Do you acknowledge?
QRX	Wait
QRX?	Should I wait?
QRV	I am ready to copy
QRV?	Are you ready to copy?
QRL	The frequency is in use
QRL?	Is the frequency in use?
QTH	My location is...
QTH?	What is your location?

 


      Notes

If the duration of a dot is taken to be one unit then that of a dash is
three units. The space between the components of one character is one
unit, between characters is three units and between words seven units.
To indicate that a mistake has been made and for the receiver to delete
the last word, send di-di-di-di-di-di-di-dit (eight dots).

The prosigns are combinations of two letters sent together with no space
in between. The other abbreviations and Q codes are sent with the normal
spacing.
	
*/


// not in table:   "LLLL "      /*  CH */ 
// also not the prosigns !!!

#define	MC_SPACE	"S "		/* word space = 7 dits */ 
 

// accessed with full 8 bit ascii code:
//unsigned 
char * alfa_to_morse_patterntab[]= { 
  /* 0x00 */ MC_SPACE    
, /* 0x01 */ MC_SPACE    
, /* 0x02 */ MC_SPACE    
, /* 0x03 */ MC_SPACE    
, /* 0x04 */ MC_SPACE    
, /* 0x05 */ MC_SPACE    
, /* 0x06 */ MC_SPACE    
, /* 0x07 */ MC_SPACE    
, /* 0x08 */ MC_SPACE    
, /* 0x09 */ MC_SPACE    
, /* 0x0A */ MC_SPACE    
, /* 0x0B */ MC_SPACE    
, /* 0x0C */ MC_SPACE    
, /* 0x0D */ MC_SPACE    
, /* 0x0E */ MC_SPACE    
, /* 0x0F */ MC_SPACE    
, /* 0x10 */ MC_SPACE    
, /* 0x11 */ MC_SPACE    
, /* 0x12 */ MC_SPACE    
, /* 0x13 */ MC_SPACE    
, /* 0x14 */ MC_SPACE    
, /* 0x15 */ MC_SPACE    
, /* 0x16 */ MC_SPACE    
, /* 0x17 */ MC_SPACE    
, /* 0x18 */ MC_SPACE    
, /* 0x19 */ MC_SPACE    
, /* 0x1A */ MC_SPACE    
, /* 0x1B */ MC_SPACE    
, /* 0x1C */ MC_SPACE    
, /* 0x1D */ MC_SPACE    
, /* 0x1E */ MC_SPACE    
, /* 0x1F */ MC_SPACE    
, /* 0x20 */ MC_SPACE	/* space */    
, /* 0x21 */ MC_SPACE    
, /* 0x22 */ MC_SPACE    
, /* 0x23 */ MC_SPACE    
, /* 0x24 */ MC_SPACE    
, /* 0x25 */ MC_SPACE    
, /* 0x26 */ MC_SPACE    
, /* 0x27 */ "KLLLLK "  /*  '  */    
, /* 0x28 */ "LKLLK "   /*  (  */    
, /* 0x29 */ "LKLLKL "  /*  )  */      
, /* 0x2A */ MC_SPACE    
, /* 0x2B */ "KLKLK "   /*  +  */    
, /* 0x2C */ "LLKKLL "  /*  , */      
, /* 0x2D */ "LKKKKL "  /*  - */    
, /* 0x2E */ "KLKLKL "  /*  . */    
, /* 0x2F */ "LKKLK "   /*  /  */    
, /* 0x30 */ "LLLLL "	/* 0  */   
, /* 0x31 */ "KLLLL "   /* 1  */   
, /* 0x32 */ "KKLLL "   /* 2  */   
, /* 0x33 */ "KKKLL "   /* 3  */   
, /* 0x34 */ "KKKKL "   /* 4  */   
, /* 0x35 */ "KKKKK "   /* 5  */   
, /* 0x36 */ "LKKKK "   /* 6  */   
, /* 0x37 */ "LLKKK "   /* 7  */   
, /* 0x38 */ "LLLKK "   /* 8  */   
, /* 0x39 */ "LLLLK "   /* 9  */   
, /* 0x3A */ "LLLKKK "  /*  : */      
, /* 0x3B */ "LKLKLK "  /*  ; */      
, /* 0x3C */ MC_SPACE    
, /* 0x3D */ "LKKKL "   /*  =  */      
, /* 0x3E */ MC_SPACE    
, /* 0x3F */ "KKLLKK "  /*  ?  */   
, /* 0x40 */ "KLLKLK "  /*  @  */   
, /* 0x41 */ "KL    "   /* A  */    
, /* 0x42 */ "LKKK  "   /* B  */    
, /* 0x43 */ "LKLK  "   /* C  */    
, /* 0x44 */ "LKK   "   /* D  */    
, /* 0x45 */ "K     "   /* E  */    
, /* 0x46 */ "KKLK  "   /* F  */    
, /* 0x47 */ "LLK   "   /* G  */    
, /* 0x48 */ "KKKK  "   /* H  */    
, /* 0x49 */ "KK    "   /* I  */    
, /* 0x4A */ "KLLL  "   /* J  */    
, /* 0x4B */ "LKL   "   /* K  */    
, /* 0x4C */ "KLKK  "   /* L  */    
, /* 0x4D */ "LL    "   /* M  */    
, /* 0x4E */ "LK    "   /* N  */    
, /* 0x4F */ "LLL   "   /* O  */    
, /* 0x50 */ "KLLK  "   /* P  */    
, /* 0x51 */ "LLKL  "   /* Q  */    
, /* 0x52 */ "KLK   "   /* R  */    
, /* 0x53 */ "KKK   "   /* S  */    
, /* 0x54 */ "L     "   /* T  */    
, /* 0x55 */ "KKL   "   /* U  */    
, /* 0x56 */ "KKKL  "   /* V  */    
, /* 0x57 */ "KLL   "   /* W  */    
, /* 0x58 */ "LKKL  "   /* X  */    
, /* 0x59 */ "LKLL  "   /* Y  */    
, /* 0x5A */ "LLKK  "   /* Z  */    
, /* 0x5B */ MC_SPACE    
, /* 0x5C */ MC_SPACE    
, /* 0x5D */ MC_SPACE    
, /* 0x5E */ MC_SPACE    
, /* 0x5F */ MC_SPACE    
, /* 0x60 */ MC_SPACE    
, /* 0x61 */ "KL    "   /* A  */    
, /* 0x62 */ "LKKK  "   /* B  */    
, /* 0x63 */ "LKLK  "   /* C  */    
, /* 0x64 */ "LKK   "   /* D  */    
, /* 0x65 */ "K     "   /* E  */    
, /* 0x66 */ "KKLK  "   /* F  */    
, /* 0x67 */ "LLK   "   /* G  */    
, /* 0x68 */ "KKKK  "   /* H  */    
, /* 0x69 */ "KK    "   /* I  */    
, /* 0x6A */ "KLLL  "   /* J  */    
, /* 0x6B */ "LKL   "   /* K  */    
, /* 0x6C */ "KLKK  "   /* L  */    
, /* 0x6D */ "LL    "   /* M  */    
, /* 0x6E */ "LK    "   /* N  */    
, /* 0x6F */ "LLL   "   /* O  */    
, /* 0x70 */ "KLLK  "   /* P  */    
, /* 0x71 */ "LLKL  "   /* Q  */    
, /* 0x72 */ "KLK   "   /* R  */    
, /* 0x73 */ "KKK   "   /* S  */    
, /* 0x74 */ "L     "   /* T  */    
, /* 0x75 */ "KKL   "   /* U  */    
, /* 0x76 */ "KKKL  "   /* V  */    
, /* 0x77 */ "KLL   "   /* W  */    
, /* 0x78 */ "LKKL  "   /* X  */    
, /* 0x79 */ "LKLL  "   /* Y  */    
, /* 0x7A */ "LLKK  "   /* Z  */    
, /* 0x7B */ MC_SPACE    
, /* 0x7C */ MC_SPACE    
, /* 0x7D */ MC_SPACE    
, /* 0x7E */ MC_SPACE    
, /* 0x7F */ MC_SPACE    
, /* 0x80 */ MC_SPACE    
, /* 0x81 */ MC_SPACE    
, /* 0x82 */ MC_SPACE    
, /* 0x83 */ MC_SPACE    
, /* 0x84 */ MC_SPACE    
, /* 0x85 */ MC_SPACE    
, /* 0x86 */ MC_SPACE    
, /* 0x87 */ MC_SPACE    
, /* 0x88 */ MC_SPACE    
, /* 0x89 */ MC_SPACE    
, /* 0x8A */ MC_SPACE    
, /* 0x8B */ MC_SPACE    
, /* 0x8C */ MC_SPACE    
, /* 0x8D */ MC_SPACE    
, /* 0x8E */ MC_SPACE    
, /* 0x8F */ MC_SPACE    
, /* 0x90 */ MC_SPACE    
, /* 0x91 */ MC_SPACE    
, /* 0x92 */ MC_SPACE    
, /* 0x93 */ MC_SPACE    
, /* 0x94 */ MC_SPACE    
, /* 0x95 */ MC_SPACE    
, /* 0x96 */ MC_SPACE    
, /* 0x97 */ MC_SPACE    
, /* 0x98 */ MC_SPACE    
, /* 0x99 */ MC_SPACE    
, /* 0x9A */ MC_SPACE    
, /* 0x9B */ MC_SPACE    
, /* 0x9C */ MC_SPACE    
, /* 0x9D */ MC_SPACE    
, /* 0x9E */ MC_SPACE    
, /* 0x9F */ MC_SPACE    
, /* 0xA0 */ MC_SPACE    
, /* 0xA1 */ MC_SPACE    
, /* 0xA2 */ MC_SPACE    
, /* 0xA3 */ MC_SPACE    
, /* 0xA4 */ MC_SPACE    
, /* 0xA5 */ MC_SPACE    
, /* 0xA6 */ MC_SPACE    
, /* 0xA7 */ MC_SPACE    
, /* 0xA8 */ MC_SPACE    
, /* 0xA9 */ MC_SPACE    
, /* 0xAA */ MC_SPACE    
, /* 0xAB */ MC_SPACE    
, /* 0xAC */ MC_SPACE    
, /* 0xAD */ MC_SPACE    
, /* 0xAE */ MC_SPACE    
, /* 0xAF */ MC_SPACE    
, /* 0xB0 */ MC_SPACE    
, /* 0xB1 */ MC_SPACE    
, /* 0xB2 */ MC_SPACE    
, /* 0xB3 */ MC_SPACE    
, /* 0xB4 */ MC_SPACE    
, /* 0xB5 */ MC_SPACE    
, /* 0xB6 */ MC_SPACE    
, /* 0xB7 */ MC_SPACE    
, /* 0xB8 */ MC_SPACE    
, /* 0xB9 */ MC_SPACE    
, /* 0xBA */ MC_SPACE    
, /* 0xBB */ MC_SPACE    
, /* 0xBC */ MC_SPACE    
, /* 0xBD */ MC_SPACE    
, /* 0xBE */ MC_SPACE    
, /* 0xBF */ MC_SPACE    
, /* 0xC0 */ "KLKL "      /*  ÀÅ */      
, /* 0xC1 */ MC_SPACE    
, /* 0xC2 */ MC_SPACE    
, /* 0xC3 */ MC_SPACE    
, /* 0xC4 */ "KLLKL "     /*  Ää */    
, /* 0xC5 */ "KLKL "      /*  ÀÅ */      
, /* 0xC6 */ MC_SPACE    
, /* 0xC7 */ MC_SPACE    
, /* 0xC8 */ "KLKKL "     /*  È  */     
, /* 0xC9 */ "KKLKK "     /*  É  */     
, /* 0xCA */ MC_SPACE    
, /* 0xCB */ MC_SPACE    
, /* 0xCC */ MC_SPACE    
, /* 0xCD */ MC_SPACE    
, /* 0xCE */ MC_SPACE    
, /* 0xCF */ MC_SPACE    
, /* 0xD0 */ MC_SPACE    
, /* 0xD1 */ "LLKLL "     /*  Ñ  */     
, /* 0xD2 */ MC_SPACE    
, /* 0xD3 */ MC_SPACE    
, /* 0xD4 */ MC_SPACE    
, /* 0xD5 */ MC_SPACE    
, /* 0xD6 */ "LLLK "      /*  Öö */    
, /* 0xD7 */ MC_SPACE    
, /* 0xD8 */ MC_SPACE    
, /* 0xD9 */ MC_SPACE    
, /* 0xDA */ MC_SPACE    
, /* 0xDB */ MC_SPACE    
, /* 0xDC */ "KKLL "      /*  Üü */     
, /* 0xDD */ MC_SPACE    
, /* 0xDE */ MC_SPACE    
, /* 0xDF */ "KKKLLKK "   /*  ß  */    
, /* 0xE0 */ MC_SPACE    
, /* 0xE1 */ MC_SPACE    
, /* 0xE2 */ MC_SPACE    
, /* 0xE3 */ MC_SPACE    
, /* 0xE4 */ "KLLKL "     /*  Ää */     
, /* 0xE5 */ MC_SPACE    
, /* 0xE6 */ MC_SPACE    
, /* 0xE7 */ MC_SPACE    
, /* 0xE8 */ MC_SPACE    
, /* 0xE9 */ MC_SPACE    
, /* 0xEA */ MC_SPACE    
, /* 0xEB */ MC_SPACE    
, /* 0xEC */ MC_SPACE    
, /* 0xED */ MC_SPACE    
, /* 0xEE */ MC_SPACE    
, /* 0xEF */ MC_SPACE    
, /* 0xF0 */ MC_SPACE    
, /* 0xF1 */ MC_SPACE    
, /* 0xF2 */ MC_SPACE    
, /* 0xF3 */ MC_SPACE    
, /* 0xF4 */ MC_SPACE    
, /* 0xF5 */ MC_SPACE    
, /* 0xF6 */ "LLLK "      /*  Öö */    
, /* 0xF7 */ MC_SPACE    
, /* 0xF8 */ MC_SPACE    
, /* 0xF9 */ MC_SPACE    
, /* 0xFA */ MC_SPACE    
, /* 0xFB */ MC_SPACE    
, /* 0xFC */ "KKLL "      /*  Üü */     
, /* 0xFD */ MC_SPACE    
, /* 0xFE */ MC_SPACE    
, /* 0xFF */ MC_SPACE    
};	// alfa_to_morse_patterntab[]



typedef struct morse_control_struct
{
	unsigned char *  text_PTR;		
	int		text_IDX;		// index 0 .. LEN
	
	unsigned char *  morse_PAT;		// actual pattern pointer

	int		message_sended;	// counts messages
	int		max_message;	// repeat number
	
	int		morse_preGAP;
	int		morse_silent;	// at begin inactiv 0 .. indexA
	int		morse_modlen;	// samples for activ modulation: K or L.
	int		morse_index;	// relativ samples: 0 .. indexA+modlen for modulation.
	
	int		morse_ditLEN;	// sample count of dit, tempo is: WordPerMinute * ditLEN/ms = 1200 milli-sec
	double	R,Yn;			// envelope, 1.order recursive filter, Timeconstant = 5ms for 10%, -20dB release
		
} morse_control_type;

morse_control_type A_morse, B_morse;	// area for transmission morse text over 2 channels independant

void Set_Morse_String ( morse_control_type * MCTL, char * textstring, int ditLEN )
{
	MCTL->morse_index =  100;	// force restart
	MCTL->morse_silent=  0;
	MCTL->morse_modlen=  0;
	MCTL->message_sended=0;
	MCTL->max_message = 10000;
	
	MCTL->morse_preGAP=  0;
	MCTL->morse_ditLEN=  ditLEN;
	MCTL->text_IDX    =  0;
	MCTL->text_PTR    =  (unsigned char *) textstring;
	MCTL->morse_PAT   =  (unsigned char *) " ";	// force rescanning
	
	MCTL->Yn = 0.0;
	
	MCTL->R = 1.0 - exp( log(0.1)/(0.005 * FS ) );	// 5 ms for -20dB release time
}

double keyed_amp;

double Menvi ( morse_control_type * MCTL, int this_Xn )			// morse modulation envelope
{	
	MCTL->Yn = this_Xn * MCTL->R  + (1.0 - MCTL->R) * MCTL->Yn;	// 1.order recursive filter
	if ( MCTL->Yn > 1.0) MCTL->Yn = 1.0;		// saturation
	if ( this_Xn == 0) 
		if ( MCTL->Yn <= 0.01) MCTL->Yn = 0.0;	// stop at -40 dB, 2 Timeconstants, 10 ms
	return MCTL->Yn;	
}


double get_morse_modulation ( morse_control_type * MCTL)
{	
	unsigned char c, tnext ;
	unsigned char * Ptr;

	if ( MCTL->message_sended >= MCTL->max_message ) return Menvi(MCTL,0);
		
	MCTL->morse_index++;	// increment sample count

	if ( MCTL->morse_index <= MCTL->morse_silent)   					return Menvi(MCTL,0);	// pause modulation	
	if ( MCTL->morse_index <= (MCTL->morse_modlen+MCTL->morse_silent))	return Menvi(MCTL,1);	// activ modulation

new_char:

	MCTL->morse_index  = 0;	// restart sample counter
	
	if ( !MCTL->morse_PAT) return Menvi(MCTL,0);	
	
	c = *MCTL->morse_PAT++;
	
	if ( c=='K')
	{	
		MCTL->morse_silent = MCTL->morse_ditLEN + MCTL->morse_preGAP;
		MCTL->morse_preGAP = 0;
		MCTL->morse_modlen = MCTL->morse_ditLEN;
		return Menvi(MCTL,0);	// pause modulation	
	}

	
	if ( c=='L')
	{
		MCTL->morse_silent = MCTL->morse_ditLEN + MCTL->morse_preGAP;
		MCTL->morse_preGAP = 0;
		MCTL->morse_modlen = 3* MCTL->morse_ditLEN;
		return Menvi(MCTL,0);	// pause modulation	
	}
			
	
	if ( c=='S')	// wordspace
	{
		MCTL->morse_silent = (7-3)* MCTL->morse_ditLEN;	// 1 dah subtracted for following non-space character!
		MCTL->morse_modlen = 0;	// no modulation
		return Menvi(MCTL,0);			// pause modulation	
	}
	
		
//	get next character from string:

	if ( !MCTL->text_PTR) return Menvi(MCTL,0);
	
	tnext = MCTL->text_PTR [ MCTL->text_IDX ];
	MCTL->text_IDX++;

	if ( tnext == 0)	// repeat text:
	{	MCTL->text_IDX = 0;
		tnext = MCTL->text_PTR [ MCTL->text_IDX ];
		MCTL->text_IDX++;
		MCTL->message_sended++;
		if ( MCTL->message_sended >= MCTL->max_message ) return Menvi(MCTL,0);
	}	
		
//	if ( tnext != 0)
	{	
	    Ptr = (unsigned char *) alfa_to_morse_patterntab[tnext];	
										  
		MCTL->morse_PAT = Ptr;
		
		if ( *Ptr == 'S')	MCTL->morse_preGAP = 0;
		else				MCTL->morse_preGAP = 2* MCTL->morse_ditLEN;	// summed to 3 dits= 1 dah
		
		goto new_char;
										  			
	}

		
}	// get_morse_modulation ()


static long SIRAND16 ( long * xnseed)
{
	*xnseed = 4093L* (* xnseed) + 129L;
	return (*xnseed );
}

static float fRAND16(void )	// return random, +/- 1.0 amplitude, periode = 2^32
{
	static long seed = 0x123456;
	float const long_scale= 1.0/2147483648.0;	// 2^-31 

	return 	(float) SIRAND16( &seed) * long_scale ;
}

static long irandom ()
{
	static long xnseed = 0x123456L;
	xnseed = 4093L * xnseed + 129L;     /* periode = 2^32 */
	return (xnseed );
}
	
