/* remote-switch-bricklet
 * Copyright (C) 2013 Olaf Lüke <olaf@tinkerforge.com>
 *
 * remote-switch.c: Implementation of Remote Switch Bricklet messages
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

#include "remote-switch.h"

#include "bricklib/utility/util_definitions.h"
#include "bricklib/utility/init.h"
#include "bricklib/bricklet/bricklet_communication.h"
#include "brickletlib/bricklet_entry.h"
#include "brickletlib/bricklet_debug.h"
#include "config.h"

const uint8_t rfm69_config[][2] = {
	{REG_FRFMSB, RF_FRFMSB_433}, // 433 Mhz
	{REG_FRFMID, RF_FRFMID_433},
	{REG_FRFLSB, RF_FRFLSB_433},
//	{REG_FDEVMSB, 0x10}, // Frequency deviation
//	{REG_FDEVLSB, 0x00},
	{REG_DATAMODUL, RF_DATAMODUL_DATAMODE_PACKET | RF_DATAMODUL_MODULATIONTYPE_OOK | RF_DATAMODUL_MODULATIONSHAPING_00}, // Use OOK
	{REG_BITRATEMSB, TYPE_A_C_BITRATEMSB},
	{REG_BITRATELSB, TYPE_A_C_BITRATELSB},
	{REG_PREAMBLEMSB, 0x00}, // no preamble
	{REG_PREAMBLELSB, 0x00},
	{REG_SYNCCONFIG, RF_SYNC_OFF}, // Use empty sync to assure small pause between commands
	{REG_SYNCVALUE1, 0},
	{REG_SYNCVALUE2, 0},
	{REG_SYNCVALUE3, 0},
	{REG_SYNCVALUE4, 0},
	{REG_SYNCVALUE5, 0},
	{REG_SYNCVALUE6, 0},
	{REG_SYNCVALUE7, 0},
	{REG_SYNCVALUE8, 0},
	{REG_PACKETCONFIG1, RF_PACKET1_FORMAT_VARIABLE | RF_PACKET1_DCFREE_OFF | RF_PACKET1_CRC_OFF},
	{REG_PAYLOADLENGTH, TYPE_A_C_PACKET_LENGTH},
	{REG_FIFOTHRESH, RF_FIFOTHRESH_TXSTART_FIFONOTEMPTY}, // Set fifo threshold, send when threshold reached
//	{REG_PALEVEL, RF_PALEVEL_OUTPUTPOWER_11111 | RF_PALEVEL_PA0_ON}, // w/o power amplifier
	{REG_PALEVEL, RF_PALEVEL_OUTPUTPOWER_11111 | RF_PALEVEL_PA1_ON | RF_PALEVEL_PA2_ON}, // w/ power amplifier: PA 1 and 2 on, 20dBm
	{REG_OCP, RF_OCP_OFF | RF_OCP_TRIM_120}, // OCP off, trimming at 120mA
	{REG_TESTPA1, 0x5D}, // High power mode (only in hw version)
	{REG_TESTPA2, 0x7C}, // High power mode (only in hw version)
	{REG_OPMODE, RF_OPMODE_STANDBY}, // Set mode to transmitter
	{REG_ENDOFCONFIG, 0}
};

const uint8_t type_registers[NUM_TYPE_CONFIGURATIONS] = {
	REG_BITRATEMSB,
	REG_BITRATELSB,
	REG_PAYLOADLENGTH,
};

const uint8_t type_configurations[NUM_TYPES][NUM_TYPE_CONFIGURATIONS] = {
	{TYPE_A_C_BITRATEMSB, TYPE_A_C_BITRATELSB, TYPE_A_C_PACKET_LENGTH},
	{TYPE_B_BITRATEMSB, TYPE_B_BITRATELSB, TYPE_B_PACKET_LENGTH},
	{TYPE_B_BITRATEMSB, TYPE_B_BITRATELSB, TYPE_B_DIM_PACKET_LENGTH},
	{TYPE_FLAMINGO_BITRATEMSB, TYPE_FLAMINGO_BITRATELSB, TYPE_FLAMINGO_PACKET_LENGTH},
	{TYPE_HOMEASYEU_BITRATEMSB,TYPE_HOMEASYEU_BITRATELSB,TYPE_HOMEASYEU_PACKET_LENGTH}
};

void invocation(const ComType com, const uint8_t *data) {
	switch(((MessageHeader*)data)->fid) {
		case FID_SWITCH: {
			switch_socket_a(com, (SwitchSocketA*)data);
			return;
		}

		case FID_GET_SWITCHING_STATE: {
			get_switching_state(com, (GetSwitchingState*)data);
			return;
		}

		case FID_SET_REPEATS: {
			set_repeats(com, (SetRepeats*)data);
			return;
		}

		case FID_GET_REPEATS: {
			get_repeats(com, (GetRepeats*)data);
			return;
		}

		case FID_SWITCH_SOCKET_A: {
			switch_socket_a(com, (SwitchSocketA*)data);
			return;
		}

		case FID_SWITCH_SOCKET_B: {
			switch_socket_b(com, (SwitchSocketB*)data);
			return;
		}

		case FID_DIM_SOCKET_B: {
			dim_socket_b(com, (DimSocketB*)data);
			return;
		}

		case FID_SWITCH_SOCKET_C: {
			switch_socket_c(com, (SwitchSocketC*)data);
			return;
		}

		default: {
			BA->com_return_error(data, sizeof(MessageHeader), MESSAGE_ERROR_CODE_NOT_SUPPORTED, com);
			break;
		}
	}
}

void change_type(const SwitchingType type) {
	if(type == BC->current_type || type >= NUM_TYPES) {
		return;
	}

	for(uint8_t i = 0; i < NUM_TYPE_CONFIGURATIONS; i++) {
		rfm69_write_register(type_registers[i], &type_configurations[type][i], 1);
	}

	BC->current_packet_length = type_configurations[type][2];
	BC->current_type = type;
}

void switch_socket_a(const ComType com, const SwitchSocketA *data) {
	if(BC->state != RF_IDLE) {
		return;
	}

	change_type(TYPE_A_C);

	const uint8_t house_code = data->house_code;
	for(uint8_t i = 0; i < 5; i++) {
		if(house_code & (1 << i)) {
			BC->rfm69_data[i] = RFM69_DATA_ON;
		} else {
			BC->rfm69_data[i] = RFM69_DATA_FLOAT;
		}
	}

	const uint8_t receiver_code = data->receiver_code;
	for(uint8_t i = 0; i < 5; i++) {
		if(receiver_code & (1 << i)) {
			BC->rfm69_data[i+5] = RFM69_DATA_ON;
		} else {
			BC->rfm69_data[i+5] = RFM69_DATA_FLOAT;
		}
	}

	if(data->switch_to == RFM69_SWITCH_TO_ON) {
		BC->rfm69_data[10] = RFM69_DATA_ON;
		BC->rfm69_data[11] = RFM69_DATA_FLOAT;
	} else {
		BC->rfm69_data[10] = RFM69_DATA_FLOAT;
		BC->rfm69_data[11] = RFM69_DATA_ON;
	}

	// Sync
	BC->rfm69_data[12] = 0b10000000;
	BC->rfm69_data[13] = 0b00000000;
	BC->rfm69_data[14] = 0b00000000;
	BC->rfm69_data[15] = 0b00000000;

	BC->state = RF_SENDING;
	BA->com_return_setter(com, data);
}

void switch_socket_b(const ComType com, const SwitchSocketB *data) {
	if(BC->state != RF_IDLE) {
		return;
	}

	//if (data->address==100)
	//{
		switch_socket_flamingo(com,data);
		return;
	//}
	if (data->address==101)
	{
		switch_socket_homeeasyeu(com,data);
		return;
	}
	change_type(TYPE_B);

	// Sync
	BC->rfm69_data[0] = 0b00000100; //1 260 0 260 0 260
	BC->rfm69_data[1] = 0b00000000; //8 * 260 --> 1 260 0 2600

	// Address
	for(uint8_t i = 0; i < 26; i++) {
		if(data->address & (1 << i)) {
			BC->rfm69_data[i+2] = RFM69_DATA_B_1;
		} else {
			BC->rfm69_data[i+2] = RFM69_DATA_B_0;
		}
	}

	// Switch All
	if(data->unit == 255) {
		BC->rfm69_data[28] = RFM69_DATA_B_1;
	} else {
		BC->rfm69_data[28] = RFM69_DATA_B_0;
	}

	// On/Off
	if(data->switch_to == RFM69_SWITCH_TO_ON) {
		BC->rfm69_data[29] = RFM69_DATA_B_1;
	} else {
		BC->rfm69_data[29] = RFM69_DATA_B_0;
	}

	// Unit
	for(uint8_t i = 0; i < 4; i++) {
		if(data->unit & (1 << i)) {
			BC->rfm69_data[i+30] = RFM69_DATA_B_1;
		} else {
			BC->rfm69_data[i+30] = RFM69_DATA_B_0;
		}
	}

	// Sync
	BC->rfm69_data[34] = 0b10000000;
	BC->rfm69_data[35] = 0b00000000;
	BC->rfm69_data[36] = 0b00000000;
	BC->rfm69_data[37] = 0b00000000;
	BC->rfm69_data[38] = 0b00000000;

	BC->state = RF_SENDING;
	BA->com_return_setter(com, data);
}

void switch_socket_homeeasyeu(const ComType com, const SwitchSocketB *data) {
	
	if(BC->state != RF_IDLE) {
		return;
	}

	
	/*
AAAAAAAAAAA 11
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 32
CCCC 4
DD 2
EE 2
FFFFFF 6
G 1

15+32+11
26+32=58 Bit

 * Technische informatie:
 * Analyses Home Easy Messages and convert these into an eventcode
 * Only new EU devices with automatic code system are supported
 * Only  On / Off status is decoded, no DIM values
 * Only tested with Home Easy HE300WEU transmitter, doorsensor and PIR sensor
 * Home Easy message structure, by analyzing bitpatterns so far ...
 * AAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBCCCCDDEEFFFFFFG
 *       A = startbits/preamble, B = address, C = ?, D = Command, E = ?, F = Channel, G = Stopbit
 
 E = 01 (einse)
 E = 11 (groupe)
 C =1100 (Group)
 C= 1011 (einzeln)
 
 D= 10 (on)
 D= 01 (off)
 
 AAAAAAAAAAA BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB CCCC DD EE FFFFFF G
 11000111100 10111011010100011110110101100011 1011 10 01 000111 1 ON
 11000111100 10111011010100011110110101100011 1011 01 01 000111 1 OFF
 11000111100 10111011010100011110110101100011 1011 10 01 000111 1 #channel 0 on      7
 11000111100 10111011010100011110110101100011 1011 01 01 000111 1 #channel 0 off     7
 11000111100 10111011010100011110110101100011 1011 10 01 001011 1 #channel 1 on     11
 11000111100 10111011010100011110110101100011 1011 01 01 001011 1 #channel 1 off
 11000111100 10111011010100011110110101100011 1011 10 01 001101 1 #channel 2 on     13
 11000111100 10111011010100011110110101100011 1011 01 01 001101 1 #channel 2 off
 11000111100 10111011010100011110110101100011 1011 10 01 001110 1 #channel 3 on     14
 11000111100 10111011010100011110110101100011 1011 01 01 001110 1 #channel 3 off
 11000111100 10111011010100011110110101100011 1011 10 01 010011 1 #channel 4 on     19
 11000111100 10111011010100011110110101100011 1011 01 01 010011 1 #channel 4 off
 11000111100 10111011010100011110110101100011 1011 10 01 010101 1 #channel 5 on     21
 11000111100 10111011010100011110110101100011 1011 01 01 010101 1 #channel 5 off
 11000111100 10111011010100011110110101100011 1011 10 01 010110 1 #channel 6 on^    22
 11000111100 10111011010100011110110101100011 1011 01 01 010110 1 #channel 6 off
 11000111100 10111011010100011110110101100011 1011 10 01 011001 1 #channel 7 on     25
 11000111100 10111011010100011110110101100011 1011 01 01 011001 1 #channel 7 off
 11000111100 10111011010100011110110101100011 1011 10 01 011010 1 #channel 8 on     26
 11000111100 10111011010100011110110101100011 1011 01 01 011010 1 #channel 8 off
 11000111100 10111011010100011110110101100011 1011 10 01 011100 1 #channel 9 on     28
 11000111100 10111011010100011110110101100011 1011 01 01 011100 1 #channel 9 off
 11000111100 10111011010100011110110101100011 1011 10 01 000011 1 #channel 10 on    3
 11000111100 10111011010100011110110101100011 1011 01 01 000011 1 #channel 10 off   
 11000111100 10111011010100011110110101100011 1011 10 01 000101 1 #channel 11 on    5
 11000111100 10111011010100011110110101100011 1011 01 01 000101 1 #channel 11 off
 11000111100 10111011010100011110110101100011 1011 10 01 000110 1 #channel 12 on    6
 11000111100 10111011010100011110110101100011 1011 01 01 000110 1 #channel 12 off
 11000111100 10111011010100011110110101100011 1011 10 01 001001 1 #channel 13 on     9
 11000111100 10111011010100011110110101100011 1011 01 01 001001 1 #channel 13 off
 11000111100 10111011010100011110110101100011 1011 10 01 001010 1 #channel 14 on    10
 11000111100 10111011010100011110110101100011 1011 01 01 001010 1 #channel 14 off
 11000111100 10111011010100011110110101100011 1011 10 01 001100 1 #channel 15 on     12
 11000111100 10111011010100011110110101100011 1011 01 01 001100 1 #channel 15 off
 
 11000111100 10111100011101110010001111100011 1100 10 11 000111 1 HE301EU ON
 11000111100 10111100011101110010001111100011 1100 01 11 000111 1 HE301EU OFF
 
 11000111100 10111101001101011011001011011100 1011 10 01 000111 1 HE300EU 1:ON, Switch:I   7
 11000111100 10111101001101011011001011011100 1011 01 01 000111 1 HE300EU 1:OFF, Switch:I 
 11000111100 10111101001101011011001011011100 1011 10 01 001011 1 HE300EU2 :ON ,Switch:I  11
 11000111100 10111101001101011011001011011100 1011 01 01 001011 1 HE300EU2 :OFF, Switch:I
 11000111100 10111101001101011011001011011100 1011 10 01 001101 1 HE300EU3 :ON, Switch:I   13
 11000111100 10111101001101011011001011011100 1011 01 01 001101 1 HE300EU3 :OFF, Switch:I
 11000111100 10111101001101011011001011011100 1011 10 01 001110 1 HE300EU4 :ON, Switch:I    14
 11000111100 10111101001101011011001011011100 1011 01 01 001110 1 HE300EU4 :OFF, Switch:I
 11000111100 10111101001101011011001011011100 1100 10 11 000111 1 HE300EUGroup:ON, Switch:I
 11000111100 10111101001101011011001011011100 1100 01 11 000111 1 HE300EUGroup:OFF, Switch:I
 11000111100 10111101001101011011001011011100 1011 10 01 010011 1 HE300EU1:ON, Switch:II
 11000111100 10111101001101011011001011011100 1011 01 01 010011 1 HE300EU1:OFF, Switch:II
 11000111100 10111101001101011011001011011100 1011 10 01 010101 1 HE300EU2:ON, Switch:II
 11000111100 10111101001101011011001011011100 1011 01 01 010101 1 HE300EU2:OFF, Switch:II
 11000111100 10111101001101011011001011011100 1011 10 01 010110 1 HE300EU3:ON, Switch:II
 11000111100 10111101001101011011001011011100 1011 01 01 010110 1 HE300EU3:OFF, Switch:II
 11000111100 10111101001101011011001011011100 1011 10 01 011001 1 HE300EU4:ON,S witch:II
 11000111100 10111101001101011011001011011100 1011 01 01 011001 1 HE300EU4:OFF,Switch:II
 11000111100 10111101001101011011001011011100 1100 10 11 000111 1 HE300EUGroup:ON,Switch:II
 11000111100 10111101001101011011001011011100 1100 01 11 000111 1 HE300EUGroup:OFF,Switch:II
 11000111100 10111101001101011011001011011100 1011 10 01 011010 1 HE300EU1:ON,Switch:III
 11000111100 10111101001101011011001011011100 1011 01 01 011010 1 HE300EU1:OFF,Switch:III
 11000111100 10111101001101011011001011011100 1011 10 01 011100 1 HE300EU2:ON,Switch:III
 11000111100 10111101001101011011001011011100 1011 01 01 011100 1 HE300EU2:OFF,Switch:III
 11000111100 10111101001101011011001011011100 1011 10 01 100011 1 HE300EU3:ON,Switch:III
 11000111100 10111101001101011011001011011100 1011 01 01 100011 1 HE300EU3:OFF,Switch:III
 11000111100 10111101001101011011001011011100 1011 10 01 100101 1 HE300EU4:ON,Switch:III
 11000111100 10111101001101011011001011011100 1100 10 11 000111 1 HE300EUGroup:ON,Switch:III
 11000111100 10111101001101011011001011011100 1100 01 11 000111 1 HE300EUGroup:OFF,Switch:III
 11000111100 10111101001101011011001011011100 1011 01 01 100101 1 HE300EU4:OFF,Switch:III
 11000111100 10111101001101011011001011011100 1011 10 01 100110 1 HE300EU1:ON,Switch:IV
 11000111100 10111101001101011011001011011100 1011 01 01 100110 1 HE300EU1:OFF,Switch:IV
 11000111100 10111101001101011011001011011100 1011 10 01 101001 1 HE300EU2:ON,Switch:IV
 11000111100 10111101001101011011001011011100 1011 01 01 101001 1 HE300EU2:OFF,Switch:IV
 11000111100 10111101001101011011001011011100 1011 10 01 101010 1 HE300EU3:ON,Switch:IV
 11000111100 10111101001101011011001011011100 1011 01 01 101010 1 HE300EU3:OFF,Switch:IV
 11000111100 10111101001101011011001011011100 1011 10 01 101100 1 HE300EU4:ON,Switch:IV
 11000111100 10111101001101011011001011011100 1011 01 01 101100 1 HE300EU4:OFF,Switch:IV
 11000111100 10111101001101011011001011011100 1100 10 11 000111 1 HE300EUGroup:ON,Switch:IV
 11000111100 10111101001101011011001011011100 1100 01 11 000111 1 HE300EUGroup:OFF,Switch:IV	
	*/
	
	change_type(TYPE_HOMEEASYEU);

	/*
	uint8_t ui8_Pos=0;
	// Sync
	BC->rfm69_data[ui8_Pos++] = 0b00000100;//High 260 Low 2670
	BC->rfm69_data[ui8_Pos++] = 0b00000000;

	//Preamble
	//AAAAAAAAAAA
	//11000111100
	uint16_t ui16_Preamble=0b11000111100;
	for(uint8_t i = 0; i < 11; i++) {
		if(ui16_Preamble & (1 << (10-i))) 
		{
			BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
		} else {
			BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_0;
		}
	}
	
	// Address
	//BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
	for(uint8_t i = 0; i < 32; i++) {
		if(data->address & (1 << i)) {
			BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
		} else {
			BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_0;
		}
	}

	//CCCC 4
	//C =1100 (Group)
	//C= 1011 (einzeln)
	if(data->unit == 255) {
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_0;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_0;
	} else {
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_0;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
	}
	
	
	//DD 2
	//D= 10 (on)
	//D= 01 (off)
	// On/Off
	if(data->switch_to == RFM69_SWITCH_TO_ON) {
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_0;
	} else {
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_0;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
	}
	
	//EE
	//E = 01 (einse)
	//E = 11 (groupe)
	if(data->unit == 255) {
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
	} else {
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_0;
		BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
	}
	
	//FFFFFF
	// Unit
	for(uint8_t i = 0; i < 5; i++) {
		if(data->unit & (1 << i)) {
			BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_1;
		} else {
			BC->rfm69_data[ui8_Pos++] = RFM69_DATA_B_0;
		}
	}

	// Sync
	BC->rfm69_data[ui8_Pos++] = 0b10000000;
	
	for(uint8_t i=ui8_Pos;i<64;i++) BC->rfm69_data[i] = 0b00000000;
	*/
	
						  
	char* test_pattern = 0;
	
	//
	//11000111100 10111101001101011011001011011100 1011 10 01 100110 1 HE300EU1:ON,Switch:IV
	//11000111100 10111101001101011011001011011100 1011 01 01 100110 1 HE300EU1:OFF,Switch:IV	
	//
	
	if(data->switch_to == RFM69_SWITCH_TO_ON) {
		test_pattern = "1100011110010111101001101011011001011011100101110011001101";
	} else {
		test_pattern = "1100011110010111101001101011011001011011100101101011001101";
	}
	
	for(uint8_t ii=0;ii<64;ii++) BC->rfm69_data[ii] = 0;

	int i=0;
	uint16_t ui16_BitPos=8;
	while(test_pattern[i]!=0)
	{
		if(test_pattern[i]=='1') 
		{
			//Add (H 260/ L 1320) --> 1000000
			BC->rfm69_data[ui16_BitPos>>3]<<=1;
			BC->rfm69_data[ui16_BitPos>>3]|=1;
			ui16_BitPos++;
			
			BC->rfm69_data[ui16_BitPos>>3]<<=1;
			ui16_BitPos++;

			BC->rfm69_data[ui16_BitPos>>3]<<=1;
			ui16_BitPos++;
			
			BC->rfm69_data[ui16_BitPos>>3]<<=1;
			ui16_BitPos++;
			
			BC->rfm69_data[ui16_BitPos>>3]<<=1;
			ui16_BitPos++;
			
			BC->rfm69_data[ui16_BitPos>>3]<<=1;
			ui16_BitPos++;
		} 
		else if(test_pattern[i]=='0')
		{
			//Add (H 260/ L 260) --> 10
			BC->rfm69_data[ui16_BitPos>>3]<<=1;
			BC->rfm69_data[ui16_BitPos>>3]|=1;
			ui16_BitPos++;
			
			BC->rfm69_data[ui16_BitPos>>3]<<=1;
			ui16_BitPos++;			
		}	
		i++;
	}
	while(ui16_BitPos&0x7) 
	{
		BC->rfm69_data[ui16_BitPos>>3]<<=1;	
		ui16_BitPos++;
	}
	
	/*BC->rfm69_data[35] = 0b00000000;
	BC->rfm69_data[36] = 0b00000000;
	BC->rfm69_data[37] = 0b00000000;
	BC->rfm69_data[38] = 0b00000000;*/

	BC->state = RF_SENDING;
	BA->com_return_setter(com, data);
}



