/*
C
 * Display.c
 *
 *  Created on: 15. 7. 2019
 *  Author: 	Vitoslavský Ondøej
 *  Company: 	UVB Technik
 *  Display: 	BC-1602A-YPLEH
 *  Datasheet: 	https://datasheet.octopart.com/BC-1602A-YPLEH-Bolymin-datasheet-41171537.pdf
 *
 *  Description:
 *  	This file is used for communication with BC-1602A-YPLEH display.
 *  	Thanks to 4bit communication are used only upper 4 data
 *  	pins on display's PCB (11...14) ie (DB4...DB7).
 *  	Pin R/W (5) on display can be grounded because no display data will be read.
 *
 */

#include "main.h"
#include <Display_driver.h>




void Display_Init4(){
	Display_LowLevel_Init();
	HAL_Delay(15);
	HAL_GPIO_WritePin(LCD_E_GPIO_PORT,LCD_E_PIN,GPIO_PIN_RESET);
	Display_Send4(COM1_4);
	Display_Send4(COM2_4);
	Display_Send4(WID_4);
	Display_Send4(DOF_4);
	Display_Send4(CLR_4);
	Display_Send4(MOD_4);
	Display_Send4(DON_4);
	Display_Clear_Row(2);
	HAL_Delay(1);
}

void Display_LowLevel_Init(){
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOE_CLK_ENABLE();

	GPIO_InitStruct.Pin = LCD_DB7_PIN|LCD_DB6_PIN|LCD_DB5_PIN|LCD_DB4_PIN|LCD_RS_PIN|LCD_E_PIN;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_PULLDOWN;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
	HAL_GPIO_Init(LCD_COMMON_PORT, &GPIO_InitStruct);

	HAL_GPIO_WritePin(LCD_COMMON_PORT,LCD_DB7_PIN|LCD_DB6_PIN|LCD_DB5_PIN|LCD_DB4_PIN|LCD_RS_PIN|LCD_E_PIN,1);
}



void Display_Send4(uint16_t binar){
	HAL_GPIO_WritePin(LCD_RS_GPIO_PORT,LCD_RS_PIN,(binar & (R_S))>>9);
	HAL_GPIO_WritePin(LCD_DB7_GPIO_PORT,LCD_DB7_PIN,(binar & (DB7))>>7);
	HAL_GPIO_WritePin(LCD_DB6_GPIO_PORT,LCD_DB6_PIN,(binar & (DB6))>>6);
	HAL_GPIO_WritePin(LCD_DB5_GPIO_PORT,LCD_DB5_PIN,(binar & (DB5))>>5);
	HAL_GPIO_WritePin(LCD_DB4_GPIO_PORT,LCD_DB4_PIN,(binar & (DB4))>>4);

	Delay_us(10);
	HAL_GPIO_WritePin(LCD_E_GPIO_PORT,LCD_E_PIN,1);
	Delay_us(10);
	HAL_GPIO_WritePin(LCD_E_GPIO_PORT,LCD_E_PIN,0);

	HAL_GPIO_WritePin(LCD_DB7_GPIO_PORT,LCD_DB7_PIN,(binar & (DB3))>>3);
	HAL_GPIO_WritePin(LCD_DB6_GPIO_PORT,LCD_DB6_PIN,(binar & (DB2))>>2);
	HAL_GPIO_WritePin(LCD_DB5_GPIO_PORT,LCD_DB5_PIN,(binar & (DB1))>>1);
	HAL_GPIO_WritePin(LCD_DB4_GPIO_PORT,LCD_DB4_PIN,(binar & (DB0)));


	Delay_us(10);
	HAL_GPIO_WritePin(LCD_E_GPIO_PORT,LCD_E_PIN,1);
	Delay_us(10);
	HAL_GPIO_WritePin(LCD_E_GPIO_PORT,LCD_E_PIN,0);

	Display_Wait(binar);
}



void Display_UVB(){
	Display_Write_String("UVB Technik", 0,2);
	for (uint8_t i = 0; i < 16; i++) {
		Display_Write_String(">", 1,i);
		HAL_Delay(100);
	}

	Display_Clear_Row(2);
}



void Display_Wait(uint16_t binar){

	if(binar == CLR_4)
	{
		Delay_us(2500);
	}
	else if(binar == COM1_4){
		Delay_us(4500);
	}
	else
	{
		Delay_us(50);
	}

}



