//##############################################################################
//    filename:        LCD_lib_busy.c
//##############################################################################
//    LCD library for HD44780,ST7036,SPLC782A  ...
//##############################################################################
//      Author:            	V.SchK
//      Company:        	HS-Ulm
//      Adapted:            AS
//      Revision:        	2.0 (for XC8)
//      Date:         		April 2020
//     	Compiler            XC8 v2.10
//      MPLAB X             v5.35
//      MCC                 v3.95
//##############################################################################

//#define FOSC    8000000UL
//#define FCY     (FOSC/2)
#include "LCD_lib_busy.h"
//#include <xc.h>
//#include "Digital_Preamp.h"
#include "definitions.h"                // SYS function prototypes


union LCDv8bit LCD_data;         // bitfield variable (bitwise acess)
unsigned short LCD_busy_cnt;

// -------------------- LCD-functions ------------------------------------------
#ifdef LCD_ON
void LCD_On (void)
{
    LCD_ON = 1;
    LCD_ON_DIR = 0;
#warning DO NOT FORGET TO SWITCH ON THE DISPLAY IF CONTROLLED BY MCU !
}
#endif

void LCD_Init (void)
{
    LCD_RW = 0; LCD_RW_DIR = 0;
    LCD_RS = 0; LCD_RS_DIR = 0;
    ShortDelay1us(); 
    LCD_E  = 0; LCD_E_DIR  = 0;
    ShortDelay1us(); 

    LCD_D4_OUT = 0; LCD_D4_DIR = 0;
    LCD_D5_OUT = 0; LCD_D5_DIR = 0;
    LCD_D6_OUT = 0; LCD_D6_DIR = 0;
    LCD_D7_OUT = 0; LCD_D7_DIR = 0;

    LCD_busy_cnt = 1;		// busy_flag time out counter

    LCD_DELAY_15MS()              // wait for 15ms  //ASO
// display reset procedure
    LCD_Write_Nibble(LCD_RESET);    LCD_DELAY_5MS();
    LCD_Write_Nibble(LCD_RESET);    LCD_DELAY_100US();
    LCD_Write_Nibble(LCD_RESET);    LCD_DELAY_5MS(); //ASO
    while (LCD_Busy()) {;}          // wait
// set 4-bit mode always !!!
    LCD_Write_Nibble(FOUR_BIT);   while (LCD_Busy()) {;} // wait


    
#if defined EXT_LCD_3_3_V
    LCD_Command(FOUR_BIT_TWO_LINE + EXT_INSTR_TBL_1);
    LCD_Command(EXT1_BIAS_1_5);
    LCD_Command(EXT1_CONTRAST + 0x0C);
    LCD_Command(EXT1_BOOST_ICON_C + BOOST_ON + 1);
    LCD_Command(EXT1_FOLLOWER + FOLLOWER_ON + 5);
#elif defined EXT_LCD_5_V
    LCD_Command(FOUR_BIT_TWO_LINE + EXT_INSTR_TBL_1);
    LCD_Command(EXT1_BIAS_1_4);
    LCD_Command(EXT1_CONTRAST + 0x04);
    LCD_Command(EXT1_BOOST_ICON_C + BOOST_OFF + 2);
    LCD_Command(EXT1_FOLLOWER + FOLLOWER_ON + 1);
#else
    LCD_Command(FOUR_BIT_TWO_LINE);
    LCD_Command_Delay();
#endif

    LCD_Command(DISPLAY_CTRL + DISPLAY_ON);// + BLINK_ON);
    LCD_Command_Delay();
    LCD_Command(ENTRY_MODE + CURSOR_INC + DSHIFT_OFF);
    LCD_Command_Delay();
    LCD_Command(CLEAR_DISPLAY);
    LCD_Command_Delay();
    LCD_Command(RETURN_HOME);
    LCD_Command_Delay();
}
// --------------------------------------------------------------
void LCD_SignalsTest()
{
    LCD_RS_DIR = 0;
    LCD_RW_DIR = 0;
    LCD_E_DIR = 0;
    LCD_D4_DIR = 0;
    LCD_D5_DIR = 0;
    LCD_D6_DIR = 0;
    LCD_D7_DIR = 0;

    LCD_RS = 1;
    LCD_RW = 1;
    LCD_ENABLE();
    LCD_D4_OUT = 1;
    LCD_D5_OUT = 1;
    LCD_D6_OUT = 1;
    LCD_D7_OUT = 1;

    LCD_RS = 0;
    LCD_RW = 0;
    LCD_DISABLE();
    LCD_D4_OUT = 0;
    LCD_D5_OUT = 0;
    LCD_D6_OUT = 0;
    LCD_D7_OUT = 0;
}

//****************************************************************************
//     _    ______________________________
// RS  _>--<______________________________
//     _____
// RW       \_____________________________
//                  __________________
// E   ____________/                  \___
//     _____________                ______
// DB  _____________>--------------<______

