/*
 This project is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 Multiprotocol 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 General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with Multiprotocol.  If not, see <http://www.gnu.org/licenses/>.
 */


#if defined(FRSKYL_CC2500_INO)

#include "iface_cc2500.h"

//#define FRSKYL_FORCE_ID
#define FRSKYL_PACKET_LEN	256
#define FRSKYL_PERIOD		18000

uint8_t FrSkyL_buffer[FRSKYL_PACKET_LEN];

static void __attribute__((unused)) FrSkyL_build_bind_packet()
{
	//Header
	packet[0] = 0x4E;				// Unknown but constant
	//Bind packet
	memset(&packet[1],0x00,3);
	//ID
	packet[4 ] = rx_tx_addr[3];		// ID
	packet[5 ] = rx_tx_addr[2];		// ID
	int idx = ((state -FRSKY_BIND) % 10) * 5;
	packet[6 ] = idx;
	packet[7 ] = hopping_frequency[idx++];
	packet[8 ] = hopping_frequency[idx++];
	packet[9 ] = hopping_frequency[idx++];
	packet[10] = hopping_frequency[idx++];
	packet[11] = hopping_frequency[idx++];
	packet[12] = rx_tx_addr[1];		// ID or hw ver?
	packet[13] = RX_num;
	packet[14] = 0x00;				// Unknown but constant
	//CRC
	uint16_t lcrc = FrSkyX_crc(&packet[1], 14);
	packet[15] = lcrc >> 8;
	packet[16] = lcrc;
	//Debug
/*	debug("Bind:");
	for(uint8_t i=0;i<17;i++)
		debug(" %02X",packet[i]);
	debugln("");*/
}

static void __attribute__((unused)) FrSkyL_build_packet()
{
	static uint8_t chan_offset=0;
	uint16_t chan_0,chan_1;

	//Header
	packet[0 ] = 0x4E;				// Unknown but constant
	//ID
	packet[1 ] = rx_tx_addr[3];		// ID
	packet[2 ] = rx_tx_addr[2];		// ID
	packet[3 ] = rx_tx_addr[1];		// ID or hw ver?
	//skip_hop
	packet[4 ] = (FrSkyX_chanskip<<6)|hopping_frequency_no; 
	packet[5 ] = FrSkyX_chanskip>>2;
	//Channels
	uint8_t startChan = chan_offset;
	for(uint8_t i = 0; i <9 ; i+=3)
	{//9 bytes of channel data
		chan_0 = FrSkyX_scaleForPXX(startChan,6);
		startChan++;
		//
		chan_1 = FrSkyX_scaleForPXX(startChan,6);
		startChan++;
		//
		packet[6+i] = lowByte(chan_0);									//3 bytes*4
		packet[6+i+1]=(((chan_0>>8) & 0x0F)|(chan_1 << 4));
		packet[6+i+2]=chan_1>>4;
	}
	if(sub_protocol & 0x01 )											//6ch mode only??
		chan_offset = 0 ;
	else
		chan_offset^=0x06;
	//CRC
	uint16_t lcrc = FrSkyX_crc(&packet[1], 14, RX_num);
	packet[15] = lcrc >> 8;
	packet[16] = lcrc;
	//Debug
	/*debug("Norm:");
	for(uint8_t i=0;i<17;i++)
		debug(" %02X",packet[i]);
	debugln("");*/
}

static void __attribute__((unused))  FrSkyL_encode_packet(bool type)
{
	#define FRSKYL_BIT0 0xED
	#define FRSKYL_BIT1 0x712
	
	uint32_t bits = 0;
	uint8_t bitsavailable = 0;
	uint8_t idx = 0,len=6;
	if(type)
	{//just replace packet content
		idx=66;
		len=17;
	}

	//debugln("Encode:");
	for (uint8_t i = 0; i < len; i++)
	{
		uint8_t tmp=packet[i];
		//debug("%02X =",tmp);
		for(uint8_t j=0;j<8;j++)
		{
			bits <<= 11;
			if(tmp&0x01)
				bits |= FRSKYL_BIT1;
			else
				bits |= FRSKYL_BIT0;
			tmp >>=1;
			bitsavailable += 11;
			while (bitsavailable >= 8) {
				uint32_t bits_tmp=bits>>(bitsavailable-8);
				bitsavailable -= 8;
				FrSkyL_buffer[idx] = bits_tmp;
				//debug(" %02X",FrSkyL_buffer[idx]);
				idx++;
			}
		}
		//debugln("");
	}
}

