/********************************************/
/* TFT Display Code for HX8357-B Controller */
/*PIC32MX795F512L-80I/PF                    */
/********************************************/

#include "xc.h"
#include "HX8357B.h"
#include "CourierNew16.h"
#include "Delay.h"

void Backlight_Control(int back_level)
{   
    //PWM Setup for backlight control
    //sets frequency
    PR2 = 300;
    
    OC1CONbits.OCTSEL = 0;  //select TMR2
    OC1CONbits.OCM = 6;     //PWM mode, no fault pin
    OC1CONbits.ON = 1;

    //specifies duty cycle in percent
    if(back_level <= 10 | back_level >= 0)
    {
        back_level = back_level * (PR2 / 10);
        
        //sets the duty cycle
        OC1RS = back_level;
    }

    T2CONbits.ON = 1;
    
    return;
}

void HX8357B_Init(void)
{
    //Configure Pin for D/C
    TRISFbits.TRISF3 = 0;

    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //Software RESET
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    PMDIN = 0x01;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    //>120mS Delay
    //to allow display to complete reset
    //set Timer 5 prescaler /256
    T5CONbits.TCKPS = 7;
    Delay(65535);
    T5CONbits.TCKPS = 0;
    
     //Select Display (/CS)    
    PORTFbits.RF13 = 0;
    
    //SLPOUT
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    PMDIN = 0x011;
    while(PMMODEbits.BUSY == 1);

    //Set pixel color mode = 16-bit
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    PMDIN = 0x03a;
    while(PMMODEbits.BUSY == 1);
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    PMDIN = 0x05;
    while(PMMODEbits.BUSY == 1);
    
    //Set Screen Rotation
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //MADCTL
    PMDIN = 0x036;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    //D7 (MY)
    //D6 (MX)
    //D5 (MV)
    //D4 (ML)
    //D3 (RGB) 1=BGR. 0=RGB
    //D2 (reserved)
    //D1 (SS)
    //D0 (GS)
    //0x28 = wide screen, connector on righthand side
    //0xe8 = wide screen, connector on Lefthand side
    PMDIN = 0x28;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//00h - no operation
void HX8357B_NOP(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 00h = NOP
    PMDIN = 0x00;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//01 - software reset
void HX8357B_SWRESET(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 01h = SWRESET
    PMDIN = 0x01;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//0Ah - read power mode
void HX8357B_RDDPM(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 0ah = RDDPM
    PMDIN = 0x0a;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //Dummy Read
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    //Read Display Data
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//0Bh - read display MADCTL
void HX8357B_RDDMADCTL(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 0bh = RDDPM
    PMDIN = 0x0b;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //Dummy Read
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    //Read Display Data
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//0Ch - get pixel format
void HX8357B_RDDCOLMOD(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 0ch = RDDCOLMOD
    PMDIN = 0x0c;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //Dummy Read
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    //Read Display Data
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//0Dh - get display mode
void HX8357B_RDDIM(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 0dh = RDDIM
    PMDIN = 0x0d;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //Dummy Read
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    //Read Display Data
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//0Eh - get signal mode
void HX8357B_RDDSM(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 0eh = RDDSM
    PMDIN = 0x0e;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //Dummy Read
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    //Read Display Data
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//0Fh - get diagnostic result
void HX8357B_RDDSDR(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 0fh = RDDSDR
    PMDIN = 0x0f;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //Dummy Read
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    //Read Display Data
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//10h - enter sleep mode
void HX8357B_SLPIN(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 10h = SLPIN
    PMDIN = 0x10;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//11h - exit sleep mode
void HX8357B_SLPOUT(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 11h = SLPOUT
    PMDIN = 0x11;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//12h - enter partial mode
void HX8357B_PTLON(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 12h = PTLON
    PMDIN = 0x12;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//13h - enter normal mode
void HX8357B_NORON(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 13h = NORON
    PMDIN = 0x13;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//20h - exit inversion mode
void HX8357B_INVOFF(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 20h = INVOFF
    PMDIN = 0x20;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//21h - exit inversion mode
void HX8357B_INVON(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 21h = INVON
    PMDIN = 0x21;
    while(PMMODEbits.BUSY == 1);
    
     //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
   return;
}

//28h - display off
void HX8357B_DISPOFF(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 28h = DSPOFF
    PMDIN = 0x28;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//29h - display on
void HX8357B_DISPON(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 29h = DISPON
    PMDIN = 0x29;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//2a - set column address
void HX8357B_CASET(int col_start, int col_end)
{
    if(col_end == 0)
    {
        col_end = col_start + 15;
    }
        
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    PMDIN = 0x02a;
    while(PMMODEbits.BUSY == 1);
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    //break in to bytes HI and LO
    //Column Start
    //HI
    if(col_start > 0xff)
    {
        PMDIN = 1;       
    }
    else
    {
        PMDIN = 0;               
    }
    while(PMMODEbits.BUSY == 1);
    //LO
    PMDIN = col_start;
    while(PMMODEbits.BUSY == 1);
    
    //Column End
    //HI
    if(col_end > 0xff)
    {
        PMDIN = 1;       
    }
    else
    {
        PMDIN = 0;               
    }
    while(PMMODEbits.BUSY == 1);
    //LO
    PMDIN = col_end;
    while(PMMODEbits.BUSY == 1);
        
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//2Bh - set row address
void HX8357B_RASET(int row_start, int row_end)
{
    if(row_end == 0)
    {
        row_end = row_start + 21;
    }
        
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    PMDIN = 0x02b;
    while(PMMODEbits.BUSY == 1);
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    //break in to bytes HI and LO
    //Row Start
    //HI
    if(row_start > 0xff)
    {
        PMDIN = 1;       
    }
    else
    {
        PMDIN = 0;               
    }
    while(PMMODEbits.BUSY == 1);
    //LO
    PMDIN = row_start;
    while(PMMODEbits.BUSY == 1);
    
    //Row End
    //HI
    if(row_end > 0xff)
    {
        PMDIN = 1;       
    }
    else
    {
        PMDIN = 0;               
    }
    while(PMMODEbits.BUSY == 1);
    //LO
    PMDIN = row_end;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//2Ch - memory write
void HX8357B_RAMWR(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 2Ch = RAMWR
    PMDIN = 0x2C;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //pixel data is then written here
    //until another command is given
    
    //Select Display (/CS)    
    //PORTFbits.RF13 = 1;
            
    return;
}

//2Eh - memory read
void HX8357B_RAMRD(void)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 2eh = RDDSM
    PMDIN = 0x2e;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //Dummy Read
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    //Read Display Data
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

//BFh - get device ID
void HX8357B_GETDEVICEID(void)
{
    int temp;
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command bfh = RDDSDR
    PMDIN = 0xbf;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //Dummy Read
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    //MIPI Alliance code
    Display_Read = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    Display_Read = Display_Read << 8;
    
    temp = PMDIN;
    while(PMMODEbits.BUSY == 1);

    Display_Read = temp + Display_Read;
    Display_Read = Display_Read << 8;

    //Device ID code
    temp = PMDIN;
    while(PMMODEbits.BUSY == 1);
    
    Display_Read = temp + Display_Read;
    Display_Read = Display_Read << 8;

    temp = PMDIN;
    while(PMMODEbits.BUSY == 1);

    Display_Read = temp + Display_Read;
    Display_Read = Display_Read << 8;

    //single-byte Escape or Exit Code (0xFF)
    temp = PMDIN;
    while(PMMODEbits.BUSY == 1);

    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

void HX8357B_Rect(int col_start, int col_end, int row_start, int row_end, int rect_color)
{
    int i;

    HX8357B_CASET(col_start, col_end - 1);    
    HX8357B_RASET(row_start, row_end - 1);
            
    HX8357B_RAMWR();
            
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    for(i=0;i<(col_end - col_start) * (row_end - row_start); i++)
    {
        PMDIN = ~rect_color;
        while(PMMODEbits.BUSY == 1);
    }    
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
            
    return;
}

void HX8357B_CLRSCN(int back_color)
{
    //Column set
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    PMDIN = 0x02a;
    while(PMMODEbits.BUSY == 1);
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    PMDIN = 0;
    while(PMMODEbits.BUSY == 1);
    PMDIN = 0;
    while(PMMODEbits.BUSY == 1);
    PMDIN = 0x01;
    while(PMMODEbits.BUSY == 1);
    PMDIN = 0xdf;
    while(PMMODEbits.BUSY == 1);

    //row set
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    PMDIN = 0x02b;
    while(PMMODEbits.BUSY == 1);
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    PMDIN = 0;
    while(PMMODEbits.BUSY == 1);
    PMDIN = 0;
    while(PMMODEbits.BUSY == 1);
    PMDIN = 0x01;
    while(PMMODEbits.BUSY == 1);
    PMDIN = 0x40;
    while(PMMODEbits.BUSY == 1);

    int i;
    //Command
    PORTFbits.RF3 = 0;                     
    //Write RAM
    PMDIN = 0x02c;
    while(PMMODEbits.BUSY == 1);

    //Data
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;                    
    for(i=0;i<=153600; i++)
    {
        PMDIN = ~back_color;
        while(PMMODEbits.BUSY == 1);       
    }
        
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    return;
}

//Writes a character to the screen
void WriteChar(int col_start, int row_start, int ascii_char, int fore_color)
{
   
    //Makes sure no out of bounds
    if(ascii_char > 0x7F || ascii_char < 0)
    {
        ascii_char = 0x2a;
    }
    
    int x;
    int text_char = ascii_char - 32;
    int off_set = lut[text_char];
    int read = courier_new_16pt_bold[off_set];
    int a = 0b10000000;
    int pixel = 0;
    int s = 0;
    int i;
    
    col_end = col_start + 15;
    row_end = row_start + 21;
    HX8357B_CASET(col_start, col_end);
    HX8357B_RASET(row_start, row_end);
    
    HX8357B_RAMWR();
    
    for(s=0;s<=45;s++)
    {
        for(i=0;i<=7;i++)
        {
            x = read & a;
            if(x > 0)
            {
                pixel = ~fore_color;
            }
            else
            {
                pixel = ~back_color;
            }

            //Select Display (/CS)    
            PORTFbits.RF13 = 0;
            
            PMDIN = pixel;
            while(PMMODEbits.BUSY == 1);

            //Select Display (/CS)    
            PORTFbits.RF13 = 1;
            
            a=a/2;
        }
        off_set++;
        read = courier_new_16pt_bold[off_set];
        a = 0b10000000;
    }
    //this keeps track of the horizontal position.
    //col_count = col_count + 15;
    hchar = hchar + 15;
    return;
}

//Writes a string to the screen
//Write_String(column start, row start, string index, name of the array, name of the offset array)
void Write_String(int col_start, int row_start, int fore_color, int string_index, const unsigned char  the_array[], const uint16_t array_offset[])
{
    int offset = array_offset[string_index];
    int test_char = the_array[offset];
    HX8357B_RASET(row_start, row_start + 21);

    while(test_char != 0)
    {       
        HX8357B_CASET(col_start, col_start + 15);
        
        test_char = the_array[offset];
        
        //Prevents extra space at end of string
        if(test_char != 0)
        {
            WriteChar(col_start, row_start, test_char, fore_color);    
            offset++;       
            col_start = col_start + 15;
        }
    }
    
    return;
}

