mirror of
				https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
				synced 2025-10-29 10:01:04 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			622 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			622 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /*
 | |
|  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(FRSKY_RX_CC2500_INO)
 | |
| 
 | |
| #include "iface_cc2500.h" 
 | |
| 
 | |
|  #define FRSKY_RX_D16FCC_LENGTH	0x1D+1
 | |
|  #define FRSKY_RX_D16LBT_LENGTH	0x20+1
 | |
|  #define FRSKY_RX_D16v2_LENGTH	0x1D+1
 | |
|  #define FRSKY_RX_D8_LENGTH		0x11+1
 | |
|  #define FRSKY_RX_FORMATS		5
 | |
| 
 | |
| enum
 | |
| {
 | |
| 	FRSKY_RX_D8			=0,
 | |
| 	FRSKY_RX_D16FCC		=1,
 | |
| 	FRSKY_RX_D16LBT		=2,
 | |
| 	FRSKY_RX_D16v2FCC	=3,
 | |
| 	FRSKY_RX_D16v2LBT	=4,
 | |
| };
 | |
| 
 | |
| enum {
 | |
| 	FRSKY_RX_TUNE_START,
 | |
| 	FRSKY_RX_TUNE_LOW,
 | |
| 	FRSKY_RX_TUNE_HIGH,
 | |
| 	FRSKY_RX_BIND,
 | |
| 	FRSKY_RX_DATA,
 | |
| };
 | |
| 
 | |
| const PROGMEM uint8_t FRSKY_RX_common_reg[][2] = {
 | |
| 	{CC2500_02_IOCFG0, 0x01},
 | |
| 	{CC2500_18_MCSM0, 0x18},
 | |
| 	{CC2500_07_PKTCTRL1, 0x05},
 | |
| 	{CC2500_3E_PATABLE, 0xFF},
 | |
| 	{CC2500_0C_FSCTRL0, 0},
 | |
| 	{CC2500_0D_FREQ2, 0x5C},
 | |
| 	{CC2500_13_MDMCFG1, 0x23},
 | |
| 	{CC2500_14_MDMCFG0, 0x7A},
 | |
| 	{CC2500_19_FOCCFG, 0x16},
 | |
| 	{CC2500_1A_BSCFG, 0x6C},
 | |
| 	{CC2500_1B_AGCCTRL2, 0x03},
 | |
| 	{CC2500_1C_AGCCTRL1, 0x40},
 | |
| 	{CC2500_1D_AGCCTRL0, 0x91},
 | |
| 	{CC2500_21_FREND1, 0x56},
 | |
| 	{CC2500_22_FREND0, 0x10},
 | |
| 	{CC2500_23_FSCAL3, 0xA9},
 | |
| 	{CC2500_24_FSCAL2, 0x0A},
 | |
| 	{CC2500_25_FSCAL1, 0x00},
 | |
| 	{CC2500_26_FSCAL0, 0x11},
 | |
| 	{CC2500_29_FSTEST, 0x59},
 | |
| 	{CC2500_2C_TEST2, 0x88},
 | |
| 	{CC2500_2D_TEST1, 0x31},
 | |
| 	{CC2500_2E_TEST0, 0x0B},
 | |
| 	{CC2500_03_FIFOTHR, 0x07},
 | |
| 	{CC2500_09_ADDR, 0x03},
 | |
| };
 | |
| 
 | |
| const PROGMEM uint8_t FRSKY_RX_d16fcc_reg[][2] = {
 | |
| 	{CC2500_17_MCSM1, 0x0C},
 | |
| 	{CC2500_0E_FREQ1, 0x76},
 | |
| 	{CC2500_0F_FREQ0, 0x27},
 | |
| 	{CC2500_06_PKTLEN, 0x1E},
 | |
| 	{CC2500_08_PKTCTRL0, 0x01},
 | |
| 	{CC2500_0B_FSCTRL1, 0x0A},
 | |
| 	{CC2500_10_MDMCFG4, 0x7B},
 | |
| 	{CC2500_11_MDMCFG3, 0x61},
 | |
| 	{CC2500_12_MDMCFG2, 0x13},
 | |
| 	{CC2500_15_DEVIATN, 0x51},
 | |
| };
 | |
| 
 | |
| const PROGMEM uint8_t FRSKY_RX_d16lbt_reg[][2] = {
 | |
| 	{CC2500_17_MCSM1, 0x0E},
 | |
| 	{CC2500_0E_FREQ1, 0x80},
 | |
| 	{CC2500_0F_FREQ0, 0x00},
 | |
| 	{CC2500_06_PKTLEN, 0x23},
 | |
| 	{CC2500_08_PKTCTRL0, 0x01},
 | |
| 	{CC2500_0B_FSCTRL1, 0x08},
 | |
| 	{CC2500_10_MDMCFG4, 0x7B},
 | |
| 	{CC2500_11_MDMCFG3, 0xF8},
 | |
| 	{CC2500_12_MDMCFG2, 0x03},
 | |
| 	{CC2500_15_DEVIATN, 0x53},
 | |
| };
 | |
| 
 | |
| const PROGMEM uint8_t FRSKY_RX_d8_reg[][2] = {
 | |
| 	{CC2500_17_MCSM1,    0x0C},
 | |
| 	{CC2500_0E_FREQ1,    0x76},
 | |
| 	{CC2500_0F_FREQ0,    0x27},
 | |
| 	{CC2500_06_PKTLEN,   0x19},
 | |
| 	{CC2500_08_PKTCTRL0, 0x05},
 | |
| 	{CC2500_0B_FSCTRL1,  0x08},
 | |
| 	{CC2500_10_MDMCFG4,  0xAA},
 | |
| 	{CC2500_11_MDMCFG3,  0x39},
 | |
| 	{CC2500_12_MDMCFG2,  0x11},
 | |
| 	{CC2500_15_DEVIATN,  0x42},
 | |
| };
 | |
| 
 | |
| static uint8_t FRSKY_RX_chanskip;
 | |
| static int8_t  FRSKY_RX_finetune;
 | |
| static uint8_t FRSKY_RX_format;
 | |
| 
 | |
| static void __attribute__((unused)) FRSKY_RX_strobe_rx()
 | |
| {
 | |
| 	 CC2500_Strobe(CC2500_SIDLE);
 | |
| 	 CC2500_Strobe(CC2500_SFRX);
 | |
| 	 CC2500_Strobe(CC2500_SRX);
 | |
| }
 | |
| 
 | |
| static void __attribute__((unused)) FRSKY_RX_initialise_cc2500() {
 | |
| 	const uint8_t FRSKY_RX_length[] = { FRSKY_RX_D8_LENGTH, FRSKY_RX_D16FCC_LENGTH, FRSKY_RX_D16LBT_LENGTH, FRSKY_RX_D16v2_LENGTH, FRSKY_RX_D16v2_LENGTH };
 | |
| 	packet_length = FRSKY_RX_length[FRSKY_RX_format];
 | |
| 	CC2500_Reset();
 | |
| 	CC2500_Strobe(CC2500_SIDLE);
 | |
| 	for (uint8_t i = 0; i < sizeof(FRSKY_RX_common_reg) / 2; i++)
 | |
| 		CC2500_WriteReg(pgm_read_byte_near(&FRSKY_RX_common_reg[i][0]), pgm_read_byte_near(&FRSKY_RX_common_reg[i][1]));
 | |
| 
 | |
| 	switch (FRSKY_RX_format)
 | |
| 	{
 | |
| 		case FRSKY_RX_D16v2FCC:
 | |
| 		case FRSKY_RX_D16FCC:
 | |
| 			for (uint8_t i = 0; i < sizeof(FRSKY_RX_d16fcc_reg) / 2; i++)
 | |
| 				CC2500_WriteReg(pgm_read_byte_near(&FRSKY_RX_d16fcc_reg[i][0]), pgm_read_byte_near(&FRSKY_RX_d16fcc_reg[i][1]));
 | |
| 			if(FRSKY_RX_format==FRSKY_RX_D16v2FCC)
 | |
| 			{
 | |
| 				CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05);	// Enable CRC
 | |
| 				CC2500_WriteReg(CC2500_17_MCSM1, 0x0E);		// Go/Stay in RX mode
 | |
| 				CC2500_WriteReg(CC2500_11_MDMCFG3, 0x84);	// bitrate 70K->77K
 | |
| 			}
 | |
| 			break;
 | |
| 		case FRSKY_RX_D16v2LBT:
 | |
| 		case FRSKY_RX_D16LBT:
 | |
| 			for (uint8_t i = 0; i < sizeof(FRSKY_RX_d16lbt_reg) / 2; i++)
 | |
| 				CC2500_WriteReg(pgm_read_byte_near(&FRSKY_RX_d16lbt_reg[i][0]), pgm_read_byte_near(&FRSKY_RX_d16lbt_reg[i][1]));
 | |
| 			if(FRSKY_RX_format==FRSKY_RX_D16v2LBT)
 | |
| 				CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05);	// Enable CRC
 | |
| 			break;
 | |
| 		case FRSKY_RX_D8:
 | |
| 			for (uint8_t i = 0; i < sizeof(FRSKY_RX_d8_reg) / 2; i++)
 | |
| 				CC2500_WriteReg(pgm_read_byte_near(&FRSKY_RX_d8_reg[i][0]), pgm_read_byte_near(&FRSKY_RX_d8_reg[i][1]));
 | |
| 			CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
 | |
| 			break;
 | |
| 	}
 | |
| 	CC2500_WriteReg(CC2500_0A_CHANNR, 0);  // bind channel
 | |
| 	rx_disable_lna = IS_POWER_FLAG_on;
 | |
| 	CC2500_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN); // lna disable / enable
 | |
| 	FRSKY_RX_strobe_rx();
 | |
| 	delayMicroseconds(1000); // wait for RX to activate
 | |
| }
 | |
| 
 | |
| static void __attribute__((unused)) FRSKY_RX_set_channel(uint8_t channel)
 | |
| {
 | |
| 	CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[channel]);
 | |
| 	if(FRSKY_RX_format == FRSKY_RX_D8)
 | |
| 		CC2500_WriteReg(CC2500_23_FSCAL3, 0x89);
 | |
| 	CC2500_WriteReg(CC2500_25_FSCAL1, calData[channel]);
 | |
| 	FRSKY_RX_strobe_rx();
 | |
| }
 | |
| 
 | |
| static void __attribute__((unused)) FRSKY_RX_calibrate()
 | |
| {
 | |
| 	FRSKY_RX_strobe_rx();
 | |
| 	for (unsigned c = 0; c < 47; c++)
 | |
| 	{
 | |
| 		CC2500_Strobe(CC2500_SIDLE);
 | |
| 		CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[c]);
 | |
| 		CC2500_Strobe(CC2500_SCAL);
 | |
| 		delayMicroseconds(900);
 | |
| 		calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static uint8_t __attribute__((unused)) frskyx_rx_check_crc_id(bool bind,bool init)
 | |
| {
 | |
| 	/*debugln("RX");
 | |
| 	for(uint8_t i=0; i<packet_length;i++)
 | |
| 		debug(" %02X",packet[i]);
 | |
| 	debugln("");*/
 | |
