/* 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 . */ // Compatible with Q90C quad. #if defined(Q90C_CCNRF_INO) #include "iface_xn297.h" //#define FORCE_Q90C_ORIGINAL_ID #define Q90C_BIND_COUNT 250 #define Q90C_PACKET_PERIOD 7336 // 6200 on saimat's TX... #define Q90C_INITIAL_WAIT 500 #define Q90C_PACKET_SIZE 12 #define Q90C_RF_BIND_CHANNEL 0x33 #define Q90C_RF_NUM_CHANNELS 3 #define Q90C_ADDRESS_LENGTH 5 bool Q90C_VTX; int16_t Q90C_channel(uint8_t num, int16_t in_min,int16_t in_max, int16_t out_min,int16_t out_max) { int32_t val=Channel_data[num]; if(valin_max) val=in_max; val=(val-in_min)*(out_max-out_min)/(in_max-in_min)+out_min; return (uint16_t)val; } static void __attribute__((unused)) Q90C_send_packet() { if(IS_BIND_IN_PROGRESS) { memcpy(packet, rx_tx_addr, 4); memcpy(&packet[4], hopping_frequency, 3); //packet[7] = 0x1e; // 2e on Saimat 1??? packet[10] = 0x4B; packet[11] = 0x4E; } else { XN297_Hopping(hopping_frequency_no++); // RF Freq hopping_frequency_no %= Q90C_RF_NUM_CHANNELS; packet[0]= convert_channel_8b(THROTTLE); // 0..255 // A,E,R have weird scaling, 0x00-0xff range (unsigned) but center isn't 7f or 80 // rudder ff-7a-00 if (Channel_data[RUDDER] <= CHANNEL_MID) packet[1] = Q90C_channel(RUDDER, CHANNEL_MIN_100, CHANNEL_MID, 0xff, 0x7a ); else packet[1] = Q90C_channel(RUDDER, CHANNEL_MID, CHANNEL_MAX_100, 0x7a, 0x00 ); // elevator 00-88-ff if (Channel_data[ELEVATOR] <= CHANNEL_MID) packet[2] = Q90C_channel(ELEVATOR, CHANNEL_MIN_100, CHANNEL_MID, 0x00, 0x88); else packet[2] = Q90C_channel(ELEVATOR, CHANNEL_MID, CHANNEL_MAX_100, 0x88, 0xff); // aileron ff-88-00 if (Channel_data[AILERON] <= CHANNEL_MID) packet[3] = Q90C_channel(AILERON, CHANNEL_MIN_100, CHANNEL_MID, 0xff, 0x88); else packet[3] = Q90C_channel(AILERON, CHANNEL_MID, CHANNEL_MAX_100, 0x88, 0x00); // required to "arm" (low throttle + aileron to the right) if (packet[0] < 5 && packet[3] < 25) { packet[1] = 0x7a; packet[2] = 0x88; } packet[4] = 0x1e; // T trim 00-1e-3c packet[5] = 0x1e; // R trim 3c-1e-00 packet[6] = 0x1e; // E trim 00-1e-3c //packet[7] = 0x1e; // A trim 00-1e-3c packet[8] |= 0x02; // Rudder rate 0=min,1,2=max if(state!=Channel_data[CH5]) { state=Channel_data[CH5]; if(stateCHANNEL_MAX_COMMAND) packet[8] ^= 0x10; // Acro else packet[8] ^= 0x08; // Horizon } if(!Q90C_VTX && CH6_SW) packet[8] ^= 0x20; // VTX+ Q90C_VTX=CH6_SW; debugln("8=%02X",packet[8]); packet[10] = packet_count++; } packet[7] = 0x1e; // bind 1e or 2e, normal: A trim 00-1e-3c // checksum if(IS_BIND_DONE) { uint8_t sum=0; for (uint8_t i = 0; i < Q90C_PACKET_SIZE - 1; i++) sum += packet[i]; packet[11] = sum ^ crc8; } // Send XN297_SetFreqOffset(); // Set frequency offset XN297_SetPower(); // Set tx_power XN297_SetTxRxMode(TX_EN); XN297_WriteEnhancedPayload(packet, Q90C_PACKET_SIZE, 0); } static void __attribute__((unused)) Q90C_initialize_txid() { calc_fh_channels(Q90C_RF_NUM_CHANNELS); rx_tx_addr[4]=0x4B; #ifdef FORCE_Q90C_ORIGINAL_ID //24 03 01 82 18 26 37 1E 00 00 4B 4E memcpy(rx_tx_addr, (uint8_t*)"\x24\x03\x01\x82\x4B", Q90C_ADDRESS_LENGTH); //Goebish memcpy(hopping_frequency, (uint8_t*)"\x18\x26\x37", Q90C_RF_NUM_CHANNELS); //4C 0A 02 01 17 24 36 2E 00 00 4B 4E memcpy(rx_tx_addr, (uint8_t*)"\x4C\x0A\x02\x01\x4B", Q90C_ADDRESS_LENGTH); //Saimat 1 memcpy(hopping_frequency, (uint8_t*)"\x17\x24\x36", Q90C_RF_NUM_CHANNELS); //34 13 02 01 18 26 37 1E 00 00 4B 4E memcpy(rx_tx_addr, (uint8_t*)"\x34\x13\x02\x01\x4B", Q90C_ADDRESS_LENGTH); //Saimat 2 memcpy(hopping_frequency, (uint8_t*)"\x18\x26\x37", Q90C_RF_NUM_CHANNELS); #endif crc8=rx_tx_addr[0]^rx_tx_addr[1]^rx_tx_addr[2]^rx_tx_addr[3]; } static void __attribute__((unused)) Q90C_RF_init() { XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K); if(IS_BIND_IN_PROGRESS) XN297_SetTXAddr((uint8_t*)"\x4F\x43\x54\x81\x81", Q90C_ADDRESS_LENGTH); else XN297_SetTXAddr(rx_tx_addr, Q90C_ADDRESS_LENGTH); XN297_HoppingCalib(Q90C_RF_NUM_CHANNELS); // Calibrate all channels XN297_RFChannel(Q90C_RF_BIND_CHANNEL); // Set bind channel } uint16_t Q90C_callback() { #ifdef MULTI_SYNC telemetry_set_input_sync(Q90C_PACKET_PERIOD); #endif if(bind_counter) if(--bind_counter==0) { BIND_DONE; XN297_SetTXAddr(rx_tx_addr, Q90C_ADDRESS_LENGTH); } Q90C_send_packet(); return Q90C_PACKET_PERIOD; } void Q90C_init() { Q90C_initialize_txid(); Q90C_RF_init(); hopping_frequency_no = 0; packet_count = 0; bind_counter=Q90C_BIND_COUNT; //features state=Channel_data[CH5]; Q90C_VTX=CH6_SW; packet[8] = 0x00; packet[9] = 0x00; } #endif