/* A MORSE  by F5BEZ  on Teensy 2  Development Board
 * http://www.pjrc.com/teensy/
 * Copyright (c) 2008, 2010 PJRC.COM, LLC
 * 
 *
 * Adaptative MORSE decodeur & Keyer by F5BEZ  Dominique LEVEQUE   (c)
 * V1  1977       doc Petit QST , doc  WB9KPT I/0 , W6PRO  about timing DD and LS & flowchart  
 * V2  1979       F1BEZ     assembleur Intel  8080 CPU  ( out char on a rs232 terminal  )
 * V3  2011       F5BEZ     Phoenix from flowchart and upgrade for paddles keyers
 *
 * V3.0  10/06/2011  Teensy 2  straight key, out rx char USB for PC  (serial hd-listen)
 * V3.1  11/06/2011  add standalone display LCD  of the 16 last caracters... 
 * V3.2  16/06/2011  add keyer 2 inputs  1 or 2  paddles, no-iambic, iambic 
 * V3.3  22/06/2011  add commands 1 "smart button", Tx CW, buffers, A/D, eeprom   
 * V3.4  14/08/2011  add commands by serial and external programme amorse.exe  
 * V3.5  15/10/2011  add keyer iambic modes A B  unsqueeze 2 contacts  add dot ( dash )   
 * 
 * 
 * somes parts of codes (analog, eeprom, usb-serial) are adapted from //http://www.pjrc.com/teensy
 * All amorseV35.zip, software and its documentation, should not be separated.
 * Users radioamateur and education, if non-commercial, are permitted to use under conditions :
 * The copyright notices and versions above must be included in your evolutions
 * of this software, and please with a copy for update to f5bez-4@orange.fr  73
 *
 *
 * L'ensemble amorseV35.zip, logiciel et sa documentation, ne doivent pas être dissocié.
 * Les utilisations non commerciales dans les domaines radioamateur et éducation, sont permises aux conditions que   
 * les notifications d'auteur et des versions ci-dessus doivent être incluses, 
 * dans vos reprises de ce logiciel, dont copie svp  à  f5bez-4@orange.fr    73  
 */

//-------- todo / reste à faire  ----------
// todo  or not yet coded or solved :  A finir ou pas encore solutionné  :
// inp s-metre  in repeater mode  by A/D and dc mem supercap    or by CAT serial request ...
// ------- open ideas ----------- 
// command      3 or 4  inputs  1 push 1 left 1 right  ( 1 escape ? )     
// or one rotate-push  button ( same of my GPS NAV in my car   or  same sport watche )
// one push display on the LCD the start menu command, a time-out ( or escape ) come back to rx loop
// rotate left or right lift up or down the list commands on the LCD 
// a time-out after come back too, or a push accept the command displayed   
// if it's a sub menu , the process do again    


//-------- conventions ----------
//
// here comes conventions for variables names types :  bool  byte 
// AVR C  bool don't exist.  It take the same minimum place like a char 
#define bool char unsigned      // just used to specifie  bin  0 or 1 FALSE/TRUE
//char unsigned  same  uint8_t 
//int  same uint16_t 
//#define byte uint8_t
#define byte char unsigned      // as 8 bit  0x00..0xFF  0..255

// local var name 'car' in fcts are a short for 1 'caracter' 
// my representation for code blocks { } is always vertically one under the other ' box ' 
// #nnn are TAGs to quickly found a proc.  under edit
//-------- tools used ----------
// TeensyLoader (xp , vista)   7 not tested ! 
// Edit with Programmer's Notepad 2    template C/C++ 
// Compilateur C   avr-gcc (WinAVR 20100110) 4.3.3 
// makefile  is completed with  .c  related, somes are little adapted
//
// warning  on compil 
// ... differ in signedness //  8 bit signed / not signed ! no matter !
// 
// size place  
//   text	   data	    bss	    dec	    hex	filename
//  19762	   1002	      4	  20768	   5120	amorse.elf
// Teensy 2  prg 32K eeprom 1024  ram 2560   var heap stack  !! almost full
//											 near limit stack  heap for ram ...
//-------- includes --------
//
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <avr/eeprom.h> //http://www.pjrc.com/teensy/td_libs_EEPROM.html
#include <util/delay.h>
#include "usb_serial.h"
#include "print.h"
#include "analog.h"
#include "amorse.h"
#include "LCD_1x16.h" 
//
//-------- TEENSY 2  hardware define inp out -------------
//
#if defined(__AVR_ATmega32U4__) || defined(__AVR_AT90USB1286__)

// --- INPUTS ---

// port F  bit 0  F0 straihgt key   0 = input   1 output ,  1 avec pull up 
#define KEYSTRG_CONFIG  (DDRF  &= ~(1<<0)) 
#define KEYSTRG_PULLUP  (PORTF |=  (1<<0))   

// port F  bit 1  F1 dot                         1 with pull up 
#define KEYIDOT_CONFIG  (DDRF  &= ~(1<<1)) 
#define KEYIDOT_PULLUP  (PORTF |=  (1<<1))

// port F  bit 4  F4 dash                        1 avec pull up 
#define KEYIDASH_CONFIG  (DDRF  &= ~(1<<4)) 
#define KEYIDASH_PULLUP  (PORTF |=  (1<<4))   


// port F  bit 5  F5 smart key command button    1 avec pull up 
#define KEYSCMD_CONFIG  (DDRF  &= ~(1<<5)) 
#define KEYSCMD_PULLUP  (PORTF |=  (1<<5))   

 
 // port F  bit 7  F7  spare    if not analog F7   1 avec pull up 
//#define KEYIDASH_CONFIG  (DDRF  &= ~(1<<7)) 
//#define KEYIDASH_PULLUP  (PORTF |=  (1<<7))   


// port F  bit 6  F6 analog inp  A6  pot 10k Vcc  no pull up    speed in tx
#define ANALOGA6        (DIDR0 = 0x40)           
// port F  bit 7  F7  analog inp  A7   as s-meter input  no pull up
#define ANALOGA7        (DIDR0 = 0x80)     // see pb F4            
  
   
// --- OUTPUTS ---

// port D  bit 1  D1  led + beeper external active 1    
#define OUTCWBIP_CONFIG	(DDRD |= (1<<1))
#define OUTCWBIP_ON		(PORTD |= (1<<1))
#define OUTCWBIP_OFF	(PORTD &= ~(1<<1))

// port D  bit 2  D2  CW OUT  KEY TX   active 0    
#define OUTCWKEY_CONFIG	(DDRD |= (1<<2))
#define OUTCWKEY_ON		(PORTD &= ~(1<<2))
#define OUTCWKEY_OFF	(PORTD |= (1<<2))

// port D  bit 3  D3  CW OUT  MOX PTT TX  active 0    
#define OUTCWMOX_CONFIG	(DDRD |= (1<<3))
#define OUTCWMOX_ON		(PORTD &= ~(1<<3))
#define OUTCWMOX_OFF	(PORTD |= (1<<3))

// port D  bit 6  D6  led inside Teensy  active 1
#define OUTCWLED_CONFIG	(DDRD |= (1<<6))
#define OUTCWLED_ON		(PORTD |= (1<<6))       
#define OUTCWLED_OFF	(PORTD &= ~(1<<6))

// port D  bit 7  D7  CW OUT Toggle Audio active 1
#define OUTCWTAF_CONFIG	(DDRD |= (1<<7))
#define OUTCWTAF_ON		(PORTD |= (1<<7))       
#define OUTCWTAF_OFF	(PORTD &= ~(1<<7))




#define CPU_PRESCALE(n)	(CLKPR = 0x80, CLKPR = (n))

#endif

//--------------------------------------------
//
// --- defines ---
//
//--------------------------------------------


#define DELAY1MS     1    // adjust   1ms delay    
#define DELAY500US   500  // adjust   uS    half previous
#define DELAYCWMOX   200  // adjust   mS    ptt cde before 1st dot or dash   ( post tx )
#define DELAYDSPY    300  // time display type command on LCD   mS 

#define UTINITIAL   90    // Unit Time ( dot ) start about 10 wpm  see DELAY1MS see table 
#define ELOVERFLOW  1200  // !! see DELAY1MS DEBUG  too      50 > ~ 15 W/mn 43 > ~ 20 W/mn
#define MAXTIME     1000  // preset   must be less  ELOVERFLOW
#define	MAXCOLONNE	30    // width size of car displayed per line to pc : cr when a space 
#define	MAXCODERX   128   // max index pointeur code for table rx
#define MAXCODETX   63    // max index pointeur code for table tx
#define	MAXDBNCE	2	  // debounce value     shift down key 
#define MAXDASH 	5	  // n of last dashes for average ELtime
#define MAXDOT  	5     // n of last dot
#define MAXMESSNB   4     // messages nbre buffers-messages 
#define MAXMESSSIZE 32    // messages size buffers   // see mem ram !


#define KEYCDEBUTTON 1    // key used   smart command button
#define KEYSTRAIGHT  2	  // key straight  or 'pioche'
#define KEYPADDLES   3	  // key ( 1 or 2 paddles )
#define LCDWIDTH	16	  // LCD display N caracters  16  20
#define SIZEVERS     5    // version 
#define SIZEBUFF    60    // amorse general purpose buffer

	
#define NUL0	  0x00    // NULL	0x00  NULL is already predefined as ptr
#define	LF		  0x0A    // LF 
#define CR		  0x0D    // CR
#define	SPACE	  0x20    // SP
#define	IDDLE	  0x7E    // '~'  fill with to clear 
#define HEADER	  0x23    // '#'  for amorse.exe    indic log/trace lines   
#define INDCAR    0x24    // '$'  for amorse.exe    indic car
#define INDENDL   0x25    // '%'  for amorse.exe    indic end ligne to write ligne 
#define TOPCODETX 0x21    // '!'  first car table cw tx  
#define MAXLRND   0x5B    //  Z   +1 
#define	TRUE		1
#define	FALSE		0
#define UP      	1     // straight key up  open  pull-up   1 
#define DOWN    	0     // key down active is 0  <<<

#define CWTXTONE 	1     // with output  
#define CWTXWAIT 	2     // without ( inter space times )
#define CW_AR		91	  // see end cw tx table 
#define CW_VA		92	
#define CW_AS		93	
#define CW_XX		94	   
#define CW_AT		95    // @ 	
 	
#define DSPTOUSB  	1     //  1 yes  allow out cw to usb serial for pc,  0 debug
#define DSPYABRV  	1     //  1 yes  add display pc abreviations 
#define	DSPTOLCD  	1     //  1 yes  to LCD
#define DSPTRACE  	0     //  1 yes  test phases  ,  0   no   see cde U

#define DEFZEEPROM  __attribute__((section(".eeprom"))) 

//--------------------------------------------
// ---  data EEPROM variables --- 
// 
typedef struct
 { 
 byte zoctet0;  // don't use    0xFF  
 byte zoctet1;  // startmode 1..3 - 0xFF 1rst
 byte zoctet2;  // flagrxcwavge  average false  0 true 1
 byte zoctet3;  // typealgo  1..9   11..19   ( 1..9 [ +10 ]   )
 byte zoctet4;  // ndebounce  2..10  ms / cycle   // pb compilateur  qq name at pos 5 ???
 byte zoctet5;  // endlettertime  normal   /  ajustable   
 byte zoctet6;  // mode AB key  0  direct 1 trig
 byte zoctet7;  // mode AB type 0  A , 1  B 
 byte zoctet8;  // mode spare1
 byte zoctet9;  // mode spare2
 byte zoctet10; // tpscyclebalise  1..60  mn       
 byte zoctet11; // next
 int  zword1;   // unittime  speed 	40..200
 int  zword2; 	// interlettertime 100..400  ms
 int  zword3; 	// next
 char zarray2[MAXMESSSIZE];  // message 2  ' cq user ..'
 char zarray3[MAXMESSSIZE];  // message 3  balise user 
 char zarray4[MAXMESSSIZE];  // message 4  word  to match for repeater
 } struct_zepvars; 

 struct_zepvars  DEFZEEPROM   ptzoneeeprom;  // declare EEPROM variable 

//--------------------------------------------
// ---  PROGRAM zone (EEPROM) variables 
// 
// The fixed data should stay in flash memory to save place in ram  !
// Need use  <avr/pgmspace.h>  PROGMEM  and fct  pgm_read_byte( );  to read them
// http://www.embedds.com/store-constants-and-arrays-in-program-memory/
//
//volatile char PROGMEM bufferdebug[SIZEBUFF];      //test

