/*
 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/>.
 */
//  ESky protocol for small models since 2014 (150, 300, 150X, ...)

#if defined(ESKY150_NRF24L01_INO)

#include "iface_nrf24l01.h"

#define ESKY150_PAYLOADSIZE 15
#define ESKY150_TX_ADDRESS_SIZE 4
#define ESKY150_BINDING_PACKET_PERIOD	2000
#define ESKY150_SENDING_PACKET_PERIOD	4800

static void __attribute__((unused)) ESKY150_RF_init()
{
	//Original TX always sets for channelx 0x22 and 0x4a
	// Use channels 2..79
	hopping_frequency[0] = rx_tx_addr[3]%37+2;
	hopping_frequency[1] = hopping_frequency[0] + 40;

	NRF24L01_Initialize();
	NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02);   // 4-byte RX/TX address
	NRF24L01_SetBitrate(NRF24L01_BR_2M);
	NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, ESKY150_PAYLOADSIZE);   // bytes of data payload for pipe 0
	NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, ESKY150_TX_ADDRESS_SIZE);

	NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
	// Enable: Dynamic Payload Length, Payload with ACK , W_TX_PAYLOAD_NOACK
	NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL) | _BV(NRF2401_1D_EN_ACK_PAY) | _BV(NRF2401_1D_EN_DYN_ACK));

	NRF24L01_SetTxRxMode(TX_EN);						// Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
}

static void __attribute__((unused)) ESKY150_bind_init()
{
	uint8_t ESKY150_addr[ESKY150_TX_ADDRESS_SIZE] = { 0x73, 0x73, 0x74, 0x63 }; //This RX address "sstc" is fixed for ESky2

	// Build packet
	packet[0]  = rx_tx_addr[0];
	packet[1]  = rx_tx_addr[1];
	packet[2]  = rx_tx_addr[2];
	packet[3]  = rx_tx_addr[3]; 
	packet[4]  = ESKY150_addr[0];
	packet[5]  = ESKY150_addr[1];
	packet[6]  = ESKY150_addr[2];
	packet[7]  = ESKY150_addr[3];
	packet[8]  = rx_tx_addr[0];
	packet[9]  = rx_tx_addr[1];
	packet[10] = rx_tx_addr[2];
	packet[11] = rx_tx_addr[3]; 
	packet[12] = 0;
	packet[13] = 0;
	packet[14] = 0;

	// Bind address
	NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, ESKY150_addr, ESKY150_TX_ADDRESS_SIZE);
	NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, ESKY150_addr, ESKY150_TX_ADDRESS_SIZE);
	
	// Bind Channel 1
	NRF24L01_WriteReg(NRF24L01_05_RF_CH, 1);
}

static void __attribute__((unused)) ESKY150_send_packet()
{
	// Build packet
	uint16_t throttle=convert_channel_16b_limit(THROTTLE,1000,2000);
	uint16_t aileron=convert_channel_16b_limit(AILERON,1000,2000);
	uint16_t elevator=convert_channel_16b_limit(ELEVATOR,1000,2000);
	uint16_t rudder=convert_channel_16b_limit(RUDDER,1000,2000);
	//set unused channels to zero, for compatibility with older 4 channel models
	uint8_t flight_mode=0;
	uint16_t aux_ch6=0;
	uint8_t aux_ch7=0;
	if(sub_protocol)
	{ // 7 channels
		flight_mode=ESKY150_convert_2bit_channel(CH5);
		aux_ch6=convert_channel_16b_limit(CH6,1000,2000);
		aux_ch7=ESKY150_convert_2bit_channel(CH7);
	}
	packet[0]  = hopping_frequency[0];
	packet[1]  = hopping_frequency[1];
	packet[2]  = ((flight_mode << 6) & 0xC0) | ((aux_ch7 << 4) & 0x30) | ((throttle >> 8) & 0xFF);
	packet[3]  = throttle & 0xFF;
	packet[4]  = ((aux_ch6 >> 4) & 0xF0) | ((aileron >> 8) & 0xFF); //and 0xFF works as values are anyways not bigger than 12 bits, but faster code like that
	packet[5]  = aileron  & 0xFF;
	packet[6]  = (aux_ch6 & 0xF0) | ((elevator >> 8) & 0xFF); //and 0xFF works as values are anyways not bigger than 12 bits, but faster code like that
	packet[7]  = elevator & 0xFF;
	packet[8]  = ((aux_ch6 << 4) & 0xF0) | ((rudder >> 8) & 0xFF); //and 0xFF works as values are anyways not bigger than 12 bits, but faster code like that
	packet[9]  = rudder & 0xFF;
	// The next 4 Bytes are sint8 trim values (TAER). As trims are already included within normal outputs, these values are set to zero.
	packet[10] = 0x00;
	packet[11] = 0x00;
	packet[12] = 0x00;
	packet[13] = 0x00;
	// Calculate checksum:
	uint8_t sum = 0;
	for (uint8_t i = 0; i < 14; ++i)
		sum += packet[i];
	packet[14] = sum;

	// Hop on 2 channels
	hopping_frequency_no++;
	hopping_frequency_no&=0x01;
	NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);

	// Clear packet status bits and TX FIFO
	NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
	NRF24L01_FlushTx();

	// Send packet
	NRF24L01_WritePayload(packet, ESKY150_PAYLOADSIZE);

	//Keep transmit power updated
	NRF24L01_SetPower();
}

uint8_t ESKY150_convert_2bit_channel(uint8_t num)
{
	if(Channel_data[num] > CHANNEL_MAX_COMMAND)
		return 0x03;
	else
		if(Channel_data[num] < CHANNEL_MIN_COMMAND)
			return 0x00;
		else
			if(Channel_data[num] > CHANNEL_SWITCH)
				return 0x02;
	return 0x01;	
}

uint16_t ESKY150_callback()
{
	if(IS_BIND_DONE)
	{
		#ifdef MULTI_SYNC
			telemetry_set_input_sync(ESKY150_SENDING_PACKET_PERIOD);
		#endif
		ESKY150_send_packet();
	}
	else
	{
		NRF24L01_WritePayload(packet, ESKY150_PAYLOADSIZE);
		if (--bind_counter == 0)
		{
			BIND_DONE;
			// Change TX address from bind to normal mode
			NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, ESKY150_TX_ADDRESS_SIZE);
		}
		return ESKY150_BINDING_PACKET_PERIOD;
	}
	return ESKY150_SENDING_PACKET_PERIOD;
}

void ESKY150_init(void)
{
	ESKY150_RF_init();
	if(IS_BIND_IN_PROGRESS)
	{
		bind_counter=3000;
		ESKY150_bind_init();
	}
	hopping_frequency_no=0;
}

#endif