/* ###################################################################
**     This component module is generated by Processor Expert. Do not modify it.
**     Filename    : McuHD44780.h
**     Project     : FRDM-K64F_Generator
**     Processor   : MK64FN1M0VLL12
**     Component   : LCDHTA
**     Version     : Component 01.031, Driver 01.00, CPU db: 3.00.000
**     Compiler    : GNU C Compiler
**     Date/Time   : 2020-08-14, 06:24, # CodeGen: 679
**     Abstract    :
**          This component implements a driver for multiple 2x16 character displays.
**     Settings    :
**          Component name                                 : McuHD44780
**          HW Interface                                   : 
**            LCD Type                                     : generic
**            LCD Lines                                    : 2
**            Characters per Line                          : 16
**            Line Addresses                               : 
**              Line 1                                     : 0x00
**              Line 2                                     : 0x40
**              Line 3                                     : 0x10
**              Line 4                                     : 0x50
**            LCD Enable Signal                            : Disabled
**            Read from Display                            : Enabled
**              R/W signal                                 : SDK_BitIO
**              Check Busy Flag                            : yes
**            Wait (us)                                    : 0
**            E signal                                     : SDK_BitIO
**            E2                                           : Enabled
**              E2 signal                                  : SDK_BitIO
**            RS signal                                    : SDK_BitIO
**            Data/Control Bus                             : 
**              Data/Control Bus Width                     : 8bit
**              DB0..DB3                                   : Enabled
**                DB0                                      : SDK_BitIO
**                DB1                                      : SDK_BitIO
**                DB2                                      : SDK_BitIO
**                DB3                                      : SDK_BitIO
**              DB4..DB7                                   : Enabled
**                DB4                                      : SDK_BitIO
**                DB5                                      : SDK_BitIO
**                DB6                                      : SDK_BitIO
**                DB7                                      : SDK_BitIO
**              Bits/Byte Bus                              : Disabled
**          System Interface                               : 
**            Wait                                         : McuWait
**     Contents    :
**         WriteLCDCommand  - void McuHD44780_WriteLCDCommand(uint8_t cmd);
**         Write            - void McuHD44780_Write(char ch);
**         WriteLn          - void McuHD44780_WriteLn(void);
**         WriteLineStr     - void McuHD44780_WriteLineStr(uint8_t line, char *str);
**         WriteString      - void McuHD44780_WriteString(char *str);
**         LoadSoftChar     - void McuHD44780_LoadSoftChar(uint8_t charCode, uint8_t *softChar);
**         ShiftLeft        - void McuHD44780_ShiftLeft(void);
**         ShiftRight       - void McuHD44780_ShiftRight(void);
**         GotoXY           - void McuHD44780_GotoXY(uint8_t line, uint8_t column);
**         SetEntryMode     - void McuHD44780_SetEntryMode(bool increment, bool shiftLeft);
**         DisplayOn        - void McuHD44780_DisplayOn(void);
**         DisplayOff       - void McuHD44780_DisplayOff(void);
**         CursorOn         - void McuHD44780_CursorOn(void);
**         CursorOff        - void McuHD44780_CursorOff(void);
**         CursorShiftRight - void McuHD44780_CursorShiftRight(void);
**         CursorShiftLeft  - void McuHD44780_CursorShiftLeft(void);
**         BlinkingOn       - void McuHD44780_BlinkingOn(void);
**         BlinkingOff      - void McuHD44780_BlinkingOff(void);
**         Home             - void McuHD44780_Home(void);
**         Line             - void McuHD44780_Line(uint8_t line);
**         Clear            - void McuHD44780_Clear(void);
**         UseDisplay       - uint8_t McuHD44780_UseDisplay(uint8_t display);
**         DeInit           - void McuHD44780_DeInit(void);
**
** * Copyright (c) 2008-2020, Erich Styger
**  * Web:         https://mcuoneclipse.com
**  * SourceForge: https://sourceforge.net/projects/mcuoneclipse
**  * Git:         https://github.com/ErichStyger/McuOnEclipse_PEx
**  * All rights reserved.
**  *
**  * Redistribution and use in source and binary forms, with or without modification,
**  * are permitted provided that the following conditions are met:
**  *
**  * - Redistributions of source code must retain the above copyright notice, this list
**  *   of conditions and the following disclaimer.
**  *
**  * - Redistributions in binary form must reproduce the above copyright notice, this
**  *   list of conditions and the following disclaimer in the documentation and/or
**  *   other materials provided with the distribution.
**  *
**  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
**  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
**  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
**  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
**  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
**  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
**  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
**  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
**  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
**  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
** ###################################################################*/
/*!
** @file McuHD44780.h
** @version 01.00
** @brief
**          This component implements a driver for multiple 2x16 character displays.
*/         
/*!
**  @addtogroup McuHD44780_module McuHD44780 module documentation
**  @{
*/         

/* MODULE McuHD44780. */
#include "McuHD44780.h"
#include "McuWait.h"

/* DEFINES for display commands.
   See
   - www.freescale.com/files/microcontrollers/doc/app_note/AN1745.pdf
   - http://www.mikrocontroller.net/articles/HD44780
   for additional details.
*/
#define ClearDisplayCmd                 0x01 /* clears the display */