void switch_socket_flamingo(const ComType com, const SwitchSocketB *data) {
	if(BC->state != RF_IDLE) {
		return;
	}

	change_type(TYPE_FLAMINGO);

//	0xD9762A10,            /* Remote 0, Unit A, Aan */
//	0xDAA47850,                                           /* Remote 0, Unit A, Uit */
//	0xDBDA22E0,                                           /* Remote 0, Unit B, Aan *///
//	0xDBA27220,                                           /* Remote 0, Unit B, Uit *///  
//	0x19BFD260,                                           /* Remote 0, Unit C, Aan //*/
//	0x195EEAA0,                                           /* Remote 0, Unit C, Uit// */  
//	0x984CC650,                                           /* Remote 0, Unit D, Aa//n */  
//	0x9A8C1050,                                           /* Remote 0, Unit D, Uit */  
//	0xDBFFFE90,                                           /* Remote 1, Unit A, Aan */
//	0xD91CEF10,                                           /* Remote 1, Unit A, Uit */  
//	0xDBC52FA0,                                           /* Remote 1, Unit B, Aan */
//	0xD9E35160,                                           /* Remote 1, Unit B, Uit */  
//	0x19B0FE60,                                           /* Remote 1, Unit C, Aan */
//	0x19682B20,                                           /* Remote 1, Unit C, Uit */  
//	0x9924E7D0,                                           /* Remote 1, Unit D, Aan */
//	0x9BA928D0};                                          /* Remote 1, Unit D, Uit */

/*
1 On:
D8458490	1101	1000	0100	0101	1000	0100	1001
D81FC5D0	1101	1000	0001	1111	1100	0101	1101
DBE24A90	1101	1011	1110	0010	0100	1010	1001
DAE00A10	1101	1010	1110	0000	0000	1010	0001
2: On:
D8EFCBA0	1101	1000	1110	1111	1100	1011	1010
DBA8AAE0	1101	1011	1010	1000	1010	1010	1110
D8ACD660	1101	1000	1010	1100	1101	0110	0110
DB8D7C60	1101	1011	1000	1101	0111	1100	0110
3: On
1B066260	0001	1011	0000	0110	0110	0010	0110
1A6320E0	0001	1010	0110	0011	0010	0000	1110
19329C60	0001	1001	0011	0010	1001	1100	0110
1B2402E0	0001	1011	0010	0100	0000	0010	1110
4: On
9A57DF90	1001	1010	0101	0111	1101	1111	1001
9A932550	1001	1010	1001	0011	0010	0101	0101
9807AE50	1001	1000	0000	0111	1010	1110	0101
9920CBD0	1001	1001	0010	0000	1100	1011	1101
Master: On
5BBD7570	0101	1011	1011	1101	0111	0101	0111
5ACDB430	0101	1010	1100	1101	1011	0100	0011
58D73BB0	0101	1000	1101	0111	0011	1011	1011
5AC7FF30	0101	1010	1100	0111	1111	1111	0011


1: Off
D92F4050	1101	1001	0010	1111	0100	0000	0101
DA40E650	1101	1010	0100	0000	1110	0110	0101
D82BF710	1101	1000	0010	1011	1111	0111	0001
D9B86790	1101	1001	1011	1000	0110	0111	1001
2: Off
DAA28B20	1101	1010	1010	0010	1000	1011	0010
D91D7960	1101	1001	0001	1101	0111	1001	0110
DB016220	1101	1011	0000	0001	0110	0010	0010
DB75FAA0	1101	1011	0111	0101	1111	1010	1010
3:Off
1BE59CA0	0001	1011	1110	0101	1001	1100	1010
18C422A0	0001	1000	1100	0100	0010	0010	1010
1826A720	0001	1000	0010	0110	1010	0111	0010
1883FA20	0001	1000	1000	0011	1111	1010	0010
4: Off
9A4FE4D0	1001	1010	0100	1111	1110	0100	1101
98F0EB50	1001	1000	1111	0000	1110	1011	0101
9935A490	1001	1001	0011	0101	1010	0100	1001
9A8A6C50	1001	1010	1000	1010	0110	1100	0101
Master Off:
59634630	0101	1001	0110	0011	0100	0110	0011
580B74B0	0101	1000	0000	1011	0111	0100	1011
587750F0	0101	1000	0111	0111	0101	0000	1111
59499530	0101	1001	0100	1001	1001	0101	0011
*/
	uint32_t ui32_Code = 0;
	if(data->switch_to == RFM69_SWITCH_TO_ON) {
		ui32_Code=0xDBFFFE90;
	} else {
		ui32_Code=0xD91CEF10;
	}
	
//	uint32_t ui32_BitPos=0;

//#define RFM69_DATA_F_0      0b11111100
//#define RFM69_DATA_F_1      0b11000000

//#define RFM69_DATA_F_SYNC1	0x11000000 //1 + 3 * 0 (12 null fehlen damit)
//#define RFM69_DATA_F_SYNC2	0x00000000 //4 * 0 (8 null fehlen damit)
//#define RFM69_DATA_F_SYNC3	0x00000000 //4 * 0 (4 null fehlen damit)
//#define RFM69_DATA_F_SYNC4	0x00000000 //5 * 0 (0 null fehlen damit)
	
	BC->rfm69_data[0]=RFM69_DATA_F_SYNC1;
	BC->rfm69_data[1]=RFM69_DATA_F_SYNC2;
	BC->rfm69_data[2]=RFM69_DATA_F_SYNC3;
	BC->rfm69_data[3]=RFM69_DATA_F_SYNC4;

	for(uint32_t BitNr=0;BitNr<28;BitNr++)
	{
		if (ui32_Code & (unsigned int)0x80000000)
		{
			//one - 1HIGH, 3LOW
			BC->rfm69_data[4+BitNr] = 0b11111100;//RFM69_DATA_F_1;
		}
		else
		{
			//zero - 3HIGH, 1LOW
			BC->rfm69_data[4+BitNr] = 0b11000000;//RFM69_DATA_F_0;
		}
		//ui32_Code<<=1;
		ui32_Code=ui32_Code<<1;
	}

	/*for(uint32_t i=36;i<TYPE_FLAMINGO_PACKET_LENGTH;i++) 
	{
		BC->rfm69_data[i]=0;	
	}*/
	/*BC->rfm69_data[32]=0;
	BC->rfm69_data[33]=0;
	BC->rfm69_data[34]=0;
	BC->rfm69_data[35]=0;*/

	BC->state = RF_SENDING;
	BA->com_return_setter(com, data);
}

