/* ************************************************************************************
pour ESP32 WROOM, afficheur TFT ILI9341 & lecteur SDcard
par Silicium628
************************************************************************************ */

#include <Arduino.h>
#include "main.h"
#include "constantes2_628.h"

String version = "1.2";

#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 <XPT2046_Touchscreen.h>

#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

//#define SD_MISO 12 
//#define SD_MOSI 13
//#define SD_SCLK 14
//#define SD_CS   5  // Chip select control pin

const int GPIO_SDA = 27; 
const int GPIO_SCL = 22; 

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

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

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

SPIClass mySpi2 = SPIClass(HSPI);

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

ETALON_TS eTS;
uint16_t x_touch, y_touch;

TOUCH_BOUTON bt_test1;
TOUCH_BOUTON bt_test2;
TOUCH_BOUTON bt_test3;
TOUCH_BOUTON bt_test_TS; // TouchScreen
TOUCH_BOUTON bt_stop;

uint8_t SDcardOk=0;
boolean stop = false;


void printTouchToDisplay() // pour TEST
{
	TFT.fillScreen(NOIR);

	TFT.setFreeFont(FM9);
	TFT.setTextColor(BLEU_CLAIR, NOIR);
	TFT.drawString("TEST TOUCH screen", 80, 120);
	TFT.drawString("dessinez avec le stylet", 60, 140);

	init_1_bouton(230, 50, 70, 20, "stop", &bt_stop);
  	bt_stop.affiche(GRIS_3, VERT, 2);

	while(! stop)
	{
		if (ts.tirqTouched() && ts.touched()) 
		{
			TS_Point p = ts.getPoint();

			x_touch = eTS.x0 + p.x /eTS.dx;
			y_touch = eTS.y0 + p.y /eTS.dy;

			TFT.drawRect(x_touch, y_touch, 1, 1, JAUNE);
		}
		test_clic_bt_stop();
	} 
	init_affichages();
} 


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

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

    if(cardType == CARD_NONE)
    {
		Serial.println("NO SDcard"); 
        return;
    }

    SDcardOk=1;

	Serial.print("SDcard Type: "); Serial.println();
	if(cardType == CARD_SD) {Serial.println("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
}


void init_1_bouton(uint16_t xi, uint16_t yi, uint8_t dx, uint8_t dy, String si, TOUCH_BOUTON *bouton_i)
{
	uint16_t c1 = GRIS_3;
	uint16_t c2 = BLANC;

	bouton_i->init(xi, yi, dx, dy, 3);
	bouton_i->cliked = false;
	bouton_i->selected = false;
	bouton_i->s = si;
	bouton_i->affiche(c1, c2, 1);
}


void init_affichages()
{
	TFT.fillRect(0, 14, 319, 230, NOIR);
	TFT.setTextColor(JAUNE, NOIR);

	TFT.drawRect(0, 0, 319, 240, VERT); // cadre principal pourtour de l'écran
	TFT.setFreeFont(FF0);
	TFT.setTextColor(BLANC, BLEU);
	String s1 = "v:" + version;
	TFT.drawString(s1, 45, 15);

  	init_1_bouton(200, 90, 50, 20, "img1", &bt_test1);
  	bt_test1.affiche(GRIS_3, VERT, 2);

	init_1_bouton(200, 120, 50, 20, "img2", &bt_test2);
  	bt_test2.affiche(GRIS_3, VERT, 2);

	init_1_bouton(200, 150, 50, 20, "img3", &bt_test3);
  	bt_test3.affiche(GRIS_3, VERT, 2);

	init_1_bouton(200, 180, 85, 20, "test TS", &bt_test_TS);
  	bt_test3.affiche(GRIS_3, VERT, 2);
}



void setup() 
{
// é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(100);

	//Wire.begin(GPIO_SDA, GPIO_SCL, 100000);

	// Start the SPI for the touch screen and init the TS library
	mySpi1.begin(XPT2046_CLK, XPT2046_MISO, XPT2046_MOSI, XPT2046_CS); 
	ts.begin(mySpi1);
	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); 

/* rappel: valeurs écrites dans le fichier 	User_Setup.h : 
concerne l'afficheur ILI9341
#define TFT_MISO 12 
#define TFT_MOSI 13
#define TFT_SCLK 14
#define TFT_CS   15  // Chip select control pin

En résumé, l'afficheur IL9341, et le lecteur de SDcad, partagent le même bus SPI, 
et se différencient par les broches CS (chip select)
ce qui est l'utilisation normale d'un bus SPI
*/
	init_SDcard();

	TFT.init();
	TFT.setRotation(3);
	TFT.fillScreen(NOIR);
	TFT.setTextColor(BLANC, NOIR);

	TFT.setFreeFont(FF0);
	uint16_t y=5;
	Serial.println("TEST ILI9341");
	delay(300);
	TFT.drawString("Test afficheur ILI9341", 5, y);

	y+=20;
	String s1="version " + version;
	TFT.drawString(s1, 0, y);
	y+=20;
	delay(300);

	init_affichages();

}


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

 	if ((x_touch > bouton_i->x0) && (x_touch < bouton_i->x0 + bouton_i->read_dx()) 
	&& ( y_touch > bouton_i->y0-4) && (y_touch < bouton_i->y0-4 + bouton_i->read_dy()) ) 
	{
		bouton_i->cliked = true;
		bouton_i->selected = true;
		bouton_i->affiche(c1, c2, 2);
	} 
}

