/*********************************************************
					Multiprotocol Tx code
               by Midelic and Pascal Langer(hpnuts)
	http://www.rcgroups.com/forums/showthread.php?t=2165676
    https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/edit/master/README.md
	Thanks to PhracturedBlue, Hexfet, Goebish and all protocol developers
				Ported  from deviation firmware 
 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 .
*/
#include 
#include 
#include 
#include "Multiprotocol.h"
//Multiprotocol module configuration file
#include "_Config.h"
//Global constants/variables
uint32_t MProtocol_id;//tx id,
uint32_t MProtocol_id_master;
uint32_t Model_fixed_id=0;
uint32_t fixed_id;
uint8_t  cyrfmfg_id[6];//for dsm2 and devo
uint32_t blink=0;
//
uint16_t counter;
uint8_t  channel;
uint8_t  packet[40];
#define NUM_CHN 16
// Servo data
uint16_t Servo_data[NUM_CHN];
uint8_t  Servo_AUX;
// Protocol variables
uint8_t  rx_tx_addr[5];
uint8_t  phase;
uint16_t bind_counter;
uint8_t  bind_phase;
uint8_t  binding_idx;
uint32_t packet_counter;
uint16_t packet_period;
uint8_t  packet_count;
uint8_t  packet_sent;
uint8_t  packet_length;
uint8_t  hopping_frequency[23];
uint8_t  *hopping_frequency_ptr;
uint8_t  hopping_frequency_no=0;
uint8_t  rf_ch_num;
uint8_t  throttle, rudder, elevator, aileron;
uint8_t  flags;
uint16_t crc;
//
uint32_t state;
uint8_t  len;
uint8_t  RX_num;
// Mode_select variables
uint8_t mode_select;
uint8_t protocol_flags=0,protocol_flags2=0;
// PPM variable
volatile uint16_t PPM_data[NUM_CHN];
// Serial variables
#define RXBUFFER_SIZE 25
#define TXBUFFER_SIZE 12
volatile uint8_t rx_buff[RXBUFFER_SIZE];
volatile uint8_t rx_ok_buff[RXBUFFER_SIZE];
volatile uint8_t tx_buff[TXBUFFER_SIZE];
volatile uint8_t idx = 0;
//Serial protocol
uint8_t sub_protocol;
uint8_t option;
uint8_t cur_protocol[2];
uint8_t prev_protocol=0;
// Telemetry
#define MAX_PKT 27
uint8_t pkt[MAX_PKT];//telemetry receiving packets
#if defined(TELEMETRY)
	uint8_t pktt[MAX_PKT];//telemetry receiving packets
	volatile uint8_t tx_head;
	volatile uint8_t tx_tail;
	uint8_t v_lipo;
	int16_t RSSI_dBm;
	//const uint8_t RSSI_offset=72;//69 71.72 values db
	uint8_t telemetry_link=0; 
	uint8_t telemetry_counter=0;