void switch_socket_flamingo1(const ComType com, const SwitchSocketB *data) {
	if(BC->state != RF_IDLE) {
		return;
	}

	change_type(TYPE_FLAMINGO);

//	0xD9762A10,            /* Remote 0, Unit A, Aan */
//	0xDAA47850,                                           /* Remote 0, Unit A, Uit */
//	0xDBDA22E0,                                           /* Remote 0, Unit B, Aan *///
//	0xDBA27220,                                           /* Remote 0, Unit B, Uit *///  
//	0x19BFD260,                                           /* Remote 0, Unit C, Aan //*/
//	0x195EEAA0,                                           /* Remote 0, Unit C, Uit// */  
//	0x984CC650,                                           /* Remote 0, Unit D, Aa//n */  
//	0x9A8C1050,                                           /* Remote 0, Unit D, Uit */  
//	0xDBFFFE90,                                           /* Remote 1, Unit A, Aan */
//	0xD91CEF10,                                           /* Remote 1, Unit A, Uit */  
//	0xDBC52FA0,                                           /* Remote 1, Unit B, Aan */
//	0xD9E35160,                                           /* Remote 1, Unit B, Uit */  
//	0x19B0FE60,                                           /* Remote 1, Unit C, Aan */
//	0x19682B20,                                           /* Remote 1, Unit C, Uit */  
//	0x9924E7D0,                                           /* Remote 1, Unit D, Aan */
//	0x9BA928D0};                                          /* Remote 1, Unit D, Uit */

	uint32_t ui32_Code = 0;
	if(data->switch_to == RFM69_SWITCH_TO_ON) {
		ui32_Code=0xD8458490;
	} else {
		ui32_Code=0xD92F4050;
	}
	
	uint32_t ui32_BitPos=0;

	//add SYNC --> 1 HIGH, 15 LOW
	BC->rfm69_data[ui32_BitPos>>3]<<=1; 
	BC->rfm69_data[ui32_BitPos>>3]|=1; 
	ui32_BitPos++;

	for(uint32_t i=0;i<15;i++)
	{
		BC->rfm69_data[ui32_BitPos>>3]<<=1; 
		ui32_BitPos++;
	}

	for(uint32_t bit=0;bit<32;bit++)
	{
		if (ui32_Code & 0x80000000)
		{
			//one - 1HIGH, 3LOW
			BC->rfm69_data[ui32_BitPos>>3]<<=1; 
			BC->rfm69_data[ui32_BitPos>>3]|=1; 
			ui32_BitPos++;

			BC->rfm69_data[ui32_BitPos>>3]<<=1; 
			ui32_BitPos++;

			BC->rfm69_data[ui32_BitPos>>3]<<=1; 
			ui32_BitPos++;

			BC->rfm69_data[ui32_BitPos>>3]<<=1; 
			ui32_BitPos++;
		}
		else
		{
			//zero - 3HIGH, 1LOW
			BC->rfm69_data[ui32_BitPos>>3]<<=1; 
			BC->rfm69_data[ui32_BitPos>>3]|=1; 
			ui32_BitPos++;

			BC->rfm69_data[ui32_BitPos>>3]<<=1; 
			BC->rfm69_data[ui32_BitPos>>3]|=1; 
			ui32_BitPos++;

			BC->rfm69_data[ui32_BitPos>>3]<<=1; 
			BC->rfm69_data[ui32_BitPos>>3]|=1; 
			ui32_BitPos++;

			BC->rfm69_data[ui32_BitPos>>3]<<=1; 
			ui32_BitPos++;

		}
		//ui32_Code<<=1;
		ui32_Code=ui32_Code<<1;
	}

	while(ui32_BitPos&0x7) 
	{
		BC->rfm69_data[ui32_BitPos>>3]<<=1;	
		ui32_BitPos++;
	}
	for(uint32_t i=(ui32_BitPos>>3);i<64;i++) 
	{
		BC->rfm69_data[i]=0;	
	}

	BC->state = RF_SENDING;
	BA->com_return_setter(com, data);
}