uint32_t bmp_offset = 0;
uint16_t bmp_width;
uint16_t bmp_heigh;


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); 
		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 test_clic_bouton_test1()
{
	test_clic_boutons(&bt_test1 ); 
	bt_test1.affiche(GRIS_3, VERT, 2);
	delay(100);
	if (bt_test1.cliked) 
	{
		Serial.println("-------------------------------");
		Serial.println("bt_test1.cliked");
		bt_test1.cliked = false;
		bt_test1.selected = true;
		bt_test1.affiche(GRIS_3, VERT, 2);;
	
		affi_image_from_SD("/bmp565/7.bmp", 0, 0); 
		
		bt_test1.cliked = false;
		bt_test1.selected = false;
		bt_test1.affiche(GRIS_3, VERT, 2);

		Serial.println("-------------------------------");
	}
}


void test_clic_bouton_test2()
{
	test_clic_boutons(&bt_test2 ); 
	bt_test2.affiche(GRIS_3, VERT, 2);
	delay(100);
	if (bt_test2.cliked) 
	{
		Serial.println("-------------------------------");
		Serial.println("bt_test2.cliked");
		bt_test2.cliked = false;
		bt_test2.selected = true;
		bt_test2.affiche(GRIS_3, VERT, 2);;
	
		affi_image_from_SD("/bmp565/avion1.bmp", 0, 0); 
		
		bt_test2.cliked = false;
		bt_test2.selected = false;
		bt_test2.affiche(GRIS_3, VERT, 2);

		Serial.println("-------------------------------");
	}
}


void test_clic_bouton_test3()
{
	test_clic_boutons(&bt_test3 ); 
	bt_test3.affiche(GRIS_3, VERT, 2);
	delay(100);
	if (bt_test3.cliked) 
	{
		Serial.println("-------------------------------");
		Serial.println("bt_test3.cliked");
		bt_test3.cliked = false;
		bt_test3.selected = true;
		bt_test3.affiche(GRIS_3, VERT, 2);;
	
		affi_image_from_SD("/bmp565/PFD.bmp", 50, 100);
		
		bt_test3.cliked = false;
		bt_test3.selected = false;
		bt_test3.affiche(GRIS_3, VERT, 2);

		Serial.println("-------------------------------");
	}
}


void test_clic_bt_stop()
{
	test_clic_boutons(&bt_stop ); 
	if (bt_stop.cliked) 
	{
		bt_stop.cliked = false;
		stop = true;
	}
}


void test_clic_bt_test_TS()
{
	test_clic_boutons(&bt_test_TS ); 
	bt_test_TS.affiche(GRIS_3, VERT, 2);
	delay(100);
	if (bt_test_TS.cliked) 
	{
		Serial.println("-------------------------------");
		Serial.println("bt_test3.cliked");
		bt_test_TS.cliked = false;
		bt_test_TS.selected = true;
		bt_test_TS.affiche(GRIS_3, VERT, 2);;
	
		stop = false;
		printTouchToDisplay();
		
		bt_test_TS.cliked = false;
		bt_test_TS.selected = false;
		bt_test_TS.affiche(GRIS_3, VERT, 2);

		Serial.println("-------------------------------");
	}
}


void loop() 
{
	if (ts.tirqTouched() && ts.touched()) 
	{
		TS_Point p = ts.getPoint();
		x_touch = eTS.x0 + p.x /eTS.dx;
		y_touch = eTS.y0 + p.y /eTS.dy;

		test_clic_bouton_test1();
		test_clic_bouton_test2();
		test_clic_bouton_test3();
		test_clic_bt_test_TS();
	}
}



/** ***************************************************************************************
	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 xi, uint16_t yi, uint8_t dxi, uint8_t dyi, uint8_t dri)
{
	x0 = xi;
	y0 = yi;
	dx = dxi;
	dy = dyi;
	dr = dri;

	cliked = false;
	selected = false;
}



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

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

	//FM9 FMB9 FSS9... voir le fichier FrSPIFFS_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(s, x0+3, y0 + 2);
}

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

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