178 lines
5.4 KiB
Arduino
Raw Permalink Normal View History

2020-05-24 17:39:14 +02:00
/*
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/>.
*/
// Compatible with Q90C quad.
#if defined(Q90C_CCNRF_INO)
2020-05-24 17:39:14 +02:00
2021-03-17 17:19:41 +01:00
#include "iface_xn297.h"
2020-05-24 17:39:14 +02:00
2020-06-14 19:10:59 +02:00
//#define FORCE_Q90C_ORIGINAL_ID
2020-05-24 17:39:14 +02:00
#define Q90C_BIND_COUNT 250
2020-06-14 22:22:13 +02:00
#define Q90C_PACKET_PERIOD 7336 // 6200 on saimat's TX...
2020-05-24 17:39:14 +02:00
#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
2020-06-15 15:23:02 +02:00
bool Q90C_VTX;
2020-05-24 17:39:14 +02:00
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(val<in_min) val=in_min;
else if(val>in_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);
2020-06-14 23:22:27 +02:00
//packet[7] = 0x1e; // 2e on Saimat 1???
2020-06-14 22:28:36 +02:00
packet[10] = 0x4B;
packet[11] = 0x4E;
2020-05-24 17:39:14 +02:00
}
else
{
XN297_Hopping(hopping_frequency_no++); // RF Freq
2020-05-26 12:41:33 +02:00
hopping_frequency_no %= Q90C_RF_NUM_CHANNELS;
2020-05-24 17:39:14 +02:00
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)
2020-05-26 22:26:30 +02:00
packet[1] = Q90C_channel(RUDDER, CHANNEL_MIN_100, CHANNEL_MID, 0xff, 0x7a );
2020-05-24 17:39:14 +02:00
else
2020-05-26 22:26:30 +02:00
packet[1] = Q90C_channel(RUDDER, CHANNEL_MID, CHANNEL_MAX_100, 0x7a, 0x00 );
2020-05-24 17:39:14 +02:00
// 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)
2020-05-26 22:26:30 +02:00
packet[3] = Q90C_channel(AILERON, CHANNEL_MIN_100, CHANNEL_MID, 0xff, 0x88);
2020-05-24 17:39:14 +02:00
else
2020-05-26 22:26:30 +02:00
packet[3] = Q90C_channel(AILERON, CHANNEL_MID, CHANNEL_MAX_100, 0x88, 0x00);
2020-05-24 17:39:14 +02:00
// 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
2020-06-14 23:22:27 +02:00
//packet[7] = 0x1e; // A trim 00-1e-3c
2020-06-15 14:45:49 +02:00
packet[8] |= 0x02; // Rudder rate 0=min,1,2=max
2020-06-14 23:22:27 +02:00
if(state!=Channel_data[CH5])
{
state=Channel_data[CH5];
if(state<CHANNEL_MIN_COMMAND)
packet[8] ^= 0x04; // Angle
else if(state>CHANNEL_MAX_COMMAND)
packet[8] ^= 0x10; // Acro
else
packet[8] ^= 0x08; // Horizon
}
2020-06-15 15:30:31 +02:00
if(!Q90C_VTX && CH6_SW)
2020-06-15 15:23:02 +02:00
packet[8] ^= 0x20; // VTX+
2020-06-15 15:30:31 +02:00
Q90C_VTX=CH6_SW;
2020-06-15 14:45:49 +02:00
debugln("8=%02X",packet[8]);
2020-05-24 17:39:14 +02:00
packet[10] = packet_count++;
}
2020-06-14 23:22:27 +02:00
packet[7] = 0x1e; // bind 1e or 2e, normal: A trim 00-1e-3c
2020-05-24 17:39:14 +02:00
2020-05-26 12:41:33 +02:00
// checksum
2020-06-14 22:28:36 +02:00
if(IS_BIND_DONE)
2020-06-14 22:22:13 +02:00
{
2020-06-14 22:28:36 +02:00
uint8_t sum=0;
2020-06-14 22:22:13 +02:00
for (uint8_t i = 0; i < Q90C_PACKET_SIZE - 1; i++)
sum += packet[i];
2020-06-14 22:28:36 +02:00
packet[11] = sum ^ crc8;
2020-05-26 12:41:33 +02:00
}
2020-05-24 17:39:14 +02:00
// Send
XN297_SetFreqOffset(); // Set frequency offset
XN297_SetPower(); // Set tx_power
XN297_SetTxRxMode(TX_EN);
XN297_WriteEnhancedPayload(packet, Q90C_PACKET_SIZE, 0);
2020-05-24 17:39:14 +02:00
}
static void __attribute__((unused)) Q90C_initialize_txid()
{
2020-05-26 22:26:30 +02:00
calc_fh_channels(Q90C_RF_NUM_CHANNELS);
2020-06-14 19:10:59 +02:00
rx_tx_addr[4]=0x4B;
2020-05-24 17:39:14 +02:00
#ifdef FORCE_Q90C_ORIGINAL_ID
2020-06-14 22:22:13 +02:00
//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
2020-05-24 17:39:14 +02:00
memcpy(hopping_frequency, (uint8_t*)"\x18\x26\x37", Q90C_RF_NUM_CHANNELS);
#endif
2020-06-14 19:10:59 +02:00
crc8=rx_tx_addr[0]^rx_tx_addr[1]^rx_tx_addr[2]^rx_tx_addr[3];
2020-05-24 17:39:14 +02:00
}
2021-02-09 18:23:33 +01:00
static void __attribute__((unused)) Q90C_RF_init()
2020-05-24 17:39:14 +02:00
{
XN297_Configure(XN297_CRCEN, XN297_SCRAMBLED, XN297_250K);
2020-05-24 17:39:14 +02:00
if(IS_BIND_IN_PROGRESS)
XN297_SetTXAddr((uint8_t*)"\x4F\x43\x54\x81\x81", Q90C_ADDRESS_LENGTH);
2020-05-24 17:39:14 +02:00
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
2020-05-24 17:39:14 +02:00
}
uint16_t Q90C_callback()
{
#ifdef MULTI_SYNC
telemetry_set_input_sync(Q90C_PACKET_PERIOD);
#endif
2021-02-12 11:21:42 +01:00
if(bind_counter)
2020-05-24 17:39:14 +02:00
if(--bind_counter==0)
{
BIND_DONE;
XN297_SetTXAddr(rx_tx_addr, Q90C_ADDRESS_LENGTH);
2020-05-24 17:39:14 +02:00
}
Q90C_send_packet();
return Q90C_PACKET_PERIOD;
}
2021-02-09 18:23:33 +01:00
void Q90C_init()
2020-05-24 17:39:14 +02:00
{
Q90C_initialize_txid();
2021-02-09 18:23:33 +01:00
Q90C_RF_init();
2020-05-24 17:39:14 +02:00
hopping_frequency_no = 0;
packet_count = 0;
bind_counter=Q90C_BIND_COUNT;
2020-06-14 23:22:27 +02:00
//features
state=Channel_data[CH5];
2020-06-15 15:23:02 +02:00
Q90C_VTX=CH6_SW;
2020-06-14 23:22:27 +02:00
packet[8] = 0x00;
packet[9] = 0x00;
2020-05-24 17:39:14 +02:00
}
#endif