void dim_socket_b(const ComType com, const DimSocketB *data) {
	if(BC->state != RF_IDLE) {
		return;
	}

	change_type(TYPE_B_DIM);

	// Sync
	BC->rfm69_data[0] = 0b00000100;
	BC->rfm69_data[1] = 0b00000000;

	// Address
	for(uint8_t i = 0; i < 26; i++) {
		if(data->address & (1 << i)) {
			BC->rfm69_data[i+2] = RFM69_DATA_B_1;
		} else {
			BC->rfm69_data[i+2] = RFM69_DATA_B_0;
		}
	}

	// Switch All
	if(data->unit == 255) {
		BC->rfm69_data[28] = RFM69_DATA_B_1;
	} else {
		BC->rfm69_data[28] = RFM69_DATA_B_0;
	}

	// Dim bit (we have to shift everything by 4 to the left after here
	BC->rfm69_data[29] = 0b10100000;

	// Unit
	for(uint8_t i = 0; i < 4; i++) {
		if(data->unit & (1 << i)) {
			TYPE_B_DIM_SHIFT(RFM69_DATA_B_1, BC->rfm69_data, i+30);
		} else {
			TYPE_B_DIM_SHIFT(RFM69_DATA_B_0, BC->rfm69_data, i+30);
		}
	}

	// Dim value
	for(uint8_t i = 0; i < 4; i++) {
		if(data->dim_value & (1 << (3-i))) {
			TYPE_B_DIM_SHIFT(RFM69_DATA_B_1, BC->rfm69_data, i+34);
		} else {
			TYPE_B_DIM_SHIFT(RFM69_DATA_B_0, BC->rfm69_data, i+34);
		}
	}

	// Sync
	BC->rfm69_data[37] |= 0b0001000;
	BC->rfm69_data[38] = 0b00000000;
	BC->rfm69_data[39] = 0b00000000;
	BC->rfm69_data[40] = 0b00000000;
	BC->rfm69_data[41] = 0b00000000;
	BC->rfm69_data[42] = 0b00000000;

	BC->state = RF_SENDING;
	BA->com_return_setter(com, data);
}

