#include "led_i2c.h"
 
uint8_t _displayfunction;
//extern uint8_t adress = 0x7e;
 
uint8_t _Addr;				// I2C Address of the IO expander
uint8_t _backlightPinMask;	// Backlight IO pin mask
uint8_t _backlightStsMask;	// Backlight status mask
uint8_t _En;				// LCD expander word for enable pin
uint8_t _Rw;				// LCD expander word for R/W pin
uint8_t _Rs;				// LCD expander word for Register Select pin
uint8_t _data_pins[4];		// LCD data lines
uint8_t _displayfunction;	// LCD_5x10DOTS or LCD_5x8DOTS, LCD_4BITMODE or LCD_8BITMODE, LCD_1LINE or LCD_2LINE
uint8_t _displaycontrol;	// LCD base control command LCD on/off, blink, cursor all commands are "ored" to its contents.
uint8_t _displaymode;		// Text entry mode to the LCD
uint8_t _numlines;			// Number of lines of the LCD, initialized with begin()
uint8_t _cols;				// Number of columns in the LCD
uint8_t _rows;				// Number of rows in the LCD
uint8_t _backlightval;
t_backlighPol _polarity;	// Backlight polarity

RESULT_I2C result;
 
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_config ( uint8_t lcd_Addr )
 {
	 _Addr = lcd_Addr;
	 
	 _backlightPinMask = 0;
	 _backlightStsMask = LCD_BACKLIGHT;
	 _polarity = POSITIVE;
	 
	 _En = ( 1 << 2 );
	 _Rw = ( 1 << 1 );
	 _Rs = ( 1 << 0 );
	 
	 // Initialise pin mapping
	 _data_pins[0] = ( 1 << 4 );
	 _data_pins[1] = ( 1 << 5 );
	 _data_pins[2] = ( 1 << 6 );
	 _data_pins[3] = ( 1 << 7 );
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_init ( uint8_t cols, uint8_t lines, uint8_t dotsize )
 {
	 I2C_MyInit();
	 lcd_i2c_begin ( cols, lines, dotsize );
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_begin ( uint8_t cols, uint8_t lines, uint8_t dotsize)
 {
	 if (lines > 1) _displayfunction |= LCD_2LINE;
	 
	 _numlines = lines;
	 _cols = cols;
	 
	 // for some 1 line displays you can select a 10 pixel high font
	 // ------------------------------------------------------------
	 if ((dotsize != LCD_5x8DOTS) && (lines == 1)) _displayfunction |= LCD_5x10DOTS;
	 
	 // 100ms delay
	 // ---------------------------------------------------------------------------
	 delay_ms(100);
	 
	 //put the LCD into 4 bit or 8 bit mode
	 // -------------------------------------
	 if (!(_displayfunction & LCD_8BITMODE))
	 {
		 // we start in 8bit mode, try to set 4 bit mode
		 // Special case of "Function Set"
		 lcd_i2c_send ( 0x03, FOUR_BITS );
		 //_delay_us(4500); // wait min 4.1ms
         delay_ms(5);
		 
		 // second try
		 lcd_i2c_send ( 0x03, FOUR_BITS );
		 //_delay_us(150); // wait min 100us
         delay_ms(1);
		 
		 // third go!
		 lcd_i2c_send( 0x03, FOUR_BITS );
		 //_delay_us(150); // wait min of 100us
         delay_ms(1);
		 
		 // finally, set to 4-bit interface
		 lcd_i2c_send ( 0x02, FOUR_BITS );
		 //_delay_us(150); // wait min of 100us
	 }
	 else
	 {
		 // Send function set command sequence
		 lcd_i2c_send ( LCD_FUNCTIONSET | _displayfunction, COMMAND );
		 //_delay_us(4500);  // wait more than 4.1ms
         delay_ms(5);
		 
		 // second try
		 lcd_i2c_send ( LCD_FUNCTIONSET | _displayfunction, COMMAND );
		 //_delay_us(150);
         delay_ms(1);
		 
		 // third go
		 lcd_i2c_send ( LCD_FUNCTIONSET | _displayfunction, COMMAND );
		 //_delay_us(150);
         delay_ms(1);
	 }

	 // finally, set # lines, font size, etc.
	 lcd_i2c_send ( LCD_FUNCTIONSET | _displayfunction, COMMAND );
	// _delay_us ( 60 );  // wait more
         delay_ms(1);
	 
	 // turn the display on with no cursor or blinking default
	 _displaycontrol = LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF;
	 lcd_i2c_display();
	 
	 // clear the LCD
	 lcd_i2c_clear();
	 
	 // Initialize to default text direction (for romance languages)
	 _displaymode = LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT;
	 // set the entry mode
	 lcd_i2c_send ( LCD_ENTRYMODESET | _displaymode, COMMAND );
	 
	 lcd_i2c_backlight();
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_send ( uint8_t value, uint8_t mode )
 {
	 if ( mode == FOUR_BITS )
	 {
		 lcd_i2c_write4bits( (value & 0x0F), COMMAND );
	 }
	 else
	 {
		 lcd_i2c_write4bits( (value >> 4), mode );
		 lcd_i2c_write4bits( (value & 0x0F), mode);
	 }
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_write4bits(uint8_t value, uint8_t mode)
 {
	 uint8_t pinMapValue = 0;
	 
	 // Map the value to LCD pin mapping
	 // --------------------------------
	 for (int i = 0; i < 4; i++)
	 {
		 if ( ( value & 0x1 ) == 1 ) pinMapValue |= _data_pins[i];
		 value = ( value >> 1 );
	 }
	 
	 // Is it a command or data
	 // -----------------------
	 if ( mode == DATA )	mode = _Rs;
	 pinMapValue |= mode | _backlightStsMask;
	 lcd_i2c_pulseEnable ( pinMapValue );
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_pulseEnable(uint8_t data)
 {
	 result = I2C_StartTransmission (I2C1, I2C_Direction_Transmitter, _Addr);   if(result > 0) return;
	 result = I2C_WriteData (I2C1, data | _En);                                 if(result > 0) return;
	 I2C_MyStop(I2C1);
     for(int i = 0; i < 32; i++) {}
	 result = I2C_StartTransmission (I2C1, I2C_Direction_Transmitter, _Addr);   if(result > 0) return;
	 result = I2C_WriteData (I2C1, data & ~_En);                                if(result > 0) return;
	 I2C_MyStop(I2C1);
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_display(void)
 {
	 _displaycontrol |= LCD_DISPLAYON;
	 lcd_i2c_send ( LCD_DISPLAYCONTROL | _displaycontrol, COMMAND );
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_noDisplay(void)
 {
	 _displaycontrol &= ~LCD_DISPLAYON;
	 lcd_i2c_send ( LCD_DISPLAYCONTROL | _displaycontrol, COMMAND );
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_clear(void)
 {
	 lcd_i2c_send ( LCD_CLEARDISPLAY, COMMAND ); // clear display, set cursor position to zero
	// _delay_us (HOME_CLEAR_EXEC);				// this command is time consuming
         delay_ms(2);
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_backlight(void)
 {
	 lcd_i2c_setBacklight(255);
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_noBacklight(void)
 {
	 lcd_i2c_setBacklight(0);
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_setBacklight ( uint8_t value )
 {
	 // Check if backlight is available
	 // ----------------------------------------------------
	 if ( _backlightPinMask != 0x0 )
	 {
		 // Check for polarity to configure mask accordingly
		 // ----------------------------------------------------------
		 if  (((_polarity == POSITIVE) && (value > 0)) ||
		 ((_polarity == NEGATIVE ) && ( value == 0 )))
		 {
			 //_backlightStsMask = _backlightPinMask & LCD_BACKLIGHT;
			 _backlightStsMask = _backlightPinMask | 0x08;
		 }
		 else
		 {
			 //_backlightStsMask = _backlightPinMask & LCD_NOBACKLIGHT;
			 _backlightStsMask = _backlightPinMask & 0xf7;
		 }
		 I2C_StartTransmission (I2C1, I2C_Direction_Transmitter, _Addr);
		 I2C_WriteData (I2C1, _backlightStsMask );
		 I2C_MyStop(I2C1);
	 }
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_setBacklightPin ( uint8_t value, t_backlighPol pol )
 {
	 _backlightPinMask = ( 1 << value );
	 _polarity = pol;
	 lcd_i2c_setBacklight(BACKLIGHT_OFF);
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_print(char data[], uint8_t size)
 {
	 for(int i = 0; i < size; i++)
	 {
		 lcd_i2c_send ( data[i], DATA );
		 //data++;
	 }
 }
//--------------------------------------------
//
//--------------------------------------------
 void lcd_i2c_setCursor(uint8_t col, uint8_t row)
 {
	 int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 };
	 if ( row > _numlines ) {
		 row = _numlines-1;    // we count rows starting w/0
	 }
	 lcd_i2c_send(LCD_SETDDRAMADDR | (col - 1 + row_offsets[row-1]),COMMAND);
 }
 