#define ReturnHomeCmd                   0x02 /* moves the cursor to the beginning of the first line */

#define EntryModeSetCmd                 0x04
  #define EntryModeSet_ShiftOn             1 /* S flag: shift display */
  #define EntryModeSet_IncrementOn         2 /* I/D flag: increment cursor */

#define DisplayOnOffControlCmd          0x08 /* Display on/off control command. There are 3 bits D, C and B as well */
  #define DisplayOnOffControl_BlinkOn      1 /* B flag: blinking cursor on/off; B=1 blinking, B=0 not blinking */
  #define DisplayOnOffControl_CursorOn     2 /* C flag: cursor on/off, C=1 cursor on, C=0 cursor off */
  #define DisplayOnOffControl_DisplayOn    4 /* D flag: display on/off, D=1 display on, D=0 display off */

#define FunctionSetCmd                  0x20
  #define FunctionSet_8bit              0x10 /* DL flag: DL=1: 8bit, DL=0: 4bit */
  #define FunctionSet_4bit                 0 /* DL flag: DL=1: 8bit, DL=0: 4bit */
  #define FunctionSet_2Lines            0x08 /* N flag: number of display lines: N=1 2 or 4 lines, N=0 1 line */
  #define FunctionSet_1Line                0 /* N flag: number of display lines: N=1 2 or 4 lines, N=0 1 line */
  #define FunctionSet_Font5x10          0x04 /* F flag: character font, F=1 5x10 dots, F=0 5x8 dots */
  #define FunctionSet_Font5x8              0 /* F flag: character font, F=1 5x10 dots, F=0 5x8 dots */

#define CursorOnCmd    (DisplayOnOffControlCmd|DisplayOnOffControl_DisplayOn|DisplayOnOffControl_CursorOn)
#define CursorOffCmd   (DisplayOnOffControlCmd|DisplayOnOffControl_DisplayOn)
#define GotoXYCmd      0x80  /* 0x80 | Display RAM address */
#define Line1Offset    0x00 /* Display RAM address of first line, usually 0x00 */
#define Line2Offset    0x40 /* Display RAM address of second line, usually 0x40 */
#define Line3Offset    0x10 /* Display RAM address of third line, usually 0x10 */
#define Line4Offset    0x50 /* Display RAM address of fourth line, usually 0x50 */
#define FirstLineCmd   (GotoXYCmd|Line1Offset)
#define SecondLineCmd  (GotoXYCmd|Line2Offset)
#define ThirdLineCmd   (GotoXYCmd|Line3Offset)
#define FourthLineCmd  (GotoXYCmd|Line4Offset)

#define RightShiftCmd      0x1C
#define LeftShiftCmd       0x18
#define RightShiftCursor   0x14
#define LeftShiftCursor    0x10

static uint8_t DisplayOnOffControlStatus = 0;

#define BusyFlag       0x80 /* BF Flag */

/* support for custom soft characters in the display which can be used with McuHD44780_LoadSoftChar() */
const uint8_t McuHD44780_SoftCharUE[8] = { /* ü */
  0x11, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0d, 0
/* X...X
   .....
   X...X
   X...X
   X...X
   X..XX
   .XX.X */
};

const uint8_t McuHD44780_SoftCharAE[8] = { /* ä */
  0x11, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F, 0
/* X...X
   .....
   .XXX.
   ....X
   .XXXX
   X...X
   .XXXX */
};

const uint8_t McuHD44780_SoftCharOE[8] = { /* ö */
  0x11, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E, 0
/* X...X
   .....
   .XXX.
   X...X
   X...X
   X...X
   .XXX. */
};

#if McuHD44780_CONFIG_USE_RW_SIGNAL
/* macros for the RW pin */
#define ClrRW() \
        RW1_ClrVal()                    /* RW=0: write mode */
#define SetRW() \
        RW1_SetVal()                    /* RW=1: read mode */
#endif /* McuHD44780_CONFIG_USE_RW_SIGNAL */

/* macros for the RS pin */
#define ClrRS() \
        RS1_ClrVal()                    /* RS=0: command mode */
#define SetRS() \
        RS1_SetVal()                    /* RS=1: data mode */

/* macros for the EN pin */
#define ClrEN() \
        EN1_ClrVal()                    /* EN=0 */
#define SetEN() \
        EN1_SetVal()                    /* EN=1 */

#if McuHD44780_CONFIG_USE_E2_SIGNAL
  /* macros for the EN2 pin */
  #define ClrEN2() \
        EN2_ClrVal()                    /* E2=0 */
  #define SetEN2() \
        EN2_SetVal()                    /* E2=1 */
  static uint8_t McuHD44780_currDisplay = 1; /* only for displays with E1 and E2: if set to 1, it will use E1, if set to 2 it will use E2 */
#endif

/* macros for the data bus */
#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==8
  #define DataAsOutput03() \
        DB01_SetOutput();               /* set data port as output */ \
        DB11_SetOutput();               /* set data port as output */ \
        DB21_SetOutput();               /* set data port as output */ \
        DB31_SetOutput();               /* set data port as output */
