/*
 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/KN_nrf24l01.c dated 2015-11-09

#if defined(KN_NRF24L01_INO)

#include "iface_nrf24l01.h"

// Wait for RX chip stable - 10ms
#define KN_INIT_WAIT_MS  10000

//Payload(16 bytes) plus overhead(10 bytes) is 208 bits, takes about 0.4ms or 0.2ms
//to send for the rate of 500kb/s and 1Mb/s respectively.

// Callback timeout period for sending bind packets, minimum 250
#define KN_BINDING_PACKET_PERIOD  1000

// Timeout for sending data packets, in uSec, KN protocol requires 2ms
#define KN_WL_SENDING_PACKET_PERIOD  2000
// Timeout for sending data packets, in uSec, KNFX protocol requires 1.2 ms
#define KN_FX_SENDING_PACKET_PERIOD  1200

// packets to be sent during binding, last 0.5 seconds in WL Toys and 0.2 seconds in Feilun
#define KN_WL_BIND_COUNT 500
#define KN_FX_BIND_COUNT 200 

#define KN_PAYLOADSIZE 16

//24L01 has 126 RF channels, can we use all of them?
#define KN_MAX_RF_CHANNEL 73

//KN protocol for WL Toys changes RF frequency every 10 ms, repeats with only 4 channels.
//Feilun variant uses only 2 channels, so we will just repeat the hopping channels later
#define KN_RF_CH_COUNT 4

//KN protocol for WL Toys sends 4 data packets every 2ms per frequency, plus a 2ms gap.
#define KN_WL_PACKET_SEND_COUNT 5
//KN protocol for Feilun sends 8 data packets every 1.2ms per frequency, plus a 0.3ms gap.
#define KN_FX_PACKET_SEND_COUNT 8
 
#define KN_TX_ADDRESS_SIZE 5

enum {
    KN_PHASE_PRE_BIND,
    KN_PHASE_BINDING,
    KN_PHASE_PRE_SEND,
    KN_PHASE_SENDING,
};

enum {
	KN_FLAG_DR     = 0x01, // Dual Rate: 1 - full range
	KN_FLAG_TH     = 0x02, // Throttle Hold: 1 - hold
	KN_FLAG_IDLEUP = 0x04, // Idle up: 1 - 3D
	KN_FLAG_RES1   = 0x08, // HoverDebugging
	KN_FLAG_RES2   = 0x10,
	KN_FLAG_RES3   = 0x20,
	KN_FLAG_GYRO3  = 0x40, // 0 - 6G mode, 1 - 3G mode
	KN_FLAG_GYROR  = 0x80  // Always 0 so far
};

//-------------------------------------------------------------------------------------------------
// This function init 24L01 regs and packet data for binding
// Send tx address, hopping table (for Wl Toys), and data rate to the KN receiver during binding.
// It seems that KN can remember these parameters, no binding needed after power up.
// Bind uses fixed TX address "KNDZK", 1 Mbps data rate and channel 83
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_bind_init()
{
	NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"KNDZK", 5);
	packet[0]  = 'K';
	packet[1]  = 'N';
	packet[2]  = 'D';
	packet[3]  = 'Z';
	//Use first four bytes of tx_addr
	packet[4]  = rx_tx_addr[0];
	packet[5]  = rx_tx_addr[1];
	packet[6]  = rx_tx_addr[2];
	packet[7]  = rx_tx_addr[3];

	if(sub_protocol==WLTOYS)
	{
		packet[8]  = hopping_frequency[0];
		packet[9]  = hopping_frequency[1];
		packet[10] = hopping_frequency[2];
		packet[11] = hopping_frequency[3];
	}
	else
	{
		packet[8]  = 0x00;
		packet[9]  = 0x00;
		packet[10] = 0x00;
		packet[11] = 0x00;
	}
	packet[12] = 0x00;
	packet[13] = 0x00;
	packet[14] = 0x00;
	packet[15] = 0x01;	//(USE1MBPS_YES) ? 0x01 : 0x00;

	//Set RF channel
	NRF24L01_WriteReg(NRF24L01_05_RF_CH, 83);
}

//-------------------------------------------------------------------------------------------------
// Update control data to be sent
// Do it once per frequency, so the same values will be sent 4 times
// KN uses 4 10-bit data channels plus a 8-bit switch channel
//
// The packet[0] is used for pitch/throttle, the relation is hard coded, not changeable.
// We can change the throttle/pitch range though.
//
// How to use trim? V977 stock controller can trim 6-axis mode to eliminate the drift.
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_update_packet_control_data()
{
	uint16_t value;
	value = convert_channel_10b(THROTTLE, false);
	packet[0]  = (value >> 8) & 0xFF;
	packet[1]  = value & 0xFF;
	value = convert_channel_10b(AILERON, false);
	packet[2]  = (value >> 8) & 0xFF;
	packet[3]  = value & 0xFF;
	value = convert_channel_10b(ELEVATOR, false);
	packet[4]  = (value >> 8) & 0xFF;
	packet[5]  = value & 0xFF;
	value = convert_channel_10b(RUDDER, false);
	packet[6]  = (value >> 8) & 0xFF;
	packet[7]  = value & 0xFF;
	// Trims, middle is 0x64 (100) range 0-200
	packet[8]  = convert_channel_16b_limit(CH9,0,200); // 0x64; // T
	packet[9]  = convert_channel_16b_limit(CH10,0,200); // 0x64; // A
	packet[10] = convert_channel_16b_limit(CH11,0,200); // 0x64; // E
	packet[11] = convert_channel_16b_limit(CH12,0,200); // 0x64; // R

	packet[12] = GET_FLAG(CH5_SW,  KN_FLAG_DR)
				|GET_FLAG(CH6_SW,  KN_FLAG_TH)
				|GET_FLAG(CH7_SW,  KN_FLAG_IDLEUP)
				|GET_FLAG(CH8_SW,  KN_FLAG_GYRO3)
				|GET_FLAG(CH13_SW, KN_FLAG_RES1);	//Hover debugging

	packet[13] = 0x00;
	if(sub_protocol==WLTOYS)
		packet[13] = (packet_sent << 5) | (hopping_frequency_no << 2);

	packet[14] = 0x00;
	packet[15] = 0x00;

	NRF24L01_SetPower();
}


//-------------------------------------------------------------------------------------------------
// This function generate RF TX packet address
// V977 can remember the binding parameters; we do not need rebind when power up.
// This requires the address must be repeatable for a specific RF ID at power up.
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_calculate_tx_addr()
{
	if(sub_protocol==FEILUN)
	{
		uint8_t addr2;
		// Generate TXID with sum of minimum 256 and maximum 256+MAX_RF_CHANNEL-32
		rx_tx_addr[1] = 1 + rx_tx_addr[0] % (KN_MAX_RF_CHANNEL-33);
		addr2 = 1 + rx_tx_addr[2] % (KN_MAX_RF_CHANNEL-33);
		if ((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1]) < 256)
			rx_tx_addr[2] = addr2;
		else
			rx_tx_addr[2] = 0x00;
		rx_tx_addr[3] = 0x00;
		while((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]) < 257)
			rx_tx_addr[3] += addr2;
	}
    //The 5th byte is a constant, must be 'K'
    rx_tx_addr[4] = 'K';
}

//-------------------------------------------------------------------------------------------------
// This function generates "random" RF hopping frequency channel numbers.
// These numbers must be repeatable for a specific seed
// The generated number range is from 0 to MAX_RF_CHANNEL. No repeat or adjacent numbers
//
// For Feilun variant, the channels are calculated from TXID, and since only 2 channels are used
// we copy them to fill up to MAX_RF_CHANNEL
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) kn_calculate_freqency_hopping_channels()
{
	if(sub_protocol==WLTOYS)
	{
		uint8_t idx = 0;
		uint32_t rnd = MProtocol_id;
		while (idx < KN_RF_CH_COUNT)
		{
			uint8_t i;
			rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization

			// Use least-significant byte. 73 is prime, so channels 76..77 are unused
			uint8_t next_ch = ((rnd >> 8) % KN_MAX_RF_CHANNEL) + 2;
			// Keep the distance 2 between the channels - either odd or even
			if (((next_ch ^ MProtocol_id) & 0x01 )== 0)
				continue;
			// Check that it's not duplicate and spread uniformly
			for (i = 0; i < idx; i++)
				if(hopping_frequency[i] == next_ch)
					break;
			if (i != idx)
				continue;
			hopping_frequency[idx++] = next_ch;
		}
	}
	else
	{//FEILUN
		hopping_frequency[0] = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]; // - 256; ???
		hopping_frequency[1] = hopping_frequency[0] + 32;
		hopping_frequency[2] = hopping_frequency[0];
		hopping_frequency[3] = hopping_frequency[1];
	}
}

//-------------------------------------------------------------------------------------------------
// This function setup 24L01
// V977 uses one way communication, receiving only. 24L01 RX is never enabled.
// V977 needs payload length in the packet. We should configure 24L01 to enable Packet Control Field(PCF)
//   Some RX reg settings are actually for enable PCF
//-------------------------------------------------------------------------------------------------
static void __attribute__((unused)) KN_RF_init()
{
	kn_calculate_tx_addr();
	kn_calculate_freqency_hopping_channels();

	NRF24L01_Initialize();

	NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20);   // bytes of data payload for pipe 0
	NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0
	// Enable: Dynamic Payload Length to enable PCF
	NRF24L01_WriteReg(NRF24L01_1D_FEATURE, _BV(NRF2401_1D_EN_DPL));

	NRF24L01_SetTxRxMode(TX_EN);						// Clear data ready, data sent, retransmit and enable CRC 16bits, ready for TX
}
  
//================================================================================================
// Private Functions
//================================================================================================
void KN_init()
{
	if(sub_protocol==WLTOYS)
	{
		packet_period = KN_WL_SENDING_PACKET_PERIOD;
		bind_counter  = KN_WL_BIND_COUNT;
		packet_count  = KN_WL_PACKET_SEND_COUNT;
		seed = KN_WL_PACKET_SEND_COUNT * KN_WL_SENDING_PACKET_PERIOD;
	}
	else
	{
		packet_period = KN_FX_SENDING_PACKET_PERIOD;
		bind_counter  = KN_FX_BIND_COUNT;
		packet_count  = KN_FX_PACKET_SEND_COUNT;
		seed = KN_FX_PACKET_SEND_COUNT * KN_FX_SENDING_PACKET_PERIOD;
	}
	KN_RF_init();
	phase = IS_BIND_IN_PROGRESS ? KN_PHASE_PRE_BIND : KN_PHASE_PRE_SEND;
}

uint16_t KN_callback()
{
	switch (phase)
	{
		case KN_PHASE_PRE_BIND:
			kn_bind_init();
			phase=KN_PHASE_BINDING;
			//Do once, no break needed
		case KN_PHASE_BINDING:
			if(bind_counter>0)
			{
				bind_counter--;
				NRF24L01_WritePayload(packet, KN_PAYLOADSIZE);
				return KN_BINDING_PACKET_PERIOD;
			}
			BIND_DONE;
			//Continue
		case KN_PHASE_PRE_SEND:
			packet_sent = 0;
			hopping_frequency_no = 0;
			NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, KN_TX_ADDRESS_SIZE);
			phase = KN_PHASE_SENDING;
			//Do once, no break needed
		case KN_PHASE_SENDING:
			if(packet_sent >= packet_count)
			{
				#ifdef MULTI_SYNC
					telemetry_set_input_sync(seed);
				#endif
				packet_sent = 0;
				hopping_frequency_no++;
				if(hopping_frequency_no >= KN_RF_CH_COUNT) hopping_frequency_no = 0;
				kn_update_packet_control_data();
				NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
			}
			else
			{
				// Update sending count and RF channel index.
				// The protocol sends 4 data packets every 2ms per frequency, plus a 2ms gap.
				// Each data packet need a packet number and RF channel index
				packet[13] = 0x00;
				if(sub_protocol==WLTOYS)
					packet[13] = (packet_sent << 5) | (hopping_frequency_no << 2);
			}
			NRF24L01_WritePayload(packet, KN_PAYLOADSIZE);
			packet_sent++;
			return packet_period;
	} //switch
 
    //Bad things happened, reset
    packet_sent = 0;
    phase = KN_PHASE_PRE_SEND;
    return packet_period;
}

#endif
