diff --git a/Multiprotocol/Multi.txt b/Multiprotocol/Multi.txt index 914617a..b8073e6 100644 --- a/Multiprotocol/Multi.txt +++ b/Multiprotocol/Multi.txt @@ -47,4 +47,5 @@ 47,GD00X,GD_V1,GD_V2 48,V761 49,KF606 +50,REDPINE,FAST,SLOW 63,XN_DUMP,250K,1M,2M diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 4398ecb..fed9edd 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -19,7 +19,7 @@ #define VERSION_MAJOR 1 #define VERSION_MINOR 2 #define VERSION_REVISION 1 -#define VERSION_PATCH_LEVEL 61 +#define VERSION_PATCH_LEVEL 62 //****************** // Protocols @@ -76,6 +76,7 @@ enum PROTOCOLS PROTO_GD00X = 47, // =>NRF24L01 PROTO_V761 = 48, // =>NRF24L01 PROTO_KF606 = 49, // =>NRF24L01 + PROTO_REDPINE = 50, // =>CC2500 PROTO_XN297DUMP = 63, // =>NRF24L01 }; @@ -270,6 +271,11 @@ enum BUGSMINI BUGSMINI= 0, BUGS3H = 1, }; +enum REDPINE +{ + RED_FAST= 0, + RED_SLOW= 1, +}; #define NONE 0 #define P_HIGH 1 #define P_LOW 0 @@ -613,6 +619,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- GD00X 47 V761 48 KF606 49 + REDPINE 50 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No @@ -749,6 +756,9 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- sub_protocol==GD00X GD_V1 0 GD_V2 1 + sub_protocol==REDPINE + RED_FAST 0 + RED_SLOW 1 Power value => 0x80 0=High/1=Low Stream[3] = option_protocol; diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 7ceaf9c..871376c 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -113,7 +113,7 @@ uint8_t len; uint8_t armed, arm_flags, arm_channel_previous; #ifdef CC2500_INSTALLED - uint8_t calData[48]; + uint8_t calData[50]; #endif #ifdef CHECK_FOR_BOOTLOADER @@ -442,6 +442,11 @@ void setup() option = FORCE_CORONA_TUNING; // Use config-defined tuning value for CORONA else #endif + #if defined(FORCE_REDPINE_TUNING) && defined(REDPINE_CC2500_INO) + if (protocol==PROTO_REDPINE) + option = FORCE_REDPINE_TUNING; // Use config-defined tuning value for REDPINE + else + #endif #if defined(FORCE_HITEC_TUNING) && defined(HITEC_CC2500_INO) if (protocol==PROTO_HITEC) option = FORCE_HITEC_TUNING; // Use config-defined tuning value for HITEC @@ -969,6 +974,14 @@ static void protocol_init() remote_callback = ReadCORONA; break; #endif + #if defined(REDPINE_CC2500_INO) + case PROTO_REDPINE: + PE1_off; //antenna RF2 + PE2_on; + next_callback = initREDPINE(); + remote_callback = ReadREDPINE; + break; + #endif #if defined(HITEC_CC2500_INO) case PROTO_HITEC: PE1_off; //antenna RF2 @@ -1321,6 +1334,11 @@ void update_serial_data() option=FORCE_CORONA_TUNING; // Use config-defined tuning value for CORONA else #endif + #if defined(FORCE_REDPINE_TUNING) && defined(REDPINE_CC2500_INO) + if (protocol==PROTO_REDPINE) + option=FORCE_REDPINE_TUNING; // Use config-defined tuning value for REDPINE + else + #endif #if defined(FORCE_HITEC_TUNING) && defined(HITEC_CC2500_INO) if (protocol==PROTO_HITEC) option=FORCE_HITEC_TUNING; // Use config-defined tuning value for HITEC diff --git a/Multiprotocol/Redpine_cc2500.ino b/Multiprotocol/Redpine_cc2500.ino new file mode 100644 index 0000000..44a259a --- /dev/null +++ b/Multiprotocol/Redpine_cc2500.ino @@ -0,0 +1,242 @@ +/* + 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(REDPINE_CC2500_INO) + +#include "iface_cc2500.h" + +#define REDPINE_LOOPTIME_FAST 9 //9ms +#define REDPINE_LOOPTIME_SLOW 22 //22ms + +#define REDPINE_BIND 1000 +#define REDPINE_PACKET_SIZE 11 +#define REDPINE_FEC false // from cc2500 datasheet: The convolutional coder is a rate 1/2 code with a constraint length of m=4 +#define REDPINE_NUM_HOPS 50 + +static void REDPINE_set_channel(uint8_t ch) +{ + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch]); + CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[ch]); +} + +static void REDPINE_build_bind_packet() +{ + memset(&packet[0], 0, REDPINE_PACKET_SIZE); + + packet[0] = REDPINE_PACKET_SIZE - 1; + packet[1] = 0x03; + packet[2] = 0x01; + packet[3] = rx_tx_addr[2]; + packet[4] = rx_tx_addr[3]; // Use RX_Num + uint16_t idx = ((REDPINE_BIND - bind_counter) % 10) * 5; + packet[5] = idx; + packet[6] = hopping_frequency[idx++]; + packet[7] = hopping_frequency[idx++]; + packet[8] = hopping_frequency[idx++]; + packet[9] = hopping_frequency[idx++]; + packet[10] = hopping_frequency[idx++]; + // packet[11] = 0x02; + // packet[12] = RXNUM; +} + +static uint16_t Redpine_Scale(uint8_t chan) +{ + uint16_t chan_val=Channel_data[chan]; // -125%..+125% <=> 0..2047 + if (chan_val > 2046) chan_val = 2046; + else if (chan_val < 10) chan_val = 10; + return chan_val; +} + + +static void REDPINE_data_frame() { + uint16_t chan[4]; + + memset(&packet[0], 0, REDPINE_PACKET_SIZE); + + packet[0] = REDPINE_PACKET_SIZE - 1; + packet[1] = rx_tx_addr[2]; + packet[2] = rx_tx_addr[3]; // Use RX_Num + + chan[0] = Redpine_Scale(0); + chan[1] = Redpine_Scale(1); + chan[2] = Redpine_Scale(2); + chan[3] = Redpine_Scale(3); + + packet[3] = chan[0]; + packet[4] = (((chan[0] >> 8) & 0x07) | (chan[1] << 4)) | GET_FLAG(CH5_SW, 0x08); + packet[5] = ((chan[1] >> 4) & 0x7F) | GET_FLAG(CH6_SW, 0x80); + packet[6] = chan[2]; + packet[7] = (((chan[2] >> 8) & 0x07) | (chan[3] << 4)) | GET_FLAG(CH7_SW, 0x08); + packet[8] = ((chan[3] >> 4) & 0x7F) | GET_FLAG(CH8_SW, 0x80); + packet[9] = GET_FLAG(CH9_SW, 0x01) + | GET_FLAG(CH10_SW, 0x02) + | GET_FLAG(CH11_SW, 0x04) + | GET_FLAG(CH12_SW, 0x08) + | GET_FLAG(CH13_SW, 0x10) + | GET_FLAG(CH14_SW, 0x20) + | GET_FLAG(CH15_SW, 0x40) + | GET_FLAG(CH16_SW, 0x80); + + if (sub_protocol==0) + packet[10] = REDPINE_LOOPTIME_FAST; + else + packet[10] = REDPINE_LOOPTIME_SLOW; +} + +static uint16_t ReadREDPINE() +{ + if ( prev_option != option ) + { // Frequency adjust + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + prev_option = option ; + } + if(IS_BIND_IN_PROGRESS) + { + if(bind_counter== REDPINE_BIND) + REDPINE_init(0); + if(state == REDPINE_BIND/2) + REDPINE_init(1); + REDPINE_set_channel(49); + CC2500_SetPower(); + CC2500_Strobe(CC2500_SFRX); + REDPINE_build_bind_packet(); + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteData(packet, REDPINE_PACKET_SIZE); + if(--bind_counter==0) + { + BIND_DONE; + REDPINE_init(sub_protocol); + } + return 9000; + } + else + { + CC2500_SetTxRxMode(TX_EN); + REDPINE_set_channel(hopping_frequency_no); + CC2500_SetPower(); + CC2500_Strobe(CC2500_SFRX); + REDPINE_data_frame(); + CC2500_Strobe(CC2500_SIDLE); + hopping_frequency_no = (hopping_frequency_no + 1) % 49; + CC2500_WriteData(packet, REDPINE_PACKET_SIZE); + if (sub_protocol==0) + return REDPINE_LOOPTIME_FAST*100; + else + return REDPINE_LOOPTIME_SLOW*100; + } + return 1; +} + +// register, fast 250k, slow +static const uint8_t REDPINE_init_data[][3] = { + {CC2500_00_IOCFG2, 0x06, 0x06}, + {CC2500_02_IOCFG0, 0x06, 0x06}, + {CC2500_03_FIFOTHR, 0x07, 0x07}, + {CC2500_07_PKTCTRL1, 0x04, 0x04}, + {CC2500_08_PKTCTRL0, 0x05, 0x05}, + {CC2500_09_ADDR, 0x00, 0x00}, + {CC2500_0B_FSCTRL1, 0x0A, 0x0A}, + {CC2500_0C_FSCTRL0, 0x00, 0x00}, + {CC2500_0D_FREQ2, 0x5D, 0x5c}, + {CC2500_0E_FREQ1, 0x93, 0x76}, + {CC2500_0F_FREQ0, 0xB1, 0x27}, + {CC2500_10_MDMCFG4, 0x2D, 0x7B}, + {CC2500_11_MDMCFG3, 0x3B, 0x61}, + {CC2500_12_MDMCFG2, 0x73, 0x13}, + #ifdef REDPINE_FEC + {CC2500_13_MDMCFG1, 0xA3, 0xA3}, + #else + {CC2500_13_MDMCFG1, 0x23, 0x23}, + #endif + {CC2500_14_MDMCFG0, 0x56, 0x7a}, // Chan space + {CC2500_15_DEVIATN, 0x00, 0x51}, + {CC2500_17_MCSM1, 0x0c, 0x0c}, + {CC2500_18_MCSM0, 0x08, 0x08}, //??? 0x18, 0x18}, + {CC2500_19_FOCCFG, 0x1D, 0x16}, + {CC2500_1A_BSCFG, 0x1C, 0x6c}, + {CC2500_1B_AGCCTRL2, 0xC7, 0x43}, + {CC2500_1C_AGCCTRL1, 0x00, 0x40}, + {CC2500_1D_AGCCTRL0, 0xB0, 0x91}, + {CC2500_21_FREND1, 0xB6, 0x56}, + {CC2500_22_FREND0, 0x10, 0x10}, + {CC2500_23_FSCAL3, 0xEA, 0xA9}, + {CC2500_24_FSCAL2, 0x0A, 0x0A}, + {CC2500_25_FSCAL1, 0x00, 0x00}, + {CC2500_26_FSCAL0, 0x11, 0x11}, + {CC2500_29_FSTEST, 0x59, 0x59}, + {CC2500_2C_TEST2, 0x88, 0x88}, + {CC2500_2D_TEST1, 0x31, 0x31}, + {CC2500_2E_TEST0, 0x0B, 0x0B}, + {CC2500_3E_PATABLE, 0xff, 0xff} +}; + +static void REDPINE_init(uint8_t format) +{ + CC2500_Reset(); + + CC2500_WriteReg(CC2500_06_PKTLEN, REDPINE_PACKET_SIZE); + + for (uint8_t i=0; i < ((sizeof REDPINE_init_data) / (sizeof REDPINE_init_data[0])); i++) + CC2500_WriteReg(REDPINE_init_data[i][0], REDPINE_init_data[i][format+1]); + + prev_option = option; + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + CC2500_Strobe(CC2500_SIDLE); + + // calibrate hop channels + for (uint8_t c = 0; c < REDPINE_NUM_HOPS; c++) + { + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR, hopping_frequency[c]); + CC2500_Strobe(CC2500_SCAL); + delayMicroseconds(900); + calData[c] = CC2500_ReadReg(CC2500_25_FSCAL1); + } +} + +static uint16_t initREDPINE() +{ + hopping_frequency_no = 0; + // Used from kn_nrf24l01.c : kn_calculate_freqency_hopping_channels + uint32_t idx = 0; + uint32_t rnd = MProtocol_id; + #define REDPINE_MAX_RF_CHANNEL 255 + hopping_frequency[idx++] = 1; + while (idx < REDPINE_NUM_HOPS-1) + { + uint32_t i; + rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization + // Drop least-significant byte for better randomization. Start from 1 + uint8_t next_ch = (rnd >> 8) % REDPINE_MAX_RF_CHANNEL + 1; + // Check that it's not duplicate nor adjacent nor channel 0 or 1 + for (i = 0; i < idx; i++) + { + uint8_t ch = hopping_frequency[i]; + if ((ch <= next_ch + 1) && (ch >= next_ch - 1) && (ch > 1)) + break; + } + if (i != idx) + continue; + hopping_frequency[idx++] = next_ch; + } + hopping_frequency[49] = 0; // Last channel is the bind channel at hop 0 + + bind_counter=REDPINE_BIND; + REDPINE_init(sub_protocol); + CC2500_SetTxRxMode(TX_EN); // enable PA + return 10000; +} +#endif diff --git a/Multiprotocol/Validate.h b/Multiprotocol/Validate.h index 43d14ce..2387495 100644 --- a/Multiprotocol/Validate.h +++ b/Multiprotocol/Validate.h @@ -87,6 +87,11 @@ #error "The CORONA forced frequency tuning value is outside of the range -127..127." #endif #endif +#ifdef FORCE_REDPINE_TUNING + #if ( FORCE_REDPINE_TUNING < -127 ) || ( FORCE_REDPINE_TUNING > 127 ) + #error "The REDPINE forced frequency tuning value is outside of the range -127..127." + #endif +#endif #ifdef FORCE_HITEC_TUNING #if ( FORCE_HITEC_TUNING < -127 ) || ( FORCE_HITEC_TUNING > 127 ) #error "The HITEC forced frequency tuning value is outside of the range -127..127." @@ -154,6 +159,7 @@ #undef FRSKYX_CC2500_INO #undef SFHSS_CC2500_INO #undef CORONA_CC2500_INO + #undef REDPINE_CC2500_INO #undef HITEC_CC2500_INO #undef XN297L_CC2500_EMU #endif diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 20d6762..16fa8d8 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -87,8 +87,8 @@ //#define ORANGE_TX_BLUE /** CC2500 Fine Frequency Tuning **/ -//For optimal performance the CC2500 RF module used by the FrSkyD, FrSkyV, FrSkyX, SFHSS, CORONA and Hitec protocols needs to be tuned for each protocol. -//Initial tuning should be done via the radio menu with a genuine FrSky/Futaba/CORONA/Hitec receiver. +//For optimal performance the CC2500 RF module used by the FrSkyD, FrSkyV, FrSkyX, SFHSS, CORONA, Redpine and Hitec protocols needs to be tuned for each protocol. +//Initial tuning should be done via the radio menu with a genuine FrSky/Futaba/CORONA/Hitec/Redpine receiver. //Once a good tuning value is found it can be set here and will override the radio's 'option' setting for all existing and new models which use that protocol. //For more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/tree/master/docs/Frequency_Tuning.md //Uncomment the lines below (remove the "//") and set an appropriate value (replace the "0") to enable. Valid range is -127 to +127. @@ -98,6 +98,7 @@ //#define FORCE_SFHSS_TUNING 0 //#define FORCE_CORONA_TUNING 0 //#define FORCE_HITEC_TUNING 0 +//#define FORCE_REDPINE_TUNING 0 /** A7105 Fine Frequency Tuning **/ //This is required in rare cases where some A7105 modules and/or RXs have an inaccurate crystal oscillator. @@ -164,6 +165,7 @@ #define J6PRO_CYRF6936_INO #define WFLY_CYRF6936_INO #define WK2x01_CYRF6936_INO + //#define TRAXXAS_CYRF6936_INO //The protocols below need a CC2500 to be installed @@ -173,6 +175,7 @@ #define FRSKYX_CC2500_INO #define HITEC_CC2500_INO #define SFHSS_CC2500_INO +#define REDPINE_CC2500_INO //The protocols below need a NRF24L01 to be installed #define ASSAN_NRF24L01_INO @@ -598,6 +601,9 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= { CX35 CX10D CX10WD + PROTO_REDPINE + RED_FAST + RED_SLOW PROTO_SFHSS NONE PROTO_SHENQI