From a5518ce072f359ba3a41497c7a6504de3fb93c0f Mon Sep 17 00:00:00 2001
From: Giorgio Momigliano <gmomigliano@protonmail.com>
Date: Thu, 21 May 2020 04:19:05 +0200
Subject: [PATCH] Game

---
 Makefile            | 129 ++++++++++++++++++++
 buttons.c           |  59 +++++++++
 buttons.h           |  13 ++
 lafortuna.sh        |  43 +++++++
 lib/README.md       |   5 +
 lib/lcd/font.h      | 104 ++++++++++++++++
 lib/lcd/ili934x.h   | 103 ++++++++++++++++
 lib/lcd/lcd.c       | 262 ++++++++++++++++++++++++++++++++++++++++
 lib/lcd/lcd.h       |  49 ++++++++
 lib/led/led.c       |  36 ++++++
 lib/led/led.h       |  14 +++
 lib/rotary/rotary.c |  48 ++++++++
 lib/rotary/rotary.h |  21 ++++
 main.c              | 287 ++++++++++++++++++++++++++++++++++++++++++++
 main.h              |   9 ++
 15 files changed, 1182 insertions(+)
 create mode 100644 Makefile
 create mode 100644 buttons.c
 create mode 100644 buttons.h
 create mode 100644 lafortuna.sh
 create mode 100644 lib/README.md
 create mode 100644 lib/lcd/font.h
 create mode 100644 lib/lcd/ili934x.h
 create mode 100644 lib/lcd/lcd.c
 create mode 100644 lib/lcd/lcd.h
 create mode 100644 lib/led/led.c
 create mode 100644 lib/led/led.h
 create mode 100644 lib/rotary/rotary.c
 create mode 100644 lib/rotary/rotary.h
 create mode 100644 main.c
 create mode 100644 main.h

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..ec3c0f4
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,129 @@
+# Universal Makefile   Version: 23.02.2016
+#
+# Appears to work under Linux, OSX, and Cygwin/Windows.
+# Under OSX it should be named "Makefile".
+#
+# Requires GNU 'make' and 'find'. 
+ 
+# Target Architecture
+BOARD := LaFortuna
+MCU   := at90usb1286
+F_CPU := 8000000UL
+ 
+# Tool Options
+CFLAGS    := -Os -mmcu=$(MCU) -DF_CPU=$(F_CPU)
+# CFLAGS    += -Wl,-u,vfprintf -lprintf_flt -lm  # floating point support 
+CFLAGS    += -fno-strict-aliasing  # FATfs does not adhere to strict aliasing
+CFLAGS    += -Wno-main             # main() will never return 
+CFLAGS    += -Wall -Wextra -pedantic
+CFLAGS    += -Wstrict-overflow=5 -fstrict-overflow -Winline              
+CHKFLAGS  := 
+# CHKFLAGS  += -fsyntax-only
+BUILD_DIR := _build
+ 
+# Ignoring hidden directories; sorting to drop duplicates:
+CFILES := $(shell find . ! -path "*/\.*" -type f -name "*.c")
+CPPFILES := $(shell find . ! -path "*/\.*" -type f -name "*.cpp")
+CPATHS := $(sort $(dir $(CFILES)))
+CPPATHS += $(sort $(dir $(CPPFILES)))
+vpath %.c   $(CPATHS)
+vpath %.cpp $(CPPATHS)
+HFILES := $(shell find . ! -path "*/\.*" -type f -name "*.h")
+HPATHS := $(sort $(dir $(HFILES)))
+vpath %.h $(HPATHS)
+CFLAGS += $(addprefix -I ,$(HPATHS))
+DEPENDENCIES := $(patsubst %.c,$(BUILD_DIR)/%.d,$(notdir $(CFILES)))
+DEPENDENCIES += $(patsubst %.cpp,$(BUILD_DIR)/%.d,$(notdir $(CPPILES)))
+OBJFILES     := $(patsubst %.c,$(BUILD_DIR)/%.o,$(notdir $(CFILES)))
+OBJFILES     += $(patsubst %.cpp,$(BUILD_DIR)/%.o,$(notdir $(CPPFILES)))
+ 
+.PHONY: upld prom clean check-syntax ?
+ 
+upld: $(BUILD_DIR)/main.hex
+	$(info )
+	$(info =========== ${BOARD} =============)
+	dfu-programmer $(MCU) erase
+	dfu-programmer $(MCU) flash $(BUILD_DIR)/main.hex
+	dfu-programmer $(MCU) launch --no-reset # requires dfu-programmer >= v0.7.0 
+ 
+prom: $(BUILD_DIR)/main.eep upld
+	$(info ======== EEPROM: ${BOARD} ========)
+	dfu-programmer $(MCU) flash-eeprom $(BUILD_DIR)/main.eep
+ 
+$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR)
+	@avr-gcc $(CFLAGS) -MMD -MP -c $< -o $@
+ 
+$(BUILD_DIR)/%.o: %.cpp Makefile | $(BUILD_DIR)
+	@avr-g++ $(CFLAGS) -MMD -MP -c $< -o $@
+ 
+$(BUILD_DIR)/%.elf %.elf: $(OBJFILES)
+	@avr-gcc -mmcu=$(MCU) -o $@  $^
+ 
+$(BUILD_DIR)/%.hex %.hex: $(BUILD_DIR)/%.elf
+	@avr-objcopy -R .eeprom -R .fuse -R .lock -R .signature -O ihex  $<  "$@"
+ 
+$(BUILD_DIR)/%.eep %.eep: $(BUILD_DIR)/%.elf
+	@avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex $< "$@"
+ 
+ 
+-include $(sort $(DEPENDENCIES))
+ 
+$(BUILD_DIR):
+	@mkdir -p $(BUILD_DIR)
+ 
+# Emacs flymake support
+check-syntax:
+	@avr-gcc $(CFLAGS) $(CHKFLAGS) -o /dev/null -S $(CHK_SOURCES)
+ 
+clean:
+	@$(RM) -rf $(BUILD_DIR)
+ 
+?%:
+	@echo '$*=$($*)'
+ 
+?:
+	$(info -------------------------------------------------)
+	$(info Usage:)
+	$(info Source files can be grouped into subdirectories.)
+	$(info To build an executable and attempt to upload it,)
+	$(info use just "make". If the executable requires EEPROM) 
+	$(info initialization, use "make prom".) 
+	$(info )
+	$(info make mymain.hex --> to build a hex-file for mymain.c)
+	$(info make mymain.eep --> for an EEPROM  file for mymain.c)
+	$(info make mymain.elf --> for an elf-file for mymain.c)
+	$(info make ?CFILES    --> show C source files to be used)
+	$(info make ?CPPFILES  --> show C++ source files to be used)
+	$(info make ?HFILES    --> show header files found)
+	$(info make ?HPATHS    --> show header locations)
+	$(info make ?CFLAGS    --> show compiler options)
+	$(info )
+	$(info See the Makefile for more variables that can be)
+	$(info displayed as above.)
+	$(info -------------------------------------------------)
+	@:
+ 
+ 
+# The MIT License (MIT)
+# 
+# Copyright (c) 2014-2015 Klaus-Peter Zauner
+# 
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# 
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+#===================================================================
diff --git a/buttons.c b/buttons.c
new file mode 100644
index 0000000..309f7aa
--- /dev/null
+++ b/buttons.c
@@ -0,0 +1,59 @@
+//
+// Created by platelminto on 2/11/20.
+// Is one of the buttons pressed (only triggers once per press)
+
+#include <avr/io.h>
+#include "lib/rotary/rotary.h"
+
+int up_pressed = 0;
+int right_pressed = 0;
+int down_pressed = 0;
+int left_pressed = 0;
+
+int is_up_pressed() {
+    if (!up_pressed && !((PINC >> SWN) & 1)) {
+        up_pressed = 1;
+        return 1;
+    } else if (!((PINC >> SWN) & 1)) {
+        return 0;
+    } else {
+        up_pressed = 0;
+        return 0;
+    }
+}
+
+int is_right_pressed() {
+    if (!right_pressed && !((PINC >> SWE) & 1)) {
+        right_pressed = 1;
+        return 1;
+    } else if (!((PINC >> SWE) & 1)) {
+        return 0;
+    } else {
+        right_pressed = 0;
+        return 0;
+    }
+}
+
+int is_down_pressed() {
+    if (!down_pressed && !((PINC >> SWS) & 1)) {
+        down_pressed = 1;
+        return 1;
+    } else if (!((PINC >> SWS) & 1)) {
+        return 0;
+    } else {
+        down_pressed = 0;
+        return 0;
+    }
+}
+
+int is_left_pressed() {
+    if (!left_pressed && !((PINC >> SWW) & 1)) {
+        left_pressed = 1;
+        return 1;
+    } else if (!((PINC >> SWW) & 1)) {
+        return 0;
+    } else {
+        left_pressed = 0;
+        return 0;
+    }
+}
\ No newline at end of file
diff --git a/buttons.h b/buttons.h
new file mode 100644
index 0000000..a52bc4c
--- /dev/null
+++ b/buttons.h
@@ -0,0 +1,13 @@
+//
+// Created by platelminto on 2/11/20.
+//
+
+#ifndef TESTING_BUTTONS_H
+#define TESTING_BUTTONS_H
+
+#endif //TESTING_BUTTONS_H
+
+int is_up_pressed(void);
+int is_right_pressed(void);
+int is_down_pressed(void);
+int is_left_pressed(void);
diff --git a/lafortuna.sh b/lafortuna.sh
new file mode 100644
index 0000000..71647e0
--- /dev/null
+++ b/lafortuna.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+#Arguments: flag and file
+FLAG=$1
+FILE=$2
+FILE_HEAD=$(echo $FILE | cut -f1 -d".")
+
+case $FLAG in
+        -hex)
+                echo "Compiling file '$FILE' and creating hex object:"
+                avr-gcc -mmcu=at90usb1286 -DF_CPU=8000000 -Wall -Os $FILE -o $FILE_HEAD.elf
+                avr-objcopy -O ihex $FILE_HEAD.elf $FILE_HEAD.hex
+
+                echo "DONE. Flash using flag -load"
+                ;;
+        -load)
+                echo "Flashing hex program '$FILE' to board:"
+                dfu-programmer at90usb1286 erase
+                dfu-programmer at90usb1286 flash $FILE_HEAD.hex
+                dfu-programmer at90usb1286 reset
+
+                echo "DONE. Restart your LaFortuna board."
+                ;;
+        -all)
+                echo "Compiling file '$FILE' and creating hex object:"
+                avr-gcc -mmcu=at90usb1286 -DF_CPU=8000000 -Wall -Os $FILE -o $FILE_HEAD.elf
+                avr-objcopy -O ihex $FILE_HEAD.elf $FILE_HEAD.hex
+
+                echo "Flashing hex program '$FILE_HEAD' to board:"
+                dfu-programmer at90usb1286 erase
+                dfu-programmer at90usb1286 flash $FILE_HEAD.hex
+                dfu-programmer at90usb1286 reset
+
+                echo "Delete temporary files"
+                rm $FILE_HEAD.elf
+                rm $FILE_HEAD.hex
+
+                echo "DONE. Power cycle your LaFortuna board."
+                ;;
+        -info)
+                echo "------Compile & Flash script for LaFortuna------"
+                echo "--Adapted from ak6g12's script by ec6g13 2015--"
+esac
diff --git a/lib/README.md b/lib/README.md
new file mode 100644
index 0000000..3459092
--- /dev/null
+++ b/lib/README.md
@@ -0,0 +1,5 @@
+# Libraries for the La Fortuna #
+
+* `lcd`: LCD display library - Steve Gunn
+* `led`: LED utility library - Steve Gunn
+* `rotary`: Rotary encoder utility library - Steve Gunn
diff --git a/lib/lcd/font.h b/lib/lcd/font.h
new file mode 100644
index 0000000..3f0a7c8
--- /dev/null
+++ b/lib/lcd/font.h
@@ -0,0 +1,104 @@
+/*  Author: Steve Gunn
+ * Licence: This work is licensed under the Creative Commons Attribution License.
+ *           View this license at http://creativecommons.org/about/licenses/
+ */
+
+#include <avr/pgmspace.h>
+
+const char font5x7[] PROGMEM = {
+	0x00, 0x00, 0x00, 0x00, 0x00, // SPACE
+	0x00, 0x00, 0x5F, 0x00, 0x00, // !
+	0x00, 0x03, 0x00, 0x03, 0x00, // "
+	0x14, 0x3E, 0x14, 0x3E, 0x14, // #
+	0x24, 0x2A, 0x7F, 0x2A, 0x12, // $
+	0x43, 0x33, 0x08, 0x66, 0x61, // %
+	0x36, 0x49, 0x55, 0x22, 0x50, // &
+	0x00, 0x05, 0x03, 0x00, 0x00, // '
+	0x00, 0x1C, 0x22, 0x41, 0x00, // (
+	0x00, 0x41, 0x22, 0x1C, 0x00, // )
+	0x14, 0x08, 0x3E, 0x08, 0x14, // *
+	0x08, 0x08, 0x3E, 0x08, 0x08, // +
+	0x00, 0x50, 0x30, 0x00, 0x00, // ,
+	0x08, 0x08, 0x08, 0x08, 0x08, // -
+	0x00, 0x60, 0x60, 0x00, 0x00, // .
+	0x20, 0x10, 0x08, 0x04, 0x02, // /
+	0x3E, 0x51, 0x49, 0x45, 0x3E, // 0
+	0x00, 0x04, 0x02, 0x7F, 0x00, // 1
+	0x42, 0x61, 0x51, 0x49, 0x46, // 2
+	0x22, 0x41, 0x49, 0x49, 0x36, // 3
+	0x18, 0x14, 0x12, 0x7F, 0x10, // 4
+	0x27, 0x45, 0x45, 0x45, 0x39, // 5
+	0x3E, 0x49, 0x49, 0x49, 0x32, // 6
+	0x01, 0x01, 0x71, 0x09, 0x07, // 7
+	0x36, 0x49, 0x49, 0x49, 0x36, // 8
+	0x26, 0x49, 0x49, 0x49, 0x3E, // 9
+	0x00, 0x36, 0x36, 0x00, 0x00, // :
+	0x00, 0x56, 0x36, 0x00, 0x00, // ;
+	0x08, 0x14, 0x22, 0x41, 0x00, // <
+	0x14, 0x14, 0x14, 0x14, 0x14, // =
+	0x00, 0x41, 0x22, 0x14, 0x08, // >
+	0x02, 0x01, 0x51, 0x09, 0x06, // ?
+	0x3E, 0x41, 0x59, 0x55, 0x5E, // @
+	0x7E, 0x09, 0x09, 0x09, 0x7E, // A
+	0x7F, 0x49, 0x49, 0x49, 0x36, // B
+	0x3E, 0x41, 0x41, 0x41, 0x22, // C
+	0x7F, 0x41, 0x41, 0x41, 0x3E, // D
+	0x7F, 0x49, 0x49, 0x49, 0x41, // E
+	0x7F, 0x09, 0x09, 0x09, 0x01, // F
+	0x3E, 0x41, 0x41, 0x49, 0x3A, // G
+	0x7F, 0x08, 0x08, 0x08, 0x7F, // H
+	0x00, 0x41, 0x7F, 0x41, 0x00, // I
+	0x30, 0x40, 0x40, 0x40, 0x3F, // J
+	0x7F, 0x08, 0x14, 0x22, 0x41, // K
+	0x7F, 0x40, 0x40, 0x40, 0x40, // L
+	0x7F, 0x02, 0x0C, 0x02, 0x7F, // M
+	0x7F, 0x02, 0x04, 0x08, 0x7F, // N
+	0x3E, 0x41, 0x41, 0x41, 0x3E, // O
+	0x7F, 0x09, 0x09, 0x09, 0x06, // P
+	0x1E, 0x21, 0x21, 0x21, 0x5E, // Q
+	0x7F, 0x09, 0x09, 0x09, 0x76, // R
+	0x26, 0x49, 0x49, 0x49, 0x32, // S
+	0x01, 0x01, 0x7F, 0x01, 0x01, // T
+	0x3F, 0x40, 0x40, 0x40, 0x3F, // U
+	0x1F, 0x20, 0x40, 0x20, 0x1F, // V
+	0x7F, 0x20, 0x10, 0x20, 0x7F, // W
+	0x41, 0x22, 0x1C, 0x22, 0x41, // X
+	0x07, 0x08, 0x70, 0x08, 0x07, // Y
+	0x61, 0x51, 0x49, 0x45, 0x43, // Z
+	0x00, 0x7F, 0x41, 0x00, 0x00, // [
+	0x02, 0x04, 0x08, 0x10, 0x20, // slash 
+	0x00, 0x00, 0x41, 0x7F, 0x00, // ]
+	0x04, 0x02, 0x01, 0x02, 0x04, // ^
+	0x40, 0x40, 0x40, 0x40, 0x40, // _
+	0x00, 0x01, 0x02, 0x04, 0x00, // `
+	0x20, 0x54, 0x54, 0x54, 0x78, // a
+	0x7F, 0x44, 0x44, 0x44, 0x38, // b
+	0x38, 0x44, 0x44, 0x44, 0x44, // c
+	0x38, 0x44, 0x44, 0x44, 0x7F, // d
+	0x38, 0x54, 0x54, 0x54, 0x18, // e
+	0x04, 0x04, 0x7E, 0x05, 0x05, // f
+	0x08, 0x54, 0x54, 0x54, 0x3C, // g
+	0x7F, 0x08, 0x04, 0x04, 0x78, // h
+	0x00, 0x44, 0x7D, 0x40, 0x00, // i
+	0x20, 0x40, 0x44, 0x3D, 0x00, // j
+	0x7F, 0x10, 0x28, 0x44, 0x00, // k
+	0x00, 0x41, 0x7F, 0x40, 0x00, // l
+	0x7C, 0x04, 0x78, 0x04, 0x78, // m
+	0x7C, 0x08, 0x04, 0x04, 0x78, // n
+	0x38, 0x44, 0x44, 0x44, 0x38, // o
+	0x7C, 0x14, 0x14, 0x14, 0x08, // p
+	0x08, 0x14, 0x14, 0x14, 0x7C, // q
+	0x00, 0x7C, 0x08, 0x04, 0x04, // r
+	0x48, 0x54, 0x54, 0x54, 0x20, // s
+	0x04, 0x04, 0x3F, 0x44, 0x44, // t
+	0x3C, 0x40, 0x40, 0x20, 0x7C, // u
+	0x1C, 0x20, 0x40, 0x20, 0x1C, // v
+	0x3C, 0x40, 0x30, 0x40, 0x3C, // w
+	0x44, 0x28, 0x10, 0x28, 0x44, // x
+	0x0C, 0x50, 0x50, 0x50, 0x3C, // y
+	0x44, 0x64, 0x54, 0x4C, 0x44, // z
+	0x00, 0x08, 0x36, 0x41, 0x41, // {
+	0x00, 0x00, 0x7F, 0x00, 0x00, // |
+	0x41, 0x41, 0x36, 0x08, 0x00, // }
+	0x02, 0x01, 0x02, 0x04, 0x02};// ~
+
diff --git a/lib/lcd/ili934x.h b/lib/lcd/ili934x.h
new file mode 100644
index 0000000..6629497
--- /dev/null
+++ b/lib/lcd/ili934x.h
@@ -0,0 +1,103 @@
+/*  Author: Steve Gunn
+ * Licence: This work is licensed under the Creative Commons Attribution License.
+ *           View this license at http://creativecommons.org/about/licenses/
+ */
+
+#define BLC			4
+#define RESET		7
+
+#define CMD_ADDR  0x4000
+#define DATA_ADDR 0x4100
+
+#define write_cmd(cmd)				asm volatile("sts %0,%1" :: "i" (CMD_ADDR), "r" (cmd) : "memory");
+#define write_data(data)			asm volatile("sts %0,%1" :: "i" (DATA_ADDR), "r" (data) : "memory");
+#define write_data16(data)			asm volatile("sts %0,%B1 \n\t sts %0,%A1" :: "i" (DATA_ADDR), "r" (data)  : "memory");
+#define write_cmd_data(cmd, data)	asm volatile("sts %0,%1 \n\t sts %2,%3" :: "i" (CMD_ADDR), "r" (cmd), "i" (DATA_ADDR), "r" (data)  : "memory");
+  
+/* Basic Commands */
+#define NO_OPERATION								0x00
+#define SOFTWARE_RESET								0x01
+#define READ_DISPLAY_IDENTIFICATION_INFORMATION		0x04
+#define READ_DISPLAY_STATUS							0x09
+#define READ_DISPLAY_POWER_MODE						0x0A
+#define READ_DISPLAY_MADCTL							0x0B
+#define READ_DISPLAY_PIXEL_FORMAT					0x0C
+#define READ_DISPLAY_IMAGE_FORMAT					0x0D
+#define READ_DISPLAY_SIGNAL_MODE					0x0E
+#define READ_DISPLAY_SELF_DIAGNOSTIC_RESULT			0x0F
+#define ENTER_SLEEP_MODE							0x10
+#define SLEEP_OUT									0x11	
+#define PARTIAL_MODE_ON								0x12
+#define NORMAL_DISPLAY_MODE_ON						0x13
+#define DISPLAY_INVERSION_OFF						0x20
+#define DISPLAY_INVERSION_ON						0x21
+#define GAMMA_SET									0x26
+#define DISPLAY_OFF									0x28
+#define DISPLAY_ON									0x29
+#define COLUMN_ADDRESS_SET							0x2A
+#define PAGE_ADDRESS_SET							0x2B
+#define MEMORY_WRITE								0x2C
+#define COLOR_SET									0x2D
+#define MEMORY_READ									0x2E
+#define PARTIAL_AREA								0x30
+#define VERTICAL_SCROLLING_DEFINITION				0x33
+#define TEARING_EFFECT_LINE_OFF						0x34
+#define TEARING_EFFECT_LINE_ON						0x35
+#define MEMORY_ACCESS_CONTROL						0x36	
+#define VERTICAL_SCROLLING_START_ADDRESS			0x37
+#define IDLE_MODE_OFF								0x38
+#define IDLE_MODE_ON								0x39
+#define PIXEL_FORMAT_SET							0x3A
+#define WRITE_MEMORY_CONTINUE						0x3C
+#define READ_MEMORY_CONTINUE						0x3E
+#define SET_TEAR_SCANLINE							0x44
+#define GET_SCANLINE								0x45
+#define WRITE_DISPLAY_BRIGHTNESS					0x51
+#define READ_DISPLAY_BRIGHTNESS						0x52
+#define WRITE_CTRL_DISPLAY							0x53
+#define READ_CTRL_DISPLAY							0x54
+#define WRITE_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL	0x55
+#define READ_CONTENT_ADAPTIVE_BRIGHTNESS_CONTROL	0x56
+#define WRITE_CABC_MINIMUM_BRIGHTNESS				0x5E
+#define READ_CABC_MINIMUM_BRIGHTNESS				0x5F
+#define READ_ID1									0xDA
+#define READ_ID2									0xDB
+#define READ_ID3									0xDC
+
+/* Extended Commands */
+#define RGB_INTERFACE_SIGNAL_CONTROL				0xB0
+#define FRAME_CONTROL_IN_NORMAL_MODE				0xB1
+#define FRAME_CONTROL_IN_IDLE_MODE					0xB2
+#define FRAME_CONTROL_IN_PARTIAL_MODE				0xB3
+#define DISPLAY_INVERSION_CONTROL					0xB4
+#define BLANKING_PORCH_CONTROL						0xB5
+#define DISPLAY_FUNCTION_CONTROL					0xB6
+#define ENTRY_MODE_SET								0xB7
+#define BACKLIGHT_CONTROL_1							0xB8
+#define BACKLIGHT_CONTROL_2							0xB9
+#define BACKLIGHT_CONTROL_3							0xBA
+#define BACKLIGHT_CONTROL_4							0xBB
+#define BACKLIGHT_CONTROL_5							0xBC
+#define BACKLIGHT_CONTROL_7							0xBE
+#define BACKLIGHT_CONTROL_8							0xBF
+#define POWER_CONTROL_1								0xC0
+#define POWER_CONTROL_2								0xC1
+#define POWER_CONTROL3_(FOR_NORMAL_MODE)			0xC2
+#define POWER_CONTROL4_(FOR_IDLE_MODE)				0xC3
+#define POWER_CONTROL5_(FOR_PARTIAL_MODE)			0xC4
+#define VCOM_CONTROL_1								0xC5
+#define VCOM_CONTROL_2								0xC7
+#define NV_MEMORY_WRITE								0xD0
+#define NV_MEMORY_PROTECTION_KEY					0xD1
+#define NV_MEMORY_STATUS_READ						0xD2
+#define READ_ID4									0xD3
+#define POSITIVE_GAMM_CORRECTION					0xE0
+#define NEGATIVE_GAMMA_CORRECTION					0xE1
+#define DIGITAL_GAMMA_CONTROL						0xE2
+#define DIGITAL_GAMMA_CONTROL2						0xE3
+#define INTERFACE_CONTROL							0xF6
+
+/* Undocumented commands */
+#define INTERNAL_IC_SETTING							0xCB
+#define GAMMA_DISABLE								0xF2
+
diff --git a/lib/lcd/lcd.c b/lib/lcd/lcd.c
new file mode 100644
index 0000000..3eaf9cf
--- /dev/null
+++ b/lib/lcd/lcd.c
@@ -0,0 +1,262 @@
+/*  Author: Steve Gunn
+ * Licence: This work is licensed under the Creative Commons Attribution License.
+ *           View this license at http://creativecommons.org/about/licenses/
+ *
+ *  
+ *  - Jan 2015  Modified for LaFortuna (Rev A, black edition) [KPZ]
+ */
+
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+#include "font.h"
+#include "ili934x.h"
+#include "lcd.h"
+
+lcd display;
+
+void init_lcd()
+{
+    /* Enable extended memory interface with 10 bit addressing */
+    XMCRB = _BV(XMM2) | _BV(XMM1);
+    XMCRA = _BV(SRE);
+    DDRC |= _BV(RESET);
+    DDRB |= _BV(BLC);
+    _delay_ms(1);
+    PORTC &= ~_BV(RESET);
+    _delay_ms(20);
+    PORTC |= _BV(RESET);
+    _delay_ms(120);
+    write_cmd(DISPLAY_OFF);
+    write_cmd(SLEEP_OUT);
+    _delay_ms(60);
+    write_cmd_data(INTERNAL_IC_SETTING,          0x01);
+    write_cmd(POWER_CONTROL_1);
+        write_data16(0x2608);
+    write_cmd_data(POWER_CONTROL_2,              0x10);
+    write_cmd(VCOM_CONTROL_1);
+        write_data16(0x353E);
+    write_cmd_data(VCOM_CONTROL_2, 0xB5);
+    write_cmd_data(INTERFACE_CONTROL, 0x01);
+        write_data16(0x0000);
+    write_cmd_data(PIXEL_FORMAT_SET, 0x55);     /* 16bit/pixel */
+    set_orientation(West);
+    clear_screen();
+    display.x = 0;
+    display.y = 0;
+    display.background = BLACK;
+    display.foreground = WHITE;
+    write_cmd(DISPLAY_ON);
+    _delay_ms(50);
+    write_cmd_data(TEARING_EFFECT_LINE_ON, 0x00);
+    EICRB |= _BV(ISC61);
+    PORTB |= _BV(BLC);
+}
+
+void lcd_brightness(uint8_t i)
+{
+    /* Configure Timer 2 Fast PWM Mode 3 */
+    TCCR2A = _BV(COM2A1) | _BV(WGM21) | _BV(WGM20);
+    TCCR2B = _BV(CS20);
+    OCR2A = i;
+}
+
+void set_orientation(orientation o)
+{
+    display.orient = o;
+    write_cmd(MEMORY_ACCESS_CONTROL);
+    if (o==North) { 
+        display.width = LCDWIDTH;
+        display.height = LCDHEIGHT;
+        write_data(0x48);
+    }
+    else if (o==West) {
+        display.width = LCDHEIGHT;
+        display.height = LCDWIDTH;
+        write_data(0xE8);
+    }
+    else if (o==South) {
+        display.width = LCDWIDTH;
+        display.height = LCDHEIGHT;
+        write_data(0x88);
+    }
+    else if (o==East) {
+        display.width = LCDHEIGHT;
+        display.height = LCDWIDTH;
+        write_data(0x28);
+    }
+    write_cmd(COLUMN_ADDRESS_SET);
+    write_data16(0);
+    write_data16(display.width-1);
+    write_cmd(PAGE_ADDRESS_SET);
+    write_data16(0);
+    write_data16(display.height-1);
+}
+
+
+
+void set_frame_rate_hz(uint8_t f)
+{
+    uint8_t diva, rtna, period;
+    if (f>118)
+        f = 118;
+    if (f<8)
+        f = 8;
+    if (f>60) {
+        diva = 0x00;
+    } else if (f>30) {
+        diva = 0x01;
+    } else if (f>15) {
+        diva = 0x02;
+    } else {
+        diva = 0x03;
+    }
+    /*   !!! FIXME !!!  [KPZ-30.01.2015] */
+    /*   Check whether this works for diva > 0  */
+    /*   See ILI9341 datasheet, page 155  */
+    period = 1920.0/f;
+    rtna = period >> diva;
+    write_cmd(FRAME_CONTROL_IN_NORMAL_MODE);
+    write_data(diva);
+    write_data(rtna);
+}
+
+void fill_rectangle(rectangle r, uint16_t col)
+{
+    write_cmd(COLUMN_ADDRESS_SET);
+    write_data16(r.left);
+    write_data16(r.right);
+    write_cmd(PAGE_ADDRESS_SET);
+    write_data16(r.top);
+    write_data16(r.bottom);
+    write_cmd(MEMORY_WRITE);
+/*  uint16_t x, y;
+    for(x=r.left; x<=r.right; x++)
+        for(y=r.top; y<=r.bottom; y++)
+            write_data16(col);
+*/
+    uint16_t wpixels = r.right - r.left + 1;
+    uint16_t hpixels = r.bottom - r.top + 1;
+    uint8_t mod8, div8;
+    uint16_t odm8, odd8;
+    if (hpixels > wpixels) {
+        mod8 = hpixels & 0x07;
+        div8 = hpixels >> 3;
+        odm8 = wpixels*mod8;
+        odd8 = wpixels*div8;
+    } else {
+        mod8 = wpixels & 0x07;
+        div8 = wpixels >> 3;
+        odm8 = hpixels*mod8;
+        odd8 = hpixels*div8;
+    }
+    uint8_t pix1 = odm8 & 0x07;
+    while(pix1--)
+        write_data16(col);
+
+    uint16_t pix8 = odd8 + (odm8 >> 3);
+    while(pix8--) {
+        write_data16(col);
+        write_data16(col);
+        write_data16(col);
+        write_data16(col);
+        write_data16(col);
+        write_data16(col);
+        write_data16(col);
+        write_data16(col);
+    }
+}
+
+void fill_rectangle_indexed(rectangle r, uint16_t* col)
+{
+    uint16_t x, y;
+    write_cmd(COLUMN_ADDRESS_SET);
+    write_data16(r.left);
+    write_data16(r.right);
+    write_cmd(PAGE_ADDRESS_SET);
+    write_data16(r.top);
+    write_data16(r.bottom);
+    write_cmd(MEMORY_WRITE);
+    for(x=r.left; x<=r.right; x++)
+        for(y=r.top; y<=r.bottom; y++)
+            write_data16(*col++);
+}
+
+void clear_screen()
+{
+    display.x = 0;
+    display.y = 0;
+    rectangle r = {0, display.width-1, 0, display.height-1};
+    fill_rectangle(r, display.background);
+}
+
+void display_char(char c)
+{
+    uint16_t x, y;
+    PGM_P fdata; 
+    uint8_t bits, mask;
+    uint16_t sc=display.x, ec=display.x + 4, sp=display.y, ep=display.y + 7;
+
+    /*   New line starts a new line, or if the end of the
+         display has been reached, clears the display.
+    */
+    if (c == '\n') { 
+        display.x=0; display.y+=8;
+        if (display.y >= display.height) { clear_screen(); }
+        return;
+    }
+
+    if (c < 32 || c > 126) return;
+    fdata = (c - ' ')*5 + font5x7;
+    write_cmd(PAGE_ADDRESS_SET);
+    write_data16(sp);
+    write_data16(ep);
+    for(x=sc; x<=ec; x++) {
+        write_cmd(COLUMN_ADDRESS_SET);
+        write_data16(x);
+        write_data16(x);
+        write_cmd(MEMORY_WRITE);
+        bits = pgm_read_byte(fdata++);
+        for(y=sp, mask=0x01; y<=ep; y++, mask<<=1)
+            write_data16((bits & mask) ? display.foreground : display.background);
+    }
+    write_cmd(COLUMN_ADDRESS_SET);
+    write_data16(x);
+    write_data16(x);
+    write_cmd(MEMORY_WRITE);
+    for(y=sp; y<=ep; y++)
+        write_data16(display.background);
+
+    display.x += 6;
+    if (display.x >= display.width) { display.x=0; display.y+=8; }
+}
+
+void display_string(char *str)
+{
+    uint8_t i;
+    for(i=0; str[i]; i++) 
+        display_char(str[i]);
+}
+
+void display_string_xy(char *str, uint16_t x, uint16_t y)
+{
+    uint8_t i;
+    display.x = x;
+    display.y = y;
+    for(i=0; str[i]; i++)
+        display_char(str[i]);
+}
+
+void display_register(uint8_t reg)
+{
+	uint8_t i;
+
+	for(i = 0; i < 8; i++) {
+		if((reg & (_BV(7) >> i)) != 0) {
+			display_char( '1' );
+		} else {
+			display_char( '.' );
+		}
+	}
+}
+
diff --git a/lib/lcd/lcd.h b/lib/lcd/lcd.h
new file mode 100644
index 0000000..7366346
--- /dev/null
+++ b/lib/lcd/lcd.h
@@ -0,0 +1,49 @@
+/*  Author: Steve Gunn
+ * Licence: This work is licensed under the Creative Commons Attribution License.
+ *           View this license at http://creativecommons.org/about/licenses/
+ */
+ 
+#include <avr/io.h>
+#include <stdint.h>
+
+
+#define LCDWIDTH	240
+#define LCDHEIGHT	320
+
+/* Colour definitions RGB565 */
+#define WHITE       0xFFFF
+#define BLACK       0x0000
+#define BLUE        0x001F      
+#define GREEN       0x07E0      
+#define CYAN        0x07FF      
+#define RED         0xF800      
+#define MAGENTA     0xF81F      
+#define YELLOW      0xFFE0      
+
+typedef enum {North, West, South, East} orientation;
+
+typedef struct {
+	uint16_t width, height;
+	orientation orient;
+	uint16_t x, y;
+	uint16_t foreground, background;
+} lcd;
+
+extern lcd display;
+
+typedef struct {
+	uint16_t left, right;
+	uint16_t top, bottom;
+} rectangle;	
+
+void init_lcd();
+void lcd_brightness(uint8_t i);
+void set_orientation(orientation o);
+void set_frame_rate_hz(uint8_t f);
+void clear_screen();
+void fill_rectangle(rectangle r, uint16_t col);
+void fill_rectangle_indexed(rectangle r, uint16_t* col);
+void display_char(char c);
+void display_string(char *str);
+void display_string_xy(char *str, uint16_t x, uint16_t y);
+void display_register(uint8_t reg);
diff --git a/lib/led/led.c b/lib/led/led.c
new file mode 100644
index 0000000..b57f737
--- /dev/null
+++ b/lib/led/led.c
@@ -0,0 +1,36 @@
+/*  Author: Steve Gunn
+ * Licence: This work is licensed under the Creative Commons Attribution License.
+ *           View this license at http://creativecommons.org/about/licenses/
+ */
+ 
+#include <avr/io.h>
+#include "led.h"
+
+void init_led()
+{
+	DDRB |= _BV(LED);
+	PORTB &= ~_BV(LED);
+}
+
+void led_on()
+{
+	PORTB |= _BV(LED);
+}
+
+void led_off()
+{
+	TCCR0A = 0x00;
+	TCCR0B = 0x00;
+	PORTB &= ~_BV(LED);
+}
+
+void led_brightness(uint8_t i)
+{
+	/* Configure Timer 0 Fast PWM Mode 3 */
+	TCCR0A = _BV(COM0A1) | _BV(WGM01) | _BV(WGM00);
+	TCCR0B = _BV(CS20);
+	OCR0A = i;
+}
+
+
+
diff --git a/lib/led/led.h b/lib/led/led.h
new file mode 100644
index 0000000..76a7008
--- /dev/null
+++ b/lib/led/led.h
@@ -0,0 +1,14 @@
+/*  Author: Steve Gunn
+ * Licence: This work is licensed under the Creative Commons Attribution License.
+ *           View this license at http://creativecommons.org/about/licenses/
+ */
+ 
+#include <stdint.h>
+
+#define LED		PB7
+
+void init_led();
+void led_on();
+void led_off();
+void led_brightness(uint8_t i);
+
diff --git a/lib/rotary/rotary.c b/lib/rotary/rotary.c
new file mode 100644
index 0000000..c1b1cfc
--- /dev/null
+++ b/lib/rotary/rotary.c
@@ -0,0 +1,48 @@
+/*  Author: Steve Gunn
+ * Licence: This work is licensed under the Creative Commons Attribution License.
+ *           View this license at http://creativecommons.org/about/licenses/
+ */
+ 
+#include <avr/io.h>
+#include <avr/interrupt.h>
+#include <util/delay.h>
+#include "rotary.h"
+
+volatile int8_t rotary = 0;
+
+void init_rotary()
+{
+	/* Ensure all pins are inputs with pull-ups enabled */
+	DDRE &= ~_BV(ROTA) & ~_BV(ROTB) & ~_BV(SWC);
+	PORTE |= _BV(ROTA) | _BV(ROTB) | _BV(SWC);
+	DDRC &= ~_BV(SWN) & ~_BV(SWE) & ~_BV(SWS) & ~_BV(SWW);
+	PORTC |= _BV(SWN) | _BV(SWE) | _BV(SWS) | _BV(SWW);
+	/* Configure interrupt for any edge on rotary and falling edge for button */
+	EICRB |= _BV(ISC40) | _BV(ISC50) | _BV(ISC71);
+}
+
+int8_t get_rotary()
+{
+	static uint8_t lastAB = 0x00;
+	uint8_t AB = PINE & (_BV(ROTA) | _BV(ROTB));
+	if ((AB == 0x00 && lastAB == 0x20) || (AB == 0x30 && lastAB == 0x10))
+		rotary--;
+	if ((AB == 0x30 && lastAB == 0x20) || (AB == 0x00 && lastAB == 0x10))
+		rotary++;
+	lastAB = AB;
+	return rotary;
+}
+
+uint8_t get_switch()
+{
+	return PINC & (_BV(SWN) | _BV(SWE) | _BV(SWS) | _BV(SWW));
+}
+
+ISR(INT4_vect)
+{
+	get_rotary();
+	_delay_us(100);
+}
+
+ISR(INT5_vect, ISR_ALIASOF(INT4_vect));
+
diff --git a/lib/rotary/rotary.h b/lib/rotary/rotary.h
new file mode 100644
index 0000000..2decfce
--- /dev/null
+++ b/lib/rotary/rotary.h
@@ -0,0 +1,21 @@
+/*  Author: Steve Gunn
+ * Licence: This work is licensed under the Creative Commons Attribution License.
+ *           View this license at http://creativecommons.org/about/licenses/
+ */
+ 
+#include <stdint.h>
+
+#define ROTA	PE4
+#define ROTB	PE5
+#define SWC		PE7
+#define SWN		PC2
+#define SWE		PC3
+#define SWS		PC4
+#define SWW		PC5
+
+extern volatile int8_t rotary;
+
+void init_rotary();
+int8_t get_rotary();
+uint8_t get_switch();
+
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..db5adaa
--- /dev/null
+++ b/main.c
@@ -0,0 +1,287 @@
+/* Configure I/O Ports */
+
+/* For La Fortuna board
+
+   | Port | Pin | Function         |
+   |------+-----+------------------|
+   | C    |   2 | Up Button        |
+   | C    |   3 | Right Button     |
+   | C    |   4 | Down Button      |
+   | C    |   5 | Left Button      |
+
+*/
+
+#include <stdio.h>
+#include <avr/io.h>
+#include <util/delay.h>
+#include <avr/interrupt.h>
+#include <time.h>
+#include <stdlib.h>
+#include "lib/lcd/lcd.h"
+#include "lib/rotary/rotary.h"
+#include "buttons.h"
+#include "main.h"
+
+#define FPS 10
+#define BLOCK_SIZE 8
+#define SCREEN_WIDTH 320
+#define DIFFICULTY_INTERVAL 130
+#define SCREEN_HEIGHT 240
+#define UP_BUFFER 0
+#define RIGHT_BUFFER 1
+#define DOWN_BUFFER 2
+#define LEFT_BUFFER 3
+#define MAX_ENEMIES ((SCREEN_WIDTH / BLOCK_SIZE) * (SCREEN_HEIGHT / BLOCK_SIZE)) / 2
+
+#define max(x,y) ((x) >= (y)) ? (x) : (y)
+#define min(x,y) ((x) <= (y)) ? (x) : (y)
+
+/* Bits 0-3: Up, Right, Down, Left */
+volatile uint8_t MOVEMENT_BUFFER = 0;
+
+volatile uint16_t x = SCREEN_WIDTH/2;
+volatile uint16_t y = SCREEN_HEIGHT/2;
+
+volatile uint16_t apple_x;
+volatile uint16_t apple_y;
+
+volatile uint8_t enemy_spawn_chance = 1;
+
+struct coord {uint16_t x; uint16_t y;};
+
+volatile struct coord enemies[MAX_ENEMIES];
+volatile uint16_t current_enemies = 0;
+
+volatile uint16_t current_difficulty_time = 0;
+
+volatile uint16_t score = 0;
+
+rectangle snake_head = {SCREEN_WIDTH/2, SCREEN_WIDTH/2 + BLOCK_SIZE,
+                   SCREEN_HEIGHT/2, SCREEN_HEIGHT/2 + BLOCK_SIZE};
+rectangle previous_block;
+
+rectangle apple;
+
+volatile uint8_t tick = 0;
+
+enum move{Up, Right, Down, Left};
+
+// uint8_t moves_buffered = 0;
+// uint8_t moves[NUMBER_MOVES_BUFFERED];
+volatile enum move current_direction = Right;
+
+void init(void) {
+
+    /* 8MHz clock, no prescaling (DS, p. 48) */
+    CLKPR = (1 << CLKPCE);
+    CLKPR = 0;
+
+    init_lcd();
+
+    set_frame_rate_hz(61);
+    /* Enable tearing interrupt to get flicker free display */
+    EIMSK |= _BV(INT6);
+
+    /* Set as input */
+    DDRC &= ~_BV(SWN) & ~_BV(SWE) & ~_BV(SWS) & ~_BV(SWW);
+    /* Enable direction buttons */
+    PORTC |= _BV(SWN) | _BV(SWE) | _BV(SWS) | _BV(SWW);
+
+    /* Timer 0 for button listening interrupt: */
+    TCCR0A = _BV(WGM01);
+    TCCR0B = _BV(CS02) | _BV(CS00); /* F_CPU / 1024 */
+
+    /* Timer 3 (16-bit) for frame counting */
+    TCCR3A = 0;
+    TCCR3B |= _BV(WGM32);
+    TCCR3B |= _BV(CS32) | _BV(CS30); /* F_CPU / 1024 */
+
+    OCR0A = 78; /* 8MHz clock / 1024 (from TCCR0B flags) / 100 (for ~10ms delay) */
+    OCR3A = 7812 / FPS; /* 8MHz clock / 1024 / FPS */
+
+    /* Enable timer interrupts */
+    TIMSK0 |= _BV(OCIE0A);
+    TIMSK3 |= _BV(OCIE3A);
+
+    /* Set seed for random numbers */
+    srand(time(NULL));
+}
+
+ISR(TIMER3_COMPA_vect) {
+    tick = 1;
+}
+
+ISR(TIMER0_COMPA_vect) {
+    if (is_up_pressed()) {
+        MOVEMENT_BUFFER |= _BV(UP_BUFFER);
+    } else if (is_right_pressed()) {
+        MOVEMENT_BUFFER |= _BV(RIGHT_BUFFER);
+    } else if (is_down_pressed()) {
+        MOVEMENT_BUFFER |= _BV(DOWN_BUFFER);
+    } else if (is_left_pressed()) {
+        MOVEMENT_BUFFER |= _BV(LEFT_BUFFER);
+    }
+}
+
+void redraw_apple(void) {
+    apple_x = (rand() % (SCREEN_WIDTH / 8)) * 8;
+    apple_y = (rand() % (SCREEN_HEIGHT / 8)) * 8;
+
+    if (apple_y == 0) {
+        apple_y = BLOCK_SIZE;
+    }
+
+    apple.left = apple_x;
+    apple.right = apple_x + BLOCK_SIZE;
+    apple.top = apple_y;
+    apple.bottom = apple_y + BLOCK_SIZE;
+
+    fill_rectangle(apple, 3000);
+}
+
+void clear_enemies(void) {
+    for (uint16_t i = 0; i < current_enemies; i++) {
+        rectangle enemy;
+        enemy.left = enemies[i].x;
+        enemy.right = enemies[i].x + BLOCK_SIZE;
+        enemy.top = enemies[i].y;
+        enemy.bottom = enemies[i].y + BLOCK_SIZE;
+        fill_rectangle(enemy, 0);
+    }
+
+    current_enemies = 0;
+}
+
+void reset(void) {
+    _delay_ms(1000);
+    fill_rectangle(apple, 0);
+    clear_enemies();
+    score = 0;
+    enemy_spawn_chance = 1;
+    current_direction = Right;
+    x = SCREEN_WIDTH/2;
+    y = SCREEN_HEIGHT/2;
+    redraw_apple();
+    info_redraw_logic();
+}
+
+void snake_move_logic(void) {
+    switch (current_direction) {
+        case Up:
+            y -= BLOCK_SIZE;
+            break;
+        case Right:
+            x += BLOCK_SIZE;
+            break;
+        case Down:
+            y += BLOCK_SIZE;
+            break;
+        case Left:
+            x -= BLOCK_SIZE;
+            break;
+    }
+
+    if (y > SCREEN_HEIGHT - BLOCK_SIZE || /* Don't need to handle < 0 as it's unsigned */
+        x > SCREEN_WIDTH - BLOCK_SIZE) {
+        reset();
+    }
+
+    previous_block = snake_head;
+
+    snake_head.left = x;
+    snake_head.right = x + BLOCK_SIZE;
+    snake_head.top = y;
+    snake_head.bottom = y + BLOCK_SIZE;
+}
+
+void snake_direction_logic(void) {
+    if ((MOVEMENT_BUFFER >> UP_BUFFER) & 1) {
+        current_direction = Up;
+        MOVEMENT_BUFFER = 0;
+    }
+    if ((MOVEMENT_BUFFER >> RIGHT_BUFFER) & 1) {
+        current_direction = Right;
+        MOVEMENT_BUFFER = 0;
+    }
+    if ((MOVEMENT_BUFFER >> DOWN_BUFFER) & 1) {
+        current_direction = Down;
+        MOVEMENT_BUFFER = 0;
+    }
+    if (((MOVEMENT_BUFFER >> LEFT_BUFFER) & 1)) {
+        current_direction = Left;
+        MOVEMENT_BUFFER = 0;
+    }
+}
+
+void enemy_spawn_logic(void) {
+    if (rand() % 180 <= enemy_spawn_chance) {
+        struct coord c = {(rand() % (SCREEN_WIDTH / 8)) * 8, (rand() % (SCREEN_HEIGHT / 8)) * 8};
+        while ((c.x == x && c.y == y) || (c.x == apple_x && c.y == apple_y)) {
+            c.x = (rand() % (SCREEN_WIDTH / 8)) * 8;
+            c.y = (rand() % (SCREEN_HEIGHT / 8)) * 8;
+        }
+        enemies[current_enemies++] = c;
+        rectangle enemy;
+        enemy.left = c.x;
+        enemy.right = c.x + BLOCK_SIZE;
+        enemy.top = c.y;
+        enemy.bottom = c.y + BLOCK_SIZE;
+        fill_rectangle(enemy, RED);
+    }
+}
+
+void snake_draw_logic(void) {
+    fill_rectangle(previous_block, 0);
+    fill_rectangle(snake_head, 5000);
+}
+
+void info_redraw_logic(void) {
+    char str[50];
+    sprintf(str, "Score: %05d  Difficulty: %d", score, enemy_spawn_chance);
+    display_string_xy(str, 0, 0);
+}
+
+ISR(INT6_vect) {
+    snake_draw_logic();
+    info_redraw_logic();
+}
+
+void apple_draw_logic(void) {
+    if (apple_x == x && apple_y == y) {
+        clear_enemies();
+        score += 200;
+        redraw_apple();
+    }
+}
+
+void enemy_collision_logic(void) {
+    for (uint16_t i = 0; i < current_enemies; i++) {
+        if (enemies[i].x == x && enemies[i].y == y) {
+            reset();
+        }
+    }
+}
+
+int main() {
+    init();
+
+    sei();
+
+    reset();
+
+    for (;;) {
+        if (tick) {
+            snake_direction_logic();
+            snake_move_logic();
+            apple_draw_logic();
+            enemy_collision_logic();
+            enemy_spawn_logic();
+            if (current_difficulty_time++ >= DIFFICULTY_INTERVAL) {
+                enemy_spawn_chance++;
+                current_difficulty_time = 0;
+            }
+            score++;
+            tick = 0;
+        }
+    }
+}
diff --git a/main.h b/main.h
new file mode 100644
index 0000000..b8da695
--- /dev/null
+++ b/main.h
@@ -0,0 +1,9 @@
+//
+// Created by platelminto on 5/20/20.
+//
+
+#ifndef SNAKE_MAIN_H
+#define SNAKE_MAIN_H
+
+#endif //SNAKE_MAIN_H
+
-- 
GitLab