/*
Copyright (c) 2013 - 2015 released Microchip Technology Inc.  All rights reserved.

Microchip licenses to you the right to use, modify, copy and distribute
Software only when embedded on a Microchip microcontroller or digital signal
controller that is integrated into your product or third party product
(pursuant to the sublicense terms in the accompanying license agreement).

You should refer to the license agreement accompanying this Software for
additional information regarding your rights and obligations.

SOFTWARE AND DOCUMENTATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF
MERCHANTABILITY, TITLE, NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL MICROCHIP OR ITS LICENSORS BE LIABLE OR OBLIGATED UNDER
CONTRACT, NEGLIGENCE, STRICT LIABILITY, CONTRIBUTION, BREACH OF WARRANTY, OR
OTHER LEGAL EQUITABLE THEORY ANY DIRECT OR INDIRECT DAMAGES OR EXPENSES
INCLUDING BUT NOT LIMITED TO ANY INCIDENTAL, SPECIAL, INDIRECT, PUNITIVE OR
CONSEQUENTIAL DAMAGES, LOST PROFITS OR LOST DATA, COST OF PROCUREMENT OF
SUBSTITUTE GOODS, TECHNOLOGY, SERVICES, OR ANY CLAIMS BY THIRD PARTIES
(INCLUDING BUT NOT LIMITED TO ANY DEFENSE THEREOF), OR OTHER SIMILAR COSTS.
 */


#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#include "lcd.h"
#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/pin_manager.h"

/* 
Function: 
void WriteIOExpd (uint8_t reg, uint8_t data)

Description: 
 * Function used to write a byte to the IO expander
  */
void WriteIOExpd (uint8_t reg, uint8_t data)
{
          LCD_CHIP_SELECT_SetLow();
          SPI_Exchange8bit(IO_EXPD_ADDR);
          SPI_Exchange8bit(reg);           // Select the required register
          SPI_Exchange8bit(data);          // Write the data
          LCD_CHIP_SELECT_SetHigh(); 
}

/* 
Function: 
void WriteLcdCommand(uint8_t cmd)

Description: 
 * Function used to write a command to the LCD screen
  */
void WriteLcdCommand(uint8_t cmd)
{
          WriteIOExpd(GPIO_A,0x60);    //RS LOW -- E HIGH -- LCD Enabled 

          WriteIOExpd(GPIO_B,cmd);     // Write the command on PORT B

          WriteIOExpd(GPIO_A,0x20);    //RS LOW -- E LOW -- LCD Enabled
}

/* 
Function: 
void WriteLcdByte(uint8_t data)

Description: 
 * Function used to write a byte on the LCD screen
  */
void WriteLcdByte(uint8_t data)
{
          WriteIOExpd(GPIO_A,0xE0);    //RS HIGH -- E HIGH -- LCD Enabled --> This is to choose the data register on the LCD

          WriteIOExpd(GPIO_B,data);    //Write the byte on PORT B

          WriteIOExpd(GPIO_A,0xA0);    //RS HIGH -- E LOW -- LCD enabled --> This is to latch the data on the LCD
}

/* 
Function: 
void WriteLcdString(char *data)

Description: 
 * Function used to write a string on the LCD screen
  */
void WriteLcdString(char *data)
{
    uint8_t i=0;
    while(data[i])
    {
        WriteLcdByte(data[i++]);
    }
}

/* 
Function: 
void LcdClear (void)

Description: 
 * Function used to clear the LCD screen
  */
void LcdClear(void)
{
    WriteLcdCommand(0x01);            // 0x01 is the command to clear the LCD Display
    LcdGoto(0,0);
}

/* 
Function: 
void LcdGoto (uint8_t row, uint8_t column)

Description: 
 * Function used to move the LCD cursor
  */
void LcdGoto(uint8_t row, uint8_t column)
{
    if (row<2)
        {
        uint8_t pos = (row == 0) ? (0x80 | column) : (0xC0 | column);       // 0x80 is the start address of Line 1 and 0xC0 for Line 2
        WriteLcdCommand(pos);
        }

}

/* 
Function: 
void LCDInitialization (void)

Description: 
 * Function used to initialize the LCD
  */
void LcdInitialization (void)
{
    RC3PPSbits.RC3PPS = 0x10;   //RC3->MSSP:SCK;
    
    WriteIOExpd(IO_DIR_A,0x00);   // Make PORT A as output
    WriteIOExpd(IO_DIR_B,0x00);   // Make PORT B as output

    WriteIOExpd(GPIO_A,0x20);     // Enable VDD for the LCD panel
    __delay_ms(10);      // delay required to correctly initialize the LCD

    WriteLcdCommand(0x3C);
    __delay_ms(10);

    WriteLcdCommand(0x0C);
    __delay_ms(10);

    WriteLcdCommand(0x01); // Clear the display
    __delay_ms(10);

    WriteLcdCommand(0x0C);
    __delay_ms(130);    // Delay required to let the LCD initialize correctly

    WriteLcdCommand(0x80);
    __delay_ms(1);
}

/**
 * <B>Permet de créer jusqu'à 8 caractères personnalisés dans la CGRAM</B>
 * 
 * <B>Prototype : </B><CODE>void LcdCreateChar(uint8_t location, uint8_t charmap[]);</CODE>
 * 
 * @param location : Entre 0 et 7, emplacement dans la CGRAM
 * @param charmap[] : Tableau de 8 octets dans lequel est dessiné la matrice 5x8 du caractère
 *
 * @Example
 * <CODE>
 * //Tableau 5x8 contenant le caractère personnalisé<BR> 
 * uint8_t coeur[] = {
 *    0b00000,
 *    0b01010,
 *    0b11111,
 *    0b11111,
 *    0b11111,
 *    0b01110,
 *    0b00100,
 *    0b00000
 * };<BR><BR> 
 * // Création du caractère personalisé dans la CGRAM de l'afficheur<BR> 
 * LcdCreateChar(0, coeur);<BR><BR> 
 * // Affichage du caractère personalisé<BR> 
 * WriteLcdByte(0);
 * </CODE>
 */
void LcdCreateChar(uint8_t location, uint8_t charmap[]) {
  location &= 0x7;  // Pour être sûr de limiter aux 8 premières
  WriteLcdCommand(LCD_SETCGRAMADDR | (location << 3));
  for (int i=0; i<8; i++) {
    WriteLcdByte(charmap[i]);
  }
}

/**
 * <B>Décale l'ensemble de l'affiichage d'un caractère vers la droite</B>
 * 
 */
void LcdScrollDisplayRight(void) {
  WriteLcdCommand(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT);
}

/**
 * <B>Décale l'ensemble de l'affiichage d'un caractère vers la gauche</B>
 * 
 */
void LcdScrollDisplayLeft(void) {
  WriteLcdCommand(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT);
}
