//www.DFRobot.com
//last updated on 21/12/2011
//Tim Starling Fix the reset bug (Thanks Tim)
//wiki doc http://www.dfrobot.com/wiki/index.php?title=I2C/TWI_LCD1602_Module_(SKU:_DFR0063)
//Support Forum: http://www.dfrobot.com/forum/
//Compatible with the Arduino IDE 1.0
//Library version:1.1

/*  ╔════════════════════════════════════════════════════════════════════════════════════════════════════════════╗
    ║ Last updated on 19/10/2018 by Grosse Christophe (Technozone51) to support french accentuated characters    ║
    ║ Use custom character in CGRAM dynamicaly created as needed. So there is a limit of 8 different accentuated ║
    ║ characters who could be defined at the same time. after clearing the screen, the custom characters are     ║
    ║ deleted so you can use 8 different accentuated characters on the next screen.								 ║
	╚════════════════════════════════════════════════════════════════════════════════════════════════════════════╝
*/
#include "TZ51_LiquidCrystal_I2C.h"
#include <avr/pgmspace.h>
#include <inttypes.h>
#if defined(ARDUINO) && ARDUINO >= 100

#include "Arduino.h"

#define printIIC(args)	Wire.write(args)

const byte PROGMEM agrave[8] = {  B01000,  B00100,  B01110,  B00001,  B01111,  B10001,  B01111,  B00000};//{136,134,128,142,145,147,141,128};
const byte PROGMEM acirc[8] = {132,138,128,142,145,147,141,128};
const byte PROGMEM atilda[8] = {  B00101,  B01010,  B00000,  B01110,  B10001,  B10011,  B01101,  B00000};
const byte PROGMEM atrema[8] ={  B01010,  B00000,  B01110,  B00001,  B01111,  B10001,  B01111,  B00000};
const byte PROGMEM eaigu[8] = {130,132,142,145,159,144,142,128};
const byte PROGMEM egrave[8] = {136,132,142,145,159,144,142,128};
const byte PROGMEM ecirc[8] = {132,138,142,145,159,144,142,128};
const byte PROGMEM imajcirc[8] = {  B00100,  B01010,  B00000,  B01110,  B00100,  B00100,  B01110,  B00000};//{132,138,128,140,132,132,142,128};
const byte PROGMEM imajtrema[8] = {  B01010,  B00000,  B01110,  B00100,  B00100,  B00100,  B01110,  B00000};
const byte PROGMEM itrema[8] = {  B01010,  B00000,  B01100,  B00100,  B00100,  B00100,  B01110,  B00000};
const byte PROGMEM icirc[8] ={  B00100,  B01010,  B00000,  B01100,  B00100,  B00100,  B01110,  B00000};
const byte PROGMEM ocirc[8] = {132,138,128,142,145,145,142,128};
const byte PROGMEM ugrave[8] = {136,134,128,145,145,147,141,128};
const byte PROGMEM ucirc[8] = {132,138,128,145,145,147,141,128};
const byte PROGMEM utrema[8] ={  B00000,  B01010,  B00000,  B10001,  B10001,  B10011,  B01101,  B00000};
const byte PROGMEM ccedille[8] ={  B00000,  B01110,  B10001,  B10000,  B10000,  B01110,  B00100,  B01000};
const byte PROGMEM etrema[8] ={  B01010,  B00000,  B01110,  B10001,  B11111,  B10000,  B01110,  B00000};
const byte PROGMEM otrema[8] ={  B00000,  B01010,  B00000,  B01110,  B10001,  B10001,  B01110,  B00000};
const byte PROGMEM ntilda[8] ={  B00101,  B01010,  B00000,  B10111,  B11001,  B10001,  B10001,  B00000};
const byte PROGMEM euro[8] ={  B01110,  B10001,  B11100,  B10000,  B11100,  B10001,  B01110,  B00000};
const byte PROGMEM technozone[8] ={  B01110,  B11111,  B10101,  B11111,  B11111,  B01010,  B01110,  B00100};//{  B01110,  B11111,  B10101,  B11111,  B11111,  B11011,  B01110,  B00100};
const byte PROGMEM degre[8] ={  B00010,  B00101,  B00010,  B00000,  B00000,  B00000,  B00000,  B00000};
byte tempcar[8]={0,0,0,0,0,0,0,0};