void LCD_Write_Nibble(unsigned char value)
{
    LCD_data.all = value;
    LCD_RS = LCD_CMD;
    LCD_RW = LCD_WR;

    LCD_D4_OUT = LCD_data.bit4;
    LCD_D5_OUT = LCD_data.bit5;
    LCD_D6_OUT = LCD_data.bit6;
    LCD_D7_OUT = LCD_data.bit7;
    LCD_STROBE();
}
// --------------------------------------------------------------
void LCD_Write(unsigned char value) // command or data
{
    LCD_data.all = value;
    LCD_RW = LCD_WR;

    LCD_D7_OUT = LCD_data.bit7;
    LCD_D6_OUT = LCD_data.bit6;
    LCD_D5_OUT = LCD_data.bit5;
    LCD_D4_OUT = LCD_data.bit4;
    LCD_STROBE();

    LCD_D7_OUT = LCD_data.bit3;
    LCD_D6_OUT = LCD_data.bit2;
    LCD_D5_OUT = LCD_data.bit1;
    LCD_D4_OUT = LCD_data.bit0;
    LCD_STROBE();
}
// --------------------------------------------------------------
void LCD_ValueOut_00(unsigned char row, unsigned char col, short value,
                     unsigned char min_dig)
{
    char chBuffer, leading_0;

    LCD_Command(CURSOR_ADDR + (LINE_OFFSET * row) + col);
    leading_0 = 1;

    if (value < 0)
    {
        chBuffer = '-';
        LCD_CharOut(chBuffer);
        value = -value;
    }
    else if(!leading_0 &&(min_dig == 1))
    {
        chBuffer = ' ';
        LCD_CharOut(chBuffer);
    }
    chBuffer = value / 10000;
    if(leading_0){
        if((chBuffer != 0)||(min_dig == 5)) leading_0 = 0;
    }
    if(!leading_0){
        LCD_CharOut(chBuffer +0x30);
    }
    value = value - (10000 * chBuffer);
    chBuffer = value / 1000;
    if(leading_0){
        if((chBuffer != 0)||(min_dig == 4)) leading_0 = 0;
    }
    if(!leading_0){
        LCD_CharOut(chBuffer +0x30);
    }
    value = value - (1000 * chBuffer);
    chBuffer = value / 100;
    if(leading_0){
        if((chBuffer != 0)||(min_dig == 3)) leading_0 = 0;
    }
    if(!leading_0){
        LCD_CharOut(chBuffer +0x30);
    }
    value = value - ((short)100 * chBuffer);
    chBuffer = value  / 10;
    if(leading_0){
        if((chBuffer != 0)||(min_dig == 2)) leading_0 = 0;
    }
    if(!leading_0){
        LCD_CharOut(chBuffer +0x30);
    }
    value = value - ((short)10 * chBuffer);
    chBuffer = value;
    LCD_CharOut(chBuffer +0x30);
}
// --------------------------------------------------------------
void LCD_ConstTextOut(unsigned char row, unsigned char col, const char *text)
{
    int Char_count = 0;

    LCD_Command(CURSOR_ADDR + (LINE_OFFSET *  row) +  col);
    while ((*text) && (Char_count < 16)) {
        LCD_CharOut(*text);
        text++;
        Char_count++;
    }
}
// --------------------------------------------------------------
void LCD_TextOut(unsigned char row, unsigned char col, unsigned char *text)
{
    int Char_count = 0;
    
    LCD_Command(CURSOR_ADDR + (LINE_OFFSET * row) +  col);
    while ((*text) && (Char_count < 16)) 
    {
        LCD_CharOut(*text);
        text++;
        Char_count++;
    }
}
// --------------------------------------------------------------

//unsigned char LCD_Read(void)
//{
//    LCD_D4_DIR = 1;
//    LCD_D5_DIR = 1;
//    LCD_D6_DIR = 1;
//    LCD_D7_DIR = 1;
//    LCD_RW = LCD_RD; // Set read mode
//
//    LCD_ENABLE(); LCD_DELAY_1US();
//    LCD_data.bit7 = LCD_D7_IN;
//    LCD_data.bit6 = LCD_D6_IN;
//    LCD_data.bit5 = LCD_D5_IN;
//    LCD_data.bit4 = LCD_D4_IN;
//    LCD_DISABLE();
//
//    LCD_ENABLE(); LCD_DELAY_1US();
//    LCD_data.bit3 = LCD_D7_IN;
//    LCD_data.bit2 = LCD_D6_IN;
//    LCD_data.bit1 = LCD_D5_IN;
//    LCD_data.bit0 = LCD_D4_IN;
//    LCD_DISABLE();
//
//    return LCD_data.all;
//}

unsigned char LCD_Busy(void)
{
    if (LCD_busy_cnt >= LCD_TIMEOUT)
    {
        LCD_busy_cnt = 1;
        return 0;                   // return -1 for time out ???????????????
    }

    LCD_RW = LCD_RD;
    LCD_RS = LCD_CMD;
    LCD_D4_DIR = 1; LCD_D5_DIR = 1; LCD_D6_DIR = 1; LCD_D7_DIR = 1;

    LCD_ENABLE(); LCD_DELAY_1US();
    LCD_data.bit7 = LCD_D7_IN;
    LCD_DISABLE();LCD_DELAY_1US();
    LCD_ENABLE(); LCD_DELAY_1US();
    LCD_data.bit3 = LCD_D7_IN;
    LCD_DISABLE();LCD_DELAY_1US();

    LCD_D4_DIR = 0; LCD_D5_DIR = 0; LCD_D6_DIR = 0; LCD_D7_DIR = 0;
    LCD_RW = LCD_WR;

    if (LCD_data.bit7 == LCD_BUSY) 
    {
        LCD_busy_cnt++;
        return 1;
    } else {
        LCD_busy_cnt = 1;
        return 0;
    }
}
//==============================================================================
void LCD_Clear_Line1(void)
{
    LCD_ConstTextOut(0,0,"                ");   // could be optimized
}

void LCD_Clear_Line2(void)
{
    LCD_ConstTextOut(1,0,"                ");   // could be optimized
}

void LCD_Start(void)
{
//    LCD_On();           // for PICDEM2+ RD7 controls LCD power supply    
    DelayAfterPowerOn(); 
    CORETIMER_DelayMs (15);   // depend upon LCD controller 
    LCD_Init();
    CORETIMER_DelayMs (15);
}

// -------------------- END LCD-functions ---------------------------
