/* ************************************************************************************
	Gene UHF et Wobulateur AD9850 + ADF4351  
	par Silicium628
	pour ma carte (fab : JLCPCB) ESP32 Wroom + afficheur 2.8" TFT 240x320  + SDcard
	
	Cette version utilise la SDcard

************************************************************************************ */

// REMARQUES: 
// 1) lorsque la carte est connectée sur un bus USB de l'ordinateur,
// un terminal série tel que CuteCom affichera beaucoup de choses en temps réel.
// 2) Pour s'y retrouver dans le code, le plus simple est de partir de la fonction 'loop()' qui appelle les autres 
// 3) Le fichier User_Setup dans le dossier 'lib/TFT_eSPI' est spécifique à cette configuration
// pour ce qui concerne les connexions mais aussi les limitations de fréquence du bus SPI


#include <Arduino.h>
#include "main.h"
#include "ADF4351-ESP32.h"
#include "AD9850-ESP32.h"

String version = "2.10.1"; 

#include "FS.h"
#include "SD.h"
#include "Wire.h"
#include <stdint.h>

#include <Free_Fonts.h>
#include "TFT_eSPI.h" // Hardware-specific library
#include "SPI.h"
#include "Digit_Font.h"
#include <XPT2046_Touchscreen.h>

#include "constantes2_628.h"
#include "Couleurs_AEC.h"

int style = 0; // 0 bleu, 1 vert, 3 jaune

ADF4351 CarteADF4351;
AD9850  CarteAD9850;


#define SPI_READ_FREQUENCY 16000000

#define XPT2046_IRQ 36
#define XPT2046_MOSI 32 //T_DI 32
#define XPT2046_MISO 39 //T_DO 39
#define XPT2046_CLK 25
#define XPT2046_CS 33

const int GPIO_SDA = 21; 
const int GPIO_SCL = 22; 

const int analogPin = 35;
const int boutonPin1 = 4; // GPIO4

//const int GPIO_BL = 4; // pour LED backlight ILI9341- INUTILISE POUR CETTE APPLICATION - relier backlight à +3v3
// donc le GPIO4 est libre...

const int _DX = 320;
const int _DY = 240;

SPIClass mySpi = SPIClass(VSPI);
XPT2046_Touchscreen ts(XPT2046_CS, XPT2046_IRQ);

SPIClass mySpi2 = SPIClass(HSPI);

TFT_eSPI TFT = TFT_eSPI(); // Configurer le fichier User_Setup.h de la bibliothèque TFT_eSPI au préalable

TFT_eSprite sprite_frq = TFT_eSprite(&TFT); // grands chiffres en haut
TFT_eSprite sprite_freq_W_min = TFT_eSprite(&TFT);
TFT_eSprite sprite_freq_W_max = TFT_eSprite(&TFT);  

uint16_t FRQ_x0;
uint16_t FRQ_y0;

const uint64_t F_min_AD9850  = 1;
const uint64_t F_max_AD9850  =   52000000; // 52 MHz , au delà le signal est pourri !

const uint64_t F_min_ADF4351 =   33000000;
const uint64_t F_max_ADF4351 = 4400000000;


struct ETALON_TS // etalon touch screen
{
    int16_t x0;
    int16_t dx;
	int16_t y0;
    int16_t dy;
};

ETALON_TS eTS;

struct POINT
{
	uint16_t x;
	uint16_t y;
};

// coordonnées des points de calibrage de l'écran tactile 
// (calibration ? étalonnage ?? ajustage ??? boaf, m'enfin !!)
POINT A, B;

uint8_t SDcardOk=0;

uint16_t x_touch, y_touch;
uint16_t memo_x_touch, memo_y_touch;

uint16_t compte1=0;
uint16_t compte2=0;

uint8_t num_capture = 0;

uint64_t frequence=10000; 
uint32_t pas_W = 0; // pas (de wobulation)
//uint64_t freq_W_min;
uint64_t freq_W_max;
uint64_t Fmin, Fmax;


double F_9850;	// fréquence à envoyer à l'AD9850 (en 1/10 Hz)
double F_4351;	// fréquence à envoyer à l'ADF4351 (en MHz avec décimales)

//boolean le_pas_est_choisi = false; 
boolean soft_setup =false;
boolean do_capt_screen = false;

boolean stop1=false;

uint16_t JAUNE_chiffres = 65504; 
uint16_t VERT_chiffres = 2016;

TOUCH_BOUTON bt_RAZ;

//fréquences presets
TOUCH_BOUTON bt_455k;
TOUCH_BOUTON bt_4M;
TOUCH_BOUTON bt_10_7M;
TOUCH_BOUTON bt_27M;
TOUCH_BOUTON bt_35M;
TOUCH_BOUTON bt_41M;
TOUCH_BOUTON bt_144M;
TOUCH_BOUTON bt_432M;
TOUCH_BOUTON bt_2400M;


TOUCH_BOUTON bt_AD9850;
TOUCH_BOUTON bt_ADF4351;

TOUCH_BOUTON bt_mode_GENE;
TOUCH_BOUTON bt_mode_WOBU;

TOUCH_BOUTON bt_STOP_1; // du balayage fréquenciel
TOUCH_BOUTON bt_STOP_2; // de la boucle de déplacement du curseur

TOUCH_BOUTON bt_polarite;

TOUCH_BOUTON bt_gain_P; // gain +
TOUCH_BOUTON bt_gain_M; // gain -

TOUCH_BOUTON bt_pas_P; // incrémente le pas de wobulation suivant la suite 1,2,5...
TOUCH_BOUTON bt_pas_M;
uint8_t num_pas=0;

TOUCH_BOUTON bt_TEST;

CHF_PAD chf_pad1;

enum OUTPUT_MODE {MODE_9850, MODE_4351}; 
OUTPUT_MODE out_mode1;
OUTPUT_MODE memo_out_mode1;

enum FONCTION_MODE {MODE_ACCUEIL, MODE_GENE, MODE_WOBU}; 
FONCTION_MODE f_mode1;
//FONCTION_MODE memo_f_mode1;

enum POLARITE {_DIR, _INV};
POLARITE polarite1 = _DIR;

uint32_t liste_pas_W_a[3] = {1, 2, 5}; // num 0 à 3
uint64_t liste_pas_W_b[7] = {1, 10, 100, 1000, 10000, 100000, 1000000}; // numéros 0 à 6

uint16_t memo_img[200*32];


void init_sprites()
{
	sprite_frq.createSprite(315, 45);
	sprite_frq.setTextDatum(MR_DATUM); // alignement du texte

	sprite_freq_W_min.createSprite(80, 8);
	sprite_freq_W_max.createSprite(80, 8);
}


void init_variables_globales()
{
	FRQ_x0 = 2;	
	FRQ_y0 = 30;

	//frequence = 4123456789; // 4.12 GHz
	frequence = 60000000;  // 60MHz
}


void init_1_bouton(uint8_t n_font, uint16_t xi, uint16_t yi, uint8_t dx, uint8_t dy, String si, TOUCH_BOUTON *bouton_i)
{
	bouton_i->init(xi, yi, dx, dy, 3, GRIS_5);
	bouton_i->cliked = false;
	bouton_i->selected = false;
	bouton_i->label = si;
	bouton_i->affiche(BLANC, VERT, n_font);
}


void popup(uint16_t x, uint16_t y, String s1, String s2)
{
	TFT.readRect(x, y, 200, 32, memo_img); // memorise image avant de tracer le texte

	TFT.fillRect(x, y, 200, 32, NOIR);
	TFT.drawRect(x, y, 200, 32, VERT);
	TFT.setTextColor(BLANC, NOIR);
	TFT.setFreeFont(FF1); // 1ere ligne en 'gros' caractères
	TFT.drawString(s1, x+2, y+2);
	TFT.setFreeFont(FF0); // 2eme ligne en plus petits caractères (mais elle peut donc être plus longue)
	TFT.drawString(s2, x+2, y+20);
	delay(3000);
	TFT.pushRect(x, y, 200, 32, memo_img);
}



void test_bouton_physique1()
{
	int v = digitalRead(boutonPin1);
	if (v == 0) 
	{
		capture_ecran();
	}
}