#endif

#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==8 || McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
  #define DataAsOutput47() \
        DB41_SetOutput();               /* set data port as output */ \
        DB51_SetOutput();               /* set data port as output */ \
        DB61_SetOutput();               /* set data port as output */ \
        DB71_SetOutput()                /* set data port as output */
#endif

#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==8 || McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
  #define DataAsInput03() \
        DB01_SetInput();                /* set data port as input */ \
        DB11_SetInput();                /* set data port as input */ \
        DB21_SetInput();                /* set data port as input */ \
        DB31_SetInput();                /* set data port as input */
#endif

#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
  #define DataAsInput47() \
        DB41_SetInput();                /* set data port as input */ \
        DB51_SetInput();                /* set data port as input */ \
        DB61_SetInput();                /* set data port as input */ \
        DB71_SetInput()                 /* set data port as input */
#endif

#if McuHD44780_CONFIG_LCD_DATA_BUS_PORT_8BIT
  #define DataAsOutput()        DataBus_SetOutput() /* set data port as output */
  #define DataAsInput()         DataBus_SetInput() /* set data port as input */
#elif McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
  #define DataAsOutput()        DataAsOutput47()
  #define DataAsInput()         DataAsInput47()
#elif McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==8
  #define DataAsOutput()        DataAsOutput03(); DataAsOutput47()
  #define DataAsInput()         DataAsInput03(); DataAsInput47()
#endif



/* waiting macros */
#define Waitns(x) \
        McuWait_Waitns(x)               /* Wait x ns */
#define Waitus(x) \
        McuWait_Waitus(x)               /* Wait x us */
#define Waitms(x) \
        McuWait_Waitms(x)               /* Wait x ms */

/* timings from Hitachi HD44708.pdf */
#define Timing_PWeh_ns   230 /* PWeh: Enable Pulse width (high level) */
#define Timing_tAS_ns     40 /* tAB: Address set-up time (RS, RW to E ) */
#define Timing_tDDR_ns   160 /* tDDR: Data delay time */
#define Timing_tCYCLE_ns 500 /* tCYLE: Enable Cycle time */

#if McuHD44780_CONFIG_USE_DISPLAY_READ && McuHD44780_CONFIG_USE_DISPLAY_READ_CHECK_BUSY_FLAG
static uint8_t DataGet(void) {
  uint8_t val;

#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
  val =  (DB71_GetVal()<<3)
        |(DB61_GetVal()<<2)
        |(DB51_GetVal()<<1)
        |(DB41_GetVal()<<0);
#elif McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==8 /* 8bit */
  val =  (DB71_GetVal()<<7)
        |(DB61_GetVal()<<6)
        |(DB51_GetVal()<<5)
        |(DB41_GetVal()<<4)
        |(DB31_GetVal()<<3)
        |(DB21_GetVal()<<2)
        |(DB11_GetVal()<<1)
        |(DB01_GetVal()<<0);
#endif
  return val;
}
#endif /* #if McuHD44780_CONFIG_USE_DISPLAY_READ && McuHD44780_CONFIG_USE_DISPLAY_READ_CHECK_BUSY_FLAG */

static void DataPut(uint8_t val) {
#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
  DB71_PutVal((val&(1<<3))!=0);
  DB61_PutVal((val&(1<<2))!=0);
  DB51_PutVal((val&(1<<1))!=0);
  DB41_PutVal((val&(1<<0))!=0);
#else /* 8bit */
  DB71_PutVal((val&(1<<7))!=0);
  DB61_PutVal((val&(1<<6))!=0);
  DB51_PutVal((val&(1<<5))!=0);
  DB41_PutVal((val&(1<<4))!=0);
  DB31_PutVal((val&(1<<3))!=0);
  DB21_PutVal((val&(1<<2))!=0);
  DB11_PutVal((val&(1<<1))!=0);
  DB01_PutVal((val&(1<<0))!=0);
#endif
}

/* Internal method prototypes */
static void EnablePulse(void);

/*
** ===================================================================
**     Method      :  EnablePulse (component LCDHTA)
**
**     Description :
**         This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
static void EnablePulse(void)
{
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  if (McuHD44780_currDisplay==1) {
    SetEN();
  } else {
    SetEN2();
  }
#else
  SetEN();
#endif                                  /* set EN to 1 to create pulse */
#if McuHD44780_CONFIG_LCD_TYPE==1
  /* Diplaytech 162c: not clear why this is not according to the 500ns spec? */
  Waitms(2);
#else
  Waitns(Timing_PWeh_ns);
#endif
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  if (McuHD44780_currDisplay==1) {
    ClrEN();                            /* set to 0 to finish pulse */
  } else {
    ClrEN2();                           /* set to 0 to finish pulse */
  }
#else
  ClrEN();                              /* set to 0 to finish pulse */
#endif
}