void chargeCar_P(const byte tableau[]) {
  for (int i = 0; i < 8; i++) {
    tempcar[i] = pgm_read_byte(tableau + i); // Normalement on aurait fait tableau[i], mais pas ici vu que le tableau est marqué avec PROGMEM
	//Serial.print("ChargeCar ");
	//Serial.print(tempcar[i],DEC);
  }
}
										
uint8_t LiquidCrystal_I2C::substitute(uint8_t v) {
 Serial.print("in subtitute ");
 Serial.println(v,DEC);
 //test si un custom est déjà créé et si il y a de la place
 int index_available=-1;
 int index_ready=-1; 
 for (int i=0;i<8;i++) {
   //Serial.println("into for loop");
   //Serial.println(_custom[i],DEC);
   if (_custom[i]==v) {
	   index_ready=i;
   }
   if (_custom[i]==0) {
	   index_available=i;
   }
 }
 /*Serial.print("index_ready = ");
 Serial.println(index_ready,DEC);
 Serial.print("index_available = ");
 Serial.println(index_available,DEC);*/
 uint8_t value=32;
 if (index_ready!=-1) {
   //Si le custom est déjà créer; il suffit de renvoyer son index 
    //Serial.println("custom existant");
    return index_ready;
 } else {
   //Le custom n'existe pas encore il faut le créer si possible
   if (index_available!=-1) {
     //Il y a encore de la place pour créer le nouveau custom
	 Serial.println("creation nouveau custom");
	 Serial.println(_skipnext);
	 _increate=1;
	 switch(_skipnext) {
	  case 1 : {	 
		switch (v) {
		  //case 130 : chargeCar_P(euro);createChar(index_available,tempcar);break;//à
		  case 160 : chargeCar_P(agrave);createChar(index_available,tempcar);break;//à
		  case 162 : chargeCar_P(acirc);createChar(index_available,tempcar);break;//â
		  case 163 : chargeCar_P(atilda);createChar(index_available,tempcar);break;//ã
		  case 164 : chargeCar_P(atrema);createChar(index_available,tempcar);break;//ä
		  case 167 : chargeCar_P(ccedille);createChar(index_available,tempcar);break;//ç
		  case 169 : chargeCar_P(eaigu);createChar(index_available,tempcar);break;//é
		  case 168 : chargeCar_P(egrave);createChar(index_available,tempcar);break;//è
		  case 170 : chargeCar_P(ecirc);createChar(index_available,tempcar);break;//ê
		  case 171 : chargeCar_P(etrema);createChar(index_available,tempcar);break;//ë
		  case 142 : chargeCar_P(imajcirc);createChar(index_available,tempcar);break;//Î
		  case 143 : chargeCar_P(imajtrema);createChar(index_available,tempcar);break;//Ï
		  case 174 : chargeCar_P(icirc);createChar(index_available,tempcar);break;//î
		  case 175 : chargeCar_P(itrema);createChar(index_available,tempcar);break;//ï
		  case 177 : chargeCar_P(ntilda);createChar(index_available,tempcar);break;//ñ
		  case 180 : chargeCar_P(ocirc);createChar(index_available,tempcar);break;//ô
		  case 182 : chargeCar_P(otrema);createChar(index_available,tempcar);break;//ö
		  case 185 : chargeCar_P(ugrave);createChar(index_available,tempcar);break;//ù
		  case 187 : chargeCar_P(ucirc);createChar(index_available,tempcar);break;//û
		  case 188 : chargeCar_P(utrema);createChar(index_available,tempcar);break;//û
		  default : value=63;break;
		  }
	    break;
		}
	  case 2 : {
		  switch (v) {
		  case 130 : chargeCar_P(euro);createChar(index_available,tempcar);break;//à
		  default : value=63;break;
		  }
		break;
	  }
	  case 3 : {
		  switch (v) {
		  case 164 : chargeCar_P(technozone);createChar(index_available,tempcar);break;//¤
		  case 176 : chargeCar_P(degre);createChar(index_available,tempcar);break;//°
		  default : value=63;break;
		  }
		break;
	  }
	 }
	   _increate=0;
	   if (value==32) {
		   _custom[index_available]=v;
		   return index_available;
	   } else {
		   //Le caractere n'est pas encore défini , on renvoie le caractere non accentué
		   return value;
	   }
	 
   } else {
     //Il n'y a plus de place pour un nouveau custom, on renvoie la lettre non accentué
	 //Serial.println("plus de place");
	 
	 switch (v) {
		  case 130 : value=69;break;//€
		  case 160 : value=97;break;//à
		  case 162 : value=97;break;//â
		  case 163 : value=97;break;//ã
		  case 164 : value=97;break;//ä
		  case 167 : value=99;break;//ç
		  case 169 : value=101;break; //é
		  case 168 : value=101;break; //è
		  case 170 : value=101;break; //ê
		  case 171 : value=101;break;//ë
		  case 142 : value=73;break; //î
		  case 143 : value=73;break; //Ï
		  case 174 : value=105;break;//î
		  case 175 : value=105;break;//ï 
		  case 177 : value=110;break;//ñ
		  case 180 : value=111;break; //ô
		  case 182 : value=111;break;//ö
		  case 185 : value=117;break;//ù
		  case 187 : value=117;break;//ü
		  case 188 : value=117;break;//ü
		  default : value=63;break;
	  }
	  return value;
   }
 }
}

