mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-12-04 03:39:41 +00:00
FrSkyX v2.1: initial support
Rewrite of the FrSkyX code to support both v1 and v2.1.0 with FCC and LBT. FrSky v1 accessible as usual FrSky v2.1.0 accessible through the protocol 64=FrSkyX2 with the same subprotocols as v1 The LBT feature is now fully implemented on the TX and turned on for both v1 LBT and v2.1.0 LBT. For v2.1.0, to access the bind functions Telem=on/off, CH1-8/9-16 and bidirectional SPort (SxR setup for example), you need to update OpenTX to the latest 2.3.8 nightly (not available yet).
This commit is contained in:
@@ -21,34 +21,65 @@
|
||||
|
||||
static void __attribute__((unused)) FrSkyX_build_bind_packet()
|
||||
{
|
||||
packet[0] = (sub_protocol & 2 ) ? 0x20 : 0x1D ; // LBT or FCC
|
||||
packet[1] = 0x03;
|
||||
packet[2] = 0x01;
|
||||
//
|
||||
packet[3] = rx_tx_addr[3];
|
||||
packet[4] = rx_tx_addr[2];
|
||||
int idx = ((state -FRSKY_BIND) % 10) * 5;
|
||||
packet[5] = idx;
|
||||
packet[6] = hopping_frequency[idx++];
|
||||
packet[7] = hopping_frequency[idx++];
|
||||
packet[8] = hopping_frequency[idx++];
|
||||
packet[9] = hopping_frequency[idx++];
|
||||
packet[10] = hopping_frequency[idx++];
|
||||
packet[11] = 0x02;
|
||||
packet[12] = RX_num;
|
||||
//
|
||||
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
|
||||
memset(&packet[13], 0, limit - 13);
|
||||
if(binding_idx&0x01)
|
||||
memcpy(&packet[13],(void *)"\x55\xAA\x5A\xA5",4); // Telem off
|
||||
if(binding_idx&0x02)
|
||||
memcpy(&packet[17],(void *)"\x55\xAA\x5A\xA5",4); // CH9-16
|
||||
//
|
||||
uint16_t lcrc = FrSkyX_crc(&packet[3], limit-3);
|
||||
//
|
||||
packet[limit++] = lcrc >> 8;
|
||||
packet[limit] = lcrc;
|
||||
//
|
||||
uint8_t packet_size = 0x1D;
|
||||
if(protocol==PROTO_FRSKYX && (sub_protocol & 2 ))
|
||||
packet_size=0x20; // FrSkyX V1 LBT
|
||||
//Header
|
||||
packet[0] = packet_size; // Number of bytes in the packet (after this one)
|
||||
packet[1] = 0x03; // Bind packet
|
||||
packet[2] = 0x01; // Bind packet
|
||||
|
||||
//ID
|
||||
packet[3] = rx_tx_addr[3]; // ID
|
||||
packet[4] = rx_tx_addr[2]; // ID
|
||||
|
||||
if(protocol==PROTO_FRSKYX)
|
||||
{
|
||||
int idx = ((state -FRSKY_BIND) % 10) * 5;
|
||||
packet[5] = idx;
|
||||
packet[6] = hopping_frequency[idx++];
|
||||
packet[7] = hopping_frequency[idx++];
|
||||
packet[8] = hopping_frequency[idx++];
|
||||
packet[9] = hopping_frequency[idx++];
|
||||
packet[10] = hopping_frequency[idx++];
|
||||
packet[11] = 0x02; // Unknown but constant ID?
|
||||
packet[12] = RX_num;
|
||||
//
|
||||
memset(&packet[13], 0, packet_size - 14);
|
||||
if(binding_idx&0x01)
|
||||
memcpy(&packet[13],(void *)"\x55\xAA\x5A\xA5",4); // Telem off
|
||||
if(binding_idx&0x02)
|
||||
memcpy(&packet[17],(void *)"\x55\xAA\x5A\xA5",4); // CH9-16
|
||||
}
|
||||
else
|
||||
{
|
||||
//packet 1D 03 01 0E 1C 02 00 00 32 0B 00 00 A8 26 28 01 A1 00 00 00 3E F6 87 C7 00 00 00 00 C9 C9
|
||||
packet[5] = 0x02; // Unknown but constant ID?
|
||||
packet[6] = RX_num;
|
||||
//Bind flags
|
||||
packet[7]=0;
|
||||
if(binding_idx&0x01)
|
||||
packet[7] |= 0x40; // Telem off
|
||||
if(binding_idx&0x02)
|
||||
packet[7] |= 0x80; // CH9-16
|
||||
//Unknown bytes
|
||||
memcpy(&packet[8],"\x32\x0B\x00\x00\xA8\x26\x28\x01\xA1\x00\x00\x00\x3E\xF6\x87\xC7",16);
|
||||
packet[20]^= 0x0E ^ rx_tx_addr[3]; // Update the ID
|
||||
packet[21]^= 0x1C ^ rx_tx_addr[2]; // Update the ID
|
||||
//Xor
|
||||
for(uint8_t i=3; i<packet_size-1; i++)
|
||||
packet[i] ^= 0xA7;
|
||||
}
|
||||
//CRC
|
||||
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_size-4);
|
||||
packet[packet_size-1] = lcrc >> 8;
|
||||
packet[packet_size] = lcrc;
|
||||
|
||||
/*//Debug
|
||||
debug("Bind:");
|
||||
for(uint8_t i=0;i<=packet_size;i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");*/
|
||||
}
|
||||
|
||||
#define FrSkyX_FAILSAFE_TIME 1032
|
||||
@@ -81,10 +112,14 @@ static void __attribute__((unused)) FrSkyX_build_packet()
|
||||
failsafe_count++;
|
||||
#endif
|
||||
|
||||
packet[0] = (sub_protocol & 0x02 ) ? 0x20 : 0x1D ; // LBT or FCC
|
||||
packet[1] = rx_tx_addr[3];
|
||||
packet[2] = rx_tx_addr[2];
|
||||
packet[3] = 0x02;
|
||||
uint8_t packet_size = 0x1D;
|
||||
if(protocol==PROTO_FRSKYX && (sub_protocol & 2 ))
|
||||
packet_size=0x20; // FrSkyX V1 LBT
|
||||
//Header
|
||||
packet[0] = packet_size; // Number of bytes in the packet (after this one)
|
||||
packet[1] = rx_tx_addr[3]; // ID
|
||||
packet[2] = rx_tx_addr[2]; // ID
|
||||
packet[3] = 0x02; // Unknown but constant ID?
|
||||
//
|
||||
packet[4] = (FrSkyX_chanskip<<6)|hopping_frequency_no;
|
||||
packet[5] = FrSkyX_chanskip>>2;
|
||||
@@ -128,8 +163,7 @@ static void __attribute__((unused)) FrSkyX_build_packet()
|
||||
chan_offset^=0x08;
|
||||
|
||||
//sequence and send SPort
|
||||
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
|
||||
for (uint8_t i=22;i<limit;i++)
|
||||
for (uint8_t i=22;i<packet_size-1;i++)
|
||||
packet[i]=0;
|
||||
packet[21] = FrSkyX_RX_Seq << 4; //TX=8 at startup
|
||||
#ifdef SPORT_SEND
|
||||
@@ -157,7 +191,7 @@ static void __attribute__((unused)) FrSkyX_build_packet()
|
||||
//debugln("Send:%d",FrSkyX_TX_Seq);
|
||||
packet[21] |= FrSkyX_TX_Seq;
|
||||
uint8_t nbr_bytes=0;
|
||||
for (uint8_t i=23;i<limit;i++)
|
||||
for (uint8_t i=23;i<packet_size-1;i++)
|
||||
{
|
||||
if(SportHead==SportTail)
|
||||
break; //buffer empty
|
||||
@@ -208,14 +242,20 @@ static void __attribute__((unused)) FrSkyX_build_packet()
|
||||
FrSkyX_TX_Seq = ( FrSkyX_TX_Seq + 1 ) & 0x03 ; // Next iteration send next packet
|
||||
#endif // SPORT_SEND
|
||||
|
||||
uint16_t lcrc = FrSkyX_crc(&packet[3], limit-3);
|
||||
packet[limit++]=lcrc>>8;//high byte
|
||||
packet[limit]=lcrc;//low byte
|
||||
//CRC
|
||||
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_size-4);
|
||||
packet[packet_size-1] = lcrc >> 8;
|
||||
packet[packet_size] = lcrc;
|
||||
|
||||
/*//Debug
|
||||
debug("Norm:");
|
||||
for(uint8_t i=0;i<=packet_size;i++)
|
||||
debug(" %02X",packet[i]);
|
||||
debugln("");*/
|
||||
}
|
||||
|
||||
uint16_t ReadFrSkyX()
|
||||
{
|
||||
static bool transmit=true;
|
||||
#ifdef DEBUG_SERIAL
|
||||
static uint16_t fr_time=0;
|
||||
#endif
|
||||
@@ -241,7 +281,61 @@ uint16_t ReadFrSkyX()
|
||||
BIND_DONE;
|
||||
state++; //FRSKY_DATA1
|
||||
break;
|
||||
case FRSKY_DATA5:
|
||||
|
||||
case FRSKY_DATA1:
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); //Frequency offset hack
|
||||
prev_option = option ;
|
||||
}
|
||||
FrSkyX_set_start(hopping_frequency_no);
|
||||
FrSkyX_build_packet();
|
||||
if(sub_protocol & 2)
|
||||
{// LBT
|
||||
CC2500_Strobe(CC2500_SRX); //Acquire RSSI
|
||||
state++;
|
||||
return 400; // LBT v2.1
|
||||
}
|
||||
case FRSKY_DATA2:
|
||||
if(sub_protocol & 2)
|
||||
{
|
||||
uint16_t rssi=0;
|
||||
for(uint8_t i=0;i<4;i++)
|
||||
rssi += CC2500_ReadReg(CC2500_34_RSSI | CC2500_READ_BURST); // 0.5 db/count, RSSI value read from the RSSI status register is a 2's complement number
|
||||
rssi>>=2;
|
||||
#if 0
|
||||
uint8_t rssi_level=convert_channel_8b(CH16)>>1; //CH16 0..127
|
||||
if ( rssi > rssi_level && rssi < 128) //test rssi level dynamically
|
||||
#else
|
||||
if ( rssi > 72 && rssi < 128) //LBT and RSSI between -36 and -8.5 dBm
|
||||
#endif
|
||||
{
|
||||
POWER_FLAG_off; // Reduce to low power before transmitting
|
||||
debugln("Busy %d %d",hopping_frequency_no,rssi);
|
||||
}
|
||||
}
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_Strobe(CC2500_SFTX);
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
hopping_frequency_no = (hopping_frequency_no+FrSkyX_chanskip)%47;
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
state=FRSKY_DATA3;
|
||||
if(sub_protocol & 2)
|
||||
return 4000; // LBT v2.1
|
||||
else
|
||||
return 5200; // FCC v2.1
|
||||
case FRSKY_DATA3:
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
CC2500_Strobe(CC2500_SRX);
|
||||
state++;
|
||||
if(sub_protocol & 2)
|
||||
return 4100; // LBT v2.1
|
||||
else
|
||||
return 3300; // FCC v2.1
|
||||
case FRSKY_DATA4:
|
||||
#ifdef MULTI_SYNC
|
||||
telemetry_set_input_sync(9000);
|
||||
#endif
|
||||
@@ -251,11 +345,19 @@ uint16_t ReadFrSkyX()
|
||||
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
||||
if (len && (len<=(0x0E + 3))) //Telemetry frame is 17
|
||||
{
|
||||
//debug("Telem:");
|
||||
packet_count=0;
|
||||
CC2500_ReadData(packet_in, len);
|
||||
#if defined TELEMETRY
|
||||
frsky_check_telemetry(packet_in,len); //Check and parse telemetry packets
|
||||
if(protocol==PROTO_FRSKYX || (protocol==PROTO_FRSKYX2 && (packet_in[len-1] & 0x80)) )
|
||||
{//with valid crc for FRSKYX2
|
||||
//Debug
|
||||
//for(uint8_t i=0;i<len;i++)
|
||||
// debug(" %02X",packet_in[i]);
|
||||
frsky_check_telemetry(packet_in,len); //Check and parse telemetry packets
|
||||
}
|
||||
#endif
|
||||
//debugln("");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -278,61 +380,8 @@ uint16_t ReadFrSkyX()
|
||||
}
|
||||
CC2500_Strobe(CC2500_SFRX); //Flush the RXFIFO
|
||||
}
|
||||
FrSkyX_build_packet();
|
||||
state = FRSKY_DATA1;
|
||||
#if not defined(FRSKYX_LBT)
|
||||
return 500;
|
||||
#endif // for LBT just continue to DATA1 right away
|
||||
case FRSKY_DATA1:
|
||||
if ( prev_option != option )
|
||||
{
|
||||
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); //Frequency offset hack
|
||||
prev_option = option ;
|
||||
}
|
||||
FrSkyX_set_start(hopping_frequency_no);
|
||||
transmit=true;
|
||||
#ifdef FRSKYX_LBT
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
delayMicroseconds(90); //Wait for the freq to stabilize
|
||||
CC2500_Strobe(CC2500_SRX); //Acquire RSSI
|
||||
state++;
|
||||
return 500;
|
||||
case FRSKY_DATA2:
|
||||
uint8_t rssi;
|
||||
rssi = CC2500_ReadReg(CC2500_34_RSSI | CC2500_READ_BURST); // 0.5 db/count, RSSI value read from the RSSI status register is a 2's complement number
|
||||
if ((sub_protocol & 2) && rssi > 72 && rssi < 128) //LBT and RSSI between -36 and -8.5 dBm
|
||||
{
|
||||
transmit=false;
|
||||
debugln("Busy %d %d",hopping_frequency_no,rssi);
|
||||
}
|
||||
#endif
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
CC2500_Strobe(CC2500_SFRX);
|
||||
CC2500_SetTxRxMode(TX_EN);
|
||||
CC2500_SetPower();
|
||||
hopping_frequency_no = (hopping_frequency_no+FrSkyX_chanskip)%47;
|
||||
if(transmit)
|
||||
{
|
||||
#ifdef DEBUG_SERIAL
|
||||
uint16_t fr_cur=millis();
|
||||
fr_time=fr_cur-fr_time;
|
||||
if(fr_time!=9)
|
||||
debugln("Bad timing: %d",fr_time);
|
||||
fr_time=fr_cur;
|
||||
#endif
|
||||
CC2500_WriteData(packet, packet[0]+1);
|
||||
}
|
||||
state=FRSKY_DATA3;
|
||||
return 5200;
|
||||
case FRSKY_DATA3:
|
||||
CC2500_SetTxRxMode(RX_EN);
|
||||
CC2500_Strobe(CC2500_SIDLE);
|
||||
state++;
|
||||
return 200;
|
||||
case FRSKY_DATA4:
|
||||
CC2500_Strobe(CC2500_SRX);
|
||||
state++;
|
||||
return 3100;
|
||||
return 500; // FCC & LBT v2.1
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -340,15 +389,23 @@ uint16_t ReadFrSkyX()
|
||||
uint16_t initFrSkyX()
|
||||
{
|
||||
set_rx_tx_addr(MProtocol_id_master);
|
||||
Frsky_init_hop();
|
||||
|
||||
if(protocol==PROTO_FRSKYX)
|
||||
Frsky_init_hop();
|
||||
else
|
||||
{
|
||||
#ifdef FRSKYX2_FORCE_ID
|
||||
rx_tx_addr[3]=0x0E;
|
||||
rx_tx_addr[2]=0x1C;
|
||||
FrSkyX_chanskip=18;
|
||||
#endif
|
||||
FrSkyX2_init_hop();
|
||||
}
|
||||
|
||||
packet_count=0;
|
||||
while(!FrSkyX_chanskip)
|
||||
FrSkyX_chanskip=random(0xfefefefe)%47;
|
||||
|
||||
//for test***************
|
||||
//rx_tx_addr[3]=0xB3;
|
||||
//rx_tx_addr[2]=0xFD;
|
||||
//************************
|
||||
FrSkyX_init();
|
||||
|
||||
if(IS_BIND_IN_PROGRESS)
|
||||
|
||||
Reference in New Issue
Block a user