//-----------------------------------------------------------------------------
// table 1 of ascii caracters and somes pseudo caracters for particulars cw cases
// code is the index computed by the algorithm  dash-dot       
 const byte PROGMEM tablemorserx[MAXCODERX+1] =
    {
	0x20,	////               pt 0
	0x20,	////               code from  1  not used 
	'E',    // E: .        //  see dot  >  * 2      = 2  >   E 
	'T',	// T: -        //  see dash >  * 2 + 1  = 3  >   T  
	'I',	// I: ..       //  second pass      2 * 2 
	'A',	// A: ._       //  second pass      2 * 2 + 1
	'N','M','S','U','R',                             // 10
	'W','D','K','G','O','H','V','F',0x20,'L',       // 20
	0x20,'P','J','B','X','C','Y','Z','Q',0x20,      // 30
	0x20,'5','4','#','3','?',0x20,'?','2','&',      // 40           # reserved header
	0x20,'+',0x20,0x20,0x20,0x27,'1','6','=','/',   // 50  42 +  46  ' (hex)  49  =
	0x20,0x20,';','(',0x20,'7',',',0x20,0x20,'8',   // 60
	0x20,'9','0',0x20,    							 // 64
    // ponctuations    but somes variants exist ! here international code !  
	0x20,0x20,0x20,0x20,'.',0x20,  // 70     69  . = VA
	0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,  // 80
	0x20,0x22,0x20,0x20,'.',0x20,0x20,0x20,0x20,'@',    // 90  @   82  " (hex) 85 . 
	0x20,0x20,0x20,0x20,0x20,0x20,'-',0x20,0x20,0x20,   // 100     97 - 
	0x20,0x20,0x20,0x20,0x20,';','!',0x20,')',0x20,     // 110     106  ;  109  )
	0x20,0x20,0x20,0x20,',',0x20,0x20,0x20,0x20,':',    // 120 :     115  , 
	0x20,0x20,0x20,0x20,0x20,0x20,0x20  // 127  +0			
	};      //MAXCODERX                                     nb not $ INDCAR  % end line


//-----------------------------------------------------------------------------
//  table 2    ponct .. , . numbers 0 .. 9 , letters A .. Z , and somes acc. and abrv.
//  ascii  48d 30h 0  ,  65d 41h A  , 84d 54h  T  and so on
//  from left to right start with edge 1 to 0 : 111'10'...   allow 6 signs cw   
//  0xFD = 1111101  1 = . (E) , 0xFC = 11111100  0 = - (T) , 0xC0 = 11000000  ----- (0) 
 const byte PROGMEM tablemorsetx[MAXCODETX+1] =
    {
	0xFF,0xAD,0xFF,0xFF,0xFF,0xFF,0xD1,       // ! " # $ % & '  
	0xC9,0x92,0xFF,0xD5,0x8C,0x9E,0xAA,0xCD,  // ( ) * + , - . / 
 	0xC0,0xD0,0xD8,0xDC,0xDE,0xDF,0xCF,0xC7,  // 0 ... 7  order is ASCII table
    0xC3,0xC1,0x87,0x95,0xCA,0xCE,0xD5,0xB3,  // 8 9 : ; < = > ?
    0xFF,0xFA,0xE7,0xE5,0xF3,0xFD,0xED,0xF1,  // (sp)  A B  ...  G
    0xEF,0xFB,0xE8,0xF2,0xEB,0xF8,0xF9,0xF0,  // H I J ... O 
    0xE9,0xE2,0xF5,0xF7,0xFC,0xF6,0xEE,0xF4,  // P Q R ... W
    0xE6,0xE4,0xE3,                            // X Y Z   
	0xD5,0xBA,0xD7,0xFF,0xA5                   // 91 AR, 92 VA, 93 AS,94   ,95 @
    };   // MAXCODETX


//-----------------------------------------------------------------------------
//  table 3 extended cw
 const byte PROGMEM tablemorsecw[] =  
	{
	0x40,0x13,0x1A,0x0B,0x1E,0x12,0x20,0x18,
	0x02,0x1C,0x1F,0x27,0x3F,0x2F,0x2F,0x15
	};
 const byte PROGMEM mversion[SIZEVERS] ="V3.5";
 

