#define F_CPU 16000000UL

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

#define LCD_RST PC1
#define LCD_SCE PC2
#define LCD_DC  PC3
#define LCD_DIN PC4
#define LCD_CLK PC5

volatile uint16_t image_pos = (uint16_t) image;

void lcd_write(uint8_t val, uint8_t as_data) {
	PORTC &= ~_BV(LCD_SCE);
	
	if (as_data) {
		PORTC |= _BV(LCD_DC);
	} else {
		PORTC &= ~_BV(LCD_DC);
	}
	
	for (uint8_t i = 0; i < 8; i += 1) {
		if ((val >> (7-i)) & 0x01) {
			PORTC |= _BV(LCD_DIN);
		} else {
			PORTC &= ~_BV(LCD_DIN);
		}
		
		PORTC |= _BV(LCD_CLK);
		PORTC &= ~_BV(LCD_CLK);
	}
	
	PORTC |= _BV(LCD_SCE);
}

void lcd_write_cmd(uint8_t val) {
	lcd_write(val, 0);
}

void lcd_write_data(uint8_t val) {
	lcd_write(val, 1);
}

void lcd_init() {
	DDRC |= _BV(LCD_SCE);
	DDRC |= _BV(LCD_RST);
	DDRC |= _BV(LCD_DC);
	DDRC |= _BV(LCD_DIN);
	DDRC |= _BV(LCD_CLK);
	
	PORTC |= _BV(LCD_RST);
	PORTC |= _BV(LCD_SCE);
	_delay_ms(10);
	PORTC &= ~_BV(LCD_RST);
	_delay_ms(70);
	PORTC |= _BV(LCD_RST);
	PORTC &= ~_BV(LCD_SCE);
	
	lcd_write_cmd(0x21);
	lcd_write_cmd(_BV(4) | 0); // Bias system (0-7)
	lcd_write_cmd(_BV(2) | 0); // Temperature coefficient (0-3)
	lcd_write_cmd(_BV(7) | 50); // V_OP (0-127)
	lcd_write_cmd(0x20);
	lcd_write_cmd(_BV(3) | _BV(2)); // D = 1, E = 0
}

void lcd_render() {
	lcd_write_cmd(0x80); // X = 0
	lcd_write_cmd(0x40); // Y = 0
	
	for (int i = 0; i < 504; ++i) {
		lcd_write_data(pgm_read_byte(image_pos));
		
		++image_pos;
	}
}

int main(void) {
	lcd_init();
	
	lcd_render();
	
	while (1) {}
}
