/* 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(MLINK_CYRF6936_INO) #include "iface_cyrf6936.h" //#define MLINK_FORCE_ID #define MLINK_BIND_COUNT 696 // around 20s #define MLINK_NUM_FREQ 78 #define MLINK_BIND_CHANNEL 0x01 #define MLINK_PACKET_SIZE 8 enum { MLINK_BIND_TX=0, MLINK_BIND_PREP_RX, MLINK_BIND_RX, MLINK_PREP_DATA, MLINK_SEND1, MLINK_SEND2, MLINK_SEND3, MLINK_CHECK3, MLINK_RX, MLINK_BUILD4, }; uint8_t MLINK_Data_Code[16], MLINK_CRC_Init, MLINK_Unk_6_2; const uint8_t PROGMEM MLINK_init_vals[][2] = { //Init from dump { CYRF_01_TX_LENGTH, 0x08 }, // Length of packet { CYRF_02_TX_CTRL, 0x40 }, // Clear TX Buffer { CYRF_03_TX_CFG, 0x3C }, //0x3E in normal mode, 0x3C in bind mode: SDR 64 chip codes (=8 bytes data code used) { CYRF_05_RX_CTRL, 0x00 }, { CYRF_06_RX_CFG, 0x93 }, // AGC enabled, overwrite enable, valid flag enable { CYRF_0B_PWR_CTRL, 0x00 }, //{ CYRF_0C_XTAL_CTRL, 0x00 }, // Set to GPIO on reset //{ CYRF_0D_IO_CFG, 0x00 }, // Set to GPIO on reset //{ CYRF_0E_GPIO_CTRL, 0x00 }, // Set by the CYRF_SetTxRxMode function { CYRF_0F_XACT_CFG, 0x04 }, // end state idle { CYRF_10_FRAMING_CFG, 0x00 }, // SOP disabled { CYRF_11_DATA32_THOLD, 0x05 }, // not used??? { CYRF_12_DATA64_THOLD, 0x0F }, // 64 Chip Data PN Code Correlator Threshold { CYRF_14_EOP_CTRL, 0x05 }, // 5 consecutive noncorrelations symbol for EOP { CYRF_15_CRC_SEED_LSB, 0x00 }, // not used??? { CYRF_16_CRC_SEED_MSB, 0x00 }, // not used??? { CYRF_1B_TX_OFFSET_LSB,0x00 }, { CYRF_1C_TX_OFFSET_MSB,0x00 }, { CYRF_1D_MODE_OVERRIDE,0x00 }, { CYRF_1E_RX_OVERRIDE, 0x14 }, // RX CRC16 is disabled and Force Receive Data Rate { CYRF_1F_TX_OVERRIDE, 0x04 }, // TX CRC16 is disabled { CYRF_26_XTAL_CFG, 0x08 }, { CYRF_29_RX_ABORT, 0x00 }, { CYRF_32_AUTO_CAL_TIME,0x3C }, { CYRF_35_AUTOCAL_OFFSET,0x14 }, { CYRF_39_ANALOG_CTRL, 0x03 }, // Receive invert and all slow }; static void __attribute__((unused)) MLINK_cyrf_config() { for(uint8_t i = 0; i < sizeof(MLINK_init_vals) / 2; i++) CYRF_WriteRegister(pgm_read_byte_near(&MLINK_init_vals[i][0]), pgm_read_byte_near(&MLINK_init_vals[i][1])); CYRF_WritePreamble(0x333304); CYRF_SetTxRxMode(TX_EN); } static void __attribute__((unused)) MLINK_send_bind_packet() { uint8_t p_c=packet_count>>1; memset(packet, p_c<0x16?0x00:0xFF, MLINK_PACKET_SIZE-1); packet[0]=0x0F; // bind packet[1]=p_c; switch(p_c) { case 0x00: packet[2]=0x40; //unknown but seems constant packet[4]=0x01; //unknown but seems constant packet[5]=0x03; //unknown but seems constant packet[6]=0xE3; //unknown but seems constant break; case 0x05: packet[6]=MLINK_CRC_Init; //CRC init value break; case 0x06: packet[2]=MLINK_Unk_6_2; //unknown and different //Start of hopping frequencies for(uint8_t i=0;i<4;i++) packet[i+3]=hopping_frequency[i]; break; case 0x15: packet[6]=0x51; //unknown but seems constant break; case 0x16: packet[2]=0x51; //unknown but seems constant packet[3]=0xEC; //unknown but seems constant packet[4]=0x05; //unknown but seems constant break; case 0x1A: packet[1]=0xFF; memset(&packet[2],0x00,5); break; } if(p_c>=0x01 && p_c<=0x04) {//DATA_CODE uint8_t p_c_5=(p_c-1)*5; for(uint8_t i=0;i<5;i++) if(i+p_c_5<16) packet[i+2]=MLINK_Data_Code[i+p_c_5]; } else if(p_c>=0x07 && p_c<=0x15) {//Hopping frequencies uint8_t p_c_5=5*(p_c-6)-1; for(uint8_t i=0;i<5;i++) if(i+p_c_50x19) { packet[1]=0xFF; memset(&packet[2], 0x00, MLINK_PACKET_SIZE-3); } //Calculate CRC crc8=0xFF; // Init = 0xFF for(uint8_t i=0;i> 4,3448 >> 4,true) : 0x00; start--; // switch to next channel packet[i+1]=val; } } else #endif {// Normal packets if(hopping_frequency_no==0) tog=1; //Channels to be sent if(phase==MLINK_SEND1 || ((hopping_frequency_no%5==0) && (phase==MLINK_SEND2))) { if((hopping_frequency_no&1)==0) packet[0] = 0x09; //10,8,6 else packet[0] = 0x01; //11,9,7 } else if(phase==MLINK_SEND2) { if(tog) packet[0] = 0x02; //x,15,13 else packet[0] = 0x0A; //x,14,12 tog^=1; } else {//phase==MLINK_SEND3 if((hopping_frequency_no&1)==0) packet[0] = 0x88; //4,2,0 else packet[0] = 0x80; //5,3,1 } //Start channel start=4+6*(packet[0]&3); if((packet[0]&0x08)==0) start++; //Channels 426..1937..3448 for(uint8_t i=0;i<3;i++) { uint16_t val=start<16 ? convert_channel_16b_nolimit(start,426,3448,false) : 0x0000; start-=2; // switch to next channel packet[i*2+1]=val>>8; packet[i*2+2]=val; } } //Calculate CRC crc8=bit_reverse(hopping_frequency_no + MLINK_CRC_Init); // Init = relected freq index + offset for(uint8_t i=0;i>1; break; } #if defined HUB_TELEMETRY if(id) { uint16_t val=((packet_in[i+2]&0x80)<<8)|((packet_in[i+2]&0x7F)<<7)|(packet_in[i+1]>>1); //remove the alarm LSB bit, move the sign bit to MSB frsky_send_user_frame(id, val, val>>8); } #endif } } else if(packet_in[0]==0x03) { // RX-5 : 03 15 23 00 00 01 02 //Incoming packet values RX_RSSI = packet_in[2]<<1; // Looks to be the RX RSSI value RX_LQI = packet_in[5]; // Looks to be connection lost } else RX_RSSI = TX_LQI; // Read TX RSSI TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI)&0x1F; if(telemetry_lost) { telemetry_lost = 0; packet_count = 50; telemetry_counter = 100; } } #endif #ifdef MLINK_FW_TELEMETRY static void __attribute__((unused)) MLINK_Send_Telemetry() { telemetry_counter += 2; // TX LQI counter telemetry_link = 4; // Read TX RSSI TX_RSSI = CYRF_ReadRegister(CYRF_13_RSSI)&0x1F; if(telemetry_lost) { telemetry_lost = 0; packet_count = 50; telemetry_counter = 100; } } #endif uint16_t MLINK_callback() { uint8_t status; uint16_t start; switch(phase) { case MLINK_BIND_RX: //debugln("RX"); status=CYRF_ReadRegister(CYRF_05_RX_CTRL); if( (status&0x80) == 0 ) {//Packet received len=CYRF_ReadRegister(CYRF_09_RX_COUNT); debugln("L=%02X",len) if( len==8 ) { CYRF_ReadDataPacketLen(packet, len*2); debug("RX="); for(uint8_t i=0;i<8;i++) debug(" %02X",packet[i*2]); debugln(""); //Check CRC crc8=0xFF; // Init = 0xFF for(uint8_t i=0;i 0x19*2) { if(packet[0] == 0x8F) packet_count++; else if(packet[0] == 0x9F) packet_count=0x80; // End bind else packet_count=0; // Restart bind... } } } } else packet_count=0; CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); // Enable RX abort CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x24); // Force end state CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x00); // Disable RX abort phase=MLINK_BIND_TX; // Retry sending bind packet CYRF_SetTxRxMode(TX_EN); // Transmit mode if(packet_count) return 18136; case MLINK_BIND_TX: if(--bind_counter==0 || packet_count>=0x1B*2) { // Switch to normal mode BIND_DONE; phase=MLINK_PREP_DATA; return 22720; } MLINK_send_bind_packet(); if(packet_count == 0 || packet_count > 0x19*2) { phase++; // MLINK_BIND_PREP_RX return 4700; // Original is 4900 } packet_count++; if(packet_count&1) return 6000; return 22720; case MLINK_BIND_PREP_RX: start=micros(); while ((uint16_t)((uint16_t)micros()-(uint16_t)start) < 200) // Wait max 200µs for TX to finish if((CYRF_ReadRegister(CYRF_02_TX_CTRL) & 0x80) == 0x00) break; // Packet transmission complete CYRF_SetTxRxMode(RX_EN); // Receive mode CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x82); // Prepare to receive phase++; //MLINK_BIND_RX if(packet_count > 0x19*2) return 28712; // Give more time to the RX to confirm that the bind is ok... return 28712-4700; case MLINK_PREP_DATA: CYRF_ConfigDataCode(MLINK_Data_Code); MLINK_CRC_Init += 0xED; hopping_frequency_no = 0x00; CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]); CYRF_SetPower(0x38); #if defined(MLINK_HUB_TELEMETRY) || defined(MLINK_FW_TELEMETRY) packet_count = 0; telemetry_lost = 1; #endif phase++; case MLINK_SEND1: MLINK_send_data_packet(); phase++; return 4880+1111; case MLINK_SEND2: MLINK_send_data_packet(); phase++; if(hopping_frequency_no%5==0) return 4617+1017; return 4617+1422; case MLINK_SEND3: MLINK_send_data_packet(); phase++; return 4611; case MLINK_CHECK3: //Switch to next channel hopping_frequency_no++; if(hopping_frequency_no>=MLINK_NUM_FREQ) hopping_frequency_no=0; CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]); //Receive telemetry if(hopping_frequency_no%5==0) {//Receive telemetry CYRF_SetTxRxMode(RX_EN); // Receive mode CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x82); // Prepare to receive phase++; //MLINK_RX return 8038+2434+410-1000; } else CYRF_SetPower(0x38); phase=MLINK_SEND1; return 4470; case MLINK_RX: #if defined(MLINK_HUB_TELEMETRY) || defined(MLINK_FW_TELEMETRY) //TX LQI calculation packet_count++; if(packet_count>=50) { packet_count=0; TX_LQI=telemetry_counter; if(telemetry_counter==0) telemetry_lost = 1; telemetry_counter = 0; } #endif status=CYRF_ReadRegister(CYRF_05_RX_CTRL); debug("T(%02X):",status); if( (status&0x80) == 0 ) {//Packet received len=CYRF_ReadRegister(CYRF_09_RX_COUNT); debug("(%X)",len) if( len && len <= MLINK_PACKET_SIZE ) { CYRF_ReadDataPacketLen(packet_in, len*2); #if defined(MLINK_HUB_TELEMETRY) || defined(MLINK_FW_TELEMETRY) if(len==MLINK_PACKET_SIZE) { for(uint8_t i=0;i<8;i++) //Check CRC crc8=bit_reverse(MLINK_CRC_Init); for(uint8_t i=0;i