#if McuHD44780_CONFIG_USE_DISPLAY_READ && McuHD44780_CONFIG_USE_DISPLAY_READ_CHECK_BUSY_FLAG
/*
** ===================================================================
**     Method      :  McuHD44780_WaitForLCDReady (component LCDHTA)
**
**     Description :
**         This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
void McuHD44780_WaitForLCDReady(void)
{
  uint8_t ch;

  /* Wait until the display is ready for new data.
     This means that we wait until the busy flag (MSB) in the status register is cleared */
  DataAsInput();                        /* set data port as input */
  SetRW();                              /* RW = 1: read mode */
  Waitns(Timing_tAS_ns);
  for(;;) {                             /* loop breaks as soon the busy flag is cleared */
  #if McuHD44780_CONFIG_USE_E2_SIGNAL
    if(McuHD44780_currDisplay==1) {
      SetEN();                          /* EN = 1; EN to high for getting the busy flag  */
    } else {
      SetEN2();                         /* EN = 1; EN to high for getting the busy flag  */
    }
  #else
    SetEN();                            /* EN = 1; EN to high for getting the busy flag  */
  #endif
    Waitns(Timing_tDDR_ns);             /* Read mode timing tDDR: time until we can read data */
#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
    /* for 4bit data bus: need to do read twice */
    ch = (uint8_t)(DataGet()<<4);       /* read high byte */
    Waitns(Timing_PWeh_ns-Timing_tDDR_ns); /* for accurate lenght of EN pulse */
  #if McuHD44780_CONFIG_USE_E2_SIGNAL
    if(McuHD44780_currDisplay==1) {
      ClrEN();
    } else {
      ClrEN2();
    }
  #else
    ClrEN();
  #endif
    Waitns(Timing_tCYCLE_ns-Timing_PWeh_ns); /* need to wait a cycle time until we can enable EN again */
  #if McuHD44780_CONFIG_USE_E2_SIGNAL
    if(McuHD44780_currDisplay==1) {
      SetEN();                          /* EN = 1; EN to high for getting the busy flag  */
    } else {
      SetEN2();                         /* EN = 1; EN to high for getting the busy flag  */
    }
  #else
    SetEN();                            /* EN = 1; EN to high for getting the busy flag  */
  #endif
    Waitns(Timing_tDDR_ns);             /* Read mode timing tDDR: time until we can read data */
    ch |= DataGet();                    /* read low byte */
#else
    ch = DataGet();                     /* read status */
#endif
    Waitns(Timing_PWeh_ns-Timing_tDDR_ns); /* for accurate length of EN pulse */
  #if McuHD44780_CONFIG_USE_E2_SIGNAL
    if(McuHD44780_currDisplay==1) {
      ClrEN();
    } else {
      ClrEN2();
    }
  #else
    ClrEN();
  #endif
    if (!(ch&BusyFlag)) {
      break;
    }
    Waitns(Timing_tCYCLE_ns-Timing_PWeh_ns); /* need to wait a cycle time until we can enable EN again */
  } /* for */
  #if McuHD44780_CONFIG_USE_RW_SIGNAL
  ClrRW();                              /* RW = 0: back to write mode */
  #endif
  DataAsOutput();                       /* set data port as output */
}
#endif /* McuHD44780_CONFIG_USE_DISPLAY_READ && McuHD44780_CONFIG_USE_DISPLAY_READ_CHECK_BUSY_FLAG */

/*
** ===================================================================
**     Method      :  WriteLCDCommand (component LCDHTA)
**
**     Description :
**         Writes a command to the display
**     Parameters  :
**         NAME            - DESCRIPTION
**         cmd             - command passed to the LCD
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_WriteLCDCommand(uint8_t cmd)
{
#if McuHD44780_CONFIG_WAIT_DISPLAY_US > 0
  McuWait_Waitus(McuHD44780_CONFIG_WAIT_DISPLAY_US); /* wait for some time not to write to the display while he may be busy with previous command */
#endif
#if McuHD44780_CONFIG_USE_DISPLAY_READ && McuHD44780_CONFIG_USE_DISPLAY_READ_CHECK_BUSY_FLAG
  McuHD44780_WaitForLCDReady();         /* Wait until LCD is ready */
#endif
#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
  /* 2 4bit transfer */
  DataPut((uint8_t)((cmd&0xF0)>>4));    /* Write the data (cycle #1) */
  EnablePulse();                        /* transfer data */
  Waitus(McuHD44780_CONFIG_WAIT_LCD_CMD_AFTER_4BIT_DATA1_US);
  DataPut((uint8_t)(cmd&0x0F) );        /* Write the data (cycle #2) */
  EnablePulse();                        /* do the command transfer */
  Waitus(McuHD44780_CONFIG_WAIT_LCD_CMD_AFTER_4BIT_DATA2_US);
#else
  /* 8bit transfer */
  DataPut(cmd);                         /* put data on bus */
  EnablePulse();                        /* do the command transfer */
#endif
}

/*
** ===================================================================
**     Method      :  Clear (component LCDHTA)
**
**     Description :
**         Clears the display and moves the cursor to the first line.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_Clear(void)
{
  McuHD44780_WriteLCDCommand(ClearDisplayCmd); /* send the clear command to the LCD */
}

