/************************************
* lcd-Treiber-Bibliothek für Hitachi 44780 und kompatible
* z.B. KS0070B
*
*/
#include <inttypes.h>
#include <avr/io.h>
#include "lcd4.h"

/* Prototypes */
extern void wait_100us(void);
//void lcd_init(void);
//void lcd_write(uint8_t whichwrite, uint8_t zeichen, uint8_t position);
void lcd_instruct(uint8_t zeichen); //Optimzation of Code length (costs one fuction call)
	// expands to lcd_write(instruct, zeichen, 0); 
// void lcd_blank_line(uint8_t lcd_whichwrite);	
void lcd_preinstruct(uint8_t zeichen); //Optimzation of Code length (costs one fuction call)
	// expands to lcd_write(preinstruct, zeichen, 0);
// void lcd_blank_line(uint8_t lcd_whichwrite);

// Implementation
void lcd_5ms(void);
void lcd_1s(void);
/* end Prototypes */

#define lcd_mask_Write_Adress(position) ((position & 0x7F)| lcd_SET_DD_RAM)
// 4-Bit to be added, no indent
// enum whichtype{instruct, data};
void lcd_init(void){
	/* setting up ports first */
	lcd_dataport_DDR=0xff;
	lcd_dataport=0xff;
	set_lcd_RS_DDR;
	set_lcd_E_DDR;
	/* end setting up ports */
	set_lcd_RS;
	set_lcd_E;
	lcd_5ms();
	lcd_5ms();
	lcd_5ms();
	lcd_instruct(lcd_SET_FUNCTION_8BIT);
	lcd_5ms();
	lcd_instruct(lcd_SET_FUNCTION_8BIT);
	lcd_instruct(lcd_SET_FUNCTION_8BIT);
	#ifdef lcd_bus8
		lcd_preinstruct(lcd_SET_FUNCTION_8BIT|lcd_SET_FUNCTION_2LINE|lcd_SET_FUNCTION_7X5);
	#endif
		lcd_dataport_DDR|=lcd_dataport_mask;
	#ifdef lcd_bus4
		lcd_instruct(lcd_SET_FUNCTION_4BIT|lcd_SET_FUNCTION_2LINE|lcd_SET_FUNCTION_7X5);
	#endif
	lcd_5ms();
	lcd_instruct(lcd_DISPLAY_OO_ON|lcd_DISPLAY_OO_CURSOR_OFF);
	lcd_instruct(lcd_ENTRY_MODE_SET|lcd_ENTRY_MODE_SET_INCREASE | lcd_ENTRY_MS_DISPLAY_NOT_S);
	lcd_instruct(lcd_RETURN_HOME);
	lcd_5ms();
}

void  lcd_5ms(void){
	for(uint8_t i=50;i>0;i--){
		wait_100us();
		}
	}
	
void  lcd_1s(void){
	for(uint8_t i=200;i>0;i--){
		lcd_5ms();
		}
	}
	
void lcd_instruct(uint8_t zeichen){
	lcd_write(instruct,zeichen,0);
	}
void lcd_preinstruct(uint8_t zeichen){
	lcd_write(preinstruct,zeichen,0);
	}
	
void lcd_write(uint8_t lcd_whichwrite, uint8_t zeichen, uint8_t position){
	switch (lcd_whichwrite){
		case instruct :
		case preinstruct :
			unset_lcd_RS;
			break;
		case line2:
		case line1:
			position = position & 0x3f;
			if (lcd_whichwrite == line2){ position=position + 0x40; };
		case therepos:
			lcd_instruct(lcd_mask_Write_Adress(position));
		case here:		 
			set_lcd_RS;
			break;
		
		
	}
	set_lcd_E;
	asm volatile ("nop");
	lcd_dataport=( zeichen & lcd_dataport_mask);
	asm volatile ("nop");
	#ifdef lcd_bus4
		if (!(lcd_whichwrite==preinstruct)){
			unset_lcd_E;
			zeichen = zeichen << 4;
			wait_100us();
			set_lcd_E;
			asm volatile ("nop");
			lcd_dataport|=( zeichen & lcd_dataport_mask);
			asm volatile ("nop");
		}
	#endif
	unset_lcd_E;
	wait_100us();
			
}

void lcd_blank_line(uint8_t lcd_whichwrite)
	{
	uint8_t count;
	uint8_t countin;
	
	switch (lcd_whichwrite){
		case instruct:
			lcd_blank_line(line1);
		case line2:
			count=0x40;
			break;
		case line1:
			count=0;
			break;
		}
	
	for (countin=count; countin < count+15; countin++){
		lcd_write(therepos, 32, countin);
	}
}