// Fonction optimisée pour l'afficheur ILI9341 320x240 avec la  library 'TFT_eSPI'
// ne convient PAS pour les ESP32 Wroom + afficheur 3.5" TFT 480x320
void capture_ecran() // enregistre image bmp 320x240 RGB565 (5+6+5 = 16bits/px)
{
Serial.println("capture_ecran()"); 

	if (SDcardOk==0) 
	{
		Serial.println("SDcard absente, capture ecran impossible"); 
		return;
	}

	int32_t x, y;
	uint16_t color565;

	uint8_t  lineBuffer8[(320*2)];
	uint16_t lineBuffer16[320];
	uint8_t octet_A, octet_B;
	String s1, s2;	

	s1 ="/bmp565/capture";
	s1 += String(num_capture);
	s1 += ".bmp" ;

Serial.print("s1= "); Serial.println(s1);

	while(SD.exists(s1) &&  num_capture <= 50) 
	{
		num_capture ++;
		s1 ="/bmp565/capture";
		s1 += String(num_capture);
		s1 += ".bmp" ;
	}
	if (num_capture >= 50)
	{
		popup(40, 150, "Nb de CPT > 50 !", "Voir sur la SDcard"+s1);
		num_capture =0;
	} 

	File file1 = SD.open(s1, FILE_WRITE); // crée le fichier si pas présent
	delay(20);
	if (file1)
	{
		// création entête bmp565 - 138 octets; voir bmp565_header[] dans le fichier main.h
		for(uint8_t i=0; i<138; i++) { file1.write(bmp565_header[i]); }
		TFT.setTextColor(VERT, NOIR);
		for (int16_t y=239; y>=0; y--)
		{
			TFT.readRect(0, y, 320, 1, lineBuffer16); // lit une ligne
			s2=String(y/24);
			TFT.drawString(s2, 2, 2); // pour terminer par une écriture

			uint16_t i=0;
			for (int16_t x=0; x<320; x++) //320
			{
				uint16_t color565px = lineBuffer16[x];  // BBBBBrrr rrrVVVVV 
				octet_A = (color565px & 0b1111111100000000) >> 8;
				octet_B = (color565px & 0b0000000011111111);

				lineBuffer8[i]   = octet_A;
				lineBuffer8[i+1] = octet_B;
				i+=2;
			}	
			file1.write(lineBuffer8, sizeof(lineBuffer8)); 
		} 
		file1.close();
		num_capture ++;

		// TFT.fillScreen(NOIR);

		popup(40, 150, "   Capture OK", "    "+s1);

	
		delay(2000);
	}
}



void printTouchToDisplay() // pour TEST positions lors de la conception de l'interface graphique
{
// dessine une petite croix jaune au points d'appuis du stylet

	init_1_bouton(1, 235, 114, 30, 15, "TEST", &bt_TEST);

	uint16_t memo_seg_H[22];
	uint16_t memo_seg_V[22];
	uint16_t memo_x, memo_y;

	TFT.setFreeFont(FM9);
	TFT.setTextColor(BLEU_CLAIR, NOIR);
	//TFT.drawString("TEST TOUCH screen", 80, 120);

	TFT.readRect(x_touch-10, y_touch, 20, 1, memo_seg_H); 
	TFT.readRect(x_touch, y_touch-10, 1, 20, memo_seg_V);
	while(1)
	{
		if (ts.tirqTouched() && ts.touched()) 
		{
			get_XY_touch();
			TFT.readRect(x_touch-10, y_touch, 20, 1, memo_seg_H); // memorise image avant de tracer le trait
			delay(10);
			TFT.pushRect(memo_x_touch-10, memo_y_touch, 20, 1, memo_seg_H); // efface avec l'image enregistrée
			delay(10);
			TFT.drawFastHLine(x_touch-10, y_touch, 20, JAUNE);
			delay(10);

			TFT.readRect(x_touch, y_touch-10, 1, 20, memo_seg_V); // memorise image avant de tracer le trait
			delay(10);
			TFT.pushRect(memo_x_touch, memo_y_touch-10, 1, 20, memo_seg_V); // efface avec l'image enregistrée
			delay(10);
			TFT.drawFastVLine(x_touch, y_touch-10, 20, JAUNE);

			String s1;
			s1 = String(x_touch)+ "    ";
			TFT.drawString(s1, 120, 130);
			s1 = String(y_touch)+ "    ";
			TFT.drawString(s1, 120, 154);
			delay(10);

			test_clic_bouton_TEST();
		}
	}
} 



void affiche_box_FRQ(uint16_t couleur) // autour de la fréquence (gros chiffres)
{
	TFT.drawRect(0, FRQ_y0 -17, 319, 48, couleur);
}



void acquisition_reponse()
{
	uint16_t valeurLue = analogRead(analogPin); // = 0..4095

}


void out_frequence()
{
	if (out_mode1 == MODE_9850)
	{
		F_9850 = 10.0 * frequence;
		CarteAD9850.out_F(F_9850);
	}

	if (out_mode1 == MODE_4351)
	{
		F_4351 = (double) frequence / 1e6;
		CarteADF4351.setFreq(F_4351);
		CarteADF4351.Write_All_Register();
	}
}


void affiche_frequence(uint64_t frq)
{	
	uint16_t couleur_chiffres;
	uint16_t couleur_fond;

	if(style == 0) { couleur_chiffres = VERT_chiffres; couleur_fond = NOIR; }
	if(style == 1) { couleur_chiffres = BLANC; couleur_fond = BLEU; }
	if(style == 2) { couleur_chiffres = JAUNE_chiffres; couleur_fond = NOIR; }

	sprite_frq.fillRect(0, 0, 320, 45, couleur_fond); // couleur_fond efface

	sprite_frq.setTextColor(couleur_chiffres, couleur_fond); 
	String Str_frq = formatage_frq(frq);  // ajoute les points (.) séparateurs des milliers
	sprite_frq.drawString(Str_frq, 320, 30, 6);  //320, 32, 6
	sprite_frq.pushSprite(FRQ_x0, 14);
	
	affi_mode();
	out_frequence();
	
}


void encadre_chiffre(uint16_t x)
{
	TFT.drawRect(x, 18, 28, 44, BLANC);
}


void efface_bande_boutons()
{
	TFT.fillRect(0, 61, 319, 19, NOIR);
	TFT.drawRect(0, 61, 319, 19, BLANC);
}


void affi_boutons_gene() // boutons presets de fréquences
{
	efface_bande_boutons();

	TFT.setFreeFont(FF0);
	TFT.setTextColor(BLANC, NOIR);
	TFT.drawString("presets->", 5, 65);

	if (out_mode1 == MODE_9850)
	{
		uint16_t x = 60;
		init_1_bouton(1, x, 65, 30, 10, "455k", &bt_455k); 	x+=35;
		init_1_bouton(1, x, 65, 20, 10, "4M", &bt_4M); 		x+=25;
		init_1_bouton(1, x, 65, 30, 10, "10.7", &bt_10_7M); x+=35;
		init_1_bouton(1, x, 65, 25, 10, "27M", &bt_27M); 	x+=30;

	}

	if (out_mode1 == MODE_4351)
	{
		uint16_t x = 60;
		init_1_bouton(1, x, 65, 25, 10, "35M", &bt_35M); 	x+=30;
		init_1_bouton(1, x, 65, 25, 10, "41M", &bt_41M); 	x+=30;
		init_1_bouton(1, x, 65, 30, 10, "144M", & bt_144M); x+=35;
		init_1_bouton(1, x, 65, 30, 10, "432M", & bt_432M); x+=35;
		init_1_bouton(1, x, 65, 30, 10, "2.4G", & bt_2400M);
	}

	TFT.drawRect(1, 61, 319, 19, BLANC);
}



void affi_select_PAS()
{
	efface_bande_boutons();
	init_1_bouton(1, 5, 63, 40, 15, "PAS-", &bt_pas_P);
	init_1_bouton(1, 55, 63, 40, 15, "PAS+", &bt_pas_M);
}