/*
** ===================================================================
**     Method      :  Home (component LCDHTA)
**
**     Description :
**         Moves the cursor to the beginning of the first line.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_Home(void)
{
  McuHD44780_WriteLCDCommand(ReturnHomeCmd); /* moves the cursor to the beginning of the first line */
}

/*
** ===================================================================
**     Method      :  McuHD44780_WriteLCDData (component LCDHTA)
**
**     Description :
**         This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
void McuHD44780_WriteLCDData(uint8_t ch)
{
#if McuHD44780_CONFIG_WAIT_DISPLAY_US > 0
   McuWait_Waitus(McuHD44780_CONFIG_WAIT_DISPLAY_US); /* wait for some time not to write to the display while he may be busy with previous command */
#endif
#if McuHD44780_CONFIG_USE_DISPLAY_READ && McuHD44780_CONFIG_USE_DISPLAY_READ_CHECK_BUSY_FLAG
   McuHD44780_WaitForLCDReady();        /* Wait until LCD is ready */
#endif
   SetRS();                             /* RS = 1: data mode */
#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
   /* 2 4bit transfer */
   DataPut((uint8_t)((ch&0xF0)>>4));    /* Write the data (cycle #1) */
   EnablePulse();                       /* transfer data */
   Waitus(McuHD44780_CONFIG_WAIT_LCD_CMD_AFTER_4BIT_DATA1_US);
   DataPut((uint8_t)(ch&0x0F));         /* Write the data (cycle #2) */
   EnablePulse();                       /* do the command transfer */
   Waitus(McuHD44780_CONFIG_WAIT_LCD_CMD_AFTER_4BIT_DATA2_US);
#else
   /* 8bit data transfer */
   DataPut(ch);                         /* put data on bus */
   EnablePulse();                       /* do the command transfer */
#endif
   ClrRS();                             /* RS = 0: back to command mode */
}

/*
** ===================================================================
**     Method      :  GotoXY (component LCDHTA)
**
**     Description :
**         Places the cursor on a specified position on the display.
**     Parameters  :
**         NAME            - DESCRIPTION
**         line            - Line number starting with 1
**         column          - Column number starting with 1
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_GotoXY(uint8_t line, uint8_t column)
{
/* row is in the range 1..LCD_Nof_Lines and column in the range 1..LCD_Nof_Columns */
#if McuHD44780_CONFIG_LCD_NOF_LINES==1
  /* only one line in LCD: ignore line argument */
  (void)line;                           /* to avoid compiler warning about unused variable */
  McuHD44780_WriteLCDCommand((uint8_t)(GotoXYCmd + (column-1)));
#elif McuHD44780_CONFIG_LCD_NOF_LINES==2
  McuHD44780_WriteLCDCommand((uint8_t)(GotoXYCmd + (column-1) + (line==1 ? 0x00:Line2Offset)));
#elif McuHD44780_CONFIG_LCD_NOF_LINES==3
  uint8_t offset;

  if (line==1) {
    offset = 0x00;
  } else if (line==2) {
    offset = Line2Offset;
  } else { /* line 3 */
    offset = Line3Offset;
  }
  McuHD44780_WriteLCDCommand((uint8_t)(GotoXYCmd + (column-1) + offset));
#elif McuHD44780_CONFIG_LCD_NOF_LINES==4
  uint8_t offset;

  if (line==1) {
    offset = 0x00;
  } else if (line==2) {
    offset = Line2Offset;
  } else if (line==3) {
    offset = Line3Offset;
  } else { /* line 4 */
    offset = Line4Offset;
  }
  McuHD44780_WriteLCDCommand((uint8_t)(GotoXYCmd + (column-1) + offset));
#else
  #error "only up to 4 LCD lines are supported!"
#endif
}

/*
** ===================================================================
**     Method      :  ShiftLeft (component LCDHTA)
**
**     Description :
**         Shifts all characters to the left.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_ShiftLeft(void)
{
  McuHD44780_WriteLCDCommand(LeftShiftCmd);
}

/*
** ===================================================================
**     Method      :  Write (component LCDHTA)
**
**     Description :
**         Write a single character to the display
**     Parameters  :
**         NAME            - DESCRIPTION
**         ch              - Character to write
**     Returns     : Nothing
** ===================================================================
*/
/* The method is implemented as a macro, see McuHD44780.h */
/*
** ===================================================================
**     Method      :  WriteLn (component LCDHTA)
**
**     Description :
**         Writes a new line to the display
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_WriteLn(void)
{
#if McuHD44780_CONFIG_LCD_NOF_LINES==1
  /* only one line in LCD: move to beginning of first line */
  McuHD44780_WriteLCDCommand(FirstLineCmd);
#elif McuHD44780_CONFIG_LCD_NOF_LINES==2
  McuHD44780_WriteLCDCommand(SecondLineCmd);
#else
  /* more than 2 lines, cannot use WriteLn() */
#endif
}

