#include <stdbool.h>
#include <stdint.h>
#include "fonts.h"
#include "jlx12864.h"
#include "pins.h"

/* LCD type: 0 - uc1701, 1 - ssd1306 */
uint8_t lcd_type = 0;

void init_uc1701(void);
void init_ssd1306(void);
void ssd1306_off();
void ssd1306_on();

void delay(int i) 
{ 
      volatile int j,k; 
      for(j=0;j<i;j++) 
            for(k=0;k<110;k++); 
} 

void transfer_command(int data) { 
	uint8_t i; 
	gpio_set(OLED_CS, 0);
	gpio_set(OLED_CD, 0);
	for(i=0;i<8;i++) {
		gpio_set(OLED_SCK, 0);	
		if (data & 0x80)
			gpio_set(OLED_MOSI, 1);	
		else
		    gpio_set(OLED_MOSI, 0);
		gpio_set(OLED_SCK, 1);
        	data <<= 1;     
	}
	gpio_set(OLED_CS, 1);
} 

void transfer_data(int data) { 
	uint8_t i; 
	gpio_set(OLED_CS, 0);
	gpio_set(OLED_CD, 1);
	for(i=0;i<8;i++) {
		gpio_set(OLED_SCK, 0);	 
		if (data & 0x80)
			gpio_set(OLED_MOSI, 1);
		else   
			gpio_set(OLED_MOSI, 0);
		gpio_set(OLED_SCK, 1);
		data <<= 1;     
	} 
	gpio_set(OLED_CS, 1);
} 

void init_lcd() {
    /* Detect LCD type */
    if (gpio_get(OLED_TYPE)) {
        gpio_set(LCD_BKLGHT, true);
        init_uc1701();
        lcd_type = 0;
    }
    else {
        init_ssd1306();
        lcd_type = 1;
    }
}

void init_uc1701()
{
	gpio_set(OLED_CS, 0);
	gpio_set(OLED_RST, 0);
	delay(500);
	gpio_set(OLED_RST, 1);
	delay(200);
	transfer_command(0xe2);
	transfer_command(0x2c);
	transfer_command(0x2e);
	transfer_command(0x2f);
	transfer_command(0x24);
	transfer_command(0x81);
	transfer_command(0x1a);
    transfer_command(0xa2);
	transfer_command(0xc8);
	transfer_command(0xa0);
	transfer_command(0x40);
	transfer_command(0xaf);
	gpio_set(OLED_CS, 1);
}

void init_ssd1306()
{
    gpio_set(OLED_CS, 0);
    gpio_set(OLED_RST, 0);
    delay(500);
    gpio_set(OLED_RST, 1);
    delay(200);

    /* Display off */
    transfer_command(0xAE);

    /* Set lower column address */
    transfer_command(0x02);
    /* Set higher column address */
    transfer_command(0x10);

    /* Set display start line */
    transfer_command(0x40);

    /* Set page address */
    transfer_command(0xB0);

    /* Set contrast value 0xFF */
    transfer_command(0x81);
    transfer_command(0xFF);

    /* Normal / reverse */
    transfer_command(0xA6);

    /* Multiplex ratio */
    transfer_command(0xA8);
    /* duty = 1/64 */
    transfer_command(0x3F);

    /* Set charge pump enable */
    transfer_command(0xAD);
    transfer_command(0x8B);

    /* Set Vpp 9V (0x30 - 0x33) */
    transfer_command(0x33);

//    /* Set segment remap */
//    transfer_command(0xA1);
//    /* COM scan direction */
//    transfer_command(0xC8);

    /* Rotate display 180 degree*/
    /* Set segment remap */
    transfer_command(0xA0);
    /* COM scan direction */
    transfer_command(0xC0);

    /* Set display offset */
    transfer_command(0xD3);
    transfer_command(0x00);

    /* Set osc divider */
    transfer_command(0xD5);
    transfer_command(0x80);

    /* Set precharge period */
    transfer_command(0xD9);
    transfer_command(0x1F);

    /* setc COM pins */
    transfer_command(0xDA);
    transfer_command(0x12);

    /* Set vcomh */
    transfer_command(0xDB);
    transfer_command(0x40);

    /* Display on */
    transfer_command(0xAF);
    gpio_set(OLED_CS, 1);
}

void ssd1306_off() {
        transfer_command(0xAE);
}

void ssd1306_on() {
        transfer_command(0xAF);
}