uint64_t calcul_pas_w(uint8_t n) // progression 1,2,5,10,20...[5e6]re
{
	if (n>21) {return 0;}
	int b=0;
	for(int i=0; i<7; i++)
	{
		if(n<3) {return liste_pas_W_a[n] * liste_pas_W_b[b];}
		b++; n-=3;
	}
	return 0;
}



void init_boutons_choix_MODULE()
{
	init_1_bouton(2,  45, 90, 90, 25, " AD9850",  &bt_AD9850);
	init_1_bouton(2, 175, 90, 90, 25, " ADF4351", &bt_ADF4351);
}


void init_boutons_choix_MODE()
{
	init_1_bouton(1, 80, 0, 60, 15, "GENE",  &bt_mode_GENE);
	init_1_bouton(1, 160, 0, 60, 15, "WOBU", &bt_mode_WOBU);
}



void init_affichages()
{
Serial.println("init_affichages()"); 	
	TFT.fillRect(0, 0, 319, 239, NOIR);

	TFT.setTextColor(BLANC, NOIR);

	TFT.drawRect(0, 0, 319, 240, BLANC); // cadre principal pourtour de l'écran
	//TFT.setFreeFont(FF0);
	//TFT.setTextColor(BLANC, BLEU);
	//String s1 = "v:" + version;
	//TFT.drawString(s1, 2, 2);
	
	while (!Serial && (millis() <= 1000));

	TFT.setFreeFont(FF0);

	init_1_bouton(1, 285, 0, 30, 12, "RAZ", &bt_RAZ);
	
	affi_boutons_gene();

/*
	TFT.fillRect(3,  80, 115, 3, ORANGE); // barres horizontales colorées 
	TFT.fillRect(135, 80, 105, 3, VERT);
	TFT.setFreeFont(FF0);
	TFT.setTextColor(ORANGE, NOIR);
	TFT.drawString("AD9850", 45, 80);
	TFT.setTextColor(VERT, NOIR);
	TFT.drawString("ADF4351", 165, 80);
*/
	affiche_box_FRQ(GRIS_3); // autour de la fréquence (gros chiffres JAUNE ou VERT)
	
	bt_RAZ.affiche(BLANC, VERT, 1); 
	bt_TEST.affiche(BLANC, VERT, 1); 

	TFT.drawRect(0, 0, 319, 240, BLANC); // cadre principal pourtour de l'écran

}


void affi_page_info()
{
// affiche une page d'information:

	TFT.fillScreen(NOIR);
	TFT.setTextColor(BLANC, NOIR);
	TFT.setFreeFont(FF1);
	uint16_t y=0;
	TFT.drawString("DOUBLE GENE UHF - WOBULATEUR", 0, y);	y+=40;

	TFT.setTextColor(ORANGE, NOIR);
	TFT.drawString("AD9850  -> 0 to 35Hz MHz", 0, y);	y+=20;
	TFT.setTextColor(VERT, NOIR);
	TFT.drawString("ADF4351 -> 35 MHz to 4.4 GHz", 0, y);	y+=40;

	TFT.setTextColor(BLANC, NOIR);
	TFT.setFreeFont(FF0);
	String s1="version " + version;
	TFT.drawString(s1, 0, y);	y+=20;

	TFT.setTextColor(CYAN, NOIR);
	TFT.setFreeFont(FF1);
	TFT.drawString("Silicium628", 0, y);	y+=40;

	delay(1000);
}


void init_SDcard()
{
	Serial.println("---------------------");
	Serial.println("init_SDcard()");	
	String s1;
	
	TFT.fillRect(0, 0, 480, 320, NOIR); // efface tout l'écran
	TFT.setTextColor(BLANC, NOIR);
	TFT.setFreeFont(FF1);

 	if(!SD.begin(5, mySpi2)) 
	{ 
		Serial.println("Card Mount Failed");
		SDcardOk=0;
	} 
	else 
	{ 
		Serial.println("SDcard OK");	
		SDcardOk=1;
		TFT.fillRect(0, 0, 480, 320, VERT);
		delay(100);
	}
  
    uint8_t cardType = SD.cardType();

    if(cardType == CARD_NONE)
    {
		Serial.println("NO SDcard"); 
		SDcardOk=0;
        return;
    }
    
	Serial.print("SDcard Type: ");
	if(cardType == CARD_SD) {Serial.print("SDSC");}
    else if(cardType == CARD_SDHC) {Serial.println("SDHC");}
	
	uint32_t cardSize = SD.cardSize() / (1024 * 1024);
	s1=(String)cardSize + " GB";
	Serial.println(s1); Serial.println();
	
	delay (100);
	TFT.fillRect(0, 0, 480, 320, NOIR); // efface
}


uint16_t read_16(File fp)
{
    uint8_t low;
    uint16_t high;
    low = fp.read();
    high = fp.read();
    return (high<<8)|low;
}


uint32_t read_32(File fp)
{
    uint16_t low;
    uint32_t high;
    low = read_16(fp);
    high = read_16(fp);
    return (high<<8)|low;   
}

void affi_image_from_SD(String filename, uint16_t x0, uint16_t y0)
{
Serial.println("----------------------------");
Serial.println("affi_image_from_SD()");

	uint8_t bmp_data[2]={0,0};
	uint8_t  a, b;
	uint16_t x=0;
	uint16_t y=0;
	int16_t xmax;

	uint32_t seekOffset;
  	uint16_t w, h, row, col;


	File fp = SD.open(filename, "r");
	if (!fp) { Serial.println("ERREUR open file on SD"); return; }

	uint16_t etiq1 = read_16(fp);

// test bmp_header	
	if (etiq1 == 0x4D42) 
	{
		read_32(fp);
		read_32(fp);
		seekOffset = read_32(fp);
Serial.print("seekOffset ="); Serial.println(seekOffset); // 138

		Serial.print("seekOffset= "); Serial.println(seekOffset); 
		read_32(fp);
		w = read_32(fp);
		h = read_32(fp);
		Serial.print("w= "); Serial.println(w); // 75
		Serial.print("h= "); Serial.println(h); // 50
		Serial.println(read_16(fp)); // 1
		Serial.println(read_16(fp)); // 16
		Serial.println(read_16(fp)); // 3
		fp.seek(seekOffset);
	}	

	y += h;
	xmax = w;
	if(xmax%2 == 1) {xmax +=1;}

	uint16_t padding = (4 - ((w * 2) & 2)) & 2;
	uint8_t lineBuffer[(w*2) + padding];

	for (row = 0; row < h; row++) 
	{
		fp.read(lineBuffer, sizeof(lineBuffer));
		uint8_t*  bptr = lineBuffer;
		uint16_t* tptr = (uint16_t*)lineBuffer;

		for (uint16_t col = 0; col < w; col++)
		{
			a = *bptr++;
			b = *bptr++;
			*tptr++ = (a <<8 | b);
		}
		TFT.pushImage(x0 + x, y0 + y, w, 1, (uint16_t*)lineBuffer);
		y--;			
	}
	fp.close();
}


void write_fichier_params() // sur la SDcard
{
Serial.println("write fichier '/params.txt'");	

	File file1 = SD.open("/params.txt", FILE_WRITE);
	String s1;

	/*
	s1 ="[couleur_fond]";
	s1 += "<";
	s1 += String(couleur_fond_ecran); 
	s1 +=">";
	file1.println(s1); 
*/

	s1 ="[frequence]";
	s1 += "<";
	s1 += String(frequence); 
	s1 +=">";
	file1.println(s1); 

	s1 ="[Ax]";
	s1 += "<";
	s1 += String(A.x); 
	s1 +=">";
	file1.println(s1); 

	s1 ="[Ay]";
	s1 += "<";
	s1 += String(A.y); 
	s1 +=">";
	file1.println(s1); 

	s1 ="[Bx]";
	s1 += "<";
	s1 += String(B.x); 
	s1 +=">";
	file1.println(s1); 

	s1 ="[By]";
	s1 += "<";
	s1 += String(B.y); 
	s1 +=">";
	file1.println(s1); 


	file1.close();
	delay(100);
}