void Display_Write_String(char* string, uint8_t row, uint8_t col){
	uint8_t pos=row*0x40+col;

	Display_Send4(DB7|pos);
	for(uint8_t i=0;i<16;i++){
		if(string[i]=='\0')
			break;
		if(((pos>16)&&(pos<0x40))||(pos>0x4F))
			break;
		if(string[i]=='\n'){
			while(1){
				Display_Send4(R_S|' ');
				pos++;
				if(((pos>16)&&(pos<0x40))||(pos>0x4F))
					break;
			}
			break;
		}
		Display_Send4(R_S|string[i]);
		pos++;
	}
}


void Display_Scroll_String(char* string, uint8_t row, uint8_t iterations){

	for(uint8_t c = 0; c<iterations; c++)
	{
		for(uint8_t i=0;;i++){
			if((i<16)&&(string[i]=='\0')){
				Display_Write_String(&string[0],row, 0);
				goto end;
			}
			else if(string[i]=='\0'){
				break;
			}
		}
		for(uint8_t i=0;;i++)
		{
			if(i==0)
				HAL_Delay(500);

			Display_Write_String(&string[i],row, 0);
			if(i==0)
				HAL_Delay(500);
			if(string[i+16]=='\0')
				break;
			if(string[i]=='\0')
				break;
			HAL_Delay(250);
	}
	end:
	HAL_Delay(1000);
	}
	Display_Clear_Row(row);

}


void Display_Write_Number(float number, uint8_t row, uint8_t col,uint8_t length){
	char string[BUFFERLENGTH];
	uint8_t pos=row*0x40+col;

	Display_Send4(DB7|pos);

	if(number<0){
		number-=2*(number);
		Display_Send4(R_S|'-');
		pos++;
	}
/*
	else{
		Display_Send4(R_S|'+');
		pos++;
	}
*/
	Transform(number, length, &string[0]);
	for(uint8_t i=0;i<16;i++){
			if(string[i]=='\0')
				break;
			else if(((pos>16)&&(pos<0x40))||(pos>0x4F))
				break;
			else if((string[i]=='.')&&(length==0))
				break;

			Display_Send4(R_S|string[i]);
			pos++;

		}
}


void Display_Clear_Row(uint8_t row){
	uint8_t pos;
	switch(row){
	case 0:
		pos=0;
		Display_Send4(DB7|pos);
		for(;;pos++){
			if(((pos>16)&&(pos<0x40))||(pos>0x4F))
				break;
			Display_Send4(R_S|' ');
		}
		break;
	case 1:
		pos=0x40;
		Display_Send4(DB7|pos);
		for(;;pos++){
			if(((pos>16)&&(pos<0x40))||(pos>0x4F))
				break;
			Display_Send4(R_S|' ');
		}
		break;
	case 2:
		Display_Send4(CLR_4);
		break;
	default:
		break;
	}
}


void Transform(double number, uint8_t length, char *buf){

    uint8_t b=0, over=1, count=0;
    number+=0.00000000002; //prevention from 23.00 being transformed as 22.99

    //counts how big the number in tens is
    for(uint32_t c=1000000000;c>=10;c/=10)
    {
    	if(number>c)
    	{
    		number/=c;
            over=10-count;
            break;
    	}
    	count++;
	}

    //transforms the number to string and adds a decimal point
    for(uint8_t i=0;i<length+over+2;i++)
	{
        if(i==over){
            buf[over]='.';
            i++;
        }
        b=(uint8_t)number;
        buf[i]=b+'0';
        number-=b;
        number*=10;
	}

    //fills rest of the string with "empty" chars '\0'
	for(uint8_t i=length+over+1;i<BUFFERLENGTH-1;i++){
        buf[i]='\0';
    }
}



char* Hex_To_String(uint32_t convert,uint8_t bytes) {
	uint8_t pom;
	uint8_t shift = 0;
	uint8_t pos = bytes*2+1;
	string[0] = '0';
	string[1] = 'x';
	for (uint8_t i = pos; i > 1; i--) {
		pom = (convert >> shift) & (0x000F);
		if (pom < 10)
			string[i] = pom + '0';
		else
			string[i] = pom - 10 + 'a';
		shift += 4;
	}
	string[pos+1] = '\0';
	return &string[0];
}

