/************************************************/
/*TFT Display Code for Display Controller       */
/*Ver 1.0                                       */
/*PIC32MX795F512L-80I                           */
/*PIC32MX695F512L-80I                           */
/************************************************/

#include <xc.h>
#include "MainBrain.h"

    uint8_t back_level;
    int fore_color;
    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(uint8_t 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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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 Display_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;

        Display_CASET(col_start, col_end - 1);    
        Display_RASET(row_start, row_end - 1);

        Display_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 Display_CLRSCN(uint16_t back_color)
    {
        int i;
        Display_CASET(0, 479);
        Display_RASET(0, 319);
        Display_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;
        Display_CASET(col_start, col_end);
        Display_RASET(row_start, row_end);

        Display_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];

            Display_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;
    }