void TS_calibrate()  // calibrage de l'écran tactile
{
	uint8_t L = 20;
	boolean ok; 
	String s1;

	TFT.setTextColor(BLANC, NOIR);
	TFT.setFreeFont(FF1);

// traitement point A
	TFT.fillScreen(NOIR);
	TFT.drawString("Cliquez sur le point A", 20, 50);
	delay(300);
	TFT.drawFastVLine(10, 0, L, JAUNE);
	TFT.drawFastHLine(0, 10, L, JAUNE);  
	ok = false;
	while (! ok)
	{
		if (ts.tirqTouched() && ts.touched()) 
		{
			memo_y_touch = y_touch;
			TS_Point p = ts.getPoint();
			s1 = "Ax=" + String(p.x) + "     "; TFT.drawString(s1, 50, 100);
			s1 = "Ay=" + String(p.y) + "     "; TFT.drawString(s1, 50, 120);
			delay(100);

			if( (p.x<600) && (p.y < 600)) // évite de valider une position irréaliste 
			{
				A.x = p.x; // point A : variable globale
				A.y = p.y;
				ok = true;
			}
		}	
	}	

// traitement point B
	TFT.fillScreen(NOIR);
	delay(300);
	TFT.drawString("Cliquez sur le point B", 20, 70);
	TFT.drawFastVLine(310, 230-L/2, L, JAUNE);
	TFT.drawFastHLine(310-L/2, 230, L, JAUNE);
	ok = false;
	while (! ok)
	{
		if (ts.tirqTouched() && ts.touched()) 
		{
			memo_y_touch = y_touch;
			TS_Point p = ts.getPoint();
			s1 = "Bx=" + String(p.x) + "     "; TFT.drawString(s1, 50, 150);
			s1 = "By=" + String(p.y) + "     "; TFT.drawString(s1, 50, 170);
			delay(100);

			if( (p.x>3600) && (p.y > 3400)) // évite de valider une position irréaliste
			{
				B.x = p.x;
				B.y = p.y;
				ok = true;
			}
		}	
	}

	if(SDcardOk==1)
	{	
		TFT.fillScreen(NOIR);
		TFT.drawString("Ok", 20, 60);
		TFT.setFreeFont(FF0);
		TFT.drawString("Write fichier params sur la SD", 10, 90);
		write_fichier_params();
		delay(1000);
	}

	TFT.fillScreen(NOIR);
	init_affichages();

	//TS_verif();
	//printTouchToDisplay(); // POUR TESTER LA CALIBRATION DE L'ECRAN TACTILE
}


String read_line_params(uint16_t line_num)
{
	int i = 1;
	char buffer[64];
	String s;	

	File file = SD.open("/params.txt", "r");

	while (file.available())
	{
		int l = file.readBytesUntil('\n', buffer, sizeof(buffer));
		buffer[l] = 0;
		if (line_num == i)
		{
			s = buffer;
			file.close();
			return(s);
		}  
		i++;
	}
	return "";
}


int32_t extract_params(String ligne, String label)
{
	String s2;
	uint32_t valeur = 0;
	int p1, p2;

	p1 = ligne.indexOf('[');	p2 = ligne.indexOf(']');
	s2 = ligne.substring(p1+1, p2);

	if (s2 == label)
	{
		p1 = ligne.indexOf('<');	p2 = ligne.indexOf('>');
		s2 = ligne.substring(p1+1, p2);
		valeur = s2.toInt();
		return valeur;
	}
	return -1;
}


void read_params() // lecture du fichier '/params.txt' en SD	
{
	Serial.println("lecture du fichier '/params.txt' en SD");
	String s1;
	int valeur;
	
	s1 = "Z";
	uint8_t n=1;
	while (s1 !="") 
	{
		s1 =  read_line_params(n); // retourne(par exemple): [couleur_fond]<267> 

		//valeur = extract_params(s1, "frequence");
		//if(valeur != -1) {frequence = valeur;}

		valeur = extract_params(s1, "Ax");
		if(valeur != -1) {A.x = valeur;}

		valeur = extract_params(s1, "Ay");
		if(valeur != -1) {A.y = valeur;}

		valeur = extract_params(s1, "Bx");
		if(valeur != -1) {B.x = valeur;}

		valeur = extract_params(s1, "By");
		if(valeur != -1) {B.y = valeur;}

		n++;
	}
}


void affi_mode()
{
	TFT.setFreeFont(FF0);
	if (out_mode1 == MODE_9850)
	{
		TFT.setTextColor(VERT, NOIR);
		TFT.drawString("AD9850 ", 20, 3);
	}
	if (out_mode1 == MODE_4351)
	{
		TFT.setTextColor(CYAN, NOIR);
		TFT.drawString("ADF4351", 20, 3);
	}

	TFT.setFreeFont(FF1);

	if (out_mode1 != memo_out_mode1)
	{
		if(f_mode1 == MODE_GENE)  { affi_boutons_gene(); }
		if(f_mode1 == MODE_WOBU)  { affi_select_PAS(); }
	}	
	memo_out_mode1 = out_mode1;
}


void efface_grand_cadre() // en épargnant la bande des boutons (1M..100k..10k..1HZ)
{
	TFT.fillRect(1, 80, 317, 159, NOIR);
}


void trace_sinusoide()
{
	float y;
	float v;
	for (uint16_t n=0; n<320; n++)
	{
		v = (float)n/20.0;
		y = 180-50*sin(v);
		TFT.drawPixel(n, (int)y, VERT);
	}
}	


void setup()
{
	if (soft_setup == false)
	{
		soft_setup = true;
	// étalonnage touch screen;  ces valeurs peuvent varier d'un afficheur à l'autre
	// pour l'instant il faut les fixer ici à la main...
		eTS.x0 = -30;	eTS.y0 = -30;
		eTS.dx =  11;	eTS.dy =  14;

		Serial.begin(115200);
		delay(20);
		Serial.println("setup A"); 

		pinMode(boutonPin1, INPUT_PULLUP); // bouton physique

		pinMode(ADF_CLK, OUTPUT);
		pinMode(ADF_DATA, OUTPUT);
		pinMode(ADF_LE, OUTPUT);
		pinMode(ADF_CE, OUTPUT);

		pinMode(AD_WCL, OUTPUT);
		pinMode(AD_D7, OUTPUT);
		pinMode(AD_FQU, OUTPUT);
		pinMode(AD_RESET, OUTPUT);

		//pinMode(GPIO_BL, OUTPUT);
		//digitalWrite(GPIO_BL, HIGH); 

		init_variables_globales();

		Wire.begin(GPIO_SDA, GPIO_SCL, 2000000); 
		//Tuner_Init(tuner_init_tab9216);
		//affiche_frequence(frequence);

		// Start the SPI for the touch screen and init the TS library
		mySpi.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS); 
		ts.begin(mySpi);
		ts.setRotation(3);


	// mySpi2 -> pour le lecteur de SDcard
	// mySpi2 -> partage du bus SPI - mêmes valeurs de GPIO (sck=14, miso=12)	
	// que pour l'afficheur ILI9341 , sauf CS=5. Voir sur le schéma ainsi que le fichier User_Setup.h 
		mySpi2.begin(14, 12, 13, 5); 

		init_SDcard();
		delay(20);

		if (SDcardOk == true) 
		{ 
			read_params(); // sur la SDcard
		}

		TFT.init();
		TFT.setRotation(3); // 0..3 à voir, suivant disposition de l'afficheur
		TFT.fillScreen(VERT);

		init_sprites();

		affi_page_info();
		delay(300);

	//	TS_calibrate();

		// si les coordonnées des points de calibrage sont aux fraises...
		if ( (A.x <300) || (A.x >700) || (A.y <200) || (A.y >600) || 
		(B.x < 3500) || (B.x > 3900) || (B.y <3400) || (A.y >3800) )
		{
			TS_calibrate();
		}

		out_mode1 = MODE_9850;
		style = 0;
		frequence = 4000000;
	}

	Serial.println("setup B"); 

	init_affichages();
	affi_image_from_SD("/scope2.bmp", 0, 90);
	affiche_frequence(frequence); // et met à jour Fd0
	delay(500);
	
	//f_mode1 = MODE_ACCUEIL;
	efface_grand_cadre(); // grand cadre en partie basse
	
	chf_pad1.init();

	CarteADF4351.init();
	CarteADF4351.mute(0);

	CarteAD9850.reset();
	delay(10);
	CarteAD9850.out_F(10000.0);

	init_boutons_choix_MODE();
	bt_mode_GENE.selected = true;
	bt_mode_GENE.affiche(NOIR, JAUNE, 2);
	f_mode1 = MODE_GENE;

	bt_mode_WOBU.selected = false; // l'autre bouton
	bt_mode_WOBU.affiche(NOIR, GRIS_4, 2);
	

	affiche_frequence(frequence);
	
	efface_grand_cadre();

	affi_mode();
	trace_sinusoide();
	init_boutons_choix_MODULE();