void switch_socket_c(const ComType com, const SwitchSocketC *data) {
	if(BC->state != RF_IDLE) {
		return;
	}

	uint8_t system_code;
	if(data->system_code >= 'a' && data->system_code <= 'p') {
		system_code = data->system_code - 'a';
	} else if(data->system_code >= 'A' && data->system_code <= 'P') {
		system_code = data->system_code - 'A';
	} else {
		BA->com_return_error(data, sizeof(MessageHeader), MESSAGE_ERROR_CODE_INVALID_PARAMETER, com);
		return;
	}

	if (data->device_code < 1 || data->device_code > 16) {
		BA->com_return_error(data, sizeof(MessageHeader), MESSAGE_ERROR_CODE_INVALID_PARAMETER, com);
		return;
	}

	change_type(TYPE_A_C);

	// System Code
	for(uint8_t i = 0; i < 4; i++) {
		if(system_code & (1 << i)) {
			BC->rfm69_data[i] = RFM69_DATA_FLOAT;
		} else {
			BC->rfm69_data[i] = RFM69_DATA_ON;
		}
	}

	// Device Code
	const uint8_t device_code = data->device_code - 1;
	for(uint8_t i = 0; i < 4; i++) {
		if(device_code & (1 << i)) {
			BC->rfm69_data[i+4] = RFM69_DATA_FLOAT;
		} else {
			BC->rfm69_data[i+4] = RFM69_DATA_ON;
		}
	}

	// Fixed On+Float
	BC->rfm69_data[8] = RFM69_DATA_ON;
	BC->rfm69_data[9] = RFM69_DATA_FLOAT;

	// On/Off
	if(data->switch_to == RFM69_SWITCH_TO_ON) {
		BC->rfm69_data[10] = RFM69_DATA_FLOAT;
		BC->rfm69_data[11] = RFM69_DATA_FLOAT;
	} else {
		BC->rfm69_data[10] = RFM69_DATA_FLOAT;
		BC->rfm69_data[11] = RFM69_DATA_ON;
	}

	// Sync
	BC->rfm69_data[12] = 0b10000000;
	BC->rfm69_data[13] = 0b00000000;
	BC->rfm69_data[14] = 0b00000000;
	BC->rfm69_data[15] = 0b00000000;

	BC->state = RF_SENDING;
	BA->com_return_setter(com, data);
}

