#include "n1110.h"
#include "lcd_generic_font.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"

/***************** LOW LEVEL ************************************************/
void __attribute__ ((noinline))  lcd_init (void)
{

	LCD_GPIO->BSRR = LCD_RESET_PIN | LCD_CS_PIN;
	LCD_GPIO->BRR = LCD_SCK_PIN | LCD_SDA_PIN;

	lcd_hw_reset(); // HW reset

	lcd_write(COMMAND, 0xE2); // Internal reset
	lcd_write(COMMAND, 0xEB); // Thermal comp. on
	lcd_write(COMMAND, 0x2F); // Supply mode

#ifdef N1202UD
	lcd_write(COMMAND, 0xA9); // n1202 upside down
#endif /* N1202UD */

#ifdef N1202
	lcd_write(COMMAND, 0xA1);// n1202
	lcd_write(COMMAND, 0xC8);
#endif /* N1202 */

#ifdef N1110UD
	lcd_write(COMMAND, 0xA1);// n1110 ud
#endif /* N1110UD */
#ifdef N1110
	lcd_write(COMMAND, 0xA9);// n1110
	lcd_write(COMMAND, 0xC8);
#endif /* N1110 */

	//lcd_write(COMMAND, 0xA9);// A1 // Horisontal reverse: Reverse - 0xA9, Normal - 0xA1
	//lcd_write(COMMAND, 0xC8); // Vertical reverse (comment if no need)

	lcd_write(COMMAND, 0xA4); // Clear screen
	lcd_write(COMMAND, 0xA6); // Positive - A7, Negative - A6
	lcd_write(COMMAND, 0x91); // Contrast 0x80...0x9F

	lcd_write(COMMAND, 0xAF); // Enable LCD
}

/*
 * N1110 LCD hardware reset
 * !!!NOTE: needs normal delay implementation
 */
void __attribute__ ((noinline))  lcd_hw_reset (void){
	volatile register uint32_t i;
	/* !RESET -> Wait -> RESET */
	LCD_GPIO->BRR = LCD_RESET_PIN;
	for(i=0; i<24000; i++) {};
	LCD_GPIO->BSRR = LCD_RESET_PIN;
}

/*
 * N1110 LCD write data or command
 */
void __attribute__ ((noinline))  lcd_write (lcd_cd_t cd, uint8_t byte){
	register uint32_t i;

	/* Slave select */
	LCD_GPIO->BRR = LCD_CS_PIN;

	/* DATA/COMMAND selection */
	if(cd == DATA)
		LCD_GPIO->BSRR = LCD_SDA_PIN;
	else
		LCD_GPIO->BRR = LCD_SDA_PIN;

	LCD_GPIO->BSRR = LCD_SCK_PIN;

	for(i=0; i<8; i++)
	{
		LCD_GPIO->BRR = LCD_SCK_PIN;
		/* SDA */
		if(byte & 0x80)
			LCD_GPIO->BSRR = LCD_SDA_PIN;
		else
			LCD_GPIO->BRR = LCD_SDA_PIN;
		__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
		LCD_GPIO->BSRR = LCD_SCK_PIN;

		byte <<= 1;
	}

	LCD_GPIO->BRR = LCD_SCK_PIN;

	/* Slave release */
	LCD_GPIO->BSRR = LCD_CS_PIN;
	//GPIO_WriteBit(LCD_GPIO, LCD_CS_PIN, Bit_SET); // SS rise
}

/*
 * Clear LCD screen
 */
void __attribute__ ((noinline))  lcd_clear (void){
	register uint32_t i,j;

	lcd_write(COMMAND, 0xAE); // Disable display

	for(i=0; i < LCD_YMAX; i++)
	{
		/* Set row to clear */
		lcd_gotoxy(0,i);
		/* Fill row with zeros */
		for(j=0; j < LCD_XMAX; j++) lcd_write(DATA, 0x00);
	}

	lcd_gotoxy(0, 0); // GOTO 0,0
	lcd_write(COMMAND, 0xAF); // Enable display
}

/*
 * Set current position
 */
void __attribute__ ((noinline))  lcd_gotoxy (uint8_t x ,uint8_t y){
	lcd_write(COMMAND, (0xB0 | (y & 0x0F)) );
	lcd_write(COMMAND, (0x10 | (x >> 0x04)) );
	lcd_write(COMMAND, 0x0F & x);
}

void  lcd_putnum (int x, int y,char *str){

	char c;
	int i,j;

	char* str2 = str;

	for(i =0;i<3;i++)
	{
		lcd_gotoxy(x,y+2-i);

		str2 = str;
		while( (c = (*str2++)) )
		{
			if( (c>=0x30  &&  c<= 0x39)|| (c<13) )
			{
				int n = c - 0x30;
				if(n < 0) n = c+10;

				for(j=numbers_idx[n]+i; j< numbers_idx[n]+14*3 ; j+=3)
					{
					int dd = 0;
					if(j< numbers_idx[n+1]) dd = numbers[j];

					if( (*str2 == '.') && (i==0)&&(j>( numbers_idx[n]+14*3 - 9))) dd |= 0xF0;

					lcd_write(DATA, dd);

					}


			}
		}

	}


	//lcd_write(DATA,0);
}

/*
 * Put character to current position
 */
void __attribute__ ((noinline))  lcd_putchar (const char c){
	register uint32_t i;
	char cc = c;
	if(cc < 32) cc = 0; else cc -= 32;

	for(i=0; i<5; i++) lcd_write(DATA, (lcd_font[((cc&0x7f)*5)+i]));
	lcd_write(DATA, 0x00);
}

/*
 * Put string from RAM
 */
void __attribute__ ((noinline))  lcd_putstr (const char *str)					{
	char c;
	while( (c = (*str++)) ) lcd_putchar(c);
}