/*	
	for(int n=0; n<21; n++)
	{
		uint64_t v = calcul_pas_w(n);
		Serial.println(v);  // pour test
	}
*/	

	Serial.println("Fin du Setup"); 
	Serial.println("-----------------------");

}


void get_XY_touch() // pour affi 320 x 240px
{
	TS_Point p = ts.getPoint();
	float dx = B.x - A.x;
	float ech_x = 290.0 / dx;//300
	float x0 = A.x;

	float dy = B.y - A.y;
	float ech_y = 210.0 / dy; //230
	float y0 = A.y;

	memo_x_touch = x_touch;
	memo_y_touch = y_touch;

	x_touch = 12 + uint16_t( (p.x - x0) * ech_x); //x_touch = 10 + uint16_t( (p.x - x0) * ech_x); 
	if(x_touch > 319){x_touch = 0;}
	y_touch = 15 + uint16_t( (p.y - y0) * ech_y);  //y_touch = 10 + uint16_t( (p.y - y0) * ech_y); 
	if(y_touch > 239){y_touch = 0;} 
}


void test_clic_boutons(TOUCH_BOUTON *bouton_i)
{
	uint16_t c1 = NOIR;
	uint16_t c2 = VERT;

 	if ((x_touch > bouton_i->x0) && (x_touch < (bouton_i->x0 )+ bouton_i->read_dx()) 
	&& ( y_touch > ((bouton_i->y0)) ) && (y_touch < ((bouton_i->y0) + (bouton_i->read_dy())) ) ) 
	{
		bouton_i->cliked = true;
		bouton_i->selected = true;
		//bouton_i->affiche(BLANC, c2, 1);
		delay(100);
	} 
}


int test_clic_boutons_inc_dec() // boutons placés derrière les chiffres de la fréquence
{
	int8_t num_bouton = -1;
	uint64_t facteur;

	TOUCH_BOUTON  bt_Hi, bt_Li;
	for(uint8_t n=0; n<10; n++)
	{
		bt_Hi = chf_pad1.bt_pad_H[n];
		test_clic_boutons(&bt_Hi); 
		if(bt_Hi.cliked) { num_bouton = n; }

		bt_Li = chf_pad1.bt_pad_L[n];
		test_clic_boutons(&bt_Li); 
		if(bt_Li.cliked) { num_bouton = n+10; }
	}

	if(num_bouton != -1)
	{	
		if (num_bouton<10)	
		{
			facteur = pow(10, 9-num_bouton);
			frequence += facteur;
		}
		if ((num_bouton>=10) && (num_bouton<20))
		{
			facteur = pow(10, 19-num_bouton);
			if (frequence > facteur) {frequence -= facteur;}
			else {frequence = 1;}
		}

		if (frequence == 0) {frequence = 1;}	
		//if (frequence > 4400000000) {frequence = 4400000000;}

		if (out_mode1 == MODE_9850)
		{
			if (frequence < F_min_AD9850) {frequence = F_min_AD9850;}
			if (frequence > F_max_AD9850) {frequence = F_max_AD9850;} // au delà le signal est possible, mais très dégradé !
		}

		if (out_mode1 == MODE_4351)
		{
			if (frequence < F_min_ADF4351) {frequence = F_min_ADF4351;}
			if (frequence > F_max_ADF4351) {frequence = F_max_ADF4351;}
		}

		affiche_frequence(frequence);		
		delay(100);
	}
	return num_bouton;
}



void draw_AEC(uint16_t x0, uint16_t y0, uint16_t L, uint8_t sens)
{
// ligne arc-en-ciel	
// affiche une ligne de pixels colorés à partir de la variable 'couleurs_aec' mémorisée en PROGMEM (voir fichier Couleurs_AEC.h)
// L = longueur de la ligne

//Serial.println("draw_draw_AEC()");
	uint16_t x, i, j;
	uint16_t y1;
	uint16_t couleur_i;

	for (int16_t i=0; i<L; i++)
	{
		float f = 470.0/L * i; // pour balayer toute l'échelle des couleurs disponibles
		j=uint16_t(f);
		
		couleur_i = couleurs_aec[2*j] | couleurs_aec[2*j+1]<<8;

		if (sens==0){x=i;} else {x=L-i;}

		TFT.drawFastVLine(x0+x, y0, 20, couleur_i);

	}
}

void test_clic_bts_choix_module()  // AD9850  - ADF4351
{
	test_clic_boutons(&bt_AD9850); 
	if (bt_AD9850.cliked) 
	{
		bt_AD9850.cliked = false;
		bt_AD9850.affiche(BLANC, VERT_2, 2);

		bt_ADF4351.selected = false; // l'autre bouton
		bt_ADF4351.affiche(BLANC, VERT_2, 2);
	
		out_mode1 = MODE_9850;
		style = 0;
		frequence = 4000000;
		affiche_frequence(frequence);

		affi_boutons_gene();
		f_mode1 = MODE_GENE;
	}

	test_clic_boutons(&bt_ADF4351); 
	if (bt_ADF4351.cliked) 
	{
		bt_ADF4351.cliked = false;
		bt_ADF4351.affiche(BLANC, BLEU, 2);

		bt_AD9850.selected = false; // l'autre bouton
		bt_AD9850.affiche(BLANC, VERT_2, 2);
			
		out_mode1 = MODE_4351;
		style = 1;
		frequence = 100000000;
		affiche_frequence(frequence);

		affi_boutons_gene();
		f_mode1 = MODE_GENE;
	}

}


void test_clic_bts_MODE()  // GENE - WOBU
{
	test_clic_boutons(&bt_mode_GENE); 
	if (bt_mode_GENE.cliked) 
	{
		bt_mode_GENE.cliked = false;
		bt_mode_GENE.affiche(NOIR, JAUNE, 2);

		bt_mode_WOBU.selected = false; // l'autre bouton
		bt_mode_WOBU.affiche(NOIR, GRIS_4, 2);
	
		f_mode1 = MODE_GENE;
		out_mode1 = MODE_9850;
		style = 0;
		frequence = 4000000;
		affiche_frequence(frequence);
		
		bt_mode_GENE.selected = true;
		bt_mode_GENE.affiche(NOIR, JAUNE, 2);
		affi_boutons_gene();
		efface_grand_cadre();
		init_boutons_choix_MODULE();
		TFT.drawRect(0, 0, 319, 240, BLANC); // cadre principal pourtour de l'écran
		bt_AD9850.selected=true;
		bt_AD9850.affiche(BLANC, VERT_2, 2);
	}


	test_clic_boutons(&bt_mode_WOBU); 
	if (bt_mode_WOBU.cliked) 
	{
		bt_mode_WOBU.cliked = false;
		bt_mode_WOBU.affiche(NOIR, JAUNE, 2);

		bt_mode_GENE.selected = false; // l'autre bouton
		bt_mode_GENE.affiche(NOIR, GRIS_4, 2);
			
		f_mode1 = MODE_WOBU;
		num_pas = 15;
		pas_W = calcul_pas_w(num_pas);

		affi_select_PAS();
		affi_grille();

		GO();
	}
	
}

void test_clic_bouton_RAZ()
{
	test_clic_boutons(&bt_RAZ ); 
	
	if (bt_RAZ.cliked) 
	{
		bt_RAZ.affiche(BLANC, ROUGE, 1);
		delay(50);
		bt_RAZ.cliked = false;
		bt_RAZ.selected = true;
		bt_RAZ.affiche(BLANC, ROUGE, 1);
	
		frequence =0;
		affiche_frequence(frequence);

		bt_RAZ.cliked = false;
		bt_RAZ.selected = false;
		bt_RAZ.affiche(BLANC, ROUGE, 1);

		delay(300);
		//init_affichages();
	}
}



