changeset 16:7c312f2f6291

Update the code to work on current robot
author Radomir Dopieralski <sheep-devel@sheep.art.pl>
date Thu, 11 Jun 2015 13:46:30 +0200
parents 61de3195b19d
children 3265a2f99027
files katka/IRLremote.cpp katka/IRLremote.h katka/creep.ino katka/ir.ino katka/katka.ino katka/servos.ino
diffstat 6 files changed, 866 insertions(+), 23 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/katka/IRLremote.cpp	Thu Jun 11 13:46:30 2015 +0200
@@ -0,0 +1,50 @@
+/*
+Copyright (c) 2014 NicoHood
+See the readme for credit to other people.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#include "IRLremote.h"
+
+//================================================================================
+// User function helper
+//================================================================================
+
+// ensure available() returns false
+uint8_t  IRLProtocol = 0;
+uint16_t IRLAddress = 0;
+uint32_t IRLCommand = 0;
+
+// Called when directly received correct IR Signal
+// Do not use Serial inside, it can crash your Arduino!
+void IREvent(uint8_t protocol, uint16_t address, uint32_t command) {
+	// For no user function set we need to pause IR
+	// to not overwrite the actual values until they are read.
+	if (IRLProtocol) return;
+	IRLAddress = address;
+	IRLCommand = command;
+	IRLProtocol = protocol;
+}
+
+void decodeIR(const uint16_t duration){
+	// add your own protocols here or create your own decoding function
+	// you can overwrite this function in your .ino file
+	decodeAll(duration);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/katka/IRLremote.h	Thu Jun 11 13:46:30 2015 +0200
@@ -0,0 +1,778 @@
+/*
+Copyright (c) 2014 NicoHood
+See the readme for credit to other people.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+*/
+
+#ifndef IRLREMOTE_H
+#define IRLREMOTE_H
+
+#include <Arduino.h>
+
+//missing 1.0.6 definition workaround
+#if ARDUINO == 106
+#define NOT_AN_INTERRUPT -1
+#endif
+
+// board type detection
+#if defined(__MK20DX128__) || defined(__MK20DX256__)
+#define  IRLREMOTE_ARM
+#define  IRLREMOTE_TEENSY3
+#elif defined(__SAM3X8E__)
+#define  IRLREMOTE_ARM
+#define  IRLREMOTE_DUE
+#else  
+// default to assuming everything else is avr for now
+#define  IRLREMOTE_AVR
+#endif
+
+// delay_basic is only for avrs. with ARM sending is currently not possible
+#ifdef IRLREMOTE_AVR
+#include <util/delay_basic.h>
+#endif
+
+//================================================================================
+// Definitions
+//================================================================================
+
+//NEC
+//IRP notation: {38.4k,564}<1,-1|1,-3>(16,-8,D:8,S:8,F:8,~F:8,1,-78,(16,-4,1,-173)*)
+// Lead + Space logic
+#define NEC_HZ 38400
+#define NEC_PULSE 564UL
+#define NEC_BLOCKS 4
+#define NEC_ADDRESS_LENGTH 16
+#define NEC_COMMAND_LENGTH 16
+#define NEC_LENGTH 2 + NEC_BLOCKS*8*2 // 2 for lead + space, each block has 8bits: mark and space
+#define NEC_TIMEOUT NEC_PULSE*173
+#define NEC_MARK_LEAD NEC_PULSE*16
+#define NEC_SPACE_LEAD NEC_PULSE*8
+#define NEC_SPACE_HOLDING NEC_PULSE*4
+#define NEC_MARK_ZERO NEC_PULSE*1
+#define NEC_MARK_ONE NEC_PULSE*1
+#define NEC_SPACE_ZERO NEC_PULSE*1
+#define NEC_SPACE_ONE NEC_PULSE*3
+
+//PANASONIC
+//IRP notation: {37k,432}<1,-1|1,-3>(8,-4,3:8,1:8,D:8,S:8,F:8,(D^S^F):8,1,-173)+
+// Lead + Space logic
+#define PANASONIC_HZ 37000
+#define PANASONIC_PULSE 432UL
+#define PANASONIC_BLOCKS 6
+#define PANASONIC_ADDRESS_LENGTH 16
+#define PANASONIC_COMMAND_LENGTH 32
+#define PANASONIC_LENGTH 2 + PANASONIC_BLOCKS*8*2 // 2 for lead + space, each block has 8bits: mark and space
+#define PANASONIC_TIMEOUT PANASONIC_PULSE*173
+#define PANASONIC_MARK_LEAD PANASONIC_PULSE*8
+#define PANASONIC_SPACE_LEAD PANASONIC_PULSE*4
+#define PANASONIC_SPACE_HOLDING 0 // no holding function in this protocol
+#define PANASONIC_MARK_ZERO PANASONIC_PULSE*1
+#define PANASONIC_MARK_ONE PANASONIC_PULSE*1
+#define PANASONIC_SPACE_ZERO PANASONIC_PULSE*1
+#define PANASONIC_SPACE_ONE PANASONIC_PULSE*3
+
+/*
+Panasonic pulse demonstration:
+
+*---------|                        |------------|   |---------|   |---|   ... -|   |---------
+*         |                        |            |   |         |   |   |   ...  |   |
+*         |                        |            |   |         |   |   |   ...  |   |
+*         |------------------------|            |---|         |---|   |-  ...  |---|
+*         |       Lead Mark        | Lead Space |  Logical 1  | Log 0 |  Data  |End|
+
+*/
+
+//SONY 8, 12, 15, 20
+//IRP notation: {40k,600}<1,-1|2,-1>(4,-1,F:8,^22200)
+//IRP notation: {40k,600}<1,-1|2,-1>(4,-1,F:7,D:5,^45m)+ 
+//IRP notation: {40k,600}<1,-1|2,-1>(4,-1,F:7,D:8,^45m)+ 
+//IRP notation: {40k,600}<1,-1|2,-1>(4,-1,F:7,D:5,S:8,^45m) +
+// Lead + Mark logic
+#define SONY_HZ 40000
+#define SONY_PULSE 600UL
+#define SONY_BLOCKS_8 1
+#define SONY_BLOCKS_12 2
+#define SONY_BLOCKS_15 2
+#define SONY_BLOCKS_20 3
+#define SONY_ADDRESS_LENGTH_8 0
+#define SONY_ADDRESS_LENGTH_12 5
+#define SONY_ADDRESS_LENGTH_15 8
+#define SONY_ADDRESS_LENGTH_20 13
+#define SONY_COMMAND_LENGTH_8 8
+#define SONY_COMMAND_LENGTH_12 7
+#define SONY_COMMAND_LENGTH_15 7
+#define SONY_COMMAND_LENGTH_20 7
+#define SONY_LENGTH_8 2 + (8-1)*2 // 2 for lead + space, -1 for mark end, 8 bit
+#define SONY_LENGTH_12 2 + (7+5-1)*2 // 2 for lead + space, -1 for mark end, 12 bit
+#define SONY_LENGTH_15 2 + (7+8-1)*2 // 2 for lead + space, -1 for mark end, 15 bit
+#define SONY_LENGTH_20 2 + (7+5+8-1)*2 // 2 for lead + space, -1 for mark end, 20 bit
+#define SONY_TIMEOUT_8 22200
+#define SONY_TIMEOUT 45000 // 12, 15, 20 have the same timeout
+#define SONY_MARK_LEAD SONY_PULSE*4
+#define SONY_SPACE_LEAD SONY_PULSE*1
+#define SONY_SPACE_HOLDING 0 // no holding function in this protocol
+#define SONY_MARK_ZERO SONY_PULSE*1
+#define SONY_MARK_ONE SONY_PULSE*2
+#define SONY_SPACE_ZERO SONY_PULSE*1
+#define SONY_SPACE_ONE SONY_PULSE*1
+
+typedef enum IRType{
+	IR_NO_PROTOCOL, // 0
+	IR_USER, // 1
+	IR_ALL, // 2
+	IR_NEC, // ...
+	IR_PANASONIC,
+	IR_SONY8,
+	IR_SONY12,
+	IR_SONY15,
+	IR_SONY20,
+	// add new protocols here
+	IR_RAW,
+};
+
+// definitions to use decoding functions with extra accuracy
+#define IR_EXTRA_ACCURACY true
+#define IR_NO_EXTRA_ACCURACY false
+
+// definition for sending to determine what should be send first
+#define IR_ADDRESS_FIRST true
+#define IR_COMMAND_FIRST false
+
+// definition to convert an uint8_t array to an uint16_t/uint32_t at any position (thx timeage!)
+#define UINT16_AT_OFFSET(p_to_8, offset)    ((uint16_t)*((const uint16_t *)((p_to_8)+(offset))))
+#define UINT32_AT_OFFSET(p_to_8, offset)    ((uint32_t)*((const uint32_t *)((p_to_8)+(offset))))
+
+// definition to get the higher value
+#define MAX(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a > _b ? _a : _b; })
+
+// definition to get the lower value
+#define MIN(a,b) \
+   ({ __typeof__ (a) _a = (a); \
+       __typeof__ (b) _b = (b); \
+     _a < _b ? _a : _b; })
+
+//================================================================================
+// Prototypes
+//================================================================================
+
+// attach the interrupt function
+template <IRType irType>
+inline void IRLbegin(const uint8_t interrupt) __attribute__((always_inline));
+
+// dettach the interrupt function
+inline void IRLend(const uint8_t interrupt) __attribute__((always_inline));
+
+// variables for IR processing if no user function was set
+extern uint8_t  IRLProtocol;
+extern uint16_t IRLAddress;
+extern uint32_t IRLCommand;
+
+// functions to use if no user function was set
+inline bool IRLavailable(void) __attribute__((always_inline));
+inline void IRLreset(void) __attribute__((always_inline));
+inline uint8_t IRLgetProtocol(void) __attribute__((always_inline));
+inline uint16_t IRLgetAddress(void) __attribute__((always_inline));
+inline uint32_t IRLgetCommand(void) __attribute__((always_inline));
+
+// function called on a valid IR event, must be overwritten by the user
+void __attribute__((weak)) IREvent(uint8_t protocol, uint16_t address, uint32_t command);
+
+// optinal user function called when the user wants to implement its own decoding function
+void __attribute__((weak)) decodeIR(const uint16_t duration);
+
+// called by interrupt CHANGE
+template <IRType irType>
+inline void IRLinterrupt(void) __attribute__((always_inline));
+
+// special decode function for each protocol
+inline void decodeAll(const uint16_t duration) __attribute__((always_inline));
+template <bool extraAccuracy> inline void decodeNec(const uint16_t duration);
+template <bool extraAccuracy> inline void decodePanasonic(const uint16_t duration) __attribute__((always_inline));
+template <bool extraAccuracy> inline void decodeSony8(const uint16_t duration);
+template <bool extraAccuracy> inline void decodeSony12(const uint16_t duration);
+template <bool extraAccuracy> inline void decodeSony15(const uint16_t duration);
+template <bool extraAccuracy> inline void decodeSony20(const uint16_t duration);
+inline void decodeRaw(const uint16_t duration) __attribute__((always_inline));
+
+// functions to check if the received data is valid with the protocol checksums
+inline bool IRLcheckInverse0(uint8_t data[]) __attribute__((always_inline));
+inline bool IRLcheckInverse1(uint8_t data[]) __attribute__((always_inline));
+inline bool IRLcheckHolding(uint8_t data[]) __attribute__((always_inline));
+inline bool IRLcheckXOR0(uint8_t data[]) __attribute__((always_inline));
+
+// default decoder helper function
+template <uint8_t irLength, uint16_t timeoutThreshold, uint16_t markLeadThreshold, uint16_t spaceLeadThreshold,
+	uint16_t spaceLeadHoldingThreshold, uint16_t markThreshold, uint16_t spaceThreshold,
+	uint16_t markTimeout, uint16_t spaceTimeout>
+	inline bool IRLdecode(uint16_t duration, uint8_t data[]) __attribute__((always_inline));
+
+// functions to send the protocol
+template <IRType irType>
+inline void IRLwrite(const uint8_t pin, uint16_t address, uint32_t command) __attribute__((always_inline));
+
+template <uint8_t addressLength, uint8_t commandLength,
+	uint16_t Hz, bool addressFirst,
+	uint16_t markLead, uint16_t spaceLead,
+	uint16_t markZero, uint16_t markOne,
+	uint16_t spaceZero, uint16_t spaceOne>
+	inline void IRLsend(volatile uint8_t * outPort, uint8_t bitmask, uint16_t address, uint32_t command) __attribute__((always_inline));
+
+// functions to set the pin high or low (with bitbang pwm)
+inline void IRLmark(const uint16_t Hz, volatile uint8_t * outPort, uint8_t bitMask, uint16_t time) __attribute__((always_inline));
+inline void IRLspace(volatile uint8_t * outPort, uint8_t bitMask, uint16_t time) __attribute__((always_inline));
+
+//================================================================================
+// Inline Implementations (receive)
+//================================================================================
+
+template <IRType irType>
+void IRLbegin(const uint8_t interrupt){
+	// attach the function that decodes the signals
+	attachInterrupt(interrupt, IRLinterrupt<irType>, CHANGE);
+}
+
+void IRLend(const uint8_t interrupt){
+	// release the interrupt, if its NOT_AN_INTERRUPT the detach function does nothing
+	detachInterrupt(interrupt);
+	// also make sure to call reset() after end() if you use the intern reading functions
+}
+
+bool IRLavailable(void){
+	return IRLProtocol;
+}
+
+void IRLreset(void){
+	IRLProtocol = 0;
+}
+
+uint8_t IRLgetProtocol(void){
+	return IRLProtocol;
+}
+
+uint16_t IRLgetAddress(void){
+	return IRLAddress;
+}
+
+uint32_t IRLgetCommand(void){
+	return IRLCommand;
+}
+
+template <IRType irType>
+void IRLinterrupt(void){
+	//save the duration between the last reading
+	static uint32_t lastTime = 0;
+	uint32_t time = micros();
+	uint32_t duration_32 = time - lastTime;
+	lastTime = time;
+
+	// calculate 16 bit duration. On overflow set duration to a clear timeout
+	uint16_t duration = 0xFFFF;
+	if (duration_32 <= 0xFFFF)
+		duration = duration_32;
+
+	// determinate which decode function must be called
+	switch (irType){
+	case IR_USER:
+		// userfunction that can be overwritten
+		decodeIR(duration);
+		break;
+	case IR_ALL:
+		decodeAll(duration);
+		break;
+	case IR_NEC:
+		decodeNec<IR_NO_EXTRA_ACCURACY>(duration);
+		break;
+	case IR_PANASONIC:
+		decodePanasonic<IR_NO_EXTRA_ACCURACY>(duration);
+		break;
+		//case IR_SONY8:
+		//	decodeSony8<IR_NO_EXTRA_ACCURACY>(duration);
+		//	break;
+	case IR_SONY12:
+		decodeSony12<IR_NO_EXTRA_ACCURACY>(duration);
+		break;
+		//case IR_SONY15:
+		//	decodeSony15<IR_NO_EXTRA_ACCURACY>(duration);
+		//	break;
+		//case IR_SONY20:
+		//	decodeSony20<IR_NO_EXTRA_ACCURACY>(duration);
+		//	break;
+	case IR_RAW:
+		decodeRaw(duration);
+		break;
+	}
+}
+
+void decodeAll(const uint16_t duration){
+	// go through all known protocols and decode with more (resource unfriendly) accuration
+	decodeNec<IR_EXTRA_ACCURACY>(duration);
+	decodePanasonic<IR_EXTRA_ACCURACY>(duration);
+	decodeSony12<IR_EXTRA_ACCURACY>(duration);
+}
+
+template <bool extraAccuracy> void decodeNec(const uint16_t duration){
+	// temporary buffer to hold bytes for decoding this protocol
+	static uint8_t data[NEC_BLOCKS];
+
+	// pass the duration to the decoding function
+	bool newInput;
+	if (extraAccuracy) // no accuracy set at the moment, no conflict detected yet
+		newInput = IRLdecode <NEC_LENGTH, (NEC_TIMEOUT + NEC_MARK_LEAD) / 2, // irLength, timeoutThreshold
+		(NEC_MARK_LEAD + NEC_SPACE_ONE) / 2, (NEC_SPACE_LEAD + NEC_SPACE_HOLDING) / 2, // markLeadThreshold, spaceLeadThreshold
+		(NEC_SPACE_HOLDING + NEC_SPACE_ONE) / 2, 0, // spaceLeadHoldingThreshold, markThreshold
+		(NEC_SPACE_ONE + NEC_SPACE_ZERO) / 2, // spaceThreshold
+		0, 0>// markTimeout, spaceTimeout
+		(duration, data);
+	else
+		newInput = IRLdecode <NEC_LENGTH, (NEC_TIMEOUT + NEC_MARK_LEAD) / 2, // irLength, timeoutThreshold
+		(NEC_MARK_LEAD + NEC_SPACE_ONE) / 2, (NEC_SPACE_LEAD + NEC_SPACE_HOLDING) / 2, // markLeadThreshold, spaceLeadThreshold
+		(NEC_SPACE_HOLDING + NEC_SPACE_ONE) / 2, 0, // spaceLeadHoldingThreshold, markThreshold
+		(NEC_SPACE_ONE + NEC_SPACE_ZERO) / 2, // spaceThreshold
+		0, 0>// markTimeout, spaceTimeout
+		(duration, data);
+
+	if (newInput){
+		// Check if the protcol's checksum is correct
+		bool holding;
+		if (IRLcheckInverse1(data) || (holding = IRLcheckHolding(data))){
+			// normally NEC also check for the inverse of the address.
+			// newer remotes dont have this because of the wide used protocol all addresses were already used
+			// to make it less complicated its left out and the user can check the command inverse himself if needed
+			//if (!holding && !extended && !IRLcheckInverse0(data))
+			//	return;
+
+			// save address + command and trigger event
+			uint16_t address = UINT16_AT_OFFSET(data, 0);
+			uint32_t command = UINT16_AT_OFFSET(data, 2);
+			IREvent(IR_NEC, address, command);
+		}
+	}
+}
+
+template <bool extraAccuracy> void decodePanasonic(const uint16_t duration){
+	// temporary buffer to hold bytes for decoding this protocol
+	static uint8_t data[PANASONIC_BLOCKS];
+
+	// pass the duration to the decoding function
+	bool newInput;
+	if (extraAccuracy) // no accuracy set at the moment, no conflict detected yet
+		newInput = IRLdecode <PANASONIC_LENGTH, (PANASONIC_TIMEOUT + PANASONIC_MARK_LEAD) / 2, // irLength, timeoutThreshold
+		(PANASONIC_MARK_LEAD + PANASONIC_SPACE_ONE) / 2, (PANASONIC_SPACE_LEAD + PANASONIC_SPACE_ONE) / 2, // markLeadThreshold, spaceLeadThreshold
+		0, 0, // spaceLeadHoldingThreshold, markThreshold
+		(PANASONIC_SPACE_ONE + PANASONIC_SPACE_ZERO) / 2, // spaceThreshold
+		0, 0>// markTimeout, spaceTimeout
+		(duration, data);
+	else
+		newInput = IRLdecode <PANASONIC_LENGTH, (PANASONIC_TIMEOUT + PANASONIC_MARK_LEAD) / 2, // irLength, timeoutThreshold
+		(PANASONIC_MARK_LEAD + PANASONIC_SPACE_ONE) / 2, (PANASONIC_SPACE_LEAD + PANASONIC_SPACE_ONE) / 2, // markLeadThreshold, spaceLeadThreshold
+		0, 0, // spaceLeadHoldingThreshold, markThreshold
+		(PANASONIC_SPACE_ONE + PANASONIC_SPACE_ZERO) / 2, // spaceThreshold
+		0, 0>// markTimeout, spaceTimeout
+		(duration, data);
+
+	if (newInput){
+		// Check if the protcol's checksum is correct
+		if (IRLcheckXOR0(data)){
+			uint16_t address = UINT16_AT_OFFSET(data, 0);
+			uint32_t command = UINT32_AT_OFFSET(data, 2);
			IREvent(IR_PANASONIC, address, command);
+			return;
+		}
+	}
+}
+
+template <bool extraAccuracy> void decodeSony12(const uint16_t duration){
+	// temporary buffer to hold bytes for decoding this protocol
+	static uint8_t data[SONY_BLOCKS_12];
+
+	// pass the duration to the decoding function
+	bool newInput;
+	if (extraAccuracy)
+		newInput = IRLdecode <SONY_LENGTH_12, (SONY_TIMEOUT + SONY_MARK_LEAD) / 2, // irLength, timeoutThreshold
+		(SONY_MARK_LEAD + SONY_MARK_ONE) / 2, 0, // markLeadThreshold, spaceLeadThreshold
+		0, (SONY_MARK_ONE + SONY_MARK_ZERO) / 2, // spaceLeadHoldingThreshold, markThreshold
+		0, // spaceThreshold
+		(SONY_MARK_LEAD + SONY_MARK_ONE) / 2, SONY_MARK_ONE>// markTimeout, spaceTimeout
+		(duration, data);
+	else
+		newInput = IRLdecode <SONY_LENGTH_12, (SONY_TIMEOUT + SONY_MARK_LEAD) / 2, // irLength, timeoutThreshold
+		(SONY_MARK_LEAD + SONY_MARK_ONE) / 2, 0, // markLeadThreshold, spaceLeadThreshold
+		0, (SONY_MARK_ONE + SONY_MARK_ZERO) / 2, // spaceLeadHoldingThreshold, markThreshold
+		0, // spaceThreshold
+		0, 0>// markTimeout, spaceTimeout
+		(duration, data);
+
+	if (newInput){
+		// protocol has no checksum
+		uint16_t address = UINT16_AT_OFFSET(data, 0) >> 7;
+		uint32_t command = data[0] & 0x7F;
+		IREvent(IR_SONY12, address, command);
+		return;
+	}
+}
+
+void decodeRaw(const uint16_t duration){
+	//TODO, use advanced raw example instead
+}
+
+bool IRLcheckInverse0(uint8_t data[]){
+	// check if byte 2 and is the inverse of byte 3
+	if (uint8_t((data[0] ^ (~data[1]))) == 0)
+		return true;
+	else return false;
+}
+
+bool IRLcheckInverse1(uint8_t data[]){
+	// check if byte 0 and is the inverse of byte 1
+	if (uint8_t((data[2] ^ (~data[3]))) == 0)
+		return true;
+	else return false;
+}
+
+bool IRLcheckHolding(uint8_t data[]){
+	// check if at least the command is always 1
+	if (data[2] == 0xFF && data[3] == 0xFF)
+		return true;
+	else return false;
+}
+
+bool IRLcheckXOR0(uint8_t data[]){
+	// this function is used for panasonic checksum
+	if (uint8_t(data[2] ^ data[3] ^ data[4]) == data[5])
+		return true;
+	else return false;
+}
+
+// multifunctional template for receiving
+template <uint8_t irLength, uint16_t timeoutThreshold, uint16_t markLeadThreshold, uint16_t spaceLeadThreshold,
+	uint16_t spaceLeadHoldingThreshold, uint16_t markThreshold, uint16_t spaceThreshold,
+	uint16_t markTimeout, uint16_t spaceTimeout>
+	bool IRLdecode(uint16_t duration, uint8_t data[]){
+
+	// variables for ir processing
+	static uint8_t count = 0;
+
+	// if timeout always start next possible reading and abort any pending readings
+	if (duration >= timeoutThreshold)
+		count = 1;
+
+	// on a reset (error in decoding) we are waiting for a timeout to start a new reading again
+	// this is to not conflict with other protocols while they are sending 0/1 which might be similar to a lead in another protocol
+	else if (count == 0)
+		return false;
+
+	// check pulses for mark/space and lead + logical 0/1 seperate
+	else{
+		// Mark pulses (odd numbers)
+		if (count % 2 == 1){
+			// check Mark Lead (needs a timeout or a correct signal)
+			if (markLeadThreshold && count == 1){
+				// lead is okay// wrong lead
+				if (duration <= markLeadThreshold){
+					count = 0;
+					return false;
+				}
+			}
+
+			else{
+				// check for timeout if needed (might be a different protocol)
+				if (markTimeout && duration > markTimeout){
+					count = 0;
+					return false;
+				}
+
+				// only check values if the protocol has different logical space pulses
+				else if (markThreshold){
+
+					// get number of the Mark Bits (starting from zero)
+					uint8_t length;
+					// only save every 2nd value, substract the first two lead pulses
+					if (!spaceThreshold)
+						length = (count / 2) - 1;
+					// special case: spaces and marks both have data in the pulse
+					else length = count - 2;
+
+					// move bits and write 1 or 0 depending on the duration
+					// 1.7: changed from MSB to LSB. somehow takes a bit more flash but is correct and easier to handle.
+					data[length / 8] >>= 1;
+					if (duration > markThreshold)
+						data[length / 8] |= 0x80;
+					//else // normally not needed through the bitshift
+					//	data[length / 8] &= ~0x80;
+				}
+
+				// check last input (always a mark)
+				if (count > irLength){
+					count = 0;
+					return true;
+				}
+			}
+		}
+
+		// Space pulses (even numbers)
+		else{
+			//check Space Lead/Space Holding
+			if (spaceLeadThreshold && count == 2){
+				// normal Space, next reading
+				if (duration > spaceLeadThreshold);
+
+				// Button holding (if supported by protocol)
+				else if (spaceLeadHoldingThreshold && duration > spaceLeadHoldingThreshold){
+					// set command to 0xFF if button is held down
+					if (irLength == (4 * 8 * 2 + 2)){
+						data[0] = data[1] = 0x00;
+						data[2] = data[3] = 0xFF;
+					}
+					count = 0;
+					return true;
+				}
+				// wrong space
+				else {
+					count = 0;
+					return false;
+				}
+			}
+			else{
+				// check for timeout if needed (might be a different protocol)
+				if (spaceTimeout && duration > spaceTimeout){
+					count = 0;
+					return false;
+				}
+
+				// only check values if the protocol has different logical space pulses
+				else if (spaceThreshold){
+
+					// get number of the Space Bits (starting from zero)
+					uint8_t length;
+					// only save every 2nd value, substract the first two lead pulses
+					if (!markThreshold)
+						length = (count / 2) - 2;
+					// special case: spaces and marks both have data in the pulse
+					else length = count - 2;
+
+					// move bits and write 1 or 0 depending on the duration
+					// 1.7: changed from MSB to LSB. somehow takes a bit more flash but is correct and easier to handle.
+					data[length / 8] >>= 1;
+					if (duration > spaceThreshold)
+						data[length / 8] |= 0x80;
+					//else // normally not needed through the bitshift
+					//	data[length / 8] &= ~0x80;
+				}
+			}
+		}
+
+		// next reading, no errors
+		count++;
+	}
+
+	// no valid input (yet)
+	return false;
+}
+
+//================================================================================
+// Inline Implementations (send)
+//================================================================================
+
+template <IRType irType>
+void IRLwrite(const uint8_t pin, uint16_t address, uint32_t command)
+{
+	// get the port mask and the pointers to the out/mode registers for faster access
+	uint8_t bitMask = digitalPinToBitMask(pin);
+	uint8_t port = digitalPinToPort(pin);
+	volatile uint8_t * outPort = portOutputRegister(port);
+	volatile uint8_t * modePort = portModeRegister(port);
+
+	// set pin to OUTPUT and LOW
+	*modePort |= bitMask;
+	*outPort &= ~bitMask;
+
+	// disable interrupts
+	uint8_t oldSREG = SREG;
+	cli();
+
+	switch (irType){
+
+	case IR_NEC:
+		// NEC only sends the data once
+		if (command == 0xFFF)
+			// send holding indicator
+			IRLsend<0, 0, NEC_HZ, 0, NEC_MARK_LEAD, NEC_SPACE_HOLDING,
+			0, 0, 0, 0>
+			(outPort, bitMask, address, command);
+		else
+			// send data
+			IRLsend<NEC_ADDRESS_LENGTH, NEC_COMMAND_LENGTH, NEC_HZ, IR_ADDRESS_FIRST, NEC_MARK_LEAD, NEC_SPACE_LEAD,
+			NEC_MARK_ZERO, NEC_MARK_ONE, NEC_SPACE_ZERO, NEC_SPACE_ONE>
+			(outPort, bitMask, address, command);
+		break;
+
+	case IR_PANASONIC: //TODO test
+		// send data
+		IRLsend<PANASONIC_ADDRESS_LENGTH, PANASONIC_COMMAND_LENGTH, PANASONIC_HZ, IR_ADDRESS_FIRST, PANASONIC_MARK_LEAD, PANASONIC_SPACE_LEAD,
+			PANASONIC_MARK_ZERO, PANASONIC_MARK_ONE, PANASONIC_SPACE_ZERO, PANASONIC_SPACE_ONE>
+			(outPort, bitMask, address, command);
+		break;
+
+	case IR_SONY12: //TODO test, address -1?
+		// repeat 3 times
+		for (uint8_t i = 0; i < 3; i++)
+			// send data
+			IRLsend<SONY_ADDRESS_LENGTH_12, SONY_COMMAND_LENGTH_12, SONY_HZ, IR_COMMAND_FIRST, SONY_MARK_LEAD, SONY_SPACE_LEAD,
+			SONY_MARK_ZERO, SONY_MARK_ONE, SONY_SPACE_ZERO, SONY_SPACE_ONE>
+			(outPort, bitMask, address, command);
+		break;
+	}
+
+	// enable interrupts
+	SREG = oldSREG;
+
+	// set pin to INPUT again to be save
+	*modePort &= ~bitMask;
+}
+
+// multifunctional template for sending
+template <uint8_t addressLength, uint8_t commandLength,
+	uint16_t Hz, bool addressFirst,
+	uint16_t markLead, uint16_t spaceLead,
+	uint16_t markZero, uint16_t markOne,
+	uint16_t spaceZero, uint16_t spaceOne>
+	void IRLsend(volatile uint8_t * outPort, uint8_t bitmask, uint16_t address, uint32_t command){
+
+	// send lead mark
+	if (markLead)
+		IRLmark(Hz, outPort, bitmask, markLead);
+
+	// send lead space
+	if (spaceLead)
+		IRLspace(outPort, bitmask, spaceLead);
+
+	// abort if input values are both the same (sending a holding signal for example)
+	if (markOne != markZero || spaceOne != spaceZero)
+	{
+		// go through all bits
+		for (uint8_t i = 0; i < (addressLength + commandLength); i++){
+			// determine if its a logical one or zero, starting with address or command
+			bool bitToSend;
+			if (addressFirst && i < addressLength || !addressFirst && i >= commandLength){
+				bitToSend = address & 0x01;
+				address >>= 1;
+			}
+			else{
+				bitToSend = command & 0x01;
+				command >>= 1;
+			}
+
+			// send logic mark bits if needed
+			if (markOne != markZero){
+				// modulate if spaces dont have logic, else only every even number
+				if (spaceOne == spaceZero || spaceOne != spaceZero && i % 2 == 0)
+				{
+					if (bitToSend)
+						IRLmark(Hz, outPort, bitmask, markOne);
+					else
+						IRLmark(Hz, outPort, bitmask, markZero);
+				}
+			}
+			else
+				IRLmark(Hz, outPort, bitmask, markOne);
+
+			// send logic space bits if needed
+			if (spaceOne != spaceZero){
+				// modulate if marks dont have logic, else only every odd number
+				if (markOne == markZero || markOne != markZero && i % 2 == 1){
+					if (bitToSend)
+						IRLspace(outPort, bitmask, spaceOne);
+					else
+						IRLspace(outPort, bitmask, spaceZero);
+				}
+			}
+			else
+				IRLspace(outPort, bitmask, spaceOne);
+		}
+	}
+
+	// finish mark
+	IRLmark(Hz, outPort, bitmask, markZero); //TODO zero or one for sony?
+	IRLspace(outPort, bitmask, 0);
+}
+
+void IRLmark(const uint16_t Hz, volatile uint8_t * outPort, uint8_t bitMask, uint16_t time) {
+	/*
+	Bitbangs PWM in the given Hz number for the given time
+	________________________________________________________________________________
+	Delay calculation:
+	F_CPU/1.000.000 to get number of cycles/uS
+	/3 to get the number of loops needed for 1ms (1loop = 3 cycles)
+
+	Multiply with the number of ms delay:
+	1/kHz to get the seconds
+	* 1.000.000 to get it in uS
+	/2 to get half of a full pulse
+
+	Substract the while, portmanipulation, loop overhead /3 loop cycles
+
+	F_CPU(16.000.000)            1 * 1.000.000(pulse in uS)   12(overhead)
+	========================== * ========================== - ==============
+	1.000.000 * 3(loop cycles)   Hz * 2(half of a pulse)      3(loop cycles)
+
+	<==>
+
+	F_CPU(16.000.000) - (12(overhead) * Hz * 2(half of a pulse))
+	===========================================================
+	Hz * 2(half of a on/off pulse) * 3(loop cycles)
+
+	________________________________________________________________________________
+	Iterations calculation:
+	Devide time with cycles in while loop
+	Multiply this with the cycles per uS
+	cycles per while loop: 3(loop cycles) * delay + overhead
+
+	time * (F_CPU(16.000.000) / 1.000.000)
+	======================================
+	delay*3(loop cycles) + overhead
+	*/
+
+	const uint32_t loopCycles = 3;
+	const uint32_t overHead = 12; // just a guess from try + error
+	uint8_t delay = (F_CPU - (overHead * Hz * 2UL)) / (Hz * 2UL * loopCycles);
+	uint16_t iterations = (time*(F_CPU / 1000000UL)) / (delay * loopCycles + overHead);
+
+	while (iterations--){
+		// flip pin state and wait for the calculated time
+		*outPort ^= bitMask;
+#ifdef IRLREMOTE_AVR
+		_delay_loop_1(delay);
+#else
+		// ARM TODO?
+#endif
+	}
+}
+
+void IRLspace(volatile uint8_t * outPort, uint8_t bitMask, uint16_t time) {
+	// Sends an IRLspace for the specified number of microseconds.
+	// A IRLspace is no output, so the PWM output is disabled.
+	*outPort &= ~bitMask; // write pin LOW
+	delayMicroseconds(time);
+	//_delay_loop_2(time*(F_CPU/1000000UL)/4UL);
+}
+
+#endif
\ No newline at end of file
--- a/katka/creep.ino	Sun Oct 12 10:54:09 2014 +0200
+++ b/katka/creep.ino	Thu Jun 11 13:46:30 2015 +0200
@@ -1,4 +1,5 @@
 #include "misc.h"