inline size_t LiquidCrystal_I2C::write(uint8_t value) {
	//ici on modifie
	uint8_t v=value;
	if (_increate==1) {
		//Serial.print("increate : ");
		//Serial.println(value,DEC);
		send(value, Rs);
		return 1;
	}
    if (_skipnext!=0) {
      //On substitue les caractères accentués par les non accentués
	  v=substitute(value);
	  _skipnext=0;
	}
	if (v==195) {_skipnext=1;}
	if (v==226) {_skipnext=2;}
	if (v==194) {_skipnext=3;}
	if (_skipnext==0) {
		if (v!=172) {
		Serial.print(v,DEC);
		Serial.print(" at ");
		Serial.print(_posx,DEC);
		Serial.print(",");
		Serial.println(_posy,DEC);
		send(v, Rs);
		_posx+=1;}
		}
	return 1;
}

#else
#include "WProgram.h"

#define printIIC(args)	Wire.send(args)
inline void LiquidCrystal_I2C::write(uint8_t value) {
	send(value, Rs);
	return 1;
}

#endif
#include "Wire.h"



// When the display powers up, it is configured as follows:
//
// 1. Display clear
// 2. Function set: 
//    DL = 1; 8-bit interface data 
//    N = 0; 1-line display 
//    F = 0; 5x8 dot character font 
// 3. Display on/off control: 
//    D = 0; Display off 
//    C = 0; Cursor off 
//    B = 0; Blinking off 
// 4. Entry mode set: 
//    I/D = 1; Increment by 1
//    S = 0; No shift 
//
// Note, however, that resetting the Arduino doesn't reset the LCD, so we
// can't assume that its in that state when a sketch starts (and the
// LiquidCrystal constructor is called).

LiquidCrystal_I2C::LiquidCrystal_I2C(uint8_t lcd_Addr,uint8_t lcd_cols,uint8_t lcd_rows)
{
  _Addr = lcd_Addr;
  _cols = lcd_cols;
  _rows = lcd_rows;
  _skipnext=0;
  _backlightval = LCD_NOBACKLIGHT;
}

void LiquidCrystal_I2C::init(){
	init_priv();
}

void LiquidCrystal_I2C::changeadd(uint8_t lcd_addr)
{
 _Addr = lcd_addr;
}

void LiquidCrystal_I2C::init_priv()
{
	
	Wire.begin();
	_displayfunction = LCD_4BITMODE | LCD_1LINE | LCD_5x8DOTS;
	begin(_cols, _rows);  

	/*_increate=1;
	chargeCar_P(agrave);
	createChar(7,tempcar);
	_increate=0	;*/
	
}

