396 lines
11 KiB
Arduino
Raw Normal View History

2017-11-20 16:01:12 +01:00
/* **************************
* By Midelic on RCGroups *
**************************
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(FRSKYX_CC2500_INO)
#include "iface_cc2500.h"
uint8_t FrSkyX_chanskip;
2019-10-02 20:09:18 +02:00
uint8_t FrSkyX_TX_Seq, FrSkyX_TX_IN_Seq;
uint8_t FrSkyX_RX_Seq ;
2017-11-20 16:01:12 +01:00
2019-10-02 20:09:18 +02:00
#ifdef SPORT_SEND
struct t_FrSkyX_TX_Frame
{
uint8_t count;
2019-10-03 16:38:50 +02:00
uint8_t payload[8];
2019-10-02 20:09:18 +02:00
} ;
// Store FrskyX telemetry
struct t_FrSkyX_TX_Frame FrSkyX_TX_Frames[4] ;
#endif
#define FrSkyX_FAILSAFE_TIMEOUT 1032
static void __attribute__((unused)) FrSkyX_set_start(uint8_t ch )
2017-11-20 16:01:12 +01:00
{
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch]);
CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[ch]);
}
static void __attribute__((unused)) FrSkyX_init()
2017-11-20 16:01:12 +01:00
{
FRSKY_init_cc2500((sub_protocol&2)?FRSKYXEU_cc2500_conf:FRSKYX_cc2500_conf); // LBT or FCC
//
for(uint8_t c=0;c < 48;c++)
{//calibrate hop channels
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);
}
//#######END INIT########
}
static void __attribute__((unused)) FrSkyX_initialize_data(uint8_t adr)
2017-11-20 16:01:12 +01:00
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
CC2500_WriteReg(CC2500_18_MCSM0, 0x8);
CC2500_WriteReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]);
CC2500_WriteReg(CC2500_07_PKTCTRL1,0x05);
}
static void __attribute__((unused)) FrSkyX_build_bind_packet()
2017-11-20 16:01:12 +01:00
{
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);
uint16_t lcrc = FrSkyX_crc(&packet[3], limit-3);
2017-11-20 16:01:12 +01:00
//
packet[limit++] = lcrc >> 8;
packet[limit] = lcrc;
//
}
2017-12-10 09:48:20 +01:00
// 0-2047, 0 = 817, 1024 = 1500, 2047 = 2182
//64=860,1024=1500,1984=2140//Taranis 125%
static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX( uint8_t i )
2017-12-10 09:48:20 +01:00
{ //mapped 860,2140(125%) range to 64,1984(PXX values);
uint16_t chan_val=convert_channel_frsky(i)-1226;
2017-12-10 09:48:20 +01:00
if(i>7) chan_val|=2048; // upper channels offset
return chan_val;
}
#ifdef FAILSAFE_ENABLE
static uint16_t __attribute__((unused)) FrSkyX_scaleForPXX_FS( uint8_t i )
2017-12-10 09:48:20 +01:00
{ //mapped 1,2046(125%) range to 64,1984(PXX values);
uint16_t chan_val=((Failsafe_data[i]*15)>>4)+64;
if(Failsafe_data[i]==FAILSAFE_CHANNEL_NOPULSES)
chan_val=FAILSAFE_CHANNEL_NOPULSES;
else if(Failsafe_data[i]==FAILSAFE_CHANNEL_HOLD)
chan_val=FAILSAFE_CHANNEL_HOLD;
if(i>7) chan_val|=2048; // upper channels offset
return chan_val;
}
#endif
#define FrSkyX_FAILSAFE_TIME 1032
static void __attribute__((unused)) FrSkyX_build_packet()
2017-11-20 16:01:12 +01:00
{
//0x1D 0xB3 0xFD 0x02 0x56 0x07 0x15 0x00 0x00 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x12
//
2017-12-10 09:48:20 +01:00
static uint8_t chan_offset=0;
2017-11-20 16:01:12 +01:00
uint16_t chan_0 ;
uint16_t chan_1 ;
//
2017-12-10 09:48:20 +01:00
// data frames sent every 9ms; failsafe every 9 seconds
#ifdef FAILSAFE_ENABLE
static uint16_t failsafe_count=0;
static uint8_t FS_flag=0,failsafe_chan=0;
if (FS_flag == 0 && failsafe_count > FrSkyX_FAILSAFE_TIME && chan_offset == 0 && IS_FAILSAFE_VALUES_on)
2017-12-10 09:48:20 +01:00
{
FS_flag = 0x10;
failsafe_chan = 0;
} else if (FS_flag & 0x10 && failsafe_chan < (sub_protocol & 0x01 ? 8-1:16-1))
{
FS_flag = 0x10 | ((FS_flag + 2) & 0x0F); //10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
failsafe_chan ++;
} else if (FS_flag & 0x10)
{
FS_flag = 0;
failsafe_count = 0;
}
failsafe_count++;
#endif
packet[0] = (sub_protocol & 0x02 ) ? 0x20 : 0x1D ; // LBT or FCC
2017-11-20 16:01:12 +01:00
packet[1] = rx_tx_addr[3];
packet[2] = rx_tx_addr[2];
packet[3] = 0x02;
//
packet[4] = (FrSkyX_chanskip<<6)|hopping_frequency_no;
packet[5] = FrSkyX_chanskip>>2;
2017-11-20 16:01:12 +01:00
packet[6] = RX_num;
//packet[7] = FLAGS 00 - standard packet
//10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet
//20 - range check packet
#ifdef FAILSAFE_ENABLE
packet[7] = FS_flag;
#else
packet[7] = 0;
#endif
2017-11-20 16:01:12 +01:00
packet[8] = 0;
//
uint8_t startChan = chan_offset;
for(uint8_t i = 0; i <12 ; i+=3)
2017-12-10 09:48:20 +01:00
{//12 bytes of channel data
#ifdef FAILSAFE_ENABLE
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (startChan & 0x07)) )
chan_0 = FrSkyX_scaleForPXX_FS(failsafe_chan);
2017-12-10 09:48:20 +01:00
else
#endif
chan_0 = FrSkyX_scaleForPXX(startChan);
2017-12-10 09:48:20 +01:00
startChan++;
2017-11-20 16:01:12 +01:00
//
2017-12-10 09:48:20 +01:00
#ifdef FAILSAFE_ENABLE
if( (FS_flag & 0x10) && ((failsafe_chan & 0x07) == (startChan & 0x07)) )
chan_1 = FrSkyX_scaleForPXX_FS(failsafe_chan);
2017-12-10 09:48:20 +01:00
else
#endif
chan_1 = FrSkyX_scaleForPXX(startChan);
2017-12-10 09:48:20 +01:00
startChan++;
2017-11-20 16:01:12 +01:00
//
2017-12-10 09:48:20 +01:00
packet[9+i] = lowByte(chan_0); //3 bytes*4
2017-11-20 16:01:12 +01:00
packet[9+i+1]=(((chan_0>>8) & 0x0F)|(chan_1 << 4));
packet[9+i+2]=chan_1>>4;
}
2017-12-10 09:48:20 +01:00
if(sub_protocol & 0x01 ) // in X8 mode send only 8ch every 9ms
chan_offset = 0 ;
2017-11-20 16:01:12 +01:00
else
2017-12-10 09:48:20 +01:00
chan_offset^=0x08;
2017-11-20 16:01:12 +01:00
2019-10-02 20:09:18 +02:00
//sequence and send SPort
2017-11-20 16:01:12 +01:00
uint8_t limit = (sub_protocol & 2 ) ? 31 : 28 ;
for (uint8_t i=22;i<limit;i++)
packet[i]=0;
2019-10-02 20:09:18 +02:00
packet[21] = FrSkyX_RX_Seq << 4;//TX=8 at startup
#ifdef SPORT_SEND
2019-10-02 20:09:18 +02:00
if (FrSkyX_TX_IN_Seq!=0xFF)
{//RX has replied at least once
if (FrSkyX_TX_IN_Seq & 0x08)
{//Request init
2019-10-03 16:38:50 +02:00
//debugln("Init");
2019-10-02 20:09:18 +02:00
FrSkyX_TX_Seq = 0 ;
for(uint8_t i=0;i<4;i++)
FrSkyX_TX_Frames[i].count=0; // discard frames in current output buffer
}
else if (FrSkyX_TX_IN_Seq & 0x04)
{//Retransmit the requested packet
2019-10-03 16:38:50 +02:00
debugln("Retry:%d",FrSkyX_TX_IN_Seq&0x03);
packet[21] |= FrSkyX_TX_IN_Seq&0x03;
packet[22] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq&0x03].count;
2019-10-02 20:09:18 +02:00
for (uint8_t i=23;i<23+FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq&0x03].count;i++)
packet[i] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq&0x03].payload[i];
}
else if ( FrSkyX_TX_Seq != 0x08 )
{
2019-10-03 16:38:50 +02:00
if(FrSkyX_TX_Seq==FrSkyX_TX_IN_Seq)
2019-10-02 20:09:18 +02:00
{//Send packet from the incoming radio buffer
2019-10-03 16:38:50 +02:00
//debugln("Send:%d",FrSkyX_TX_Seq);
packet[21] |= FrSkyX_TX_Seq;
2019-10-02 20:09:18 +02:00
uint8_t nbr_bytes=0;
for (uint8_t i=23;i<limit;i++)
{
if(SportHead==SportTail)
break; //buffer empty
2019-10-03 16:38:50 +02:00
packet[i]=SportData[SportHead];
FrSkyX_TX_Frames[FrSkyX_TX_Seq].payload[i-23]=SportData[SportHead];
2019-10-02 20:09:18 +02:00
SportHead=(SportHead+1) & (MAX_SPORT_BUFFER-1);
nbr_bytes++;
}
2019-10-03 16:38:50 +02:00
packet[22]=nbr_bytes;
FrSkyX_TX_Frames[FrSkyX_TX_Seq].count=nbr_bytes;
if(nbr_bytes)
{//Check the buffer status
uint8_t used = SportTail;
if ( SportHead >= SportTail )
used += MAX_SPORT_BUFFER - SportHead ;
else
used -= SportHead ;
if ( used < (MAX_SPORT_BUFFER>>1) )
{
2019-10-03 16:38:50 +02:00
DATA_BUFFER_LOW_off;
debugln("Ok buf:%d",used);
}
2019-10-03 16:38:50 +02:00
}
2019-10-02 20:09:18 +02:00
FrSkyX_TX_Seq = ( FrSkyX_TX_Seq + 1 ) & 0x03 ; // Next iteration send next packet
}
else
2019-10-03 16:38:50 +02:00
{//Not in sequence somehow, transmit what the receiver wants but why not asking for retransmit...
//debugln("RX_Seq:%d,TX:%d",FrSkyX_TX_IN_Seq,FrSkyX_TX_Seq);
2019-10-02 20:09:18 +02:00
packet[21] |= FrSkyX_TX_IN_Seq;
2019-10-03 16:38:50 +02:00
packet[22] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq].count;
for (uint8_t i=23;i<23+FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq].count;i++)
packet[i] = FrSkyX_TX_Frames[FrSkyX_TX_IN_Seq].payload[i-23];
2019-10-02 20:09:18 +02:00
}
}
else
packet[21] |= 0x08 ; //FrSkyX_TX_Seq=8 at startup
}
2019-10-02 20:09:18 +02:00
if(packet[22])
{//Debug
2019-10-03 16:38:50 +02:00
debug("SP: ");
2019-10-02 20:09:18 +02:00
for(uint8_t i=0;i<packet[22];i++)
debug("%02X ",packet[23+i]);
debugln("");
}
2019-10-02 20:09:18 +02:00
#else
packet[21] |= FrSkyX_TX_Seq ;//TX=8 at startup
if ( !(FrSkyX_TX_IN_Seq & 0xF8) )
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);
2017-11-20 16:01:12 +01:00
packet[limit++]=lcrc>>8;//high byte
packet[limit]=lcrc;//low byte
}
uint16_t ReadFrSkyX()
{
switch(state)
{
default:
FrSkyX_set_start(47);
2017-11-20 16:01:12 +01:00
CC2500_SetPower();
CC2500_Strobe(CC2500_SFRX);
//
FrSkyX_build_bind_packet();
2017-11-20 16:01:12 +01:00
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteData(packet, packet[0]+1);
if(IS_BIND_DONE)
2017-11-20 16:01:12 +01:00
state = FRSKY_BIND_DONE;
else
state++;
return 9000;
case FRSKY_BIND_DONE:
FrSkyX_initialize_data(0);
2017-11-20 16:01:12 +01:00
hopping_frequency_no=0;
BIND_DONE;
state++;
break;
case FRSKY_DATA1:
if ( prev_option != option )
{
CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack
prev_option = option ;
}
CC2500_SetTxRxMode(TX_EN);
FrSkyX_set_start(hopping_frequency_no);
2017-11-20 16:01:12 +01:00
CC2500_SetPower();
CC2500_Strobe(CC2500_SFRX);
hopping_frequency_no = (hopping_frequency_no+FrSkyX_chanskip)%47;
2017-11-20 16:01:12 +01:00
CC2500_Strobe(CC2500_SIDLE);
CC2500_WriteData(packet, packet[0]+1);
state++;
return 5200;
case FRSKY_DATA2:
CC2500_SetTxRxMode(RX_EN);
CC2500_Strobe(CC2500_SIDLE);
state++;
return 200;
case FRSKY_DATA3:
CC2500_Strobe(CC2500_SRX);
state++;
return 3100;
case FRSKY_DATA4:
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
2019-10-02 20:09:18 +02:00
if (len && (len<=(0x0E + 3))) //Telemetry frame is 17
2017-11-20 16:01:12 +01:00
{
packet_count=0;
CC2500_ReadData(packet_in, len);
2017-11-20 16:01:12 +01:00
#if defined TELEMETRY
frsky_check_telemetry(packet_in,len); //check if valid telemetry packets
2017-11-20 16:01:12 +01:00
//parse telemetry packets here
//The same telemetry function used by FrSky(D8).
#endif
}
else
{
packet_count++;
// restart sequence on missed packet - might need count or timeout instead of one missed
if(packet_count>100)
{//~1sec
2019-10-02 20:09:18 +02:00
FrSkyX_TX_Seq = 0x08 ; // Request init
FrSkyX_TX_IN_Seq = 0xFF ; // No sequence received yet
#ifdef SPORT_SEND
for(uint8_t i=0;i<4;i++)
FrSkyX_TX_Frames[i].count=0; // discard frames in current output buffer
#endif
2017-11-20 16:01:12 +01:00
packet_count=0;
#if defined TELEMETRY
telemetry_lost=1;
#endif
}
CC2500_Strobe(CC2500_SFRX); //flush the RXFIFO
}
FrSkyX_build_packet();
2017-11-20 16:01:12 +01:00
state = FRSKY_DATA1;
return 500;
}
return 1;
}
uint16_t initFrSkyX()
{
set_rx_tx_addr(MProtocol_id_master);
Frsky_init_hop();
packet_count=0;
while(!FrSkyX_chanskip)
FrSkyX_chanskip=random(0xfefefefe)%47;
2017-11-20 16:01:12 +01:00
//for test***************
//rx_tx_addr[3]=0xB3;
//rx_tx_addr[2]=0xFD;
//************************
FrSkyX_init();
if(IS_BIND_IN_PROGRESS)
2017-11-20 16:01:12 +01:00
{
state = FRSKY_BIND;
FrSkyX_initialize_data(1);
2017-11-20 16:01:12 +01:00
}
else
{
state = FRSKY_DATA1;
FrSkyX_initialize_data(0);
2017-11-20 16:01:12 +01:00
}
2019-10-02 20:09:18 +02:00
FrSkyX_TX_Seq = 0x08 ; // Request init
FrSkyX_TX_IN_Seq = 0xFF ; // No sequence received yet
#ifdef SPORT_SEND
for(uint8_t i=0;i<4;i++)
FrSkyX_TX_Frames[i].count=0; // discard frames in current output buffer
2019-10-03 16:38:50 +02:00
SportHead=SportTail=0; // empty data buffer
2019-10-02 20:09:18 +02:00
#endif
FrSkyX_RX_Seq = 0 ; // Seq 0 to start with
2017-11-20 16:01:12 +01:00
return 10000;
}
#endif