void deselecte_bts_preset()
{
	if (out_mode1 == MODE_9850)
	{
		bt_455k.selected = false; 	bt_455k.affiche(BLANC, VERT, 1);
		bt_4M.selected = false; 	bt_4M.affiche(BLANC, VERT, 1);
		bt_10_7M.selected = false; 	bt_10_7M.affiche(BLANC, VERT, 1);
		bt_27M.selected = false; 	bt_27M.affiche(BLANC, VERT, 1);
	}

	if (out_mode1 == MODE_4351)
	{
		bt_35M.selected = false; 	bt_35M.affiche(BLANC, VERT, 1);
		bt_41M.selected = false; 	bt_41M.affiche(BLANC, VERT, 1);
		bt_144M.selected = false; 	bt_144M.affiche(BLANC, VERT, 1);
		bt_432M.selected = false; 	bt_432M.affiche(BLANC, VERT, 1);
		bt_2400M.selected = false; 	bt_2400M.affiche(BLANC, VERT, 1);
	}
}


void test_clic_bt_455k()
{
	test_clic_boutons(&bt_455k); 
	if (bt_455k.cliked) 
	{
		deselecte_bts_preset();
		bt_455k.cliked = false;
		bt_455k.selected=true;
		bt_455k.affiche(BLANC, VERT, 1);
		frequence =455000;
		affiche_frequence(frequence);
		delay(300);
	}
}

void test_clic_bt_4M()
{
	test_clic_boutons(&bt_4M); 
	if (bt_4M.cliked) 
	{
		deselecte_bts_preset();
		bt_4M.cliked = false;
		bt_4M.selected=true;
		bt_4M.affiche(BLANC, VERT, 1);
		frequence =4000000;
		affiche_frequence(frequence);
		delay(300);
	}
}

void test_clic_bt_10_7M()
{
	test_clic_boutons(&bt_10_7M); 
	if (bt_10_7M.cliked) 
	{
		deselecte_bts_preset();
		bt_10_7M.cliked = false;
		bt_10_7M.selected=true;
		bt_10_7M.affiche(BLANC, VERT, 1);
		frequence =10700000;
		affiche_frequence(frequence);
		delay(300);
	}
}

void test_clic_bt_27M()
{
	test_clic_boutons(&bt_27M); 
	if (bt_27M.cliked) 
	{
		deselecte_bts_preset();
		bt_27M.cliked = false;
		bt_27M.selected=true;
		bt_27M.affiche(BLANC, VERT, 1);
		frequence =27000000;
		affiche_frequence(frequence);
		delay(300);
	}
}


void test_clic_bt_35M()
{
	test_clic_boutons(&bt_35M); 
	if (bt_35M.cliked) 
	{
		deselecte_bts_preset();
		bt_35M.cliked = false;
		bt_35M.selected=true;
		bt_35M.affiche(BLANC, VERT, 1);
		frequence =35000000;
		affiche_frequence(frequence);
		delay(300);
	}
}


void test_clic_bt_41M()
{
	test_clic_boutons(&bt_41M); 
	if (bt_41M.cliked) 
	{
		deselecte_bts_preset();
		bt_41M.cliked = false;
		bt_41M.selected=true;
		bt_41M.affiche(BLANC, VERT, 1);
		frequence =41000000;
		affiche_frequence(frequence);
		delay(300);
	}
}


void test_clic_bt_144M()
{
	test_clic_boutons(&bt_144M); 
	if (bt_144M.cliked) 
	{
		deselecte_bts_preset();
		bt_144M.cliked = false;
		bt_144M.selected=true;
		bt_144M.affiche(BLANC, VERT, 1);
		frequence =144000000;
		affiche_frequence(frequence);
		delay(300);
	}
}


void test_clic_bt_432M()
{
	test_clic_boutons(&bt_432M); 
	if (bt_432M.cliked) 
	{
		deselecte_bts_preset();
		bt_432M.cliked = false;
		bt_432M.selected=true;
		bt_432M.affiche(BLANC, VERT, 1);
		frequence =432000000;
		affiche_frequence(frequence);
		delay(300);
	}
}

void test_clic_bt_2400M()
{
	test_clic_boutons(&bt_2400M); 
	if (bt_2400M.cliked) 
	{
		deselecte_bts_preset();
		bt_2400M.cliked = false;
		bt_2400M.selected=true;
		bt_2400M.affiche(BLANC, VERT, 1);
		frequence =2400000000;
		affiche_frequence(frequence);
		delay(200);
	}
}



void affi_pasW()
{
	String s1 = formatage_frq(pas_W); // ajoute les points (.) séparateurs des milliers
	String s2 = supp_zeros(s1);

	TFT.fillRect(130, 63, 120, 12, NOIR); // efface
	TFT.setFreeFont(FF1);	
	TFT.setTextColor(JAUNE);
	TFT.drawString("P=" + s2, 130, 63);
}

/*
void calcul_Fmin_Fmax()
{
	Fmin = frequence - 160 * pas_W;
	Fmax = frequence + 160 * pas_W;
}
*/

void test_clic_bt_pas_P()
{
	test_clic_boutons(&bt_pas_P); 
	if (bt_pas_P.cliked) 
	{
		bt_pas_P.cliked = false;

		if (num_pas>0) {num_pas --;}

		pas_W = calcul_pas_w(num_pas);
		affi_pasW();

		calcul_Fmin_Fmax(frequence);
		affi_freq_W_min_max();
		delay(200);
	}
}




void test_clic_bt_pas_M()
{
	test_clic_boutons(&bt_pas_M); 
	if (bt_pas_M.cliked) 
	{
		bt_pas_M.cliked = false;
		
		num_pas ++;
		if (num_pas>20) {num_pas = 20;}

		pas_W = calcul_pas_w(num_pas);
		affi_pasW();	

		calcul_Fmin_Fmax(frequence);
		affi_freq_W_min_max();
		delay(300);
	}
}


void affi_trace_passe_bas()
{
// (Filtre passe-bas de second ordre RLC) pour exemple...
// https://www.silicium628.fr/article_i.php?id=112
	float d1, d2,d3, T;
	float x = 5;
	float m=0.25;

	for(int n=0; n<800; n++)
	{
		x= n/100.0;
		d1 = 1 - x*x;
		d2 = 2*m*x;
		d3 = d1*d1 + d2*d2;
		T = 1/sqrt(d3);
		uint16_t y = int(70.0 *T);
		TFT.drawPixel(n, 240-y, BLEU);
	}
}


String formatage_frq(uint64_t frq_i) // ajoute les points (.) séparateurs des milliers
{
	String s1 = String(frq_i);
	s1 = "000000000" + s1;
	uint8_t L= s1.length();
	String sU = s1.substring(L-3); 		// Hz
	String sK = s1.substring(L-6, L-3); // kHz
	String sM = s1.substring(L-10, L-6);// MHz
	return sM + "." + sK + "." + sU + " ";
}


String supp_zeros(String s_i) // supprime les zéros et les points de séparation des milliers non significatifs
{
	String s1;

	while (s_i.substring(0, 1) == "0") 	{s_i = s_i.substring(1); } 
	if(s_i[0] == '.') {s_i = s_i.substring(1); } 
	while (s_i.substring(0, 1) == "0") 	{s_i = s_i.substring(1); } 
	if(s_i[0] == '.') {s_i = s_i.substring(1); } 
	while (s_i.substring(0, 1) == "0") 	{s_i = s_i.substring(1); } 
	return s_i;
}


void affi_freq_W_min_max() // et les affiche verticalement
{
	// la réquence centrale est celle choisie et affichée en gros chiffres en haut
	String Str_frq;
	
	Str_frq = formatage_frq(Fmin);
	TFT.fillRect(6, 150, 8, 89, NOIR); // efface
	sprite_freq_W_min.drawString(Str_frq, 0, 0);
	TFT.setPivot(10, 190);
	sprite_freq_W_min.pushRotated(-90, NOIR);

	TFT.fillRect(305, 150, 8, 89, NOIR); // efface
	Str_frq = formatage_frq(Fmax);	
	sprite_freq_W_max.drawString(Str_frq, 0, 0);
	TFT.setPivot(310, 190);
	sprite_freq_W_max.pushRotated(-90, NOIR);
}




