mirror of
https://github.com/pascallanger/DIY-Multiprotocol-TX-Module.git
synced 2025-02-04 20:48:12 +00:00
291 lines
8.1 KiB
C++
291 lines
8.1 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(FRSKYX_CC2500_INO)
|
|
|
|
#include "iface_cc2500.h"
|
|
|
|
static void __attribute__((unused)) FrSkyX_build_bind_packet()
|
|
{
|
|
//Header
|
|
packet[0] = packet_length; // 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] = rx_tx_addr[1]; // ID
|
|
packet[12] = RX_num;
|
|
//
|
|
memset(&packet[13], 0, packet_length - 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
|
|
//Unknown bytes
|
|
if(state & 0x01)
|
|
memcpy(&packet[7],"\x00\x18\x0A\x00\x00\xE0\x02\x0B\x01\xD3\x08\x00\x00\x4C\xFE\x87\xC7",17);
|
|
else
|
|
memcpy(&packet[7],"\x27\xAD\x02\x00\x00\x64\xC8\x46\x00\x64\x00\x00\x00\xFB\xF6\x87\xC7",17);
|
|
//ID
|
|
packet[5] = rx_tx_addr[1]; // ID
|
|
packet[6] = RX_num;
|
|
//Bind flags
|
|
if(binding_idx&0x01)
|
|
packet[7] |= 0x40; // Telem off
|
|
if(binding_idx&0x02)
|
|
packet[7] |= 0x80; // CH9-16
|
|
//Replace the ID
|
|
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_length-1; i++)
|
|
packet[i] ^= 0xA7;
|
|
}
|
|
//CRC
|
|
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_length-4);
|
|
packet[packet_length-1] = lcrc >> 8;
|
|
packet[packet_length] = lcrc;
|
|
|
|
/*//Debug
|
|
debug("Bind:");
|
|
for(uint8_t i=0;i<=packet_length;i++)
|
|
debug(" %02X",packet[i]);
|
|
debugln("");*/
|
|
}
|
|
|
|
static void __attribute__((unused)) FrSkyX_build_packet()
|
|
{
|
|
//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
|
|
// data frames sent every 9ms; failsafe every 9 seconds
|
|
//
|
|
//Header
|
|
packet[0] = packet_length; // 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] = rx_tx_addr[1]; // Unknown but constant ID?
|
|
//
|
|
packet[4] = (FrSkyX_chanskip<<6)|hopping_frequency_no;
|
|
packet[5] = FrSkyX_chanskip>>2;
|
|
packet[6] = RX_num;
|
|
|
|
//Channels
|
|
FrSkyX_channels(7); // Set packet[7]=failsafe, packet[8]=0?? and packet[9..20]=channels data
|
|
|
|
//Sequence and send SPort
|
|
FrSkyX_seq_sport(21,packet_length-(protocol==PROTO_FRSKYX && (FrSkyFormat & 2 )) ? 4 : 2); //21=RX|TXseq, 22=bytes count, 23..packet_length-2=data
|
|
|
|
//CRC
|
|
uint16_t lcrc = FrSkyX_crc(&packet[3], packet_length-4);
|
|
packet[packet_length-1] = lcrc >> 8;
|
|
packet[packet_length] = lcrc;
|
|
|
|
/*//Debug
|
|
debug("Norm:");
|
|
for(uint8_t i=0;i<=packet_length;i++)
|
|
debug(" %02X",packet[i]);
|
|
debugln("");*/
|
|
}
|
|
|
|
uint16_t FRSKYX_callback()
|
|
{
|
|
#if defined MULTI_EU
|
|
if(sub_protocol == CH_16 || sub_protocol == CH_8)
|
|
return 9000;
|
|
#endif
|
|
switch(state)
|
|
{
|
|
default:
|
|
FrSkyX_set_start(47);
|
|
CC2500_SetPower();
|
|
CC2500_Strobe(CC2500_SFRX);
|
|
//
|
|
FrSkyX_build_bind_packet();
|
|
CC2500_Strobe(CC2500_SIDLE);
|
|
CC2500_WriteData(packet, packet[0]+1);
|
|
if(IS_BIND_DONE)
|
|
state = FRSKY_BIND_DONE;
|
|
else
|
|
state++;
|
|
break;
|
|
case FRSKY_BIND_DONE:
|
|
FrSkyX_initialize_data(0);
|
|
hopping_frequency_no=0;
|
|
BIND_DONE;
|
|
state++; //FRSKY_DATA1
|
|
break;
|
|
|
|
case FRSKY_DATA1:
|
|
CC2500_Strobe(CC2500_SIDLE);
|
|
CC2500_SetFreqOffset();
|
|
FrSkyX_set_start(hopping_frequency_no);
|
|
FrSkyX_build_packet();
|
|
if(FrSkyFormat & 2)
|
|
{// LBT
|
|
CC2500_Strobe(CC2500_SRX); //Acquire RSSI
|
|
state++;
|
|
return 400; // LBT
|
|
}
|
|
case FRSKY_DATA2:
|
|
if(FrSkyFormat & 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 > 14 && rssi < 128) //if RSSI above -65dBm (12=-70) => ETSI requirement
|
|
#endif
|
|
{
|
|
LBT_POWER_on; //Reduce to low power before transmitting
|
|
debugln("Busy %d %d",hopping_frequency_no,rssi);
|
|
}
|
|
}
|
|
CC2500_Strobe(CC2500_SIDLE);
|
|
CC2500_Strobe(CC2500_SFTX); //Flush the TXFIFO
|
|
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(FrSkyFormat & 2)
|
|
return 4000; // LBT
|
|
else
|
|
return 5200; // FCC
|
|
case FRSKY_DATA3:
|
|
CC2500_Strobe(CC2500_SIDLE);
|
|
CC2500_Strobe(CC2500_SFRX); //Flush the RXFIFO
|
|
CC2500_SetTxRxMode(RX_EN);
|
|
CC2500_Strobe(CC2500_SRX);
|
|
state++;
|
|
if(FrSkyFormat & 2)
|
|
return 4200; // LBT
|
|
else
|
|
return 3400; // FCC
|
|
case FRSKY_DATA4:
|
|
#ifdef MULTI_SYNC
|
|
telemetry_set_input_sync(9000);
|
|
#endif
|
|
#if defined TELEMETRY
|
|
len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
|
if (len && len <= 17) //Telemetry frame is 17 bytes
|
|
{
|
|
//debug("Telem:");
|
|
CC2500_ReadData(packet_in, len); //Read what has been received so far
|
|
if(len<17)
|
|
{//not all bytes were received
|
|
uint8_t last_len=CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
|
|
if(last_len==17) //All bytes received
|
|
{
|
|
CC2500_ReadData(packet_in+len, last_len-len); //Finish to read
|
|
len=17;
|
|
}
|
|
}
|
|
if(len==17 && (protocol==PROTO_FRSKYX || (protocol==PROTO_FRSKYX2 && (packet_in[len-1] & 0x80))) )
|
|
{//Telemetry received with valid crc for FRSKYX2
|
|
//Debug
|
|
//for(uint8_t i=0;i<len;i++)
|
|
// debug(" %02X",packet_in[i]);
|
|
if(frsky_process_telemetry(packet_in,len)) //Check and process telemetry packet
|
|
{//good packet received
|
|
pps_counter++;
|
|
if(TX_LQI==0)
|
|
TX_LQI++; //Recover telemetry right away
|
|
}
|
|
}
|
|
//debugln("");
|
|
}
|
|
if (millis() - pps_timer >= 900)
|
|
{//1 packet every 9ms
|
|
pps_timer = millis();
|
|
debugln("%d pps", pps_counter);
|
|
TX_LQI = pps_counter; //Max=100%
|
|
pps_counter = 0;
|
|
}
|
|
if(TX_LQI==0)
|
|
FrSkyX_telem_init(); //Reset telemetry
|
|
else
|
|
telemetry_link=1; //Send telemetry out anyway
|
|
#endif
|
|
state = FRSKY_DATA1;
|
|
return 400; // FCC & LBT
|
|
}
|
|
return 9000;
|
|
}
|
|
|
|
void FRSKYX_init()
|
|
{
|
|
set_rx_tx_addr(MProtocol_id_master);
|
|
FrSkyFormat = sub_protocol;
|
|
|
|
if (sub_protocol==XCLONE_16||sub_protocol==XCLONE_8)
|
|
Frsky_init_clone();
|
|
else
|
|
{
|
|
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();
|
|
}
|
|
rx_tx_addr[1]=0x02; // ID related, hw version?
|
|
}
|
|
|
|
if(protocol==PROTO_FRSKYX && (FrSkyFormat & 2 ))
|
|
packet_length = 0x20; // FrSkyX V1 LBT
|
|
else
|
|
packet_length = 0x1D;
|
|
|
|
packet_count=0;
|
|
while(!FrSkyX_chanskip)
|
|
FrSkyX_chanskip=random(0xfefefefe)%47;
|
|
|
|
FrSkyX_RF_init();
|
|
|
|
if(IS_BIND_IN_PROGRESS)
|
|
{
|
|
memset(packet, 0, packet_length);
|
|
state = FRSKY_BIND;
|
|
FrSkyX_initialize_data(1);
|
|
}
|
|
else
|
|
state = FRSKY_BIND_DONE;
|
|
FrSkyX_telem_init();
|
|
}
|
|
#endif
|