void lcd_address(uint8_t page, uint8_t column) {
	gpio_set(OLED_CS, 0);

	/* Specify different column offset for lcd types */
	if (lcd_type == 0) {
		column=column-1;
	}
	else {
	    column=column+1;
	}
    page=page-1; 
    
	transfer_command(0xb0 + page);                
	transfer_command(((column >> 4) & 0x0f) + 0x10);
	transfer_command(column & 0x0f);  
} 

void clear_screen(void) {
	uint8_t i,j; 
	gpio_set(OLED_CS, 0);
	for(j=0;j<8;j++) {
		lcd_address(1 + j,1); 
		for(i=0;i<132;i++) { 
			transfer_data(0x00); 
		} 
	} 
} 

//full display test 
void full_display(uint8_t data1, uint8_t data2) { 
	int i,j; 
	for(i=0; i<8; i++) { 
		lcd_address(i+1,1); 
		for(j=0;j<64;j++) { 
			transfer_data(data1); 
			transfer_data(data2);                        
		} 
      }           
} 

void test_box(void) { 
	int i,j; 
	lcd_address(1,1); 
	transfer_data(0xff); 
	for(i=1;i<127;i++) { 
		transfer_data(0x01);   
	} 
	transfer_data(0xff); 	
	lcd_address(2,1); 
	transfer_data(0xff); 
	for(i=1;i<127;i++) { 
		transfer_data(0x80);   
	} 
	transfer_data(0xff); 
	lcd_address(3,1); 
	transfer_data(0xff); 
	for(i=1;i<127;i++) { 
		transfer_data(0x01);   
	} 
	transfer_data(0xff);  
	for(j=4;j<=7;j++) {
		lcd_address(j,1); 
		transfer_data(0xff); 
		for(i=1;i<127;i++) { 
			transfer_data(0x00);   
		}	 
		transfer_data(0xff);   
	} 
	lcd_address(8,1); 
	transfer_data(0xff); 
	for(i=1;i<127;i++) { 
		transfer_data(0x80);   
	} 
	transfer_data(0xff); 
} 

void test(void) { 
	full_display(0xff,0xff);           
	delay(1000);
	full_display(0x55,0x55); 
	delay(1000);
	full_display(0xaa,0xaa); 
	delay(1000);
	full_display(0xff,0x00);
	delay(1000);
	full_display(0x00,0xff); 
	delay(1000);
	full_display(0x55,0xaa); 
	delay(1000);
	full_display(0xaa,0x55);     
	delay(1000);
	test_box(); 
	delay(1000);
} 

/*
void display_128x64(uchar *dp) { 
	uint i,j; 
	for(j=0;j<8;j++) { 
		lcd_address(j+1,1); 
		for (i=0;i<128;i++) {  
			transfer_data(*dp); 
			dp++;
  		} 
 	} 
} 

void display_128x16(uchar page,uchar column,uchar *dp) { 
	uint i,j; 
	for(j=0;j<2;j++) { 
		lcd_address(page+j,column); 
		for (i=0;i<128;i++) {  
			transfer_data(*dp); 
			dp++; 
		} 
	} 
} 


void display_graphic_32x32(uchar page,uchar column,uchar *dp) { 
	uchar i,j; 
	for(j=0;j<4;j++) { 
		lcd_address(page+j,column); 
		for (i=0;i<32;i++) {  
			transfer_data(*dp);         
			dp++; 
		} 
	} 
} 

void display_graphic_16x16(uchar page,uchar column,uchar *dp) { 
	uchar i,j; 
	for(j=0;j<2;j++) { 
		lcd_address(page+j,column); 
		for (i=0;i<16;i++) { 
		transfer_data(*dp);         
		dp++; 
		} 
	} 
} 



void display_graphic_8x16(uchar page,uchar column,uchar *dp) { 
	uchar i,j; 
	for(j=0;j<2;j++) { 
		lcd_address(page+j,column); 
		for (i=0;i<8;i++) {  
			transfer_data(*dp); 
			dp++; 
		} 
	} 
} 

void display_string_8x16(uint page,uint column,uchar *text) 
{ 
      uint i=0,j,k,n; 
      if(column>123) 
 { 
            column=1; 
            page+=2; 
 } 
      while(text[i]>0x00) 
 {  
            if((text[i]>=0x20)&&(text[i]<=0x7e)) 
  { 
                  j=text[i]-0x20; 
                  for(n=0;n<2;n++) 
   {    
lcd_address(page+n,column); 
for(k=0;k<8;k++) 
    {      
transfer_data(ascii_table_8x16[j][k+8*n]);  

    } 
   } 
                  i++; 
                  column+=8; 
  } 
  else 
            i++; 
 } 
} 
*/

