/************************************************/
/*TFT Display Code for ILI9488 Controller       */
/*Version 1                                     */
/*Changed WriteSystemString() Function          */
/*PIC32MX795F512L-80I                           */
/*PIC32MX695F512L-80I                           */
/************************************************/

#include <xc.h>

#include "MainBrain.h"

unsigned char back_level;
int fore_color;
volatile uint16_t back_color;
unsigned hchar;
unsigned vchar;
unsigned Display_Read;
unsigned row_start;
unsigned row_end;
unsigned col_start;
unsigned col_end;
int t;

void Backlight_Control(unsigned char 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))
    {
        if(back_level == 0)
        {
            OC1RS = 300;
        }
        if(back_level == 1)
        {
            OC1RS = 270;
        }
        if(back_level == 2)
        {
            OC1RS = 243;
        }
        if(back_level == 3)
        {
            OC1RS = 216;
        }
        if(back_level == 4)
        {
            OC1RS = 189;
        }
        if(back_level == 5)
        {
            OC1RS = 162;
        }
        if(back_level == 6)
        {
            OC1RS = 135;
        }
        if(back_level == 7)
        {
            OC1RS = 108;
        }
        if(back_level == 8)
        {
            OC1RS = 81;
        }
        if(back_level == 9)
        {
            OC1RS = 54;
        }
        if(back_level == 10)
        {
            OC1RS = 27;
        }
        
    }
    
    T2CONbits.ON = 1;
    
    return;
}

void Speaker_Control(unsigned freq)
{   
    //PWM Setup for speaker control
    //sets frequency
    PR3 = freq;
    
    OC2CONbits.OCTSEL = 1;  //select TMR3
    OC2CONbits.OCM = 6;     //PWM mode, no fault pin
    OC2CONbits.ON = 1;

    OC2RS = PR3 / 2;
    

    if(freq != 0)
    {
        T3CONbits.ON = 1;
    }
    
    return;
}

void ILI9488_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 format = 16-bit
    //05h = 16-bit
    //06h = 18-bit
    //07h = 24-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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_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 - enter inversion mode
void ILI9488_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 ILI9488_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 ILI9488_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 ILI9488_CASET(unsigned col_start, unsigned 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 ILI9488_RASET(unsigned row_start, unsigned 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 ILI9488_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 ILI9488_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;
}

//30h - Set_partial_area
void ILI9488_PLTAR(unsigned SR_HI, unsigned SR_LO, unsigned ER_HI, unsigned ER_LO)
{
    //Select Display (/CS)    
    PORTFbits.RF13 = 0;
            
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 0;
    
    //Command 30h
    PMDIN = 0x30;
    while(PMMODEbits.BUSY == 1);
    
    //RF3 = D/C 1=Data, 0=Command
    PORTFbits.RF3 = 1;
    
    //Upper byte start row
    PMDIN = SR_HI;
    while(PMMODEbits.BUSY == 1);
    
    //Lower byte start row
    PMDIN = SR_LO;
    while(PMMODEbits.BUSY == 1);
    
    //Upper byte end row
    PMDIN = ER_HI;
    while(PMMODEbits.BUSY == 1);
    
    //Upper byte end row
    PMDIN = ER_LO;
    while(PMMODEbits.BUSY == 1);
    
    //Select Display (/CS)    
    PORTFbits.RF13 = 1;
                
    return;
}

//BFh - get device ID
void ILI9488_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;
}

//draws a rectangular block of colored pixels
void ILI9488_Rect(unsigned col_start, unsigned col_end, unsigned row_start, unsigned row_end, unsigned rect_color)
{
    int i;
    
    unsigned a = col_start;
    unsigned b = row_start;
    unsigned c = col_end;
    unsigned d = row_end;
    
    ILI9488_CASET(col_start, col_end - 1);    
    ILI9488_RASET(row_start, row_end - 1);
            
    ILI9488_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;
    
    col_start = a;
    row_start = b;
    col_end = c;
    row_end = d;
            
    return;
}

void ILI9488_CLRSCN(uint16_t back_color)
{
    int i;
    ILI9488_CASET(0, 479);
    ILI9488_RASET(0, 319);
    ILI9488_RAMWR();
    
    for(i=0;i<=153600;i++)
    {
        PMDIN = back_color;
        while(PMMODEbits.BUSY == 1);       
    }

    return;
}

//Writes a character to the screen
void WriteChar(unsigned col_start, unsigned row_start, unsigned 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;
    ILI9488_CASET(col_start, col_end);
    ILI9488_RASET(row_start, row_end);
    
    ILI9488_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.
    hchar = hchar + 15;
    return;
}

//Writes a null terminated string from a previously defined array
void WriteString(unsigned col_start, unsigned row_start, char array_name[], int fore_color)
{
    int offset = 0;
    
    //must initialize test_char to something other than \0
    //so we might as well use the array data
    char test_char = array_name[offset];;
    
    while(test_char != '\0')
    {
        test_char = array_name[offset];

        ILI9488_CASET(col_start, col_start + 15);

        WriteChar(col_start, row_start, test_char, fore_color);    
        offset++;       
        col_start = col_start + 15;
    }
    //cleans up the extra white space
    hchar = hchar - 15;
}