/*
** ===================================================================
**     Method      :  WriteString (component LCDHTA)
**
**     Description :
**         Writes a string to the display at the current cursor
**         position.
**     Parameters  :
**         NAME            - DESCRIPTION
**       * str             - Pointer to string (zero byte terminated)
**                           to write to the display
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_WriteString(char *str)
{
  while (*str != '\0'){
    McuHD44780_Write(*str);
    str++;
  }
}

/*
** ===================================================================
**     Method      :  WriteLineStr (component LCDHTA)
**
**     Description :
**         Writes a full line to the display (clears the rest of the
**         line).
**     Parameters  :
**         NAME            - DESCRIPTION
**         line            - Line number (starting with 1).
**       * str             - Pointer to the string which should be
**                           shown on the display.
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_WriteLineStr(uint8_t line, char *str)
{
  uint8_t i;

  McuHD44780_Line(line);                /* select line */
  for(i = 0; i < McuHD44780_MAX_LCD_LINE_CHARS && *str!='\0'; i++, str++) {
    McuHD44780_Write(*str);
  }
  /* Clear the rest of the line */
  for (; i < McuHD44780_MAX_LCD_LINE_CHARS; i++) {
    McuHD44780_Write(' ');
  }
}

/*
** ===================================================================
**     Method      :  Line (component LCDHTA)
**
**     Description :
**         Sets the current line.
**     Parameters  :
**         NAME            - DESCRIPTION
**         line            - Line number, starting with 1
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_Line(uint8_t line)
{
#if McuHD44780_CONFIG_LCD_NOF_LINES==1
  /* we only have one line, so moving to the first line */
  (void)line;                           /* to avoid compiler warning about unused variable */
  McuHD44780_WriteLCDCommand(FirstLineCmd);
#elif McuHD44780_CONFIG_LCD_NOF_LINES==2
  McuHD44780_WriteLCDCommand((uint8_t)(line==1?FirstLineCmd:SecondLineCmd));
#elif McuHD44780_CONFIG_LCD_NOF_LINES==3
  if (line==1) {
    McuHD44780_WriteLCDCommand((uint8_t)(FirstLineCmd));
  } else if (line==2) {
    McuHD44780_WriteLCDCommand((uint8_t)(SecondLineCmd));
  } else { /* line == 3 */
    McuHD44780_WriteLCDCommand((uint8_t)(ThirdLineCmd));
  }
#elif McuHD44780_CONFIG_LCD_NOF_LINES==4
  if (line==1) {
    McuHD44780_WriteLCDCommand((uint8_t)(FirstLineCmd));
  } else if (line==2) {
    McuHD44780_WriteLCDCommand((uint8_t)(SecondLineCmd));
  } else if (line==3) {
    McuHD44780_WriteLCDCommand((uint8_t)(ThirdLineCmd));
  } else { /* line == 4 */
    McuHD44780_WriteLCDCommand((uint8_t)(FourthLineCmd));
  }
#else
  #error "only up to 4 LCD lines are supported!"
#endif
}