void get_switching_state(const ComType com, const GetSwitchingState *data) {
	GetSwitchingStateReturn gssr;
	gssr.header        = data->header;
	gssr.header.length = sizeof(GetSwitchingStateReturn);
	if(BC->state == RF_IDLE) {
		gssr.state         = RFM69_READY;
	} else {
		gssr.state         = RFM69_BUSY;
	}

	BA->send_blocking_with_timeout(&gssr,
	                               sizeof(GetSwitchingStateReturn),
	                               com);
}

void set_repeats(const ComType com, const SetRepeats *data) {
	BC->num_send = data->repeats;
	if(BC->state == RF_IDLE) {
		BC->wait = data->repeats;
	}
	BA->com_return_setter(com, data);
}

void get_repeats(const ComType com, const GetRepeats *data) {
	GetRepeatsReturn grr;
	grr.header        = data->header;
	grr.header.length = sizeof(GetRepeatsReturn);
	grr.repeats       = BC->num_send;

	BA->send_blocking_with_timeout(&grr,
	                               sizeof(GetRepeatsReturn),
	                               com);
}

void rfm69_configure(void) {
	for(uint8_t i = 0; rfm69_config[i][0] != REG_ENDOFCONFIG; i++) {
		rfm69_write_register(rfm69_config[i][0], &rfm69_config[i][1], 1);
	}

	// Default configuration is for type a/c
	BC->current_type = TYPE_A_C;
	BC->current_packet_length = TYPE_A_C_PACKET_LENGTH;
}