void display_string_5x8(uint8_t page, uint8_t column, uint8_t reverse, char *text) {
	uint8_t i=0,k,disp_data;
	uint16_t j;
	bool is_symbol = 0;

	while (text[i] > 0x00) {
		if ((text[i] == 0xd0) || (text[i] == 0xd1))
			is_symbol = 1;
		if ((text[i] >= 0x20) && (text[i] <= 0x7e))
		      is_symbol = 1;
  		if (is_symbol) {
			if (text[i] == 0xd0)
			{
				i++;
				if(text[i] >= 0x90 && text[i] <= 0xbf)
					j = 6*(text[i] - 0x90);
				else
					j = 6*65;
			}
			else if(text[i] == 0xd1)
			{
				i++;
				if((text[i] >= 0x80 && text[i] <= 0x8f))
					j = 6*(text[i] - 0x50);
				else
					j = 6*64;
			}
			else
				j = 6*(text[i]-0x20);
			lcd_address(page,column);
			for(k=0;k<6;k++) {
				if (reverse==1) { 
					if(text[i]>=0x80 || text[i]==0x01)//((text[i]<0x20)||(text[i]>0x7f))
						disp_data = ~cyrillic_font5x8[j + k];
					else
						disp_data = ~Fonts5x8[j + k];
				}
				else { 
					if(text[i]>=0x80 || text[i]==0x01)//((text[i]<0x20)||(text[i]>0x7f))
						disp_data = cyrillic_font5x8[j + k];
					else
						disp_data = Fonts5x8[j + k];
				} 
				transfer_data(disp_data);
			} 
			i++; 
			column+=6; 
			if(column>123) { 
				column=1; 
				page++; 
			} 
		} 
		else i++; 
	} 
} 