void boucle_affi_curseur()
{
// dessine un trait vertical au point cliqué par le stylet
	if (pas_W==0) {return;}
	if(f_mode1 != MODE_WOBU) {return;}

	efface_bande_boutons();
	TFT.setFreeFont(FF1);	
	//TFT.setTextColor(BLEU_CLAIR);
	TFT.setTextColor(BLANC, NOIR);
	TFT.drawString("parcourir au stylet <>", 2, 64);

	init_1_bouton(1, 300, 63, 15, 16, "X", &bt_STOP_2);
	bt_STOP_2.selected = true;
	bt_STOP_2.affiche(BLANC, ROUGE, 2);

	uint16_t memo_seg_V[100]= {0};
	uint16_t memo_x;
	int64_t frq_i, memo_frq_i;

	TFT.setFreeFont(FM9);
	TFT.setTextColor(BLEU_CLAIR, NOIR);

	uint16_t couleur1 = JAUNE;
	boolean stop2 = false;
	while (! stop2)
	{
		if (ts.tirqTouched() && ts.touched()) 
		{
			memo_x = x_touch;
			get_XY_touch();

			if ((x_touch>15)&&(x_touch<300) && (memo_x>15) && (memo_x<300) && (y_touch > 80))	
			{
				TFT.pushRect(memo_x, 120, 1, 100, memo_seg_V); // efface avec l'image enregistrée			
				TFT.readRect(x_touch, 120, 1, 100, memo_seg_V); // memorise image avant de tracer le trait
				if ((x_touch>18)&&(x_touch<296)) {TFT.drawFastVLine(x_touch, 120, 100, BLEU_CLAIR);}

				String s1;
				memo_frq_i = frq_i;

				frq_i = frequence - 160*pas_W + x_touch * pas_W;

				if (frq_i != memo_frq_i)
				{
					if(frq_i==0) {couleur1 = ROUGE;} else couleur1 = JAUNE;
					s1 = formatage_frq(frq_i) + " Hz ";
					TFT.drawString(s1, 80, 82);
					//delay(5);
				}
			}
			test_clic_boutons(&bt_STOP_2 ); 
			if (bt_STOP_2.cliked) 
			{
				bt_STOP_2.cliked = false;
				stop2 = true;
				efface_bande_boutons();
			}
		}
		test_bouton_physique1();
	}
	TFT.setFreeFont(FF1);	
	TFT.setTextColor(VERT, GRIS_6);
	TFT.drawString("Choisir GENE ou WOBU" ,50, 150);

	//setup();
}


void affiche_gain(float gain)
{
	TFT.fillRect(175, 80, 45, 15, NOIR); // efface
	TFT.setFreeFont(FF1);	
	TFT.setTextColor(BLEU_CLAIR);
	TFT.drawString("gain=" +String(gain), 120, 80);
}


void calcul_Fmin_Fmax(uint64_t Fi)
{
	if(Fi > 160*pas_W)	{Fmin = Fi - 160*pas_W;} else Fmin = 0;
	Fmax = Fi + 160 * pas_W;
}


void balayage_freq(uint64_t F0)  // wobulation "autour" de la fréquence centrale F0
{
	compte1++;
	Serial.print("compte1="); Serial.println(compte1);

	if ((pas_W == 0) || (f_mode1 != MODE_WOBU))
	{
		stop1 = true;
		return;
	}
	
	uint16_t memo_seg_V[100]= {0};
	int16_t memo_n;

	TFT.setFreeFont(FM9);
	TFT.setTextColor(BLEU_CLAIR, NOIR);

	uint16_t couleur1 = JAUNE;
	
	uint16_t valeurLue1 = 230;
	uint16_t valeurLue2 = 230;
	uint16_t valeurLue3 = 230;

	float gain=0.3;
	float memo_gain;
	float vf;

	uint64_t frq_i; // peut-être négatif

	uint16_t v1;
	uint16_t memo_v1;
	uint16_t x;

	TFT.setFreeFont(FF1);
	TFT.drawString("gain :" +String(gain), 170, 120);

	stop1 = false;
	while (! stop1)
	{
		calcul_Fmin_Fmax(F0);

		compte2++;
		Serial.print("compte2="); Serial.println(compte2);
		//TFT.fillRect(1, 80, 317, 159, NOIR);
		//calcul_Fmin_Fcenter(F0);

		TFT.setFreeFont(FF1);	
		TFT.setTextColor(BLANC, NOIR);
		TFT.drawString("F0", 150, 220);

		x=1;
		for(uint16_t n=0; n<320; n++)
		{
			x++;
			//Fmax = F0 + 160 * pas_W;
			//frq_i = F0 + n * pas_W;

			if(n<160){frq_i  = F0 - (160-n) * pas_W;}
			if(n>=160){frq_i = F0 + (n-160) * pas_W;}

			frequence = frq_i;	

			out_frequence();
			delay(1);
			memo_v1 = v1;
			valeurLue1 = analogRead(analogPin); //acquisition_réponse   0..4095 
			delay(1);
			valeurLue2 = analogRead(analogPin); 
			delay(1);
			valeurLue3 = analogRead(analogPin); 

			v1 = (valeurLue1 + valeurLue2 + valeurLue3)/3; // moyenne des trois acquisitions successives
			vf = (float (valeurLue1) + float (valeurLue2) + float (valeurLue3))/3.0; 

			v1 /= 2; // 4 réglage du gain 

			vf *= gain; // 4 réglage du gain 
			//vf /=4.0;
			v1 = uint16_t(vf);

			if (v1 > 230-100) // écrétage de l'affichage (partie haute)
			{
				v1 = 230-100; 
				gain -= 0.01; // ajuste le gain
			}  

			if ((x>15) && (x<300) )//&& (memo_n>15) && (memo_n<300))	à voir
			{
				TFT.drawFastVLine(x, 100, 131, NOIR); // efface
				TFT.drawFastVLine(160, 100, 139, 10976); // trait vertical au centre (F0)
				if (n%10 == 0) { TFT.drawFastVLine(n, 220, 19, 10976); }// petits traits verticaux en bas	
				uint16_t y1, y2;

				if (polarite1 == _DIR) {y1 =  230 - memo_v1;  y2 = 230 - v1;} 
				else {y1 = 90 + memo_v1;  y2 = 90 + v1;}

				if(y1 < 100) {y1=100;}
				if(y2 < 100) {y2=100;}
				TFT.drawLine(x-1, y1, x, y2, couleur1); // trait entre [P(n-1)] et [P(n)] ...(signal)
			}	

			memo_n=n;

			if (ts.tirqTouched() && ts.touched()) 
			{
				memo_y_touch = y_touch;
				get_XY_touch();

				frequence = F0; // sinon le calcul des F min et max sera faux
				
				int num_bouton = test_clic_boutons_inc_dec();  // on peut changer la Freq centrale pendant le balayage
				if (num_bouton != -1) {F0 = frequence;}

				//test_clic_bts_pas(); // on peut changer le pas pendant le balayage

				bt_polarite.cliked = false;
				test_clic_boutons(&bt_polarite ); 
				if (bt_polarite.cliked) 
				{
					bt_polarite.cliked = false;
					if (polarite1 == _DIR) { polarite1 = _INV; bt_polarite.label = "INV"; bt_polarite.affiche(BLANC, ROUGE, 1); } 
					else { polarite1 = _DIR; bt_polarite.label = "DIR"; bt_polarite.affiche(NOIR, VERT, 1); }
					delay(300);
				}

				
				bt_gain_P.cliked = false;
				test_clic_boutons(&bt_gain_P ); 
				if (bt_gain_P.cliked) 
				{
					bt_gain_P.cliked = false;
					gain +=0.01;
					if (gain <0.1) {gain = 0.1;}
					TFT.drawString("gain=" +String(gain), 120, 80); 
					affiche_gain(gain);
					delay(100);			
				}

				bt_gain_M.cliked = false;
				test_clic_boutons(&bt_gain_M ); 
				if (bt_gain_M.cliked) 
				{
					bt_gain_M.cliked = false;
					gain -= 0.01;
					if (gain >1.0) {gain = 1.0;}
					affiche_gain(gain);
					delay(100);	
				}

				test_clic_bt_pas_P();
				test_clic_bt_pas_M();

				bt_STOP_1.cliked = false;
				test_clic_boutons(&bt_STOP_1 ); 
				if (bt_STOP_1.cliked) 
				{
					bt_STOP_1.cliked = false;
					bt_STOP_1.label = "";
					bt_STOP_1.affiche(NOIR, NOIR, 2); // fait disparaitre le bouton de l'affichage
					stop1 = true;
					break;
				}
			}
			if(gain != memo_gain) { affiche_gain(gain); memo_gain = gain;}
			test_bouton_physique1();

		}
	}
	frequence = F0;
}