| 	
 | |
| 	if(bind && packet[0]!=packet_length-1 && packet[1] !=0x03 && packet[2] != 0x01)
 | |
| 		return false;
 | |
| 	uint8_t offset=bind?3:1;
 | |
| 	
 | |
| 	// Check D8 checksum
 | |
| 	if (FRSKY_RX_format == FRSKY_RX_D8)
 | |
| 	{
 | |
| 		if((packet[packet_length+1] & 0x80) != 0x80)	// Check CRC_OK flag in status byte 2
 | |
| 			return false; 								// Bad CRC
 | |
| 		if(init)
 | |
| 		{//Save TXID
 | |
| 			rx_tx_addr[3] = packet[3];
 | |
| 			rx_tx_addr[2] = packet[4];
 | |
| 			rx_tx_addr[1] = packet[17];
 | |
| 		}
 | |
| 		else
 | |
| 			if(rx_tx_addr[3] != packet[offset] || rx_tx_addr[2] != packet[offset+1] || rx_tx_addr[1] != packet[bind?17:5])
 | |
| 				return false;							// Bad address
 | |
| 		return true;									// Full match
 | |
| 	}
 | |
| 
 | |
| 	// Check D16v2 checksum
 | |
| 	if (FRSKY_RX_format == FRSKY_RX_D16v2LBT || FRSKY_RX_format == FRSKY_RX_D16v2FCC)
 | |