/*
void display_string_16x16(uchar page,uchar column,uchar *text) 
{ 
    uchar i,j,k; 
    uint address;  
    j = 0; 
    while(text[j] != '\0') 
    { 
        i = 0; 
        address = 1; 
        while(Chinese_text_16x16[i] > 0x7e)    

        { 
            if(Chinese_text_16x16[i] == text[j]) 
            { 
                if(Chinese_text_16x16[i + 1] == text[j + 1]) 
                { 
                    address = i * 16; 
                    break; 
                } 
            } 
            i += 2;             
        } 
        if(column > 113) 
        { 
            column = 0; 
            page += 2; 
        } 
        if(address != 1)
        { 
                  for(k=0;k<2;k++) 
   { 
lcd_address(page+k,column); 
                  for(i = 0; i < 16; i++)                
                  { 
                      transfer_data(Chinese_code_16x16[address]);   
                      address++; 
                  } 
                  } 
            j += 2;         
        } 
        else           
        { 
                  for(k=0;k<2;k++) 
   { 
lcd_address(page+k,column)


for(i = 0; i < 16; i++)
                  { 
                      transfer_data(0x00);    
                  } 
                  } 
            j++; 
        } 
        column+=16; 
    } 
} 


void disp_string_8x16_16x16(uchar page,uchar column,uchar *text
) 
{ 
    uchar temp[3]; 
    uchar i = 0;     
    while(text[i] != '\0') 
    { 
        if(text[i] > 0x7e) 
        { 
            temp[0] = text[i]; 
            temp[1] = text[i + 1]; 
            temp[2] = '\0';          
            display_string_16x16(page,column,temp);  
            column += 16; 
            i += 2; 
        } 
        else 
        { 
            temp[0] = text[i];     
            temp[1] = '\0';          
            display_string_8x16(page, column, temp);  
            column += 8; 
            i++; 
        } 
    } 
} 
//显示镜像        
void display_mirror() 
{ 
      clear_screen(); 
      disp_string_8x16_16x16(1,1,"  左右上下镜像: "); 
      delay(7000); 
      clear_screen(); 
      display_128x64(bmp12864_4); 
//          delay(7000); 
            waitkey(); 
      transfer_command(0xc8);           
      transfer_command(0xa0);          
      clear_screen(); 
      display_128x64(bmp12864_4); 
//          delay(7000); 
            waitkey(); 
      transfer_command(0xc0);         
      transfer_command(0xa1);        
      clear_screen(); 
      display_128x64(bmp12864_4); 
//          delay(7000); 
            waitkey(); 
      transfer_command(0xc0);       
      transfer_command(0xa0);      
      clear_screen(); 
      display_128x64(bmp12864_4); 
//          delay(7000); 
            waitkey(); 
      transfer_command(0xc8);     
      transfer_command(0xa1);    
} 
//对比度调节 
void contrast_control() 
{ 
            clear_screen(); 
            disp_string_8x16_16x16(1,1,"软件调节亮度:"); 
            display_string_8x16(4,52,"0xcf"); 
            display_128x16(7,1,bmp12816_1); 
            display_graphic_16x16(7,1+16*4,bmp16x16_1); 
//          delay(7000); 
            waitkey(); 
            
            transfer_command(0x81); 
            transfer_command(0xdf); 
            display_string_8x16(4,52,"0xdf"); 
            display_128x16(7,1,bmp12816_1); 
            display_graphic_16x16(7,1+16*5,bmp16x16_1); 
//          delay(7000); 
            waitkey(); 
            transfer_command(0x81); 
            transfer_command(0xef); 
            display_string_8x16(4,52,"0xef"); 
            display_128x16(7,1,bmp12816_1); 
            display_graphic_16x16(7,1+16*6,bmp16x16_1); 
//          delay(7000); 
            waitkey(); 
            transfer_command(0x81); 
            transfer_command(0xff); 
            display_string_8x16(4,52,"0xff"); 
            display_128x16(7,1,bmp12816_1); 
            display_graphic_16x16(7,1+16*7,bmp16x16_1); 
//          delay(7000); 
            waitkey(); 
            transfer_command(0x81); 
            transfer_command(0x00); 
            display_string_8x16(4,52,"0x00"); 
            display_128x16(7,1,bmp12816_1); 
            display_graphic_16x16(7,1+16*0,bmp16x16_1); 
//          delay(7000); 
            waitkey(); 
            transfer_command(0x81); 
            transfer_command(0x5f); 
            display_string_8x16(4,52,"0x5f"); 
            display_128x16(7,1,bmp12816_1); 
            display_graphic_16x16(7,1+16*1,bmp16x16_1); 
//          delay(7000); 
            waitkey(); 
            transfer_command(0x81); 
            transfer_command(0xcf); 
            display_string_8x16(4,52,"0xcf"); 
            display_128x16(7,1,bmp12816_1); 
            display_graphic_16x16(7,1+16*4,bmp16x16_1); 
//          delay(7000); 
            waitkey(); 
            } 
void main(void) 
{  
      while(1) {
        initial_lcd(); 

        clear_screen(); 



	display_string_5x8(1,1,0,"{(5x8dot ASCII char)}");

        display_string_5x8(2,1,0,"{[(<~!@#$%^&*_+=?>)]}"); 
        disp_string_8x16_16x16(3,1,"标准 16x16dot 汉字");        


	display_graphic_32x32 (5,1+32*0,jing1);  
        display_graphic_32x32 (5,1+32*1,lian1); 
        display_graphic_32x32 (5,1+32*2,xun1);                                     
        disp_string_8x16_16x16(5,1+32*3,"JLX:"); 
        disp_string_8x16_16x16(7,1+32*3,"OLED"); 
        waitkey(); 
        clear_screen();     
//clear all dots 
        display_string_5x8(1,1,1,"012345678901234567890");
        display_string_5x8(1,1,1,"        MENU         "); 

        display_string_5x8(3,1,0,"Select>>>>"); 
        display_string_5x8(3,64,1,"1.Graphic ");         
        display_string_5x8(4,64,0,"2.Chinese " ); 
        display_string_5x8(5,64,0,"3.Movie   "); 
	display_string_5x8(6,64,0,"4.Contrast"); 
	display_string_5x8(7,64,0,"5.Mirror  "); 
	display_string_5x8(8,1,1,"PRE  USER   DEL   NEW"); 
        display_string_5x8(8,19,0," "); 
        display_string_5x8(8,65,0," "); 
        display_string_5x8(8,97,0," "); 
        waitkey(); 
        contrast_control(); 
        waitkey(); 
        display_mirror(); 
	waitkey(); 
	test(); 
    }
}
*/