void constructor(void) {
	_Static_assert(sizeof(BrickContext) <= BRICKLET_CONTEXT_MAX_SIZE, "BrickContext too big");

	PIN_NSS.type = PIO_OUTPUT_1;
	PIN_NSS.attribute = PIO_DEFAULT;
	BA->PIO_Configure(&PIN_NSS, 1);

	PIN_SCK.type = PIO_OUTPUT_1;
	PIN_SCK.attribute = PIO_DEFAULT;
	BA->PIO_Configure(&PIN_SCK, 1);

	PIN_MOSI.type = PIO_OUTPUT_1;
	PIN_MOSI.attribute = PIO_DEFAULT;
	BA->PIO_Configure(&PIN_MOSI, 1);

	PIN_MISO.type = PIO_INPUT;
	PIN_MISO.attribute = PIO_DEFAULT;
	BA->PIO_Configure(&PIN_MISO, 1);

	rfm69_configure();

	BC->num_send = NUM_SEND_DEFAULT;
	BC->wait = BC->num_send;
	BC->state = RF_IDLE;
	BC->switching_done = false;
}

void destructor(void) {
	PIN_NSS.type = PIO_INPUT;
	PIN_NSS.attribute = PIO_PULLUP;
	BA->PIO_Configure(&PIN_NSS, 1);

	PIN_SCK.type = PIO_INPUT;
	PIN_SCK.attribute = PIO_PULLUP;
	BA->PIO_Configure(&PIN_SCK, 1);

	PIN_MOSI.type = PIO_INPUT;
	PIN_MOSI.attribute = PIO_PULLUP;
	BA->PIO_Configure(&PIN_MOSI, 1);

	PIN_MISO.type = PIO_INPUT;
	PIN_MISO.attribute = PIO_PULLUP;
	BA->PIO_Configure(&PIN_MISO, 1);
}