| 		if((packet[packet_length+1] & 0x80) != 0x80)	// Check CRC_OK flag in status byte 2
 | |
| 			return false;
 | |
| 	//debugln("HW Checksum ok");
 | |
| 
 | |
| 	// Check D16 checksum
 | |
| 	uint16_t lcrc = FrSkyX_crc(&packet[3], packet_length - 5);		// Compute crc
 | |
| 	uint16_t rcrc = (packet[packet_length-2] << 8) | (packet[packet_length-1] & 0xff);	// Received crc
 | |
| 	if(lcrc != rcrc)
 | |
| 		return false; 									// Bad CRC
 | |
| 	//debugln("Checksum ok");
 | |
| 
 | |
| 	if (bind && (FRSKY_RX_format == FRSKY_RX_D16v2LBT || FRSKY_RX_format == FRSKY_RX_D16v2FCC))
 | |
| 		for(uint8_t i=3; i<packet_length-2; i++)		//unXOR bind packet
 | |
| 			packet[i] ^= 0xA7;
 | |
| 	
 | |
| 	uint8_t offset2=0;
 | |
| 	if (bind && (FRSKY_RX_format == FRSKY_RX_D16LBT || FRSKY_RX_format == FRSKY_RX_D16FCC))
 | |
| 		offset2=6;
 | |
