/* 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