void LiquidCrystal_I2C::begin(uint8_t cols, uint8_t lines, uint8_t dotsize) {
	if (lines > 1) {
		_displayfunction |= LCD_2LINE;
	}
	_numlines = lines;

	// for some 1 line displays you can select a 10 pixel high font
	if ((dotsize != 0) && (lines == 1)) {
		_displayfunction |= LCD_5x10DOTS;
	}

	// SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION!
	// according to datasheet, we need at least 40ms after power rises above 2.7V
	// before sending commands. Arduino can turn on way befer 4.5V so we'll wait 50
	delay(50); 
  
	// Now we pull both RS and R/W low to begin commands
	expanderWrite(_backlightval);	// reset expanderand turn backlight off (Bit 8 =1)
	delay(1000);

  	//put the LCD into 4 bit mode
	// this is according to the hitachi HD44780 datasheet
	// figure 24, pg 46
	
	  // we start in 8bit mode, try to set 4 bit mode
   write4bits(0x03 << 4);
   delayMicroseconds(4500); // wait min 4.1ms
   
   // second try
   write4bits(0x03 << 4);
   delayMicroseconds(4500); // wait min 4.1ms
   
   // third go!
   write4bits(0x03 << 4); 
   delayMicroseconds(150);
   
   // finally, set to 4-bit interface
   write4bits(0x02 << 4); 


	// set # lines, font size, etc.
	command(LCD_FUNCTIONSET | _displayfunction);  
	
	// turn the display on with no cursor or blinking default
	_displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
	display();
	
	// clear it off
	clear();
	
	// Initialize to default text direction (for roman languages)
	_displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
	
	// set the entry mode
	command(LCD_ENTRYMODESET | _displaymode);
	
	home();
  
}


void LiquidCrystal_I2C::set_pos(uint8_t x,uint8_t y){
 _posx=x;
 _posy=y;
}
/********** high level commands, for the user! */
void LiquidCrystal_I2C::clear(){
	command(LCD_CLEARDISPLAY);// clear display, set cursor position to zero
	delayMicroseconds(2000);  // this command takes a long time!
	set_pos(0,0);
	for(int i=0;i<8;i++) {_custom[i]=0;}
}

void LiquidCrystal_I2C::home(){
	command(LCD_RETURNHOME);  // set cursor position to zero
	delayMicroseconds(2000);  // this command takes a long time!
	set_pos(0,0);
}

void LiquidCrystal_I2C::setCursor(uint8_t col, uint8_t row){
	set_pos(col,row);
	int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
	if ( row > _numlines ) {
		row = _numlines-1;    // we count rows starting w/0
	}
	command(LCD_SETDDRAMADDR | (col + row_offsets[row]));
}