void GO()
{
	//if (pas_W == 0) {return;}
	bt_STOP_1.label = "X";
	bt_STOP_1.affiche(BLANC, ROUGE, 2);
	delay(100); // évite de redéclencher le bouton intempestivement
	TFT.fillRect(6, 82, 150, 10, NOIR); // efface le texte "Choisir un pas"
	affi_freq_W_min_max();  	// affiche verticalement
	balayage_freq(frequence);   // wobulation "autour" de la fréquence centrale F0
}


void affi_grille()
{
	efface_grand_cadre();
	TFT.drawFastVLine(160, 100, 139, 10976);
	for (int n =1; n<32; n++)
	{
		TFT.drawFastVLine(10*n, 220, 19, 10976);	
	}

	TFT.drawFastHLine(1, 231, 318, GRIS_6); // zero en bas
	TFT.drawFastHLine(1, 98, 318, GRIS_6);  // max en haut

	init_1_bouton(1, 300, 82, 15, 15, "X", &bt_STOP_1);
	bt_STOP_1.selected = true;
	bt_STOP_1.affiche(BLANC, ROUGE, 2);

	init_1_bouton(1, 230, 82, 30, 15, "DIR", &bt_polarite);
	bt_polarite.selected = true;
	bt_polarite.affiche(NOIR, VERT, 1);

	init_1_bouton(1, 300, 100, 15, 15, "+", &bt_gain_P);
	bt_gain_P.selected = true;
	bt_gain_P.affiche(NOIR, BLEU_CLAIR, 1);

	init_1_bouton(1, 300, 120, 15, 15, "-", &bt_gain_M);
	bt_gain_M.selected = true;
	bt_gain_M.affiche(NOIR, BLEU_CLAIR, 1);

/*
	if(le_pas_est_choisi == false)
	{	
		TFT.setFreeFont(FF1);
		TFT.setTextColor(BLANC, ROUGE);
		TFT.drawString("Choisir un pas", 80, 150);
	}
*/
}



void test_clic_bouton_TEST()
{
	test_clic_boutons(&bt_TEST ); 
	
	if (bt_TEST.cliked) 
	{
		bt_TEST.affiche(BLANC, ROUGE, 1);
		delay(10);
		Serial.println("-------------------------------");
		Serial.println("bt_TEST.cliked");
		bt_TEST.cliked = false;
		bt_TEST.selected = true;
		bt_TEST.affiche(BLANC, ROUGE, 1);
	
		//affi_nuances_de_gris();
		TS_calibrate();
		
		//TFT.fillScreen(NOIR); // effface
		//draw_AEC(0, 100, 320, 1);
		//delay(300);

		bt_TEST.cliked = false;
		bt_TEST.selected = false;
		bt_TEST.affiche(BLANC, ROUGE, 1);

		//init_affichages();
		//affiche_frequence(frequence);
		//affiche_frequence(1);
	}
}

double nb=0;


void test_clic_bts_preset()
{
	if(f_mode1 == MODE_WOBU) {return;}

	if (out_mode1 == MODE_9850)
	{			
		test_clic_bt_455k();
		test_clic_bt_4M();
		test_clic_bt_10_7M();
		test_clic_bt_27M();
	}
	if(out_mode1 == MODE_4351)
	{		
		test_clic_bt_35M();
		test_clic_bt_41M();
		test_clic_bt_144M();
		test_clic_bt_432M();
		test_clic_bt_2400M();
	}
}



void loop() 
{
	if (ts.tirqTouched() && ts.touched()) 
	{
		memo_y_touch = y_touch;
		get_XY_touch();

		test_clic_boutons_inc_dec();
		test_clic_bouton_RAZ();

		if((f_mode1 == MODE_ACCUEIL) || (f_mode1 == MODE_GENE))
		{		
			test_clic_bts_choix_module();
		}
		if(f_mode1 == MODE_GENE) { test_clic_bts_preset(); } 
		if(f_mode1 == MODE_WOBU)
		{
			test_clic_bt_pas_M();
			test_clic_bt_pas_P();
		}

		//if(f_mode1 == MODE_WOBU) { test_clic_bts_pas(); }
		test_clic_bts_MODE();
		
		if(stop1 == true) 
		{
			stop1= false;
			boucle_affi_curseur();
		}
	}

	test_bouton_physique1();

	delay(20); //20

	// uint16_t valeurLue1 = analogRead(analogPin);
	// frequence = valeurLue1;
	// //Serial.println(valeurLue1);
	// affiche_frequence(frequence);
	
}


/** ***************************************************************************************
	CLASS TOUCH_BOUTON  // affiche un nombre ou un petit texte dans un rectangle
	ainsi que (en plus petit) deux valeurs supplémentaires, par ex: les valeurs mini et maxi					
********************************************************************************************/

// Constructeur
TOUCH_BOUTON::TOUCH_BOUTON()
{

}




void TOUCH_BOUTON::init(uint16_t x_i, uint16_t y_i, uint8_t dx_i, uint8_t dy_i, uint8_t dr_i, uint16_t couleur_i)
{
	x0 = x_i;
	y0 = y_i;
	dx = dx_i;
	dy = dy_i;
	dr = dr_i;
	couleur = couleur_i;

	cliked = false;
	selected = false;
}



void TOUCH_BOUTON::affiche(uint16_t coul_txt, uint16_t coul_fill_select, uint8_t n_font)
{
	uint16_t couleur_contour = GRIS_5;

	TFT.setTextColor(coul_txt);

	if(selected) 
	{
		TFT.fillRoundRect(x0, y0, dx, dy, dr, coul_fill_select);
	}  
	else 
	{
		TFT.fillRoundRect(x0, y0, dx, dy, dr, couleur); // efface
		TFT.drawRoundRect(x0, y0, dx, dy, dr, couleur_contour); // retrace juste le contour
	}

	//FM9 FMB9 FSS9... voir le fichier FrSD_Fonts.h
	if (n_font == 1) { TFT.setFreeFont(FF0);}
	if (n_font == 2) { TFT.setFreeFont(FM9);}
	if (n_font == 3) { TFT.setFreeFont(FMB9);}
	if (n_font == 4) { TFT.setFreeFont(FSS9);} 

	TFT.drawString(label, x0+3, y0 - (2*n_font) + (dy-4)/2);
}


uint8_t TOUCH_BOUTON::read_dx()
{
	return dx;
}


uint8_t TOUCH_BOUTON::read_dy()
{
	return dy;
}


/** ***************************************************************************************
	CLASS CHF_PAD  // boutons invisibles pour incrémenter/décrémenter les chiffres de la fréquence
********************************************************************************************/
// Constructeur
CHF_PAD::CHF_PAD()
{

}

void CHF_PAD::init()
{
	for(uint8_t n=0; n<=9; n++) // 1 9
	{
		bt_pad_H[n].init(x_ch[n], 16, 25, 22, 3, GRIS_3); //18
		//bt_pad_H[n].affiche(BLANC, VERT, 1);  // pour visualiser la position des boutons

		bt_pad_L[n].init(x_ch[n], 38, 25, 22, 3, GRIS_3); //40
		//bt_pad_L[n].affiche(BLANC, ROUGE, 1);
	}

}