//--------------------------------------------
// 
// --- main --- 
//
//--------------------------------------------
int main (void) 
{
//  globals vars	 in  RAM   

int unsigned  aa;           // std for loop 

//-----------------------------------------------------------------------------
// table 4   dim    x codes  4  car + 0   // max 4c (+0)  option 5 c if extended to glue groups
unsigned char tableabrv[MAXCODERX+1][5]; 
// clear all before normally not set CONST (discards qualifiers from pointer target type)
for (aa=0;aa<MAXCODERX;aa++) strcpy(tableabrv[aa],"");
// add abreviations , conventions or long cw groups with 2 letters display  
strcpy(tableabrv[21],"[AA]");   // ._._   start transmission  or ' V V '
strcpy(tableabrv[34],"[SK]");   // ..._._   or  VA
strcpy(tableabrv[40],"[AS]");   // attendez  wait
strcpy(tableabrv[42],"[AR]");
strcpy(tableabrv[46],"[WG]");
strcpy(tableabrv[49],"[BT]");
strcpy(tableabrv[54],"[KN]");   // transmettez  send
strcpy(tableabrv[85],"[RK]");
strcpy(tableabrv[69],"[VA]");   // end 
strcpy(tableabrv[90],"[AC]");
strcpy(tableabrv[97],"[DU]");
strcpy(tableabrv[107],"[KW]");
strcpy(tableabrv[109],"[KK]");
strcpy(tableabrv[120],"[OS]");
// testing groups like glue-CQ  or glue-QTH Q.. glue-RST run but need a more great MAXTABLE and code over 127  !!!
//strcpy(tableabrv[nnn],"[RST]");

int unsigned  ELtime;		// ELapsed time           see  diagrams
int unsigned  ELAtime;		// ELapsed Average time 
int unsigned  DDtime;		// Dot-Dash time
int	unsigned  LStime;		// Letter Space time
int unsigned  Adshtime;     // Average dash
int unsigned  Adottime;     // Average dot
int unsigned  TLdash[MAXDASH]; // ELtime average last dashes
int unsigned  TLdot[MAXDOT];   // ELtime average last dots


int unittime;   	 // ref current unit time  dot and space inside letter   
int unittimesav;   	 // stack save for cde  
int unittimeread;    // from eeprom last w
int interlettertime; // mode  CW   time ms end letter intervalle training time

byte startmode;      // status start  0xFF new 1rst start when read eeprom, 1 done , 2 & more open .. 
byte typealgo;       // type algo "EL DD LS"    1  classic 1/2 , 2 strict , 6..9 open...   ( +10  same at ' space ' between words )
byte ndash;			 // pt dash table average
byte ndot;			 // pt dot table avg
byte ndebounce;      // nbre pass debounce key 
byte nummessage;     // current buffer-message 
byte endlettertime;  // 1 normal like dash  2 training with intervalle time space letter 
byte cptdebounce;    // counter n cycles low before flag
byte typeKEYMODE;    // 1 key cde bt, 2 straight, 3 paddles, 4 open ...

bool flagdsptrace;   // 1 with print traces to debug or check ( with HEADER )
bool statKEY;        // inp straight key or rx filter from audio 
bool statIKEYDOT;    // inp iambic dot
bool statIKEYDASH;   // inp iambic dash
bool statMODBsqz;    // inp iambic 0 no 1 squeezed 
bool statKEYCDE;     // inp 'smart key' command button 
bool flagcdespeed;   // pass key cde for std speed 10 w/mn when cde 
bool flagKEY; 		 // int flagKEY;    	// 0 hight 1 low straight key cw
bool flagDD;     	 // 1 if DD time reached 
bool flagLS;		 // 1 if LS time reached
bool flagrxcwavge;   // 0 no 1 average active for adaptative
bool flagKEYMEMIDOT; // inp request dot
bool flagKEYMEMIDSH; // inp request dash
bool flagKEYIDOT;    // 0 open  1 active
bool flagKEYIDASH;   // 0 open  1 active
bool flagMEMIDOT;    // cycle dot and 1 space
bool flagMEMIDASH;   // cycle dash and 1 space
bool flagMODTRIG;    // 0 direct key   1 pulse front key   ( 0 is strict key  1 is memory front pulse ) 
bool flagMODBset;    // 0 iambic  mode A   1  mode B       ( add dot or dash after release squeezing )
bool flagMODBDOT;    // 0 request a dot
bool flagMODBDASH;   // 0 request a dash
bool flagMODBsqz;    // 1 start squeezed 
bool flagKEYIAMBIC;  // sum dot dash
bool flagWAITIDOT;   // space 
bool flagWAITIDASH;  // space 
bool flagWAITSPACE;	 // space to decide period time end dot dash or new letter !
bool flagWSYNCHRO;	 // space synchro period assume 3 units between letters
bool flagendamorse;  // 0 run 1 stop 
bool flagsetbalise;  // set by TIMER (interrupt or) at mdelay count cycles 
bool flagmodbalise;  // set by command Q 
bool flagsetrepeat;  // set by Rx if catch rx vs word  
bool flagmodrepeat;  // set by command V 
bool flagserialrqt;  // set if an incomming car is received 
bool flagspare1;
bool flagspare2;


int cptmarkdot; 	 // counter relative time 
int cptspacedot;     // counter 1 unit after dot
int cptmarkdash;     // counter relative time  
int cptspacedash;    // counter 1 unit after dash
int cptspacewait;    // counter 1 unit wait strobe key after dot or dash
int cptspsynchro;    // counter 1 unit after space wait assume a synchro of space 3 units  
int cptcolonne;		 // cpt colonne before CR
int cptstone;      	 // sidetone  toggle   
int cptcyclems;		 // count ms 
byte cptcyclesec;    // count sec	  
byte cptcyclemn;     // count mn
byte tpscyclebalise; // in mn   max 255  or set int  
byte caractcwcde;    // the ascii cw letter...   or command 
byte cptrxcode;		 // code counter for rx        if < 255  

char unsigned buffertrace[SIZEBUFF+1];  // large place  but don't exceed !
char unsigned bufferabrv[LCDWIDTH+2];   // 
char unsigned bufferrxcw[LCDWIDTH+2]   = "                 "; // LCDWIDTH+1 
char unsigned bufferscrn[LCDWIDTH+1]   = "                ";  // LCDWIDTH
char unsigned bufferlcd[LCDWIDTH+1]    = "                ";  // LCDWIDTH
char unsigned buffertxc[LCDWIDTH+1]    = "                ";  // LCDWIDTH

// array mem string  n messages of size s as ram Teensy 2 can handle place for !
char unsigned tablecwmess[MAXMESSNB+1][MAXMESSSIZE+2];

static uint8_t aref = (1<<REFS0); // default to AREF = Vcc
int analogresult;
byte analogchannelpot;  // pot 
byte analogchannelsmt;  // s-metre


//--------------------------------------------     
//
// --- fonctions & procedures ---  
//
//--------------------------------------------


//--------------------------------------------
// #100 send a string from prg var in ram 
// inp  string     out usb serial by use of pchar    in print.h print.c     
void mprintbuffer( char unsigned *string) 
{
    byte car;
	byte jj = 0;
	while (TRUE) 
	 {
		car = string[jj++]; 
		if (!car) break;
		pchar(car);  //  <<<<<<<  use of pchar  
	 }
}


//--------------------------------------------
// #120 send a string to the USB serial port.  
// inp string in flash memory, using PSTR "var" ( not for ram var )
void msend_string(const char *string)
{
	char car;
	while (TRUE) 
	 {
		car = pgm_read_byte(string++); /// <<<
		if (!car) break;
		//pchar(car);    //same  cf print.h define 
		usb_serial_putchar(car);  /// same
	 }
}


//--------------------------------------------
// #130 send a string to bufferlcd
// inp string in flash memory, using PSTR "var" ( not for ram var )
void mstrcpy_string(const char *string)
{
	byte jj;
	for ( jj= 0; jj < LCDWIDTH; jj++)  
	   {
		  bufferlcd[jj] = pgm_read_byte(string++);
	   } 
}




// ------------------------------------------- 
// #140 send a string to LCD display
void minfoslcd (char unsigned *message)
{
LCD_Clear(); _delay_ms(100);
LCD_DisplayScreen(message);  
_delay_ms(DELAYDSPY);
//LCD_Clear();
}
	

//--------------------------------------------
// #160 send 1 car to LCD screen, shift left for one case and add a new caracter at right
// inp  1 car   out  LCD
void mprintlcd(char unsigned car)
{
 byte jj;
	if ( car > 0x1F )	//   avoid carat \0  \1    filter
	{
	  for ( jj= 0; jj < LCDWIDTH; jj++)  // 1st left is lost ! 
	   {
		  bufferscrn[jj] = bufferrxcw[jj+1];
	   } 
	  bufferrxcw[LCDWIDTH] = car; // add new one at right 
	  strncpy(bufferrxcw,bufferscrn,LCDWIDTH);	
	  LCD_DisplayScreen(bufferscrn);
	}
}	


//--------------------------------------------
// #200 send a formatted trace line    
// inp   num trace, string , value     out  USB  
// lines start with header and ended  with cr lf   used by ext amorse.exe                            
void mprinttrace(int ntrace, char unsigned *string, int value)
{
	char chvalue[6];    // place for int digits
	if (flagdsptrace)   // just end if not !
    {
     // use of value     somes need see 0 or 1 ,  somes  "" if  value 0 when not used
	 if (ntrace < 30 )  {chvalue[0] = 0x30 + value; chvalue[1] =  NUL0;} // 0 or 1  
      else 
 	 if (value > 0 ) itoa(value,chvalue,10);  else  strcpy(chvalue,"");    
     snprintf(buffertrace,SIZEBUFF,"%c%03d %s %s\r\n",HEADER,ntrace,string,chvalue);
     mprintbuffer(buffertrace);
	 buffertrace[0] = NUL0;     // ack clear after
    }
}


//--------------------------------------------
// #220 fct trace with report num trace, car : ascii, code : hexa,binaire, dec
void mprinttracehexbin(byte numtrace,byte car,byte code)
{
 byte codebin;
 byte car2;
 char unsigned temp[22];  //"code [ D5 1101 0101"    19 + spares
 char chbin[10];
 int  ii;   // no byte
 byte pos=0;
 char result;
 memset(chbin,NUL0,10);  //NUL0  '\0'
 codebin = code;
 for(ii=7;ii>=0;ii--)  // bin ( 8 bit in 2 quartets ) //%b  don't exist
	{
		if (((codebin >> ii) & 1)) result = '1';
		else result = '0';
		chbin[pos] = result;
		if ((ii>0) && ((ii)%4)==0)
		{
			pos++;
			chbin[pos] = ' ';
		}
		pos++;
	}
 if ( car > 0x1F ) car2 = car;  else car2 = SPACE;	
 snprintf(temp,30,"%s %c %02X %s","code",car2,code,chbin);  
 mprinttrace(numtrace,temp,code);      // code  dec 
}


//--------------------------------------------
// #250 Receive a string from the USB serial port.  The string is stored
// in the buffer and this function will not exceed the buffer size.
// A carriage return or newline completes the string, and is not
// stored into the buffer.
// The return value is the number of characters received, or 255 if
// the virtual serial connection was closed while waiting.
uint8_t mrecv_string(char *buf, uint8_t size)
{
	int16_t car;
	uint8_t count=0;

    // org  wait  n car   max size buf   or  CR
	// if call with size 1 allow get 1 car ( no cr )
	while (count < size)
	{
		car = usb_serial_getchar(); //<<<<<<<<<<<<<<
		if (car != -1)       // if something
		{
			if (car == '\r' || car == '\n') return count;
			if (car >= ' ' && car <= '~')
            {
				*buf++ = car;  
                //usb_serial_putchar(HEADER);  // or other not used but can be !
				//usb_serial_putchar(car);     // echo back it to control   
				count++;
				flagserialrqt = TRUE;      // something to parse
				caractcwcde = car;         // cgt type !    get 1 car ok
			}
		}
        else
        {
		    // to check more exceed timing ?  ?
			if (!usb_configured() ||  !(usb_serial_get_control() & USB_SERIAL_DTR))
            {
				// user no longer connected
				return 255;
			}
			// just a normal timeout, keep waiting
		}
	}
	return count;
}



//--------------------------------------------
// #270 call by mcommandextended  by ext prg : warning set corrects values ! otherwise program will hang
void msetparamvalue(byte number,int value)    
{
 switch ( number)                                  // number 01 .. 99     
  {
   case 1 : { startmode = value;   break;}         // value 000 .. 999 
   case 2 : { flagrxcwavge = value;   break;}  
   case 3 : { typealgo = value;   break;}     
   case 4 : { ndebounce = value;   break;} 
   case 5 : { endlettertime = value;   break;} 
   case 6 : { flagMODTRIG = value;   break;}    
   case 7 : { flagMODBset = value;   break;}    
   case 8 : { flagspare1 = value;   break;}    
   case 9 : { flagspare2 = value;   break;}    
   case 10 : { tpscyclebalise = value;   break;}     
   case 21 : { unittime = value; unittimesav = unittime;  break;}    
   //case 21 : { unittime = value; break;}  
   case 22 : { interlettertime = value;   break;}     
  }

}

//--------------------------------------------
// # 280 call by mcommandextended  by ext prg  
int mreadparamvalue(byte number)
{
 int value;
 switch ( number)
  {
   case 1 : { value =  startmode; break;}       
   case 2 : { value =  flagrxcwavge; break;}         
   case 3 : { value =  typealgo; break;}      
   case 4 : { value =  ndebounce; break;}  
   case 5 : { value =  endlettertime; break;}  
   case 6 : { value =  flagMODTRIG; break;}  
   case 7 : { value =  flagMODBset; break;}  
   case 8 : { value =  flagspare1; break;}  
   case 9 : { value =  flagspare2; break;}    
   case 10 : { value =  tpscyclebalise; break;}      
   //case 21 : { value =  unittime; unittimesav = unittime; break;}      
   case 21 : { value =  unittime; break;}      
   case 22 : { value =  interlettertime; break;}      
  }

 return(value);
} 

//--------------------------------------------
// #300 parse an extended command and execute it   inp  buf 
// extended protocol : XPSP12=123  XPRP03?  XPRM3?  XPSP01=001 XPSM2=CQ CQ DE F5BEZ K   
// commands by hyperterminal or program expect corrects numbers , values, sizes ...   
void mcommandextended(const char *buf, uint8_t num)
{
	uint8_t port, pin, val;
    byte number;  //  00 -  99
    int value;    // 000 - 999
	char temp[15]; 
    bool flagoldtrace = FALSE;
	if (num < 3)
     {
		msend_string(PSTR("#094 3.. chars req'd\r\n"));
		return;
	 }
	 snprintf(temp,15,"%s %s","mcde ",buf);   // troncated 
	 mprinttrace(31,temp,0);
	 // first character is the port letter
	 if (buf[0] >= 'A' && buf[0] <= 'F')
        {
		port = buf[0] - 'A';
	    }   
	    else    
	    {        
	    if (buf[0] == 'X')       // X eXtended commands  amorse   from  amorse.exe   on PC 
   	     {
		  //if (buf[1] == 'P')   // P Protocole Nb 1     othersletters for future use 
     	  if (buf[2] == 'S')    // second is  S  Set   	
		  {
		   if (buf[3] == 'P')   // third is  P parameter  	
		   {
          	number =  (buf[4] - '0') * 10 + (buf[5] - '0');  // 4 & 5 are numbers (not controled) ...
        	if (buf[6] == '=')  // =   set     
             {
              value =  (buf[7] - '0') * 100 + (buf[8] - '0') * 10 + (buf[9] - '0');  // value 000 to 999 
               msetparamvalue(number,value);  
               return;
  			 }
           }
		   if (buf[3] == 'M')   // third is  M message  
		   {
		   	number =  (buf[4] - '0');
			if (buf[5] == '=')  // =    number  1 :: MAXMESSNB        
             {
			  *(uint8_t *)buf[num] = NUL0;  // set end   must be letters ascii  uppercase 
			  strncpy(tablecwmess[number],&buf[6],MAXMESSSIZE); // max size  MAXMESSSIZE  
			  return;
			 } // =
           }  // M
		  }  // S
		  		    
		  if (buf[2] == 'R')    // second is R read
		  { 
		   flagoldtrace = flagdsptrace; flagdsptrace = TRUE;  // do  
		   if (buf[3] == 'P')    // third is  P parameter 
		   {
			number =  (buf[4] - '0') * 10 + (buf[5] - '0'); // 4 & 5 are numbers     
			if (buf[6] == '?')  // ?     
             {
              value = mreadparamvalue(number); 
			  mprinttrace(91,"value is",value);  //  trace enable
			  flagdsptrace = flagoldtrace;
			  return;
  			 }
           }  // P
		   if (buf[3] == 'M')   // third is   M message  
		   {
			number =  (buf[4] - '0');
			if (buf[5] == '?')  // ?    number  1 :: MAXMESSNB        
             {
              mprinttrace(92,tablecwmess[number],0);
			  flagdsptrace = flagoldtrace;
              return;
             } // ?
		   }  // M
		  }  // R
		 }  // X
		 
		
         else  // other letters 		 
		 {
		  msend_string(PSTR("#095 letter not used \""));
		  usb_serial_putchar(buf[0]);
		  msend_string(PSTR("\", must be A - F\r\n"));
		  return;
	     } 
	    }
	
	
	
	
	
	// this part come from the teensy serial usb exemple 
	// parse a user command and execute it, or print an error message
	// second character is the pin number
	if (buf[1] >= '0' && buf[1] <= '7') {
		pin = buf[1] - '0';
	} else {
		msend_string(PSTR("#096 pin ?? \""));
		usb_serial_putchar(buf[0]);
		msend_string(PSTR("\", must be 0..7\r\n"));
		return;
	}
	// if the third character is a question mark, read the pin
	if (buf[2] == '?') {
		// make the pin an input
		*(uint8_t *)(0x21 + port * 3) &= ~(1 << pin);
		// read the pin
		val = *(uint8_t *)(0x20 + port * 3) & (1 << pin);
		
		msend_string(PSTR("#097 state \""));          // added
		usb_serial_putchar(val ? '1' : '0');
		msend_string(PSTR("\"\r\n"));               // \ added  
		return;
	}
	// if the third character is an equals sign, write the pin
	if (num >= 4 && buf[2] == '=') {
		if (buf[3] == '0') {
			// make the pin an output
			*(uint8_t *)(0x21 + port * 3) |= (1 << pin);
			// drive it low
			*(uint8_t *)(0x22 + port * 3) &= ~(1 << pin);
			return;
		} else if (buf[3] == '1') {
			// make the pin an output
			*(uint8_t *)(0x21 + port * 3) |= (1 << pin);
			// drive it high
			*(uint8_t *)(0x22 + port * 3) |= (1 << pin);
			return;
		} else {
			msend_string(PSTR("#098 value ?? \""));
			usb_serial_putchar(buf[3]);
			msend_string(PSTR("\", must be 0 or 1\r\n"));
			return;
		}
	}
	// otherwise, error message
	msend_string(PSTR("#099 unknown command \""));
	usb_serial_putchar(buf[0]);
	msend_string(PSTR("\", must be ? or =\r\n"));
}



//--------------------------------------------
// #320 A/D    ref :  http://pjrc.com/teensy/adc.html
// inp num channel  out    value
int madc_read(uint8_t mux)
{
	uint8_t low;
	ADCSRA = (1<<ADEN) | ADC_PRESCALER;		// enable ADC
	ADCSRB = (1<<ADHSM) | (mux & 0x20);		// high speed mode
	ADMUX = aref | (mux & 0x1F);				// configure mux input
	ADCSRA = (1<<ADEN) | ADC_PRESCALER | (1<<ADSC);	// start the conversion
	while (ADCSRA & (1<<ADSC)) ;				// wait for result
	low = ADCL;									// must read LSB first
	return (ADCH << 8) | low;					// must read MSB only once!
}



//--------------------------------------------
// #340 clear cw  message m 
void mclearcwmess(char unsigned nummess)
{
char unsigned jj;
		for ( jj= 0; jj<=MAXMESSSIZE;jj++)
			  tablecwmess[nummess][jj] = IDDLE;
		 tablecwmess[nummess][0] = NUL0;
		 tablecwmess[nummess][MAXMESSSIZE+1]= NUL0; // assume end
		 memset(bufferscrn,SPACE,LCDWIDTH);
}	


//--------------------------------------------
// #360 move recept to table cw messages   
// inp  num mess, car    out  tablecwmess
void maddtocwmess(char unsigned nummess,char unsigned car)
{
char unsigned jj;
char  *ptkk;
//char  *chtest = "TEST";   // test 
	if ( car > 0x1F )
	{
     for ( jj= 0; jj<MAXMESSSIZE; jj++)   
	   tablecwmess[nummess][jj] = tablecwmess[nummess][jj+1]; // 1st left is loose ! 
	}	
	tablecwmess[nummess][MAXMESSSIZE]= car;    // set the new car at right 
	tablecwmess[nummess][MAXMESSSIZE+1]= NUL0; // assume end
	
	// here catch key-word with buffer rx 1  for repater mode
	ptkk = strstr(tablecwmess[1],tablecwmess[4]);  //chtest);
	if ( (flagmodrepeat == TRUE ) && ( ptkk != NUL0 ))  
	  flagsetrepeat = TRUE;
}

//--------------------------------------------
// #380 move cw message m to LCD screen by at left for one case and add a new caracter at right
// inp  table cw messages      out  LCD
void mreadcwmess(char unsigned nummess)
{
byte ii,jj;
byte car;
memset(bufferscrn,SPACE,LCDWIDTH);
LCD_Clear(); _delay_ms(100);   		
	for (jj=0;jj<MAXMESSSIZE;jj++)
	 {
	  for ( ii= 0; ii < LCDWIDTH;ii++)
	    {
		 car = tablecwmess[nummess][ii+jj];
		  if (car == NUL0) return;
		  if (car == IDDLE) continue;
		 bufferscrn[ii] = car;
		}
	  LCD_DisplayScreen(bufferscrn);
	  _delay_ms(DELAYDSPY);
	  do
	   {}
	   while(!(PINF & 32));  // stop lcd revue if key cde down  to read 
	 }
}	


//--------------------------------------------
// #400 inp hard pinx   out statxxx
void mkey (void)
{
 byte bt;
 bt = PINF;   // one time hard reading per cycle here
 // straight key state  bit and port predefined    F0
 // used as Rx input  (open collector to 0 in // )  hardware audio interface 
 //if (flagcdespeed == 0) statKEY =  (bt & 1);   else  statKEY = 1;  // test cde key close key inp for cde priority
 statKEY =  (bt & 1);         
 // iambic key dot state  bit and port predefined  F1
 statIKEYDOT = (bt & 2)>>1;
 // iambic key dash state  bit and port predefined  F4
 statIKEYDASH = (bt & 16)>>4;     
  // smart key command    bit and port predefined  F5
 statKEYCDE = (bt & 32)>>5;       // close audio rx cw inp before use !
 //   spare  key    state  bit and port predefined  F7
 //statIKEYxxxx = (bt & 128)>>7;
 // iambic mode B set stat when squeezed 
 if ((statIKEYDOT == 0 )  && ( statIKEYDASH == 0 )) statMODBsqz = 1;  else statMODBsqz = 0; 

}


//--------------------------------------------
// #420 use for paddles key   this part is combinatoire and handle flags
// inp statxxx  out  flagxxx
void mikeydot (void)
{
/// ------- start bloc  
  /// --------- DOT ----------------------
  //  if simple paddle dot right  or dash left  : shorts pulses are first stored   
  //  if pulse down set a request ( 0 active )
  if ( statIKEYDOT == 0 )  flagKEYMEMIDOT = 0; 
  if ( flagMODTRIG == 0 )   flagKEYMEMIDOT = statIKEYDOT;    // direct follow   
  if ( ((flagKEYMEMIDOT == 0 ) ||  ( flagMODBDOT == 0  ))  && ( flagMEMIDASH == 0 )  &&  ( flagKEYIDOT == 1 ) &&  ( flagWAITIDOT == 0 ) && ( flagWSYNCHRO  == 0 ))
  {
   flagMEMIDOT = 1;  // time run for a dot and a space
   flagKEYIDOT = 0;  // key down for a dot
   cptmarkdot = 0;   // begin time
  }
  
  if  ( flagKEYIDOT == 0 )     // if dot is in progress
  {
   if (cptmarkdot++ > unittime)   // count time vs actual unit time for a dot
   {
	flagKEYIDOT = 1;   // key up for a dot
	cptspacedot = 0;   // begin time again
	flagWAITIDOT = 1;  // time for space end dot
   }
  }

  if  ( flagWAITIDOT == 1 )   // if space is in progress
  { 
   if ( cptspacedot++ > unittime )  // count time vs actual unit time for a space = a dot time
     {
	 flagKEYMEMIDOT = 1;  // end acknoledge request for this dot  ready for next
	 flagWAITIDOT = 0;    // end time for space
	 flagMEMIDOT = 0;     // end time for a dot and a space
	 flagMODBDOT = 1;     // end ack mode B dot added  
	 cptspacewait = 0;    // begin wait time
	 flagWAITSPACE = 1;   // time for space end letter or in letter !
	 
	 }
  } 

  
  // in mode B  if release when squeezed and if a dot  set request for a dash to send 
  //if (  ( statMODBsqz == 0 )  && ( flagMODBsqz == 1 ) && (  flagKEYIDOT == 0 )  && (  flagMODBDOT == 1 )  )   
  if ( ( flagMODBset == 1 ) &&  ( statMODBsqz == 0 )  && ( flagMODBsqz == 1 ) && (  flagKEYIDOT == 0 )   )  //  dot 
  //          																	      flagMEMIDOT == 1 )   )  //  dot & space 
   {
	 flagMODBsqz = 0;     // end squeezed
	 flagMODBDASH = 0;    // set request dash  
   }
 
 
} 
  
  
//--------------------------------------------
// #440 use for paddles key    this part is combinatoire with flags
// inp statxxx  out  flagxxx 
void mikeydash(void)
{
/// ----------- DASH ------------------
  // if pulse down set request   
  if ( statIKEYDASH == 0 ) flagKEYMEMIDSH = 0;  // front 
  if ( flagMODTRIG == 0 )   flagKEYMEMIDSH = statIKEYDASH;    // direct follow   
  if ( (( flagKEYMEMIDSH == 0 ) || ( flagMODBDASH == 0 )) && ( flagMEMIDOT == 0 )  &&  ( flagKEYIDASH == 1 ) &&  ( flagWAITIDASH == 0 ) && ( flagWSYNCHRO  == 0) )
  {
   flagMEMIDASH = 1;  // time for a dash and a space
   flagKEYIDASH = 0;  // key down for a dot
   cptmarkdash = 0;   // begin time
  }
  
  if  ( flagKEYIDASH == 0 )  // if dash is in progress
  {
   if (cptmarkdash++ > ( unittime * 3 ) ) // count time vs actual unit time for a dash = 3 dot
   {
	flagKEYIDASH = 1;  // key up for a dash
	cptspacedash = 0;  // begin time
	flagWAITIDASH = 1; // time for space end dash
   }
  }
 
  if  ( flagWAITIDASH == 1 )  // if space is in progress
  { 
   if ( cptspacedash++ > unittime ) // count time vs actual unit time for a space = a dot
     {
	   flagKEYMEMIDSH = 1; // end acknoledge request for this dash  ready for next
	   flagWAITIDASH = 0;   // end time for space
	   flagMEMIDASH = 0;    // end time for a dash and a space 
	   flagMODBDASH = 1;    // end ack mode B dash added  
	   cptspacewait = 0;	// begin wait time
	   flagWAITSPACE = 1;	// time for space end letter or in letter !
	   
	 }
  } 
  
  
   // in mode B  if release after squeezed and if a dash  set request for a dot to send   
	//if (  ( statMODBsqz == 0  )  && ( flagMODBsqz == 1 ) &&  ( flagKEYIDASH == 0) &&  ( flagMODBDASH == 1 )  )  
	if ( ( flagMODBset == 1 ) && ( statMODBsqz == 0  )  && ( flagMODBsqz == 1 ) &&  ( flagKEYIDASH == 0)  )    // dash
	//                                                                                  flagMEMIDASH == 1 )  )   // dash et space 
	
      {
	   flagMODBsqz = 0;    // end squeezed
       flagMODBDOT = 0;    // set request dot
	  } 
  
    
}



//--------------------------------------------
// #450 inp  flagxxx    out flagxxx    part is combinatoire with flags
// this solve the decision time where a fast keying is in the letter or start the next...  
void mikeywait(void)
{
 int unsigned waitunittime = unittime;  // normal  def  
 if (endlettertime == 2) 	waitunittime = interlettertime;  // training set more intervalle synchro between letters 
	    
 
 //if  (( flagWAITSPACE == 1))  // if space letter in progress
 if  (( flagWAITSPACE == 1)  && (statIKEYDOT == 1) && (statIKEYDASH == 1))  
  { 
   if ( cptspacewait++ > unittime ) // count time vs actual unit time for a space 2+1 
     {
	  //flagMEMWAIT = 1;
	  flagWAITSPACE = 0;   // end time for space
	  cptspsynchro = 0;    // ack next
	  flagWSYNCHRO = 1;    // synchro time end letter elapsed, it's the begin of a next letter
	  
	   //flagMODBDOT = 1;
	   //flagMODBDASH = 1;
	 }
  } 
  // else if key dot or dash is requested here it will continue the letter ... ( with little over space time ) 

 if  ( flagWSYNCHRO == 1 )     // if space synchro in progress
 //if  (( flagWSYNCHRO == 1 ) && (flagMEMIDASH == 0 ) && (flagMEMIDOT == 0 ))    // if space synchro in progress
  {   
   if ( cptspsynchro++ > waitunittime ) // count time vs actual unit time for a space = 2+2+1 or more if training
     {
	  //flagMEMWAIT == 0;
	  flagWSYNCHRO = 0;  // end time . The next dot or dash will delayed start at right time spacing
	 
	  
	 }
  } 
 
}



//--------------------------------------------
// #460 timing adjust   fct avr teensy  
// 
void mdelay (void)
{
    // nb   fct cpu speed config  
	_delay_ms(DELAY1MS);
	//_delay_us(DELAYXXXUS);
	
	// easy alternative at interrupt mode to set the flag in the balise mode 
	// the timing is quite sufficient, without more precision needed!
	if (cptcyclems++ > 1000) {cptcyclems = 0; cptcyclesec++;}
	if (cptcyclesec  > 60) {cptcyclesec = 0; cptcyclemn++;}
	if (cptcyclemn >= tpscyclebalise) 
	 {
	  cptcyclemn = 0;   
	  flagsetbalise = TRUE;  // set the flag to use later 
	 } 
	 
}



//---------------------------------------------------------
// #470 inp delay in sec  out  elapsed or if cde key down 
void mdelaystop(char unsigned time)
 {
 time *= 10;   // step 100ms
 char unsigned count = 0;
 do 
  {
   _delay_ms(100);   // step 100ms
   if (!(PINF & 32)) break;
  }while(count++ < time); 
 }



//--------------------------------------------
// #480 bit and port for audio monitoring 
// test not more used         use of a direct hard beeper with OUTCWBIP_ON 
void mtone (void)
{
 cptstone++; // toggle  bit 0      // see about integrated tone fct !
 if ((cptstone & 1 ) == 1)
  {
  OUTCWBIP_ON;
  }
  else
  {
  OUTCWBIP_OFF;
  }
	
}

//--------------------------------------------
// #500 read key, integration bounces, timing testing, setting flags
// fcttime  normal 1     training 2 
void mstatus (int fcttime)
{
 // testing in the main loop ok  but better set here
 mdelay();   // here important it's the sampling time !!!!
   
 //st1:
  // clear flags 
  flagDD = FALSE;
  flagLS = FALSE;
  //cptstone = 1;
  
  mkey();     // read  keys  cde , straight and paddles keys 

  // if two paddles squeezed 
  if (statMODBsqz == 1 )  flagMODBsqz = 1; 
  // which  type of KEY  in use !
  if (statKEYCDE == DOWN)   typeKEYMODE = KEYCDEBUTTON;   
  if (statKEY == DOWN)   typeKEYMODE = KEYSTRAIGHT;   
  if ((statIKEYDOT == DOWN ) || (statIKEYDASH == DOWN))  typeKEYMODE = KEYPADDLES; 
  if ((typeKEYMODE == KEYCDEBUTTON) && ( flagcdespeed == FALSE))
    {
	 flagcdespeed = TRUE;         // at 1rst pass
   	 unittime = UTINITIAL;        // set about 10 w/mn for any cde
	 //DDtimesav = DDtime;
	 //LStimesav = LStime;
	 DDtime = unittime * 3 / 2;   // half of dash 
	 LStime = DDtime;  
	}
  
    
  // for no - iambic ( 1 contact at a time )   or iambic  ( same but can pinch the 2 contacts togother )
  // assume dash before dot :  'N' ( otherwise reverse next two lines for 'A' ! )
  // and if maintained will generate 'C' then ';'  release  'K' 
  mikeydash();    // paddle dash      
  mikeydot();     // paddle dot
  mikeywait();    // synchro time between letters
  
    // logical OR on 0 for key  by iambic 
  flagKEYIAMBIC = (flagKEYIDOT && flagKEYIDASH);   //||
      // no key 
	if ( ( flagKEYIAMBIC == UP )   &&  ( statKEY  == UP )  &&  ( statKEYCDE  == UP ))
	{ 
     flagKEY = UP;   // no KEYs
     OUTCWLED_OFF;   // led on board
     OUTCWBIP_OFF;  
	 OUTCWKEY_OFF;   // TEST
	}
	else  // keys or iambic ?
	{
	 if ( ( statKEY  == DOWN )  ||  ( statKEYCDE  == DOWN ) ) // by keys
	 {
      cptdebounce++;     // grown somes ms before decide down....    
	 }
	 else
	 {
	  cptdebounce = ndebounce+1;     // direct
	 }
	 
	}
   
  
//st2:
   	if ( (( statKEY  == DOWN )  ||  ( statKEYCDE  == DOWN ) ||  ( flagKEYIAMBIC == DOWN )) && ( cptdebounce > ndebounce  ) )  
	{
	  cptdebounce = 0;
	  flagKEY = DOWN; //  
	  OUTCWLED_ON;    // 1  after debounce  
	  OUTCWBIP_ON;    // 1  led and 5v beeper   >>  here if beep with key cde 
	  if ((typeKEYMODE == KEYSTRAIGHT ) || ( typeKEYMODE == KEYPADDLES ))
	   {
	   //OUTCWBIP_ON;  // 1  led and 5v beeper  >>  here if no beep with key cde
	   OUTCWKEY_ON;  // 0   to tx 
	   OUTCWMOX_ON;  // 0   to ptt 
	   }
	   //mtone(); // not used audio monitoring ( toggle out each ms 500hz )
	}
	 else 
	{
	  // test 
    } 
	
	
 //st3:
 // ELapsed time grown here by step 1ms  
	ELtime++;
	
	if ( ELtime > ELOVERFLOW )   // if too  long    
	{

	 ELtime = MAXTIME;   // presetting to max time  
	
	}  
		else
	{ 
	   // test
	}
 
 //st4: 
 // update LS flag
    // is current time >  letter-espace time ?
	// fcttime  allow an extra timing at end letter for space ending word in training mode
    // normal keying speed don't need   otherwise there too many spaces between letters !
    if ( ELtime >= (LStime * fcttime ))
	{
	//print("\flagLS=1\n");  // debug
	 flagLS = TRUE;   // end letter !
	}

 //st5:
 // update DD flag
    // is current time >  dot-dash  time ? 
    if ( ELtime >= DDtime )
	{
	
	  flagDD = TRUE;  // this a dash  else a dot !   
	}
 
 //st6:
 // store stat    
  
}


//--------------------------------------------
// #520  display caracter cw received
// in car    out  usb-serial,lcd, mem string array 
void mprintcw (char unsigned car)
{
   // Trf  via USB (to HD_LISTEN)  or SERIAL
   if(DSPTOUSB)
    {
	 if ( car == SPACE )
	  {
	   if ( cptcolonne > MAXCOLONNE )
	    {
	  	 pchar(INDENDL); pchar(CR); pchar(LF);  // ind end ligne 
		 cptcolonne = 0;
        }   
	   
	   if (flagdsptrace)   // with indication
        {
	     pchar(INDCAR);   // ind car  (not HEADER)
		 pchar(SPACE); 
	     pchar(CR); pchar(LF);  
	     
		}
		 else
		{
		 pchar(SPACE); 
		
		} 
		 
			 
	  }
	  else
	  { 
	   if (flagdsptrace)   
        {
	     pchar(INDCAR); // not HEADER
		 pchar(car); 
	     pchar(CR); pchar(LF);  
	     
		}
		 else
		{ 
	     pchar(car);
	    }
	   cptcolonne++;
	  }
	}
	 
	if(DSPTOLCD)
    {
	 // on LCD for LCDWIDTH last caracters  ...
	  mprintlcd(car);
	}
	 	 

 	 // add to message 1 
	 maddtocwmess(1,car);  // buffer 1 is default rx cw follower tracker ( turn around buffer )
}


//--------------------------------------------
//  #540 in code out return ascii caracter related from code  and his abrev in bufferabrv
char unsigned mdecode (int code)
{
  byte car;
  car = pgm_read_byte(&tablemorserx[code]);
  mprinttracehexbin(47,car,code);  // num trace
  bufferabrv[0] = NUL0;
  strcpy(bufferabrv,tableabrv[code]);
  return(car);
}


//--------------------------------------------
// #560 abort       test pin x  to end prg
void mabort (void)
{
 // if  (PINB  ==    );               // see ',' cde  from external 
 //  flagendamorse = TRUE;
 // amorse  is stand alone without end program...
 // see cde W   expect manual save average DD LS and message  in eeprom for next start
}


//----------------------------------------------------------
// #580 in type  tone or wait , time    out audio
void mcwtxtone(char unsigned type,int ttime)
{
 int jj;
 switch (type)
  {
  case CWTXTONE :
	OUTCWLED_ON;   // led on board
    OUTCWBIP_ON;  
	OUTCWKEY_ON;
	for (jj = 1; jj < ttime; jj++) 
	{
	 OUTCWTAF_ON;   // Toggle for 500us 
     _delay_us(DELAY500US);    
	 OUTCWTAF_OFF;  // audio out 1khz square to be LPF R/C filtered
	 _delay_us(DELAY500US);     
	}
	OUTCWLED_OFF;   // led on board
    OUTCWBIP_OFF;  
	OUTCWKEY_OFF;
    break;
  case CWTXWAIT :	
	for (jj = 1; jj < ttime; jj++) mdelay();  
  }	
}


//----------------------------------------------------------
// #600 inp car ascii ( 0 ...  Z more somes sp )  ,  out cw 
void msencode(char unsigned car)
{
 byte code, cptbit, testbit, flagstart;
 int ddtime;  // dot dash time
 code = pgm_read_byte(&tablemorsetx[car - TOPCODETX]);  // TOPCODETX is the 1st car of the table tx
 
 mprinttracehexbin(48,car,code);  // num trace
 flagstart = FALSE;           // start clear 
 cptbit = 0x80;               // MSB left first bit
 do 
 {
  testbit = (code & cptbit);  // test 128 64 32 8 ... or  0 if not bit
   if (flagstart == TRUE)     // now bit are data . or _
   {
     if (!testbit)
      {
       mprinttrace(41," - ",0);    // debug check table tx
	   ddtime = unittimesav * 3;   // dash  3 unit time 
      }
       else
      {
	   mprinttrace(42," . ",0);    // debug
	   ddtime = unittimesav;       // dot 1 unit time 
      }
 	  mcwtxtone(CWTXTONE,ddtime);
	  mcwtxtone(CWTXWAIT,unittimesav);  // end dot or dash add 1 unit time
   }
   // else turn around to find 1st 0
   if (!testbit)  flagstart = TRUE; // first 1>0 is the start mark
   cptbit /=  2;  // next bit ( move bit mask to right 1 ) 
 }while(cptbit >= 1);  // MSB included
 mcwtxtone(CWTXWAIT,unittimesav * 2); // end car add 2 units time ( total is 3 ) 
}


//----------------------------------------------------------
// #620 inp  code    out  cw  
// code for somes sp caracters  
// 91 'AR'  ._._ _.  , 92   VA  ..._._  , 93  AS ._..., 94  ,95 @ ._ _ ._.
void msendcar(char unsigned car)
{
 if (car > TOPCODETX && car <= MAXCODETX + TOPCODETX )  
   {
    OUTCWMOX_ON;
    _delay_ms(DELAYCWMOX);
    msencode(car);
    OUTCWMOX_OFF;     
   }
}


//----------------------------------------------------------
// #650 inp string  out cw 
void msendmessage(char unsigned nummess)
{
 byte ii=0;
 char unsigned car;
   OUTCWMOX_ON;     // Tx PTT ON 
   _delay_ms(DELAYCWMOX);  // delay before 1st car
   do
   { 
    if (!(PINF & 32)) break;   // abord by key cde (step delay)
    if (nummess == 100)        // 100 arbitrary num !
         car = buffertxc[ii++];
	 else
	     car = tablecwmess[nummess][ii++];  // nummess 1 à MAXMESSNB
    
    switch (car)
	 {
  	  case NUL0 :
        break;
	  case SPACE :
       mcwtxtone(CWTXWAIT,unittime * 4);  // space time words
     } 
	 if (car >= TOPCODETX && car <= MAXCODETX + TOPCODETX)  
   	   msencode(car); 
		// in mode 2      here same time space letters for any speed   
		if (endlettertime == 2) 	_delay_ms(interlettertime); // start 200ms  see cde O G        
	   
   }while(car != NUL0); 
   OUTCWMOX_OFF;   // end PTT OFF
}


//----------------------------------------------------------
// #670 training CW  get random caracter in ascii range 
// inp  random  out caracter  like ascii  numbers, letters , sign & ponctuation   
char unsigned mgetrndletter(void)
 {
  int randNumber; 
  byte cnttest = 1;
  
  do
  {
   //randNumber = (uint8_t) rand(MAXLRND) % MAXLRND; // & 0x7F; // 1rst Set number range to 0 to 127  
   randNumber = (uint8_t) rand() & 0x7F; // 1rst Set number range to 0 to 127  
	if (randNumber > 0x5A )  randNumber -= 0x5A;  // over  Z reduce 
	if (randNumber < 0x21 )  randNumber += 0x31;  // under ! add  if 0x21 lot number if 0x31 less
    if (randNumber < 0x30 )  continue;            // retry   this line OR the next
	// with somes ponctuations  else set // to the 2 next lines  
	if ((randNumber > 0x20) && (randNumber < 0x30))  continue;  // skip ponct 0x21 to 0x2F  
	if ((randNumber > 0x39) && (randNumber < 0x41))  continue;  // skip ponct 0x3A to 0x40
    if (randNumber > 0x5A )  continue;            // assume good range           
	break;
  }while(cnttest++ < 100);	  // secure  out !
  return(randNumber);
 }



//----------------------------------------------------------
// #700 training CW  send random group of 5 caracters and display them after
// inp  random  out cw 
void mtraining(void)
 {
 byte ii;  
 char unsigned car;   
 char chletter[2];
 chletter[1] = NUL0;  // for strcat
// seed  take last actual ELtime and cptcolonne 
// to repeat same sequence : don't  key 
// otherwise straight key something  probably differ at any time here ! 
// an other way : adc_read   on channel 1 with zener like noise !
// srand((ELtime + cptcolonne ) & 0x3F);
 srand((uint16_t)(ELtime + cptcolonne ) & 0x5F);
 do 
  {
  strcpy(bufferabrv,"");        // start clean
  for (ii=0;ii<5;ii++)         //  group of 5 letters / signs
   {
    car = mgetrndletter();      // if test car++;  	//;pchar(car);
	chletter[0] = car;          // set
	strcat(bufferabrv,chletter);    // add
	msendcar(car);
	// here same time space letters for any speed  
	if (endlettertime == 2) 	_delay_ms(interlettertime); // start 200ms  see cde O G        
	
   }
   strcat(bufferabrv,"  ");         // max LCDWIDTH
   mprintbuffer(bufferabrv);
   strcpy(bufferlcd,bufferabrv);
   LCD_Clear();  _delay_ms(100);   
   LCD_DisplayStringCentered(2,bufferlcd);   // 2 for right
   mdelaystop(3);               // keep display 3 sec  or stop
  }while(PINF & 32);            // stop  if key cde was down   
 }
  

//----------------------------------------------------------
// #720 send message 3 each x Mn   
// in  flagsetbalise  , tpscyclebalise     out  fct Send
void mbalise(void)  
 {
  if ((flagsetbalise == TRUE ) && ( flagmodbalise  == TRUE )) 
   {
    msendmessage(3);         // message 3 preset before !
	flagsetbalise = FALSE;   // ack for next time
   } 
 }    
  

//----------------------------------------------------------
// #740 send message 3 if rx cw  match preset word in message 4 
// in  flagsetrepeat     out  fct S	
void mrepeater(void)   
 {
  if ((flagsetrepeat == TRUE ) && ( flagmodrepeat  == TRUE )) 
   {
    //read smetre value (with superCapa memory) here for analog connexion, 
    //an other way is a serial CAT result to read this value...   
    //analogresult = madc_read(analogchannelsmt);
    mclearcwmess(1);      // clear otherwise key-word will catch again in loop
    // add cw smetre RST  after end mess 3  
	msendmessage(3);       // message 3 preset before !
	flagsetrepeat = FALSE;   // ack for next time
   } 
 }   
 




//--------------------------------------------
// #750 set speed tx cw by pot    
// inp  pot   out  variables   end  by cde bt  
void msetpotspeed(void)
{
 byte cptexit = 0;
 int readctrl;
 char unsigned chvalue[8]  = "       "; // 7
do 
  {
   analogresult = madc_read(analogchannelpot); 
   unittimesav = analogresult / 5  + 24;  // range   6 à 40 w mn
   unittime = unittimesav;
   //mcommandbycar('Z');       // display current speed   // no reentrance !
   //mprinttrace(74,"unittime",unittime);
   readctrl= 960/unittimesav;
   itoa(readctrl,chvalue,10); 
   snprintf(bufferlcd,LCDWIDTH+1," %c %s %s      ",'B',chvalue,"W/mn"); // " B 10 W/mn      " 
   LCD_DisplayScreen(bufferlcd);  
   mprinttrace(71,"speed W/mn",readctrl);    //speed W/mn 10
   msendcar('7');
   msendcar('3');
   mdelaystop(1); 	
   cptexit++; 
   if ( cptexit > 30 )   return;
  }while(PINF & 32);            // stop  if key cde was down   
 
}


 
 
//--------------------------------------------
// #800 commands   
// inp  cw letter one caracter cde key    out  actions 
// fct mstrcpy_string  and PSTR( )  used to save ram place 
void mcommandbycar(char unsigned cdecar)
{
 char unsigned chvalue[8]  = "       "; // 7
 int fractime;
 int fendtime;
 int readctrl;
 bool flagoldtrace = FALSE;
 char temp[10]; 
 snprintf(temp,10,"%s %c","command",cdecar);
 mprinttrace(80,temp,0);
 fractime = unittimesav  / 10;   // + - 10%  // morse speed
 fendtime = interlettertime / 5; // + - 20%  // intervalle letter in training
 
 // 1) display 
 switch (cdecar)
 {
   // local stand alone std smart key command    and by external command
   case 'Z' : mstrcpy_string(PSTR(" Z read speed   ")); break; // test and at init
   case 'B' : mstrcpy_string(PSTR(" B set  speed   ")); break; // by pot 
   case 'P' : mstrcpy_string(PSTR(" P more  cw QRQ ")); break; // more speed QRQ
   case 'J' : mstrcpy_string(PSTR(" J less  cw QRS ")); break; // less speed QRS
   case 'O' : mstrcpy_string(PSTR(" O more  cw end ")); break;
   case 'G' : mstrcpy_string(PSTR(" G less  cw end ")); break;
   case 'F' : mstrcpy_string(PSTR(" F end letter x ")); break;
   case 'N' : mstrcpy_string(PSTR(" N read  mess x ")); bufferlcd[14] = nummessage + 0x30; break;
   case 'S' : mstrcpy_string(PSTR(" S send  mess x ")); bufferlcd[14] = nummessage + 0x30; break;
   case 'C' : mstrcpy_string(PSTR(" C clear mess x ")); bufferlcd[14] = nummessage + 0x30; break;
   case 'W' : mstrcpy_string(PSTR(" W write infos  ")); break;  // speed & message 1
   case 'R' : mstrcpy_string(PSTR(" R read  infos  ")); break;  // message n  test ctrl
   case 'L' : mstrcpy_string(PSTR(" L training cw  ")); break; 
   case 'Y' : mstrcpy_string(PSTR(" Y A/D  test    ")); break;
   case 'Q' : mstrcpy_string(PSTR(" Q beacon     x ")); break;  // mode balise   toggle
   case 'V' : mstrcpy_string(PSTR(" V repeater   x ")); break;  // mode repeteur toggle
   case 'X' : mstrcpy_string(PSTR(" X mode trig  x ")); break;  // mode iambic key direct or pulse
   case 'K' : mstrcpy_string(PSTR(" K mode  A B  x ")); break;  // mode iambic A or B
   case '?' : mstrcpy_string(PSTR(" ? test tx cw   ")); break;
   case '1' : mstrcpy_string(PSTR(" 1 message 1    ")); break;
   case '2' : mstrcpy_string(PSTR(" 2 message 2    ")); break;
   case '3' : mstrcpy_string(PSTR(" 3 message 3    ")); break;
   case '4' : mstrcpy_string(PSTR(" 4 message 4    ")); break;
   
   // accentuations are used as one caracter by external command 
   case '+' : mstrcpy_string(PSTR(" + traces     x ")); break;  // mode trace    toggle
   case '-' : mstrcpy_string(PSTR(" - open         ")); break;  
   case '=' : mstrcpy_string(PSTR(" = dsp   infos  ")); break;  // to PC 
   case ':' : mstrcpy_string(PSTR(" : version      ")); break;
   case ',' : mstrcpy_string(PSTR(" , warm reset   ")); break;  // virgule c omma
   case ';' : mstrcpy_string(PSTR(" ; open         ")); break;
   case '(' : mstrcpy_string(PSTR(" ( open         ")); break;  // parenthèse
   case ')' : mstrcpy_string(PSTR(" ) open         ")); break;  
   case '/' : mstrcpy_string(PSTR(" / open         ")); break;
   case 0x27: mstrcpy_string(PSTR(" ' open         ")); break;  //  '  apostrophe
   case 0x22: mstrcpy_string(PSTR("   open         ")); break;  //  "  guillement  
   
   // caracters not used as command 
   case 'E' : break;  // short pulse is not error neither command
   case 'T' : break;  // more long pulse neither
   //  A  D  I                        case 'I' : break;  // same
   default  : mstrcpy_string(PSTR(" ! error      x ")); bufferlcd[14] = cdecar;
 } 


// 2) actions...    1 button =  smart commands ...  
switch (cdecar)
 {
  // commands by external -------
  case ';' :        // open 
       OUTCWBIP_ON;   // test beep  must off next cycle
  break; 
  //case 0x27 : //''' :        // open 
       
  //break; 
  //  -  '  "   /  (   )   
  
  case ',' :       // warm restart 1  !
   flagendamorse = TRUE; // if run in  main rx loop !
  break; 
  case ':' :        // version on lcd   or open 
  for (aa=0;aa<SIZEVERS;aa++)  // 
	bufferabrv[aa]=pgm_read_byte(&mversion[aa]);  
  snprintf(bufferlcd,LCDWIDTH+1," %c %s %s   ",':',"version",bufferabrv);  
  LCD_DisplayScreen(bufferlcd);  
  mprinttrace(70,bufferlcd,0); 
  mdelaystop(1); 	
  goto endcommand;    //break;
  
  // -------------------------
  case 'Z' :
   // test message with 8 car measure global time
   // val unittime 1ms  time            car / mn    wpm / mn ( / 5 ) base PARIS
   // 		268			27.4			17.5		3.5
   //       100         10.6			45.2		9   
   //        84			8.7				55			11
   //		 73			7.5				64			13
   //		 41			4.3				111.6		22 
   // as unittime is 1.5 dot or 1/2 dash  base 1ms   eqv unit 10 timing test on 8 car
   // vit m/mn 8 / unit / 10   *  60 / 5    or  approx word / mn = 960 / unit   
    dspspeed:
	mprinttrace(74,"unittime",unittime);
	readctrl= 960/unittimesav;
    itoa(readctrl,chvalue,10); 
    snprintf(bufferlcd,LCDWIDTH+1," %c %s %s      ",'Z',chvalue,"W/mn"); // " Z 10 W/mn      " 
	LCD_DisplayScreen(bufferlcd);  
	mprinttrace(71,"speed W/mn",readctrl);    //speed W/mn 10
    mdelaystop(1); 	
	goto endcommand;    //break;
	
   case 'B' :	
	msetpotspeed();
    break;
   case 'P' : 
    unittimesav -= fractime;  // less unittime  to  more speed
	unittime = unittimesav;
	DDtime = unittime * 3 / 2;      // half of dash   // same of init   can be change too 
	LStime = DDtime; //unittime * 2;          // at least 
	goto dspspeed;  // option recursif (re-call mcommandbycar 'Z') pb pile mem
   case 'J' : 
    unittimesav += fractime;
	unittime = unittimesav;
	DDtime = unittime * 3 / 2;      // half of dash 
	LStime = DDtime; //unittime * 2;          // at least 
	goto dspspeed;  
   case 'O' : 
    interlettertime += fendtime; 
    mprinttrace(75,"end car +",interlettertime);
    break;
   case 'G' : 
    interlettertime -= fendtime; 
	mprinttrace(76,"end car -",interlettertime);
    break;
   case 'F' :
    endlettertime++;                     // 1 normal 2 training... 
    if (endlettertime > 2) endlettertime = 1;   // 1 2 ( 3 .. ) 
	bufferlcd[14] = endlettertime + 0x30; 
	mprinttrace(73,"end car time",endlettertime);
    break;
   case 'N' : 
    minfoslcd(bufferlcd); 
    mprinttrace(77,"read mess",nummessage);
	mreadcwmess(nummessage);  // on LCD
    goto endcommand;    //break;   
   case 'S' : 
    minfoslcd(bufferlcd); 
    mprinttrace(78,"send mess",nummessage);
	msendmessage(nummessage); // test cw tx message n
	goto endcommand;    //break;
   case 'C' : 
    minfoslcd(bufferlcd); 
	mprinttrace(79,"clear mess",nummessage);
	mclearcwmess(nummessage); 
	goto endcommand;    //break;
   case 'W' :
   //W  write in eeprom params and messages  
   //EEPROM write type  see eeprom.h  
   	eeprom_busy_wait();
	eeprom_write_byte(&ptzoneeeprom.zoctet1,startmode);      // write   byte    
	eeprom_write_byte(&ptzoneeeprom.zoctet2,flagrxcwavge);  
	eeprom_write_byte(&ptzoneeeprom.zoctet3,typealgo);  
	eeprom_write_byte(&ptzoneeeprom.zoctet4,ndebounce);
	eeprom_write_byte(&ptzoneeeprom.zoctet5,endlettertime);
	eeprom_write_byte(&ptzoneeeprom.zoctet6,flagMODTRIG);
	eeprom_write_byte(&ptzoneeeprom.zoctet7,flagMODBset);
	eeprom_write_byte(&ptzoneeeprom.zoctet8,flagspare1);
	eeprom_write_byte(&ptzoneeeprom.zoctet9,flagspare2);
	eeprom_write_byte(&ptzoneeeprom.zoctet10,tpscyclebalise);
	eeprom_write_byte(&ptzoneeeprom.zoctet11,0xFF);  
	eeprom_write_word(&ptzoneeeprom.zword1,unittimesav);   // write 2 bytes 
    eeprom_write_word(&ptzoneeeprom.zword2,interlettertime); 
	eeprom_write_word(&ptzoneeeprom.zword3, 0xFFFF); 
	eeprom_write_block(tablecwmess[2], ptzoneeeprom.zarray2, sizeof tablecwmess[2]); //write x bytes 
    eeprom_write_block(tablecwmess[3], ptzoneeeprom.zarray3, sizeof tablecwmess[3]); 
    eeprom_write_block(tablecwmess[4], ptzoneeeprom.zarray4, sizeof tablecwmess[4]);  

    mprinttrace(19,"write mode",startmode);  // info done
    //_delay_ms(300); // time to write ?
    break;       // no break; = read after
   
   
   case 'R' :
   //R Read from eeprom at warm start or by R 
    eeprom_busy_wait();
    startmode = eeprom_read_byte(&ptzoneeeprom.zoctet1);     // read   byte 
	flagrxcwavge = eeprom_read_byte(&ptzoneeeprom.zoctet2);  
	typealgo  = eeprom_read_byte(&ptzoneeeprom.zoctet3);  
	ndebounce   = eeprom_read_byte(&ptzoneeeprom.zoctet4); 
	endlettertime  = eeprom_read_byte(&ptzoneeeprom.zoctet5); 
 	flagMODTRIG   = eeprom_read_byte(&ptzoneeeprom.zoctet6);  
	flagMODBset   = eeprom_read_byte(&ptzoneeeprom.zoctet7);  
	flagspare1  = eeprom_read_byte(&ptzoneeeprom.zoctet8);  
	flagspare2  = eeprom_read_byte(&ptzoneeeprom.zoctet9);  
	tpscyclebalise    = eeprom_read_byte(&ptzoneeeprom.zoctet10);  
	readctrl = eeprom_read_byte(&ptzoneeeprom.zoctet11);  
	unittimeread = eeprom_read_word(&ptzoneeeprom.zword1);   // read 2 bytes 
	interlettertime = eeprom_read_word(&ptzoneeeprom.zword2);  
	readctrl = eeprom_read_word(&ptzoneeeprom.zword3);  
	eeprom_read_block(tablecwmess[2], ptzoneeeprom.zarray2, sizeof ptzoneeeprom.zarray2); //read n bytes 
   	eeprom_read_block(tablecwmess[3], ptzoneeeprom.zarray3, sizeof ptzoneeeprom.zarray3); 
	eeprom_read_block(tablecwmess[4], ptzoneeeprom.zarray4, sizeof ptzoneeeprom.zarray4); 
    _delay_ms(10);
   break;    // no break; follow by test K to check

   case 'L' :
    mtraining();    // training CW  block 5 caracters 
    break;

   case 'Y' :	
	analogresult = madc_read(analogchannelpot);   //analogRead(analogchannel);
    itoa(analogresult,chvalue,10);   
    snprintf(bufferlcd,LCDWIDTH+1," %c %s %s     ",'Y',"A/D-6",chvalue); //  
	LCD_DisplayScreen(bufferlcd);  
	mprinttrace(72,"read A/D-6",analogresult);  // read A/D 6 448
    mdelaystop(1); 	
    goto endcommand; //break;

   case 'Q' :
    flagmodbalise  =  !flagmodbalise;   // toggle
	bufferlcd[14] = flagmodbalise + 0x30; 
	mprinttrace(14,"beacon is",flagmodbalise); //(flagmodbalise ? '1' : '0'));
    //  chgt  tpscyclebalise   by extd command
    break;
	
   case 'V' :
    flagmodrepeat  =  !flagmodrepeat;   // toggle
	bufferlcd[14] = flagmodrepeat + 0x30; 
	mprinttrace(15,"repeater is",flagmodrepeat); //
    //   key-word    by extdcommand
    break;

   case 'X' :
    flagMODTRIG  =  !flagMODTRIG;   // toggle
	bufferlcd[14] = flagMODTRIG + 0x30; 
	mprinttrace(16,"mod trig is",flagMODTRIG); //
    break;

   case 'K' :
    flagMODBset  =  !flagMODBset;   // toggle
	bufferlcd[14] = flagMODBset + 0x30; 
	mprinttrace(17,"iambic mod is",flagMODBset); //
    break;

   case '?' :   		// signdl  
    minfoslcd(bufferlcd); 
    msendmessage(100);  // test cw tx buffertxc         (100 arbitrary )
    msendcar(CW_AR);    // test AR code 
    goto endcommand;    //break;  
	
   case '+' :
    flagdsptrace  =  !flagdsptrace;   // toggle
	bufferlcd[14] = flagdsptrace + 0x30; 
	mprinttrace(18,"trace is",flagdsptrace); // 0 will not be displayed !
    //   for PC  
    break;
	
	//case '1', || '2'|| '3' :    case  * > 1 * < MAXMESSNB
   case '1' :  
   case '2' : 
   case '3' : 
   case '4' :                      // >>>> max MAXMESSNB
   nummessage = cdecar - 0x30;   // max MAXMESSNB
   mprinttrace(67,"N mess is",cdecar - 0x30);  //atoi(cdecar));
   break;
  
  case '=' :
	// read variables   init  read  modified   or  set by ext prg 
    flagoldtrace = flagdsptrace; flagdsptrace = TRUE;  // do 
	
	mprinttrace(10,"start mode",startmode);
	mprinttrace(11,"rx average",flagrxcwavge);
	mprinttrace(32,"type  algo",typealgo);
	mprinttrace(34,"n debounce",ndebounce);
	mprinttrace(35,"end letter",endlettertime);
	mprinttrace(24,"n-iambic T",flagMODTRIG);
	mprinttrace(25,"iambic A B",flagMODBset);
	mprinttrace(26,"flagspare1",flagspare1);
	mprinttrace(27,"flagspare2",flagspare2);
	mprinttrace(37,"tps beacon",tpscyclebalise);
	mprinttrace(42,"unit  time",unittime);  // unittimeread  set by init 
	mprinttrace(43,"inter time",interlettertime);
	
	//mprinttrace(44,tablecwmess[1],0);
	mprinttrace(45,tablecwmess[2],0);  // test debug what is read
	mprinttrace(46,tablecwmess[3],0);  
	mprinttrace(47,tablecwmess[4],0);  
	flagdsptrace = flagoldtrace; 
	break;
		 
   // 
   default:
   mprinttrace(68,"not affected",0);
   
 }  // switch
  minfoslcd(bufferlcd); 
 
  endcommand:  // for theses already displayed
  memset(bufferlcd,SPACE,LCDWIDTH);
  LCD_Clear(); _delay_ms(100);
  LCD_DisplayScreen(bufferscrn);  // no delay after
}



//--------------------------------------------
// #820 check if cars in rx serial, if there are  do command
void mserialget(void)
{

char buf[MAXMESSSIZE+20];  // large place for protocole + messages   see ram place !
uint8_t n;
uint8_t nbr;

nbr = usb_serial_available();
 if ( nbr > 0 )
 {
			//msend_string(PSTR("> "));            // no prompt 
		  n = mrecv_string(buf, sizeof(buf));   // ok need CR
		  if (n > 1 )    
			{
			  if ( n != 255) 
			  {
			  // msend_string(PSTR("\r\n"));
			  buf[n] = NUL0;  // last must be end for XSMx=mmmmm NUL0 for strcpy 
			  mcommandextended(buf, n);   // extended commands 
			  }
			  // else
			  // time out 
            }
             else
            { 
		     // command  of 1 car  
		     if (flagserialrqt == TRUE)
	          {
			   mcommandbycar(caractcwcde);
			   caractcwcde = SPACE;  // acq
		       flagserialrqt = FALSE;  // ack 
		      }
            } 	
 }  
}
		


//--------------------------------------------
// #840  Fcts rx cw decode    see flowchart  
void mrxcwkeystart(void)
{	
   // --------- print space
   // ack key cde    1 espace   
   if (!(typeKEYMODE == KEYCDEBUTTON))   //  not for cde button
	{
	  mprintcw(SPACE);  
	  mprinttrace(50,"start space",0);    // debug
	  OUTCWMOX_OFF;  // here  end time of word !
     	
	 // allow change speed for send  when space letter, straight key (no audio) , in mode training
	 if ((typeKEYMODE == KEYSTRAIGHT)  && (flagLS == TRUE ) && (endlettertime == 2))
      { 
	   // here memory of average dot time has keying by straight key  	
	   unittime = Adottime ;  // Tx new ref speed for iambic key  last avg dot see TAG10
	   // DDtime =                    //  not for tx 
	   // LStime = 
	   
      }   
	}
	else
	{
	 typeKEYMODE = KEYSTRAIGHT;   // ack  set no key cde
	 flagcdespeed = FALSE;        // ack
	 unittime = unittimesav;      // ack  set at previous or modified speed 
	 //DDtime = DDtimesav;        //  Rx   but recomputed
	 //LStime = LStimesav;
	}

  
	
	// here  test test  algo + 10   take effective change when a space only 
    
		  switch  (typealgo)
		   {
		   case 11 :   // classic        1/2
		   DDtime = Adshtime / 2 ;
		   LStime = DDtime;               // =  Adshtime / 2 ;
		   break;
		   case 12 :   // W6PRO         with  flagrxcwavge true
		   DDtime =  ( Adshtime * 4  +  ELtime ) / 10;
		   LStime = DDtime;  // =  Adshtime / 2 ;
		   break;
		   case 13:   //  with DBNCE 1 .. 5  
		   DDtime = (Adshtime / 3) +  (ELtime / 4); 
		   LStime =  DDtime;    //Adshtime * 2 / 3; // DDtime;     // 2/3   
		   break; 
		   case 14 :   // WB9KPT     with  flagrxcwavge true / false 
		   LStime = ( Adshtime / 2) + DDtime;
		   DDtime = LStime / 2 ;
		   break;
		   case 15:   /// test 5      with DBNCE 1    open....
		   DDtime = Adshtime  * 3 / 5 ;  // Adshtime * 2 / 3;  //* 3 / 5;    //* 2 / 3; 
		   LStime = DDtime + (DDtime * 10 / 100);
		   //break; 
           }  
          
  
	   
}    	
	
	
	
//--------------------------------------------	
// #860 Key  up    here heart loop wait  	
void mrxcwkeyup(void)
{
	// loop wait key up             
	do
	{
	///// here service for somes fct depend when flag is set or not
	// enable interrupt here
	 		
	// test if flag balise is set   during quiet time   key up !
	mbalise();      // send message 3 each x Mn  
	// test if flag repeater is set
	mrepeater();    // send message 3 if rx cw  match preset word in message 4 
	// test for Rx serial for external commandes from PC soft  a-morse 
	mserialget();   // get command cars if there are !
	if (flagendamorse == TRUE )  return;   // exit if ',' cde warm reset
	 // now  here  turn around waiting for something ( each end word ) ... 
	mstatus(1);     // normal 1  ( not  endlettertime  ) 
	
	}while(flagKEY==UP);
	// disable interrupt here
	
}




//--------------------------------------------
// #870 key down   here    see rx flowchart
void mrxcwkeydown(void)
{
byte cptrxcodeloc;    // must be local

cptrxcodeloc = cptrxcode; // take global old

 	// key down :  start
	keydown:
	
	ELtime = 0;
	mprinttrace(51,"key-down",0);   // debug
		
	    // loop ELapsed time grow...
		do
		{
		mstatus(1);					// normal 1  ( not  endlettertime  ) 
		}while(flagKEY==DOWN);

    // key up   what about ELtime   is it < or >  DD  ?
	
	
	mprinttrace(52,"DD time",DDtime);    // before 
	mprinttrace(53,"key-up-1",ELtime);   //   debug
	
	if (flagDD==TRUE)        // over current DDtime or not !
	{
	 // ------ dash   
	 
	 // here somes  algos can be tested ...
	 // the goal is the dynamic average time for DD et LS in regard of the incoming time 
	 // first algo is related from original ' Petit ' :  LS=time/2 + DD  from last dot dash
	 // he said too use 3/4 of dash can be a good compromise...
	 // second from WB9KPT  1977  (LS=DD= time/2 + DD) / 2  for smaller LS from last too
	 // third from F1BEZ in 1979 build with uP 8080 ! is a little more adaptative :
	 // my experiments is about the ' glue letters ' and the shorts  LS time   !
	 // the way is an adaptative DD and LS which would the average of the lasts dots dashes,
	 // but a little more complex. it softens the short dot. 
 
	    if (typeKEYMODE == KEYSTRAIGHT)    // for straight KEY or audio input of course...
		{
		 if ( flagrxcwavge == TRUE )      // with average for adaptative...
		  {
		   //  do average last dashes
		   TLdash[ndash++] = ELtime;  
		   if (ndash > MAXDASH) ndash = 0;   // turn around 
		    ELAtime = 0;
		
		   for (aa = 0; aa< MAXDASH; aa++)
			{
			 ELAtime = ELAtime + TLdash[aa];
			}
		   ELAtime = ELAtime / MAXDASH; 		// average EL for theses MAXDASH last dashes
		   
	      }
           else
          {
		   ELAtime = ELtime;  				// without 
		  }
          if (ELAtime == 0) ELAtime = 4;    
		  Adshtime = ELAtime;
		  mprinttrace(65,"DSH time",Adshtime);   // ctrl moyenne
          ///// last or average last dashes  is used  for DD as 1/2  2/3 or others ! 
	      switch  (typealgo)
		  {
		   case 1 :   // classic        1/2
		   DDtime = Adshtime / 2 ;
		   LStime = DDtime;               // =  Adshtime / 2 ;
		   break;
		   case 2 :   // W6PRO         with  flagrxcwavge true
		   DDtime =  ( Adshtime * 4  +  ELtime ) / 10;
		   LStime = DDtime;  // =  Adshtime / 2 ;
		   break;
		   case 3:   //  with DBNCE 1 .. 5  
		   DDtime = (Adshtime / 3) +  (ELtime / 4); 
		   LStime =  DDtime;    //Adshtime * 2 / 3; // DDtime;     // 2/3   
		   break; 
		   case 4 :   // WB9KPT     with  flagrxcwavge true / false 
		   LStime = ( Adshtime / 2) + DDtime;
		   DDtime = LStime / 2 ;
		   break;
		   case 5:   /// test 5      with DBNCE 1    open....
		   DDtime = Adshtime  * 3 / 5 ;  // Adshtime * 2 / 3;  //* 3 / 5;    //* 2 / 3; 
		   LStime = DDtime + (DDtime * 10 / 100);
		   //break; 
		   
		  }
		 
	    }
		else  // paddle key 
		{
		 // nothing   use of last DD LS time
		}
	    
		 // methode for ' code ' computation and a table with the cw ' abbreviations ' 
		 // here is the way for unique sequence  dash is n time multiple of 2 + 1
		cptrxcodeloc *= 2;  //code X 2
		cptrxcodeloc++;     // + 1 
		
         	 
		mprinttrace(54,"--DASH--",cptrxcodeloc);   // debug
		mprinttrace(55,"DD time -",DDtime);        //  new
		mprinttrace(56,"LS time -",LStime);  
				
	}
	else
	{
		// -------- dot 
	    if (typeKEYMODE == KEYSTRAIGHT)  // for straihgt KEY 
		{
		 if ( flagrxcwavge == TRUE )    // with average for adaptative
		  {
	       // here somes average algo , methode continue like dash upper
		   TLdot[ndot++] = ELtime; 
		   if (ndot > MAXDOT) ndot = 0;   // turn around 
		     ELAtime = 0;
		   for (aa = 0; aa< MAXDOT; aa++)
		    {
		     ELAtime = ELAtime + TLdot[aa];
		    }
		    ELAtime = ELAtime / MAXDOT;      // TAG10
		  }
		   else
		  {
		  ELAtime = ELtime;
		  }
		  if (ELAtime == 0) ELAtime = 4;    
		  Adottime = ELAtime;
		  mprinttrace(66,"DOT time",Adottime);   // ctrl moyenne
	      //// dot     last or average used 
		  //LStime not updated in dot phase here   or testing
		  switch  (typealgo)
		  {
		    case 1 :   // classic   
	        DDtime =  Adottime +  ELtime / 2;  // avg dot + 1/2 last        
            //LStime = DDtime;
            break;
		    case 2 :   // W6PRU   
	        DDtime =  ( Adshtime * 5  +  ELtime * 2 ) / 12;   // no   Adottime        
            //LStime = DDtime;
            break;
			case 3 :
			DDtime = Adottime * 3 / 2; // * 1.5   // * 2;
			//LStime not updated in dot phase here
			break;
			case 4 :  // WB9KPT  
			//DDtime = Adottime * 2;
			//LStime not updated in dot phase here
			break;
			case 5 :   // test   dot dash short     
		    //DDtime = (Adshtime + LStime)  / 2; // 2/3    // Adottime * 9 / 5;  //* 2;    //    see  dash  2/3 
			//LStime = DDtime;
		    break;
			
		  }
		}
		else  // paddle key 
		{
		 // nothing   use of last DD LS time
		}
				
		// here is the way for unique sequence  dot is n time multiple of 2 
		cptrxcodeloc *= 2;             // code x 2
		mprinttrace(57,"..DOT..",cptrxcodeloc);   // debug
		mprinttrace(58,"DD time .",DDtime);        //  new
		mprinttrace(59,"LS time .",LStime);  
		
		
	}
	


    // -------- key up  return   wait  
	// here test a limit of code calculation , in regard of the morse table
	if ( cptrxcodeloc > MAXCODERX )
	{
		mprinttrace(64,"maxcode",cptrxcodeloc);  
		cptrxcodeloc /= 2;  					//code / 2  arbitrairy back
	}
	else
	{
		//w1:
		ELtime = 0;      				// clear and recycle
		//mprinttrace(58,"LS time",LStime);   // before
		// wait up   is it  end letter ?
		do
		{
		mstatus(1);  	     			// normal 1  ( not  endlettertime  ) 
			if ( flagKEY == DOWN )
			{
			 goto keydown;   			// down ! so continue
			}
		}while( flagLS == FALSE );
		
		mprinttrace(53,"key-up-2",ELtime);   //   debug
	}

    	
	// ---------- key up  end letter  !
	// here code has grown with dot and dash 
	ELtime = 0;   // clear and recycle  for testing end word
   	
	caractcwcde = mdecode(cptrxcodeloc);     	// code is offset for rx table
	cptrxcodeloc = 1;   						// clear after use for next step
	
	if ((typeKEYMODE == KEYCDEBUTTON)  && ( flagcdespeed == TRUE )) 
	{ 
	 // here it's an hole in the cycle Rx but no matter, run the command and follow here...
 	 mcommandbycar(caractcwcde);
	 caractcwcde = SPACE; // acq
	 typeKEYMODE = KEYSTRAIGHT; // acq cde
	}
	else // not a command 
	{
	 if (caractcwcde != HEADER)    // this is excluded reserved for trace
	  mprintcw(caractcwcde);
	
	 // add abreviation on pc ( no place on LCD.. )
	 if (DSPYABRV)
      {		   
		mprintbuffer(bufferabrv); // return if nul 
		strcpy (bufferabrv,"");  // clear after
	  }
	
	// --------- wait up  again   is end word ( 2  ( or * 2 )  * LS time ) 
	// allow an extra timing at end letter for space ending word in training mode
    // normal keying speed don't need   otherwise there are too many spaces between letters ! 
	 do
	  {
	   //  LStime * coeff      test twice the dash time 
	   mstatus(2); // endlettertime);      // normal 1 ...  training 2  timing end letter less spaces
	  
		if ( flagKEY == DOWN )
		{
		 goto keydown;   // down ! so continue
		}
	  }while(flagLS == FALSE );
	  mprinttrace(53,"key-up-3",ELtime);   //   debug
    // key up 
	}
	
	
	cptrxcode = cptrxcodeloc;  // store for next pass
	
    // key up       finish !! 
} 


//----------end fonctions -----------------------------------------------------

warmrestart1:
//-----------------------------------------------------------------------------
// #900 set for 16 MHz clock 
CPU_PRESCALE(0);
_delay_ms(100);


// --------------------------------------------------------------------
// Configure all ports     B and port D pins as inputs with pullup resistors.
// See the "Using I/O Pins" page for details.            not pull up if A/D
// http://www.pjrc.com/teensy/pins.html


KEYSTRG_CONFIG;      
KEYSTRG_PULLUP;	 
KEYIDOT_CONFIG;
KEYIDOT_PULLUP;
KEYIDASH_CONFIG;
KEYIDASH_PULLUP;
KEYSCMD_CONFIG;
KEYSCMD_PULLUP;

ANALOGA6;     // after other Fx
//ANALOGA7;     // after other Fx  

/// conf all pins like  out  and   def to 0    for LCD
DDRB = 0xFF;
PORTB = 0x00; 
DDRD = 0xFF;
PORTD = 0x00;
DDRC = 0xFF;
PORTC = 0x00;
// already out 
OUTCWBIP_CONFIG;
OUTCWBIP_OFF;     
OUTCWKEY_CONFIG;
OUTCWKEY_OFF;
OUTCWMOX_CONFIG;
OUTCWMOX_OFF;
OUTCWTAF_CONFIG;
OUTCWTAF_OFF;
OUTCWLED_CONFIG;
OUTCWLED_OFF;
_delay_ms(100);

// 
// --------------------------------------------------------------------
// #920  init 

for (aa=1;aa<LCDWIDTH;aa++)  // control cw tables fun warm up the processor... 
 bufferlcd[aa]=pgm_read_byte(&tablemorserx[pgm_read_byte(&tablemorsecw[aa])]);  
for (aa=0;aa<SIZEVERS;aa++)  // at cold start
 bufferabrv[aa]=pgm_read_byte(&mversion[aa]);  
for (aa=0;aa<MAXMESSNB;aa++)
 {
  memset(tablecwmess[aa],IDDLE,MAXMESSSIZE);
  tablecwmess[aa][MAXMESSSIZE+1] = NUL0;
 }


// 
//-----------------------  settings...    default 
// #940  presetting   ##  value from eeprom R  **  value  changed by interface a_morse.exe

startmode = 0;              // ## cold 
flagrxcwavge = TRUE;   	    // ##    
typealgo =  1;              // ## 
ndebounce =	MAXDBNCE;  		// ##    
endlettertime = 1;      	// ##  2 training and allow speed change by straight key ! cd F
flagMODTRIG = 1;            // ## trig   
flagMODBset = 0;            // ## mode A 
flagspare1 = 1;             // ## 
flagspare2 = 1; 		    // ##
tpscyclebalise = 15;        // ##  test 1  or  15 ( 1/4h )  
unittime = UTINITIAL;       // ##  cde P  J
interlettertime = 200;      // ##  cde  O  G   if training 2


flagendamorse = FALSE;      // always running
flagdsptrace = TRUE;        // ** cde +
cptdebounce = 0; 
cptcolonne = 0;
cptstone = 0;
typeKEYMODE = KEYSTRAIGHT;  
flagKEY = UP;
flagDD = FALSE;
flagLS = FALSE;
cptrxcode = 1;
ELtime = 0;
ELAtime = 0;
DDtime = 0;
LStime = 0;
Adshtime = 4;
Adottime = 4;
ndash = 0;
ndot = 0;
flagcdespeed = FALSE;      // FALSE user, TRUE fixed speed cw user when cde  
flagKEYIAMBIC = UP;
flagKEYIDOT = UP;
flagKEYIDASH = UP;
flagKEYIAMBIC = UP;
flagKEYMEMIDOT = 1;
flagKEYMEMIDSH = 1;
flagMEMIDOT = 0;
flagMEMIDASH = 0;
flagMODBDOT = 1;
flagMODBDASH = 1;
flagMODBsqz = 0;
flagWAITIDOT =  0;         
flagWAITIDASH = 0;
flagWAITSPACE = 0;
//flagMEMWAIT = 0;
flagWSYNCHRO = 0;

analogchannelpot = 6;  	// A6  ( F6 pin 17 )  // see define     pot for cw speed
analogchannelsmt = 7;  	// A7  ( F7 pin 16 )  // see define     s-metre  DC hard
nummessage = 1;  		// def Rx 
cptcyclems = 0;
cptcyclesec = 0;
cptcyclemn = 0;

flagsetbalise = FALSE;
flagmodbalise = FALSE;
flagsetrepeat = FALSE;
flagmodrepeat = FALSE;
flagserialrqt = FALSE; 
	

//-------- end settings ------------------------------
// #960
//--------- others inits ----------------------------- 

// initialize the USB, but don't want for the host to
// configure.  The first several messages sent will be
// lost because the PC hasn't configured the USB yet,
// but we care more about blinking than debug messages!
// http://www.pjrc.com/teensy/usb_serial.html

if (!usb_configured())  usb_init();    // allow warm restart 1 if already usb-init done

//usb_init();
//while (!usb_configured()) // <<<<<<<<<<< wait     // if this line need pc , amorse don't start ( wait ) 
//Is the USB controller configured?     //  else can start  alone  on LCD   ,   USB connected after is possible 

//Returns 0 (false) if the host has not enumerated (auto-detected) and configured the USB controller. 
//Returns non-zero (true) if configuration is complete. 
//Many PC and Macintosh drivers are not immediately ready to transfer data, even after configuration is complete. 
//An additional delay of 1 second is generally a good idea to allow drivers to load on the PC before initiating 
_delay_ms(100);  // 


//http://www.pjrc.com/teensy/usb_serial.html
// download and install   serial_install.exe  see gestionnaire perepherique  note N° port COM x 
// open Hyper Terminal ( or other )   set COM x (8?)   56800  (38400 not documented ????)  no protocol 8  bit  2 stop  
// check first with appli downloaded    usb_serial ( main 1 )  Teensy must echo what you send            
// main 0  test commands to read key F0?  and set  led D3=0 .   This part is used here    
// here makefile   print.c   print.h   are  modified  for names  
// start HyperTerminal after load and start  appli on Teensy   
//uint32_t serialbaud;                    
//serialbaud = usb_serial_get_baud();	     // to check   ans see at start up on lcd

// set baud ! ...
//https://www.mainframe.cx/~ckuethe/avr-c-tutorial/#usart-out
// hard dependant            // not tested
//#define BAUD 9600          // <<<<<<<<<<<<<<
//#include <util/setbaud.h>
//	UBRR0H = UBRRH_VALUE;
	//UBRR0L = UBRRL_VALUE;
	//UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
	//UCSR0B = _BV(RXEN0) | _BV(TXEN0);
	//stdout = &O;
	//stdin  = &I;

//////  USB serial sometimes do nothing ?  
//////  print  need a lot of pass before ?
//////  when teensy start the usb serial is set (com x ) 
//////  so Hyperterminal know port x AFTER, otherwise com x is lost !
//////  something not clear about time init serial USB  vs  hid_listen  which does not lose com x
    //OUTCWBIP_ON;       // this loop for time and to scope checking 
	//for (int bb = 1; bb<3; bb++)       
	//{
//<<	  for (aa = 1; aa<1000; aa++) 	mdelay();   // aa int
	// print("\ntest-1S\n");
	//}
	//OUTCWBIP_OFF;   // scope checking for 1s
//////	

//warmrestart2:                    // with actual ram parameters
//flagendamorse = FALSE; 
usb_serial_flush_input();              // clear ( empty ) 
usb_serial_flush_output();
_delay_ms(3000);  // !! 3 sec.  time to start Hyperterminal after run Teensy    


// --------------------------------------------------------------
// here init user interrupt         project 
// http://www.pjrc.com/teensy/interrupts.html

// 
// ---------------------------------------------------------------	
// #970 initialize the LCD module !!  if delay to clear somes need time !!
LCD_Init(); _delay_ms(100); //LCD_Clear();
minfoslcd(bufferlcd);       // first check lcd ...
snprintf(buffertrace,SIZEBUFF,"%s %s %s\r\n","#020",&bufferlcd[2],bufferabrv);
mprintbuffer(buffertrace);  // not mprinttrace
buffertrace[0] = NUL0; bufferabrv[0] = NUL0; 
strncpy(buffertxc,"F5BEZ 73 ",LCDWIDTH);  // demo user message and quick test fct ? 

// ---------------------------------------------------------------- 
// #980 normal warm if cde key up, cold if start with cde key keep down 
if ((PINF & 32) == 32)
 {
  // warning must read corrects values ! otherwise program will hang !	
  // >>>>>  remember me start with cde down when  reset loader   follow with = and W 
  mcommandbycar('R'); // load datas bytes, words and array-messages from eeprom  ( block ) 
 }
if ((startmode > 0) && ( startmode < 11 ))   // normal start with previous eeprom value 
 {
  if (unittimeread > 30  && unittimeread < 250 )   // if in range !
    unittime = unittimeread;      // so change  
    // others check here	
    
 }
  else
 {
 // new first start byte is 0xFF or cold with key down  or others startmode 1..10
 // or in dev >>>>>>   bt reset load teensy erase old eeprom value <<<<<<<  
 // for(aa = 0;aa < MAXMESSNB;aa++)
 //  mclearcwmess(aa);
 // set somethings by default...  see   ext cde XPSM2=CQ CQ DE MYCALL K   and  ' W '  cde    
 strcpy(tablecwmess[1]," CW");                        //  1rst space will be shifted by 1rst cycle
 strcpy(tablecwmess[2],"CQ CQ DE F4KIO F4KIO K K");   //  demo     ARA 35  radio club 
 strcpy(tablecwmess[3],"F5ZEH BEACON");               //  demo     ARA 35  28Mhz projet balise
 strcpy(tablecwmess[4],"TEST");                       //  !  4 MAXMESSNB
 
 // now user set his cw speed and fill his messages for write them by w  
 }        
    

mstrcpy_string(PSTR("start mode : x ")); bufferlcd[13] = startmode + 0x30; 
minfoslcd(bufferlcd); 
snprintf(buffertrace,SIZEBUFF,"%s %s\r\n","#022",bufferlcd);
mprintbuffer(buffertrace);  // not mprinttrace
flagdsptrace = DSPTRACE;    // remember me after start set cde +
startmode = 1;              // for next W   or   1..10  
//NB  remember me  W default  when  reset-loader !        <<<<<<<< 
//if ( TRUE )  mcommandbycar('W');  //// dev only
mcommandbycar(':');       // version 
unittimesav = unittime;   // preset or read   see cdes  P  J  Z  W
mcommandbycar('Z');       // display current speed 
// preset for  DD LS   all other choice change herre  see cde  P  J
DDtime = unittime * 3 / 2;      // half of dash 
LStime = DDtime;  //unittime * 2;          // at least 

// preset for the 1rst average DD LS 
 for (aa = 0; aa< MAXDASH; aa++)
	 {
	  TLdash[aa] =  unittime  * 3;
     }
     for (aa = 0; aa< MAXDOT; aa++)
     {
      TLdot[aa] =  unittime;
     }


//--------------------------------------------
// 
// #990         --- main loop  --- 
//
//--------------------------------------------
// option call by isr interrupt by timer each sampling time  
 
 while (!flagendamorse)
 {
    //mdelay();        // here important it's the sampling time !!!! but moved see mstatus
	mrxcwkeystart();   // which key ?
	mrxcwkeyup();      // with others fcts when up ( when waiting )   
	mrxcwkeydown();    // decode
	//mabort();		   // not used	
 
 }  //  end main loop  
    goto warmrestart1; 
} // main end program  amorse  enjoy it !  ouf ! voilà bonnes manips ...
 //  by Dominique LEVEQUE f5bez 2011    
//---------------------------------------------------------------.