+#include "ir.h"
 #include "clock.h"
 #include "servos.h"
 #include "leg.h"
@@ -25,8 +26,8 @@
                      HOME_Y - 8 + creep_tilt * LEGS[leg][3]);
         }
     }
-    ir();
     tick(TICK);
+    ir_loop();
 }
 
 void creep() {
@@ -38,27 +39,27 @@
         return;
     }
     if (LEGS[leg][3] > 0) {
-        while (creep_tilt < 4) {
+        while (creep_tilt < 6) {
             creep_tilt += 2;
             creep_frame();
         }
     } else {
-        while (creep_tilt > -4) {
+        while (creep_tilt > -6) {
             creep_tilt -= 2;
             creep_frame();
         }
     }
     creep_on_ground[leg] = false;
-    move_leg_by(leg, 20, -20);
+    move_leg_by(leg, 20, -10);
     creep_frame();
     creep_frame();
     move_leg(leg,
              (HOME_X - 10) * LEGS[leg][2] + 15 +
-             (10 * creep_speed + creep_rotation * LEGS[leg][2]),
+             (8 * creep_speed + creep_rotation * LEGS[leg][2]),
              legs_y[leg]);
     creep_frame();
     creep_frame();
-    move_leg_by(leg, 0, 20);
+    move_leg_by(leg, 0, 10);
     creep_frame();
     creep_frame();
     creep_on_ground[leg] = true;
--- a/katka/ir.ino	Sun Oct 12 10:54:09 2014 +0200
+++ b/katka/ir.ino	Thu Jun 11 13:46:30 2015 +0200
@@ -1,37 +1,50 @@
 #include "creep.h"
 
 void ir_setup() {
-    IRLbegin<IR_ALL>(0); // Sensor on PIN 2
+    IRLbegin<IR_NEC>(0); // Sensor on PIN 2
     pinMode(13, OUTPUT);
     digitalWrite(13, LOW);
 }
 
-void ir() {
-    // digitalWrite(13, LOW);
-}
-
-void IREvent(uint8_t protocol, uint16_t address, uint32_t command) {
+void ir_loop() {
     static uint32_t last=0;
+    uint32_t IRcommand = 0;
+    static bool led = true;
 
-    if (command == 0xFFFFFF) {
-        command = last;
+    if (!IRLavailable()) {
+        if (led) {
+            digitalWrite(13, LOW);
+            led = false;
+        }
+        return;
     }
-    switch (command) {
-        case 0x02FD:
+
+    if (IRcommand == 0xFFFF) {
+        IRcommand = last;
+    } else {
+        last = IRcommand;
+    }
+
+    digitalWrite(13, HIGH);
+    led = true;
+
+    switch (IRcommand) {
+        case 0xBF40:
             creep_speed = min(1.0, creep_speed + 0.25);
             break;
-        case 0x9867:
+        case 0xE619:
             creep_speed = max(-1.0, creep_speed - 0.25);
             break;
-        case 0xE01F:
+        case 0xF807:
             creep_rotation = min(1.0, creep_rotation + 0.25);
             break;
-        case 0x906F:
+        case 0xF609:
             creep_rotation = max(-1.0, creep_rotation - 0.25);
             break;
-        case 0xA857:
+        case 0xEA15:
             creep_speed = 0.0;
             creep_rotation = 0.0;
             break;
     }
+    IRLreset();
 }
--- a/katka/katka.ino	Sun Oct 12 10:54:09 2014 +0200
+++ b/katka/katka.ino	Thu Jun 11 13:46:30 2015 +0200
@@ -1,6 +1,6 @@
 /* Katka creeping around autonomously. */
 
-#include <IRLremote.h>
+#include "IRLremote.h"
 #include <Servo.h>
 
 #include "servos.h"
--- a/katka/servos.ino	Sun Oct 12 10:54:09 2014 +0200
+++ b/katka/servos.ino	Thu Jun 11 13:46:30 2015 +0200
@@ -12,7 +12,7 @@
 //  pin, reverse, trim
 
     // hind right
-    {6, -1, 5}, // ankle
+    {6, -1, 0}, // ankle
     {7, 1, 0},  // knee
 
     // front right
@@ -25,7 +25,7 @@
 
     // hind left
     {12, -1, 0}, // knee
-    {14, 1, -5}, // ankle
+    {14, 1, 0}, // ankle
 };
 
 Servo servos[MAX_SERVO];
@@ -47,5 +47,6 @@
 void servo_setup() {
     for (unsigned char servo = 0; servo < MAX_SERVO; ++servo) {
         servos[servo].attach(SERVOS[servo][0], SERVO_FREQ_MIN, SERVO_FREQ_MAX);
+        delay(200);
     }
 }