/*
** ===================================================================
**     Method      :  McuHD44780_Init (component LCDHTA)
**
**     Description :
**         This method is internal. It is used by Processor Expert only.
** ===================================================================
*/
void McuHD44780_Init(void)
{
  /* for non-Processor Expert projects, initialize the used pins */
#if McuLib_CONFIG_SDK_VERSION_USED != McuLib_CONFIG_SDK_PROCESSOR_EXPERT
  RS1_Init();
  EN1_Init();
  #if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==8
  DB01_Init();
  DB11_Init();
  DB21_Init();
  DB31_Init();
  #endif

  DB41_Init();
  DB51_Init();
  DB61_Init();
  DB71_Init();
  #if McuHD44780_CONFIG_USE_E2_SIGNAL
  EN2_Init();
  #endif
  #if McuHD44780_CONFIG_USE_RW_SIGNAL
  RW1_Init();
  #endif
#endif

  /* This function initializes the driver.
     The low level init already shall have set our data port to input/output, currently set to output,
     plus all control pins are set as outputs with low values. To be sure, we do it here again. */
  ClrEN();                              /* EN Pin low */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  ClrEN2();                             /* EN2 Pin low */
#endif
#if McuHD44780_CONFIG_USE_RW_SIGNAL
  ClrRW();                              /* RW Pin low */
#endif
  ClrRS();                              /* RS Pin low: command mode */
  DataPut(0);

  /* make pins output */
  DataAsOutput();

  /* send the reset sequence according to the data sheet */
  Waitms(80);                           /* wait for more than 15ms after Vcc rises to 4.5V, wait for more than 40ms after Vcc rises to 2.7V. In case of POR (Power On Reset) we need some additional time. */
#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
  DataPut(0x3);                         /* BF cannot be checked before this function, function set (interface is 8bits long) */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
  EnablePulse();                        /* transfer data */
  McuHD44780_UseDisplay(2);
  EnablePulse();                        /* transfer data */
#else
  EnablePulse();                        /* transfer data */
#endif
  Waitms(5);                            /* wait for more than 4.1 ms */
  /* 0x3 is already on the bus from previous DataPut(), do not need to put it again here */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
  EnablePulse();                        /* transfer data */
  McuHD44780_UseDisplay(2);
  EnablePulse();                        /* transfer data */
#else
  EnablePulse();                        /* transfer data */
#endif
  Waitus(100);                          /* wait for more than 100us */
  /* 0x3 is already on the bus from previous DataPut(), do not need to put it again here */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
  EnablePulse();                        /* transfer data */
  McuHD44780_UseDisplay(2);
  EnablePulse();                        /* transfer data */
#else
  EnablePulse();                        /* transfer data */
#endif
  Waitus(100);                          /* wait for more than 100us */

  DataPut(0x2);                         /* Function set */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
  EnablePulse();                        /* transfer data */
  McuHD44780_UseDisplay(2);
  EnablePulse();                        /* transfer data */
#else
  EnablePulse();                        /* transfer data */
#endif
  Waitus(100);
#else
  DataPut(FunctionSetCmd|FunctionSet_8bit); /* Function set (interface is 8bit) */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
  EnablePulse();                        /* transfer data */
  McuHD44780_UseDisplay(2);
  EnablePulse();                        /* transfer data */
#else
  EnablePulse();                        /* transfer data */
#endif
  Waitms(5);                            /* wait at least 4.1ms */
  /* transmit again the same data (which is already on the bus */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
  EnablePulse();                        /* transfer data */
  McuHD44780_UseDisplay(2);
  EnablePulse();                        /* transfer data */
#else
  EnablePulse();                        /* transfer data */
#endif
  Waitus(100);                          /* wait at least 100us */
  /* transmit again the same data (which is already on the bus */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
  EnablePulse();                        /* transfer data */
  McuHD44780_UseDisplay(2);
  EnablePulse();                        /* transfer data */
#else
  EnablePulse();                        /* transfer data */
#endif /* McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4 */
  Waitus(100);
#endif

#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
#endif
  McuHD44780_WriteLCDCommand(FunctionSetCmd|FunctionSet_Font5x8
#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
                 |FunctionSet_4bit      /* we are using 4bit data bus */
#else
                 |FunctionSet_8bit      /* we are using 8bit data bus */
#endif
             #if McuHD44780_CONFIG_LCD_NOF_LINES==1
                 |FunctionSet_1Line     /* we are using only one line */
             #else
                 |FunctionSet_2Lines    /* we are using two or more lines */
             #endif
                 );
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(2);
  McuHD44780_WriteLCDCommand(FunctionSetCmd|FunctionSet_Font5x8
#if McuHD44780_CONFIG_LCD_DATA_BUS_WIDTH==4
                 |FunctionSet_4bit      /* we are using 4bit data bus */
#else
                 |FunctionSet_8bit      /* we are using 8bit data bus */
#endif
             #if McuHD44780_CONFIG_LCD_NOF_LINES==1
                 |FunctionSet_1Line     /* we are using only one line */
             #else
                 |FunctionSet_2Lines    /* we are using two or more lines */
             #endif
                 );
#endif

  DisplayOnOffControlStatus = DisplayOnOffControlCmd|DisplayOnOffControl_DisplayOn; /* Display on, cursor on, do not blink */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
#endif
  McuHD44780_WriteLCDCommand(DisplayOnOffControlStatus);
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(2);
  McuHD44780_WriteLCDCommand(DisplayOnOffControlStatus);
#endif
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
#endif
  McuHD44780_WriteLCDCommand(ClearDisplayCmd); /* Clear display */
  McuHD44780_WriteLCDCommand(EntryModeSetCmd|EntryModeSet_IncrementOn); /* Entry mode set: Increment mode, display shift off */
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(2);
  McuHD44780_WriteLCDCommand(ClearDisplayCmd); /* Clear display */
  McuHD44780_WriteLCDCommand(EntryModeSetCmd|EntryModeSet_IncrementOn); /* Entry mode set: Increment mode, display shift off */
#endif
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  McuHD44780_UseDisplay(1);
#endif
}

/*
** ===================================================================
**     Method      :  LoadSoftChar (component LCDHTA)
**
**     Description :
**         Loads a user defined (softchar) into the display CGRAM.
**     Parameters  :
**         NAME            - DESCRIPTION
**         charCode        - The character code to be defined
**                           (0..7)
**       * softChar        - Pointer to an array of 8 bytes
**                           defining the soft character
**                           Example of the soft character 'ü':
**                           const byte SoftCharUE[8] = { // ü
**                           0x11, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0d, 0
**                           //  X...X
**                           //  .....
**                           //  X...X
**                           //  X...X
**                           //  X...X
**                           //  X..XX
**                           //  .XX.X
**                           };
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_LoadSoftChar(uint8_t charCode, uint8_t *softChar)
{
  /* Loads a user defined character (soft character, 5x8 dots) into the CG-RAM
     in the display. The character can be used afterwards like a normal character code */
  #define CGAddress 0x40                /* Base address for softchars */
  #define DDAddress 0x80                /* To finish the download mode */
  uint8_t i;

  McuHD44780_WriteLCDCommand((uint8_t)(CGAddress + (charCode * 0x08))); /* Set CG Ram: Character code * 0x08 [size] */
  for (i=0; i<=7; i++){
    McuHD44780_Write(softChar[i]);
  }
  McuHD44780_WriteLCDCommand(DDAddress); /* finish the download */
}

