2018-01-03 13:04:58 +01:00
/*
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(CORONA_CC2500_INO)
# include "iface_cc2500.h"
//#define CORONA_FORCE_ID
# define CORONA_RF_NUM_CHANNELS 3
# define CORONA_ADDRESS_LENGTH 4
2018-07-20 19:13:56 +02:00
# define CORONA_BIND_CHANNEL_V1 0xD1 // also Flydream V3
2018-01-03 13:04:58 +01:00
# define CORONA_BIND_CHANNEL_V2 0xB8
# define CORONA_COARSE 0x00
2018-07-20 19:13:56 +02:00
# define FDV3_BIND_PERIOD 5000
# define FDV3_CHANNEL_PERIOD 4000
2018-01-03 13:04:58 +01:00
const PROGMEM uint8_t CORONA_init_values [ ] = {
/* 00 */ 0x29 , 0x2E , 0x06 , 0x07 , 0xD3 , 0x91 , 0xFF , 0x04 ,
/* 08 */ 0x05 , 0x00 , CORONA_BIND_CHANNEL_V1 , 0x06 , 0x00 , 0x5C , 0x4E , 0xC4 + CORONA_COARSE ,
/* 10 */ 0x5B , 0xF8 , 0x03 , 0x23 , 0xF8 , 0x47 , 0x07 , 0x30 ,
/* 18 */ 0x18 , 0x16 , 0x6C , 0x43 , 0x40 , 0x91 , 0x87 , 0x6B ,
/* 20 */ 0xF8 , 0x56 , 0x10 , 0xA9 , 0x0A , 0x00 , 0x11 , 0x41 ,
/* 28 */ 0x00 , 0x59 , 0x7F , 0x3F , 0x81 , 0x35 , 0x0B
} ;
2018-07-20 19:13:56 +02:00
uint8_t fdv3_id_send ;
2018-01-03 13:04:58 +01:00
static void __attribute__ ( ( unused ) ) CORONA_rf_init ( )
{
CC2500_Strobe ( CC2500_SIDLE ) ;
for ( uint8_t i = 0 ; i < = 0x2E ; + + i )
CC2500_WriteReg ( i , pgm_read_byte_near ( & CORONA_init_values [ i ] ) ) ;
2018-07-20 19:13:56 +02:00
if ( sub_protocol = = COR_V2 )
2018-01-03 13:04:58 +01:00
{
CC2500_WriteReg ( CC2500_0A_CHANNR , CORONA_BIND_CHANNEL_V2 ) ;
CC2500_WriteReg ( CC2500_0E_FREQ1 , 0x80 ) ;
CC2500_WriteReg ( CC2500_0F_FREQ0 , 0x00 + CORONA_COARSE ) ;
CC2500_WriteReg ( CC2500_15_DEVIATN , 0x50 ) ;
CC2500_WriteReg ( CC2500_17_MCSM1 , 0x00 ) ;
CC2500_WriteReg ( CC2500_1B_AGCCTRL2 , 0x67 ) ;
CC2500_WriteReg ( CC2500_1C_AGCCTRL1 , 0xFB ) ;
CC2500_WriteReg ( CC2500_1D_AGCCTRL0 , 0xDC ) ;
}
2018-07-20 19:13:56 +02:00
else if ( sub_protocol = = FD_V3 )
{
// Flydream receiver captures have deviation 50, tx captures show 47
CC2500_WriteReg ( CC2500_15_DEVIATN , 0x50 ) ;
}
2018-01-03 13:04:58 +01:00
CC2500_WriteReg ( CC2500_0C_FSCTRL0 , option ) ;
//not sure what they are doing to the PATABLE since basically only the first byte is used and it's only 8 bytes long. So I think they end up filling the PATABLE fully with 0xFF
CC2500_WriteRegisterMulti ( CC2500_3E_PATABLE , ( const uint8_t * ) " \x08 \xFF \xFF \xFF \xFF \xFF \xFF \xFF \xFF \xFF \xFF \xFF \xFF " , 13 ) ;
CC2500_SetTxRxMode ( TX_EN ) ;
CC2500_SetPower ( ) ;
}
// Generate id and hopping freq
2021-02-09 18:23:33 +01:00
static void __attribute__ ( ( unused ) ) CORONA_TXID_init ( )
2018-01-03 13:04:58 +01:00
{
# ifdef CORONA_FORCE_ID
// Example of ID and channels taken from dumps
2018-07-20 19:13:56 +02:00
switch ( sub_protocol )
2018-01-03 13:04:58 +01:00
{
2018-07-20 19:13:56 +02:00
case COR_V1 :
memcpy ( ( void * ) rx_tx_addr , ( void * ) " \x1F \xFE \x6C \x35 " , CORONA_ADDRESS_LENGTH ) ;
memcpy ( ( void * ) hopping_frequency , ( void * ) " \x17 \x0D \x03 \x49 " , CORONA_RF_NUM_CHANNELS + 1 ) ;
break ;
case COR_V2 :
memcpy ( ( void * ) rx_tx_addr , ( void * ) " \xFE \xFE \x02 \xFB " , CORONA_ADDRESS_LENGTH ) ;
memcpy ( ( void * ) hopping_frequency , ( void * ) " \x14 \x3D \x35 " , CORONA_RF_NUM_CHANNELS ) ;
case FD_V3 :
memcpy ( ( void * ) rx_tx_addr , ( void * ) " \x02 \xFA \x38 \x38 " , CORONA_ADDRESS_LENGTH ) ;
memcpy ( ( void * ) hopping_frequency , ( void * ) " \x71 \xB9 \x30 " , CORONA_RF_NUM_CHANNELS ) ;
break ;
}
2018-01-03 13:04:58 +01:00
# else
// From dumps channels are anything between 0x00 and 0xC5 on V1.
// But 0x00 and 0xB8 should be avoided on V2 since they are used for bind.
2018-07-20 19:13:56 +02:00
// Below code make sure channels are between 0x02 and 0xA0, spaced with
// a minimum of 2 and not ordered (RX only use the 1st channel unless there is an issue).
// Extra hopping frequency used for Flydream V3 id packets.
2018-01-03 13:04:58 +01:00
uint8_t order = rx_tx_addr [ 3 ] & 0x03 ;
for ( uint8_t i = 0 ; i < CORONA_RF_NUM_CHANNELS + 1 ; i + + )
hopping_frequency [ i ^ order ] = 2 + rx_tx_addr [ 3 - i ] % 39 + ( i < < 5 ) + ( i < < 3 ) ;
2018-07-20 19:13:56 +02:00
if ( sub_protocol ! = FD_V3 )
{
// ID looks random but on the 15 V1 dumps they all show the same odd/even rule
if ( rx_tx_addr [ 3 ] & 0x01 )
{ // If [3] is odd then [0] is odd and [2] is even
rx_tx_addr [ 0 ] | = 0x01 ;
rx_tx_addr [ 2 ] & = 0xFE ;
}
else
{ // If [3] is even then [0] is even and [2] is odd
rx_tx_addr [ 0 ] & = 0xFE ;
rx_tx_addr [ 2 ] | = 0x01 ;
}
rx_tx_addr [ 1 ] = 0xFE ; // Always FE in the dumps of V1 and V2
2018-01-03 13:04:58 +01:00
}
else
2018-07-20 19:13:56 +02:00
{
rx_tx_addr [ 1 ] = 0xFA ; // Always FA for Flydream V3
rx_tx_addr [ 3 ] = hopping_frequency [ CORONA_RF_NUM_CHANNELS ] ; // channel used for id/freq packets
2018-01-03 13:04:58 +01:00
}
# endif
}
2018-07-20 19:13:56 +02:00
static uint16_t __attribute__ ( ( unused ) ) CORONA_build_bind_pkt ( )
2018-01-03 13:04:58 +01:00
{
2018-07-20 19:13:56 +02:00
if ( sub_protocol = = COR_V1 )
{ // V1
if ( bind_counter & 1 )
{ // Send TX ID
packet [ 0 ] = 0x04 ; // 5 bytes to follow
2018-01-03 13:04:58 +01:00
for ( uint8_t i = 0 ; i < CORONA_ADDRESS_LENGTH ; i + + )
2018-07-20 19:13:56 +02:00
packet [ i + 1 ] = rx_tx_addr [ i ] ;
packet [ 5 ] = 0xCD ; // Unknown but seems to be always the same value for V1
return 3689 ;
2018-01-03 13:04:58 +01:00
}
else
2018-07-20 19:13:56 +02:00
{ // Send hopping freq
packet [ 0 ] = 0x03 ; // 4 bytes to follow
for ( uint8_t i = 0 ; i < CORONA_RF_NUM_CHANNELS + 1 ; i + + )
2018-01-03 13:04:58 +01:00
packet [ i + 1 ] = hopping_frequency [ i ] ;
2018-07-20 19:13:56 +02:00
// Only the first 3 channels of hopping_frequency used for data
return 3438 ;
2018-01-03 13:04:58 +01:00
}
}
else
2018-07-20 19:13:56 +02:00
{ // V2 and FDV3
packet [ 0 ] = 0x04 ; // 5 bytes to follow
for ( uint8_t i = 0 ; i < CORONA_ADDRESS_LENGTH ; i + + )
packet [ i + 1 ] = rx_tx_addr [ i ] ;
packet [ 5 ] = 0x00 ; // Unknown but seems to be always the same value for V2 and FDV3
if ( sub_protocol = = FD_V3 )
return FDV3_BIND_PERIOD ;
2018-01-03 13:04:58 +01:00
else
2018-07-20 19:13:56 +02:00
return 26791 ;
}
}
// 8 Channels with direct values from PPM
static uint16_t __attribute__ ( ( unused ) ) CORONA_build_packet ( )
{
CC2500_SetPower ( ) ;
if ( state & & sub_protocol = = COR_V2 )
{ // Send identifier packet for 2.65sec. This is how the RX learns the hopping table after a bind. Why it's not part of the bind like V1 is a mistery...
// Set channel
CC2500_WriteReg ( CC2500_0A_CHANNR , 0x00 ) ;
state - - ;
packet [ 0 ] = 0x07 ; // 8 bytes to follow
// Send hopping freq
for ( uint8_t i = 0 ; i < CORONA_RF_NUM_CHANNELS ; i + + )
packet [ i + 1 ] = hopping_frequency [ i ] ;
// Send TX ID
for ( uint8_t i = 0 ; i < CORONA_ADDRESS_LENGTH ; i + + )
packet [ i + 4 ] = rx_tx_addr [ i ] ;
packet [ 8 ] = 0 ;
return 6647 ;
}
// Flydream every fourth packet is identifier packet and is on channel number
// that is last byte of rx_tx_addr
if ( fdv3_id_send )
{
fdv3_id_send = 0 ;
CC2500_WriteReg ( CC2500_0A_CHANNR , rx_tx_addr [ CORONA_ADDRESS_LENGTH - 1 ] ) ;
packet [ 0 ] = 0x07 ; // 8 bytes to follow
// Send TX ID
for ( uint8_t i = 0 ; i < CORONA_ADDRESS_LENGTH ; i + + )
packet [ i + 1 ] = rx_tx_addr [ i ] ;
// Send hopping freq
for ( uint8_t i = 0 ; i < CORONA_RF_NUM_CHANNELS ; i + + )
packet [ i + 1 + CORONA_ADDRESS_LENGTH ] = hopping_frequency [ i ] ;
packet [ 8 ] = 0 ;
return 2 * FDV3_CHANNEL_PERIOD ; // extra delay after id packet according to captures
}
// Set RF channel
CC2500_WriteReg ( CC2500_0A_CHANNR , hopping_frequency [ hopping_frequency_no ] ) ;
// Build packet
packet [ 0 ] = 0x10 ; // 17 bytes to follow
// Channels
memset ( packet + 9 , 0x00 , 4 ) ;
for ( uint8_t i = 0 ; i < 8 ; i + + )
{ // Channel values are packed
uint16_t val = convert_channel_ppm ( i ) ;
packet [ i + 1 ] = val ;
packet [ 9 + ( i > > 1 ) ] | = ( i & 0x01 ) ? ( val > > 4 ) & 0xF0 : ( val > > 8 ) & 0x0F ;
}
// TX ID
for ( uint8_t i = 0 ; i < CORONA_ADDRESS_LENGTH ; i + + )
packet [ i + 13 ] = rx_tx_addr [ i ] ;
packet [ 17 ] = 0x00 ;
if ( sub_protocol ! = FD_V3 )
{
// Packet period is based on hopping
switch ( hopping_frequency_no )
{
case 0 :
packet_period = sub_protocol = = COR_V1
? 4991
: 4248 ;
break ;
case 1 :
packet_period = sub_protocol = = COR_V1
? 4991
: 4345 ;
break ;
case 2 :
packet_period = sub_protocol = = COR_V1
? 12520
: 13468 ;
if ( sub_protocol = = COR_V2 )
packet [ 17 ] = 0x03 ;
break ;
2018-01-03 13:04:58 +01:00
}
}
2018-07-20 19:13:56 +02:00
hopping_frequency_no + + ;
if ( sub_protocol = = FD_V3 )
{
if ( hopping_frequency_no = = CORONA_RF_NUM_CHANNELS )
{
fdv3_id_send = 1 ;
packet_period = 6000 ; // extra delay before id packet according to captures
}
else
packet_period = FDV3_CHANNEL_PERIOD ;
}
hopping_frequency_no % = CORONA_RF_NUM_CHANNELS ;
return packet_period ;
2018-01-03 13:04:58 +01:00
}
2021-02-09 18:23:33 +01:00
uint16_t CORONA_callback ( )
2018-01-03 13:04:58 +01:00
{
2019-11-11 19:15:39 +01:00
# ifdef MULTI_SYNC
telemetry_set_input_sync ( 22000 ) ;
# endif
2018-07-20 19:13:56 +02:00
// Tune frequency if it has been changed
2021-01-25 11:33:30 +01:00
CC2500_SetFreqOffset ( ) ;
2018-07-20 19:13:56 +02:00
if ( IS_BIND_IN_PROGRESS )
2018-01-10 11:25:07 +01:00
{
2018-07-20 19:13:56 +02:00
if ( bind_counter - - = = 0 ) BIND_DONE ;
packet_period = CORONA_build_bind_pkt ( ) ;
2018-01-10 11:25:07 +01:00
}
2018-07-20 19:13:56 +02:00
else
packet_period = CORONA_build_packet ( ) ;
2018-01-10 11:25:07 +01:00
// Send packet
CC2500_WriteData ( packet , packet [ 0 ] + 2 ) ;
2018-01-03 13:04:58 +01:00
return packet_period ;
}
2021-02-09 18:23:33 +01:00
void CORONA_init ( )
2018-01-03 13:04:58 +01:00
{
2018-07-20 19:13:56 +02:00
switch ( sub_protocol )
{
case COR_V1 :
bind_counter = 1400 ; // Stay in bind mode for 5s
break ;
case COR_V2 :
bind_counter = 187 ; // Stay in bind mode for 5s
break ;
case FD_V3 :
bind_counter = 2000 ; // Stay in bind mode for 10s
break ;
}
2018-01-03 13:04:58 +01:00
state = 400 ; // Used by V2 to send RF channels + ID for 2.65s at startup
hopping_frequency_no = 0 ;
2018-07-20 19:13:56 +02:00
fdv3_id_send = 0 ;
2021-02-09 18:23:33 +01:00
CORONA_TXID_init ( ) ;
2018-01-03 13:04:58 +01:00
CORONA_rf_init ( ) ;
}
# endif