// Turn the display on/off (quickly)
void LiquidCrystal_I2C::noDisplay() {
	_displaycontrol &= ~LCD_DISPLAYON;
	command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal_I2C::display() {
	_displaycontrol |= LCD_DISPLAYON;
	command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turns the underline cursor on/off
void LiquidCrystal_I2C::noCursor() {
	_displaycontrol &= ~LCD_CURSORON;
	command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal_I2C::cursor() {
	_displaycontrol |= LCD_CURSORON;
	command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// Turn on and off the blinking cursor
void LiquidCrystal_I2C::noBlink() {
	_displaycontrol &= ~LCD_BLINKON;
	command(LCD_DISPLAYCONTROL | _displaycontrol);
}
void LiquidCrystal_I2C::blink() {
	_displaycontrol |= LCD_BLINKON;
	command(LCD_DISPLAYCONTROL | _displaycontrol);
}

// These commands scroll the display without changing the RAM
void LiquidCrystal_I2C::scrollDisplayLeft(void) {
	command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
void LiquidCrystal_I2C::scrollDisplayRight(void) {
	command(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}

// This is for text that flows Left to Right
void LiquidCrystal_I2C::leftToRight(void) {
	_displaymode |= LCD_ENTRYLEFT;
	command(LCD_ENTRYMODESET | _displaymode);
}

// This is for text that flows Right to Left
void LiquidCrystal_I2C::rightToLeft(void) {
	_displaymode &= ~LCD_ENTRYLEFT;
	command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'right justify' text from the cursor
void LiquidCrystal_I2C::autoscroll(void) {
	_displaymode |= LCD_ENTRYSHIFTINCREMENT;
	command(LCD_ENTRYMODESET | _displaymode);
}

// This will 'left justify' text from the cursor
void LiquidCrystal_I2C::noAutoscroll(void) {
	_displaymode &= ~LCD_ENTRYSHIFTINCREMENT;
	command(LCD_ENTRYMODESET | _displaymode);
}

// Allows us to fill the first 8 CGRAM locations
// with custom characters
void LiquidCrystal_I2C::createChar(uint8_t location, uint8_t charmap[]) {
	location &= 0x7; // we only have 8 locations 0-7
	command(LCD_SETCGRAMADDR | (location << 3));
	for (int i=0; i<8; i++) {
		write(charmap[i]);
	}
	setCursor(_posx,_posy);
}

// Turn the (optional) backlight off/on
void LiquidCrystal_I2C::noBacklight(void) {
	_backlightval=LCD_NOBACKLIGHT;
	expanderWrite(0);
}

void LiquidCrystal_I2C::backlight(void) {
	_backlightval=LCD_BACKLIGHT;
	expanderWrite(0);
}



/*********** mid level commands, for sending data/cmds */

inline void LiquidCrystal_I2C::command(uint8_t value) {
	send(value, 0);
}


/************ low level data pushing commands **********/

// write either command or data
void LiquidCrystal_I2C::send(uint8_t value, uint8_t mode) {
	uint8_t highnib=value&0xf0;
	uint8_t lownib=(value<<4)&0xf0;
       write4bits((highnib)|mode);
	write4bits((lownib)|mode); 
}

void LiquidCrystal_I2C::write4bits(uint8_t value) {
	expanderWrite(value);
	pulseEnable(value);
}

void LiquidCrystal_I2C::expanderWrite(uint8_t _data){                                        
	Wire.beginTransmission(_Addr);
	printIIC((int)(_data) | _backlightval);
	Wire.endTransmission();   
}

void LiquidCrystal_I2C::pulseEnable(uint8_t _data){
	expanderWrite(_data | En);	// En high
	delayMicroseconds(1);		// enable pulse must be >450ns
	
	expanderWrite(_data & ~En);	// En low
	delayMicroseconds(50);		// commands need > 37us to settle
} 


// Alias functions

void LiquidCrystal_I2C::cursor_on(){
	cursor();
}

void LiquidCrystal_I2C::cursor_off(){
	noCursor();
}

void LiquidCrystal_I2C::blink_on(){
	blink();
}

void LiquidCrystal_I2C::blink_off(){
	noBlink();
}

void LiquidCrystal_I2C::load_custom_character(uint8_t char_num, uint8_t *rows){
		createChar(char_num, rows);
}

void LiquidCrystal_I2C::setBacklight(uint8_t new_val){
	if(new_val){
		backlight();		// turn backlight on
	}else{
		noBacklight();		// turn backlight off
	}
}

void LiquidCrystal_I2C::printstr(const char c[]){
	//This function is not identical to the function used for "real" I2C displays
	//it's here so the user sketch doesn't have to be changed 
	print(c);
}

void LiquidCrystal_I2C::config(uint8_t choix){
	switch (choix) {
    case 1:
      LiquidCrystal_I2C::backlight();
      break;
    case 2:
      LiquidCrystal_I2C::noBacklight();
      break;
	case 3:
      LiquidCrystal_I2C::cursor();
      break;
	case 4:
      LiquidCrystal_I2C::noCursor();
      break;
	case 5:
      LiquidCrystal_I2C::blink();
      break;
	case 6:
      LiquidCrystal_I2C::noBlink();
      break;
	case 7:
      LiquidCrystal_I2C::display();
      break;
	case 8:
      LiquidCrystal_I2C::noDisplay();
      break;
  }
}

// unsupported API functions
void LiquidCrystal_I2C::off(){}
void LiquidCrystal_I2C::on(){}
void LiquidCrystal_I2C::setDelay (int cmdDelay,int charDelay) {}
uint8_t LiquidCrystal_I2C::status(){return 0;}
uint8_t LiquidCrystal_I2C::keypad (){return 0;}
uint8_t LiquidCrystal_I2C::init_bargraph(uint8_t graphtype){return 0;}
void LiquidCrystal_I2C::draw_horizontal_graph(uint8_t row, uint8_t column, uint8_t len,  uint8_t pixel_col_end){}
void LiquidCrystal_I2C::draw_vertical_graph(uint8_t row, uint8_t column, uint8_t len,  uint8_t pixel_row_end){}
void LiquidCrystal_I2C::setContrast(uint8_t new_val){}

	