2015-12-30 01:41:12 +01: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/>.
*/
2016-09-01 14:00:42 +02:00
# if defined(DSM_CYRF6936_INO)
2015-12-30 01:41:12 +01:00
# include "iface_cyrf6936.h"
2016-09-19 18:58:09 +02:00
# define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel
2015-12-30 01:41:12 +01:00
//During binding we will send BIND_COUNT/2 packets
//One packet each 10msec
2016-09-19 18:58:09 +02:00
# define DSM_BIND_COUNT 300
2015-12-30 01:41:12 +01:00
enum {
2016-09-19 18:58:09 +02:00
DSM_BIND_WRITE = 0 ,
DSM_BIND_CHECK ,
DSM_BIND_READ ,
DSM_CHANSEL ,
DSM_CH1_WRITE_A ,
DSM_CH1_CHECK_A ,
DSM_CH2_WRITE_A ,
DSM_CH2_CHECK_A ,
DSM_CH2_READ_A ,
DSM_CH1_WRITE_B ,
DSM_CH1_CHECK_B ,
DSM_CH2_WRITE_B ,
DSM_CH2_CHECK_B ,
DSM_CH2_READ_B ,
2015-12-30 01:41:12 +01:00
} ;
2016-09-19 18:58:09 +02:00
//
uint8_t sop_col ;
uint8_t ch_map [ 14 ] ;
2018-09-10 09:58:31 +02:00
const uint8_t PROGMEM DSM_ch_map_progmem [ ] [ 14 ] = {
2016-09-24 13:58:06 +02:00
//22+11ms for 4..7 channels
{ 1 , 0 , 2 , 3 , 0xff , 0xff , 0xff , 1 , 0 , 2 , 3 , 0xff , 0xff , 0xff } , //4ch - Guess
{ 1 , 0 , 2 , 3 , 4 , 0xff , 0xff , 1 , 0 , 2 , 3 , 4 , 0xff , 0xff } , //5ch - Guess
{ 1 , 5 , 2 , 3 , 0 , 4 , 0xff , 1 , 5 , 2 , 3 , 0 , 4 , 0xff } , //6ch - HP6DSM
{ 1 , 5 , 2 , 4 , 3 , 6 , 0 , 1 , 5 , 2 , 4 , 3 , 6 , 0 } , //7ch - DX6i
//22ms for 8..12 channels
{ 1 , 5 , 2 , 3 , 6 , 0xff , 0xff , 4 , 0 , 7 , 0xff , 0xff , 0xff , 0xff } , //8ch - DX8/DX7
{ 1 , 5 , 2 , 3 , 6 , 0xff , 0xff , 4 , 0 , 7 , 8 , 0xff , 0xff , 0xff } , //9ch - Guess
{ 1 , 5 , 2 , 3 , 6 , 0xff , 0xff , 4 , 0 , 7 , 8 , 9 , 0xff , 0xff } , //10ch - Guess
{ 1 , 5 , 2 , 3 , 6 , 10 , 0xff , 4 , 0 , 7 , 8 , 9 , 0xff , 0xff } , //11ch - Guess
{ 1 , 5 , 2 , 4 , 6 , 10 , 0xff , 0 , 7 , 3 , 8 , 9 , 11 , 0xff } , //12ch - DX18
//11ms for 8..12 channels
{ 1 , 5 , 2 , 3 , 6 , 7 , 0xff , 1 , 5 , 2 , 4 , 0 , 0xff , 0xff } , //8ch - DX7
{ 1 , 5 , 2 , 3 , 6 , 7 , 0xff , 1 , 5 , 2 , 4 , 0 , 8 , 0xff } , //9ch - Guess
{ 1 , 5 , 2 , 3 , 4 , 8 , 9 , 1 , 5 , 2 , 3 , 0 , 7 , 6 } , //10ch - DX18
} ;
2016-09-19 18:58:09 +02:00
2018-09-10 09:58:31 +02:00
const uint8_t PROGMEM DSM_pncodes [ 5 ] [ 8 ] [ 8 ] = {
2015-12-30 01:41:12 +01:00
/* Note these are in order transmitted (LSB 1st) */
{ /* Row 0 */
/* Col 0 */ { 0x03 , 0xBC , 0x6E , 0x8A , 0xEF , 0xBD , 0xFE , 0xF8 } ,
/* Col 1 */ { 0x88 , 0x17 , 0x13 , 0x3B , 0x2D , 0xBF , 0x06 , 0xD6 } ,
/* Col 2 */ { 0xF1 , 0x94 , 0x30 , 0x21 , 0xA1 , 0x1C , 0x88 , 0xA9 } ,
/* Col 3 */ { 0xD0 , 0xD2 , 0x8E , 0xBC , 0x82 , 0x2F , 0xE3 , 0xB4 } ,
/* Col 4 */ { 0x8C , 0xFA , 0x47 , 0x9B , 0x83 , 0xA5 , 0x66 , 0xD0 } ,
/* Col 5 */ { 0x07 , 0xBD , 0x9F , 0x26 , 0xC8 , 0x31 , 0x0F , 0xB8 } ,
/* Col 6 */ { 0xEF , 0x03 , 0x95 , 0x89 , 0xB4 , 0x71 , 0x61 , 0x9D } ,
/* Col 7 */ { 0x40 , 0xBA , 0x97 , 0xD5 , 0x86 , 0x4F , 0xCC , 0xD1 } ,
2016-09-23 16:01:18 +02:00
/* Col 8 {0xD7, 0xA1, 0x54, 0xB1, 0x5E, 0x89, 0xAE, 0x86}*/
2015-12-30 01:41:12 +01:00
} ,
{ /* Row 1 */
/* Col 0 */ { 0x83 , 0xF7 , 0xA8 , 0x2D , 0x7A , 0x44 , 0x64 , 0xD3 } ,
/* Col 1 */ { 0x3F , 0x2C , 0x4E , 0xAA , 0x71 , 0x48 , 0x7A , 0xC9 } ,
/* Col 2 */ { 0x17 , 0xFF , 0x9E , 0x21 , 0x36 , 0x90 , 0xC7 , 0x82 } ,
/* Col 3 */ { 0xBC , 0x5D , 0x9A , 0x5B , 0xEE , 0x7F , 0x42 , 0xEB } ,
/* Col 4 */ { 0x24 , 0xF5 , 0xDD , 0xF8 , 0x7A , 0x77 , 0x74 , 0xE7 } ,
/* Col 5 */ { 0x3D , 0x70 , 0x7C , 0x94 , 0xDC , 0x84 , 0xAD , 0x95 } ,
/* Col 6 */ { 0x1E , 0x6A , 0xF0 , 0x37 , 0x52 , 0x7B , 0x11 , 0xD4 } ,
/* Col 7 */ { 0x62 , 0xF5 , 0x2B , 0xAA , 0xFC , 0x33 , 0xBF , 0xAF } ,
2016-09-23 16:01:18 +02:00
/* Col 8 {0x40, 0x56, 0x32, 0xD9, 0x0F, 0xD9, 0x5D, 0x97} */
2015-12-30 01:41:12 +01:00
} ,
{ /* Row 2 */
/* Col 0 */ { 0x40 , 0x56 , 0x32 , 0xD9 , 0x0F , 0xD9 , 0x5D , 0x97 } ,
/* Col 1 */ { 0x8E , 0x4A , 0xD0 , 0xA9 , 0xA7 , 0xFF , 0x20 , 0xCA } ,
/* Col 2 */ { 0x4C , 0x97 , 0x9D , 0xBF , 0xB8 , 0x3D , 0xB5 , 0xBE } ,
/* Col 3 */ { 0x0C , 0x5D , 0x24 , 0x30 , 0x9F , 0xCA , 0x6D , 0xBD } ,
/* Col 4 */ { 0x50 , 0x14 , 0x33 , 0xDE , 0xF1 , 0x78 , 0x95 , 0xAD } ,
/* Col 5 */ { 0x0C , 0x3C , 0xFA , 0xF9 , 0xF0 , 0xF2 , 0x10 , 0xC9 } ,
/* Col 6 */ { 0xF4 , 0xDA , 0x06 , 0xDB , 0xBF , 0x4E , 0x6F , 0xB3 } ,
/* Col 7 */ { 0x9E , 0x08 , 0xD1 , 0xAE , 0x59 , 0x5E , 0xE8 , 0xF0 } ,
2016-09-23 16:01:18 +02:00
/* Col 8 {0xC0, 0x90, 0x8F, 0xBB, 0x7C, 0x8E, 0x2B, 0x8E} */
2015-12-30 01:41:12 +01:00
} ,
{ /* Row 3 */
/* Col 0 */ { 0xC0 , 0x90 , 0x8F , 0xBB , 0x7C , 0x8E , 0x2B , 0x8E } ,
/* Col 1 */ { 0x80 , 0x69 , 0x26 , 0x80 , 0x08 , 0xF8 , 0x49 , 0xE7 } ,
/* Col 2 */ { 0x7D , 0x2D , 0x49 , 0x54 , 0xD0 , 0x80 , 0x40 , 0xC1 } ,
/* Col 3 */ { 0xB6 , 0xF2 , 0xE6 , 0x1B , 0x80 , 0x5A , 0x36 , 0xB4 } ,
/* Col 4 */ { 0x42 , 0xAE , 0x9C , 0x1C , 0xDA , 0x67 , 0x05 , 0xF6 } ,
/* Col 5 */ { 0x9B , 0x75 , 0xF7 , 0xE0 , 0x14 , 0x8D , 0xB5 , 0x80 } ,
/* Col 6 */ { 0xBF , 0x54 , 0x98 , 0xB9 , 0xB7 , 0x30 , 0x5A , 0x88 } ,
/* Col 7 */ { 0x35 , 0xD1 , 0xFC , 0x97 , 0x23 , 0xD4 , 0xC9 , 0x88 } ,
2016-09-23 16:01:18 +02:00
/* Col 8 {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93} */
2016-09-19 18:58:09 +02:00
// Wrong values used by Orange TX/RX
// /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40}
2015-12-30 01:41:12 +01:00
} ,
{ /* Row 4 */
/* Col 0 */ { 0xE1 , 0xD6 , 0x31 , 0x26 , 0x5F , 0xBD , 0x40 , 0x93 } ,
/* Col 1 */ { 0xDC , 0x68 , 0x08 , 0x99 , 0x97 , 0xAE , 0xAF , 0x8C } ,
/* Col 2 */ { 0xC3 , 0x0E , 0x01 , 0x16 , 0x0E , 0x32 , 0x06 , 0xBA } ,
/* Col 3 */ { 0xE0 , 0x83 , 0x01 , 0xFA , 0xAB , 0x3E , 0x8F , 0xAC } ,
/* Col 4 */ { 0x5C , 0xD5 , 0x9C , 0xB8 , 0x46 , 0x9C , 0x7D , 0x84 } ,
/* Col 5 */ { 0xF1 , 0xC6 , 0xFE , 0x5C , 0x9D , 0xA5 , 0x4F , 0xB7 } ,
/* Col 6 */ { 0x58 , 0xB5 , 0xB3 , 0xDD , 0x0E , 0x28 , 0xF1 , 0xB0 } ,
/* Col 7 */ { 0x5F , 0x30 , 0x3B , 0x56 , 0x96 , 0x45 , 0xF4 , 0xA1 } ,
2016-09-23 16:01:18 +02:00
/* Col 8 {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8} */
2015-12-30 01:41:12 +01:00
} ,
} ;
2018-09-10 09:58:31 +02:00
static void __attribute__ ( ( unused ) ) DSM_read_code ( uint8_t * buf , uint8_t row , uint8_t col , uint8_t len )
2016-02-05 17:27:51 +01:00
{
2016-09-23 16:01:18 +02:00
for ( uint8_t i = 0 ; i < len ; i + + )
2018-09-10 09:58:31 +02:00
buf [ i ] = pgm_read_byte_near ( & DSM_pncodes [ row ] [ col ] [ i ] ) ;
2016-02-05 17:27:51 +01:00
}
2018-09-10 09:58:31 +02:00
static uint8_t __attribute__ ( ( unused ) ) DSM_get_pn_row ( uint8_t channel )
2016-09-21 14:29:09 +02:00
{
return ( ( sub_protocol = = DSMX_11 | | sub_protocol = = DSMX_22 ) ? ( channel - 2 ) % 5 : channel % 5 ) ;
}
2018-09-10 09:58:31 +02:00
const uint8_t PROGMEM DSM_init_vals [ ] [ 2 ] = {
2016-10-16 19:51:42 +02:00
{ CYRF_02_TX_CTRL , 0x00 } , // All TX interrupt disabled
2016-09-23 16:01:18 +02:00
{ CYRF_05_RX_CTRL , 0x00 } , // All RX interrupt disabled
{ CYRF_28_CLK_EN , 0x02 } , // Force receive clock enable
{ CYRF_32_AUTO_CAL_TIME , 0x3c } , // Default init value
{ CYRF_35_AUTOCAL_OFFSET , 0x14 } , // Default init value
{ CYRF_06_RX_CFG , 0x4A } , // LNA enabled, RX override enabled, Fast turn mode enabled, RX is 1MHz below TX
{ CYRF_1B_TX_OFFSET_LSB , 0x55 } , // Default init value
{ CYRF_1C_TX_OFFSET_MSB , 0x05 } , // Default init value
{ CYRF_39_ANALOG_CTRL , 0x01 } , // All slow for synth setting time
2016-09-23 21:27:38 +02:00
{ CYRF_01_TX_LENGTH , 0x10 } , // 16 bytes packet
{ CYRF_14_EOP_CTRL , 0x02 } , // Set EOP Symbol Count to 2
{ CYRF_12_DATA64_THOLD , 0x0a } , // 64 Chip Data PN corelator threshold, default datasheet value is 0x0E
//Below is for bind only
{ CYRF_03_TX_CFG , 0x38 | CYRF_BIND_POWER } , //64 chip codes, SDR mode
2016-09-23 16:01:18 +02:00
{ CYRF_10_FRAMING_CFG , 0x4a } , // SOP disabled, no LEN field and SOP correlator of 0x0a but since SOP is disabled...
{ CYRF_1F_TX_OVERRIDE , 0x04 } , // Disable TX CRC, no ACK, use TX synthesizer
{ CYRF_1E_RX_OVERRIDE , 0x14 } , // Disable RX CRC, Force receive data rate, use RX synthesizer
} ;
2018-09-10 09:58:31 +02:00
const uint8_t PROGMEM DSM_data_vals [ ] [ 2 ] = {
2016-09-23 21:27:38 +02:00
{ CYRF_29_RX_ABORT , 0x20 } , // Abort RX operation in case we are coming from bind
2016-09-23 16:01:18 +02:00
{ CYRF_0F_XACT_CFG , 0x24 } , // Force Idle
{ CYRF_29_RX_ABORT , 0x00 } , // Clear abort RX
2016-09-23 21:27:38 +02:00
{ CYRF_03_TX_CFG , 0x28 | CYRF_HIGH_POWER } , // 64 chip codes, 8DR mode
2016-09-23 16:01:18 +02:00
{ CYRF_10_FRAMING_CFG , 0xea } , // SOP enabled, SOP_CODE_ADR 64 chips, Packet len enabled, SOP correlator 0x0A
{ CYRF_1F_TX_OVERRIDE , 0x00 } , // CRC16 enabled, no ACK
{ CYRF_1E_RX_OVERRIDE , 0x00 } , // CRC16 enabled, no ACK
2016-09-21 14:29:09 +02:00
} ;
2017-01-03 19:07:10 +01:00
static void __attribute__ ( ( unused ) ) DSM_cyrf_config ( )
2016-09-21 14:29:09 +02:00
{
2018-09-10 09:58:31 +02:00
for ( uint8_t i = 0 ; i < sizeof ( DSM_init_vals ) / 2 ; i + + )
CYRF_WriteRegister ( pgm_read_byte_near ( & DSM_init_vals [ i ] [ 0 ] ) , pgm_read_byte_near ( & DSM_init_vals [ i ] [ 1 ] ) ) ;
2016-09-21 14:29:09 +02:00
CYRF_WritePreamble ( 0x333304 ) ;
CYRF_ConfigRFChannel ( 0x61 ) ;
}
2017-01-03 19:07:10 +01:00
static void __attribute__ ( ( unused ) ) DSM_build_bind_packet ( )
2015-12-30 01:41:12 +01:00
{
uint8_t i ;
uint16_t sum = 384 - 0x10 ; //
2016-04-06 12:57:42 +02:00
packet [ 0 ] = 0xff ^ cyrfmfg_id [ 0 ] ;
packet [ 1 ] = 0xff ^ cyrfmfg_id [ 1 ] ;
2015-12-30 01:41:12 +01:00
packet [ 2 ] = 0xff ^ cyrfmfg_id [ 2 ] ;
2016-04-06 12:57:42 +02:00
packet [ 3 ] = 0xff ^ cyrfmfg_id [ 3 ] ;
2015-12-30 01:41:12 +01:00
packet [ 4 ] = packet [ 0 ] ;
packet [ 5 ] = packet [ 1 ] ;
packet [ 6 ] = packet [ 2 ] ;
packet [ 7 ] = packet [ 3 ] ;
for ( i = 0 ; i < 8 ; i + + )
sum + = packet [ i ] ;
packet [ 8 ] = sum > > 8 ;
packet [ 9 ] = sum & 0xff ;
packet [ 10 ] = 0x01 ; //???
2019-06-23 17:13:30 +02:00
packet [ 11 ] = num_ch ;
2016-09-19 18:58:09 +02:00
if ( sub_protocol = = DSM2_22 )
2019-06-23 17:13:30 +02:00
packet [ 12 ] = num_ch < 8 ? 0x01 : 0x02 ; // DSM2/1024 1 or 2 packets depending on the number of channels
2016-09-19 18:58:09 +02:00
if ( sub_protocol = = DSM2_11 )
packet [ 12 ] = 0x12 ; // DSM2/2048 2 packets
if ( sub_protocol = = DSMX_22 )
# if defined DSM_TELEMETRY
packet [ 12 ] = 0xb2 ; // DSMX/2048 2 packets
# else
2019-06-23 17:13:30 +02:00
packet [ 12 ] = num_ch < 8 ? 0xa2 : 0xb2 ; // DSMX/2048 1 or 2 packets depending on the number of channels
2016-09-19 18:58:09 +02:00
# endif
if ( sub_protocol = = DSMX_11 | | sub_protocol = = DSM_AUTO ) // Force DSMX/1024 in mode Auto
packet [ 12 ] = 0xb2 ; // DSMX/1024 2 packets
2015-12-30 01:41:12 +01:00
packet [ 13 ] = 0x00 ; //???
for ( i = 8 ; i < 14 ; i + + )
sum + = packet [ i ] ;
packet [ 14 ] = sum > > 8 ;
packet [ 15 ] = sum & 0xff ;
}
2017-01-03 19:07:10 +01:00
static void __attribute__ ( ( unused ) ) DSM_initialize_bind_phase ( )
2016-09-21 14:29:09 +02:00
{
CYRF_ConfigRFChannel ( DSM_BIND_CHANNEL ) ; //This seems to be random?
2016-09-23 16:01:18 +02:00
//64 SDR Mode is configured so only the 8 first values are needed but need to write 16 values...
CYRF_ConfigDataCode ( ( const uint8_t * ) " \xD7 \xA1 \x54 \xB1 \x5E \x89 \xAE \x86 \xc6 \x94 \x22 \xfe \x48 \xe6 \x57 \x4e " , 16 ) ;
2017-01-03 19:07:10 +01:00
DSM_build_bind_packet ( ) ;
2016-09-21 14:29:09 +02:00
}
2017-01-03 19:07:10 +01:00
static void __attribute__ ( ( unused ) ) DSM_cyrf_configdata ( )
2016-09-21 14:29:09 +02:00
{
2018-09-10 09:58:31 +02:00
for ( uint8_t i = 0 ; i < sizeof ( DSM_data_vals ) / 2 ; i + + )
CYRF_WriteRegister ( pgm_read_byte_near ( & DSM_data_vals [ i ] [ 0 ] ) , pgm_read_byte_near ( & DSM_data_vals [ i ] [ 1 ] ) ) ;
2016-09-21 14:29:09 +02:00
}
2017-01-03 19:07:10 +01:00
static void __attribute__ ( ( unused ) ) DSM_update_channels ( )
2016-09-16 17:59:57 +02:00
{
2016-09-19 18:58:09 +02:00
prev_option = option ;
if ( sub_protocol = = DSM_AUTO )
2019-06-23 17:13:30 +02:00
num_ch = 12 ; // Force 12 channels in mode Auto
2016-09-19 18:58:09 +02:00
else
2019-11-05 19:12:06 +01:00
num_ch = option & 0x7F ; // Remove the Max Throw flag
2019-06-23 17:13:30 +02:00
if ( num_ch < 4 | | num_ch > 12 )
num_ch = 6 ; // Default to 6 channels if invalid choice...
2016-09-19 18:58:09 +02:00
2016-09-24 13:58:06 +02:00
// Create channel map based on number of channels and refresh rate
2019-06-23 17:13:30 +02:00
uint8_t idx = num_ch - 4 ;
if ( num_ch > 7 & & num_ch < 11 & & ( sub_protocol = = DSM2_11 | | sub_protocol = = DSMX_11 ) )
2016-09-25 10:08:29 +02:00
idx + = 5 ; // In 11ms mode change index only for channels 8..10
2016-09-24 13:58:06 +02:00
for ( uint8_t i = 0 ; i < 14 ; i + + )
2018-09-10 09:58:31 +02:00
ch_map [ i ] = pgm_read_byte_near ( & DSM_ch_map_progmem [ idx ] [ i ] ) ;
2016-09-16 17:59:57 +02:00
}
2017-01-03 19:07:10 +01:00
static void __attribute__ ( ( unused ) ) DSM_build_data_packet ( uint8_t upper )
2015-12-30 01:41:12 +01:00
{
2016-09-19 18:58:09 +02:00
uint8_t bits = 11 ;
2016-03-13 09:29:25 +01:00
2016-09-19 18:58:09 +02:00
if ( prev_option ! = option )
2017-01-03 19:07:10 +01:00
DSM_update_channels ( ) ;
2016-09-19 18:58:09 +02:00
2016-09-21 14:29:09 +02:00
if ( sub_protocol = = DSMX_11 | | sub_protocol = = DSMX_22 )
2015-12-30 01:41:12 +01:00
{
packet [ 0 ] = cyrfmfg_id [ 2 ] ;
2016-04-06 12:57:42 +02:00
packet [ 1 ] = cyrfmfg_id [ 3 ] ;
2015-12-30 01:41:12 +01:00
}
else
{
packet [ 0 ] = ( 0xff ^ cyrfmfg_id [ 2 ] ) ;
2016-04-06 12:57:42 +02:00
packet [ 1 ] = ( 0xff ^ cyrfmfg_id [ 3 ] ) ;
2016-09-19 18:58:09 +02:00
if ( sub_protocol = = DSM2_22 )
2018-01-08 19:37:14 +01:00
bits = 10 ; // Only DSM_22 is using a resolution of 1024
2015-12-30 01:41:12 +01:00
}
2018-11-20 16:54:55 +01:00
# ifdef DSM_THROTTLE_KILL_CH
2018-11-23 10:03:55 +01:00
uint16_t kill_ch = Channel_data [ DSM_THROTTLE_KILL_CH - 1 ] ;
2018-11-20 16:54:55 +01:00
# endif
2016-09-19 18:58:09 +02:00
for ( uint8_t i = 0 ; i < 7 ; i + + )
2015-12-30 01:41:12 +01:00
{
2016-09-19 18:58:09 +02:00
uint8_t idx = ch_map [ ( upper ? 7 : 0 ) + i ] ; //1,5,2,3,0,4
2016-08-22 18:17:14 +02:00
uint16_t value = 0xffff ; ;
if ( idx ! = 0xff )
2015-12-30 01:41:12 +01:00
{
2018-01-09 11:56:42 +01:00
/* Spektrum own remotes transmit normal values during bind and actually use this (e.g. Nano CP X) to
select the transmitter mode ( e . g . computer vs non - computer radio ) , so always send normal output */
2018-11-20 16:54:55 +01:00
# ifdef DSM_THROTTLE_KILL_CH
2019-10-08 18:52:47 +02:00
if ( idx = = CH1 & & kill_ch < = 604 )
{ //Activate throttle kill only if channel is throttle and DSM_THROTTLE_KILL_CH below -50%
2018-11-20 16:54:55 +01:00
if ( kill_ch < CHANNEL_MIN_100 ) // restrict val to 0...400
kill_ch = 0 ;
else
kill_ch - = CHANNEL_MIN_100 ;
2018-11-23 10:03:55 +01:00
value = ( kill_ch * 21 ) / 25 ; // kill channel -100%->904us ... -50%->1100us *0x150/400
2018-11-20 16:54:55 +01:00
}
else
2018-01-09 16:04:04 +01:00
# endif
2018-11-20 16:54:55 +01:00
# ifdef DSM_MAX_THROW
value = Channel_data [ CH_TAER [ idx ] ] ; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
# else
2019-11-05 19:12:06 +01:00
if ( option & 0x80 )
value = Channel_data [ CH_TAER [ idx ] ] ; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
else
value = convert_channel_16b_nolimit ( CH_TAER [ idx ] , 0x150 , 0x6B0 ) ; // -100%..+100% => 1100..1900us and -125%..+125% => 1000..2000us based on Redcon 6 channel DSM2 RX
2018-11-20 16:54:55 +01:00
# endif
2018-01-08 19:37:14 +01:00
if ( bits = = 10 ) value > > = 1 ;
2016-09-24 13:58:06 +02:00
value | = ( upper & & i = = 0 ? 0x8000 : 0 ) | ( idx < < bits ) ;
2015-12-30 01:41:12 +01:00
}
packet [ i * 2 + 2 ] = ( value > > 8 ) & 0xff ;
packet [ i * 2 + 3 ] = ( value > > 0 ) & 0xff ;
}
}
2017-01-03 19:07:10 +01:00
static void __attribute__ ( ( unused ) ) DSM_set_sop_data_crc ( )
2015-12-30 01:41:12 +01:00
{
2016-09-21 14:29:09 +02:00
//The crc for channel '1' is NOT(mfgid[0] << 8 + mfgid[1])
//The crc for channel '2' is (mfgid[0] << 8 + mfgid[1])
uint16_t crc = ( cyrfmfg_id [ 0 ] < < 8 ) + cyrfmfg_id [ 1 ] ;
if ( phase = = DSM_CH1_CHECK_A | | phase = = DSM_CH1_CHECK_B )
CYRF_ConfigCRCSeed ( crc ) ; //CH2
else
CYRF_ConfigCRCSeed ( ~ crc ) ; //CH1
2016-02-05 17:27:51 +01:00
2018-09-10 09:58:31 +02:00
uint8_t pn_row = DSM_get_pn_row ( hopping_frequency [ hopping_frequency_no ] ) ;
2016-09-21 14:29:09 +02:00
uint8_t code [ 16 ] ;
2018-09-10 09:58:31 +02:00
DSM_read_code ( code , pn_row , sop_col , 8 ) ; // pn_row between 0 and 4, sop_col between 1 and 7
2016-02-05 17:27:51 +01:00
CYRF_ConfigSOPCode ( code ) ;
2018-09-10 09:58:31 +02:00
DSM_read_code ( code , pn_row , 7 - sop_col , 8 ) ; // 7-sop_col between 0 and 6
DSM_read_code ( code + 8 , pn_row , 7 - sop_col + 1 , 8 ) ; // 7-sop_col+1 between 1 and 7
2016-02-05 17:27:51 +01:00
CYRF_ConfigDataCode ( code , 16 ) ;
2016-09-21 14:29:09 +02:00
CYRF_ConfigRFChannel ( hopping_frequency [ hopping_frequency_no ] ) ;
hopping_frequency_no + + ;
2016-09-19 18:58:09 +02:00
if ( sub_protocol = = DSMX_11 | | sub_protocol = = DSMX_22 )
2016-09-21 14:29:09 +02:00
hopping_frequency_no % = 23 ;
2015-12-30 01:41:12 +01:00
else
2016-09-21 14:29:09 +02:00
hopping_frequency_no % = 2 ;
2015-12-30 01:41:12 +01:00
}
2017-01-03 19:07:10 +01:00
static void __attribute__ ( ( unused ) ) DSM_calc_dsmx_channel ( )
2015-12-30 01:41:12 +01:00
{
uint8_t idx = 0 ;
uint32_t id = ~ ( ( ( uint32_t ) cyrfmfg_id [ 0 ] < < 24 ) | ( ( uint32_t ) cyrfmfg_id [ 1 ] < < 16 ) | ( ( uint32_t ) cyrfmfg_id [ 2 ] < < 8 ) | ( cyrfmfg_id [ 3 ] < < 0 ) ) ;
uint32_t id_tmp = id ;
while ( idx < 23 )
{
uint8_t i ;
uint8_t count_3_27 = 0 , count_28_51 = 0 , count_52_76 = 0 ;
id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F ; // Randomization
uint8_t next_ch = ( ( id_tmp > > 8 ) % 0x49 ) + 3 ; // Use least-significant byte and must be larger than 3
2016-04-06 12:57:42 +02:00
if ( ( next_ch ^ cyrfmfg_id [ 3 ] ) & 0x01 )
2015-12-30 01:41:12 +01:00
continue ;
for ( i = 0 ; i < idx ; i + + )
{
if ( hopping_frequency [ i ] = = next_ch )
break ;
if ( hopping_frequency [ i ] < = 27 )
count_3_27 + + ;
else
if ( hopping_frequency [ i ] < = 51 )
count_28_51 + + ;
else
count_52_76 + + ;
}
if ( i ! = idx )
continue ;
if ( ( next_ch < 28 & & count_3_27 < 8 )
| | ( next_ch > = 28 & & next_ch < 52 & & count_28_51 < 7 )
| | ( next_ch > = 52 & & count_52_76 < 8 ) )
hopping_frequency [ idx + + ] = next_ch ;
}
}
2016-09-19 18:58:09 +02:00
static uint8_t __attribute__ ( ( unused ) ) DSM_Check_RX_packet ( )
{
uint8_t result = 1 ; // assume good packet
uint16_t sum = 384 - 0x10 ;
for ( uint8_t i = 1 ; i < 9 ; i + + )
{
2019-09-30 17:35:12 +02:00
sum + = packet_in [ i ] ;
2016-09-19 18:58:09 +02:00
if ( i < 5 )
2019-09-30 17:35:12 +02:00
if ( packet_in [ i ] ! = ( 0xff ^ cyrfmfg_id [ i - 1 ] ) )
2016-09-19 18:58:09 +02:00
result = 0 ; // bad packet
}
2019-09-30 17:35:12 +02:00
if ( packet_in [ 9 ] ! = ( sum > > 8 ) & & packet_in [ 10 ] ! = ( uint8_t ) sum )
2016-09-19 18:58:09 +02:00
result = 0 ;
return result ;
}
2016-09-01 14:00:42 +02:00
uint16_t ReadDsm ( )
2015-12-30 01:41:12 +01:00
{
2019-08-01 14:23:08 +02:00
# define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2
# ifdef STM32_BOARD
# define DSM_WRITE_DELAY 1500 // Time after write to verify write complete
# else
# define DSM_WRITE_DELAY 1950 // Time after write to verify write complete
# endif
# define DSM_READ_DELAY 600 // Time before write to check read phase, and switch channels. Was 400 but 600 seems what the 328p needs to read a packet
2016-09-20 18:27:09 +02:00
# if defined DSM_TELEMETRY
uint8_t rx_phase ;
uint8_t len ;
# endif
2016-10-16 19:51:42 +02:00
uint8_t start ;
2016-09-19 18:58:09 +02:00
switch ( phase )
2015-12-30 01:41:12 +01:00
{
2016-09-19 18:58:09 +02:00
case DSM_BIND_WRITE :
if ( bind_counter - - = = 0 )
2016-09-20 18:27:09 +02:00
# if defined DSM_TELEMETRY
2016-09-19 18:58:09 +02:00
phase = DSM_BIND_CHECK ; //Check RX answer
2016-09-20 18:27:09 +02:00
# else
phase = DSM_CHANSEL ; //Switch to normal mode
# endif
2016-09-19 18:58:09 +02:00
CYRF_WriteDataPacket ( packet ) ;
return 10000 ;
2016-09-20 18:27:09 +02:00
# if defined DSM_TELEMETRY
2016-09-19 18:58:09 +02:00
case DSM_BIND_CHECK :
2016-09-23 16:01:18 +02:00
//64 SDR Mode is configured so only the 8 first values are needed but we need to write 16 values...
CYRF_ConfigDataCode ( ( const uint8_t * ) " \x98 \x88 \x1B \xE4 \x30 \x79 \x03 \x84 \xC9 \x2C \x06 \x93 \x86 \xB9 \x9E \xD7 " , 16 ) ;
2016-09-19 18:58:09 +02:00
CYRF_SetTxRxMode ( RX_EN ) ; //Receive mode
2016-09-23 16:01:18 +02:00
CYRF_WriteRegister ( CYRF_05_RX_CTRL , 0x87 ) ; //Prepare to receive
bind_counter = 2 * DSM_BIND_COUNT ; //Timeout of 4.2s if no packet received
2016-09-19 18:58:09 +02:00
phase + + ; // change from BIND_CHECK to BIND_READ
return 2000 ;
case DSM_BIND_READ :
//Read data from RX
rx_phase = CYRF_ReadRegister ( CYRF_07_RX_IRQ_STATUS ) ;
if ( ( rx_phase & 0x03 ) = = 0x02 ) // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_phase | = CYRF_ReadRegister ( CYRF_07_RX_IRQ_STATUS ) ;
if ( ( rx_phase & 0x07 ) = = 0x02 )
2016-09-23 16:01:18 +02:00
{ // data received with no errors
2016-09-19 18:58:09 +02:00
CYRF_WriteRegister ( CYRF_07_RX_IRQ_STATUS , 0x80 ) ; // need to set RXOW before data read
len = CYRF_ReadRegister ( CYRF_09_RX_COUNT ) ;
2019-09-30 17:35:12 +02:00
if ( len > TELEMETRY_BUFFER_SIZE - 2 )
len = TELEMETRY_BUFFER_SIZE - 2 ;
CYRF_ReadDataPacketLen ( packet_in + 1 , len ) ;
2016-09-19 18:58:09 +02:00
if ( len = = 10 & & DSM_Check_RX_packet ( ) )
{
2019-09-30 17:35:12 +02:00
packet_in [ 0 ] = 0x80 ;
2016-09-19 18:58:09 +02:00
telemetry_link = 1 ; // send received data on serial
phase + + ;
return 2000 ;
}
2016-09-16 17:59:57 +02:00
}
2016-09-23 16:01:18 +02:00
else
if ( ( rx_phase & 0x02 ) ! = 0x02 )
{ // data received with errors
CYRF_WriteRegister ( CYRF_29_RX_ABORT , 0x20 ) ; // Abort RX operation
CYRF_SetTxRxMode ( RX_EN ) ; // Force end state read
CYRF_WriteRegister ( CYRF_29_RX_ABORT , 0x00 ) ; // Clear abort RX operation
CYRF_WriteRegister ( CYRF_05_RX_CTRL , 0x83 ) ; // Prepare to receive
}
2016-09-19 23:43:14 +02:00
if ( - - bind_counter = = 0 )
2016-09-23 16:01:18 +02:00
{ // Exit if no answer has been received for some time
phase + + ; // DSM_CHANSEL
2016-09-19 23:43:14 +02:00
return 7000 ;
}
2016-09-19 18:58:09 +02:00
return 7000 ;
2016-09-20 18:27:09 +02:00
# endif
2016-09-19 18:58:09 +02:00
case DSM_CHANSEL :
2015-12-30 01:41:12 +01:00
BIND_DONE ;
2017-01-03 19:07:10 +01:00
DSM_cyrf_configdata ( ) ;
2015-12-30 01:41:12 +01:00
CYRF_SetTxRxMode ( TX_EN ) ;
2016-04-06 12:57:42 +02:00
hopping_frequency_no = 0 ;
2016-09-19 18:58:09 +02:00
phase = DSM_CH1_WRITE_A ; // in fact phase++
2017-01-03 19:07:10 +01:00
DSM_set_sop_data_crc ( ) ;
2015-12-30 01:41:12 +01:00
return 10000 ;
2016-09-19 18:58:09 +02:00
case DSM_CH1_WRITE_A :
2019-11-11 19:15:39 +01:00
# ifdef MULTI_SYNC
telemetry_set_input_sync ( 11000 ) ; // Always request 11ms spacing even if we don't use half of it in 22ms mode
# endif
2016-09-19 18:58:09 +02:00
case DSM_CH1_WRITE_B :
case DSM_CH2_WRITE_A :
case DSM_CH2_WRITE_B :
2017-01-03 19:07:10 +01:00
DSM_build_data_packet ( phase = = DSM_CH1_WRITE_B | | phase = = DSM_CH2_WRITE_B ) ; // build lower or upper channels
2016-09-19 18:58:09 +02:00
CYRF_ReadRegister ( CYRF_04_TX_IRQ_STATUS ) ; // clear IRQ flags
2015-12-30 01:41:12 +01:00
CYRF_WriteDataPacket ( packet ) ;
2016-09-19 18:58:09 +02:00
phase + + ; // change from WRITE to CHECK mode
2016-04-06 12:57:42 +02:00
return DSM_WRITE_DELAY ;
2016-09-19 18:58:09 +02:00
case DSM_CH1_CHECK_A :
case DSM_CH1_CHECK_B :
case DSM_CH2_CHECK_A :
case DSM_CH2_CHECK_B :
2018-08-21 14:58:44 +02:00
start = ( uint8_t ) micros ( ) ;
while ( ( uint8_t ) ( ( uint8_t ) micros ( ) - ( uint8_t ) start ) < 100 ) // Wait max 100µs, max I've seen is 50µs
if ( ( CYRF_ReadRegister ( CYRF_02_TX_CTRL ) & 0x80 ) = = 0x00 )
2015-12-30 01:41:12 +01:00
break ;
2019-08-01 14:23:08 +02:00
2016-10-16 19:51:42 +02:00
if ( phase = = DSM_CH1_CHECK_A | | phase = = DSM_CH1_CHECK_B )
{
# if defined DSM_TELEMETRY
// reset cyrf6936 if freezed after switching from TX to RX
if ( ( ( CYRF_ReadRegister ( CYRF_04_TX_IRQ_STATUS ) & 0x22 ) = = 0x20 ) | | ( CYRF_ReadRegister ( CYRF_02_TX_CTRL ) & 0x80 ) )
{
CYRF_Reset ( ) ;
2017-01-03 19:07:10 +01:00
DSM_cyrf_config ( ) ;
DSM_cyrf_configdata ( ) ;
2016-10-16 19:51:42 +02:00
CYRF_SetTxRxMode ( TX_EN ) ;
}
# endif
2017-01-03 19:07:10 +01:00
DSM_set_sop_data_crc ( ) ;
2016-10-16 19:51:42 +02:00
phase + + ; // change from CH1_CHECK to CH2_WRITE
return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
}
2016-09-19 18:58:09 +02:00
if ( phase = = DSM_CH2_CHECK_A )
CYRF_SetPower ( 0x28 ) ; //Keep transmit power in sync
2016-04-06 12:57:42 +02:00
# if defined DSM_TELEMETRY
2016-09-19 18:58:09 +02:00
phase + + ; // change from CH2_CHECK to CH2_READ
CYRF_SetTxRxMode ( RX_EN ) ; //Receive mode
CYRF_WriteRegister ( CYRF_05_RX_CTRL , 0x87 ) ; //0x80??? //Prepare to receive
2016-04-06 12:57:42 +02:00
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY ;
2016-09-19 18:58:09 +02:00
case DSM_CH2_READ_A :
case DSM_CH2_READ_B :
2016-04-06 12:57:42 +02:00
//Read telemetry
2016-09-19 18:58:09 +02:00
rx_phase = CYRF_ReadRegister ( CYRF_07_RX_IRQ_STATUS ) ;
if ( ( rx_phase & 0x03 ) = = 0x02 ) // RXC=1, RXE=0 then 2nd check is required (debouncing)
rx_phase | = CYRF_ReadRegister ( CYRF_07_RX_IRQ_STATUS ) ;
if ( ( rx_phase & 0x07 ) = = 0x02 )
2016-04-06 12:57:42 +02:00
{ // good data (complete with no errors)
CYRF_WriteRegister ( CYRF_07_RX_IRQ_STATUS , 0x80 ) ; // need to set RXOW before data read
2016-09-19 18:58:09 +02:00
len = CYRF_ReadRegister ( CYRF_09_RX_COUNT ) ;
2019-09-30 17:35:12 +02:00
if ( len > TELEMETRY_BUFFER_SIZE - 2 )
len = TELEMETRY_BUFFER_SIZE - 2 ;
CYRF_ReadDataPacketLen ( packet_in + 1 , len ) ;
packet_in [ 0 ] = CYRF_ReadRegister ( CYRF_13_RSSI ) & 0x1F ; // store RSSI of the received telemetry signal
2016-04-06 12:57:42 +02:00
telemetry_link = 1 ;
}
2016-09-23 16:01:18 +02:00
CYRF_WriteRegister ( CYRF_29_RX_ABORT , 0x20 ) ; // Abort RX operation
2019-06-23 17:13:30 +02:00
if ( phase = = DSM_CH2_READ_A & & ( sub_protocol = = DSM2_22 | | sub_protocol = = DSMX_22 ) & & num_ch < 8 ) // 22ms mode
2016-04-06 12:57:42 +02:00
{
2016-09-23 16:01:18 +02:00
CYRF_SetTxRxMode ( RX_EN ) ; // Force end state read
CYRF_WriteRegister ( CYRF_29_RX_ABORT , 0x00 ) ; // Clear abort RX operation
2016-09-19 18:58:09 +02:00
CYRF_WriteRegister ( CYRF_05_RX_CTRL , 0x87 ) ; //0x80??? //Prepare to receive
2016-09-23 16:01:18 +02:00
phase = DSM_CH2_READ_B ;
2016-04-06 12:57:42 +02:00
return 11000 ;
}
2016-09-19 18:58:09 +02:00
if ( phase = = DSM_CH2_READ_A )
phase = DSM_CH1_WRITE_B ; //Transmit upper
2016-04-06 12:57:42 +02:00
else
2016-09-19 18:58:09 +02:00
phase = DSM_CH1_WRITE_A ; //Transmit lower
2016-09-23 16:01:18 +02:00
CYRF_SetTxRxMode ( TX_EN ) ; //TX mode
CYRF_WriteRegister ( CYRF_29_RX_ABORT , 0x00 ) ; //Clear abort RX operation
2017-01-03 19:07:10 +01:00
DSM_set_sop_data_crc ( ) ;
2016-04-06 12:57:42 +02:00
return DSM_READ_DELAY ;
# else
// No telemetry
2017-01-03 19:07:10 +01:00
DSM_set_sop_data_crc ( ) ;
2016-09-19 18:58:09 +02:00
if ( phase = = DSM_CH2_CHECK_A )
2015-12-30 01:41:12 +01:00
{
2019-06-23 17:13:30 +02:00
if ( num_ch > 7 | | sub_protocol = = DSM2_11 | | sub_protocol = = DSMX_11 )
2016-09-19 18:58:09 +02:00
phase = DSM_CH1_WRITE_B ; //11ms mode or upper to transmit change from CH2_CHECK_A to CH1_WRITE_A
else
{ //Normal mode 22ms
phase = DSM_CH1_WRITE_A ; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper)
return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
2016-03-13 09:29:25 +01:00
}
2015-12-30 01:41:12 +01:00
}
else
2016-09-19 18:58:09 +02:00
phase = DSM_CH1_WRITE_A ; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower)
2016-04-06 12:57:42 +02:00
return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ;
# endif
2015-12-30 01:41:12 +01:00
}
return 0 ;
}
2016-09-01 14:00:42 +02:00
uint16_t initDsm ( )
2015-12-30 01:41:12 +01:00
{
2016-09-23 16:01:18 +02:00
CYRF_GetMfgData ( cyrfmfg_id ) ;
2016-04-06 12:57:42 +02:00
//Model match
2016-09-23 16:01:18 +02:00
cyrfmfg_id [ 3 ] ^ = RX_num ;
//Calc sop_col
sop_col = ( cyrfmfg_id [ 0 ] + cyrfmfg_id [ 1 ] + cyrfmfg_id [ 2 ] + 2 ) & 0x07 ;
2018-09-10 09:58:31 +02:00
//Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8"
2016-09-23 16:01:18 +02:00
if ( sop_col = = 0 )
{
2016-09-24 13:58:06 +02:00
cyrfmfg_id [ rx_tx_addr [ 0 ] % 3 ] ^ = 0x01 ; //Change a bit so sop_col will be different from 0
2016-09-23 16:01:18 +02:00
sop_col = ( cyrfmfg_id [ 0 ] + cyrfmfg_id [ 1 ] + cyrfmfg_id [ 2 ] + 2 ) & 0x07 ;
}
//Hopping frequencies
2016-09-19 18:58:09 +02:00
if ( sub_protocol = = DSMX_11 | | sub_protocol = = DSMX_22 )
2017-01-03 19:07:10 +01:00
DSM_calc_dsmx_channel ( ) ;
2015-12-30 01:41:12 +01:00
else
{
uint8_t tmpch [ 10 ] ;
CYRF_FindBestChannels ( tmpch , 10 , 5 , 3 , 75 ) ;
//
uint8_t idx = random ( 0xfefefefe ) % 10 ;
hopping_frequency [ 0 ] = tmpch [ idx ] ;
while ( 1 )
{
idx = random ( 0xfefefefe ) % 10 ;
if ( tmpch [ idx ] ! = hopping_frequency [ 0 ] )
break ;
}
hopping_frequency [ 1 ] = tmpch [ idx ] ;
}
//
2017-01-03 19:07:10 +01:00
DSM_cyrf_config ( ) ;
2015-12-30 01:41:12 +01:00
CYRF_SetTxRxMode ( TX_EN ) ;
//
2017-01-03 19:07:10 +01:00
DSM_update_channels ( ) ;
2016-09-23 16:01:18 +02:00
//
2018-01-03 13:04:58 +01:00
if ( IS_BIND_IN_PROGRESS )
2015-12-30 01:41:12 +01:00
{
2017-01-03 19:07:10 +01:00
DSM_initialize_bind_phase ( ) ;
2016-09-19 18:58:09 +02:00
phase = DSM_BIND_WRITE ;
bind_counter = DSM_BIND_COUNT ;
2015-12-30 01:41:12 +01:00
}
else
2016-09-19 18:58:09 +02:00
phase = DSM_CHANSEL ; //
2015-12-30 01:41:12 +01:00
return 10000 ;
}
2017-04-12 16:10:18 +02:00
# endif