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

    source::worx libPiGPio
    Copyright © 2022 c.holzheuer
    chris@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Uses:

    pigpiod_if2 by joan2937, pigpio @ abyz.me.uk
    https://abyz.me.uk/rpi/pigpio

    sigslot  by 2017 Pierre-Antoine Lacaze
    https://github.com/palacaze/sigslot

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


#include <piglcd.h>



pigLCD::pigLCD( i2c_addr_t addr, i2c_bus_t bus )
{
    init( addr,  bus );
}


pigLCD::~pigLCD()
{
    reset();
}


void pigLCD::init( i2c_addr_t addr, i2c_bus_t bus, int width, bool bl, uint8_t RS, uint8_t , uint8_t E, uint8_t BL, uint8_t B4 )
{
    _i2c.init( addr, bus );

    _width = width;
    _backlight = bl;

    _RS = (1<<RS);
    _E  = (1<<E);
    _BL = (1<<BL);
    _B4 = B4;

    put_inst( 0x33 ); // Initialise 1
    put_inst( 0x32 ); // Initialise 2
    put_inst( 0x06 ); // Cursor increment
    put_inst( 0x0C ); // Display on,move_to off, blink off
    put_inst( 0x28 ); // 4-bits, 1 line, 5x8 font
    put_inst( 0x01 ); // Clear display
    //?? move_to( 0,0 )
    put_inst( _LCD_ROW[0]+0 );

}


/**
 * @brief pigLCD::close
 * Close the LCD (clearing the screen) and release used resources.
 */

void pigLCD::reset()
{
    put_inst( 0x01 ); // Clear display
    set_backlight( false );
}


/**
 * @brief pigLCD::set_backlight
 * @param bl
 * toogle backlight on or off.
 */

void pigLCD::set_backlight( bool bl )
{
    _backlight = bl;
    // hack
    move_to( 0, 0 );
}


/**
 * @brief pigLCD::move_to
 * @param row
 * @param col
 *
 * Position cursor at row and column (0 based).
 */

void pigLCD::move_to( int row, int col )
{
   put_inst( _LCD_ROW[row]+col );
}


/**
 * @brief pigLCD::write
 * @param c
 * Write a character at the current cursor postion and
 * increment the cursor.
 */

void pigLCD::write( const char c )
{
    put_data( (uint8_t) c );
}


void pigLCD::write( const std::string text )
{
    for( const char c : text )
        write( c );
}


void pigLCD::write( int row, int col, const std::string text )
{
    move_to( row, col );
    write( text );
}




void pigLCD::put_byte( uint8_t MSb, uint8_t LSb )
{

  if( _backlight )
  {
      MSb |= _BL;
      LSb |= _BL;
  }
  
  char buf[4];
  buf[0] = (char) MSb | _E;
  buf[1] = (char) MSb & ~_E;
  buf[2] = (char) LSb | _E;
  buf[3] = LSb & ~_E;
  _i2c.i2c_write_device( buf, 4 );
 
  //    self.pi.i2c_write_device(self._h,
  //       [MSb | self.E, MSb & ~self.E, LSb | self.E, LSb & ~self.E]) */

}


void pigLCD::put_inst( uint8_t bits )
{

    uint8_t MSN = (bits>>4) & 0x0F;
    uint8_t LSN = bits & 0x0F;

    uint8_t MSb = MSN << _B4;
    uint8_t LSb = LSN << _B4;

    put_byte( MSb, LSb );

}


void pigLCD::put_data( uint8_t bits )
{

    uint8_t MSN = (bits>>4) & 0x0F;
    uint8_t LSN = bits & 0x0F;

    uint8_t MSb = (MSN << _B4) | _RS;
    uint8_t LSb = (LSN << _B4) | _RS;

    put_byte( MSb, LSb );

}



