/*
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 .
*/
#if defined(WFLY_CYRF6936_INO)
#include "iface_cyrf6936.h"
//#define WFLY_FORCE_ID
#define WFLY_BIND_COUNT 1500 // around 15s
#define WFLY_NUM_FREQUENCE 4
#define WFLY_BIND_CHANNEL 0x09
enum {
WFLY_BIND_TX=0,
WFLY_BIND_PREP_RX,
WFLY_BIND_RX,
WFLY_PREP_DATA,
WFLY_DATA,
};
const uint8_t PROGMEM WFLY_sop_bind[]={ 0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46 };
const uint8_t PROGMEM WFLY_sop_data[]={ 0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A };
//Most of the bytes are unknown... 1C A7 looks to be the bind ID, BF 13 is the TX ID, 15 is the channel used to send the hopping frequencies.
const uint8_t PROGMEM WFLY_bind_packet[]={ 0x1C, 0xA7, 0x60, 0x04, 0x04, 0xBF, 0x13, 0x15, 0xC5, 0x40, 0x8A, 0x37, 0xE0, 0xE8, 0x03, 0xA3 };
const uint8_t PROGMEM WFLY_init_vals[][2] = {
//Init from dump
{CYRF_1D_MODE_OVERRIDE, 0x19}, // Reset
{CYRF_32_AUTO_CAL_TIME, 0x3C}, // Default init value
{CYRF_35_AUTOCAL_OFFSET, 0x14}, // Default init value
{CYRF_1B_TX_OFFSET_LSB, 0x55}, // Default init value
{CYRF_1C_TX_OFFSET_MSB, 0x05}, // Default init value
{CYRF_06_RX_CFG, 0x48 | 0x02}, // LNA enabled, Fast Turn Mode enabled, adding overwrite enable to not lockup RX
{CYRF_10_FRAMING_CFG, 0xE8}, // SOP enable
{CYRF_03_TX_CFG, 0x08 | CYRF_BIND_POWER}, // Original=0x0F, 8DR Mode, 32 chip codes
{CYRF_0C_XTAL_CTRL, 0xC4}, // Enable XOUT as GPIO
{CYRF_0D_IO_CFG, 0x04}, // Enable PACTL as GPIO
{CYRF_0F_XACT_CFG, 0x21}, // Abort current operation
{CYRF_1E_RX_OVERRIDE, 0x00}, // Accept packets with 0 seed for bind
{CYRF_15_CRC_SEED_LSB, 0x00}, // CRC seed for bind
{CYRF_16_CRC_SEED_MSB, 0x00}, // CRC seed for bind
};
static void __attribute__((unused)) WFLY_cyrf_bind_config()
{
for(uint8_t i = 0; i < sizeof(WFLY_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1]));
CYRF_PROGMEM_ConfigSOPCode(WFLY_sop_bind);
CYRF_ConfigRFChannel(WFLY_BIND_CHANNEL);
CYRF_SetTxRxMode(TX_EN);
}
static void __attribute__((unused)) WFLY_cyrf_data_config()
{
for(uint8_t i = 0; i < (sizeof(WFLY_init_vals) / 2)-3; i++)
CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1]));
//CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x08); // Do not accept CRC with 0 seed but not needed since the RX is not sending any data...
CYRF_WriteRegister(CYRF_15_CRC_SEED_LSB, rx_tx_addr[2]);
CYRF_WriteRegister(CYRF_16_CRC_SEED_MSB, rx_tx_addr[3]);
CYRF_PROGMEM_ConfigSOPCode(WFLY_sop_data);
CYRF_SetTxRxMode(TX_EN);
}
static uint16_t __attribute__((unused)) WFLY_send_data_packet()
{
packet_count++;
packet[0] = rx_tx_addr[2];
packet[1] = rx_tx_addr[3];
if(packet_count%4==3)
{ // Send the hopping frequencies
packet[2]=0x70; // packet type
packet[3]=0x04; // unknown
packet[4]=0x00; // unknown
packet[5]=0x04; // unknown
packet[6]=hopping_frequency[0];
packet[7]=hopping_frequency[0];
packet[8]=hopping_frequency[1];
packet[9]=hopping_frequency[2];
len=10; // packet[10] contains the checksum
}
else
{ // Send sticks packet
uint8_t nbr_ch=option;
if(nbr_ch<4) nbr_ch=9; // 4 channels min can be sent, default to 9
if(nbr_ch>9) nbr_ch=9; // 9 channels max can be sent
packet[2]=nbr_ch-3; // nbr of channels to follow
packet[3]=packet_count>>2; // packet counter 0x00..0x3F
len=4;
for(uint8_t i=0;i<3;i++)
{ // Channels
uint16_t ch = convert_channel_16b_nolimit(i*4+0,151,847,IS_FAILSAFE_VALUES_on);
uint8_t offset=i*5;
packet[3+offset] |= ch<<6;
packet[4+offset] = ch>>2;
len++;
if(--nbr_ch==0) break;
ch = convert_channel_16b_nolimit(i*4+1,151,847,IS_FAILSAFE_VALUES_on);
packet[5+offset] = ch;
packet[6+offset] = ch>>8;
len+=2;
if(--nbr_ch==0) break;
ch = convert_channel_16b_nolimit(i*4+2,151,847,IS_FAILSAFE_VALUES_on);
packet[6+offset] |= ch<<2;
packet[7+offset] = ch>>6;
len++;
if(--nbr_ch==0) break;
ch = convert_channel_16b_nolimit(i*4+3,151,847,IS_FAILSAFE_VALUES_on);
packet[7+offset] |= ch<<4;
packet[8+offset] = ch>>4;
len++;
if(--nbr_ch==0) break;
}
#ifdef FAILSAFE_ENABLE
if(IS_FAILSAFE_VALUES_on)
{
packet[2] |= 0x10; // 19 times 3 times 0x10 followed by 3 times 0x18 and so on but 1 time 0x10 seems to be enough for the RX to learn
FAILSAFE_VALUES_off;
}
#endif
}
uint8_t sum=0;
for(uint8_t i = 0; i < len; i++)
sum += packet[i];
packet[len] = sum;
CYRF_ConfigRFChannel(hopping_frequency[(packet_count)%4]);
CYRF_SetPower(0x08);
CYRF_WriteDataPacketLen(packet, len+1);
switch(packet_count%4)
{
case 0:
return 1393;
case 1:
return 1330;
case 2:
return 1555;
}
return 1093; // case 3
}
uint16_t WFLY_callback()
{
uint8_t status,len,sum=0,check=0;
uint8_t start;
static uint8_t retry;
switch(phase)
{
case WFLY_BIND_TX:
CYRF_SetTxRxMode(TX_EN);
CYRF_WriteDataPacketLen(packet, sizeof(WFLY_bind_packet));
debug("P=");
for(uint8_t i=0;i=10)
{ // Good packet received
if(packet_in[2]==0x64)
{ // Switch to normal mode
BIND_DONE;
phase=WFLY_PREP_DATA;
return 10000;
}
memcpy((void *)packet,(void *)packet_in,0x10); // Send back to the RX what we've just received with no modifications
}
phase=WFLY_BIND_TX;
return 200;
}
}
if(status & 0x85 || --retry == 0)
{ // RX error or no answer
debugln("Abort");
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort
CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x21); // Force end state
CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort
phase=WFLY_BIND_TX; // Retry sending bind packet
}
return 700;
case WFLY_PREP_DATA:
WFLY_cyrf_data_config();
packet_count=0;
phase++;
case WFLY_DATA:
#ifdef MULTI_SYNC
telemetry_set_input_sync(5371);
#endif
start=micros();
while ((uint8_t)((uint8_t)micros()-(uint8_t)start) < 200)
if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00)
break; // Packet transmission complete
return WFLY_send_data_packet();
}
return 1000;
}
void WFLY_init()
{
//Random start channel
uint8_t ch=0x0A+random(0xfefefefe)%0x0E;
if(ch%3==0)
ch++; // remove these channels as they seem to not be working...
rf_ch_num=0x0C+(rx_tx_addr[1]&0x03)*3; // use the start channels which do not seem to work to send the hopping table instead
#ifdef WFLY_FORCE_ID // data taken from TX dump
rx_tx_addr[2]=0xBF; // ID
rx_tx_addr[3]=0x13; // ID
ch=0x16; // value seen between 0x0A and 0x17
rf_ch_num=0x15 // RF channel to send the current hopping table
#endif
debug("ID:")
for(uint8_t i=0;i<2;i++)
debug(" %02X", rx_tx_addr[2+i]);
debugln("");
hopping_frequency[0]=ch;
hopping_frequency[1]=ch+0x1E;
hopping_frequency[2]=ch+0x2D;
hopping_frequency[3]=rf_ch_num; // RF channel used to send the current hopping table
debug("RF Channels:")
for(uint8_t i=0;i