| 	if(init)
 | |
| 	{//Save TXID
 | |
| 		rx_tx_addr[3] = packet[3];
 | |
| 		rx_tx_addr[2] = packet[4];
 | |
| 		rx_tx_addr[1] = packet[5+offset2];
 | |
| 		rx_tx_addr[0] = packet[6+offset2];				// RXnum
 | |
| 	}
 | |
| 	else
 | |
| 		if(rx_tx_addr[3] != packet[offset] || rx_tx_addr[2] != packet[offset+1] || rx_tx_addr[1] != packet[offset+2+offset2])
 | |
| 			return false;								// Bad address
 | |
| 	//debugln("Address ok");
 | |
| 	
 | |
| 	if(!bind && rx_tx_addr[0] != packet[6])
 | |
| 		return false;									// Bad RX num
 | |
| 	
 | |
| 	//debugln("Match");
 | |
| 	return true;										// Full match
 | |
| }
 | |
| 
 | |
| static void __attribute__((unused)) FRSKY_RX_build_telemetry_packet()
 | |
| {
 | |
| 	uint16_t raw_channel[8];
 | |
| 	uint32_t bits = 0;
 | |
| 	uint8_t bitsavailable = 0;
 | |
| 	uint8_t idx = 0;
 | |
| 	uint8_t i;
 | |
| 
 | |
| 	if (FRSKY_RX_format == FRSKY_RX_D8)
 | |
| 	{// decode D8 channels
 | |
| 		raw_channel[0] = ((packet[10] & 0x0F) << 8 | packet[6]);
 | |
| 		raw_channel[1] = ((packet[10] & 0xF0) << 4 | packet[7]);
 | |
| 		raw_channel[2] = ((packet[11] & 0x0F) << 8 | packet[8]);
 | |
| 		raw_channel[3] = ((packet[11] & 0xF0) << 4 | packet[9]);
 | |
| 		raw_channel[4] = ((packet[16] & 0x0F) << 8 | packet[12]);
 | |
| 		raw_channel[5] = ((packet[16] & 0xF0) << 4 | packet[13]);
 | |
| 		raw_channel[6] = ((packet[17] & 0x0F) << 8 | packet[14]);
 | |
| 		raw_channel[7] = ((packet[17] & 0xF0) << 4 | packet[15]);
 | |
| 		for (i = 0; i < 8; i++) {
 | |
| 			if (raw_channel[i] < 1290)
 | |
| 				raw_channel[i] = 1290;
 | |
| 			rx_rc_chan[i] = min(((raw_channel[i] - 1290) << 4) / 15, 2047);
 | |
| 		}
 | |
| 	}
 | |
| 	else
 | |
| 	{// decode D16 channels
 | |
| 		raw_channel[0] = ((packet[10] << 8) & 0xF00) | packet[9];
 | |
| 		raw_channel[1] = ((packet[11] << 4) & 0xFF0) | (packet[10] >> 4);
 | |
| 		raw_channel[2] = ((packet[13] << 8) & 0xF00) | packet[12];
 | |
| 		raw_channel[3] = ((packet[14] << 4) & 0xFF0) | (packet[13] >> 4);
 | |
| 		raw_channel[4] = ((packet[16] << 8) & 0xF00) | packet[15];
 | |
| 		raw_channel[5] = ((packet[17] << 4) & 0xFF0) | (packet[16] >> 4);
 | |
| 		raw_channel[6] = ((packet[19] << 8) & 0xF00) | packet[18];
 | |
| 		raw_channel[7] = ((packet[20] << 4) & 0xFF0) | (packet[19] >> 4);	
 | |
| 		for (i = 0; i < 8; i++) {
 | |
| 			// ignore failsafe channels
 | |
| 			if(packet[7] != 0x10+(i<<1)) {
 | |
| 				uint8_t shifted = (raw_channel[i] & 0x800)>0;
 | |
| 				uint16_t channel_value = raw_channel[i] & 0x7FF;
 | |
| 				if (channel_value < 64)
 | |
| 					rx_rc_chan[shifted ? i + 8 : i] = 0;
 | |
| 				else
 | |
| 					rx_rc_chan[shifted ? i + 8 : i] = min(((channel_value - 64) << 4) / 15, 2047);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	// buid telemetry packet
 | |
| 	packet_in[idx++] = RX_LQI;
 | |
| 	packet_in[idx++] = RX_RSSI;
 | |
| 	packet_in[idx++] = 0;  // start channel
 | |
| 	packet_in[idx++] = FRSKY_RX_format == FRSKY_RX_D8 ? 8 : 16; // number of channels in packet
 | |
| 
 | |
| 	// pack channels
 | |
| 	for (i = 0; i < packet_in[3]; i++) {
 | |
| 		bits |= ((uint32_t)rx_rc_chan[i]) << bitsavailable;
 | |
| 		bitsavailable += 11;
 | |
| 		while (bitsavailable >= 8) {
 | |
| 			packet_in[idx++] = bits & 0xff;
 | |
| 			bits >>= 8;
 | |
| 			bitsavailable -= 8;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void __attribute__((unused)) FRSKY_RX_data()
 | |
| {
 | |
| 	uint16_t temp = FRSKY_RX_EEPROM_OFFSET;
 | |
| 	FRSKY_RX_format = eeprom_read_byte((EE_ADDR)temp++) % FRSKY_RX_FORMATS;
 | |
| 	rx_tx_addr[3] = eeprom_read_byte((EE_ADDR)temp++);
 | |
| 	rx_tx_addr[2] = eeprom_read_byte((EE_ADDR)temp++);
 | |
| 	rx_tx_addr[1] = eeprom_read_byte((EE_ADDR)temp++);
 | |
| 	rx_tx_addr[0] = RX_num;
 | |
| 	FRSKY_RX_finetune = eeprom_read_byte((EE_ADDR)temp++);
 | |
| 	debug("format=%d, ", FRSKY_RX_format);
 | |
| 	debug("addr[3]=%02X, ", rx_tx_addr[3]);
 | |
| 	debug("addr[2]=%02X, ", rx_tx_addr[2]);
 | |
| 	debug("addr[1]=%02X, ", rx_tx_addr[1]);
 | |
| 	debug("rx_num=%02X, ",  rx_tx_addr[0]);
 | |
| 	debugln("tune=%d", (int8_t)FRSKY_RX_finetune);
 | |
| 	if(FRSKY_RX_format != FRSKY_RX_D16v2LBT && FRSKY_RX_format != FRSKY_RX_D16v2FCC)
 | |
| 	{//D8 & D16v1
 | |
| 		for (uint8_t ch = 0; ch < 47; ch++)
 | |
| 			hopping_frequency[ch] = eeprom_read_byte((EE_ADDR)temp++);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		FrSkyFormat=FRSKY_RX_format == FRSKY_RX_D16v2FCC?0:2;
 | |
| 		FrSkyX2_init_hop();
 | |
| 	}
 | |
| 	debug("ch:");
 | |
| 	for (uint8_t ch = 0; ch < 47; ch++)
 | |
| 		debug(" %02X", hopping_frequency[ch]);
 | |
| 	debugln("");
 | |
| 
 | |
| 	FRSKY_RX_initialise_cc2500();
 | |
| 	FRSKY_RX_calibrate();
 | |
| 	CC2500_WriteReg(CC2500_18_MCSM0, 0x08); // FS_AUTOCAL = manual
 | |
| 	CC2500_WriteReg(CC2500_09_ADDR, rx_tx_addr[3]); // set address
 | |
| 	CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); // check address
 | |
| 	if (option == 0)
 | |
| 		CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
 | |
| 	else
 | |
| 		CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
 | |
| 	FRSKY_RX_set_channel(hopping_frequency_no);
 | |
| 	phase = FRSKY_RX_DATA;
 | |
| }
 | |
| 
 | |
| void FRSKY_RX_init()
 | |
| {
 | |
| 	if(sub_protocol == FRSKY_ERASE)
 | |
| 	{
 | |
| 		if(IS_BIND_IN_PROGRESS)
 | |
| 		{// Clear all cloned addresses
 | |
| 			uint16_t addr[]={ FRSKYD_CLONE_EEPROM_OFFSET+1, FRSKYX_CLONE_EEPROM_OFFSET+1, FRSKYX2_CLONE_EEPROM_OFFSET+1 };
 | |
| 			for(uint8_t i=0; i<3;i++)
 | |
| 				for(uint8_t j=0; j<3;j++)
 | |
| 					eeprom_write_byte((EE_ADDR)(addr[i]+j), 0xFF);
 | |
| 			packet_count = 100;
 | |
| 		}			
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		FRSKY_RX_chanskip = 1;
 | |
| 		hopping_frequency_no = 0;
 | |
| 		rx_data_started = false;
 | |
| 		FRSKY_RX_finetune = 0;
 | |
| 		telemetry_link = 0;
 | |
| 		packet_count = 0;
 | |
| 		if (IS_BIND_IN_PROGRESS)
 | |
| 		{
 | |
| 			FRSKY_RX_format = FRSKY_RX_D8;
 | |
| 			FRSKY_RX_initialise_cc2500();
 | |
| 			phase = FRSKY_RX_TUNE_START;
 | |
| 			debugln("FRSKY_RX_TUNE_START");
 | |
| 		}
 | |
| 		else
 | |
| 			FRSKY_RX_data();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| uint16_t FRSKY_RX_callback()
 | |
| {
 | |
| 	static int8_t read_retry = 0;
 | |
| 	static int8_t tune_low, tune_high;
 | |
| 	uint8_t len, ch;
 | |
| 
 | |
| 	if(sub_protocol == FRSKY_ERASE)
 | |
| 	{
 | |
| 		if(packet_count)
 | |
| 			packet_count--;
 | |
| 		else
 | |
| 			BIND_DONE;
 | |
| 		return 10000;	//  Nothing to do...
 | |
| 	}
 | |
| 
 | |
| 	if(IS_BIND_DONE && phase != FRSKY_RX_DATA)
 | |
| 		FRSKY_RX_init();	// Abort bind
 | |
| 
 | |
| 	if ((prev_option != option) && (phase >= FRSKY_RX_DATA))
 | |
| 	{
 | |
| 		if (option == 0)
 | |
| 			CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
 | |
| 		else
 | |
| 			CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
 | |
| 		prev_option = option;
 | |
| 	}
 | |
| 
 | |
| 	if (rx_disable_lna != IS_POWER_FLAG_on)
 | |
| 	{
 | |
| 		rx_disable_lna = IS_POWER_FLAG_on;
 | |
| 		CC2500_SetTxRxMode(rx_disable_lna ? TXRX_OFF : RX_EN);
 | |
| 	}
 | |
| 
 | |
| 	len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
 | |
| 	switch(phase)
 | |
| 	{
 | |
| 		case FRSKY_RX_TUNE_START:
 | |
| 			if (len == packet_length + 2) //+2=RSSI+LQI+CRC
 | |
| 			{
 | |
| 				CC2500_ReadData(packet, len);
 | |
| 				if(frskyx_rx_check_crc_id(true,true))
 | |
| 				{
 | |
| 					FRSKY_RX_finetune = -127;
 | |
| 					CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
 | |
| 					phase = FRSKY_RX_TUNE_LOW;
 | |
| 					debugln("FRSKY_RX_TUNE_LOW");
 | |
| 					FRSKY_RX_strobe_rx();
 | |
| 					state = 0;
 | |
| 					return 1000;
 | |
| 				}
 | |
| 			}
 | |
| 			FRSKY_RX_format = (FRSKY_RX_format + 1) % FRSKY_RX_FORMATS; // switch to next format (D8, D16FCC, D16LBT, D16v2FCC, D16v2LBT)
 | |
| 			FRSKY_RX_initialise_cc2500();
 | |
| 			FRSKY_RX_finetune += 10;
 | |
| 			CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
 | |
| 			FRSKY_RX_strobe_rx();
 | |
| 			return 18000;
 | |
| 
 | |
| 		case FRSKY_RX_TUNE_LOW:
 | |
| 			if (len == packet_length + 2) //+2=RSSI+LQI+CRC
 | |
| 			{
 | |
| 				CC2500_ReadData(packet, len);
 | |
| 				if(frskyx_rx_check_crc_id(true,false)) {
 | |
| 					tune_low = FRSKY_RX_finetune;
 | |
| 					FRSKY_RX_finetune = 127;
 | |
| 					CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
 | |
| 					phase = FRSKY_RX_TUNE_HIGH;
 | |
| 					debugln("FRSKY_RX_TUNE_HIGH");
 | |
| 					FRSKY_RX_strobe_rx();
 | |
| 					return 1000;
 | |
| 				}
 | |
| 			}
 | |
| 			FRSKY_RX_finetune += 1;
 | |
| 			CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
 | |
| 			FRSKY_RX_strobe_rx();
 | |
| 			return 18000;
 | |
| 
 | |
| 		case FRSKY_RX_TUNE_HIGH:
 | |
| 			if (len == packet_length + 2) //+2=RSSI+LQI+CRC
 | |
| 			{
 | |
| 				CC2500_ReadData(packet, len);
 | |
| 				if(frskyx_rx_check_crc_id(true,false)) {
 | |
| 					tune_high = FRSKY_RX_finetune;
 | |
| 					FRSKY_RX_finetune = (tune_low + tune_high) / 2;
 | |
| 					CC2500_WriteReg(CC2500_0C_FSCTRL0, (int8_t)FRSKY_RX_finetune);
 | |
| 					if(tune_low < tune_high)
 | |
| 					{
 | |
| 						phase = FRSKY_RX_BIND;
 | |
| 						debugln("FRSKY_RX_TUNE_HIGH");
 | |
| 					}
 | |
| 					else
 | |
| 					{
 | |
| 						phase = FRSKY_RX_TUNE_START;
 | |
| 						debugln("FRSKY_RX_TUNE_START");
 | |
| 					}
 | |
| 					FRSKY_RX_strobe_rx();
 | |
| 					return 1000;
 | |
| 				}
 | |
| 			}
 | |
| 			FRSKY_RX_finetune -= 1;
 | |
| 			CC2500_WriteReg(CC2500_0C_FSCTRL0, FRSKY_RX_finetune);
 | |
| 			FRSKY_RX_strobe_rx();
 | |
| 			return 18000;
 | |
| 
 | |
| 		case FRSKY_RX_BIND:
 | |
| 			if (len == packet_length + 2) //+2=RSSI+LQI+CRC
 | |
| 			{
 | |
| 				CC2500_ReadData(packet, len);
 | |
| 				if(frskyx_rx_check_crc_id(true,false)) {
 | |
| 					if(FRSKY_RX_format != FRSKY_RX_D16v2LBT && FRSKY_RX_format != FRSKY_RX_D16v2FCC)
 | |
| 					{// D8 & D16v1
 | |
| 						if(packet[5] <= 0x2D)
 | |
| 						{
 | |
| 							for (ch = 0; ch < 5; ch++)
 | |
| 								hopping_frequency[packet[5]+ch] = packet[6+ch];
 | |
| 							state |= 1 << (packet[5] / 5);
 | |
| 						}
 | |
| 					}
 | |
| 					else
 | |
| 						state = 0x3FF; //No hop table for D16v2
 | |
| 					if (state == 0x3FF)
 | |
| 					{
 | |
| 						debugln("Bind complete");
 | |
| 						BIND_DONE;
 | |
| 						// store format, finetune setting, txid, channel list
 | |
| 						uint16_t temp = FRSKY_RX_EEPROM_OFFSET;
 | |
| 						if(sub_protocol==FRSKY_CLONE)
 | |
| 						{
 | |
| 							if(FRSKY_RX_format==FRSKY_RX_D8)
 | |
| 								temp=FRSKYD_CLONE_EEPROM_OFFSET;
 | |
| 							else if(FRSKY_RX_format == FRSKY_RX_D16FCC || FRSKY_RX_format == FRSKY_RX_D16LBT)
 | |
| 								temp=FRSKYX_CLONE_EEPROM_OFFSET;
 | |
| 							else
 | |
| 								temp=FRSKYX2_CLONE_EEPROM_OFFSET;
 | |
| 						}
 | |
| 						eeprom_write_byte((EE_ADDR)temp++, FRSKY_RX_format);
 | |
| 						eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[3]);
 | |
| 						eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[2]);
 | |
| 						eeprom_write_byte((EE_ADDR)temp++, rx_tx_addr[1]);
 | |
| 						if(sub_protocol == FRSKY_RX || sub_protocol == FRSKY_CPPM)	// FRSKY_RX, FRSKY_CPPM
 | |
| 							eeprom_write_byte((EE_ADDR)temp++, FRSKY_RX_finetune);
 | |
| 						if(FRSKY_RX_format != FRSKY_RX_D16v2FCC && FRSKY_RX_format != FRSKY_RX_D16v2LBT)
 | |
| 							for (ch = 0; ch < 47; ch++)
 | |
| 								eeprom_write_byte((EE_ADDR)temp++, hopping_frequency[ch]);
 | |
| 						FRSKY_RX_data();
 | |
| 						debugln("FRSKY_RX_DATA");
 | |
| 					}
 | |
| 				}
 | |
| 				FRSKY_RX_strobe_rx();
 | |
| 			}
 | |
| 			return 1000;
 | |
| 
 | |
| 		case FRSKY_RX_DATA:
 | |
| 			if (len == packet_length + 2) //+2=RSSI+LQI+CRC
 | |
| 			{
 | |
| 				CC2500_ReadData(packet, len);
 | |
| 				if(frskyx_rx_check_crc_id(false,false))
 | |
| 				{
 | |
| 					RX_RSSI = packet[len-2];
 | |
| 					if(RX_RSSI >= 128)
 | |
| 						RX_RSSI -= 128;
 | |
| 					else
 | |
| 						RX_RSSI += 128;
 | |
| 					bool chanskip_valid=true;
 | |
| 					// hop to next channel
 | |
| 					if (FRSKY_RX_format != FRSKY_RX_D8)
 | |
| 					{//D16v1 & D16v2
 | |
| 						if(rx_data_started)
 | |
| 						{
 | |
| 							if(FRSKY_RX_chanskip != (((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2)))
 | |
| 							{
 | |
| 								chanskip_valid=false;	// chanskip value has changed which surely indicates a bad frame
 | |
| 								packet_count++;
 | |
| 								if(packet_count>5)		// the TX must have changed chanskip...
 | |
| 									FRSKY_RX_chanskip = ((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2);	// chanskip init
 | |
| 							}
 | |
| 							else
 | |
| 								packet_count=0;
 | |
| 						}
 | |
| 						else
 | |
| 							FRSKY_RX_chanskip = ((packet[4] & 0xC0) >> 6) | ((packet[5] & 0x3F) << 2);	// chanskip init
 | |
| 					}
 | |
| 					hopping_frequency_no = (hopping_frequency_no + FRSKY_RX_chanskip) % 47;
 | |
| 					FRSKY_RX_set_channel(hopping_frequency_no);
 | |
| 					if(chanskip_valid)
 | |
| 					{
 | |
| 						if ((telemetry_link & 0x7F) == 0)
 | |
| 						{ // send channels to TX
 | |
| 							FRSKY_RX_build_telemetry_packet();
 | |
| 							telemetry_link = 1;
 | |
| 							#ifdef SEND_CPPM
 | |
| 								if(sub_protocol == FRSKY_CPPM)
 | |
| 									telemetry_link |= 0x80;		// Disable telemetry output
 | |
| 							#endif
 | |
| 						}
 | |
| 						pps_counter++;
 | |
| 					}
 | |
| 					rx_data_started = true;
 | |
| 					read_retry = 0;
 | |
| 				}
 | |
| 			}
 | |
| 			
 | |
| 			// packets per second
 | |
| 			if (millis() - pps_timer >= 1000) {
 | |
| 				pps_timer = millis();
 | |
| 				debugln("%d pps", pps_counter);
 | |
| 				RX_LQI = pps_counter;
 | |
| 				if(pps_counter==0)	// no packets for 1 sec or more...
 | |
| 				{// restart the search
 | |
| 					rx_data_started=false;
 | |
| 					packet_count=0;
 | |
| 				}
 | |
| 				pps_counter = 0;
 | |
| 			}
 | |
| 
 | |
| 			// skip channel if no packet received in time
 | |
| 			if (read_retry++ >= 9) {
 | |
| 				hopping_frequency_no = (hopping_frequency_no + FRSKY_RX_chanskip) % 47;
 | |
| 				FRSKY_RX_set_channel(hopping_frequency_no);
 | |
| 				if(rx_data_started)
 | |
| 					read_retry = 0;
 | |
| 				else
 | |
| 					read_retry = -50; // retry longer until first packet is catched
 | |
| 			}
 | |
| 			break;
 | |
| 	}
 | |
| 	return 1000;
 | |
| }
 | |
| 
 | |
| #endif
 |