diff --git a/SW/libs/.gitignore b/SW/libs/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..8402f28708a3b5199bce33ed32fb6797af661894
--- /dev/null
+++ b/SW/libs/.gitignore
@@ -0,0 +1,29 @@
+*.[oad]
+*~
+*.mk
+*.elf
+*.lss
+*.map
+*.srec
+*makefile*
+*.b#*
+*.s#*
+*.asc
+*.epf
+*.pro
+*.cproject
+*.project
+*.atsln
+*.atsuo
+*.cppproj
+*.epp
+*.db
+*.d
+*.o
+*.mk
+*.elf
+*.lss
+*.map
+*.srec
+.idea/
+build/
diff --git a/SW/libs/CMakeLists.txt b/SW/libs/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6b0d2c477f4af1c6fe43214b22d6c9256b66d472
--- /dev/null
+++ b/SW/libs/CMakeLists.txt
@@ -0,0 +1,41 @@
+set(LIB_FILES
+    src/adc.cpp
+    src/adc.h
+    src/external_interrupt.h
+    src/jtag.cpp
+    src/jtag.h
+    src/MCP2515.cpp
+    src/MCP2515.h
+    src/MFRC522.cpp
+    src/MFRC522.h
+    src/spi.cpp
+    src/spi.h
+    src/usart.cpp
+    src/usart.h
+    src/wait.cpp
+    src/wait.h
+    src/macros.h
+    src/fifo.h
+    src/cplusplus.h
+    src/cplusplus.cpp
+    src/gpio.h
+    src/circularbuffer.h
+  )
+
+if((${AVR_MCU} STREQUAL "atmega8") OR (${AVR_MCU} STREQUAL "atmega8a"))
+  set(LIB_FILES ${LIB_FILES}
+      src/external_interrupt/ext_irq_m8.h
+      src/external_interrupt/ext_irq_m8.cpp)
+elseif((${AVR_MCU} STREQUAL atmega16) OR (${AVR_MCU} STREQUAL atmega16a) OR (${AVR_MCU} STREQUAL atmega32) OR (${AVR_MCU} STREQUAL atmega32a))
+  set(LIB_FILES ${LIB_FILES}
+      src/external_interrupt/ext_irq_m32.h
+      src/external_interrupt/ext_irq_m32.cpp)
+elseif((${AVR_MCU} STREQUAL "atmega128") OR (${AVR_MCU} STREQUAL "atmega128a") OR (${AVR_MCU} STREQUAL "atmega1281"))
+  set(LIB_FILES ${LIB_FILES}
+      src/external_interrupt/ext_irq_m128.h
+      src/external_interrupt/ext_irq_m128.cpp)
+else((${AVR_MCU} STREQUAL "atmega8") OR (${AVR_MCU} STREQUAL "atmega8a"))
+  message(FATAL_ERROR "Unsupported device ${AVR_MCU}")
+endif((${AVR_MCU} STREQUAL "atmega8") OR (${AVR_MCU} STREQUAL "atmega8a"))
+
+add_avr_library(rk ${LIB_FILES})
diff --git a/SW/libs/README.md b/SW/libs/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..0b72655087451f6f94a3b002200422cb959153aa
--- /dev/null
+++ b/SW/libs/README.md
@@ -0,0 +1,21 @@
+## AVR knihovny ##
+
+***
+### Build ###
+```bash
+cd rk-avr-libs
+mkdir build && cd build
+cmake ..
+make
+```
+***
+### Install Fedora only
+`./install.sh`
+
+***
+### Problémy
+- v knihovnách nelze používat makra →
+  - věci jako F_CPU se musí řešit přes API knihovny
+  - podobě u SPI, kde je nastavování pinů pro jednotlivé druhy atmeg řešeno přes #define
+- nevĂ­m, jestli se musĂ­ u knihovny specifikovat typ MCU → nastává problĂ©m se definicemi pinĹŻ a registrĹŻ
+- wait example nejde zkmpompilovat... nechápu...
diff --git a/SW/libs/examples/uart/CMakeLists.txt b/SW/libs/examples/uart/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f71ad710366a90f8c4d30a0df75e1fbeb0796fdd
--- /dev/null
+++ b/SW/libs/examples/uart/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(uart_example)
+
+set(AVR_UPLOADTOOL avrdude)
+set(AVR_PROGRAMMER usbasp)
+set(AVR_UPLOADTOOL_PORT usb)
+set(AVR_MCU atmega8)
+set(AVR_H_FUSE 0xd9)
+set(AVR_L_FUSE 0xe4)
+set(CMAKE_BUILD_TYPE Release)
+set(MCU_SPEED "1000000UL")
+set(WITH_MCU OFF)
+set(WITH_MCU OFF CACHE BOOL "Add the mCU type to the target file name." FORCE)
+
+find_package(avr)
+
+add_definitions("-fpack-struct")
+add_definitions("-fshort-enums")
+add_definitions("-Wall")
+add_definitions("-funsigned-char")
+add_definitions("-funsigned-bitfields")
+add_definitions("-ffunction-sections")
+add_definitions("-c")
+add_definitions("-std=c++14")
+
+#SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
+
+set(SOURCE_FILES main.cpp)
+
+include_directories(../../src)
+add_subdirectory(../../ rk)
+
+add_avr_executable(uart_example ${SOURCE_FILES})
+avr_target_link_libraries(uart_example rk)
diff --git a/SW/libs/examples/uart/main.cpp b/SW/libs/examples/uart/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..f2f09c0c23f48168fda6a91ecf43d7ed66e7a7b7
--- /dev/null
+++ b/SW/libs/examples/uart/main.cpp
@@ -0,0 +1,31 @@
+#include <avr/io.h>
+#include "usart.h"
+
+int main()
+{
+    //Vytvoření objektu uart
+    usart uart;
+
+    //NastavenĂ­ uartu
+    uart.set_operating_mode(ASYNCHRONOUS_NORMAL);
+    uart.set_baudrate(4800);
+    uart.set_data_bits(8);
+    uart.set_stop_bits(1);
+    uart.set_parity(PARITY_NONE);
+    uart.enable_reciver(true);
+    uart.enable_trasmitter(true);
+
+    //Odeslání textového řetězce
+    uart.transmit_string("\n\rHello world!\n\r");
+
+    char znak;
+
+    for(;;)
+    {
+        //Přijmi znak
+        znak = uart.receive_char();
+
+        //Odešli znak zpátky
+        uart.transmit_char(znak);
+    }
+}
\ No newline at end of file
diff --git a/SW/libs/examples/wait/CMakeLists.txt b/SW/libs/examples/wait/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..934a42df0517811a732ea6cdb61c55bf79a74493
--- /dev/null
+++ b/SW/libs/examples/wait/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(wait_example)
+
+set(AVR_UPLOADTOOL avrdude)
+set(AVR_PROGRAMMER usbasp)
+set(AVR_UPLOADTOOL_PORT usb)
+set(AVR_MCU atmega8)
+set(AVR_H_FUSE 0xd9)
+set(AVR_L_FUSE 0xe4)
+set(CMAKE_BUILD_TYPE Release)
+set(MCU_SPEED "1000000UL")
+set(WITH_MCU OFF)
+set(WITH_MCU OFF CACHE BOOL "Add the mCU type to the target file name." FORCE)
+
+find_package(avr)
+
+add_definitions("-fpack-struct")
+add_definitions("-fshort-enums")
+add_definitions("-Wall")
+add_definitions("-funsigned-char")
+add_definitions("-funsigned-bitfields")
+add_definitions("-ffunction-sections")
+add_definitions("-c")
+add_definitions("-std=c++14")
+
+#SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
+SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "")
+
+set(SOURCE_FILES main.cpp)
+
+include_directories(../../src)
+add_subdirectory(../../ rk)
+
+add_avr_executable(wait_example ${SOURCE_FILES})
+avr_target_link_libraries(wait_example rk)
diff --git a/SW/libs/examples/wait/main.cpp b/SW/libs/examples/wait/main.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a3384607e16d043be26a8c1f8d794a7dfdcabfa2
--- /dev/null
+++ b/SW/libs/examples/wait/main.cpp
@@ -0,0 +1,19 @@
+#include <avr/io.h>
+#include "wait.h"
+
+
+int main()
+{
+    DDRC |= (1<<PC5);
+
+    //NastavenĂ­ frekvence MCU pro metody wait (F_CPU se nastavuje v CMakeLists.txt)
+    w.set_f_cpu(F_CPU);
+
+    for(;;)
+    {
+        PORTC ^= (1<<PC5);
+
+        //ÄŚekej 250ms
+        w.wait_ms(250);
+    }
+}
\ No newline at end of file
diff --git a/SW/libs/install.sh b/SW/libs/install.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b1763e5c54ab46cc77c1e5391de5ad847ded1482
--- /dev/null
+++ b/SW/libs/install.sh
@@ -0,0 +1,15 @@
+#!/bin/bash
+
+# Make sure only root can run our script
+if [[ $EUID -ne 0 ]]; then
+   echo "This script must be run as root" 1>&2
+   exit 1
+fi
+
+if [ ! -d /usr/avr/rk ]; then
+  sudo mkdir /usr/avr/include/rk
+fi
+
+cp src/* /usr/avr/rk/
+
+echo Done
diff --git a/SW/libs/src/MCP2515.cpp b/SW/libs/src/MCP2515.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3249c23478e3f19ff6c223a7a93ca95a5b709ef1
--- /dev/null
+++ b/SW/libs/src/MCP2515.cpp
@@ -0,0 +1,324 @@
+/* 
+* MCP2515.cpp
+*
+* Created: 5.2.2014 19:53:58
+* Author: MTV
+*/
+
+
+#include "MCP2515.h"
+#include "wait.h"
+#include "fifo.h"
+
+//spi_select_class spi(&DDRB, &PORTB, PB4);
+
+
+// default constructor
+MCP2515::MCP2515(spi_class &spi): spi(spi)
+{
+	//spi_ini();
+	//reset();
+} //MCP2515
+
+// default destructor
+MCP2515::~MCP2515()
+{
+} //~MCP2515
+
+//Inizializace SPI rozhrani
+void MCP2515::spi_ini(void)
+{
+	spi.set_operating_mode(spi.MASTER);
+	spi.enable_SPI();
+	spi.set_data_order(spi.MSB);	
+	spi.set_data_mode(spi.DATA_MODE_0);
+	spi.set_clock_rate(spi.F_OSC_2);
+} //void spi_ini(void)
+
+//////////////////////////////////////////////////////////////////////////
+/////////////////////////////Inicializace/////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void MCP2515::set_baudrate(uint8_t CNF1_val, uint8_t CNF2_val, uint8_t CNF3_val)
+{
+	spi.select(true);
+	
+	spi.write_data(SPI_WRITE);
+	spi.write_data(CNF3);
+	spi.write_data(CNF3_val);
+	spi.write_data(CNF2_val);
+	spi.write_data(CNF1_val);
+	
+	spi.select(false);
+} //void set_baudrate(uint8_t CNF1_val, uint8_t CNF3_val, uint8_t CNF2_val)
+
+void MCP2515::set_RX0BF_pin(uint8_t mode)
+{
+		 if (mode == RX_BUFFER_FULL_IRQ) modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), (1<<B0BFE) | (1<<B0BFM));
+	else if (mode == DIGITAL_OUTPUT)	 modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), (1<<B0BFE));
+	else if (mode == ON)				 modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), (1<<B0BFE));
+	else if (mode == OFF)				 modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), (1<<B0BFE) | (1<<B0BFS));
+	else modify_bit(BFPCTRL, (1<<B0BFE) | (1<<B0BFM) |(1<<B0BFS), 0);	//DISABLED
+} //void set_RX0BF_pin(uint8_t mode)
+
+void MCP2515::set_RX1BF_pin(uint8_t mode)
+{
+		  if (mode == RX_BUFFER_FULL_IRQ) modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), (1<<B1BFE) | (1<<B1BFM));
+	 else if (mode == DIGITAL_OUTPUT)     modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), (1<<B1BFE));
+	 else if (mode == ON)				  modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), (1<<B1BFE));
+	 else if (mode == OFF)				  modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), (1<<B1BFE) | (1<<B1BFS));
+	 else modify_bit(BFPCTRL, (1<<B1BFE) | (1<<B1BFM) |(1<<B1BFS), 0);	//DISABLED	
+} //void set_RX1BF_pin(uint8_t mode)
+
+void MCP2515::set_CLKOUT_pin(uint8_t state, uint8_t prescaler /* = PRESCALER_8 */)
+{
+	if (state == CLKOUT_DISABLE) modify_bit(CANCTRL, (1<<CLKEN), 0);
+	else if (prescaler == PRESCALER_1) modify_bit(CANCTRL, (1<<CLKEN) | (1<<CLKPRE0) | (1<<CLKPRE1), (1<<CLKEN));
+	else if (prescaler == PRESCALER_2) modify_bit(CANCTRL, (1<<CLKEN) | (1<<CLKPRE0) | (1<<CLKPRE1), (1<<CLKEN) | (1<<CLKPRE0));
+	else if (prescaler == PRESCALER_4) modify_bit(CANCTRL, (1<<CLKEN) | (1<<CLKPRE0) | (1<<CLKPRE1), (1<<CLKEN) | (1<<CLKPRE1));
+	else if (prescaler == PRESCALER_8) modify_bit(CANCTRL, (1<<CLKEN) | (1<<CLKPRE0) | (1<<CLKPRE1), (1<<CLKEN) | (1<<CLKPRE1) | (1<<CLKPRE0));
+	else modify_bit(CANCTRL, (1<<CLKEN), 0);	
+} //void set_CLKOUT_pin(uint8_t state, uint8_t prescaler /* = PRESCALER_8 */)
+
+void MCP2515::set_operating_mode(uint8_t mode)
+{
+		 if (mode == NORMAL_MODE)		modify_bit(CANCTRL, 0xE0, 0);
+	else if (mode == SLEEP_MODE)		modify_bit(CANCTRL, 0xE0, (1<<REQOP0));
+	else if (mode == LOOPBACK_MODE)		modify_bit(CANCTRL, 0xE0, (1<<REQOP1));
+	else if (mode == LISTEN_ONLY_MODE)	modify_bit(CANCTRL, 0xE0, (1<<REQOP0) | (1<<REQOP1));
+	else if (mode == CONFIGURATION_MODE)modify_bit(CANCTRL, 0xE0, (1<<REQOP2));
+	else ;
+} //void set_operating_mode(uint8_t mode)
+
+
+//////////////////////////////////////////////////////////////////////////
+////////////////////////////////Obsluha///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void MCP2515::write_register(uint8_t adress, uint8_t data)
+{
+	spi.select(true);
+	
+	spi.write_data(SPI_WRITE);
+	spi.write_data(adress);
+	spi.write_data(data);
+	
+	spi.select(false);
+} //void write_register(uint8_t adress, uint8_t data)
+
+uint8_t MCP2515::read_register(uint8_t adress)
+{
+	uint8_t data;
+	
+	spi.select(true);
+	
+	spi.write_data(SPI_READ);
+	spi.write_data(adress);
+	
+	data = spi.write_and_read_data(0xff);
+	
+	spi.select(false);
+	
+	return data;	
+} //uint8_t read_register(uint8_t adress)
+
+void MCP2515::modify_bit(uint8_t adress, uint8_t mask, uint8_t data)
+{
+	spi.select(true);
+	
+	spi.write_data(SPI_BIT_MODIFY);
+	spi.write_data(adress);
+	spi.write_data(mask);
+	spi.write_data(data);
+	
+	spi.select(false);
+} //void modify_bit(uint8_t adress, uint8_t mask, uint8_t data)
+
+uint8_t MCP2515::read_status(uint8_t type)
+{
+	uint8_t data;
+	
+	spi.select(true);
+	
+	spi.write_data(type);
+	data = spi.write_and_read_data(0xff);
+	
+	spi.select(false);
+	
+	return data;
+} //uint8_t read_status(uint8_t type)
+
+uint8_t MCP2515::read_rx_status(void)
+{
+	uint8_t data;
+	
+	spi.select(true);
+	
+	spi.write_data(SPI_RX_STATUS);			//Pozadavek na status
+	data = spi.write_and_read_data(0xff);	//Precteni RX statusu
+//spi.write_data(0xff);						//MCP2515 porad posila status bajt
+	
+	spi.select(false);
+	
+	//return ((~data) & 0x20);	//Vymaskovani spravneho bitu
+	//return ((~data) & 0x02);
+	return data;
+} //uint8_t read_rx_status(void)
+
+
+void MCP2515::reset()
+{
+	spi.select(true);
+	spi.write_data(SPI_RESET);
+	wait_ms(1);
+	spi.select(false);
+	wait_ms(50);
+}
+
+void MCP2515::rx_handler(fifo<can_message> &rx_buffer)
+{
+	uint8_t buffer_1[14];
+	uint8_t buffer_2[14];
+
+	buffer_1[0] = 0;
+	buffer_2[0] = 0;
+
+	//////////////////////////////////////////////////////
+	//Co je v bufferu?
+	//[   0	  ] - new message flag
+	//[  1-4  ]	- id
+	//[   5   ]	- length
+	//[  6-13 ] - data
+	//////////////////////////////////////////////////////
+
+
+	uint8_t rx_status = read_rx_status();
+
+	//Přečtení RX_BUFF_0, pokud je plný
+	if (bit_is_set(rx_status,6))	//Zprava v bufferu 0
+	{
+		spi.select(true);
+		spi.write_data(SPI_READ_RX_BUFF_0);
+
+		buffer_1[0] = 1;
+
+		for (uint8_t i=1;i<14;i++)
+		{
+			buffer_1[i] = spi.write_and_read_data(0xff);
+		}
+
+		spi.select(false);
+	}
+
+	//Přečtení RX_BUFF_2, pokud je plný
+	if (bit_is_set(rx_status,7)) //Zprava v bufferu 1
+	{
+		spi.select(true);
+		spi.write_data(SPI_READ_RX_BUFF_2);
+
+		buffer_2[0] = 1;
+
+		for (uint8_t i=1;i<14;i++)
+		{
+			buffer_2[i] = spi.write_and_read_data(0xff);
+		}
+
+		spi.select(false);
+	}
+
+	//Vytvoření a uložení can_message
+	if (buffer_1[0])
+	{
+		can_message message;
+
+		message.id  = 0;
+		message.id |= buffer_1[1]<<3;
+		message.id |= buffer_1[2]>>5;
+		message.lenght = buffer_1[5];
+
+		for(uint8_t i=0; i<message.lenght; i++)
+		{
+			message.data[i] = buffer_1[6+i];
+		}
+
+		rx_buffer.add(message);
+	}
+
+	if (buffer_2[0])
+	{
+		can_message message;
+		message.id = (uint16_t)(buffer_2[1]<<8) | (uint16_t)(buffer_2[2]>>5);
+		message.lenght = buffer_2[5];
+		for(uint8_t i=0; i<message.lenght; i++)
+		{
+			message.data[i] = buffer_2[i];
+		}
+
+		rx_buffer.add(message);
+	}
+}
+
+void MCP2515::tx_handler(fifo<can_message> &tx_buffer)
+{
+	//TODO: buffer priority
+
+	while (tx_buffer.check())
+	{
+		uint8_t reg_sidh, reg_sidl, reg_dlc, reg_data, reg_rts;
+
+		//Vybrání odesílacího bufferu
+		if ( !(read_register(TXB2CTRL) & (1<<TXREQ)) )
+		{
+			reg_sidh = TXB2SIDH;
+			reg_sidl = TXB2SIDL;
+			reg_dlc  = TXB2DLC;
+			reg_data = TXB2D0;
+			reg_rts  = SPI_RTS_TXB2;
+		}
+
+		else if ( !(read_register(TXB1CTRL) & (1<<TXREQ)) )
+		{
+			reg_sidh = TXB1SIDH;
+			reg_sidl = TXB1SIDL;
+			reg_dlc  = TXB1DLC;
+			reg_data = TXB1D0;
+			reg_rts  = SPI_RTS_TXB1;
+		}
+
+		else if ( !(read_register(TXB2CTRL) & (1<<TXREQ)) )
+		{
+			reg_sidh = TXB0SIDH;
+			reg_sidl = TXB0SIDL;
+			reg_dlc  = TXB0DLC;
+			reg_data = TXB0D0;
+			reg_rts  = SPI_RTS_TXB0;
+		}
+
+		else
+		{
+			return; //TODO: Tady by to mohlo něco dělat, teoreticky už nemusí (přemístění message)
+		}
+
+		can_message message = tx_buffer.read();	//TODO: dynamic alocation
+
+		//Zapsání ID
+		write_register(reg_sidh, (uint8_t) (message.id>>3));
+		write_register(reg_sidl, (uint8_t) (message.id<<5));
+
+		//Zapsání délky zprávy
+		write_register(reg_dlc, message.lenght);
+
+		//Zapsání dat
+		for (uint8_t i=0; i<message.lenght; i++)
+		{
+			write_register(reg_data+i, message.data[i]);
+		}
+
+		//Odeslání na sběrnici
+		spi.select(true);
+
+		spi.write_data(reg_rts);
+
+		spi.select(false);
+	}
+}
diff --git a/SW/libs/src/MCP2515.h b/SW/libs/src/MCP2515.h
new file mode 100644
index 0000000000000000000000000000000000000000..382b0ce74aff372b23ed2718f06fdf67c04cc515
--- /dev/null
+++ b/SW/libs/src/MCP2515.h
@@ -0,0 +1,370 @@
+#pragma once
+
+#include <avr/io.h>
+#include <stdint.h>
+#include "spi.h"
+#include "fifo.h"
+
+struct can_message
+{
+	uint16_t id;
+	uint8_t lenght;
+	uint8_t data[8];
+};
+
+class MCP2515
+{
+	//Definice
+	public:
+		enum spi_instructions
+		{
+			SPI_RESET			= 0xC0,
+			SPI_READ			= 0x03,
+			SPI_READ_RX_BUFF_0	= 0x90,
+			SPI_READ_RX_BUFF_1	= 0x92,
+			SPI_READ_RX_BUFF_2	= 0x94,
+			SPI_READ_RX_BUFF_3	= 0x96,
+			SPI_WRITE			= 0x02,
+			SPI_LOAD_TX_BUFF_0	= 0x40,
+			SPI_LOAD_TX_BUFF_1	= 0x41,
+			SPI_LOAD_TX_BUFF_2	= 0x42,
+			SPI_LOAD_TX_BUFF_3	= 0x43,
+			SPI_LOAD_TX_BUFF_4	= 0x44,
+			SPI_LOAD_TX_BUFF_5	= 0x45,
+			SPI_RTS_TXB0		= 0x81,
+			SPI_RTS_TXB1		= 0x82,
+			SPI_RTS_TXB2		= 0x84,
+			SPI_READ_STATUS		= 0xA0,
+			SPI_RX_STATUS		= 0xB0,
+			SPI_BIT_MODIFY		= 0x05			
+		};
+		
+		enum can_control_registers
+		{
+			RXF0SIDH	= 0x00,
+			RXF0SIDL	= 0x01,
+			RXF0EID8	= 0x02,
+			RXF0EID0	= 0x03,
+			RXF1SIDH	= 0x04,
+			RXF1SIDL	= 0x05,
+			RXF1EID8	= 0x06,
+			RXF1EID0	= 0x07,
+			RXF2SIDH	= 0x08,
+			RXF2SIDL	= 0x09,
+			RXF2EID8	= 0x0A,
+			RXF2EID0	= 0x0B,
+			BFPCTRL		= 0x0C,
+			TXRTSCTRL	= 0x0D,
+			CANSTAT		= 0x0E,
+			CANCTRL		= 0x0F,
+			
+			RXF3SIDH	= 0x10,
+			RXF3SIDL	= 0x11,
+			RXF3EID8	= 0x12,
+			RXF3EID0	= 0x13,
+			RXF4SIDH	= 0x14,
+			RXF4SIDL	= 0x15,
+			RXF4EID8	= 0x16,
+			RXF4EID0	= 0x17,
+			RXF5SIDH	= 0x18,
+			RXF5SIDL	= 0x19,
+			RXF5EID8	= 0x1A,
+			RXF5EID0	= 0x1B,
+			TEC			= 0x1C,
+			REC         = 0x1D,
+			
+			RXM0SIDH	= 0x20,
+			RXM0SIDL	= 0x21,
+			RXM0EID8	= 0x22,
+			RXM0EID0	= 0x23,
+			RXM1SIDH	= 0x24,
+			RXM1SIDL	= 0x25,
+			RXM1EID8	= 0x26,
+			RXM1EID0	= 0x27,
+			CNF3		= 0x28,
+			CNF2		= 0x29,
+			CNF1		= 0x2A,
+			CANINTE		= 0x2B,
+			CANINTF		= 0x2C,
+			EFLG		= 0x2D,
+
+			TXB0CTRL	= 0x30,
+			TXB0SIDH	= 0x31,
+			TXB0SIDL	= 0x32,
+			TXB0EID8	= 0x33,
+			TXB0EID0	= 0x34,
+			TXB0DLC		= 0x35,
+			TXB0D0		= 0x36,
+			TXB0D1		= 0x37,
+			TXB0D2		= 0x38,
+			TXB0D3		= 0x39,
+			TXB0D4		= 0x3A,
+			TXB0D5		= 0x3B,
+			TXB0D6		= 0x3C,
+			TXB0D7		= 0x3D,
+
+			TXB1CTRL	= 0x40,
+			TXB1SIDH	= 0x41,
+			TXB1SIDL	= 0x42,
+			TXB1EID8	= 0x43,
+			TXB1EID0	= 0x44,
+			TXB1DLC		= 0x45,
+			TXB1D0		= 0x46,
+			TXB1D1		= 0x47,
+			TXB1D2		= 0x48,
+			TXB1D3		= 0x49,
+			TXB1D4		= 0x4A,
+			TXB1D5		= 0x4B,
+			TXB1D6		= 0x4C,
+			TXB1D7		= 0x4D,
+
+			TXB2CTRL	= 0x50,
+			TXB2SIDH	= 0x51,
+			TXB2SIDL	= 0x52,
+			TXB2EID8	= 0x53,
+			TXB2EID0	= 0x54,
+			TXB2DLC		= 0x55,
+			TXB2D0		= 0x56,
+			TXB2D1		= 0x57,
+			TXB2D2		= 0x58,
+			TXB2D3		= 0x59,
+			TXB2D4		= 0x5A,
+			TXB2D5		= 0x5B,
+			TXB2D6		= 0x5C,
+			TXB2D7		= 0x5D,
+
+			RXB0CTRL	= 0x60,
+			RXB0SIDH	= 0x61,
+			RXB0SIDL	= 0x62,
+			RXB0EID8	= 0x63,
+			RXB0EID0	= 0x64,
+			RXB0DLC		= 0x65,
+			RXB0D0		= 0x66,
+			RXB0D1		= 0x67,
+			RXB0D2		= 0x68,
+			RXB0D3		= 0x69,
+			RXB0D4		= 0x6A,
+			RXB0D5		= 0x6B,
+			RXB0D6		= 0x6C,
+			RXB0D7		= 0x6D,
+
+			RXB1CTRL	= 0x70,
+			RXB1SIDH	= 0x71,
+			RXB1SIDL	= 0x72,
+			RXB1EID8	= 0x73,
+			RXB1EID0	= 0x74,
+			RXB1DLC		= 0x75,
+			RXB1D0		= 0x76,
+			RXB1D1		= 0x77,
+			RXB1D2		= 0x78,
+			RXB1D3		= 0x79,
+			RXB1D4		= 0x7A,
+			RXB1D5		= 0x7B,
+			RXB1D6		= 0x7C,
+			RXB1D7		= 0x7D
+		};
+		
+		enum control_register_bits
+		{
+			//Registr BFPCTRL 
+			B1BFS		= 5,
+			B0BFS		= 4,
+			B1BFE		= 3,
+			B0BFE		= 2,
+			B1BFM		= 1,
+			B0BFM		= 0,
+			
+			//Registr TXRTSCTRL 
+			B2RTS		= 5,
+			B1RTS		= 4,
+			B0RTS		= 3,
+			B2RTSM		= 2,
+			B1RTSM		= 1,
+			B0RTSM		= 0,
+			
+			//Registr CANSTAT 
+			OPMOD2		= 7,
+			OPMOD1		= 6,
+			OPMOD0		= 5,
+			ICOD2		= 3,
+			ICOD1		= 2,
+			ICOD0		= 1,
+
+			//Registr CANCTRL
+			REQOP2		= 7,
+			REQOP1		= 6,
+			REQOP0		= 5,
+			ABAT		= 4,
+			CLKEN		= 2,
+			CLKPRE1		= 1,
+			CLKPRE0		= 0,
+
+			//Registr CNF3
+			WAKFIL		= 6,
+			PHSEG22		= 2,
+			PHSEG21		= 1,
+			PHSEG20		= 0,
+
+			//Registr CNF2
+			BTLMODE		= 7,
+			SAM			= 6,
+			PHSEG12		= 5,
+			PHSEG11		= 4,
+			PHSEG10		= 3,
+			PHSEG2		= 2,
+			PHSEG1		= 1,
+			PHSEG0		= 0,
+
+			//Registr CNF1
+			SJW1		= 7,
+			SJW0		= 6,
+			BRP5		= 5,
+			BRP4		= 4,
+			BRP3		= 3,
+			BRP2		= 2,
+			BRP1		= 1,
+			BRP0		= 0,
+
+			//Registr CANINTE
+			MERRE		= 7,
+			WAKIE		= 6,
+			ERRIE		= 5,
+			TX2IE		= 4,
+			TX1IE		= 3,
+			TX0IE		= 2,
+			RX1IE		= 1,
+			RX0IE		= 0,
+
+			//Registr CANINTF
+			MERRF		= 7,
+			WAKIF		= 6,
+			ERRIF		= 5,
+			TX2IF		= 4,
+			TX1IF		= 3,
+			TX0IF		= 2,
+			RX1IF		= 1,
+			RX0IF		= 0,
+
+			//Registr EFLG
+			RX1OVR		= 7,
+			RX0OVR		= 6,
+			TXB0		= 5,
+			TXEP		= 4,
+			RXEP		= 3,
+			TXWAR		= 2,
+			RXWAR		= 1,
+			EWARN		= 0,
+			
+			//Registry TXB0CTRL - TXB2CTRL
+			ABTF		= 6,
+			MLOA		= 5,
+			TXERR		= 4,
+			TXREQ		= 3,
+			TXP1		= 1,
+			TXP0		= 0,
+			
+			//Registry RXB0CTRL, RXB1CTRL
+			RXM1		= 6,
+			RXM0		= 5,
+			RXRTR		= 3,
+			BUKT		= 2,
+			BUKT1		= 1,
+			FILHIT0		= 0,
+			
+			//Registr TXBnSIDL (n = 0, 1) 
+			EXIDE		= 3,
+
+			//Registr RXB1CTRL
+			FILHIT2		= 2,
+			FILHIT1		= 1,
+
+			//Registr RXBnSIDL (n = 0, 1)
+			SRR			= 4,
+			IDE			= 3,
+			
+			//Registr RXBnDLC (n = 0, 1)
+			RTR			= 6,
+			DLC3		= 3,
+			DLC2		= 2,
+			DLC1		= 1,
+			DLC0		= 0
+		};
+		
+		enum operating_modes
+		{
+			CONFIGURATION_MODE,
+			NORMAL_MODE,
+			SLEEP_MODE,
+			LISTEN_ONLY_MODE,
+			LOOPBACK_MODE
+		};
+		
+		enum interrupt_modes
+		{
+			NONE							= 0,
+			MESSAGE_ERROR_INTERRUPT			= (1<<MERRE),
+			BUS_ACTIVITY_WAKEUP_INTERRUPT	= (1<<WAKIE),
+			ERROR_INTERRUPT					= (1<<ERRIE),
+			TX2_INTERRUPT					= (1<<TX2IE),
+			TX1_INTERRUPT					= (1<<TX1IE),
+			TX0_INTERRUPT					= (1<<TX0IE),
+			RX1_INTERRUPT					= (1<<RX1IE),
+			RX0_INTERRUPT					= (1<<RX0IE)
+		};
+		
+		enum RXnBF_modes
+		{
+			DISABLED,
+			RX_BUFFER_FULL_IRQ,
+			DIGITAL_OUTPUT,
+			ON,
+			OFF
+		};	
+		
+		enum CLKOUT_modes
+		{
+			PRESCALER_1,
+			PRESCALER_2,
+			PRESCALER_4,
+			PRESCALER_8,
+			CLKOUT_ENABLE,
+			CLKOUT_DISABLE
+		};
+
+	private:
+		spi_class &spi;
+
+	//functions
+	public:
+		//Konstruktor, destruktor
+		MCP2515(spi_class &spi);
+		~MCP2515();
+			
+		//Inicializace
+		void	set_baudrate(uint8_t CNF1_val, uint8_t CNF2_val, uint8_t CNF3_val);
+		void	set_interrupt(uint8_t irq_type) { write_register(CANINTE, irq_type); };
+		void	set_RX0BF_pin(uint8_t mode);
+		void	set_RX1BF_pin(uint8_t mode);
+		void	set_CLKOUT_pin(uint8_t state, uint8_t prescaler = PRESCALER_8);
+		void	set_operating_mode(uint8_t mode);
+		
+		//Obsluha
+		void	write_register(uint8_t adress, uint8_t data);
+		uint8_t read_register(uint8_t adress);
+		void	modify_bit(uint8_t adress, uint8_t mask, uint8_t data);
+		
+		uint8_t	read_status(uint8_t type);
+		uint8_t read_rx_status(void);
+		
+		void reset(void);
+
+		void can_rx_message();
+		void can_tx_message();
+		void rx_handler(fifo<can_message> &rx_buffer);
+		void tx_handler(fifo<can_message> &tx_buffer);
+
+	private:
+		void spi_ini(void);
+
+}; //MCP2515
+
diff --git a/SW/libs/src/MFRC522.cpp b/SW/libs/src/MFRC522.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a864079f10027199cefff137304cbd57cbfa4f67
--- /dev/null
+++ b/SW/libs/src/MFRC522.cpp
@@ -0,0 +1,1054 @@
+
+#include "MFRC522.h"
+#include "spi.h"
+#include <avr/io.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+
+#ifdef PC7
+spi_select_class spi_mfrc522(&DDRC, &PORTC, PC7);
+
+// Konstruktory
+MFRC522_class::MFRC522_class(spi_class &spi): spi(spi)
+{
+	/*
+	//Inicializace reset pinu
+	DDRB  |= (1<<PB0);
+	PORTB |= (1<<PB0);
+	*/
+} //MFRC522_class()
+
+MFRC522_class::MFRC522_class(spi_class &spi, uint8_t _select_port, uint8_t _select_pin, uint8_t _reset_port, uint8_t _reset_pin): spi(spi)
+{
+	;; //TODO all there
+} //MFRC522_class(uint8_t _select_port, uint8_t _select_pin, uint8_t _reset_port, uint8_t _reset_pin)
+
+// Destruktor
+MFRC522_class::~MFRC522_class()
+{
+} //~MFRC522_class
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Zakladni interface pro komunikaci s MFRC522
+/////////////////////////////////////////////////////////////////////////////////////
+
+
+//Zapise bajt do registru
+void MFRC522_class::reader_write_register(uint8_t _register, uint8_t _value)
+{
+	//Vybrani MFRC522
+	spi_mfrc522.select(true);
+	
+	spi.write_data(_register & 0x7E);
+	spi.write_data(_value);
+	
+	spi_mfrc522.select(false);
+} //void reader_write_register(uint8_t _register, uint8_t _value)
+
+
+//Zapise vybrany pocet bajtu z pole do registru
+void MFRC522_class::reader_write_register(uint8_t _register,uint8_t _count, uint8_t *_values)
+{
+	spi_mfrc522.select(true);
+	
+	spi.write_data(_register & 0x7E);
+	for (uint8_t index = 0; index < _count; index++)
+	{
+		spi.write_data(_values[index]);
+	}
+	
+	spi_mfrc522.select(false);
+} //void reader_write_register(uint8_t _register,uint8_t _count, uint8_t *_values)
+
+
+//Precte bajt z registru
+uint8_t MFRC522_class::reader_read_register(uint8_t _register)
+{
+	uint8_t return_value;
+	
+	spi_mfrc522.select(true);
+	
+	spi.write_data( 0x80 | (_register & 0x7E) );
+	return_value = spi.write_and_read_data(0);
+	
+	spi_mfrc522.select(false);
+	
+	return return_value;
+} //uint8_t reader_read_register(uint8_t _register)
+
+
+//Precte zadny pocet bajtu z registru do pole
+void MFRC522_class::reader_read_register(uint8_t _register, uint8_t _count, uint8_t *_values, uint8_t _rx_align /* = 0 */)
+{
+	if (!_count) return;
+	
+	uint8_t addres = 0x80 | (_register & 0x7E);
+	uint8_t index  = 0;
+	
+	spi_mfrc522.select(true);
+	
+	_count--;
+	
+	spi.write_data(addres);
+	
+	while (index < _count)
+	{
+		if ((index == 0) && (_rx_align))
+		{
+			uint8_t mask = 0;
+			
+			for (uint8_t i = _rx_align; i <= 7; i++)
+			{
+				mask |= (1<<i);
+			}
+			
+			uint8_t r_value = spi.write_and_read_data(addres);
+			
+			_values[0] = (_values[index] & ~mask) | (r_value & mask);
+		}
+		
+		else
+		{
+			_values[index] = spi.write_and_read_data(addres);
+		}
+		
+		index++;
+	}
+	
+	_values[index] = spi.write_and_read_data(0);
+	
+	spi_mfrc522.select(false);	
+} //void reader_read_register(uint8_t _register, uint8_t _count, uint8_t *_values, uint8_t _rx_align /* = 0 */)
+
+
+//Nastavi bity dane maskou na registr _register
+void MFRC522_class::reader_set_register_bit_mask(uint8_t _register, uint8_t _mask)
+{
+	uint8_t temp;
+	
+	temp = reader_read_register(_register);
+	reader_write_register(_register, (temp | _mask));
+} //void reader_set_register_bit_mask(uint8_t _register, uint8_t _mask)
+
+
+//Zrusi bity dane maskou na registru _register
+void MFRC522_class::reader_clear_register_bit_mask(uint8_t _register, uint8_t _mask)
+{
+	uint8_t temp;
+	
+	temp = reader_read_register(_register);
+	reader_write_register(_register, (temp & (~_mask)));
+} //void reader_clear_register_bit_mask(uint8_t _register, uint8_t _mask)
+
+
+//Vypocet crc na koprocesoru MFRC522
+//@return STATUS_OK pri uspechu, nebo STATUS_TIMEOUT
+uint8_t MFRC522_class::reader_calculate_crc(uint8_t *_data, uint8_t _lenght, uint8_t *_result)
+{
+	reader_write_register(CommandReg, READER_Idle);	//Zastavi ostatni vykonavane prikazy
+	
+	reader_write_register(DivIrqReg, 0x04);				//Zrusi preruseni od CRCIRq
+	reader_set_register_bit_mask(FIFOLevelReg, 0x80);	//Inicializace FIFO
+	reader_write_register(FIFODataReg, _lenght, _data); //Odesle data do FIFO
+	reader_write_register(CommandReg, READER_CalcCRC);	//Zacne pocitani CRC
+	
+	//Cekani na dokonceni vypoctu
+	
+	uint16_t i = 5000;
+	uint8_t	 n;
+	
+	while (1)
+	{
+		n = reader_read_register(DivIrqReg);
+		
+		if (n & 0x04) break;	//POCITANI CRC HOTOVO
+		if (--i == 0) return STATUS_TIMEOUT;	//Vyprsel timeout
+	}
+	
+	reader_write_register(CommandReg, READER_Idle);
+	
+	//Precteni spocitaneho CRC
+	_result[0] = reader_read_register(CRCResultRegL);
+	_result[1] = reader_read_register(CRCResultRegH);
+	
+	return STATUS_OK;
+} //uint8_t reader_calculate_crc(uint8_t *_data, uint8_t _lenght, uint8_t *_result)
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Metody pro obsluhu MFRC522
+/////////////////////////////////////////////////////////////////////////////////////
+
+
+//Inicializace MFRC522
+void MFRC522_class::reader_ini(void)
+{
+	DDRC  |= (1<<PC6);
+	PORTC |= (1<<PC6);
+	//PORTB |= (1<<PB0);	//Power on & hard reset
+	wait_ms(50);	
+	reader_reset();		//Soft reset
+	
+	//Nastaveni timeru MFRC522 pro potreby hlidani timeoutu
+	//Frevence timeru = (13,56 MHz / (2*TPreScaler+1)
+	//TPreScaler = [TPrescaler_Hi:TPrescaler_Lo]
+	//TPrescaler_Hi jsou spodni 4 bity v TModeReg
+	//TPrescaler_Lo je TPrescalerReg
+	reader_write_register(TModeReg, 0x80);		//TAuto=1; Timer zacne automaticky pocitat po dokonceni vysilani
+	reader_write_register(TPrescalerReg, 0xA9);	//Frekvence 40kHz, perioda 25�s 
+	reader_write_register(TReloadRegH, 0x03);	//Reload timer 25ms pred timeoutem
+	reader_write_register(TReloadRegL, 0xE8);	
+	
+	reader_write_register(TxASKReg, 0x40);
+	reader_write_register(ModeReg, 0x3D);
+	
+	reader_set_antena_gain(GAIN_43dB);			//Nastaveni zisku anteny
+	
+	reader_antena_on();
+} //void reader_ini(void)
+
+
+//Vykonani soft resetu
+void MFRC522_class::reader_reset(void)
+{
+	reader_write_register(CommandReg, READER_SoftReset);	//Vykona soft reset
+
+	wait_ms(50);	//Radsi
+	
+	while (reader_read_register(CommandReg) & (1<<4))
+	{
+		;;
+	}
+} //void reader_reset(void)
+
+
+//Zapne antenu, zapnuti pinu TX1 a TX2 (po resetu jsou vypnute)
+void MFRC522_class::reader_antena_on(void)
+{
+	uint8_t _value = reader_read_register(TxControlReg);
+	
+	if ((_value & 0x03) != 0x03)
+	{
+		reader_write_register(TxControlReg, (_value | 0x03));
+	}
+} //void reader_antena_on(void)
+
+
+//Nastaveni gainu anteny
+void MFRC522_class::reader_set_antena_gain(uint8_t _gain)
+{
+	reader_write_register(RFCfgReg, _gain);		//Nastaveni zisku anteny
+} //void reader_set_antena_gain(_gain)
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Metody pro komunikaci s rfid kartami
+/////////////////////////////////////////////////////////////////////////////////////
+
+
+//Odesle data na kartu a prijme odpoved
+//CRC se zvaliduje jen v pripade specifikovani _back_data, _back_lenght
+//@return STATUS_OK,
+uint8_t MFRC522_class::reader_transmit_and_read_data(uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data, uint8_t *_back_lenght, uint8_t *_valid_bits /* = NULL */, uint8_t _rx_align /* = 0 */, bool _check_crc /* = false */)
+{
+	uint8_t wait_irq = 0x30;	//RxIRq and IdleIRq
+	
+	return reader_communicate_with_card(READER_Transceive, wait_irq, _send_data, _send_lenght, _back_data, _back_lenght, _valid_bits, _rx_align, _check_crc);
+} //uint8_t reader_transmit_and_read_data(uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data, uint8_t *_back_lenght, uint8_t *_valid_bits /* = NULL */, uint8_t _rx_align /* = 0 */, bool _check_crc /* = false */)
+
+
+//Odesle data do MCRF522 FIFO, vykona prikaz, pocka na dokonceni a precte data nazpatek z FIFO
+//CRC se zvaliduje jen v pripade specifikovani _back_data, _back_lenght
+//@return STATUS_OK, STATUS_TIMEOUT, STATUS_false_ROOM, STATUS_COLLISION, STATUS_MIFARE_NACK, STATUS_CRC_WRONG
+uint8_t MFRC522_class::reader_communicate_with_card(uint8_t _command, uint8_t _wait_irq, uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data /* = NULL */, uint8_t *_back_lenght /* = NULL */, uint8_t *_valid_bits /* = NULL */, uint8_t _rx_align /* = 0 */, bool _check_crc /* = false */)
+{
+	uint8_t n;
+	uint8_t _validBits;
+	uint16_t i;
+	
+	//Priprava dat pro BitFramingReg
+	uint8_t tx_last_bits = _valid_bits ? *_valid_bits : 0;
+	uint8_t bit_framing = (_rx_align << 4) + tx_last_bits;	//RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0]
+	
+	reader_write_register(CommandReg, READER_Idle);		//Zrusi vykonavani vsech prikazu
+	reader_write_register(ComIrqReg, 0x7F);				//Vynuluje vsech 7 bitu preruseni
+	reader_set_register_bit_mask(FIFOLevelReg, 0x80);	//inicializace FIFO
+	reader_write_register(FIFODataReg, _send_lenght, _send_data);	//Zapise _send_data do FIFO
+	reader_write_register(BitFramingReg, bit_framing);	//Vyrovnani bitu
+	reader_write_register(CommandReg, _command);		//Odesle a vykona _commad
+	
+	if (_command == READER_Transceive)
+	{
+		reader_set_register_bit_mask(BitFramingReg, 0x80);	//Odesli data z FIFO na kartu
+	}
+	
+	//Cekani na dokonceni prikazu
+	//1 smycka while trvďż˝  17.86us (reader_ini())
+	i = 2000;
+	
+	while (1)
+	{
+		n = reader_read_register(ComIrqReg);
+		if (n & _wait_irq) break;	//Preruseni ohlasilo uspech
+		
+		if (n & 0x01) return STATUS_TIMEOUT;	//Timer interupt - nic nebylo  prijato v 25ms
+		
+		if (--i == 0) return STATUS_TIMEOUT;	//Ukonceni vsech pokusu po 35.7ms
+	}
+	
+	//Zastavit, pokud se vysktla nejaka chyba
+	uint8_t error_reg_value = reader_read_register(ErrorReg);	//ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl   CollErr CRCErr ParityErr ProtocolErr
+	
+	if (error_reg_value & 0x13) return STATUS_ERROR;				//BufferOvfl ParityErr ProtocolErr	
+	
+	//Pokud chceme prijmout data nazpet
+	if (_back_data && _back_lenght)
+	{
+		n = reader_read_register(FIFOLevelReg);		//Pocet bajtu v FIFO
+		if (n > *_back_lenght) return STATUS_NO_ROOM;	//Neni misto na ulozeni dat
+		
+		*_back_lenght = n;		//Pocet dat k precteni
+		reader_read_register(FIFODataReg, n, _back_data, _rx_align);	//Prijem dat z FIFO
+		_validBits = reader_read_register(ControlReg) & 0x07;		//RxLastBits[2:0] urcuji pocet validnich prijmutych bitu
+		
+		if(_valid_bits) *_valid_bits = _validBits;
+	}
+	
+	//Navrat koliznuho stavu
+	if (error_reg_value & 0x08) return STATUS_COLLISION;
+	
+	//Vypocitani CRC kdyz bylo nastavefalse _check_crc = true
+	if (_back_data && _back_lenght && _check_crc)
+	{
+		if (*_back_lenght == 1 && _validBits == 4) return STATUS_MIFARE_NACK;	//MIFARE classic NAK neni v poradku
+		
+		if (_send_lenght == 2 || _validBits != 0) return STATUS_CRC_WRONG;		//Nemame dostatek dat pro vypocet CRC
+		
+		uint8_t control_buffer[2];
+		
+		n = reader_calculate_crc(&_back_data[0], *_back_lenght - 2, &control_buffer[0]);
+		
+		if (n != STATUS_OK) return n;
+		
+		if ( (_back_data[*_back_lenght - 2] != control_buffer[0]) || (_back_data[*_back_lenght - 1] != control_buffer[1]) ) return STATUS_CRC_WRONG;		
+	}
+	
+	return STATUS_OK;	
+} //uint8_t reader_communicate_with_card(uint8_t _command, uint8_t _wait_irq, uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data /* = NULL */, uint8_t *_back_lenght /* = NULL */, uint8_t *_valid_bits /* = NULL */, uint8_t _rx_align /* = 0 */, bool _check_crc /* = false */)
+
+
+//Posle pozadavek typu A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
+//Dve karty v dosahu muzou zp�sobovat STATUS_TIMEOUT
+//@return STATUS_OK, nebo STATUS_??? pri chybe
+uint8_t MFRC522_class::card_request(uint8_t *_buffer_ATQA, uint8_t *_buffer_size)
+{
+	return card_REQA_or_WUPA(CARD_CMD_REQA, _buffer_ATQA, _buffer_size);
+} //uint8_t card_request(uint8_t *_buffer_ATQA, uint8_t *_buffer_size)
+
+
+//Posle prikaz na probuzeni karty
+//Dve karty v dosahu muzou zp�sobovat STATUS_TIMEOUT
+//@return STATUS_OK, nebo STATUS_??? pri chybe
+uint8_t MFRC522_class::card_wake_up(uint8_t *_buffer_ATQA, uint8_t *_buffer_size)
+{
+	return card_REQA_or_WUPA(CARD_CMD_WUPA, _buffer_ATQA, _buffer_size);
+} //uint8_t card_wake_up(uint8_t *_buffer_ATQA, uint8_t *_buffer_size)
+
+
+//Posle REQA nebo WUPA prikaz
+//Dve karty v dosahu muzou zp�sobovat STATUS_TIMEOUT
+//@return STATUS_OK, nebo STATUS_??? pri chybe
+uint8_t MFRC522_class::card_REQA_or_WUPA(uint8_t _command, uint8_t *_buffer_ATQA, uint8_t *_buffer_size)
+{
+	uint8_t valid_bits, status;
+	
+	if (_buffer_ATQA == NULL || *_buffer_size < 2)	return STATUS_NO_ROOM;	//Potrebujem mit alespon 2 bity na prijem odpovedi
+	
+	reader_clear_register_bit_mask(CollReg, 0x80);
+	valid_bits = 7; 
+	status = reader_transmit_and_read_data(&_command, 1, _buffer_ATQA, _buffer_size, &valid_bits);
+	
+	if (status !=  STATUS_OK) return status;
+	
+	if (*_buffer_size != 2 || valid_bits != 0) return STATUS_ERROR;		//ATQA musi byt presne 16 bitu
+	
+	return STATUS_OK;
+} //uint8_t card_REQA_or_WUPA(uint8_t _command, uint8_t *_buffer_ATQA, uint8_t *_buffer_size)
+
+
+//Odesle SELECT/ANTICOLLISION prikaz pro vyber defifalsevane karty
+//Pred odeslanim musi byt karta v ready rezimu - card_wake_up()
+//Ostatni karty se prepfalseu do rezimu IDLE/HALT
+/************************************************************************/
+/*The UID size and value of the chosen PICC is returned in *uid along with the SAK.
+*
+* A PICC UID consists of 4, 7 or 10 bytes.
+* Only 4 bytes can be specified in a SELECT command, so for the longer UIDs two or three iterations are used:
+* 		UID size	Number of UID bytes		Cascade levels		Example of PICC
+* 		========	===================		==============		===============
+* 		single				 4						1				MIFARE Classic
+* 		double				 7						2				MIFARE Ultralight
+* 		triple				10						3				falset currently in use?
+*
+* @return STATUS_OK on success, STATUS_??? otherwise.
+*/                                                                    
+/************************************************************************/
+uint8_t MFRC522_class::card_select(UID *uid, uint8_t _valid_bits /* = 0 */)
+{
+	bool uid_complete, select_done, use_cascade_tag;
+	uint8_t cascade_level = 1,
+			result, count, index,
+			uid_index,					//Prvni index c uid->uid_data[] pro pouzivany cascade_level
+			current_level_kfalsewn_bits;	//Pocet bitu soucasneho cascade levelu
+	
+	uint8_t buffer[9];					//SELECT/ANTICOLLISION prikaz + 2 bajty CRC
+	uint8_t buffer_used;				//Pocet bajtu v buffer[] pro odeslani do FIFO
+	uint8_t rx_align;					//Pozice prvniho prijateho bitu. Pro BitFramingReg
+	uint8_t tx_last_bits;				//Pocet bitu v naposled prijate zprave. Pro BitFramingReg
+	uint8_t *response_buffer;
+	uint8_t response_lenght;
+	
+	// Description of buffer structure:
+	// 		Byte 0: SEL 				Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3
+	// 		Byte 1: NVB					Number of Valid Bits (in complete command, falset just the UID): High nibble: complete bytes, Low nibble: Extra bits.
+	// 		Byte 2: UID-data or CT		See explanation below. CT means Cascade Tag.
+	// 		Byte 3: UID-data
+	// 		Byte 4: UID-data
+	// 		Byte 5: UID-data
+	// 		Byte 6: BCC					Block Check Character - XOR of bytes 2-5
+	//		Byte 7: CRC_A
+	//		Byte 8: CRC_A
+	// The BCC and CRC_A is only transmitted if we kfalsew all the UID bits of the current Cascade Level.
+	//
+	// Description of bytes 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels)
+	//		UID size	Cascade level	Byte2	Byte3	Byte4	Byte5
+	//		========	=============	=====	=====	=====	=====
+	//		 4 bytes		1			uid0	uid1	uid2	uid3
+	//		 7 bytes		1			CT		uid0	uid1	uid2
+	//						2			uid3	uid4	uid5	uid6
+	//		10 bytes		1			CT		uid0	uid1	uid2
+	//						2			CT		uid3	uid4	uid5
+	//						3			uid6	uid7	uid8	uid9
+	
+	//Kontrola zdraveho rozumu ;)	
+	if (_valid_bits > 80) return STATUS_INVALID;
+	
+	//Priprava MFRC522
+	reader_clear_register_bit_mask(CollReg, 0x80);	//ValuesAfterColl=1 => Bits received after collision are cleared. 
+	
+	//Opakovani cascade level smycky do precteni celeho UID
+	uid_complete = false;
+	
+	while (! uid_complete)
+	{
+		//Nastaveni cascade level v SEL bajtu, zjisteny potreby pouziti cascade tag ve 2 bajtu
+		switch (cascade_level)
+		{
+			case 1:	buffer[0] = CARD_CMD_SEL_CL1;
+					uid_index = 0;
+					use_cascade_tag = _valid_bits && uid->size > 4;
+				break;
+				
+			case 2:	buffer[0] = CARD_CMD_SEL_CL2;
+					uid_index = 3;
+					use_cascade_tag = _valid_bits && uid->size > 7;
+				break;	
+				
+			case 3: buffer[0] = CARD_CMD_SEL_CL3;
+					uid_index = 6;
+					use_cascade_tag = false;
+				break;
+				
+			default: return STATUS_INTERNAL_ERROR;
+				break;
+		}	
+		
+		//Kolik je UID bitu v tomto cascade levelu
+		current_level_kfalsewn_bits = _valid_bits - (8 * uid_index);
+		if (current_level_kfalsewn_bits < 0) current_level_kfalsewn_bits = 0;
+		
+		//Zkopirovani znamych uid->uid_data[] do buffer[]
+		index = 2;
+		
+		if (use_cascade_tag) buffer[index++] = CARD_CMD_CT;
+		
+		uint8_t bytes_to_copy = current_level_kfalsewn_bits / 8 + (current_level_kfalsewn_bits % 8 ? 1 : 0);
+		
+		if (bytes_to_copy)
+		{
+			uint8_t max_bytes = use_cascade_tag ? 3 : 4;
+			
+			if (bytes_to_copy > max_bytes) bytes_to_copy = max_bytes;
+			
+			for (count = 0; count < bytes_to_copy; count++)
+			{
+				buffer[index++] = uid->uid_data[uid_index + count];
+			}
+		}
+		
+		//falsew that the data has been copied we need to include the 8 bits in CT in currentLevelKfalsewnBits
+		if (use_cascade_tag) current_level_kfalsewn_bits += 8;
+		
+		// Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations.
+		select_done = false;
+		
+		while (! select_done)
+		{
+			//Kolik bitu je potreba odeslat a prijmout
+			if (current_level_kfalsewn_bits >= 32)	//All UID bits in this Cascade Level are kfalsewn. This is a SELECT.
+			{
+				buffer[1] = 0x70;	//NVB - pocet platnych bitu - 7
+				
+				//Calulate BCC - Block Check Character
+				buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5];
+				
+				//Vypocet CRC
+				result = reader_calculate_crc(buffer, 7, &buffer[7]);
+				
+				if (result != STATUS_OK) return result;
+				
+				tx_last_bits = 0;	//0 => vsech 8 bitu je v poradku
+				buffer_used = 9;
+				
+				//Store response in the last 3 bytes of buffer (BCC and CRC_A - falset needed after tx)
+				response_buffer = &buffer[6];
+				response_lenght = 3;
+			}
+			
+			else	//This is an ANTICOLLISION.
+			{
+				tx_last_bits = current_level_kfalsewn_bits % 8;
+				count = current_level_kfalsewn_bits / 8;		//Celkovy pocet bajtu UID
+				index =  2 + count;							//Number of whole bytes: SEL + NVB + UIDs
+				buffer[1] = (index << 4) + tx_last_bits;
+				buffer_used = index + (tx_last_bits ? 1 : 0);
+				
+				//Ulozeni odpovedi v nepouzite casti bufferu
+				response_buffer = &buffer[index];
+				response_lenght = sizeof(buffer) - index; 
+			}
+			
+			//Bit adjustments
+			rx_align = tx_last_bits;	//Having a seperate variable is overkill. But it makes the next line easier to read.
+			reader_write_register(BitFramingReg, (rx_align<<4) + tx_last_bits);	//RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0]
+			
+			//Odeslani buffer[] a prijmuti odpovedi
+			result = reader_transmit_and_read_data(buffer, buffer_used, response_buffer, &response_lenght, &tx_last_bits, rx_align);
+			
+			if (result == STATUS_COLLISION)	//Vice karet v dosahu = kolize
+			{
+				result = reader_read_register(CollReg);
+				
+				if (result & 0x20) return STATUS_COLLISION;	//Without a valid collision position we canfalset continue
+			
+				uint8_t collisionn_position = result & 0x1F;
+			
+				if (collisionn_position == 0) collisionn_position = 32;
+			
+				if (collisionn_position <= current_level_kfalsewn_bits) return STATUS_INTERNAL_ERROR;	//false progress - should falset happen
+			
+				//Vybrani karty s nastavenym bitem
+				current_level_kfalsewn_bits = collisionn_position;
+			
+				count = (current_level_kfalsewn_bits - 1) % 8;	//Bit pro modifikaci
+				index = 1 + (current_level_kfalsewn_bits / 8) + (count ? 1 : 0); //Prvni bajt je index 0
+				buffer[index] |= (1<<count);
+			}
+			
+			else if (result != STATUS_OK) return result;
+			
+			else  //STATUS_OK
+			{
+				if (current_level_kfalsewn_bits >= 32)	select_done = true;	//SELECT
+				
+				else current_level_kfalsewn_bits = 32;						//ANTICOLLISION
+																		//Run loop again to do the SELECT.
+			}			
+		} //while (! select_done)
+		
+		
+		//We do falset check the CBB - it was constructed by us above.
+		
+		//Copy the found UID bytes from buffer[] to uid->uid_data[]
+		index = (buffer[2] == CARD_CMD_CT) ? 3 : 2;		//Zdrojovy index v buffer[]
+		bytes_to_copy = (buffer[2] == CARD_CMD_CT) ? 3 : 4;
+		
+		for (count = 0; count < bytes_to_copy; count++)
+		{
+			uid->uid_data[uid_index + count] = buffer[index++];
+		}
+		
+		//Kontrola odpovedi SAK (Select Ackfalsewledge)
+		if (response_lenght != 3 || tx_last_bits != 0) return STATUS_ERROR;		//SAK je vzdy 24 bitu (1 bajt + CRC)
+		
+		//Kontrola CRC, do our own calculation and store the control in buffer[2..3] - those bytes are falset needed anymore.
+		result = reader_calculate_crc(response_buffer, 1, &buffer[2]);
+		
+		if (result != STATUS_OK) return result;
+		
+		if ( (buffer[2] != response_buffer[1]) || (buffer[3] != response_buffer[2])) return STATUS_CRC_WRONG;
+		
+		if (response_buffer[0] & 0x04) cascade_level++;		//Nasteven cascade level, UID jeste neni kompletni
+	
+		else
+		{
+			uid_complete = true;
+			uid->sak = response_buffer[0];
+		}		
+	} //while (! uid_complete)
+	
+	
+	//Nastaveni spravneho uid->size
+	uid->size = 3 * cascade_level +1;
+	
+	return STATUS_OK;			
+} // uint8_t card_select(UID *uid, uint8_t _valid_bits /* = 0 */)
+
+
+//Prepne kartu ze stavu active do stavu halt
+//@return STATUS_OK, nebo STATUS_??? pro chybu
+uint8_t MFRC522_class::card_halt(void)
+{
+	uint8_t result;
+	uint8_t buffer[4];
+	
+	//Naplneni buffer[prikazy]
+	buffer[0] = CARD_CMD_HLTA;
+	buffer[1] = 0;
+	
+	//Vypocet CRC
+	result = reader_calculate_crc(buffer, 2, &buffer[2]);
+	
+	if (result != STATUS_OK) return result;
+	
+	//Odeslani prikazu
+	// The standard says:
+	//		If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the
+	//		HLTA command, this response shall be interpreted as 'falset ackfalsewledge'.
+	// We interpret that this way: Only STATUS_TIMEOUT is an success.
+	
+	result = reader_transmit_and_read_data(buffer, sizeof(buffer), NULL, 0);
+	
+	if (result == STATUS_TIMEOUT) return STATUS_OK;	//falsermalni prubeh
+	if (result == STATUS_OK) return STATUS_ERROR;	//Trocha ironie ;)
+	
+	return result;	
+} //uint8_t card_halt(void)
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Metody pro komunikaci s MIFARE kartami
+/////////////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Executes the MFRC522 MFAuthent command.
+ * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card.
+ * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1.
+ * For use with MIFARE Classic PICCs.
+ * The PICC must be selected - ie in state ACTIVE(*) - before calling this function.
+ * Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise false new communications can start.
+ * 
+ * All keys are set to FFFFFFFFFFFFh at chip delivery.
+ * 
+ * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key.
+ */
+uint8_t MFRC522_class::reader_authenticate(uint8_t _command, uint8_t _block_addr, mifare_key *key, UID *uid)
+{
+	uint8_t wait_irq = 0x10;	//IdleIRq
+	
+	//Prikazovy buffer
+	uint8_t send_data[12];
+	send_data[0] = _command;
+	send_data[1] = _block_addr;
+	
+	for (uint8_t i = 0; i < MF_KEY_SIZE; i++)
+	{
+		send_data[2+i] = key->key_data[i];
+	}
+	
+	for (uint8_t i = 0; i < 4; i++)
+	{
+		send_data[8+i] = uid->uid_data[i];
+	}
+	
+	//Start authentifikace
+	
+	return reader_communicate_with_card(READER_MFAuthent, wait_irq, &send_data[0], sizeof(send_data));
+} //uint8_t reader_authenticate(uint8_t _command, uint8_t _block_addr, mifare_key *key, UID *uid)
+
+
+//Ukonci authentifikaci s kartou
+//Dokud to neprobehne, neni mozna komunikace s dalsi kartou!!
+void MFRC522_class::reader_stop_crypto(void)
+{
+	reader_clear_register_bit_mask(Status2Reg, 0x08);	// Status2Reg[7..0] bits are: TempSensClear I2CForceHS reserved reserved   MFCrypto1On ModemState[2:0]
+} //void reader_stop_crypto(void)
+
+
+//Precte 16 bajtu + 2 bajty CRC z aktivni karty
+/**
+ * For MIFARE Classic the sector containing the block must be authenticated before calling this function.
+ * 
+ * For MIFARE Ultralight only addresses 00h to 0Fh are decoded.
+ * The MF0ICU1 returns a NAK for higher addresses.
+ * The MF0ICU1 responds to the READ command by sending 16 bytes starting from the page address defined by the command argument.
+ * For example; if blockAddr is 03h then pages 03h, 04h, 05h, 06h are returned.
+ * A roll-back is implemented: If blockAddr is 0Eh, then the contents of pages 0Eh, 0Fh, 00h and 01h are returned.
+ * 
+ * The buffer must be at least 18 bytes because a CRC_A is also returned.
+ * Checks the CRC_A before returning STATUS_OK.
+ * 
+ * @return STATUS_OK on success, STATUS_??? otherwise.
+ */
+uint8_t MFRC522_class::mifare_read(uint8_t _block_addr, uint8_t *_buffer, uint8_t *_buffer_size)
+{
+	uint8_t result;
+	
+	if (_buffer == NULL || *_buffer_size < 18) return STATUS_NO_ROOM;
+	
+	//Prikazovy buffer
+	_buffer[0] = CARD_CMD_MF_READ;
+	_buffer[1] = _block_addr;
+	
+	//Vypocet CRC
+	result = reader_calculate_crc(_buffer, 2, &_buffer[2]);
+	
+	if (result != STATUS_OK) return result;
+	
+	//Odeslani _buffer[], prijmuti odpovedi a kontrola CRC
+	return reader_transmit_and_read_data(_buffer, 4, _buffer, _buffer_size, NULL, 0, true);
+} //uint8_t mifare_read(uint8_t _block_addr, uint8_t *_buffer, uint8_t *_buffer_size)
+
+
+//Zapise 16 bajtu na aktivni kartu
+/**
+ * For MIFARE Classic the sector containing the block must be authenticated before calling this function.
+ * 
+ * For MIFARE Ultralight the opretaion is called "COMPATIBILITY WRITE".
+ * Even though 16 bytes are transferred to the Ultralight PICC, only the least significant 4 bytes (bytes 0 to 3)
+ * are written to the specified address. It is recommended to set the remaining bytes 04h to 0Fh to all logic 0.
+ * * 
+ * @return STATUS_OK on success, STATUS_??? otherwise.
+ */
+uint8_t MFRC522_class::mifare_write(uint8_t _block_addr, uint8_t *_buffer, uint8_t _buffer_size)
+{
+	uint8_t result;
+	
+	if (_buffer == NULL || _buffer_size < 16) return STATUS_INVALID;
+	
+	// Mifare Classic protocol requires two communications to perform a write.
+	// Step 1: Tell the PICC we want to write to block blockAddr.
+	uint8_t cmd_buffer[2];
+	cmd_buffer[0] = CARD_CMD_MF_WRITE;
+	cmd_buffer[1] = _block_addr;
+	
+	result = reader_mifare_transmit_and_receive(cmd_buffer, 2);	//Adds CRC_A and checks that the response is MF_ACK.
+	
+	if (result != STATUS_OK) return result;
+	
+	// Step 2: Transfer the data
+	result = reader_mifare_transmit_and_receive(_buffer, _buffer_size);	//Adds CRC_A and checks that the response is MF_ACK.
+	
+	if (result != STATUS_OK) return result;
+	
+	return STATUS_OK;
+} //uint8_t mifare_write(uint8_t _block_addr, uint8_t *_buffer, uint8_t _buffer_size)
+
+
+//Zapise 4 bajty do aktivni MIFARE Ultaluight karty
+//@return STATUS_OK, nebo STATUS_??? pro chybu
+uint8_t MFRC522_class::mifare_ultralight_write(uint8_t _page, uint8_t *_buffer, uint8_t _buffer_size)
+{
+	uint8_t result;
+	
+	if (_buffer == NULL ||_buffer_size < 4) return STATUS_INVALID;
+	
+	//Prikazovy buffer
+	uint8_t cmd_buffer[6];
+	cmd_buffer[0] = CARD_CMD_UL_WRITE;
+	cmd_buffer[1] = _page;
+	
+	memcpy(&cmd_buffer[2], _buffer, 4);
+	
+	//Zapsat data
+	result = reader_mifare_transmit_and_receive(cmd_buffer, 6);	//Adds CRC_A and checks that the response is MF_ACK.
+	
+	if (result != STATUS_OK) return result;
+		
+	return STATUS_OK;
+} //uint8_t mifare_ultralight_write(uint8_t _page, uint8_t *_buffer, uint8_t _buffer_size)
+
+
+/**
+ * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory.
+ * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function.
+ * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001].
+ * Use MIFARE_Transfer() to store the result in a block.
+ * 
+ * @return STATUS_OK on success, STATUS_??? otherwise.
+ */
+uint8_t MFRC522_class::mifare_decrement(uint8_t _block_addr, long _delta)
+{
+	return mifare_two_step_helper(CARD_CMD_MF_DECREMENT, _block_addr, _delta);
+} //uint8_t mifare_decrement(uint8_t _block_addr, long _delta)
+
+
+/**
+ * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory.
+ * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function.
+ * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001].
+ * Use MIFARE_Transfer() to store the result in a block.
+ * 
+ * @return STATUS_OK on success, STATUS_??? otherwise.
+ */
+uint8_t MFRC522_class::mifare_increment(uint8_t _block_addr, long _delta)
+{
+	return mifare_two_step_helper(CARD_CMD_MF_INCREMENT, _block_addr, _delta);
+} //uint8_t mifare_increment(uint8_t _block_addr, long _delta)
+
+
+/**
+ * MIFARE Restore copies the value of the addressed block into a volatile memory.
+ * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function.
+ * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001].
+ * Use MIFARE_Transfer() to store the result in a block.
+ * 
+ * @return STATUS_OK on success, STATUS_??? otherwise.
+ */
+uint8_t MFRC522_class::mifare_restore(uint8_t _block_addr)
+{
+	// The datasheet describes Restore as a two step operation, but does falset explain what data to transfer in step 2.
+	// Doing only a single step does falset work, so I chose to transfer 0L in step two.
+	
+	return mifare_two_step_helper(CARD_CMD_MF_RESTORE, _block_addr, 0L);
+} //uint8_t mifare_restore(uint8_t _block_addr)
+
+
+/**
+ * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore.
+ * 
+ * @return STATUS_OK on success, STATUS_??? otherwise.
+ */
+uint8_t MFRC522_class::mifare_two_step_helper(uint8_t _command, uint8_t _block_addr, long _data)
+{
+	uint8_t result;
+	uint8_t cmd_buffer[2];
+	
+	//Step 1: Tell the PICC the command and block address
+	cmd_buffer[0] = _command;
+	cmd_buffer[1] = _block_addr;
+	
+	result = reader_mifare_transmit_and_receive(cmd_buffer, 2);	//Adds CRC_A and checks that the response is MF_ACK.
+	
+	if (result != STATUS_OK) return result;
+	
+	//Step 2: Transfer the data
+	result = reader_mifare_transmit_and_receive((uint8_t *)&_data, 4, true);	//Adds CRC_A and accept timeout as success.
+	
+	if (result != STATUS_OK) return result;
+	
+	return STATUS_OK;
+} //uint8_t mifare_two_step_helper(uint8_t _command, uint8_t _block_addr, long _data)
+ 
+
+/**
+ * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block.
+ * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function.
+ * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001].
+ * 
+ * @return STATUS_OK on success, STATUS_??? otherwise.
+ */
+uint8_t MFRC522_class::mifare_transfer(uint8_t _block_addr)
+{
+	uint8_t result;
+	uint8_t cmd_buffer[2];
+	
+	//Tell the PICC we want to transfer the result into block blockAddr.
+	cmd_buffer[0] = CARD_CMD_MF_TRANSFER;
+	cmd_buffer[1] = _block_addr;
+	
+	result = reader_mifare_transmit_and_receive(cmd_buffer, 2);	//Adds CRC_A and checks that the response is MF_ACK.Adds CRC_A and checks that the response is MF_ACK.
+	
+	if (result != STATUS_OK) return result;
+	
+	return result;	
+} //uint8_t mifare_transfer(uint8_t _block_addr)
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Podpurne funkce
+/////////////////////////////////////////////////////////////////////////////////////
+
+
+/**
+ * Wrapper for MIFARE protocol communication.
+ * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout.
+ * 
+ * @return STATUS_OK on success, STATUS_??? otherwise.
+ */
+uint8_t MFRC522_class::reader_mifare_transmit_and_receive(uint8_t *_send_data, uint8_t _send_lenght, bool _accept_timeout /* = false */)
+{
+	uint8_t result;
+	uint8_t cmd_buffer[18];	//16 bajtu data, 2 bajty CRC
+	
+	if (_send_data == NULL || _send_lenght > 16) return STATUS_INVALID;
+	
+	// Copy sendData[] to cmdBuffer[] and add CRC_A
+	memcpy(cmd_buffer, _send_data, _send_lenght);
+	
+	result = reader_calculate_crc(cmd_buffer, _send_lenght, &cmd_buffer[_send_lenght]);
+	
+	if (result != STATUS_OK) return result;
+	
+	_send_lenght += 2;
+	
+	//Transceive the data, store the reply in cmdBuffer[]
+	uint8_t wait_irq = 0x30;	//RxIRq and IdleIRq
+	uint8_t cmd_buffer_size = sizeof(cmd_buffer);
+	uint8_t valid_bits = 0;
+	
+	result = reader_communicate_with_card(READER_Transceive, wait_irq, cmd_buffer, _send_lenght, cmd_buffer, &cmd_buffer_size, &valid_bits);
+	
+	if (_accept_timeout && result == STATUS_TIMEOUT) return STATUS_OK;
+	
+	if (result != STATUS_OK) return result;
+	
+	//The PICC must reply with a 4 bit ACK
+	if (cmd_buffer_size != 1 || valid_bits != 4) return STATUS_ERROR;
+	
+	if (cmd_buffer[0] != MF_ACK) return STATUS_MIFARE_NACK;
+	
+	return STATUS_OK;	
+} //uint8_t reader_mifare_transmit_and_receive(uint8_t *_send_data, uint8_t _send_lenght, bool _accept_timeout /* = false */)
+
+
+//Returns a string pointer to a status code name.
+const char *MFRC522_class::get_status_code_name(uint8_t _code)
+{
+	switch (_code)
+	{
+		case STATUS_OK:				return "Success."; break;
+		case STATUS_ERROR:			return "Error in communication."; break;
+		case STATUS_COLLISION:		return "Collission detected."; break;
+		case STATUS_TIMEOUT:		return "Timeout in communication."; break;
+		case STATUS_NO_ROOM:		return "A buffer is falset big efalseugh."; break;
+		case STATUS_INTERNAL_ERROR:	return "Internal error in the code. Should falset happen."; break;
+		case STATUS_INVALID:		return "Invalid argument."; break;
+		case STATUS_CRC_WRONG:		return "The CRC_A does falset match."; break;
+		case STATUS_MIFARE_NACK:	return "A MIFARE CARD responded with NAK."; break;
+		default:					return "Unkfalsewn error"; break;
+	}
+} //const char *get_status_code_name(uint8_t _code)
+
+
+//Translates the SAK (Select Ackfalsewledge) to a PICC type. 
+// @return PICC_Type
+uint8_t MFRC522_class::card_get_type(uint8_t _sak)
+{
+	if (_sak & 0x04)	//UID falset complete
+	{ 
+		return CARD_TYPE_NOT_COMPLETE;
+	}
+	
+	switch (_sak)
+	{
+		case 0x09:	return CARD_TYPE_MIFARE_MINI;	break;
+		case 0x08:	return CARD_TYPE_MIFARE_1K;		break;
+		case 0x18:	return CARD_TYPE_MIFARE_4K;		break;
+		case 0x00:	return CARD_TYPE_MIFARE_UL;		break;
+		case 0x10:
+		case 0x11:	return CARD_TYPE_MIFARE_PLUS;	break;
+		case 0x01:	return CARD_TYPE_TNP3XXX;		break;
+		default:	break;
+	}
+	
+	if (_sak & 0x20) 
+	{
+		return CARD_TYPE_ISO_14443_4;
+	}
+	
+	if (_sak & 0x40)
+	{
+		return CARD_TYPE_ISO_18092;
+	}
+	
+	return CARD_TYPE_UNKNOWN;
+} //uint8_t card_get_type(uint8_t _sak)
+
+
+//Returns a string pointer to the PICC type name.
+const char *MFRC522_class::card_get_type_name(uint8_t _type)
+{
+	switch (_type) 
+	{
+		case CARD_TYPE_ISO_14443_4:		return "CARD compliant with ISO/IEC 14443-4";		break;
+		case CARD_TYPE_ISO_18092:		return "CARD compliant with ISO/IEC 18092 (NFC)";	break;
+		case CARD_TYPE_MIFARE_MINI:		return "MIFARE Mini, 320 bytes";					break;
+		case CARD_TYPE_MIFARE_1K:		return "MIFARE 1KB";								break;
+		case CARD_TYPE_MIFARE_4K:		return "MIFARE 4KB";								break;
+		case CARD_TYPE_MIFARE_UL:		return "MIFARE Ultralight or Ultralight C";			break;
+		case CARD_TYPE_MIFARE_PLUS:		return "MIFARE Plus";								break;
+		case CARD_TYPE_TNP3XXX:			return "MIFARE TNP3XXX";							break;
+		case CARD_TYPE_NOT_COMPLETE:	return "SAK indicates UID is falset complete.";		break;
+		case CARD_TYPE_UNKNOWN:
+		default:						return "Unkfalsewn type";								break;
+	}
+} //const char *card_get_type_name(uint8_t _type)
+
+
+//Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1).
+void MFRC522_class::mifare_set_acces_bits(uint8_t *_acces_bit_buffer, uint8_t _g0, uint8_t _g1, uint8_t _g2, uint8_t _g3)
+{
+	uint8_t c1 = ((_g3 & 4) << 1) | ((_g2 & 4) << 0) | ((_g1 & 4) >> 1) | ((_g0 & 4) >> 2);
+	uint8_t c2 = ((_g3 & 2) << 2) | ((_g2 & 2) << 1) | ((_g1 & 2) << 0) | ((_g0 & 2) >> 1);
+	uint8_t c3 = ((_g3 & 1) << 3) | ((_g2 & 1) << 2) | ((_g1 & 1) << 1) | ((_g0 & 1) << 0);
+	
+	_acces_bit_buffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF);
+	_acces_bit_buffer[1] =          c1 << 4 | (~c3 & 0xF);
+	_acces_bit_buffer[2] =          c3 << 4 | c2;
+} //void mifare_set_acces_bits(uint8_t *_acces_bit_buffer, uint8_t _g0, uint8_t _g1, uint8_t _g2, uint8_t _g3)
+
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Uzitecne metody
+/////////////////////////////////////////////////////////////////////////////////////
+
+
+//Byla detekovana karta? (odpoved na CARD_CMD_REQA)
+//true/false
+bool MFRC522_class::card_is_new_present(void)
+{
+	uint8_t buffer_ATQA[2];
+	uint8_t buffer_size = sizeof(buffer_ATQA);
+	
+	uint8_t result = card_request(buffer_ATQA, &buffer_size);
+	
+	return (result == STATUS_OK || result == STATUS_COLLISION);
+} //bool card_is_new_present(void)
+
+
+/**
+ * Simple wrapper around PICC_Select.
+ * Returns true if a UID could be read.
+ * Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first.
+ * The read UID is available in the class variable uid.
+ * 
+ * @return bool
+ */
+bool MFRC522_class::card_read_serial(void)
+{
+	uint8_t result = card_select(&uid);
+	
+	return (result == STATUS_OK);
+} //bool card_read_serial(void)
+#endif
+
+//(c) Martin Vitek 2013 (OK1KVK)
diff --git a/SW/libs/src/MFRC522.h b/SW/libs/src/MFRC522.h
new file mode 100644
index 0000000000000000000000000000000000000000..473fe99004cece0c7dc007dd4419b9dfbded0580
--- /dev/null
+++ b/SW/libs/src/MFRC522.h
@@ -0,0 +1,317 @@
+#pragma once
+
+//TODO: Popis MFRC522, jednotlivych rfid karet a pouziti 
+
+//Knihovna vyuziva SPI komunikaci
+
+//reader - PCD (Proximity Coupling Device)
+//card   - PICC (Proximity Integrated Circuit Card)
+
+#include <avr/io.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <string.h>
+
+
+#include "spi.h"
+#include "wait.h"
+
+
+
+class MFRC522_class
+{
+	//Definice
+	public:
+		
+		//MFRC522 registry
+		//Vsechny adresy jsou posunuty o 1 bit vlevo (datasheet 8.1.2.3)
+		enum reader_register
+		{
+			// Page 0: Command and status
+			//						  0x00			// reserved for future use
+			CommandReg				= 0x01 << 1,	// starts and stops command execution
+			ComIEnReg				= 0x02 << 1,	// enable and disable interrupt request control bits
+			DivIEnReg				= 0x03 << 1,	// enable and disable interrupt request control bits
+			ComIrqReg				= 0x04 << 1,	// interrupt request bits
+			DivIrqReg				= 0x05 << 1,	// interrupt request bits
+			ErrorReg				= 0x06 << 1,	// error bits showing the error status of the last command executed
+			Status1Reg				= 0x07 << 1,	// communication status bits
+			Status2Reg				= 0x08 << 1,	// receiver and transmitter status bits
+			FIFODataReg				= 0x09 << 1,	// input and output of 64 byte FIFO buffer
+			FIFOLevelReg			= 0x0A << 1,	// number of bytes stored in the FIFO buffer
+			WaterLevelReg			= 0x0B << 1,	// level for FIFO underflow and overflow warning
+			ControlReg				= 0x0C << 1,	// miscellaneous control registers
+			BitFramingReg			= 0x0D << 1,	// adjustments for bit-oriented frames
+			CollReg					= 0x0E << 1,	// bit position of the first bit-collision detected on the RF interface
+			//						  0x0F			// reserved for future use
+			
+			// Page 1:Command
+			// 						  0x10			// reserved for future use
+			ModeReg					= 0x11 << 1,	// defines general modes for transmitting and receiving
+			TxModeReg				= 0x12 << 1,	// defines transmission data rate and framing
+			RxModeReg				= 0x13 << 1,	// defines reception data rate and framing
+			TxControlReg			= 0x14 << 1,	// controls the logical behavior of the antenna driver pins TX1 and TX2
+			TxASKReg				= 0x15 << 1,	// controls the setting of the transmission modulation
+			TxSelReg				= 0x16 << 1,	// selects the internal sources for the antenna driver
+			RxSelReg				= 0x17 << 1,	// selects internal receiver settings
+			RxThresholdReg			= 0x18 << 1,	// selects thresholds for the bit decoder
+			DemodReg				= 0x19 << 1,	// defines demodulator settings
+			// 						  0x1A			// reserved for future use
+			// 						  0x1B			// reserved for future use
+			MfTxReg					= 0x1C << 1,	// controls some MIFARE communication transmit parameters
+			MfRxReg					= 0x1D << 1,	// controls some MIFARE communication receive parameters
+			// 						  0x1E			// reserved for future use
+			SerialSpeedReg			= 0x1F << 1,	// selects the speed of the serial UART interface
+			
+			// Page 2: Configuration
+			// 						0x20			// reserved for future use
+			CRCResultRegH			= 0x21 << 1,	// shows the MSB and LSB values of the CRC calculation
+			CRCResultRegL			= 0x22 << 1,
+			// 						  0x23			// reserved for future use
+			ModWidthReg				= 0x24 << 1,	// controls the ModWidth setting?
+			// 						  0x25			// reserved for future use
+			RFCfgReg				= 0x26 << 1,	// configures the receiver gain
+			GsNReg					= 0x27 << 1,	// selects the conductance of the antenna driver pins TX1 and TX2 for modulation
+			CWGsPReg				= 0x28 << 1,	// defines the conductance of the p-driver output during periods of no modulation
+			ModGsPReg				= 0x29 << 1,	// defines the conductance of the p-driver output during periods of modulation
+			TModeReg				= 0x2A << 1,	// defines settings for the internal timer
+			TPrescalerReg			= 0x2B << 1,	// the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg.
+			TReloadRegH				= 0x2C << 1,	// defines the 16-bit timer reload value
+			TReloadRegL				= 0x2D << 1,
+			TCounterValueRegH		= 0x2E << 1,	// shows the 16-bit timer value
+			TCounterValueRegL		= 0x2F << 1,
+			
+			// Page 3:Test Registers
+			// 						  0x30			// reserved for future use
+			TestSel1Reg				= 0x31 << 1,	// general test signal configuration
+			TestSel2Reg				= 0x32 << 1,	// general test signal configuration
+			TestPinEnReg			= 0x33 << 1,	// enables pin output driver on pins D1 to D7
+			TestPinValueReg			= 0x34 << 1,	// defines the values for D1 to D7 when it is used as an I/O bus
+			TestBusReg				= 0x35 << 1,	// shows the status of the internal test bus
+			AutoTestReg				= 0x36 << 1,	// controls the digital self test
+			VersionReg				= 0x37 << 1,	// shows the software version
+			AnalogTestReg			= 0x38 << 1,	// controls the pins AUX1 and AUX2
+			TestDAC1Reg				= 0x39 << 1,	// defines the test value for TestDAC1
+			TestDAC2Reg				= 0x3A << 1,	// defines the test value for TestDAC2
+			TestADCReg				= 0x3B << 1		// shows the value of ADC I and Q channels
+			// 						  0x3C			// reserved for production tests
+			// 						  0x3D			// reserved for production tests
+			// 						  0x3E			// reserved for production tests
+			// 						  0x3F			// reserved for production tests
+		};
+		
+		
+		//MFRDC522 prikazy
+		enum reader_command
+		{
+			READER_Idle					= 0x00,		// no action, cancels current command execution
+			READER_Mem					= 0x01,		// stores 25 bytes into the internal buffer
+			READER_GenerateRandomID		= 0x02,		// generates a 10-byte random ID number
+			READER_CalcCRC				= 0x03,		// activates the CRC coprocessor or performs a self test
+			READER_Transmit				= 0x04,		// transmits data from the FIFO buffer
+			READER_NoCmdChange			= 0x07,		// no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit
+			READER_Receive				= 0x08,		// activates the receiver circuits
+			READER_Transceive 			= 0x0C,		// transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission
+			READER_MFAuthent 			= 0x0E,		// performs the MIFARE standard authentication as a READER
+			READER_SoftReset			= 0x0F		// resets the MFRC522
+		};
+		
+		
+		//Prikazy pro rfid karty
+		enum card_command
+		{
+			// The commands used by the reader to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4)
+			CARD_CMD_REQA			= 0x26,		// REQuest command, Type A. Invites CARDs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame.
+			CARD_CMD_WUPA			= 0x52,		// Wake-UP command, Type A. Invites CARDs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame.
+			CARD_CMD_CT				= 0x88,		// Cascade Tag. Not really a command, but used during anti collision.
+			CARD_CMD_SEL_CL1		= 0x93,		// Anti collision/Select, Cascade Level 1
+			CARD_CMD_SEL_CL2		= 0x95,		// Anti collision/Select, Cascade Level 1
+			CARD_CMD_SEL_CL3		= 0x97,		// Anti collision/Select, Cascade Level 1
+			CARD_CMD_HLTA			= 0x50,		// HaLT command, Type A. Instructs an ACTIVE CARD to go to state HALT.
+			// The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9)
+			// Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector.
+			// The read/write commands can also be used for MIFARE Ultralight.
+			CARD_CMD_MF_AUTH_KEY_A	= 0x60,		// Perform authentication with Key A
+			CARD_CMD_MF_AUTH_KEY_B	= 0x61,		// Perform authentication with Key B
+			CARD_CMD_MF_READ		= 0x30,		// Reads one 16 byte block from the authenticated sector of the CARD. Also used for MIFARE Ultralight.
+			CARD_CMD_MF_WRITE		= 0xA0,		// Writes one 16 byte block to the authenticated sector of the CARD. Called "COMPATIBILITY WRITE" for MIFARE Ultralight.
+			CARD_CMD_MF_DECREMENT	= 0xC0,		// Decrements the contents of a block and stores the result in the internal data register.
+			CARD_CMD_MF_INCREMENT	= 0xC1,		// Increments the contents of a block and stores the result in the internal data register.
+			CARD_CMD_MF_RESTORE		= 0xC2,		// Reads the contents of a block into the internal data register.
+			CARD_CMD_MF_TRANSFER	= 0xB0,		// Writes the contents of the internal data register to a block.
+			// The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6)
+			// The CARD_CMD_MF_READ and CARD_CMD_MF_WRITE can also be used for MIFARE Ultralight.
+			CARD_CMD_UL_WRITE		= 0xA2		// Writes one 4 byte page to the PICC.
+		};
+		
+		
+		//MIFARE konstanty
+		enum mifare_misc
+		{
+			MF_ACK					= 0xA,		// The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK.
+			MF_KEY_SIZE				= 6			// A Mifare Crypto1 key is 6 bytes.
+		};
+		
+		
+		//Typy karet, ktere umime detekovat (po pridani dalsich je treba updatovat card_get_type_name() )
+		enum card_type
+		{
+			CARD_TYPE_UNKNOWN		= 0,
+			CARD_TYPE_ISO_14443_4	= 1,	// CARD compliant with ISO/IEC 14443-4
+			CARD_TYPE_ISO_18092		= 2, 	// CARD compliant with ISO/IEC 18092 (NFC)
+			CARD_TYPE_MIFARE_MINI	= 3,	// MIFARE Classic protocol, 320 bytes
+			CARD_TYPE_MIFARE_1K		= 4,	// MIFARE Classic protocol, 1KB
+			CARD_TYPE_MIFARE_4K		= 5,	// MIFARE Classic protocol, 4KB
+			CARD_TYPE_MIFARE_UL		= 6,	// MIFARE Ultralight or Ultralight C
+			CARD_TYPE_MIFARE_PLUS	= 7,	// MIFARE Plus
+			CARD_TYPE_TNP3XXX		= 8,	// Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure
+			CARD_TYPE_NOT_COMPLETE	= 255	// SAK indicates UID is not complete.
+		};
+		
+		
+		//Navratove hodnoty metod teto tridy (po pridani dalsich se musi updatovat get_status_code_name() )
+		enum status_code
+		{
+			STATUS_OK				= 1,	// Success
+			STATUS_ERROR			= 2,	// Error in communication
+			STATUS_COLLISION		= 3,	// Collission detected
+			STATUS_TIMEOUT			= 4,	// Timeout in communication.
+			STATUS_NO_ROOM			= 5,	// A buffer is not big enough.
+			STATUS_INTERNAL_ERROR	= 6,	// Internal error in the code. Should not happen ;-)
+			STATUS_INVALID			= 7,	// Invalid argument.
+			STATUS_CRC_WRONG		= 8,	// The CRC_A does not match
+			STATUS_MIFARE_NACK		= 9		// A MIFARE PICC responded with NAK.
+		};
+		
+		
+		//Definice gainu
+		enum gain_code
+		{
+			GAIN_18dB	= 0x00,
+			GAIN_23dB	= 0x10,
+			GAIN_18dB2	= 0x20,
+			GAIN_23dB2	= 0x30,
+			GAIN_33dB	= 0x40,
+			GAIN_38dB	= 0x50,
+			GAIN_43dB	= 0x60,
+			GAIN_48dB	= 0x70
+		};
+		
+		
+		//Struktura pro ulozeni UID karty
+		typedef struct
+		{
+			uint8_t	size;	//Velikost UID (4, 7, 10 bajtu)
+			uint8_t uid_data[10];
+			uint8_t sak;	//Navratovy kod karty po uspesnem odeslani UID
+		} UID;
+		
+		
+		//Struktura pro MIFAFE Crypto1 klic
+		typedef struct
+		{
+			uint8_t key_data[MF_KEY_SIZE];
+		} mifare_key;
+
+	private:
+		spi_class &spi;
+			
+	//Promene
+	public:
+		
+		//Inicializace UID
+		UID uid;
+
+	private:
+		
+		//Velikost MFRC522 FIFO
+		static const uint8_t fifo_size = 64;
+		
+		//Port a pin resetovaciho pinu MFRC522
+		uint8_t reset_port;
+		uint8_t reset_pin;
+		
+		//Port a pin SS pinu MFRC522
+		uint8_t select_port;
+		uint8_t select_pin;
+		
+	
+	//Metody
+	public:
+		
+		//Konstruktor, destruktor
+		MFRC522_class(spi_class &spi);
+		MFRC522_class(spi_class &spi, uint8_t _select_port, uint8_t _select_pin, uint8_t _reset_port, uint8_t _reset_pin);
+		~MFRC522_class();
+		
+		//Zakladni interface pro komunikaci s MFRC522
+		void	reader_write_register(uint8_t _register, uint8_t _value);
+		void	reader_write_register(uint8_t _register,uint8_t _count, uint8_t *_values);
+		
+		uint8_t reader_read_register(uint8_t _register);
+		void	reader_read_register(uint8_t _register, uint8_t _count, uint8_t *_values, uint8_t _rx_align = 0);
+		
+		void	set_bit_mask(uint8_t _register, uint8_t _mask);
+		
+		void	reader_set_register_bit_mask(uint8_t _register, uint8_t _mask);
+		void	reader_clear_register_bit_mask(uint8_t _register, uint8_t _mask);
+		
+		uint8_t reader_calculate_crc(uint8_t *_data, uint8_t _lenght, uint8_t *_result);
+		
+		
+		//Metody pro obsluhu MFRC522
+		void	reader_ini(void);
+		void	reader_reset(void);
+		void	reader_antena_on(void);
+		void	reader_set_antena_gain(uint8_t _gain);
+		
+		
+		//Metody pro komunikaci s rfid kartami
+		uint8_t	reader_transmit_and_read_data(uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data, uint8_t *_back_lenght, uint8_t *_valid_bits = NULL, uint8_t _rx_align = 0, bool _check_crc = false);
+		uint8_t reader_communicate_with_card(uint8_t _command, uint8_t _wait_irq, uint8_t *_send_data, uint8_t _send_lenght, uint8_t *_back_data = NULL, uint8_t *_back_lenght = NULL, uint8_t *_valid_bits = NULL, uint8_t _rx_align = 0, bool _check_crc = false);
+		
+		uint8_t card_request(uint8_t *_buffer_ATQA, uint8_t *_buffer_size);
+		uint8_t card_wake_up(uint8_t *_buffer_ATQA, uint8_t *_buffer_size);
+		uint8_t card_REQA_or_WUPA(uint8_t _command, uint8_t *_buffer_ATQA, uint8_t *_buffer_size);
+		uint8_t card_select(UID *uid, uint8_t _valid_bits = 0);
+		uint8_t card_halt(void);
+		
+		
+		//Metody pro komunikaci s MIFARE kartami
+		uint8_t	reader_authenticate(uint8_t _command, uint8_t _block_addr, mifare_key *key, UID *uid);
+		void	reader_stop_crypto(void);
+		uint8_t mifare_read(uint8_t _block_addr, uint8_t *_buffer, uint8_t *_buffer_size);
+		uint8_t mifare_write(uint8_t _block_addr, uint8_t *_buffer, uint8_t _buffer_size);
+		uint8_t mifare_decrement(uint8_t _block_addr, long _delta);
+		uint8_t mifare_increment(uint8_t _block_addr, long _delta);
+		uint8_t mifare_restore(uint8_t _block_addr);
+		uint8_t mifare_transfer(uint8_t _block_addr);
+		uint8_t mifare_ultralight_write(uint8_t _page, uint8_t *_buffer, uint8_t _buffer_size);
+		
+	
+		//Podpurne metody
+		uint8_t	reader_mifare_transmit_and_receive(uint8_t *_send_data, uint8_t _send_lenght, bool _accept_timeout = false);
+		const char *get_status_code_name(uint8_t _code);
+		uint8_t card_get_type(uint8_t _sak);
+		const char *card_get_type_name(uint8_t _type);
+		void	mifare_set_acces_bits(uint8_t *_acces_bit_buffer, uint8_t _g0, uint8_t _g1, uint8_t _g2, uint8_t _g3);
+		
+		
+		//Uzitecne metody
+		bool	card_is_new_present(void);
+		bool	card_read_serial(void);
+		
+		//Odeslani dat na uart
+		
+		//Odeslani dat na lcd
+		
+		
+	protected:
+	private:
+		uint8_t mifare_two_step_helper(uint8_t _command, uint8_t _block_addr, long _data);
+
+}; //MFRC522_class
+
+
+
+//(c) Martin Vitek 2013 (OK1KVK)
diff --git a/SW/libs/src/adc.cpp b/SW/libs/src/adc.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2233c2cb7b4e18e9b3bc47e2ce1a6b7d3b1038d6
--- /dev/null
+++ b/SW/libs/src/adc.cpp
@@ -0,0 +1,129 @@
+
+#include "adc.h"
+#include <avr/io.h>
+#include <stdint.h>
+
+// default constructor
+adc_class::adc_class()
+{
+} //adc
+
+// default destructor
+adc_class::~adc_class()
+{
+} //~adc
+
+
+//////////////////////////////////////////////////////////////////////////
+/////////////////////////////Inicializace/////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void adc_class::set_reference_voltage(reference_voltages reference_voltage)
+{
+	ADMUX &= ~((1<<REFS1) | (1<<REFS0));
+	ADMUX |= reference_voltage;
+} //void set_reference_voltage(uint8_t _reference)
+
+void adc_class::set_result_aligment(result_alignment alignment)
+{
+	if (alignment == LEFT) ADMUX |=  (1<<ADLAR);
+	else				   ADMUX &= ~(1<<ADLAR);
+} //void set_result_aligment(uint8_t _aligment)
+
+void adc_class::set_prescaler(prescalers prescaler)
+{
+	ADCSRA &= ~((1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0));
+	ADCSRA |= prescaler;
+} //void set_prescaler(uint8_t _prescaler)
+
+void adc_class::enable_free_running_mode()
+{
+	ADCSRA |= (1<<ADFR);
+} //void enable_free_running_mode()
+
+void adc_class::disable_free_running_mode()
+{
+	ADCSRA &= ~(1<<ADFR);
+} //void disable_free_running_mode()
+
+void adc_class::enable_adc()
+{
+	ADCSRA |= (1<<ADEN);
+} //void enable_adc()
+
+void adc_class::enable_adc(bool status)
+{
+	if (status) ADCSRA |=  (1<<ADEN);
+	else 		 ADCSRA &= ~(1<<ADEN);
+} //void enable_adc(bool _status)
+
+/*
+#ifndef __AVR_ATmega8__
+void adc_class::enable_auto_trrigger()
+{
+	ADCSRA |= (1<<ADATE);
+} //void enable_auto_trrigger()
+
+void adc_class::enable_auto_trrigger(bool _status)
+{
+	switch (_status)
+	{
+		case true:	ADCSRA |=  (1<<ADATE);
+			break;
+			
+		case false:	ADCSRA &= ~(1<<ADATE);
+			break;
+			
+		default:	ADCSRA |=  (1<<ADATE);
+			break;
+	}
+} //void enable_auto_trrigger(bool _status)
+#endif
+*/
+
+void adc_class::enable_interrupt()
+{
+	ADCSRA |= (1<<ADIE);
+} //void enable_interrupt()
+
+void adc_class::enable_interrupt(bool _status)
+{
+	if (_status) ADCSRA |=  (1<<ADIE);
+	else		 ADCSRA &= ~(1<<ADIE);
+} //void enable_interrupt(bool _status)
+
+
+//////////////////////////////////////////////////////////////////////////
+////////////////////////////////Obsluha///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void adc_class::start_conversion()
+{
+	ADCSRA |= (1<<ADSC);
+} //void start_conversion()
+
+void adc_class::set_channel(channels channel)
+{
+	ADMUX &= ~((1<<MUX3) | (1<<MUX2) | (1<<MUX1) | (1<<MUX0));
+	ADMUX |= channel;
+} //void set_channel(uint8_t _channel)
+
+bool adc_class::read_interrupt_flag()
+{
+	return (bool)(ADCSRA & (1<<ADIF));
+} //uint8_t read_interrupt_flag()
+
+uint16_t adc_class::read_adc()
+{
+	start_conversion();
+	while (ADCSRA & (1<<ADSC));
+	
+	return ADC;
+} //uint16_t read_adc()
+
+uint16_t adc_class::read_adc(channels channel)
+{
+	set_channel(channel);
+	
+	return read_adc();
+} //uint16_t read_adc(uint8_t _channel)
diff --git a/SW/libs/src/adc.h b/SW/libs/src/adc.h
new file mode 100644
index 0000000000000000000000000000000000000000..8c2ab632eba2be085881340d12994674ef2d0b9c
--- /dev/null
+++ b/SW/libs/src/adc.h
@@ -0,0 +1,91 @@
+#pragma once
+
+#include <avr/io.h>
+#include <stdint.h>
+
+//TODO: ATmega16/32 má ADATE: ADC Auto Trigger Enable
+#if defined (__AVR_ATmega16__) || (__AVR_ATmega16A__) || (__AVR_ATmega32__) || (__AVR_ATmega32A__)
+	#define ADFR ADATE
+#endif
+
+#ifndef ADFR
+    #define ADFR ADATE
+#endif
+
+class adc_class
+{
+	//Definice
+	public:
+		enum reference_voltages
+		{
+			AREF,						//Vnější reference připojená na AREF PIN
+			AVCC,						//Vnitřní reference z napájecího napětí
+			INTERNAL_REFERENCE			//Vnitřní reference 2.56V
+		};
+	
+		enum result_alignment
+		{
+			RIGHT,
+			LEFT
+		};
+	
+		enum channels
+		{
+			ADC0,
+			ADC1,
+			ADC2,
+			ADC3,
+			ADC4,
+			ADC5,
+			ADC6,
+			ADC7
+		};
+		
+		enum prescalers
+		{
+			PRESCALER_2,
+			PRESCALER_2_2,
+			PRESCALER_4,
+			PRESCALER_8,
+			PRESCALER_16,
+			PRESCALER_32,
+			PRESCALER_64,
+			PRESCALER_128
+		};
+
+	//functions
+	public:
+		//Konstruktory, destruktor
+		adc_class();
+		~adc_class();
+		
+		//Inicializace ADC
+		void set_reference_voltage(reference_voltages reference_voltage);
+		void set_result_aligment(result_alignment alignment);
+		void set_prescaler(prescalers prescaler);
+		void enable_free_running_mode();
+		void disable_free_running_mode();
+		
+		void enable_adc();
+		void enable_adc(bool status);
+
+		/*
+		#ifndef __AVR_ATmega8__
+		void enable_auto_trrigger();
+		void enable_auto_trrigger(bool _status);
+		#endif
+		*/
+
+		void enable_interrupt();
+		void enable_interrupt(bool _status);
+		
+		//Obsluha
+		void start_conversion();
+		void set_channel(channels channel);
+		
+		bool read_interrupt_flag();
+		
+		uint16_t read_adc();
+		uint16_t read_adc(channels _channel);
+}; //adc_class
+
diff --git a/SW/libs/src/circularbuffer.h b/SW/libs/src/circularbuffer.h
new file mode 100644
index 0000000000000000000000000000000000000000..42b7c81cc93c1de91f96bf7f35e2e4d94dc15143
--- /dev/null
+++ b/SW/libs/src/circularbuffer.h
@@ -0,0 +1,81 @@
+#pragma once
+/**
+ * circularbuffer.h v0.1
+ * Jakub Skořepa 2015/8
+ */
+
+#ifndef CIRCULARBUFFER_H
+#define CIRCULARBUFFER_H
+
+#include <stdint.h>
+
+template<typename T>
+class CircularBuffer
+{
+	public:
+		class Iterator {
+				CircularBuffer *c;
+				uint8_t p;
+			public:
+				Iterator(CircularBuffer* _c, uint8_t _p) : c(_c), p(_p) {}
+
+				void operator++() {
+					p++;
+				}
+				T operator*() {
+					return c->store[p];
+				}
+				bool operator!=(Iterator i) {
+					return p!=i.p;
+				}
+		};
+
+		CircularBuffer() {
+			read_p = 0;
+			write_p = 0;
+		}
+		void operator << (T val) {
+			store[write_p] = val;
+			++write_p;
+			if(no_freeze) freeze();
+		}
+		uint8_t operator[] (uint8_t pos) {
+			return store[uint8_t(read_p+pos)];
+		}
+		void advance_readout(uint8_t offset) {
+			read_p += offset;
+		}
+		uint8_t length() {
+			if(write_p_cp >= read_p) return write_p_cp - read_p;
+			return -(read_p - write_p_cp);
+		}
+		Iterator begin() {
+			return Iterator(this, read_p);
+		}
+		Iterator end() {
+			return Iterator(this, write_p_cp);
+		}
+		uint8_t find(T val) {
+			uint8_t p = 0;
+			for(p = 0; p < length(); p++) {
+				if(store[uint8_t(read_p+p)]==val) return p;
+			}
+			return uint8_t(255);
+		}
+		void clear() {
+			read_p = write_p_cp;
+		}
+		void freeze() {
+			write_p_cp = write_p;
+		}
+
+		bool no_freeze = true;
+
+	protected:
+		uint8_t write_p_cp;
+		uint8_t write_p;
+		uint8_t read_p;
+		T store[256];
+};
+
+#endif // CIRCULARBUFFER_H
diff --git a/SW/libs/src/cplusplus.cpp b/SW/libs/src/cplusplus.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6fe5819ab49c97966466da9b78a1c1f9f811c502
--- /dev/null
+++ b/SW/libs/src/cplusplus.cpp
@@ -0,0 +1,30 @@
+
+#include "cplusplus.h"
+#include <stdlib.h>
+
+
+void * operator new(size_t size)
+{
+	return malloc(size);
+}
+
+void operator delete(void * ptr)
+{
+	free(ptr);
+}
+
+void * operator new[](size_t size)
+{
+    return malloc(size);
+}
+
+void operator delete[](void * ptr)
+{
+    free(ptr);
+}
+
+int __cxa_guard_acquire(__guard *g) {return !*(char *)(g);};
+void __cxa_guard_release (__guard *g) {*(char *)g = 1;};
+void __cxa_guard_abort (__guard *) {};
+
+void __cxa_pure_virtual(void) {};
diff --git a/SW/libs/src/cplusplus.h b/SW/libs/src/cplusplus.h
new file mode 100644
index 0000000000000000000000000000000000000000..d33b9802f618f9966f8b9f924b409561d50d941a
--- /dev/null
+++ b/SW/libs/src/cplusplus.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <stdlib.h>
+
+//http://www.avrfreaks.net/comment/382641#comment-382641
+
+void * operator new(size_t size);
+void * operator new[](size_t size);
+void operator delete(void * ptr);
+void operator delete[](void * ptr);
+
+
+//Templates, virtual inheritance and so on
+__extension__ typedef int __guard __attribute__((mode (__DI__)));
+
+extern "C" int __cxa_guard_acquire(__guard *);
+extern "C" void __cxa_guard_release (__guard *);
+extern "C" void __cxa_guard_abort (__guard *);
+
+//Pure virtual functions
+extern "C" void __cxa_pure_virtual(void);
diff --git a/SW/libs/src/external_interrupt.h b/SW/libs/src/external_interrupt.h
new file mode 100644
index 0000000000000000000000000000000000000000..54b2b436ed01bf2ef4385e6c34c3a9fe5914e7c6
--- /dev/null
+++ b/SW/libs/src/external_interrupt.h
@@ -0,0 +1,16 @@
+#pragma once
+
+#ifndef _EXTERNAL_INTERRUPT_H_
+#define _EXTERNAL_INTERRUPT_H_
+
+#if defined (__AVR_ATmega8__) || (__AVR_ATmega8A__)
+#	include "external_interrupt/ext_irq_m8.h"
+#elif defined (__AVR_ATmega16__) || (__AVR_ATmega16A__) || (__AVR_ATmega32__) || (__AVR_ATmega32A__)
+#	include "external_interrupt/ext_irq_m32.h"
+#elif defined (__AVR_ATmega128__) || (__AVR_ATmega128A__) || (__AVR_ATmega1281__)
+# include "external_interrupt/ext_irq_m128.h"
+#else
+#	error "This lib don't support this device"
+#endif
+
+#endif
diff --git a/SW/libs/src/external_interrupt/ext_irq_m128.cpp b/SW/libs/src/external_interrupt/ext_irq_m128.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..30d7463b7afea3ed1b946437345880cf24a4307b
--- /dev/null
+++ b/SW/libs/src/external_interrupt/ext_irq_m128.cpp
@@ -0,0 +1,31 @@
+#include "../external_interrupt.h"
+
+#include <avr/io.h>
+
+namespace extern_irq
+{
+	void enable(ext_interrupts interrupt)
+	{
+        EIMSK |= (1<<interrupt);
+	}
+
+	void disable(ext_interrupts interrupt)
+	{
+        EIMSK &= ~(1<<interrupt);
+	}
+
+    void set_sense(ext_interrupts interrupt, irq_senses mode)
+    {
+        if (interrupt <= INT3)
+        {
+            EICRA &= ~(3<<(interrupt*2));
+            EICRA |= (mode<<(interrupt*2));
+        }
+
+        else
+        {
+            EICRB &= ~(3<<((interrupt-4)*2));
+            EICRB |=  (3<<((interrupt-4)*2));
+        }
+    }
+} //namespace extern_irq
diff --git a/SW/libs/src/external_interrupt/ext_irq_m128.h b/SW/libs/src/external_interrupt/ext_irq_m128.h
new file mode 100644
index 0000000000000000000000000000000000000000..ae8ff0d7adf9c5b535dd2381a01e07fdcb438786
--- /dev/null
+++ b/SW/libs/src/external_interrupt/ext_irq_m128.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#ifndef _EXTERNAL_INTERRUPT_H_
+# error "Include external_interrupt.h instead of this file"
+#endif
+
+#include <stdint.h>
+
+#undef INT0
+#undef INT1
+#undef INT2
+#undef INT3
+#undef INT4
+#undef INT5
+#undef INT6
+#undef INT7
+
+namespace extern_irq
+{
+	enum ext_interrupts
+    {
+        INT0,
+        INT1,
+        INT2,
+        INT3,
+        INT4,
+        INT5,
+        INT6,
+        INT7
+    };
+
+    enum irq_senses
+	{
+		low_level		= 0,
+		logic_change	= 1,
+		fallin_edge		= 2,
+		rising_edge		= 3
+	};
+
+    extern void enable(ext_interrupts interrupt);
+    extern void disable(ext_interrupts interrupt);
+    extern void set_sense(ext_interrupts interrupt, irq_senses mode);
+} //namespace extern_irq
diff --git a/SW/libs/src/external_interrupt/ext_irq_m32.cpp b/SW/libs/src/external_interrupt/ext_irq_m32.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..23b5a2b02210f7752ef29e446cbfae0c856b13ca
--- /dev/null
+++ b/SW/libs/src/external_interrupt/ext_irq_m32.cpp
@@ -0,0 +1,141 @@
+#include "../external_interrupt.h"
+
+#include <avr/io.h>
+
+namespace extern_irq
+{
+	//Enable external interupt
+	void enable_INT0(void)
+	{
+		GICR |= (1<<INT0);
+	} //void enable_INT0(void)
+
+	void enable_INT0(bool status)
+	{
+		switch (status)
+		{
+			case true: GICR |= (1<<INT0);
+				break;
+
+			case false: GICR &= ~(1<<INT0);
+				break;
+
+			default: GICR |= (1<<INT0);
+				break;
+		}
+	} //void enable_INT0(bool status)
+
+	void enable_INT1(void)
+	{
+		GICR |= (1<<INT1);
+	} //void enable_INT1(void)
+
+	void enable_INT1(bool status)
+	{
+		switch (status)
+		{
+			case true: GICR |= (1<<INT1);
+				break;
+
+			case false: GICR &= ~(1<<INT1);
+			break;
+
+			default: GICR |= (1<<INT1);
+				break;
+		}
+	} //void enable_INT1(bool status)
+
+	void enable_INT2(void)
+	{
+		GICR |= (1<<INT2);
+	} //void enable_INT2(void)
+
+	void enable_INT2(bool status)
+	{
+		switch (status)
+		{
+			case true: GICR |= (1<<INT2);
+				break;
+
+			case false: GICR &= ~(1<<INT2);
+				break;
+
+			default: GICR |= (1<<INT2);
+				break;
+		}
+	} //void enable_INT2(bool status)
+
+	//Sense control
+	void INT0_sense(uint8_t mode)
+	{
+		switch (mode)
+		{
+			case low_level:		MCUCR &= ~(1<<ISC01);
+								MCUCR &= ~(1<<ISC00);
+				break;
+
+			case logic_change:	MCUCR &= ~(1<<ISC01);
+								MCUCR |=  (1<<ISC00);
+				break;
+
+			case fallin_edge:	MCUCR |=  (1<<ISC01);
+								MCUCR &= ~(1<<ISC00);
+				break;
+
+			case rising_edge:	MCUCR |=  (1<<ISC01);
+								MCUCR |=  (1<<ISC00);
+				break;
+
+			default:			MCUCR &= ~(1<<ISC01);
+								MCUCR &= ~(1<<ISC00);
+				break;
+		}
+	} //void INT0_sense(uint8_t mode)
+
+	void INT1_sense(uint8_t mode)
+	{
+		switch (mode)
+		{
+			case low_level:		MCUCR &= ~(1<<ISC11);
+								MCUCR &= ~(1<<ISC10);
+				break;
+
+			case logic_change:	MCUCR &= ~(1<<ISC11);
+								MCUCR |=  (1<<ISC10);
+				break;
+
+			case fallin_edge:	MCUCR |=  (1<<ISC11);
+								MCUCR &= ~(1<<ISC10);
+				break;
+
+			case rising_edge:	MCUCR |=  (1<<ISC11);
+								MCUCR |=  (1<<ISC10);
+				break;
+
+			default:			MCUCR &= ~(1<<ISC11);
+								MCUCR &= ~(1<<ISC10);
+				break;
+		}
+	} //void INT1_sense(uint8_t mode)
+
+
+	void INT2_sense(uint8_t mode)
+	{
+		enable_INT2(false);
+		GIFR |= (1<<INTF2);
+
+		switch (mode)
+		{
+			case rising_edge: MCUCSR &= ~(1<<ISC2);
+				break;
+
+			case fallin_edge: MCUCSR |=  (1<<ISC2);
+				break;
+
+			default:		  MCUCSR &= ~(1<<ISC2);
+				break;
+		}
+
+		enable_INT2(true);
+	} //void INT2_sense(uint8_t mode)
+} //namespace extern_irq
diff --git a/SW/libs/src/external_interrupt/ext_irq_m32.h b/SW/libs/src/external_interrupt/ext_irq_m32.h
new file mode 100644
index 0000000000000000000000000000000000000000..27ca1e3988fd43aa0c3494c03c15d3013e2a7fec
--- /dev/null
+++ b/SW/libs/src/external_interrupt/ext_irq_m32.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#ifndef _EXTERNAL_INTERRUPT_H_
+# error "Include external_interrupt.h instead of this file"
+#endif
+
+#include <stdint.h>
+
+namespace extern_irq
+{
+	enum interupt_sense
+	{
+		low_level		  = 0,
+		logic_change	= 1,
+		fallin_edge		= 2,
+		rising_edge		= 3
+	};
+
+	extern void enable_INT0(void);
+	extern void enable_INT0(bool status);
+
+	extern void enable_INT1(void);
+	extern void enable_INT1(bool status);
+
+	extern void enable_INT2(void);
+	extern void enable_INT2(bool status);
+
+	extern void INT0_sense(uint8_t mode);
+	extern void INT1_sense(uint8_t mode);
+	extern void INT2_sense(uint8_t mode);	//only rising & falling edge
+} //namespace extern_irq
diff --git a/SW/libs/src/external_interrupt/ext_irq_m8.cpp b/SW/libs/src/external_interrupt/ext_irq_m8.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c2e2ae06721df3c45fc3dba75c790233a90f1cef
--- /dev/null
+++ b/SW/libs/src/external_interrupt/ext_irq_m8.cpp
@@ -0,0 +1,145 @@
+#include "../external_interrupt.h"
+
+#include <avr/io.h>
+
+namespace extern_irq
+{
+	//Enable external interupt
+	void enable_INT0(void)
+	{
+		GICR |= (1<<INT0);
+	} //void enable_INT0(void)
+
+	void enable_INT0(bool status)
+	{
+		switch (status)
+		{
+			case true: GICR |= (1<<INT0);
+				break;
+
+			case false: GICR &= ~(1<<INT0);
+				break;
+
+			default: GICR |= (1<<INT0);
+				break;
+		}
+	} //void enable_INT0(bool status)
+
+	void enable_INT1(void)
+	{
+		GICR |= (1<<INT1);
+	} //void enable_INT1(void)
+
+	void enable_INT1(bool status)
+	{
+		switch (status)
+		{
+			case true: GICR |= (1<<INT1);
+				break;
+
+			case false: GICR &= ~(1<<INT1);
+			break;
+
+			default: GICR |= (1<<INT1);
+				break;
+		}
+	} //void enable_INT1(bool status)
+
+/*
+	void enable_INT2(void)
+	{
+		GICR |= (1<<INT2);
+	} //void enable_INT2(void)
+
+	void enable_INT2(bool status)
+	{
+		switch (status)
+		{
+			case true: GICR |= (1<<INT2);
+				break;
+
+			case false: GICR &= ~(1<<INT2);
+				break;
+
+			default: GICR |= (1<<INT2);
+				break;
+		}
+	} //void enable_INT2(bool status)
+*/
+
+	//Sense control
+	void INT0_sense(uint8_t mode)
+	{
+		switch (mode)
+		{
+			case low_level:		MCUCR &= ~(1<<ISC01);
+								MCUCR &= ~(1<<ISC00);
+				break;
+
+			case logic_change:	MCUCR &= ~(1<<ISC01);
+								MCUCR |=  (1<<ISC00);
+				break;
+
+			case fallin_edge:	MCUCR |=  (1<<ISC01);
+								MCUCR &= ~(1<<ISC00);
+				break;
+
+			case rising_edge:	MCUCR |=  (1<<ISC01);
+								MCUCR |=  (1<<ISC00);
+				break;
+
+			default:			MCUCR &= ~(1<<ISC01);
+								MCUCR &= ~(1<<ISC00);
+				break;
+		}
+	} //void INT0_sense(uint8_t mode)
+
+	void INT1_sense(uint8_t mode)
+	{
+		switch (mode)
+		{
+			case low_level:		MCUCR &= ~(1<<ISC11);
+								MCUCR &= ~(1<<ISC10);
+				break;
+
+			case logic_change:	MCUCR &= ~(1<<ISC11);
+								MCUCR |=  (1<<ISC10);
+				break;
+
+			case fallin_edge:	MCUCR |=  (1<<ISC11);
+								MCUCR &= ~(1<<ISC10);
+				break;
+
+			case rising_edge:	MCUCR |=  (1<<ISC11);
+								MCUCR |=  (1<<ISC10);
+				break;
+
+			default:			MCUCR &= ~(1<<ISC11);
+								MCUCR &= ~(1<<ISC10);
+				break;
+		}
+	} //void INT1_sense(uint8_t mode)
+
+/*
+	void INT2_sense(uint8_t mode)
+	{
+		enable_INT2(false);
+		GIFR |= (1<<INTF2);
+
+		switch (mode)
+		{
+			case rising_edge: MCUCSR &= ~(1<<ISC2);
+				break;
+
+			case fallin_edge: MCUCSR |=  (1<<ISC2);
+				break;
+
+			default:		  MCUCSR &= ~(1<<ISC2);
+				break;
+		}
+
+		enable_INT2(true);
+	} //void INT2_sense(uint8_t mode)
+*/
+
+} //namespace extern_irq
diff --git a/SW/libs/src/external_interrupt/ext_irq_m8.h b/SW/libs/src/external_interrupt/ext_irq_m8.h
new file mode 100644
index 0000000000000000000000000000000000000000..79b138fd1eb4b5cc127abe40ea9854e7ac63d4d1
--- /dev/null
+++ b/SW/libs/src/external_interrupt/ext_irq_m8.h
@@ -0,0 +1,27 @@
+#pragma once
+
+#ifndef _EXTERNAL_INTERRUPT_H_
+# error "Include external_interrupt.h instead of this file"
+#endif
+
+#include <stdint.h>
+
+namespace extern_irq
+{
+	enum interupt_sense
+	{
+		low_level		  = 0,
+		logic_change	= 1,
+		fallin_edge		= 2,
+		rising_edge		= 3
+	};
+
+	extern void enable_INT0(void);
+	extern void enable_INT0(bool status);
+
+	extern void enable_INT1(void);
+	extern void enable_INT1(bool status);
+
+  extern void INT0_sense(uint8_t mode);
+	extern void INT1_sense(uint8_t mode);
+} //namespace extern_irq
diff --git a/SW/libs/src/fifo.h b/SW/libs/src/fifo.h
new file mode 100644
index 0000000000000000000000000000000000000000..1967ff0eede77263da2467df7586312597be547e
--- /dev/null
+++ b/SW/libs/src/fifo.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include <stdint.h>
+#include "cplusplus.h"
+
+template <typename A_type> class fifo
+{
+	private:
+		enum settings
+		{
+			QUEUE_LENGHT	= 20
+		};
+
+		//Pole a další
+		A_type queue[QUEUE_LENGHT];
+		uint16_t read_position;
+		uint16_t write_position;
+
+
+	public:
+
+		//Konstruktor, destruktor
+		fifo();
+		~fifo();
+
+		//Metody pro operace s polem dat
+		void add(A_type &data);
+
+		A_type read();
+		uint8_t check();
+};
+
+template <typename A_type> fifo<A_type>::fifo():read_position(0),write_position(0)
+{
+
+}
+
+template <typename A_type> fifo<A_type>::~fifo()
+{
+
+}
+
+template <typename A_type> void fifo<A_type>::add(A_type &data)
+{
+	queue[write_position++] = data;
+
+	if (write_position > QUEUE_LENGHT-1) write_position = 0;
+}
+
+template <typename A_type> A_type fifo<A_type>::read()
+{
+	A_type value = queue[read_position++];
+
+	if (read_position > QUEUE_LENGHT-1) read_position = 0;
+	return value;
+}
+
+template <typename A_type> uint8_t fifo<A_type>::check()
+{
+	if (write_position < read_position)	return (QUEUE_LENGHT + write_position - read_position);
+	else return (write_position - read_position);
+}
diff --git a/SW/libs/src/gpio.h b/SW/libs/src/gpio.h
new file mode 100644
index 0000000000000000000000000000000000000000..1b7d57c479abae6260943dd63b11c6f16f944bae
--- /dev/null
+++ b/SW/libs/src/gpio.h
@@ -0,0 +1,140 @@
+
+#pragma once
+
+#include <avr/io.h>
+
+class output
+{
+	private:
+		volatile uint8_t *ddr;
+		volatile uint8_t *port;
+				 uint8_t  bit;
+	
+	public:
+		output( volatile uint8_t *ddr,
+				volatile uint8_t *port,
+						 uint8_t  bit )
+		{
+			this->ddr = ddr;
+			this->port = port;
+			this->bit = bit;
+
+			*ddr |= (1<<bit);
+		};
+		
+		void on()
+        {
+            *port |= (1<<bit);
+        };
+
+		void off()
+        {
+            *port &= ~(1<<bit);
+        };
+
+		void toggle()
+        {
+            *port ^= (1<<bit);
+        };
+};
+
+class input
+{
+	private:
+		volatile uint8_t *ddr;
+		volatile uint8_t *port;
+		volatile uint8_t *pin;
+				 uint8_t  bit;
+	public:
+		input( volatile uint8_t *ddr,
+			   volatile uint8_t *port,
+			   volatile uint8_t *pin,
+						uint8_t  bit )
+        {
+            this->ddr = ddr;
+            this->port = port;
+            this->pin = pin;
+            this->bit = bit;
+
+            *ddr &= ~(1<<bit);
+        };
+
+		~input()
+        {
+            set_pull_up(false);
+        };
+	
+		void set_pull_up()
+        {
+            *port |= (1<<bit);
+        };
+
+		void set_pull_up(bool state)
+        {
+            if (state) *port |=  (1<<bit);
+            else	   *port &= ~(1<<bit);
+        };
+		
+		bool is_set()
+        {
+            return !(*pin & (1<<bit) );
+        }
+    ;
+};
+
+
+class io
+{
+	private:
+		volatile uint8_t *ddr;
+		volatile uint8_t *port;
+		volatile uint8_t *pin;
+				 uint8_t  bit;
+
+	public:
+		enum directions
+		{
+			INPUT,
+			OUTPUT
+		};
+
+	public:
+		io( volatile uint8_t *ddr,
+			volatile uint8_t *port,
+			volatile uint8_t *pin,
+					 uint8_t  bit )
+        {
+            this->ddr = ddr;
+            this->port = port;
+            this->pin = pin;
+            this->bit = bit;
+
+            *ddr &= ~(1<<bit);
+        };
+
+		void set_direction(directions direction)
+        {
+            if (direction == OUTPUT) (*ddr |= (1<<bit));
+            else *ddr &= ~(1<<bit);
+        };
+
+		void on()
+        {
+            *port |= (1<<bit);
+        };
+
+		void off()
+        {
+            *port &= ~(1<<bit);
+        };
+
+		void toggle()
+        {
+            *port ^= (1<<bit);
+        };
+
+		bool is_set()
+        {
+            return (*pin & (1<<bit) );
+        };
+};
diff --git a/SW/libs/src/jtag.cpp b/SW/libs/src/jtag.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..381f1c80fe2a07d826df584e9452df5a832a86e8
--- /dev/null
+++ b/SW/libs/src/jtag.cpp
@@ -0,0 +1,34 @@
+
+#include "jtag.h"
+
+#include <avr/io.h>
+#include <stdint.h>
+
+
+extern void jtag::disable_jtag(void)
+{
+#if defined(__AVR_ATmega1281__)
+	MCUSR = (1<<JTD);
+	MCUSR = (1<<JTD);
+#else
+	#ifndef __AVR_ATmega8__
+		MCUCSR = (1<<JTD);
+		MCUCSR = (1<<JTD);
+    #endif
+#endif
+}
+
+extern void jtag::enable_jtag(void)
+{
+#if defined(__AVR_ATmega1281__)
+    MCUSR = (1<<JTD);
+    MCUSR = (1<<JTD);
+#else
+    #ifndef __AVR_ATmega8__
+		MCUCSR = 0;
+		MCUCSR = 0;
+    #endif
+#endif
+}
+
+
diff --git a/SW/libs/src/jtag.h b/SW/libs/src/jtag.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f2ca2c81bcb6eca4ae1580542b46740adbfcc10
--- /dev/null
+++ b/SW/libs/src/jtag.h
@@ -0,0 +1,8 @@
+#pragma once
+
+
+namespace jtag
+{
+	extern void disable_jtag(void);
+	extern void enable_jtag(void);
+}
\ No newline at end of file
diff --git a/SW/libs/src/macros.h b/SW/libs/src/macros.h
new file mode 100644
index 0000000000000000000000000000000000000000..1c3841d08a53fe5882408166cd2b6b9d45bfb279
--- /dev/null
+++ b/SW/libs/src/macros.h
@@ -0,0 +1,10 @@
+//
+// Created by martin.vitek on 15.7.15.
+//
+
+#pragma once
+
+// Zmena bitu portu, IO registru nebo promenne:
+#define setb(bajt,bit)    bajt |= 1<<(bit)    //nastav bit
+#define clrb(bajt,bit)    bajt &= ~(1<<(bit)) //nuluj bit
+#define negb(bajt,bit)    bajt ^= 1<<(bit)    //neguj bit
diff --git a/SW/libs/src/sht11.cpp b/SW/libs/src/sht11.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..8a34afa0320b08de168caeb09dc749773064160a
--- /dev/null
+++ b/SW/libs/src/sht11.cpp
@@ -0,0 +1,244 @@
+#include "sht11.h"
+
+#include "wait.h"
+
+SHT11::SHT11(io *sda, io *sck)
+{
+	this->sda = sda;
+	this->sck = sck;
+
+	sck->set_direction(sck->OUTPUT);
+	sda->set_direction(sda->OUTPUT);
+
+	sda->on();
+	sck->on();
+}
+
+void SHT11::start_tx()
+{
+	sda->set_direction(sda->OUTPUT);
+	sda->on();
+	wait_us(20);
+
+	sck->off();
+	wait_us(1);
+
+	sck->on();
+	wait_us(1);
+
+	sda->off();
+	wait_us(1);
+
+	sck->off();
+	wait_us(1);
+
+	sck->on();
+	wait_us(1);
+
+	sda->on();
+	wait_us(1);
+
+	sck->off();
+	wait_us(1);
+}
+
+void SHT11::send_command(commands command)
+{
+	for (uint8_t i=0; i<8; i++)
+	{
+		if (command & (1<<(7-i))) sda->on();
+		else sda->off();
+		wait_us(1);
+
+		sck->on();
+		wait_us(1);
+
+		sck->off();
+		if (i == 7)	sda->on();
+		else sda->off();
+		wait_us(1);
+	}
+
+	sda->set_direction(sda->INPUT);
+	sda->off();
+	wait_us(1);
+
+	while (sda->is_set()) ;
+
+	sck->on();
+	wait_us(1);
+	sck->off();
+	wait_us(1);
+
+	//while (!sda->is_set()) ;
+}
+
+uint16_t SHT11::read_data()
+{
+	while (sda->is_set()) ;
+
+	uint16_t result(0);
+
+	for (uint8_t i=0; i<8; i++)
+	{
+		sck->on();
+		wait_us(1);
+		if (sda->is_set()) result |= (1<<(15-i));
+		sck->off();
+		wait_us(1);
+	}
+
+	sda->set_direction(sda->OUTPUT);
+	sda->off();
+	sck->on();
+	wait_us(1);
+
+	sck->off();
+	sda->set_direction(sda->INPUT);
+	wait_us(1);
+
+	for (uint8_t i=0; i<8; i++)
+	{
+		sck->on();
+		wait_us(1);
+		if (sda->is_set()) result |= (1<<(7-i));
+		sck->off();
+		wait_us(1);
+	}
+
+	return result;
+}
+
+void SHT11::stop_tx()
+{
+	sda->on();
+	sda->set_direction(sda->OUTPUT);
+	sda->on();
+	wait_us(1);
+
+	sck->on();
+	wait_us(1);
+	sck->off();
+	wait_us(1);
+}
+
+uint16_t SHT11::measure_temperature()
+{
+	start_tx();
+	send_command(TEMPERATURE);
+
+	uint16_t result = read_data();
+
+	stop_tx();
+
+	return result;
+}
+
+uint16_t SHT11::measure_humidity()
+{
+	start_tx();
+	send_command(HUMIDITY);
+
+	uint16_t result = read_data();
+
+	stop_tx();
+
+	return result;
+}
+
+void SHT11::initialize()
+{
+
+}
+
+void SHT11::communication_reset()
+{
+	sda->set_direction(sda->OUTPUT);
+	sda->on();
+
+	for (uint8_t i=0; i<10; i++)
+	{
+		sck->on();
+		wait_us(1);
+		sck->off();
+		wait_us(1);
+	}
+}
+
+[[deprecated]]
+void SHT11::reset()
+{
+	send_command(SOFT_RESET);
+}
+
+bool SHT11::check_communication()
+{
+	send_command(READ_STATUS_REG);
+
+	while (sda->is_set()) ;
+
+	uint8_t result(0);
+
+	for (uint8_t i=0; i<8; i++)
+	{
+		sck->on();
+		wait_us(1);
+		if (sda->is_set()) result |= (1<<(7-i));
+		sck->off();
+		wait_us(1);
+	}
+
+	stop_tx();
+
+	return (bool)result;
+}
+
+void SHT11::start_measuring_temperature()
+{
+	start_tx();
+	send_command(TEMPERATURE);
+	measuring_temp = true;
+}
+
+void SHT11::start_measuring_humidity()
+{
+	start_tx();
+	send_command(HUMIDITY);
+	measuring_humi = true;
+}
+
+void SHT11::handler()
+{
+	if (measuring_temp && sda->is_set())
+	{
+		measuring_temp = false;
+
+		temp_raw = read_data();
+		stop_tx();
+
+		temp_done = true;
+	}
+
+	if (measuring_humi && sda->is_set())
+	{
+		measuring_humi = false;
+		humi_raw = read_data();
+		stop_tx();
+
+		humi_done = true;
+	}
+}
+
+float SHT11::get_temperature()
+{
+	temperature = (-40.1+0.01*temp_raw);
+	return temperature;
+}
+
+float SHT11::get_humidity()
+{
+	float humi_linear = (-2.0468+0.0367*humi_raw+(-1.5955e-6)*humi_raw*humi_raw);
+	humidity = (temperature - 25.)*(0.01+0.00008*humi_raw)+humi_linear;
+
+	return humidity;
+}
diff --git a/SW/libs/src/sht11.h b/SW/libs/src/sht11.h
new file mode 100644
index 0000000000000000000000000000000000000000..ecaa0b5d501efaded4bbfc03afd2648f7f89d84b
--- /dev/null
+++ b/SW/libs/src/sht11.h
@@ -0,0 +1,64 @@
+
+#pragma once
+
+#include <stdint.h>
+
+#include "gpio.h"
+
+class SHT11
+{
+	public:
+	//Definice
+		enum commands
+		{
+			TEMPERATURE		 = 0x03,
+			HUMIDITY		 = 0x05,
+			READ_STATUS_REG  = 0x07,
+			WRITE_STATUS_REG = 0x06,
+			SOFT_RESET		 = 0x1E
+		};
+
+	public:
+	//Instance
+		io *sda;
+		io *sck;
+
+	//Measuring stuff
+		int16_t temp_raw;
+		int16_t humi_raw;
+		float temperature;
+		float humidity;
+		bool measuring_temp;
+		bool measuring_humi;
+		bool temp_done;
+		bool humi_done;
+
+
+	//Metody
+		void start_tx();
+		void send_command(commands command);
+		uint16_t read_data();
+		void stop_tx();
+
+	public:
+		SHT11(io *sda, io *sck);
+
+		void initialize();
+		bool check_communication();
+		void communication_reset();
+		void reset();
+
+		uint16_t measure_temperature();
+		uint16_t measure_humidity();
+
+		void start_measuring_temperature();
+		void start_measuring_humidity();
+
+		void handler();
+
+		float get_temperature();
+		float get_humidity();
+
+		uint8_t read_status_regster();
+		void write_status_register();
+};
diff --git a/SW/libs/src/spi.cpp b/SW/libs/src/spi.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..ac06c49fb9853d1f60d502ef944b03c171da11a6
--- /dev/null
+++ b/SW/libs/src/spi.cpp
@@ -0,0 +1,202 @@
+#include "spi.h"
+#include <avr/interrupt.h>
+
+
+//Konstruktory
+spi_class::spi_class()
+{
+} //spi_class()
+
+spi_class::spi_class(operating_modes operating_mode)
+{
+	set_operating_mode(operating_mode);
+} //spi_class(operating_modes mode)
+
+//Destruktor
+spi_class::~spi_class()
+{
+	disable_SPI();
+} //~spi_class()
+
+
+//////////////////////////////////////////////////////////////////////////
+/////////////////////////////Inicializace/////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void spi_class::enable_SPI()
+{
+	SPCR |= (1<<SPE);
+} //enable_SPI()
+
+void spi_class::enable_SPI(bool status)
+{
+	if (status) SPCR |= (1<<SPE);
+	else SPCR &= ~(1<<SPE);
+} //enable_SPI(bool status)
+
+void spi_class::disable_SPI()
+{
+	SPCR &= ~(1<<SPE);
+} //disable_SPI()
+
+void spi_class::set_operating_mode(operating_modes operating_mode)
+{
+	if (operating_mode == MASTER)
+	{
+		SPI_DDR  |=  (1<<MOSI_PIN) | (1<<SCK_PIN) | (1<<SS_PIN);
+		SPI_DDR  &= ~(1<<MISO_PIN);
+		SPI_PORT |=  (1<<SS_PIN);
+
+		SPCR |= (1 << MSTR);
+	}
+
+	else
+	{
+		SPI_DDR |=   (1<<MISO_PIN);
+		SPI_DDR &= ~((1<<MOSI_PIN) | (1<<SCK_PIN) | (1<<SS_PIN));
+
+		SPCR &= ~(1<<MSTR);
+	}
+} //void set_operating_mode(uint8_t mode)
+
+void spi_class::set_data_mode(data_modes data_mode)
+{
+	if (data_mode == DATA_MODE_0)
+	{
+		set_clock_polarity(RIS_FALL);
+		set_clock_phase(SAMPLE_SETUP);
+	}
+	
+	else if (data_mode == DATA_MODE_1)
+	{
+		set_clock_polarity(RIS_FALL);
+		set_clock_phase(SETUP_SAMPLE);
+	}
+	
+	else if (data_mode == DATA_MODE_2)
+	{
+		set_clock_polarity(FALL_RIS);
+		set_clock_phase(SAMPLE_SETUP);
+	}
+		
+	else if (data_mode == DATA_MODE_3)
+	{
+		set_clock_polarity(FALL_RIS);
+		set_clock_phase(SETUP_SAMPLE);
+	}
+			
+	else
+	{
+		set_clock_polarity(RIS_FALL);
+		set_clock_phase(SAMPLE_SETUP);
+	}
+} //void set_data_mode(data_modes mode)
+
+void spi_class::set_data_order(data_order order)
+{
+	if (order == LSB) SPCR |=  (1<<DORD);
+	else			  SPCR &= ~(1<<DORD);
+} //void set_data_order(data_order data_order)
+
+void spi_class::set_clock_polarity(clock_polarity polarity)
+{
+	if (polarity == FALL_RIS) SPCR |=  (1<<CPOL);
+	else 					  SPCR &= ~(1<<CPOL);
+} //void set_clock_polarity(clock_polarity polarity)
+
+void spi_class::set_clock_phase(clock_phase phase)
+{
+	if (phase == SETUP_SAMPLE) SPCR |=  (1<<CPHA);
+	else 					   SPCR &= ~(1<<CPHA);
+} //void set_clock_phase(clock_phase phase)
+
+void spi_class::set_clock_rate(clock_rates rate)
+{
+	SPCR &= ~((1<<SPR1) | (1<<SPR0));
+	SPSR &= ~(1<<SPI2X);
+
+	SPCR |= (rate & 0b00000011);
+	SPSR |= (rate & 0b00000100);
+} //void set_clock_rate(clock_rates rate)
+
+void spi_class::enable_interrupt()
+{
+	SPCR |= (1<<SPIE);
+} //void enable_interrupt()
+
+void spi_class::enable_interrupt(bool status)
+{
+	if (status) SPCR |=  (1<<SPIE);
+	else 		SPCR &= ~(1<<SPIE);
+} //void enable_interrupt(bool status)
+
+
+//////////////////////////////////////////////////////////////////////////
+////////////////////////////////Obsluha///////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void spi_class::select(bool state)
+{
+	if (state) SPI_PORT &= ~(1<<SS_PIN);
+	else	   SPI_PORT |=  (1<<SS_PIN);
+} //void select(bool state)
+
+
+void spi_class::write_data(uint8_t data)
+{
+	SPDR = data;
+	
+	while(!(SPSR & (1<<SPIF))) ;
+	
+	uint8_t dummy = SPDR;
+} //void write_data(uint8_t data)
+
+uint8_t spi_class::read_data()
+{
+	SPDR = 0xff;
+	
+	while(!(SPSR & (1<<SPIF))) ;
+	
+	return SPDR;
+} //uint8_t read_data()
+
+uint8_t spi_class::write_and_read_data(uint8_t data)
+{
+	SPDR = data;
+	
+	while(!(SPSR & (1<<SPIF))) ;
+	
+	return SPDR;
+} //uint8_t write_and_read_data(uint8_t data)
+
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+//Konstruktor
+spi_select_class::spi_select_class(volatile uint8_t *ddr, volatile uint8_t *port, uint8_t pin)
+{
+	this->ddr  = ddr;
+	this->port = port;
+	this->pin  = pin;
+	
+	*ddr  |= (1<< pin);
+	*port |= (1<< pin);
+}
+
+//Destruktor
+spi_select_class::~spi_select_class()
+{
+}
+
+void spi_select_class::select(bool status)
+{	
+	if (status) *port &= ~(1<< pin);
+	else 		*port |=  (1<< pin);
+} //void select(bool status)
+
+
+//(c) Martin Vitek 2015 (OK1KVK)
\ No newline at end of file
diff --git a/SW/libs/src/spi.h b/SW/libs/src/spi.h
new file mode 100644
index 0000000000000000000000000000000000000000..94338e46e6b5b3bf27a766c7cce565d4dbb6959c
--- /dev/null
+++ b/SW/libs/src/spi.h
@@ -0,0 +1,127 @@
+#pragma once
+
+#include <avr/io.h>
+#include <stdint.h>
+
+
+#if defined(__AVR_ATmega8__)
+	#define SPI_DDR		DDRB
+	#define SPI_PORT	PORTB
+	#define MOSI_PIN	PB3
+	#define MISO_PIN	PB4
+	#define SCK_PIN		PB5
+	#define SS_PIN		PB2
+
+#elif defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) || defined(__AVR_ATmega32A__)
+	#define SPI_DDR		DDRB
+	#define SPI_PORT	PORTB
+	#define MOSI_PIN	PB5
+	#define MISO_PIN	PB6
+	#define SCK_PIN		PB7
+	#define SS_PIN		PB4
+
+#elif defined(__AVR_ATmega128__) || (__AVR_ATmega1281__)
+	#define SPI_DDR    	DDRB
+	#define SPI_PORT	PORTB
+	#define MOSI_PIN	PB2
+	#define MISO_PIN	PB3
+	#define SCK_PIN		PB1
+	#define SS_PIN		PB0
+
+#else
+	#error "This lib don't support this device"
+#endif
+
+
+class spi_class
+{
+	//Definice
+	public:
+		enum operating_modes
+		{
+			MASTER,
+			SLAVE
+		};
+		
+		enum data_modes
+		{
+			DATA_MODE_0	= 0,
+			DATA_MODE_1	= 1,
+			DATA_MODE_2	= 2,
+			DATA_MODE_3	= 3
+		};
+		
+		enum data_order
+		{
+			MSB	= 1,
+			LSB	= 0
+		};
+		
+		enum clock_polarity	
+		{
+			RIS_FALL = 0,
+			FALL_RIS = 1
+		};
+		
+		enum clock_phase
+		{
+			SAMPLE_SETUP = 0,
+			SETUP_SAMPLE = 1
+		};
+		
+		enum clock_rates
+		{
+			F_OSC_2		= 4,
+			F_OSC_4		= 0,
+			F_OSC_8		= 5,
+			F_OSC_16	= 1,
+			F_OSC_32	= 6,
+			F_OSC_64	= 2,
+			F_OSC_64_2  = 7,
+			F_OSC_128	= 3
+		};	
+
+	//Metody
+	public:
+		//Konstruktory, destruktor
+		spi_class();
+		spi_class(operating_modes mode);
+		~spi_class();
+		
+		//Inicializace
+		void enable_SPI();
+		void enable_SPI(bool status);
+		void disable_SPI();
+		void set_operating_mode(operating_modes operating_mode);
+		void set_data_mode(data_modes data_mode);
+		void set_data_order(data_order order);
+		void set_clock_polarity(clock_polarity polarity);
+		void set_clock_phase(clock_phase phase);
+		void set_clock_rate(clock_rates rate);
+		void enable_interrupt();
+		void enable_interrupt(bool status);
+		
+		//Obsluha
+		void select(bool state);
+		
+		void 	write_data(uint8_t data);
+		uint8_t read_data();
+		uint8_t write_and_read_data(uint8_t data);
+}; //spi_class
+
+class spi_select_class
+{	
+	private:
+		volatile uint8_t *ddr;
+		volatile uint8_t *port;
+				 uint8_t  pin;
+	
+	public:
+		spi_select_class(volatile uint8_t *ddr, volatile uint8_t *port, uint8_t pin);
+		~spi_select_class();
+		
+		void select(bool status);
+}; //spi_select_class
+
+
+//(c) Martin VĂ­tek 2015 (OK1KVK)
\ No newline at end of file
diff --git a/SW/libs/src/usart.cpp b/SW/libs/src/usart.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3f16948296c581fbcc1ba173935fb77098e2e55f
--- /dev/null
+++ b/SW/libs/src/usart.cpp
@@ -0,0 +1,346 @@
+
+#include "usart.h"
+
+#include <avr/io.h>
+#include <stdint.h>
+
+//////////////////////////////////////////////////////////////////////////
+////////////////////////Konstruktor, destruktor///////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+usart::usart(usart_regs &regs): reg(regs)
+{
+	flush_UDR_buffer();
+}
+
+usart::~usart()
+{
+	flush_UDR_buffer();
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+/////////////////////////////Inicializace/////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+void usart::set_operating_mode(operation_modes mode)
+{
+	//Nastaveni modu komunikace
+	this->mode = mode;
+
+	uint8_t mask = *reg.UCSRC_reg;
+	mask = *reg.UCSRC_reg;
+	mask &= ~(1<<UMSEL);
+	mask |=  (1<<URSEL);
+	*reg.UCSRC_reg = mask;
+
+
+	if (mode == ASYNCHRONOUS_NORMAL) *reg.UCSRA_reg &= ~(1<<U2X);
+
+	else if (mode == ASYNCHRONOUS_DOUBLE) *reg.UCSRA_reg |= (1<<U2X);
+
+	else if (mode == SYNCHRONOUS)
+	{
+		*reg.UCSRC_reg |= (1<<URSEL) | (1<<UMSEL);
+		*reg.UCSRA_reg &= ~(1<<U2X);
+	}
+
+	else return;
+}
+
+void usart::set_baudrate(uint32_t baudrate)
+{
+	uint16_t baud_value = ((F_CPU/(mode*baudrate))-1);
+
+	*reg.UBRRH_reg = (uint8_t)(baud_value>>8);
+	*reg.UBRRL_reg = (uint8_t) baud_value;
+}
+
+void usart::set_data_bits(uint8_t bits)
+{
+	uint8_t mask = *reg.UCSRC_reg;
+	mask = *reg.UCSRC_reg;
+	mask &= ~((1<<UCSZ1) | (1<<UCSZ0));
+	mask |=  (1<<URSEL);
+	*reg.UCSRC_reg = mask;
+	*reg.UCSRB_reg &= ~(1<<UCSZ2);
+
+	switch (bits)
+	{
+		case 5:
+			break;
+
+		case 6:	*reg.UCSRC_reg |= (1<<URSEL) | (1<<UCSZ0);
+			break;
+
+		case 7:	*reg.UCSRC_reg |= (1<<URSEL) | (1<<UCSZ1);
+			break;
+
+		case 8:
+				*reg.UCSRC_reg |= (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
+			break;
+
+		case 9:	*reg.UCSRB_reg |= (1<<UCSZ2);
+				*reg.UCSRC_reg |= (1<<URSEL) | (1<<UCSZ1) | (1<<UCSZ0);
+			break;
+
+		default:
+			break;
+	}
+}
+
+void usart::set_stop_bits(uint8_t bits)
+{
+	switch (bits)
+	{
+		case 1:	*reg.UCSRC_reg&= ~(1<<USBS) | (1<<URSEL);
+			break;
+
+		case 2:	*reg.UCSRC_reg|= (1<<USBS) | (1<<URSEL);
+			break;
+
+		default: *reg.UCSRC_reg&= ~(1<<USBS) | (1<<URSEL);
+			break;
+	}
+}
+
+void usart::set_parity(parity_modes parity)
+{
+	switch (parity)
+	{
+		case PARITY_NONE: *reg.UCSRC_reg &= (1<<URSEL) | ~(1<<UPM1) | ~(1<<UPM0);
+			break;
+
+		case PARITY_EVEN: *reg.UCSRC_reg |= (1<<URSEL) |  (1<<UPM1) | ~(1<<UPM0);
+			break;
+
+		case PARITY_ODD: *reg.UCSRC_reg &= (1<<URSEL) | ~(1<<UPM1) |  (1<<UPM0);
+			break;
+	}
+}
+
+void usart::enable_reciver()
+{
+	*reg.UCSRB_reg |= (1<<RXEN);
+}
+
+void usart::enable_reciver(bool status)
+{
+	if (status) *reg.UCSRB_reg |=  (1<<RXEN);
+	else 		*reg.UCSRB_reg &= ~(1<<RXEN);
+}
+
+void usart::enable_trasmitter()
+{
+	*reg.UCSRB_reg |= (1<<TXEN);
+}
+
+void usart::enable_trasmitter(bool status)
+{
+	if (status) *reg.UCSRB_reg |=  (1<<TXEN);
+	else 		*reg.UCSRB_reg &= ~(1<<TXEN);
+}
+
+void usart::enable_UDRE_interrupt()
+{
+	*reg.UCSRB_reg |= (1<<UDRIE);
+}
+
+void usart::enable_UDRE_interrupt(bool status)
+{
+	if (status) *reg.UCSRB_reg |=  (1<<UDRIE);
+	else 		*reg.UCSRB_reg &= ~(1<<UDRIE);
+}
+
+void usart::enable_TX_complete_interrupt()
+{
+	*reg.UCSRB_reg |= (1<<TXCIE);
+}
+
+void usart::enable_TX_complete_interrupt(bool status)
+{
+	if (status) *reg.UCSRB_reg |=  (1<<TXCIE);
+	else 		*reg.UCSRB_reg &= ~(1<<TXCIE);
+}
+
+void usart::enable_RX_complete_interrupt()
+{
+	*reg.UCSRB_reg |= (1<<RXCIE);
+}
+
+void usart::enable_RX_complete_interrupt(bool status)
+{
+	if (status) *reg.UCSRB_reg |=  (1<<RXCIE);
+	else 		*reg.UCSRB_reg &= ~(1<<RXCIE);
+}
+
+void usart::enable_MPCM()
+{
+	*reg.UCSRA_reg |= (1<<MPCM);
+}
+
+void usart::enable_MPCM(bool status)
+{
+	if (status) *reg.UCSRA_reg |=  (1<<MPCM);
+	else 		*reg.UCSRA_reg &= ~(1<<MPCM);
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////////////////Funkce//////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////Transmit/////////////////////////////////////
+void usart::transmit_char(uint8_t data)
+{
+	while(!(*reg.UCSRA_reg & (1<<UDRE))) ;;
+
+	*reg.UDR_reg = data;
+}
+
+void usart::transmit_string(const char *data)
+{
+	while (*data) transmit_char(*(data++));
+}
+
+void usart::transmit_data(const char *data, uint8_t size)
+{
+	uint8_t count = 0;
+	while(count < size)
+	{
+		transmit_char(*(data++));
+		count++;
+	}
+}
+
+void usart::transmit_dec32(long data)
+{
+	unsigned long n;
+	char ignoruj;
+
+	if(data<0){
+		data=-data;
+		transmit_char('-');
+	}
+
+	ignoruj=1;
+	for(n=1000000000; n>0; n/=10){
+		if(data/n){
+			transmit_char('0'+data/n);
+			ignoruj=0;
+			data%=n;
+			}else if(!ignoruj){
+			transmit_char('0');
+		}
+	}
+	if(ignoruj) transmit_char('0');
+}
+
+void usart::transmit_hex8(uint8_t data)
+{
+	if(data<0xA0) transmit_char((data>>4)+'0');
+	else transmit_char((data>>4)+'A'-10);
+
+	if((data&0x0f)<0x0A) transmit_char((data&0x0f)+'0');
+	else transmit_char((data&0x0f)+'A'-10);
+}
+
+void usart::transmit_hex16(uint16_t data)
+{
+	transmit_hex8(data>>8);
+	transmit_hex8(data&0xff);
+}
+
+void usart::transmit_hex32(uint32_t data)
+{
+	transmit_hex8(data>>24);
+	transmit_hex8(data>>16);
+	transmit_hex8(data>>8);
+	transmit_hex8(data&0xff);
+}
+
+void usart::transmit_new_line()
+{
+	transmit_string("\n\r");
+} //void transmit_new_line()
+
+void usart::transmit_space()
+{
+	transmit_char(' ');
+} //void transmit_space()
+
+void usart::transmit_binary8(uint8_t data)
+{
+	for(signed char i = 7; i > -1; i--)
+	{
+		transmit_dec32((data&(1<<i))>>i);
+	}
+} //void transmit_binary8(uint8_t data)
+
+void usart::transmit_binary16(uint16_t data)
+{
+	for(signed char i = 15; i > -1; i--)
+	{
+		transmit_dec32((data&(1<<i))>>i);
+	}
+} //void transmit_binary16(uint16_t data)
+
+void usart::transmit_binary32(uint32_t data)
+{
+	for(signed char i = 31; i > -1; i--)
+	{
+		transmit_dec32((data&(1<<i))>>i);
+	}
+} //void transmit_binary32(uint32_t data)
+
+/////////////////////////////Receive//////////////////////////////////////
+uint8_t usart::receive_char()
+{
+	while(!(*reg.UCSRA_reg & (1<<RXC))) ;;
+
+	return *reg.UDR_reg;
+}
+
+
+////////////////////////////Obsluha///////////////////////////////////////
+bool usart::check_frame_error()
+{
+	return (bool)(*reg.UCSRA_reg&(1<<FE));
+}
+
+bool usart::check_data_over_run()
+{
+	return (bool)(*reg.UCSRA_reg&(1<<DOR));
+}
+
+bool usart::check_parity_error()
+{
+	return (bool)(*reg.UCSRA_reg&(1<<UPE));
+}
+
+
+bool usart::check_usart_recive_complete()
+{
+	return (bool)(*reg.UCSRA_reg&(1<<RXC));
+}
+
+bool usart::check_usart_transmit_complete()
+{
+	return (bool)(*reg.UCSRA_reg&(1<<TXC));
+}
+
+bool usart::check_usart_data_register_empty()
+{
+	return (bool)(*reg.UCSRA_reg&(1<<UDRE));
+}
+
+
+void usart::flush_UDR_buffer()
+{
+	unsigned char dummy1, dummy2;
+	while( *reg.UCSRA_reg & (1<<RXC) ) dummy1 = *reg.UDR_reg;
+	dummy2 = dummy1;
+	dummy1 = dummy2;
+}
+
+//(c) Martin Vitek 2015 (OK1KVK)
diff --git a/SW/libs/src/usart.h b/SW/libs/src/usart.h
new file mode 100644
index 0000000000000000000000000000000000000000..666ec7b45c328018cd92dbf31248bd8e37b0ae41
--- /dev/null
+++ b/SW/libs/src/usart.h
@@ -0,0 +1,206 @@
+#pragma once
+
+#include <avr/io.h>
+#include <stdint.h>
+
+#ifndef UPE
+    #if defined(PE)
+	    #define UPE PE
+    #elif defined(UPE0)
+        #define UPE UPE0
+    #else
+        #warning "Can't define UPE"
+    #endif
+#endif
+
+#ifndef URSEL
+	#define URSEL 7
+#endif
+
+#ifndef UMSEL
+    #define UMSEL UMSEL00
+#endif
+
+#ifndef U2X
+    #define U2X U2X0
+#endif
+
+#ifndef UCSZ0
+    #define UCSZ0 UCSZ00
+#endif
+
+#ifndef UCSZ1
+    #define UCSZ1 UCSZ01
+#endif
+
+#ifndef UCSZ2
+    #define UCSZ2 UCSZ02
+#endif
+
+#ifndef USBS
+    #define USBS USBS0
+#endif
+
+#ifndef UPM0
+    #define UPM0 UPM00
+#endif
+
+#ifndef UPM1
+    #define UPM1 UPM01
+#endif
+
+#ifndef RXEN
+    #define RXEN RXEN0
+#endif
+
+#ifndef TXEN
+    #define TXEN TXEN0
+#endif
+
+#ifndef UDRIE
+    #define UDRIE UDRIE0
+#endif
+
+#ifndef TXCIE
+    #define TXCIE TXCIE0
+#endif
+
+#ifndef RXCIE
+    #define RXCIE RXCIE0
+#endif
+
+#ifndef MPCM
+    #define MPCM MPCM0
+#endif
+
+#ifndef UDRE
+    #define UDRE UDRE0
+#endif
+
+#ifndef FE
+    #define FE FE0
+#endif
+
+#ifndef DOR
+    #define DOR DOR0
+#endif
+
+#ifndef DOR
+    #define DOR DOR0
+#endif
+
+#ifndef RXC
+    #define RXC RXC0
+#endif
+
+#ifndef TXC
+    #define TXC TXC0
+#endif
+
+#ifndef RXEN
+    #define RXEN RXEN0
+#endif
+
+#ifndef URSEL
+	#define URSEL 7
+#endif
+
+struct usart_regs
+{
+	volatile uint8_t *UCSRA_reg;
+	volatile uint8_t *UCSRB_reg;
+	volatile uint8_t *UCSRC_reg;
+	volatile uint8_t *UDR_reg;
+	volatile uint8_t *UBRRL_reg;
+	volatile uint8_t *UBRRH_reg;
+};
+
+class usart
+{
+	public:
+		enum operation_modes
+		{
+			ASYNCHRONOUS_NORMAL = 16,
+			ASYNCHRONOUS_DOUBLE = 8,
+			SYNCHRONOUS			= 2
+		};
+
+		enum parity_modes
+		{
+			PARITY_NONE = 0,
+			PARITY_EVEN = 2,
+			PARITY_ODD  = 3
+		};
+
+	private:
+		usart_regs reg;
+		operation_modes mode;
+
+	public:
+		//Konstruktor, destruktor
+		usart(usart_regs &regs);
+		~usart();
+
+
+	//USART Init
+	void set_operating_mode(operation_modes mode);
+	void set_baudrate(uint32_t baudrate);
+	void set_data_bits(uint8_t bits);
+	void set_stop_bits(uint8_t bits);
+	void set_parity(parity_modes parity);
+	void enable_reciver();
+	void enable_reciver(bool status);
+	void enable_trasmitter();
+	void enable_trasmitter(bool status);
+	void enable_UDRE_interrupt();	//Data Register Empty
+	void enable_UDRE_interrupt(bool status);
+	void enable_TX_complete_interrupt();
+	void enable_TX_complete_interrupt(bool status);
+	void enable_RX_complete_interrupt();
+	void enable_RX_complete_interrupt(bool status);
+	void enable_MPCM();				//Multi Processor Communication Mode
+	void enable_MPCM(bool status);	//Datasheet page 145
+
+	//USART functions
+	void transmit_char(uint8_t data);
+	void transmit_string(const char *data);
+	void transmit_data(const char *data, uint8_t size);
+	void transmit_dec32(long data);		//Funkce pro odeslani 32bit desitkoveho cisla
+	void transmit_hex8(uint8_t data);	//Funkce pro odeslani 1 bajtoveho Hexu
+	void transmit_hex16(uint16_t data);	//Funkce pro odeslani 2 bajtoveho Hexu
+	void transmit_hex32(uint32_t data);	//Funkce pro odeslani 4 bajtoveho Hexu
+	void transmit_binary8(uint8_t data);
+	void transmit_binary16(uint16_t data);
+	void transmit_binary32(uint32_t data);
+
+	void transmit_new_line();		//Odesle \n\r
+	void transmit_space();			//Odesle mezeru
+
+
+
+	uint8_t receive_char();
+
+	bool check_frame_error();		//Dataseet page 149
+	bool check_data_over_run();		//Dataseet page 149
+	bool check_parity_error();		//Dataseet page 149
+
+	bool check_usart_recive_complete();
+	bool check_usart_transmit_complete();
+	bool check_usart_data_register_empty();
+
+	void flush_UDR_buffer();
+};
+
+
+//////////////////////////////////////////////////////////////////////////
+//////////////////Vektory preruseni RX, TX, UDRE//////////////////////////
+//////////////////////////////////////////////////////////////////////////
+
+/*
+ISR(USART_RXC_vect){};
+ISR(USART_TXC_vect){};
+ISR(USART_UDRE_vect){};
+*/
+
+
+//(c) Martin Vitek 2015 (OK1KVK)
diff --git a/SW/libs/src/wait.cpp b/SW/libs/src/wait.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..58a6fb29c4963d1c0048d1c50460fd62af705a33
--- /dev/null
+++ b/SW/libs/src/wait.cpp
@@ -0,0 +1,60 @@
+/*---------------------------------------------------------------------------
+
+soubor: wait.c
+verze:  1.0
+datum:  9.1.2012
+popis:
+
+Cekaci rutiny jsou mnohem uspornejsi nez bezne "delay.h"
+
+Tento soubor vynikl ze souboru "mojelib.h" jehoz autora bohuzel neznam.
+
+---------------------------------------------------------------------------*/
+#include "wait.h"
+
+
+//cekej milisekund:
+unsigned char reg21 = F_CPU / 60000;    // F_CPU = frekv. oscilatoru [Hz],
+                                        // (vnitrni konstanta prekladace)
+void wait_ms  (unsigned int c)
+{
+	asm("push	r20");
+	asm("push	r21");
+	asm("_Wms0:");
+	asm("ldi	r20,0x14");
+	asm("_Wms1:");
+	asm("lds	r21,reg21");
+	asm("_Wms2:");
+	asm("dec	r21");
+	asm("brne	_Wms2");
+	asm("dec		r20");
+	asm("brne	_Wms1");
+	asm("dec	r24");
+	asm("brne	_Wms0");
+	asm("dec	r25");
+	asm("brpl	_Wms0");
+	asm("pop   	r21");
+	asm("pop   	r20");
+}
+
+
+//cekej mikrosekund:
+unsigned char reg20 = F_CPU / 6000000 + 1;
+void wait_us(unsigned int c)
+{
+	asm("push	r20");
+	asm("_wus0:");
+	asm("lds	r20,reg20");  // 1-6MHz: r20=1  6-12MHz: r20=2
+	asm("_wus1:");
+	asm("dec	r20");
+	asm("brne	_wus1");
+	asm("dec	r24");
+	asm("brne	_wus0");
+	asm("dec	r25");
+	asm("brpl	_wus0");
+	asm("pop	r20");
+}
+
+//eof
+//(c) OK1ZKV 2012 & Martin VĂ­tek 2015
+
diff --git a/SW/libs/src/wait.h b/SW/libs/src/wait.h
new file mode 100644
index 0000000000000000000000000000000000000000..dcff471b104c0f5131eef5f8acd471cb56d0939e
--- /dev/null
+++ b/SW/libs/src/wait.h
@@ -0,0 +1,21 @@
+/*
+ * wait.h
+ *
+ * Created: 26.3.2013 19:38:53
+ *  Author: VK
+ */
+#pragma once
+
+#ifndef WAIT_H_
+#define WAIT_H_
+
+#ifndef F_CPU
+    #error "F_CPU not defined"
+#endif
+
+// Casove smycky:
+void wait_ms  (unsigned int c);        // cekej milisekund(max65553):
+void wait_us  (unsigned int c);        // cekej mikrosekund(max65553):
+
+
+#endif /* WAIT_H_ */
\ No newline at end of file