// Module for HD44780 LCD Module
// through 74168 shift register
// This work is provided as-is without any warranty whatsoever
// Use it at your own risk
// Modify and redistribute at will, as long as this disclaimer remains
// (C) Brian Starkey, 2010

#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>

#include "lcd_util.h"

// Bit-bang data shift
// MSB First
void shift_out(char data) {
	char i, bit;
	for (i = 7; i >= 0; i--) {
		bit = data & (1 << i);
		(bit > 0) ? (LCD_PORT |= (1 << SH_DATA)) : (LCD_PORT &= ~(1 << SH_DATA));
		LCD_PORT |= (1 << SH_CLOCK);
		LCD_PORT &= ~(1 << SH_CLOCK);
		_delay_us(100);
	}
return;
}

// Send an instruction byte (RS = 0)
void instruction_cmd(char data) {
	shift_out(data);	
	LCD_PORT &= ~(1 << RS);	
	LCD_PORT |= (1 << EN);
	LCD_PORT &= ~(1 << EN);
	_delay_ms(3);
return;
}

// Send a data byte (RS = 1)
void data_cmd(char data) {
	shift_out(data);
	LCD_PORT |= (1 << RS);	
	LCD_PORT |= (1 << EN);
	LCD_PORT &= ~(1 << EN);
	_delay_ms(3);
return;
}

// Initialise and clear LCD
void init_lcd() {
	instruction_cmd(0x38);  // 8-bit interface, 2 lines
	instruction_cmd(0x0C);  // Display on, no cursor, no blink
	instruction_cmd(0x06);  // Auto-increment cursor
	instruction_cmd(0x01);  // Clear display
return;
}

// Print a (zero-terminated) string from program memory,
// starting at DDRAM position pos
void print_string_pmem(PGM_P pstring, char pos) {
	uint8_t i = 0;
	char in_ram;
	instruction_cmd(SET_DDRAM | pos);
	while (in_ram = pgm_read_byte(&pstring[i])) {
		data_cmd(in_ram);
		i++;
	};
}

// Print a (zero-terminated) string from RAM,
// starting at DDRAM position pos
void print_string(char * string, char pos) {
	uint8_t i = 0;
	instruction_cmd(SET_DDRAM | pos);
	do {
		data_cmd(string[i]);
		i++;
	} while (string[i] != '\0');
return;
}

/*
// Generate decimal representation of a byte
// s should be an array of at least 4 chars
void ctos(char * s, char i) {
	s[3] = '\0';
	s[0] = (i/100) | 0x30;
	if (s[0] == 0x30) s[0] = ' ';
	s[1] = (i/10)%10 | 0x30;
	if ((s[1] == 0x30) && (s[0] == ' ')) s[1] = ' ';
	s[2] = (i%10) | 0x30;

}
*/