uint16_t FRSKYL_callback()
{
	static uint8_t written=0, send=0;
	switch(send)
	{
		case 1:
			CC2500_Strobe(CC2500_SIDLE);
			CC2500_Strobe(CC2500_SFTX);
			CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, FrSkyL_buffer, 64);
			CC2500_Strobe(CC2500_STX);
			CC2500_Strobe(CC2500_SIDLE);	// This cancels the current transmission???
			CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, FrSkyL_buffer, 64);
			CC2500_Strobe(CC2500_SFTX);		// This just clears what we've written???
			CC2500_Strobe(CC2500_STX);
			CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, FrSkyL_buffer, 64);
			written=64;
			send++;
			return 2623;
		case 2:
			len=FRSKYL_PACKET_LEN-written;
			if(len>31)
				len=31;
			CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, FrSkyL_buffer+written, len);
			written+=len;
			if(len!=31)			//everything has been sent
			{
				send=0;
				return 2936;
			}
			return 1984;
	}
	
	switch(state)
	{	
		default: 
			//Bind
			#ifdef MULTI_SYNC
				telemetry_set_input_sync(9000);
			#endif
			FrSkyX_set_start(47);
			CC2500_SetPower();
			CC2500_Strobe(CC2500_SFRX);
			//		
			FrSkyL_build_bind_packet();
			FrSkyL_encode_packet(true);

			CC2500_Strobe(CC2500_SIDLE);
			if(IS_BIND_DONE)
				state = FRSKY_BIND_DONE;
			else
			{
				state++;
				send=1;
			}
			return 537;
		case FRSKY_BIND_DONE:
			FrSkyX_initialize_data(0);
			hopping_frequency_no=0;
			BIND_DONE;
			state++;													//FRSKY_DATA1
			break;

		case FRSKY_DATA1:
			CC2500_SetFreqOffset();
			FrSkyX_set_start(hopping_frequency_no);
			FrSkyL_build_packet();
			FrSkyL_encode_packet(true);
			CC2500_SetPower();
			hopping_frequency_no = (hopping_frequency_no+FrSkyX_chanskip)%47;
			send=1;
			return 537;
	}		
	return 1;		
}

void FRSKYL_init()
{
	set_rx_tx_addr(MProtocol_id_master);
	rx_tx_addr[1]=0x02;		// ID related, hw version?

	#ifdef FRSKYL_FORCE_ID
		rx_tx_addr[3]=0x0E;
		rx_tx_addr[2]=0x1C;
		rx_tx_addr[1]=0x02;
	#endif
	FrSkyX2_init_hop();
	
	while(!FrSkyX_chanskip)
		FrSkyX_chanskip=random(0xfefefefe)%47;

	FrSkyX_RF_init();

	//Prepare frame
	memset(FrSkyL_buffer,0x00,FRSKYL_PACKET_LEN-3);
	memset(&FrSkyL_buffer[FRSKYL_PACKET_LEN-3],0x55,3);
	memset(packet,0xAA,6);
	FrSkyL_encode_packet(false);
	/*debugln("Frame:");
	for(uint16_t i=0;i<FRSKYL_PACKET_LEN;i++)
	{
		debug(" %02X",FrSkyL_buffer[i]);
		if(i%11==10)
			debugln("");
	}
	debugln("");*/
	
	if(IS_BIND_IN_PROGRESS)
	{	   
		state = FRSKY_BIND;
		FrSkyX_initialize_data(1);
	}
	else
	{
		state = FRSKY_DATA1;
		FrSkyX_initialize_data(0);
	}
}	
#endif
