/*
 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/>.
 */
// Last sync with hexfet new_protocols/fy326_nrf24l01.c dated 2015-07-29

#if defined(FY326_NRF24L01_INO)

#include "iface_nrf24l01.h"

#define FY326_INITIAL_WAIT		500
#define FY326_PACKET_PERIOD		1500
#define FY326_PACKET_CHKTIME	300
#define FY326_PACKET_SIZE		15
#define FY326_BIND_COUNT		16
#define FY326_RF_BIND_CHANNEL	0x17
#define FY326_NUM_RF_CHANNELS	5

enum {
    FY326_BIND1=0,
    FY326_BIND2,
    FY326_DATA,
    FY319_BIND1,
    FY319_BIND2,
};

#define rxid channel

#define CHAN_TO_TRIM(chanval) ((chanval/10)-10)
static void __attribute__((unused)) FY326_send_packet(uint8_t bind)
{
	packet[0] = rx_tx_addr[3];
	if(bind)
		packet[1] = 0x55;
	else
		packet[1] =	  GET_FLAG(CH7_SW,	0x80)	// Headless
					| GET_FLAG(CH6_SW,	0x40)	// RTH
					| GET_FLAG(CH5_SW,	0x02)	// Flip
					| GET_FLAG(CH9_SW,	0x01)	// Calibrate
					| GET_FLAG(CH8_SW,	0x04);	// Expert
	packet[2]  = convert_channel_16b_limit(AILERON, 0, 200);	// aileron
	packet[3]  = convert_channel_16b_limit(ELEVATOR, 0, 200);		// elevator
	packet[4]  = convert_channel_16b_limit(RUDDER, 0, 200);	// rudder
	packet[5]  = convert_channel_16b_limit(THROTTLE, 0, 200);		// throttle
	if(sub_protocol==FY319)
	{
		packet[6] = convert_channel_8b(AILERON);
		packet[7] = convert_channel_8b(ELEVATOR);
		packet[8] = convert_channel_8b(RUDDER);
	}
	else
	{
		packet[6]  = rx_tx_addr[0];
		packet[7]  = rx_tx_addr[1];
		packet[8]  = rx_tx_addr[2];
	}
	packet[9]  = CHAN_TO_TRIM(packet[2]);	// aileron_trim;
	packet[10] = CHAN_TO_TRIM(packet[3]);	// elevator_trim;
	packet[11] = CHAN_TO_TRIM(packet[4]);	// rudder_trim;
	packet[12] = 0;							// throttle_trim;
	packet[13] = rxid;
	packet[14] = rx_tx_addr[4];

	if (bind)
		NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL);
	else
	{
		NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
		hopping_frequency_no %= FY326_NUM_RF_CHANNELS;
	}

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

	NRF24L01_WritePayload(packet, FY326_PACKET_SIZE);

	NRF24L01_SetPower();	// Set tx_power
}

static void __attribute__((unused)) FY326_RF_init()
{
	NRF24L01_Initialize();

	if(sub_protocol==FY319)
		NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);   // Five-byte rx/tx address
	else
		NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01);   // Three-byte rx/tx address
	NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR,    (uint8_t *)"\x15\x59\x23\xc6\x29", 5);
	NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x15\x59\x23\xc6\x29", 5);
    NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, FY326_PACKET_SIZE);
    NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL);
    NRF24L01_SetBitrate(NRF24L01_BR_250K);

    NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f);
    NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07);

	//Switch to RX
	NRF24L01_SetTxRxMode(TXRX_OFF);
	NRF24L01_SetTxRxMode(RX_EN);
}

uint16_t FY326_callback()
{
	switch (phase)
	{
		case FY319_BIND1:
			if(NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
			{
				NRF24L01_ReadPayload(packet, FY326_PACKET_SIZE);
				rxid = packet[13];
				packet[0] = rx_tx_addr[3];
				packet[1] = 0x80;
				packet[14]= rx_tx_addr[4];
				NRF24L01_SetTxRxMode(TXRX_OFF);
				NRF24L01_SetTxRxMode(TX_EN);
				NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
				NRF24L01_FlushTx();
				bind_counter = 255;
				for(uint8_t i=2; i<6; i++)
					packet[i] = hopping_frequency[0];
				phase = FY319_BIND2;
			}
			return FY326_PACKET_CHKTIME;
			break;
		case FY319_BIND2:
			NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
			NRF24L01_FlushTx();
			NRF24L01_WritePayload(packet, FY326_PACKET_SIZE);
			if(bind_counter == 250)
				packet[1] = 0x40;
			if(--bind_counter == 0)
			{
				BIND_DONE;
				phase = FY326_DATA;
			}
			break;
		case FY326_BIND1:
			if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
			{ // RX fifo data ready
				NRF24L01_ReadPayload(packet, FY326_PACKET_SIZE);
				rxid = packet[13];
				rx_tx_addr[0] = 0xAA;
				NRF24L01_SetTxRxMode(TXRX_OFF);
				NRF24L01_SetTxRxMode(TX_EN);
				BIND_DONE;
				phase = FY326_DATA;
			}
			else
				if (bind_counter-- == 0)
				{
					bind_counter = FY326_BIND_COUNT;
					NRF24L01_SetTxRxMode(TXRX_OFF);
					NRF24L01_SetTxRxMode(TX_EN);
					FY326_send_packet(1);
					phase = FY326_BIND2;
					return FY326_PACKET_CHKTIME;
				}
			break;
		case FY326_BIND2:
			if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_TX_DS))
			{ // TX data sent -> switch to RX mode
				NRF24L01_SetTxRxMode(TXRX_OFF);
				NRF24L01_FlushRx();
				NRF24L01_SetTxRxMode(RX_EN);
				phase = FY326_BIND1;
			}
			else
				return FY326_PACKET_CHKTIME;
			break;
		case FY326_DATA:
			#ifdef MULTI_SYNC
				telemetry_set_input_sync(FY326_PACKET_PERIOD);
			#endif
			FY326_send_packet(0);
			break;
	}
	return FY326_PACKET_PERIOD;
}

static void __attribute__((unused)) FY326_initialize_txid()
{
	hopping_frequency[0] = 		  (rx_tx_addr[0]&0x0f);
	hopping_frequency[1] = 0x10 + (rx_tx_addr[0] >> 4);
	hopping_frequency[2] = 0x20 + (rx_tx_addr[1]&0x0f);
	hopping_frequency[3] = 0x30 + (rx_tx_addr[1] >> 4);
	hopping_frequency[4] = 0x40 + (rx_tx_addr[2] >> 4);
	if(sub_protocol==FY319)
		for(uint8_t i=0;i<5;i++)
			hopping_frequency[i]=rx_tx_addr[0] & ~0x80;
}

void FY326_init(void)
{
	BIND_IN_PROGRESS;	// autobind protocol
    rxid = 0xAA;
	bind_counter = FY326_BIND_COUNT;
	FY326_initialize_txid();
	FY326_RF_init();
	if(sub_protocol==FY319)
	{
		phase=FY319_BIND1;
	}
	else
		phase=FY326_BIND1;
}

#endif