#endif 
// Callback
typedef uint16_t (*void_function_t) (void);//pointer to a function with no parameters which return an uint16_t integer
void_function_t remote_callback = 0;
static void CheckTimer(uint16_t (*cb)(void));
// Init
void setup()
{
	// General pinout
	DDRD = (1<>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0
//**********************************
//mode_select=14;	// here to test PPM
//**********************************
	// Update LED
	LED_OFF;
	LED_SET_OUTPUT; 
	// Read or create protocol id
	MProtocol_id_master=random_id(10,false);
	//Init RF modules
	#ifdef	CC2500_INSTALLED
		CC2500_Reset();
	#endif
	//Protocol and interrupts initialization
	if(mode_select != MODE_SERIAL)
	{ // PPM
		mode_select--;
		cur_protocol[0]	=	PPM_prot[mode_select].protocol;
		sub_protocol   	=	PPM_prot[mode_select].sub_proto;
		RX_num			=	PPM_prot[mode_select].rx_num;
		MProtocol_id	=	RX_num + MProtocol_id_master;
		option			=	PPM_prot[mode_select].option;
		if(PPM_prot[mode_select].power)		POWER_FLAG_on;
		if(PPM_prot[mode_select].autobind)	AUTOBIND_FLAG_on;
		mode_select++;
		protocol_init();
		//Configure PPM interrupt
		EICRA |=(1<PPM_SWITCH)
			Servo_AUX|=1< led on
				else
					blink+=BLINK_BIND_TIME;				//blink fastly during binding
		LED_TOGGLE;
	}
}
// Protocol scheduler
static void CheckTimer(uint16_t (*cb)(void))
{ 
	uint16_t next_callback;
	uint32_t prev;
	if( (TIFR1 & (1< micros())
	{ // Callback did not took more than requested time for next callback
		if(next_callback>32000)
		{ // next_callback should not be more than 32767 so we will wait here...
			delayMicroseconds(next_callback-2000);
			cli();			// disable global int
			OCR1A=TCNT1+4000;
			sei();			// enable global int
		}
		else
		{
			cli();			// disable global int
			OCR1A+=next_callback*2;		// set compare A for callback
			sei();			// enable global int
		}
		TIFR1=(1<32000)
	{ // next_callback should not be more than 32767 so we will wait here...
		delayMicroseconds(next_callback-2000);
		next_callback=2000;
	}
	cli();							// disable global int
	OCR1A=TCNT1+next_callback*2;	// set compare A for callback
	sei();							// enable global int
	TIFR1=(1<>4)& 0x07;					//subprotocol no (0-7) bits 4-6
		RX_num=rx_ok_buff[1]& 0x0F;
		MProtocol_id=MProtocol_id_master+RX_num;	//personalized RX bind + rx num // rx_num bits 0---3
	}
	else
		if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) )	// Bind flag has been set
			CHANGE_PROTOCOL_FLAG_on;			//restart protocol with bind
	cur_protocol[0] = rx_ok_buff[0];			//store current protocol
	// decode channel values
	volatile uint8_t *p=rx_ok_buff+2;
	uint8_t dec=-3;
	for(uint8_t i=0;i=8)
		{
			dec-=8;
			p++;
		}
		p++;
		Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860;	//value range 860<->2140 -125%<->+125%
	}
	RX_FLAG_off;								//data has been processed
}
static void module_reset()
{
	if(remote_callback)
	{		// previous protocol loaded
		remote_callback = 0;
		switch(prev_protocol)
		{
			case MODE_FLYSKY:
			case MODE_HUBSAN:
				A7105_Reset();
				break;
			case MODE_FRSKY:
			case MODE_FRSKYX:
				CC2500_Reset();
				break;
			case MODE_DSM2:
			case MODE_DEVO:
				CYRF_Reset();
				break;
			default:	// MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ
				NRF24L01_Reset();
				break;
		}
	}
}
// Channel value is converted to 8bit values full scale
uint8_t convert_channel_8b(uint8_t num)
{
	return (uint8_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,0,255));	
}
// Channel value is converted to 8bit values to provided values scale
uint8_t convert_channel_8b_scale(uint8_t num,uint8_t min,uint8_t max)
{
	return (uint8_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,min,max));	
}
// Channel value is converted sign + magnitude 8bit values
uint8_t convert_channel_s8b(uint8_t num)
{
	uint8_t ch;
	ch = convert_channel_8b(num);
	return (ch < 128 ? 127-ch : ch);	
}
// Channel value is converted to 10bit values
uint16_t convert_channel_10b(uint8_t num)
{
	return (uint16_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,1,1023));
}
// Channel value is multiplied by 1.5
uint16_t convert_channel_frsky(uint8_t num)
{
	return Servo_data[num] + Servo_data[num]/2;
}
// Channel value is converted for HK310
void convert_channel_HK310(uint8_t num, uint8_t *low, uint8_t *high)
{
	uint16_t temp=0xFFFF-(4*Servo_data[num])/3;
	*low=(uint8_t)(temp&0xFF);
	*high=(uint8_t)(temp>>8);
}
// Channel value is limited to PPM_100
uint16_t limit_channel_100(uint8_t ch)
{
	if(Servo_data[ch]>PPM_MAX_100)
		return PPM_MAX_100;
	else
		if (Servo_data[ch]=TXBUFFER_SIZE)
		tx_head=0;
	tx_buff[tx_head]=data;
	sei();	// enable global int
	UCSR0B |= (1<	
	UBRR0H = UBRRH_VALUE;
	UBRR0L = UBRRL_VALUE;
	//Set frame format to 8 data bits, even parity, 2 stop bits
	UCSR0C |= (1<> 24) & 0xFF;
	rx_tx_addr[1] = (id >> 16) & 0xFF;
	rx_tx_addr[2] = (id >>  8) & 0xFF;
	rx_tx_addr[3] = (id >>  0) & 0xFF;
	rx_tx_addr[4] = 0xC1;	// for YD717: always uses first data port
}
static uint32_t random_id(uint16_t adress, uint8_t create_new)
{
	uint32_t id;
	uint8_t txid[4];
	if (eeprom_read_byte((uint8_t*)(adress+10))==0xf0 && !create_new)
	{  // TXID exists in EEPROM
		eeprom_read_block((void*)txid,(const void*)adress,4);
		id=(txid[0] | ((uint32_t)txid[1]<<8) | ((uint32_t)txid[2]<<16) | ((uint32_t)txid[3]<<24));
	}
	else
	{ // if not generate a random ID
		randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed
		//
		id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16);
		txid[0]=  (id &0xFF);
		txid[1] = ((id >> 8) & 0xFF);
		txid[2] = ((id >> 16) & 0xFF);
		txid[3] = ((id >> 24) & 0xFF);
		eeprom_write_block((const void*)txid,(void*)adress,4);
		eeprom_write_byte((uint8_t*)(adress+10),0xf0);//write bind flag in eeprom.
	}
	return id;
}
/**************************/
/**************************/
/**  Interrupt routines  **/
/**************************/
/**************************/
//PPM
ISR(INT1_vect)
{	// Interrupt on PPM pin
	static int8_t chan=-1;
	static uint16_t Prev_TCNT1=0;
	uint16_t Cur_TCNT1;
	Cur_TCNT1=TCNT1-Prev_TCNT1; // Capture current Timer1 value
	if(Cur_TCNT1<1000)
		chan=-1;				// bad frame
	else
		if(Cur_TCNT1>4840)
		{
			chan=0;				// start of frame
			PPM_FLAG_on;		// full frame present (even at startup since PPM_data has been initialized)
		}
		else
			if(chan!=-1)		// need to wait for start of frame
			{  //servo values between 500us and 2420us will end up here
				uint16_t a = Cur_TCNT1>>1;
				if(aPPM_MAX) a=PPM_MAX;
				PPM_data[chan]=a;
				if(chan++>=NUM_CHN)
					chan=-1;	// don't accept any new channels
			}
	Prev_TCNT1+=Cur_TCNT1;
}
//Serial RX
ISR(USART_RX_vect)
{	// RX interrupt
	if((UCSR0A&0x1C)==0)			// Check frame error, data overrun and parity error
	{ // received byte is ok to process
		if(idx==0)
		{	// Let's try to sync at this point
			if(UDR0==0x55)			// If 1st byte is 0x55 it looks ok
			{
				idx++;
				OCR1B=TCNT1+6500L;		// Full message should be received within timer of 3250us
				TIFR1=(1<RXBUFFER_SIZE)
			{	// A full frame has been received
				TIMSK1 &=~(1<=TXBUFFER_SIZE)//head 
		t=0;
		UDR0=tx_buff[t];
		tx_tail=t;
	}
	if (t == tx_head)
		UCSR0B &= ~(1<