Corona: FD_V3 sub protocol

New subprotocol for FlyDream V3 number 2.
This commit is contained in:
Pascal Langer 2018-07-20 19:13:56 +02:00
parent ad18856f7a
commit 236b375669
4 changed files with 200 additions and 135 deletions

View File

@ -21,10 +21,11 @@
#define CORONA_RF_NUM_CHANNELS 3
#define CORONA_ADDRESS_LENGTH 4
#define CORONA_BIND_CHANNEL_V1 0xD1
#define CORONA_BIND_CHANNEL_V1 0xD1 // also Flydream V3
#define CORONA_BIND_CHANNEL_V2 0xB8
#define CORONA_COARSE 0x00
#define CORONA_CHANNEL_TIMING 1500
#define FDV3_BIND_PERIOD 5000
#define FDV3_CHANNEL_PERIOD 4000
const PROGMEM uint8_t CORONA_init_values[] = {
/* 00 */ 0x29, 0x2E, 0x06, 0x07, 0xD3, 0x91, 0xFF, 0x04,
@ -35,13 +36,15 @@ const PROGMEM uint8_t CORONA_init_values[] = {
/* 28 */ 0x00, 0x59, 0x7F, 0x3F, 0x81, 0x35, 0x0B
};
uint8_t fdv3_id_send;
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]));
if(sub_protocol!=COR_V1)
if(sub_protocol==COR_V2)
{
CC2500_WriteReg(CC2500_0A_CHANNR, CORONA_BIND_CHANNEL_V2);
CC2500_WriteReg(CC2500_0E_FREQ1, 0x80);
@ -52,6 +55,11 @@ static void __attribute__((unused)) CORONA_rf_init()
CC2500_WriteReg(CC2500_1C_AGCCTRL1, 0xFB);
CC2500_WriteReg(CC2500_1D_AGCCTRL0, 0xDC);
}
else if(sub_protocol==FD_V3)
{
// Flydream receiver captures have deviation 50, tx captures show 47
CC2500_WriteReg(CC2500_15_DEVIATN, 0x50);
}
prev_option = option;
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
@ -68,24 +76,32 @@ static void __attribute__((unused)) CORONA_init()
{
#ifdef CORONA_FORCE_ID
// Example of ID and channels taken from dumps
if(sub_protocol==COR_V1)
switch(sub_protocol)
{
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);
}
else
{
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;
}
#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.
// 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).
// 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.
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);
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
@ -98,65 +114,54 @@ static void __attribute__((unused)) CORONA_init()
rx_tx_addr[2]|=0x01;
}
rx_tx_addr[1]=0xFE; // Always FE in the dumps of V1 and V2
}
else
{
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
}
#endif
}
// 8 Channels with direct values from PPM
static void __attribute__((unused)) CORONA_build_packet()
static uint16_t __attribute__((unused)) CORONA_build_bind_pkt()
{
// Tune frequency if it has been changed
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option = option ;
}
if(IS_BIND_DONE)
{
if(state==0 || sub_protocol==COR_V1)
{ // Build standard packet
// Set RF channel
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[hopping_frequency_no]);
// Update RF power
CC2500_SetPower();
// 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
if(sub_protocol==COR_V1)
{ // V1
if(bind_counter&1)
{ // Send TX ID
packet[0]=0x04; // 5 bytes to follow
for(uint8_t i=0; i<CORONA_ADDRESS_LENGTH; i++)
packet[i+13] = rx_tx_addr[i];
packet[17] = 0x00;
// Packet period is based on hopping
switch(hopping_frequency_no)
{
case 0:
packet_period=sub_protocol==COR_V1?4991-CORONA_CHANNEL_TIMING:4248-CORONA_CHANNEL_TIMING;
break;
case 1:
packet_period=sub_protocol==COR_V1?4991-CORONA_CHANNEL_TIMING:4345-CORONA_CHANNEL_TIMING;
break;
case 2:
packet_period=sub_protocol==COR_V1?12520-CORONA_CHANNEL_TIMING:13468-CORONA_CHANNEL_TIMING;
if(sub_protocol!=COR_V1)
packet[17] = 0x03;
break;
}
hopping_frequency_no++;
hopping_frequency_no%=CORONA_RF_NUM_CHANNELS;
packet[i+1]=rx_tx_addr[i];
packet[5]=0xCD; // Unknown but seems to be always the same value for V1
return 3689;
}
else
{ // Send hopping freq
packet[0]=0x03; // 4 bytes to follow
for(uint8_t i=0; i<CORONA_RF_NUM_CHANNELS+1; i++)
packet[i+1]=hopping_frequency[i];
// Only the first 3 channels of hopping_frequency used for data
return 3438;
}
}
else
{ // 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;
else
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);
@ -169,70 +174,127 @@ static void __attribute__((unused)) CORONA_build_packet()
for(uint8_t i=0; i<CORONA_ADDRESS_LENGTH; i++)
packet[i+4]=rx_tx_addr[i];
packet[8]=0;
packet_period=6647-CORONA_CHANNEL_TIMING;
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;
}
}
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
{ // Build bind packets
if(sub_protocol==COR_V1)
{ // V1
if(bind_counter&1)
{ // Send TX ID
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]=0xCD; // Unknown but seems to be always the same value for V1
packet_period=3689;
}
else
{ // Send hopping freq
packet[0]=0x03; // 4 bytes to follow
for(uint8_t i=0; i<CORONA_RF_NUM_CHANNELS+1; i++)
packet[i+1]=hopping_frequency[i];
// Not sure what the last byte (+1) is for now since only the first 3 channels are used...
packet_period=3438;
}
}
else
{ // V2
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
packet_period=26791;
}
packet_period = FDV3_CHANNEL_PERIOD;
}
hopping_frequency_no %= CORONA_RF_NUM_CHANNELS;
return packet_period;
}
uint16_t ReadCORONA()
{
// Tune frequency if it has been changed
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0, option);
prev_option = option ;
}
if(IS_BIND_IN_PROGRESS)
{
bind_counter--;
if (bind_counter == 0)
BIND_DONE;
}
if(packet[0]==0)
{
CORONA_build_packet();
if(IS_BIND_DONE)
return CORONA_CHANNEL_TIMING;
if (bind_counter-- == 0) BIND_DONE;
packet_period=CORONA_build_bind_pkt();
}
else
packet_period=CORONA_build_packet();
// Send packet
CC2500_WriteData(packet, packet[0]+2);
packet[0]=0;
return packet_period;
}
uint16_t initCORONA()
{
if(sub_protocol==COR_V1)
switch(sub_protocol)
{
case COR_V1:
bind_counter=1400; // Stay in bind mode for 5s
else
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;
}
state=400; // Used by V2 to send RF channels + ID for 2.65s at startup
hopping_frequency_no=0;
packet[0]=0;
fdv3_id_send = 0;
CORONA_init();
CORONA_rf_init();
return 10000;

View File

@ -34,6 +34,6 @@
34,CABELL,CAB_V3,C_TELEM,-,-,-,-,F_SAFE,UNBIND
35,ESKY150
36,H8_3D,H8_3D,H20H,H20Mini,H30Mini
37,CORONA,COR_V1,COR_V2
37,CORONA,COR_V1,COR_V2,FD_V3
38,CFlie

View File

@ -19,7 +19,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 2
#define VERSION_REVISION 0
#define VERSION_PATCH_LEVEL 21
#define VERSION_PATCH_LEVEL 22
//******************
// Protocols
@ -229,6 +229,7 @@ enum CORONA
{
COR_V1 = 0,
COR_V2 = 1,
FD_V3 = 2,
};
#define NONE 0
@ -678,6 +679,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
sub_protocol==CORONA
COR_V1 0
COR_V2 1
FD_V3 2
Power value => 0x80 0=High/1=Low
Stream[3] = option_protocol;

View File

@ -544,6 +544,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
PROTO_CORONA
COR_V1
COR_V2
FD_V3
PROTO_CFLIE
NONE
*/