/*
** ===================================================================
**     Method      :  ShiftRight (component LCDHTA)
**
**     Description :
**         Shifts all characters to the right.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_ShiftRight(void)
{
  McuHD44780_WriteLCDCommand(RightShiftCmd);
}

/*
** ===================================================================
**     Method      :  CursorOn (component LCDHTA)
**
**     Description :
**         Enables the cursor.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_CursorOn(void)
{
  DisplayOnOffControlStatus |= DisplayOnOffControl_CursorOn;
  McuHD44780_WriteLCDCommand(DisplayOnOffControlStatus);
}

/*
** ===================================================================
**     Method      :  CursorOff (component LCDHTA)
**
**     Description :
**         Disables the cursor.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_CursorOff(void)
{
  DisplayOnOffControlStatus &= ~DisplayOnOffControl_CursorOn;
  McuHD44780_WriteLCDCommand(DisplayOnOffControlStatus);
}

/*
** ===================================================================
**     Method      :  DisplayOn (component LCDHTA)
**
**     Description :
**         Sends the display on command to the display.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_DisplayOn(void)
{
  DisplayOnOffControlStatus |= DisplayOnOffControl_DisplayOn;
  McuHD44780_WriteLCDCommand(DisplayOnOffControlStatus);
}

/*
** ===================================================================
**     Method      :  DisplayOff (component LCDHTA)
**
**     Description :
**         Sends the display off command to the display.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_DisplayOff(void)
{
  DisplayOnOffControlStatus &= ~DisplayOnOffControl_DisplayOn;
  McuHD44780_WriteLCDCommand(DisplayOnOffControlStatus);
}

/*
** ===================================================================
**     Method      :  BlinkingOn (component LCDHTA)
**
**     Description :
**         Sends the display off command to the display.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_BlinkingOn(void)
{
  DisplayOnOffControlStatus |= DisplayOnOffControl_BlinkOn;
  McuHD44780_WriteLCDCommand(DisplayOnOffControlStatus);
}

/*
** ===================================================================
**     Method      :  BlinkingOff (component LCDHTA)
**
**     Description :
**         Puts the display in blinking off mode.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_BlinkingOff(void)
{
  DisplayOnOffControlStatus &= ~DisplayOnOffControl_BlinkOn;
  McuHD44780_WriteLCDCommand(DisplayOnOffControlStatus);
}

/*
** ===================================================================
**     Method      :  SetEntryMode (component LCDHTA)
**
**     Description :
**         Configures the display entry mode, if the cursor has to
**         shift and/or if the display shall shift content while
**         displaying text.
**     Parameters  :
**         NAME            - DESCRIPTION
**         increment       - Increments (TRUE) or
**                           decrements (FALSE) the display address by 1
**                           when a character code is written into or
**                           read from DDRAM. The cursor or blinking
**                           moves to the right when incremented by 1
**                           and to the left when decremented by 1.
**         shiftLeft       - The display does not shift if
**                           the 'shift' is FALSE. If 'shift' is TRUE,
**                           it will seem as if the cursor does not move
**                           but the display does.
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_SetEntryMode(bool increment, bool shiftLeft)
{
  uint8_t flags = 0;

  if (increment) {
    flags |= EntryModeSet_IncrementOn;
  }
  if (shiftLeft) {
    flags |= EntryModeSet_ShiftOn;
  }
  McuHD44780_WriteLCDCommand((uint8_t)(EntryModeSetCmd|flags)); /* Entry mode set: Increment mode, display shift mode */
}

/*
** ===================================================================
**     Method      :  UseDisplay (component LCDHTA)
**
**     Description :
**         
**     Parameters  :
**         NAME            - DESCRIPTION
**         display         - Has to be either 1 (top display,
**                           using E1) or 2 (bottom display, using E2)
**     Returns     :
**         ---             - Error code
** ===================================================================
*/
uint8_t McuHD44780_UseDisplay(uint8_t display)
{
#if McuHD44780_CONFIG_USE_E2_SIGNAL
  if (!(display==1 || display==2)) {
    return ERR_FAILED; /* wrong argument */
  }
  McuHD44780_currDisplay = display;
#else
  (void)display; /* not used, as not using E2 (additional enable) signal */
#endif
  return ERR_OK;
}

/*
** ===================================================================
**     Method      :  CursorShiftRight (component LCDHTA)
**
**     Description :
**         Shift the cursor to the right.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_CursorShiftRight(void)
{
  McuHD44780_WriteLCDCommand(RightShiftCursor);
}

/*
** ===================================================================
**     Method      :  CursorShiftLeft (component LCDHTA)
**
**     Description :
**         Shift the cursor to the left.
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_CursorShiftLeft(void)
{
  McuHD44780_WriteLCDCommand(LeftShiftCursor);
}

/*
** ===================================================================
**     Method      :  DeInit (component LCDHTA)
**
**     Description :
**         Driver de-initialization routine
**     Parameters  : None
**     Returns     : Nothing
** ===================================================================
*/
void McuHD44780_DeInit(void)
{
  /* nothing needed */
}

/* END McuHD44780. */

/*!
** @}
*/