void tick(const uint8_t tick_type) {
	if(tick_type & TICK_TASK_TYPE_CALCULATION) {
		switch(BC->state) {
			case RF_IDLE: {
				break;
			}

			case RF_SENDING: {
				uint8_t data_opmode;
				rfm69_read_register(REG_OPMODE, &data_opmode, 1);
				if(!(data_opmode & RF_OPMODE_STANDBY)) {
					uint8_t data_irqflags2;
					rfm69_read_register(REG_IRQFLAGS2, &data_irqflags2, 1);
					if((!(data_irqflags2 & RF_IRQFLAGS2_FIFONOTEMPTY))) {
						uint8_t data = RF_OPMODE_STANDBY;
						rfm69_write_register(REG_OPMODE, &data, 1);
					}
				} else {
					BC->state = RF_SEND;
				}
				break;
			}

			case RF_SEND: {
				uint8_t data_irqflags2;
				rfm69_read_register(REG_IRQFLAGS2, &data_irqflags2, 1);
				if((!(data_irqflags2 & RF_IRQFLAGS2_FIFONOTEMPTY))) {
					rfm69_write_register(REG_FIFO, BC->rfm69_data, BC->current_packet_length);
					uint8_t data = RF_OPMODE_TRANSMITTER;
					rfm69_write_register(REG_OPMODE, &data, 1);
					BC->wait--;
					if(BC->wait <= 0) {
						BC->wait = NUM_WAIT_AFTER_SEND;
						BC->state = RF_AFTER_SEND;
					} else {
						BC->state = RF_SENDING;
					}
				}
				break;
			}

			case RF_AFTER_SEND: {
				uint8_t data_opmode;
				rfm69_read_register(REG_OPMODE, &data_opmode, 1);
				if(!(data_opmode & RF_OPMODE_STANDBY)) {
					uint8_t data_irqflags2;
					rfm69_read_register(REG_IRQFLAGS2, &data_irqflags2, 1);
					if((!(data_irqflags2 & RF_IRQFLAGS2_FIFONOTEMPTY))) {
						uint8_t data = RF_OPMODE_STANDBY;
						rfm69_write_register(REG_OPMODE, &data, 1);
					}
				} else {
					BC->state = RF_WAIT_AFTER_SEND;
				}

				break;
			}

			case RF_WAIT_AFTER_SEND: {
				BC->wait--;
				if(BC->wait <= 0) {
					BC->wait = BC->num_send;
					BC->state = RF_IDLE;
					BC->switching_done = true;
				}
				break;
			}

			default: {
				// TODO: Error?
				break;
			}
		}
	}

	if(tick_type & TICK_TASK_TYPE_MESSAGE) {
		if(BC->switching_done) {
			BC->switching_done = false;
			SwitchingDone sd;
			BA->com_make_default_header(&sd, BS->uid, sizeof(SwitchingDone), FID_SWITCHING_DONE);

			BA->send_blocking_with_timeout(&sd,
										   sizeof(SwitchingDone),
										   *BA->com_current);
		}
	}
}

uint8_t spibb_transceive_byte(const uint8_t value) {
	uint8_t recv = 0;

	for(int8_t i = 7; i >= 0; i--) {
		PIN_SCK.pio->PIO_CODR = PIN_SCK.mask;
		if((value >> i) & 1) {
			PIN_MOSI.pio->PIO_SODR = PIN_MOSI.mask;
		} else {
			PIN_MOSI.pio->PIO_CODR = PIN_MOSI.mask;
		}

		SLEEP_US(1);
		if(PIN_MISO.pio->PIO_PDSR & PIN_MISO.mask) {
			recv |= (1 << i);
		}

		PIN_SCK.pio->PIO_SODR = PIN_SCK.mask;
		SLEEP_US(1);
	}

	return recv;
}

void rfm69_write_register(const uint8_t reg, const uint8_t *data, const uint8_t length) {
	SLEEP_US(1);
	PIN_NSS.pio->PIO_CODR = PIN_NSS.mask;
	spibb_transceive_byte(reg | REG_WRITE);
	for(uint8_t i = 0; i < length; i++) {
		spibb_transceive_byte(data[i]);
	}
	PIN_NSS.pio->PIO_SODR = PIN_NSS.mask;
}

void rfm69_read_register(const uint8_t reg, uint8_t *data, const uint8_t length) {
	SLEEP_US(1);
	PIN_NSS.pio->PIO_CODR = PIN_NSS.mask;
	spibb_transceive_byte(reg);
	for(uint8_t i = 1; i <= length; i++) {
		data[length - i] = spibb_transceive_byte(reg + i);
	}
	PIN_NSS.pio->PIO_SODR = PIN_NSS.mask;
}
