2019-06-04 21:44:40 +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 KF606 plane.
2021-02-16 19:06:23 +01:00
#if defined(KF606_CCNRF_INO)
2019-06-04 21:44:40 +02:00
2021-03-17 17:19:41 +01:00
#include "iface_xn297.h"
2019-06-04 21:44:40 +02:00
//#define FORCE_KF606_ORIGINAL_ID
2021-07-04 14:05:42 +02:00
//#define FORCE_MIG320_ORIGINAL_ID
2023-01-15 21:26:35 +01:00
//#define FORCE_ZCZ50_ORIGINAL_ID
2019-06-04 21:44:40 +02:00
#define KF606_INITIAL_WAIT 500
#define KF606_PACKET_PERIOD 3000
#define KF606_RF_BIND_CHANNEL 7
#define KF606_PAYLOAD_SIZE 4
#define KF606_BIND_COUNT 857 //3sec
2019-06-05 21:54:47 +02:00
#define KF606_RF_NUM_CHANNELS 2
2019-06-04 21:44:40 +02:00
static void __attribute__ (( unused )) KF606_send_packet ()
{
2023-01-15 21:26:35 +01:00
uint8_t len = KF606_PAYLOAD_SIZE ;
2019-06-04 21:44:40 +02:00
if ( IS_BIND_IN_PROGRESS )
{
2023-01-15 21:26:35 +01:00
if ( sub_protocol != KF606_ZCZ50 )
{
packet [ 0 ] = 0xAA ;
memcpy ( & packet [ 1 ], rx_tx_addr , 3 );
}
else
memcpy ( packet , rx_tx_addr , 4 );
2019-06-04 21:44:40 +02:00
}
else
{
2021-03-17 17:05:42 +01:00
XN297_Hopping ( hopping_frequency_no );
2019-06-04 21:44:40 +02:00
hopping_frequency_no ^= 1 ; // 2 RF channels
2021-07-04 14:05:42 +02:00
packet [ 0 ] = 0x55 ;
packet [ 1 ] = convert_channel_8b ( THROTTLE ); // 0..255
// Deadband is needed on aileron, 40 gives +-6%
2023-01-15 21:26:35 +01:00
switch ( sub_protocol )
2021-07-04 14:05:42 +02:00
{
2023-01-15 21:26:35 +01:00
case KF606_KF606 :
packet [ 2 ] = convert_channel_8b_limit_deadband ( AILERON , 0x20 , 0x80 , 0xE0 , 40 ); // Aileron: Max values:20..80..E0, Low rates:50..80..AF, High rates:3E..80..C1
packet [ 3 ] = convert_channel_16b_limit ( CH5 , 0xC1 , 0xDF ); // Aileron trim must be on a separated channel C1..D0..DF
break ;
case KF606_MIG320 :
packet [ 2 ] = convert_channel_8b_limit_deadband ( AILERON , 0x00 , 0x80 , 0xFF , 40 ); // Aileron: High rate:2B..80..DA
packet [ 3 ] = convert_channel_16b_limit ( CH5 , 0x01 , 0x1F ); // Aileron trim must be on a separated channel 01..10..1F
packet [ 3 ] += ( packet [ 2 ] - 0x80 ) >> 3 ; // Drive trims for more aileron authority
if ( packet [ 3 ] > 0x80 )
packet [ 3 ] = 0x01 ;
else if ( packet [ 3 ] > 0x1F )
packet [ 3 ] = 0x1F ;
packet [ 3 ] |= GET_FLAG ( CH6_SW , 0xC0 ); // 0xC0 and 0xE0 are both turning the LED off, not sure if there is another hidden feature
break ;
case KF606_ZCZ50 :
len -- ; // uses only 3 bytes of payload
packet [ 0 ] = packet [ 1 ]; // Throttle: 0x00..0xFF
packet [ 1 ] = convert_channel_8b_limit_deadband ( AILERON , 0x20 , 0x80 , 0xE0 , 40 ); // Aileron: Max values:20..80..E0, low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3.
packet [ 2 ] = convert_channel_16b_limit ( CH5 , 0x01 , 0x1F ); // Trim: 0x01..0x10..0x1F
packet [ 2 ] |= GET_FLAG ( CH6_SW , 0xC0 ); // Unknown: 0x00 or 0xC0. Left top switch on original TX changes nothing on my plane. Maybe ON/OFF for main motor?
break ;
2021-07-04 14:05:42 +02:00
}
2019-06-04 21:44:40 +02:00
}
2021-07-04 14:05:42 +02:00
if ( sub_protocol == KF606_MIG320 )
{
len ++ ;
packet [ 4 ] = 0 ; // additional channel?
}
#if 0
for(uint8_t i=0; i<len; i++)
debug("%02X ",packet[i]);
debugln("");
#endif
2021-03-17 17:05:42 +01:00
// Send
XN297_SetPower ();
XN297_SetFreqOffset ();
XN297_SetTxRxMode ( TX_EN );
2021-07-04 14:05:42 +02:00
XN297_WritePayload ( packet , len );
2019-06-04 21:44:40 +02:00
}
static void __attribute__ (( unused )) KF606_initialize_txid ()
{
rx_tx_addr [ 0 ] = rx_tx_addr [ 3 ]; // Use RX_num;
hopping_frequency [ 0 ] = ( rx_tx_addr [ 0 ] & 0x3F ) + 9 ;
hopping_frequency [ 1 ] = hopping_frequency [ 0 ] + 3 ;
#ifdef FORCE_KF606_ORIGINAL_ID
//TX1
rx_tx_addr [ 0 ] = 0x57 ;
rx_tx_addr [ 1 ] = 0x02 ;
rx_tx_addr [ 2 ] = 0x00 ;
hopping_frequency [ 0 ] = 0x20 ;
2021-07-04 14:05:42 +02:00
hopping_frequency [ 1 ] = 0x23 ;
2019-06-04 21:44:40 +02:00
//TX2
rx_tx_addr [ 0 ] = 0x25 ;
rx_tx_addr [ 1 ] = 0x04 ;
rx_tx_addr [ 2 ] = 0x00 ;
hopping_frequency [ 0 ] = 0x2E ;
2021-07-04 14:05:42 +02:00
hopping_frequency [ 1 ] = 0x31 ;
#endif
#ifdef FORCE_MIG320_ORIGINAL_ID
rx_tx_addr [ 0 ] = 0xBB ;
rx_tx_addr [ 1 ] = 0x13 ;
rx_tx_addr [ 2 ] = 0x00 ;
hopping_frequency [ 0 ] = 68 ;
hopping_frequency [ 1 ] = 71 ;
2019-06-04 21:44:40 +02:00
#endif
2023-01-15 21:26:35 +01:00
if ( sub_protocol == KF606_ZCZ50 )
{
rx_tx_addr [ 1 ] = rx_tx_addr [ 0 ];
rx_tx_addr [ 0 ] = 0xAA ;
}
#ifdef FORCE_ZCZ50_ORIGINAL_ID
rx_tx_addr [ 0 ] = 0xAA ;
rx_tx_addr [ 1 ] = 0x67 ;
rx_tx_addr [ 2 ] = 0x64 ;
rx_tx_addr [ 3 ] = 0x01 ;
hopping_frequency [ 0 ] = 48 ;
hopping_frequency [ 1 ] = 51 ;
#endif
2019-06-04 21:44:40 +02:00
}
2021-02-09 18:23:33 +01:00
static void __attribute__ (( unused )) KF606_RF_init ()
2019-06-05 21:54:47 +02:00
{
2021-03-17 17:05:42 +01:00
XN297_Configure ( XN297_CRCEN , XN297_SCRAMBLED , XN297_250K );
XN297_SetTXAddr (( uint8_t * ) " \xe7\xe7\xe7\xe7\xe7 " , 5 );
XN297_HoppingCalib ( KF606_RF_NUM_CHANNELS ); // Calibrate all channels
XN297_RFChannel ( KF606_RF_BIND_CHANNEL ); // Set bind channel
2019-06-05 21:54:47 +02:00
}
2019-06-04 21:44:40 +02:00
uint16_t KF606_callback ()
{
2019-11-11 19:15:39 +01:00
#ifdef MULTI_SYNC
telemetry_set_input_sync ( KF606_PACKET_PERIOD );
#endif
2021-02-12 11:21:42 +01:00
if ( bind_counter )
2019-06-04 21:44:40 +02:00
if ( -- bind_counter == 0 )
{
BIND_DONE ;
2023-01-15 21:26:35 +01:00
XN297_SetTXAddr ( rx_tx_addr , sub_protocol != KF606_ZCZ50 ? 3 : 4 );
2019-06-04 21:44:40 +02:00
}
KF606_send_packet ();
return KF606_PACKET_PERIOD ;
}
2021-02-09 18:23:33 +01:00
void KF606_init ()
2019-06-04 21:44:40 +02:00
{
BIND_IN_PROGRESS ; // autobind protocol
KF606_initialize_txid ();
2021-02-09 18:23:33 +01:00
KF606_RF_init ();
2019-06-04 21:44:40 +02:00
hopping_frequency_no = 0 ;
bind_counter = KF606_BIND_COUNT ;
}
#endif
2021-07-04 14:05:42 +02:00
// MIG320 protocol
// Bind
// 250K C=7 S=Y A= E7 E7 E7 E7 E7 P(5)= AA BB 13 00 00
// 3ms on ch7
// Normal
// 250K C=68 S=Y A= BB 13 00 P(5)= 55 00 80 10 00
// P[1] = THR 00..FF
// P[2] = AIL 2B..80..DA
// P[3] = TRIM 01..10..1F
// channels 68=BB&3F+9 and 71
2023-01-15 21:26:35 +01:00
// ZCZ50v2 protocol (with fake front propeller)
// Bind
// 250K C=7 S=Y A= E7 E7 E7 E7 E7 P(4)= AA 67 64 01
// 3ms on ch7
// Normal
// 250K C=48 S=Y A= AA 67 64 01 P(3)= 00 80 10
// P[0] = THR 0x00..0xFF
// P[1] = AIL low rate 0x52..0x80..0xB1, high rate: 0x41..0x80..0xC3
// P[2] = TRIM 0x01..0x10..0x1F + UNKNOWN 0x00 or 0xC0