Merge branch 'master' into bayang-analog-aux

This commit is contained in:
BrianQuad 2018-12-19 18:03:42 -07:00
commit e2eb074c18
40 changed files with 3285 additions and 423 deletions

97
.travis.yml Normal file
View File

@ -0,0 +1,97 @@
dist: trusty
sudo: true
#
language: c
#
env:
global:
- IDE_VERSION=1.8.1
matrix:
- BOARD="multi4in1:STM32F1:multistm32f103c:upload_method=serialMethod"
- BOARD="multi4in1:STM32F1:multistm32f103c:upload_method=TxFlashMethod"
- BOARD="multi4in1:avr:multixmega32d4"
- BOARD="multi4in1:avr:multiatmega328p:bootloader=none"
- BOARD="multi4in1:avr:multiatmega328p:bootloader=optiboot"
#
notifications:
email: false
#
before_install:
#
# Fetch the tag information for the current branch
- git fetch origin --tags
#
# Publish the buildroot script folder
- chmod +x ${TRAVIS_BUILD_DIR}/buildroot/bin/*
- export PATH=${TRAVIS_BUILD_DIR}/buildroot/bin/:${PATH}
#
# Install Arduino IDE
- wget http://downloads.arduino.cc/arduino-$IDE_VERSION-linux64.tar.xz
- tar xf arduino-$IDE_VERSION-linux64.tar.xz
- mv arduino-$IDE_VERSION $HOME/arduino-ide
- export PATH=$PATH:$HOME/arduino-ide
# Set the Multi boards package URL
- arduino --pref "boardsmanager.additional.urls=https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/master/package_multi_4in1_board_index.json" --save-prefs
#
- if [[ "$BOARD" =~ "multi4in1:STM32F1:" ]]; then
arduino --install-boards multi4in1:STM32F1;
fi
#
- if [[ "$BOARD" =~ "multi4in1:avr:" ]]; then
arduino --install-boards multi4in1:avr;
fi
#
- buildMulti() { arduino --verify --board $BOARD Multiprotocol/Multiprotocol.ino; }
- buildProtocol() { opt_disable $ALL_PROTOCOLS; opt_enable $1; buildMulti; }
- buildEachProtocol() { exitcode=0; for PROTOCOL in $ALL_PROTOCOLS ; do echo Building $PROTOCOL; buildProtocol $PROTOCOL; if [ $? -ne 0 ]; then exitcode=1; fi; echo; done; return $exitcode; }
#
install: true
before_script:
#
# Change current working directory to the build dir
- cd ${TRAVIS_BUILD_DIR}
# Log the initial Multi config
- cat Multiprotocol/_Config.h
# Derive the Multi protocols from the Multi source
- A7105_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_A7105_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
- CC2500_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CC2500_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
- CYRF6936_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_CYRF6936_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
- NRF24L01_PROTOCOLS=$(sed -n 's/[\/\/]*[[:blank:]]*#define[[:blank:]]*\([[:alnum:]_]*_NRF24L01_INO\)\(.*\)/\1/p' Multiprotocol/_Config.h)
- if [[ "$BOARD" =~ "multi4in1:avr:multixmega32d4" ]]; then
ALL_PROTOCOLS=$(echo $CYRF6936_PROTOCOLS);
else
ALL_PROTOCOLS=$(echo $A7105_PROTOCOLS $CC2500_PROTOCOLS $CYRF6936_PROTOCOLS $NRF24L01_PROTOCOLS);
fi
- echo $ALL_PROTOCOLS
#
# Enable CHECK_FOR_BOOTLOADER when needed
- if [[ "$BOARD" =~ ":upload_method=TxFlashMethod" ]] || [[ "$BOARD" =~ ":bootloader=optiboot" ]]; then
opt_enable CHECK_FOR_BOOTLOADER;
fi
#
# Trim the build down for the Atmega328p board
- if [[ "$BOARD" =~ "multi4in1:avr:multiatmega328p:" ]]; then
opt_disable $ALL_PROTOCOLS;
opt_enable FRSKYX_CC2500_INO AFHDS2A_A7105_INO MJXQ_NRF24L01_INO DSM_CYRF6936_INO;
fi
#
script:
# Build with all protocols enabled for STM32; a subset of protocols for Atmega
- buildMulti
#
# Serial only
- opt_disable ENABLE_PPM
- opt_enable ENABLE_SERIAL
- buildMulti
#
# PPM only
- opt_enable ENABLE_PPM
- opt_disable ENABLE_SERIAL
- buildMulti
#
# Re-enable PPM and serial
- opt_enable ENABLE_SERIAL
- opt_enable ENABLE_PPM
#
# Build each protocol individually
- buildEachProtocol

View File

@ -77,6 +77,24 @@
], ],
"toolsDependencies": [] "toolsDependencies": []
}, },
{
"name": "Multi 4-in-1 AVR Boards",
"architecture": "avr",
"version": "1.0.4",
"category": "Contributed",
"help": {
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
},
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_avr_board_v1.0.4.tar.gz",
"archiveFileName": "package_multi_4in1_avr_board_v1.0.4.tar.gz",
"checksum": "SHA-256:6c51a4eb09bcd074cc651dab3f2356ea3afd358f6330aba0d8bdfaa75f718dbb",
"size": "167975",
"boards": [
{"name": "Multi 4-in-1 (Atmega328p, 3.3V, 16MHz)"},
{"name": "Multi 4-in-1 (OrangeRX)"}
],
"toolsDependencies": []
},
{ {
"name": "Multi 4-in-1 STM32 Board", "name": "Multi 4-in-1 STM32 Board",
"architecture": "STM32F1", "architecture": "STM32F1",
@ -266,6 +284,48 @@
"version": "4.8.3-2014q1" "version": "4.8.3-2014q1"
}] }]
}, },
{
"name": "Multi 4-in-1 STM32 Board",
"architecture": "STM32F1",
"version": "1.0.9",
"category": "Contributed",
"help": {
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
},
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.0.9.tar.gz",
"archiveFileName": "package_multi_4in1_stm32_board_v1.0.9.tar.gz",
"checksum": "SHA-256:c3621d1cf6580ca5c943a67dc14dc15a60e2797a4b985548abe1919486bf4a8b",
"size": "10324251",
"boards": [{
"name": "Multi 4-in-1 (STM32F103C)"
}],
"toolsDependencies": [{
"packager": "arduino",
"name": "arm-none-eabi-gcc",
"version": "4.8.3-2014q1"
}]
},
{
"name": "Multi 4-in-1 STM32 Board",
"architecture": "STM32F1",
"version": "1.1.0",
"category": "Contributed",
"help": {
"online": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module"
},
"url": "https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/archives/package_multi_4in1_stm32_board_v1.1.0.tar.gz",
"archiveFileName": "package_multi_4in1_stm32_board_v1.1.0.tar.gz",
"checksum": "SHA-256:919ece2021757686e6892679956dcb8a01c9308a152167d61d9204656b4ed7ee",
"size": "10333612",
"boards": [{
"name": "Multi 4-in-1 (STM32F103C)"
}],
"toolsDependencies": [{
"packager": "arduino",
"name": "arm-none-eabi-gcc",
"version": "4.8.3-2014q1"
}]
},
{ {
"name": "Multi 4-in-1 OrangeRX Board - DEPRECATED, USE MULTI 4-IN-1 AVR BOARDS PACKAGE INSTEAD", "name": "Multi 4-in-1 OrangeRX Board - DEPRECATED, USE MULTI 4-IN-1 AVR BOARDS PACKAGE INSTEAD",
"architecture": "orangerx", "architecture": "orangerx",

View File

@ -182,6 +182,11 @@ void A7105_AdjustLOBaseFreq(uint8_t cmd)
offset=(int16_t)FORCE_HUBSAN_TUNING; offset=(int16_t)FORCE_HUBSAN_TUNING;
#endif #endif
break; break;
case PROTO_BUGS:
#ifdef FORCE_HUBSAN_TUNING
offset=(int16_t)FORCE_HUBSAN_TUNING;
#endif
break;
case PROTO_FLYSKY: case PROTO_FLYSKY:
#ifdef FORCE_FLYSKY_TUNING #ifdef FORCE_FLYSKY_TUNING
offset=(int16_t)FORCE_FLYSKY_TUNING; offset=(int16_t)FORCE_FLYSKY_TUNING;
@ -222,21 +227,40 @@ void A7105_AdjustLOBaseFreq(uint8_t cmd)
//debugln("Channel: %d, offset: %d, bip: %2x, bfp: %4x", Channel_data[14], offset, bip, bfp); //debugln("Channel: %d, offset: %d, bip: %2x, bfp: %4x", Channel_data[14], offset, bip, bfp);
} }
static void __attribute__((unused)) A7105_SetVCOBand(uint8_t vb1, uint8_t vb2)
{ // Set calibration band value to best match
uint8_t diff1, diff2;
if (vb1 >= 4)
diff1 = vb1 - 4;
else
diff1 = 4 - vb1;
if (vb2 >= 4)
diff2 = vb2 - 4;
else
diff2 = 4 - vb2;
if (diff1 == diff2 || diff1 > diff2)
A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb1 | 0x08);
else
A7105_WriteReg(A7105_25_VCO_SBCAL_I, vb2 | 0x08);
}
#ifdef HUBSAN_A7105_INO #ifdef HUBSAN_A7105_INO
const uint8_t PROGMEM HUBSAN_A7105_regs[] = { const uint8_t PROGMEM HUBSAN_A7105_regs[] = {
0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF, 0xFF, 0x63, 0xFF, 0x0F, 0xFF, 0xFF, 0xFF ,0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x04, 0xFF, // 00 - 0f
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2B, 0xFF, 0xFF, 0x62, 0x80, 0xFF, 0xFF, 0x0A, 0xFF, 0xFF, 0x07, // 10 - 1f
0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x17, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x47, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 20 - 2f
0xFF, 0xFF 0xFF, 0xFF // 30 - 31
}; };
#endif #endif
#ifdef FLYSKY_A7105_INO #ifdef FLYSKY_A7105_INO
const uint8_t PROGMEM FLYSKY_A7105_regs[] = { const uint8_t PROGMEM FLYSKY_A7105_regs[] = {
0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, 0xff, 0x42, 0x00, 0x14, 0x00, 0xff, 0xff ,0x00, 0x00, 0x00, 0x00, 0x01, 0x21, 0x05, 0x00, 0x50, // 00 - 0f
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, 0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x00, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f
0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, 0x13, 0xc3, 0x00, 0xff, 0x00, 0x00, 0x3b, 0x00, 0x17, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
0x01, 0x0f 0x01, 0x0f // 30 - 31
}; };
#endif #endif
#ifdef AFHDS2A_A7105_INO #ifdef AFHDS2A_A7105_INO
@ -247,13 +271,27 @@ const uint8_t PROGMEM AFHDS2A_A7105_regs[] = {
0x01, 0x0f // 30 - 31 0x01, 0x0f // 30 - 31
}; };
#endif #endif
#ifdef BUGS_A7105_INO
const uint8_t PROGMEM BUGS_A7105_regs[] = {
0xFF, 0x42, 0x00, 0x15, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x05, 0x01, 0x50, // 00 - 0f
0x9e, 0x4b, 0x00, 0x02, 0x16, 0x2b, 0x12, 0x40, 0x62, 0x80, 0x80, 0x00, 0x0a, 0x32, 0xc3, 0x0f, // 10 - 1f
0x16, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x3b, 0x00, 0x0b, 0x47, 0x80, 0x03, 0x01, 0x45, 0x18, 0x00, // 20 - 2f
0x01, 0x0f // 30 - 31
};
#endif
#define ID_NORMAL 0x55201041 #define ID_NORMAL 0x55201041
#define ID_PLUS 0xAA201041 #define ID_PLUS 0xAA201041
void A7105_Init(void) void A7105_Init(void)
{ {
uint8_t *A7105_Regs=0; uint8_t *A7105_Regs=0;
uint8_t vco_calibration0, vco_calibration1;
#ifdef BUGS_A7105_INO
if(protocol==PROTO_BUGS)
A7105_Regs=(uint8_t*)BUGS_A7105_regs;
else
#endif
#ifdef HUBSAN_A7105_INO #ifdef HUBSAN_A7105_INO
if(protocol==PROTO_HUBSAN) if(protocol==PROTO_HUBSAN)
{ {
@ -310,17 +348,19 @@ void A7105_Init(void)
A7105_WriteReg(A7105_0F_CHANNEL, 0); A7105_WriteReg(A7105_0F_CHANNEL, 0);
A7105_WriteReg(A7105_02_CALC,2); A7105_WriteReg(A7105_02_CALC,2);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
// A7105_ReadReg(A7105_25_VCO_SBCAL_I); vco_calibration0 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
//VCO Bank Calibrate channel A0 //VCO Bank Calibrate channel A0
A7105_WriteReg(A7105_0F_CHANNEL, 0xa0); A7105_WriteReg(A7105_0F_CHANNEL, 0xa0);
A7105_WriteReg(A7105_02_CALC, 2); A7105_WriteReg(A7105_02_CALC, 2);
while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end while(A7105_ReadReg(A7105_02_CALC)); // Wait for calibration to end
// A7105_ReadReg(A7105_25_VCO_SBCAL_I); vco_calibration1 = A7105_ReadReg(A7105_25_VCO_SBCAL_I);
//Reset VCO Band calibration if(protocol==PROTO_BUGS)
A7105_SetVCOBand(vco_calibration0 & 0x07, vco_calibration1 & 0x07); // Set calibration band value to best match
else
if(protocol!=PROTO_HUBSAN) if(protocol!=PROTO_HUBSAN)
A7105_WriteReg(A7105_25_VCO_SBCAL_I,protocol==PROTO_FLYSKY?0x08:0x0A); A7105_WriteReg(A7105_25_VCO_SBCAL_I,protocol==PROTO_FLYSKY?0x08:0x0A); //Reset VCO Band calibration
A7105_SetTxRxMode(TX_EN); A7105_SetTxRxMode(TX_EN);
A7105_SetPower(); A7105_SetPower();

View File

@ -86,6 +86,11 @@ enum{
static void AFHDS2A_update_telemetry() static void AFHDS2A_update_telemetry()
{ {
// Read TX RSSI
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less
if(temp<0) temp=0;
else if(temp>255) temp=255;
TX_RSSI=temp;
// AA | TXID | rx_id | sensor id | sensor # | value 16 bit big endian | sensor id ...... // AA | TXID | rx_id | sensor id | sensor # | value 16 bit big endian | sensor id ......
// max 7 sensors per packet // max 7 sensors per packet
#ifdef AFHDS2A_FW_TELEMETRY #ifdef AFHDS2A_FW_TELEMETRY
@ -169,6 +174,7 @@ static void AFHDS2A_build_bind_packet()
static void AFHDS2A_build_packet(uint8_t type) static void AFHDS2A_build_packet(uint8_t type)
{ {
uint16_t val;
memcpy( &packet[1], rx_tx_addr, 4); memcpy( &packet[1], rx_tx_addr, 4);
memcpy( &packet[5], rx_id, 4); memcpy( &packet[5], rx_id, 4);
switch(type) switch(type)
@ -181,6 +187,12 @@ static void AFHDS2A_build_packet(uint8_t type)
packet[9 + ch*2] = channelMicros&0xFF; packet[9 + ch*2] = channelMicros&0xFF;
packet[10 + ch*2] = (channelMicros>>8)&0xFF; packet[10 + ch*2] = (channelMicros>>8)&0xFF;
} }
#ifdef AFHDS2A_LQI_CH
// override channel with LQI
val = 2000 - 10*RX_LQI;
packet[9+((AFHDS2A_LQI_CH-1)*2)] = val & 0xff;
packet[10+((AFHDS2A_LQI_CH-1)*2)] = (val >> 8) & 0xff;
#endif
break; break;
case AFHDS2A_PACKET_FAILSAFE: case AFHDS2A_PACKET_FAILSAFE:
packet[0] = 0x56; packet[0] = 0x56;
@ -206,10 +218,10 @@ static void AFHDS2A_build_packet(uint8_t type)
packet[0] = 0xaa; packet[0] = 0xaa;
packet[9] = 0xfd; packet[9] = 0xfd;
packet[10]= 0xff; packet[10]= 0xff;
uint16_t val_hz=5*(option & 0x7f)+50; // option value should be between 0 and 70 which gives a value between 50 and 400Hz val=5*(option & 0x7f)+50; // option value should be between 0 and 70 which gives a value between 50 and 400Hz
if(val_hz<50 || val_hz>400) val_hz=50; // default is 50Hz if(val<50 || val>400) val=50; // default is 50Hz
packet[11]= val_hz; packet[11]= val;
packet[12]= val_hz >> 8; packet[12]= val >> 8;
if(sub_protocol == PPM_IBUS || sub_protocol == PPM_SBUS) if(sub_protocol == PPM_IBUS || sub_protocol == PPM_SBUS)
packet[13] = 0x01; // PPM output enabled packet[13] = 0x01; // PPM output enabled
else else
@ -324,17 +336,20 @@ uint16_t ReadAFHDS2A()
{ {
if(packet[9] == 0xfc) if(packet[9] == 0xfc)
packet_type=AFHDS2A_PACKET_SETTINGS; // RX is asking for settings packet_type=AFHDS2A_PACKET_SETTINGS; // RX is asking for settings
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
else else
{ {
// Read TX RSSI #ifdef AFHDS2A_LQI_CH
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less for(uint8_t sensor=0; sensor<7; sensor++)
if(temp<0) temp=0; {//read LQI value for RX output
else if(temp>255) temp=255; uint8_t index = 9+(4*sensor);
TX_RSSI=temp; if(packet[index]==AFHDS2A_SENSOR_RX_ERR_RATE)
AFHDS2A_update_telemetry(); RX_LQI=packet[index+2];
} }
#endif #endif
#if defined(AFHDS2A_FW_TELEMETRY) || defined(AFHDS2A_HUB_TELEMETRY)
AFHDS2A_update_telemetry();
#endif
}
} }
} }
packet_counter++; packet_counter++;

View File

@ -0,0 +1,365 @@
/*
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 MJX Bugs 3 Mini and Bugs 3H
#if defined(BUGSMINI_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define BUGSMINI_INITIAL_WAIT 500
#define BUGSMINI_PACKET_INTERVAL 6840
#define BUGSMINI_WRITE_WAIT 2000
#define BUGSMINI_TX_PAYLOAD_SIZE 24
#define BUGSMINI_RX_PAYLOAD_SIZE 16
#define BUGSMINI_NUM_RF_CHANNELS 15
#define BUGSMINI_ADDRESS_SIZE 5
static uint8_t BUGSMINI_txid[3];
static uint8_t BUGSMINI_txhash;
enum {
BUGSMINI_BIND1,
BUGSMINI_BIND2,
BUGSMINI_DATA1,
BUGSMINI_DATA2
};
#define BUGSMINI_CH_SW_ARM CH5_SW
#define BUGSMINI_CH_SW_ANGLE CH6_SW
#define BUGSMINI_CH_SW_FLIP CH7_SW
#define BUGSMINI_CH_SW_PICTURE CH8_SW
#define BUGSMINI_CH_SW_VIDEO CH9_SW
#define BUGSMINI_CH_SW_LED CH10_SW
// flags packet[12]
#define BUGSMINI_FLAG_FLIP 0x08 // automatic flip
#define BUGSMINI_FLAG_MODE 0x04 // low/high speed select (set is high speed)
#define BUGSMINI_FLAG_VIDEO 0x02 // toggle video
#define BUGSMINI_FLAG_PICTURE 0x01 // toggle picture
// flags packet[13]
#define BUGSMINI_FLAG_LED 0x80 // enable LEDs
#define BUGSMINI_FLAG_ARM 0x40 // arm (toggle to turn on motors)
#define BUGSMINI_FLAG_DISARM 0x20 // disarm (toggle to turn off motors)
#define BUGSMINI_FLAG_ANGLE 0x02 // angle/acro mode (set is angle mode)
static void __attribute__((unused)) BUGSMINI_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, BUGSMINI_RX_PAYLOAD_SIZE); // bytes of data payload for rx pipe 1
NRF24L01_WriteReg(NRF24L01_06_RF_SETUP, 0x07);
NRF24L01_SetBitrate(NRF24L01_BR_1M);
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00); // Set feature bits on
}
static void __attribute__((unused)) BUGSMINI_check_arming()
{
uint8_t arm_channel = BUGSMINI_CH_SW_ARM;
if (arm_channel != arm_channel_previous)
{
arm_channel_previous = arm_channel;
if (arm_channel)
{
armed = 1;
arm_flags ^= BUGSMINI_FLAG_ARM;
}
else
{
armed = 0;
arm_flags ^= BUGSMINI_FLAG_DISARM;
}
}
}
static void __attribute__((unused)) BUGSMINI_send_packet(uint8_t bind)
{
BUGSMINI_check_arming(); // sets globals arm_flags and armed
uint16_t aileron = convert_channel_16b_limit(AILERON,500,0);
uint16_t elevator = convert_channel_16b_limit(ELEVATOR,0,500);
uint16_t throttle = armed ? convert_channel_16b_limit(THROTTLE,0,500) : 0;
uint16_t rudder = convert_channel_16b_limit(RUDDER,500,0);
packet[1] = BUGSMINI_txid[0];
packet[2] = BUGSMINI_txid[1];
packet[3] = BUGSMINI_txid[2];
if(bind)
{
packet[4] = 0x00;
packet[5] = 0x7d;
packet[6] = 0x7d;
packet[7] = 0x7d;
packet[8] = 0x20;
packet[9] = 0x20;
packet[10]= 0x20;
packet[11]= 0x40;
packet[12]^= 0x40; // alternating freq hopping flag
packet[13]= 0x60;
packet[14]= 0x00;
packet[15]= 0x00;
}
else
{
packet[4] = throttle >> 1;
packet[5] = rudder >> 1;
packet[6] = elevator >> 1;
packet[7] = aileron >> 1;
packet[8] = 0x20 | (aileron << 7);
packet[9] = 0x20 | (elevator << 7);
packet[10]= 0x20 | (rudder << 7);
packet[11]= 0x40 | (throttle << 7);
packet[12]= 0x80 | (packet[12] ^ 0x40) // bugs 3 H doesn't have 0x80 ?
| BUGSMINI_FLAG_MODE
| GET_FLAG(BUGSMINI_CH_SW_PICTURE, BUGSMINI_FLAG_PICTURE)
| GET_FLAG(BUGSMINI_CH_SW_VIDEO, BUGSMINI_FLAG_VIDEO);
if(armed)
packet[12] |= GET_FLAG(BUGSMINI_CH_SW_FLIP, BUGSMINI_FLAG_FLIP);
packet[13] = arm_flags
| GET_FLAG(BUGSMINI_CH_SW_LED, BUGSMINI_FLAG_LED)
| GET_FLAG(BUGSMINI_CH_SW_ANGLE, BUGSMINI_FLAG_ANGLE);
packet[14] = 0;
packet[15] = 0; // 0x53 on bugs 3 H ?
}
uint8_t checksum = 0x6d;
for(uint8_t i=1; i < BUGSMINI_TX_PAYLOAD_SIZE; i++)
checksum ^= packet[i];
packet[0] = checksum;
if(!(packet[12]&0x40))
{
hopping_frequency_no++;
if(hopping_frequency_no >= BUGSMINI_NUM_RF_CHANNELS)
hopping_frequency_no = 0;
NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? hopping_frequency[hopping_frequency_no+BUGSMINI_NUM_RF_CHANNELS] : hopping_frequency[hopping_frequency_no]);
}
// Power on, TX mode, 2byte CRC
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, BUGSMINI_TX_PAYLOAD_SIZE);
NRF24L01_SetPower();
}
// compute final address for the rxid received during bind
// thanks to Pascal for the function!
const uint8_t PROGMEM BUGSMINI_end []= {
0x2d,0x9e ,0x95,0xa4 ,0x9c,0x5c ,0xb4,0xa6 ,0xa9,0xce ,0x56,0x2b ,0x3e,0x73 ,0xb8,0x95 ,0x6a,0x82,
0x94,0x37 ,0x3d,0x5a ,0x4b,0xb2 ,0x69,0x49 ,0xc2,0x24 ,0x6b,0x3d ,0x23,0xc6 ,0x9e,0xa3 ,0xa4,0x98,
0x5c,0x9e ,0xa6,0x52 ,0xce,0x76 ,0x2b,0x4b ,0x73,0x3a };
static void __attribute__((unused)) BUGSMINI_make_address()
{
uint8_t start, length, index;
//read rxid
uint8_t base_adr=BUGSMINI_EEPROM_OFFSET+RX_num*2;
uint8_t rxid_high = eeprom_read_byte((EE_ADDR)(base_adr+0));
uint8_t rxid_low = eeprom_read_byte((EE_ADDR)(base_adr+1));
if(rxid_high==0x00 || rxid_high==0xFF)
rx_tx_addr[0]=0x52;
else
rx_tx_addr[0]=rxid_high;
rx_tx_addr[1]=BUGSMINI_txhash;
if(rxid_low==0x00 || rxid_low==0xFF)
rx_tx_addr[2]=0x66;
else
rx_tx_addr[2]=rxid_low;
for(uint8_t end_idx=0;end_idx<23;end_idx++)
{
//calculate sequence start
if(end_idx<=7)
start=end_idx;
else
start=(end_idx-7)*16+7;
//calculate sequence length
if(end_idx>6)
{
if(end_idx>15)
length=(23-end_idx)<<1;
else
length=16;
}
else
length=(end_idx+1)<<1;
//calculate first index
index=start-rxid_high;
//scan for a possible match using the current end
for(uint8_t i=0;i<length;i++)
{
if(index==rxid_low)
{ //match found
rx_tx_addr[3]=pgm_read_byte_near( &BUGSMINI_end[end_idx<<1] );
rx_tx_addr[4]=pgm_read_byte_near( &BUGSMINI_end[(end_idx<<1)+1] );
return;
}
index+=i&1?7:8; //increment index
}
}
// Something wrong happened if we arrive here....
}
static void __attribute__((unused)) BUGSMINI_update_telemetry()
{
#if defined(BUGS_HUB_TELEMETRY)
uint8_t checksum = 0x6d;
for(uint8_t i=1; i<12; i++)
checksum += packet[i];
if(packet[0] == checksum)
{
RX_RSSI = packet[3];
if(packet[11] & 0x80)
v_lipo1 = 0xff; // Ok
else if(packet[11] & 0x40)
v_lipo1 = 0x80; // Warning
else
v_lipo1 = 0x00; // Critical
}
#endif
}
uint16_t BUGSMINI_callback()
{
uint8_t base_adr;
switch(phase)
{
case BUGSMINI_BIND1:
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
XN297_ReadPayload(packet, BUGSMINI_RX_PAYLOAD_SIZE);
base_adr=BUGSMINI_EEPROM_OFFSET+RX_num*2;
eeprom_write_byte((EE_ADDR)(base_adr+0),packet[1]); // Save rxid in EEPROM
eeprom_write_byte((EE_ADDR)(base_adr+1),packet[2]); // Save rxid in EEPROM
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
BUGSMINI_make_address();
XN297_SetTXAddr(rx_tx_addr, 5);
XN297_SetRXAddr(rx_tx_addr, 5);
phase = BUGSMINI_DATA1;
BIND_DONE;
return BUGSMINI_PACKET_INTERVAL;
}
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
BUGSMINI_send_packet(1);
phase = BUGSMINI_BIND2;
return BUGSMINI_WRITE_WAIT;
case BUGSMINI_BIND2:
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)
| _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
phase = BUGSMINI_BIND1;
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
case BUGSMINI_DATA1:
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready => read only 12 bytes to not overwrite channel change flag
XN297_ReadPayload(packet, 12);
BUGSMINI_update_telemetry();
}
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
BUGSMINI_send_packet(0);
phase = BUGSMINI_DATA2;
return BUGSMINI_WRITE_WAIT;
case BUGSMINI_DATA2:
// switch to RX mode
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_FlushRx();
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)
| _BV(NRF24L01_00_PWR_UP) | _BV(NRF24L01_00_PRIM_RX));
phase = BUGSMINI_DATA1;
return BUGSMINI_PACKET_INTERVAL - BUGSMINI_WRITE_WAIT;
}
return BUGSMINI_PACKET_INTERVAL;
}
#define BUGSMINI_NUM_TX_RF_MAPS 4
// haven't figured out BUGSMINI_txid<-->rf channel mapping yet
const uint8_t PROGMEM BUGSMINI_RF_chans[BUGSMINI_NUM_TX_RF_MAPS][BUGSMINI_NUM_RF_CHANNELS] = {
{0x22,0x2f,0x3a,0x14,0x20,0x2d,0x38,0x18,0x26,0x32,0x11,0x1d,0x29,0x35,0x17},
{0x3d,0x34,0x2b,0x22,0x19,0x40,0x37,0x2e,0x25,0x1c,0x3a,0x31,0x28,0x1f,0x16},
{0x12,0x20,0x2f,0x1a,0x28,0x38,0x14,0x23,0x32,0x1c,0x2c,0x3b,0x17,0x26,0x34},
{0x13,0x25,0x37,0x1F,0x31,0x17,0x28,0x3A,0x1C,0x2E,0x22,0x33,0x19,0x2B,0x3D} };
const uint8_t PROGMEM BUGSMINI_bind_chans[BUGSMINI_NUM_RF_CHANNELS] = {
0x1A,0x23,0x2C,0x35,0x3E,0x17,0x20,0x29,0x32,0x3B,0x14,0x1D,0x26,0x2F,0x38}; // bugs 3 mini bind channels
const uint8_t PROGMEM BUGSMINI_tx_id[BUGSMINI_NUM_TX_RF_MAPS][3] = {
{0xA8,0xE6,0x32},
{0xdd,0xab,0xfd},
{0x90,0x9e,0x4a},
{0x20,0x28,0xBA} };
const uint8_t PROGMEM BUGSMINI_tx_hash[BUGSMINI_NUM_TX_RF_MAPS] = { // 2nd byte of final address
0x6c,0x9e,0x3d,0xb3};
static void __attribute__((unused)) BUGSMINI_initialize_txid()
{
// load hopping_frequency with tx channels in low part and bind channels in high part
for(uint8_t i=0; i<BUGSMINI_NUM_RF_CHANNELS;i++)
{
hopping_frequency[i]=pgm_read_byte_near( &BUGSMINI_RF_chans[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS][i] );
hopping_frequency[i+BUGSMINI_NUM_RF_CHANNELS]=pgm_read_byte_near( &BUGSMINI_bind_chans[i] );
}
// load txid
for(uint8_t i=0; i<sizeof(BUGSMINI_txid);i++)
BUGSMINI_txid[i]=pgm_read_byte_near( &BUGSMINI_tx_id[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS][i] );
//load tx_hash
BUGSMINI_txhash = pgm_read_byte_near( &BUGSMINI_tx_hash[rx_tx_addr[3]%BUGSMINI_NUM_TX_RF_MAPS] );
}
uint16_t initBUGSMINI()
{
BUGSMINI_initialize_txid();
memset(packet, (uint8_t)0, BUGSMINI_TX_PAYLOAD_SIZE);
BUGSMINI_init();
if(IS_BIND_IN_PROGRESS)
{
XN297_SetTXAddr((const uint8_t*)"mjxRC", 5);
XN297_SetRXAddr((const uint8_t*)"mjxRC", 5);
phase = BUGSMINI_BIND1;
}
else
{
BUGSMINI_make_address();
XN297_SetTXAddr(rx_tx_addr, 5);
XN297_SetRXAddr(rx_tx_addr, 5);
phase = BUGSMINI_DATA1;
}
armed = 0;
arm_flags = BUGSMINI_FLAG_DISARM; // initial value from captures
arm_channel_previous = BUGSMINI_CH_SW_ARM;
#ifdef BUGS_HUB_TELEMETRY
init_frskyd_link_telemetry();
#endif
return BUGSMINI_INITIAL_WAIT;
}
#endif

View File

@ -38,7 +38,7 @@ enum BAYANG_FLAGS {
// flags going to packet[3] // flags going to packet[3]
BAYANG_FLAG_INVERTED = 0x80, // inverted flight on Floureon H101 BAYANG_FLAG_INVERTED = 0x80, // inverted flight on Floureon H101
BAYANG_FLAG_TAKE_OFF = 0x20, // take off / landing on X16 AH BAYANG_FLAG_TAKE_OFF = 0x20, // take off / landing on X16 AH
BAYANG_FLAG_EMG_STOP = 0x04, BAYANG_FLAG_EMG_STOP = 0x04|0x08, // 0x08 for VISUO XS809H-W-HD-G
}; };
enum BAYANG_OPTION_FLAGS { enum BAYANG_OPTION_FLAGS {

View File

@ -0,0 +1,467 @@
/*
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/>.
*/
#ifdef BUGS_A7105_INO
//////////// rxid -> radioid algorithm //////////////////////////////
// Hex digit 1 is periodic with length 2, and hex digit 2 is periodic
// with length 16. However, storing the byte of those 2 digits
// instead of manipulating bits results simpler code and smaller binary.
const uint8_t PROGMEM BUGS_most_popular_67_cycle[]= {
0x34, 0xc5, 0x6a, 0xb4, 0x29, 0xd5, 0x2c, 0xd3, 0x91, 0xb3, 0x6c, 0x49,
0x52, 0x9c, 0x4d, 0x65, 0xc3, 0x4a, 0x5b, 0xd6, 0x92, 0x6d, 0x94, 0xa6,
0x55, 0xcd, 0x2b, 0x9a, 0x36, 0x95, 0x4b, 0xd4, 0x35, 0x8d, 0x96, 0xb2,
0xa3 };
static uint8_t __attribute__((unused)) BUGS_most_popular_67(uint8_t i)
{
uint8_t ii;
if (i == 0)
return 0xd2;
else if (i == 1)
return 0xda;
else if (i % 16 < 2)
{
ii = 2 * (i / 16) + i % 16 - 2;
if (ii % 2 == 0)
ii += 7;
}
else
ii=2 * (i / 16) + (i % 16 - 2) % 7;
return pgm_read_byte_near( &BUGS_most_popular_67_cycle[ii]);
}
static uint8_t __attribute__((unused)) BUGS_most_popular_45(uint8_t i)
{
if (i == 0)
return 0xa3;
else if (i == 1)
return 0x86;
else
{
if (i % 8 == 1)
i -= 8;
else
i--;
return BUGS_most_popular_67(i);
}
}
static uint8_t __attribute__((unused)) BUGS_most_popular_23(uint8_t i)
{
if (i == 0)
return 0xb2;
else if (i == 1)
return 0xcb;
else
{
if (i % 8 == 1)
i -= 8;
else
i--;
return BUGS_most_popular_45(i);
}
}
const uint8_t PROGMEM BUGS_most_popular_01[] = {
0x52, 0xac, 0x59, 0xa4, 0x53, 0xab, 0x57, 0xa9,
0x56, 0xa5, 0x5b, 0xa7, 0x5d, 0xa6, 0x58, 0xad};
static uint32_t __attribute__((unused)) BUGS_most_popular(uint8_t i)
{
i += !(i <= 127);
uint8_t mp01=pgm_read_byte_near( &BUGS_most_popular_01[i % 16] );
return (uint32_t) mp01 << 24 |
(uint32_t) BUGS_most_popular_23(i) << 16 |
(uint32_t) BUGS_most_popular_45(i) << 8 |
BUGS_most_popular_67(i);
}
static uint32_t __attribute__((unused)) BUGS_second_most_popular(uint8_t i)
{
if (i < 127)
return BUGS_most_popular(i + 1);
else if (i > 128)
return BUGS_most_popular(i - 1);
else
return 0x52d6926d;
}
// The 22 irregular values do not match the above periodicities. They might be
// errors from the readout, but let us try them here as long as it is not
// proven.
#define BUGS_NBR_IRREGULAR 22
const uint16_t PROGMEM BUGS_irregular_keys[BUGS_NBR_IRREGULAR] = {
1131, 1287, 2842, 4668, 5311, 11594, 13122, 13813,
20655, 22975, 25007, 25068, 28252, 33309, 35364, 35765,
37731, 40296, 43668, 46540, 49868, 65535 };
const uint32_t PROGMEM BUGS_irregular_values[BUGS_NBR_IRREGULAR] = {
0x52d6926d, 0xa586da34, 0x5329d52c, 0xa66c4952,
0x536c4952, 0x524a5bd6, 0x534d65c3, 0xa9d391b3,
0x5249529c, 0xa555cd2b, 0xac9a3695, 0x58d391b3,
0xa791b36c, 0x53926d94, 0xa7926d94, 0xa72cd391,
0xa9b429d5, 0x5629d52c, 0xad2b9a36, 0xa74d65c3,
0x526d94a6, 0xad96b2a3 };
static uint32_t __attribute__((unused)) BUGS_is_irregular(uint16_t i)
{
for (uint8_t j = 0; j < BUGS_NBR_IRREGULAR; ++j)
if (pgm_read_word_near( &BUGS_irregular_keys[j]) == i)
return pgm_read_dword_near( &BUGS_irregular_values[j]);
return 0;
}
static uint32_t __attribute__((unused)) BUGS_rxid_to_radioid(uint16_t rxid)
{
uint8_t block = rxid / 256;
uint8_t second_seq_size;
bool use_most_popular;
if (rxid < 32768)
{
second_seq_size = 128 - block;
use_most_popular = rxid % 256 >= second_seq_size;
}
else
{
second_seq_size = block - 127;
use_most_popular = 255 - rxid % 256 >= second_seq_size;
}
uint32_t v = BUGS_is_irregular(rxid);
if (!v)
{
if (use_most_popular)
v = BUGS_most_popular(rxid % 255);
else
v = BUGS_second_most_popular(rxid % 255);
}
return v;
}
//////////// rxid -> radioid algorithm //////////////////////////////
// For code readability
#define BUGS_CH_SW_ARM CH5_SW
#define BUGS_CH_SW_ANGLE CH6_SW
#define BUGS_CH_SW_FLIP CH7_SW
#define BUGS_CH_SW_PICTURE CH8_SW
#define BUGS_CH_SW_VIDEO CH9_SW
#define BUGS_CH_SW_LED CH10_SW
// flags packet byte 4
#define BUGS_FLAG_FLIP 0x08 // automatic flip
#define BUGS_FLAG_MODE 0x04 // low/high speed select (set is high speed)
#define BUGS_FLAG_VIDEO 0x02 // toggle video
#define BUGS_FLAG_PICTURE 0x01 // toggle picture
// flags packet byte 5
#define BUGS_FLAG_LED 0x80 // enable LEDs
#define BUGS_FLAG_ARM 0x40 // arm (toggle to turn on motors)
#define BUGS_FLAG_DISARM 0x20 // disarm (toggle to turn off motors)
#define BUGS_FLAG_ANGLE 0x04 // angle/acro mode (set is angle mode)
#define BUGS_PACKET_SIZE 22
#define BUGS_NUM_RFCHAN 16
enum {
BUGS_BIND_1,
BUGS_BIND_2,
BUGS_BIND_3,
BUGS_DATA_1,
BUGS_DATA_2,
BUGS_DATA_3,
};
static void __attribute__((unused)) BUGS_check_arming()
{
uint8_t arm_channel = BUGS_CH_SW_ARM;
if (arm_channel != arm_channel_previous)
{
arm_channel_previous = arm_channel;
if (arm_channel)
{
armed = 1;
arm_flags ^= BUGS_FLAG_ARM;
}
else
{
armed = 0;
arm_flags ^= BUGS_FLAG_DISARM;
}
}
}
static void __attribute__((unused)) BUGS_build_packet(uint8_t bind)
{
uint8_t force_values = bind | !armed;
uint8_t change_channel = ((packet_count & 0x1) << 6);
uint16_t aileron = convert_channel_16b_limit(AILERON,800,0);
uint16_t elevator = convert_channel_16b_limit(ELEVATOR,800,0);
uint16_t throttle = convert_channel_16b_limit(THROTTLE,0,800);
uint16_t rudder = convert_channel_16b_limit(RUDDER,800,0);
memset(packet, 0, BUGS_PACKET_SIZE);
packet[1] = 0x76; // txid (rx uses to know hopping frequencies)
packet[2] = 0x71;
packet[3] = 0x94;
BUGS_check_arming(); // sets globals arm_flags and armed
if(bind)
{
packet[4] = change_channel | 0x80;
packet[5] = 0x02 | arm_flags
| GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE);
}
else
{
packet[4] = change_channel | BUGS_FLAG_MODE
| GET_FLAG(BUGS_CH_SW_FLIP, BUGS_FLAG_FLIP)
| GET_FLAG(BUGS_CH_SW_PICTURE, BUGS_FLAG_PICTURE)
| GET_FLAG(BUGS_CH_SW_VIDEO, BUGS_FLAG_VIDEO);
packet[5] = 0x02 | arm_flags
| GET_FLAG(BUGS_CH_SW_ANGLE, BUGS_FLAG_ANGLE)
| GET_FLAG(BUGS_CH_SW_LED, BUGS_FLAG_LED);
}
packet[6] = force_values ? 100 : (aileron >> 2);
packet[7] = force_values ? 100 : (elevator >> 2);
packet[8] = force_values ? 0 : (throttle >> 2);
packet[9] = force_values ? 100 : (rudder >> 2);
packet[10] = 100;
packet[11] = 100;
packet[12] = 100;
packet[13] = 100;
packet[14] = ((aileron << 6) & 0xc0)
| ((elevator << 4) & 0x30)
| ((throttle << 2) & 0x0c)
| ((rudder ) & 0x03);
// packet[15] = 0;
// driven trims
packet[16] = aileron / 8 + 14;
packet[17] = elevator / 8 + 14;
packet[18] = 64;
packet[19] = rudder / 8 + 14;
// packet[20] = 0;
// packet[21] = 0;
uint8_t check = 0x6d;
for (uint8_t i=1; i < BUGS_PACKET_SIZE; i++)
check ^= packet[i];
packet[0] = check;
}
const uint8_t PROGMEM BUGS_hop []= {
0x1d, 0x3b, 0x4d, 0x29, 0x11, 0x2d, 0x0b, 0x3d, 0x59, 0x48, 0x17, 0x41, 0x23, 0x4e, 0x2a, 0x63, // bind phase ID=0xac59a453
0x4b, 0x19, 0x35, 0x1e, 0x63, 0x0f, 0x45, 0x21, 0x51, 0x3a, 0x5d, 0x25, 0x0a, 0x44, 0x61, 0x27, // data phase ID=0xA4C56AB4 for txid 767194 if rx responds C6 BB 57 7F 00 00 00 00 00 00 FF 87 40 00 00 00
};
static void __attribute__((unused))BUGS_set_radio_data()
{ // captured radio data for bugs rx/tx version A2
// it appears that the hopping frequencies are determined by the txid
// and the data phase radio id is determined by the first 2 bytes of the
// rx bind packet
uint8_t offset=0;
uint32_t radio_id=0xac59a453; // bind phase ID=0xac59a453
if(IS_BIND_DONE)
{
offset=BUGS_NUM_RFCHAN;
// Read radio_id from EEPROM
radio_id=0;
uint8_t base_adr=BUGS_EEPROM_OFFSET+RX_num*4;
for(uint8_t i=0; i<4; i++)
radio_id|=eeprom_read_byte((EE_ADDR)(base_adr+i))<<(i*8);
}
A7105_WriteID(radio_id);
for(uint8_t i=0; i<BUGS_NUM_RFCHAN;i++)
hopping_frequency[i]=pgm_read_byte_near( &BUGS_hop[i+offset] );
}
static void __attribute__((unused)) BUGS_increment_counts()
{ // this logic works with the use of packet_count in BUGS_build_packet
// to properly indicate channel changes to rx
packet_count += 1;
if ((packet_count & 1) == 0)
{
hopping_frequency_no += 1;
hopping_frequency_no %= BUGS_NUM_RFCHAN;
}
}
#define BUGS_PACKET_PERIOD 6100
#define BUGS_DELAY_TX 2000
#define BUGS_DELAY_POST_RX 1500
#define BUGS_DELAY_BIND_RST 200
// FIFO config is one less than desired value
#define BUGS_FIFO_SIZE_RX 15
#define BUGS_FIFO_SIZE_TX 21
uint16_t ReadBUGS(void)
{
uint8_t mode, base_adr;
uint16_t rxid;
uint32_t radio_id;
uint16_t start;
// keep frequency tuning updated
#ifndef FORCE_FLYSKY_TUNING
A7105_AdjustLOBaseFreq(1);
#endif
switch(phase)
{
case BUGS_BIND_1:
BUGS_build_packet(1);
A7105_Strobe(A7105_STANDBY);
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX);
A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]);
phase = BUGS_BIND_2;
packet_period = BUGS_DELAY_TX;
break;
case BUGS_BIND_2:
//Wait for TX completion
start=micros();
while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
break;
A7105_SetTxRxMode(RX_EN);
A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no] - 2);
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_RX);
A7105_Strobe(A7105_RX);
BUGS_increment_counts();
phase = BUGS_BIND_3;
packet_period = BUGS_PACKET_PERIOD-BUGS_DELAY_TX-BUGS_DELAY_POST_RX;
break;
case BUGS_BIND_3:
mode = A7105_ReadReg(A7105_00_MODE);
A7105_Strobe(A7105_STANDBY);
A7105_SetTxRxMode(TX_EN);
if (mode & 0x01)
{
phase = BUGS_BIND_1;
packet_period = BUGS_DELAY_BIND_RST; // No received data so restart binding procedure.
break;
}
A7105_ReadData(16);
if ((packet[0] + packet[1] + packet[2] + packet[3]) == 0)
{
phase = BUGS_BIND_1;
packet_period = BUGS_DELAY_BIND_RST; // No received data so restart binding procedure.
break;
}
A7105_Strobe(A7105_STANDBY);
BIND_DONE;
// set radio_id
rxid = (packet[1] << 8) + packet[2];
radio_id = BUGS_rxid_to_radioid(rxid);
base_adr=BUGS_EEPROM_OFFSET+RX_num*4;
for(uint8_t i=0; i<4; i++)
eeprom_write_byte((EE_ADDR)(base_adr+i),radio_id>>(i*8)); // Save radio_id in EEPROM
BUGS_set_radio_data();
phase = BUGS_DATA_1;
packet_count = 0;
hopping_frequency_no = 0;
packet_period = BUGS_DELAY_POST_RX;
break;
case BUGS_DATA_1:
A7105_SetPower();
BUGS_build_packet(0);
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_TX);
A7105_WriteData(BUGS_PACKET_SIZE, hopping_frequency[hopping_frequency_no]);
phase = BUGS_DATA_2;
packet_period = BUGS_DELAY_TX;
break;
case BUGS_DATA_2:
//Wait for TX completion
start=micros();
while ((uint16_t)micros()-start < 500) // Wait max 500µs, using serial+telemetry exit in about 60µs
if(!(A7105_ReadReg(A7105_00_MODE) & 0x01))
break;
A7105_SetTxRxMode(RX_EN);
A7105_WriteReg(A7105_0F_PLL_I, hopping_frequency[hopping_frequency_no] - 2);
A7105_WriteReg(A7105_03_FIFOI, BUGS_FIFO_SIZE_RX);
A7105_Strobe(A7105_RX);
BUGS_increment_counts();
phase = BUGS_DATA_3;
packet_period = BUGS_PACKET_PERIOD-BUGS_DELAY_TX-BUGS_DELAY_POST_RX;
break;
case BUGS_DATA_3:
mode = A7105_ReadReg(A7105_00_MODE);
A7105_Strobe(A7105_STANDBY);
A7105_SetTxRxMode(TX_EN);
if (!(mode & 0x01))
{
A7105_ReadData(16);
#if defined(BUGS_HUB_TELEMETRY)
v_lipo1=packet[10] == 0xff ? 0xff : 0x00; // Voltage in this case is only an alert on level good or bad.
RX_RSSI=packet[3];
// Read TX RSSI
int16_t temp=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // Value from A7105 is between 8 for maximum signal strength to 160 or less
if(temp<0) temp=0;
else if(temp>255) temp=255;
TX_RSSI=temp;
telemetry_link=1;
#endif
}
phase = BUGS_DATA_1;
packet_period = BUGS_DELAY_POST_RX;
break;
}
return packet_period;
}
uint16_t initBUGS(void)
{
uint32_t radio_id=0;
uint8_t base_adr=BUGS_EEPROM_OFFSET+RX_num*4;
for(uint8_t i=0; i<4; i++)
radio_id|=eeprom_read_byte((EE_ADDR)(base_adr+i))<<(i*8);
if(radio_id==0xffffffff)
BIND_IN_PROGRESS;
BUGS_set_radio_data();
if (IS_BIND_IN_PROGRESS)
phase = BUGS_BIND_1;
else
phase = BUGS_DATA_1;
A7105_Init();
hopping_frequency_no = 0;
packet_count = 0;
armed = 0;
arm_flags = BUGS_FLAG_DISARM; // initial value from captures
arm_channel_previous = BUGS_CH_SW_ARM;
#ifdef BUGS_HUB_TELEMETRY
init_frskyd_link_telemetry();
#endif
return 10000;
}
#endif

View File

@ -259,6 +259,7 @@ static void __attribute__((unused)) CX10_initialize_txid()
uint16_t initCX10(void) uint16_t initCX10(void)
{ {
BIND_IN_PROGRESS; // autobind protocol
if(sub_protocol==CX10_BLUE) if(sub_protocol==CX10_BLUE)
{ {
packet_length = CX10A_PACKET_SIZE; packet_length = CX10A_PACKET_SIZE;
@ -282,7 +283,6 @@ uint16_t initCX10(void)
} }
CX10_initialize_txid(); CX10_initialize_txid();
CX10_init(); CX10_init();
BIND_IN_PROGRESS; // autobind protocol
return CX10_INITIAL_WAIT+packet_period; return CX10_INITIAL_WAIT+packet_period;
} }

View File

@ -44,7 +44,7 @@ enum {
uint8_t sop_col; uint8_t sop_col;
uint8_t DSM_num_ch=0; uint8_t DSM_num_ch=0;
uint8_t ch_map[14]; uint8_t ch_map[14];
const uint8_t PROGMEM ch_map_progmem[][14] = { const uint8_t PROGMEM DSM_ch_map_progmem[][14] = {
//22+11ms for 4..7 channels //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, 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, 0, 2, 3, 4, 0xff, 0xff, 1, 0, 2, 3, 4, 0xff, 0xff}, //5ch - Guess
@ -62,7 +62,7 @@ const uint8_t PROGMEM ch_map_progmem[][14] = {
{1, 5, 2, 3, 4, 8, 9, 1, 5, 2, 3, 0, 7, 6 }, //10ch - DX18 {1, 5, 2, 3, 4, 8, 9, 1, 5, 2, 3, 0, 7, 6 }, //10ch - DX18
}; };
const uint8_t PROGMEM pncodes[5][8][8] = { const uint8_t PROGMEM DSM_pncodes[5][8][8] = {
/* Note these are in order transmitted (LSB 1st) */ /* Note these are in order transmitted (LSB 1st) */
{ /* Row 0 */ { /* Row 0 */
/* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}, /* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8},
@ -123,18 +123,18 @@ const uint8_t PROGMEM pncodes[5][8][8] = {
}, },
}; };
static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len) static void __attribute__((unused)) DSM_read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len)
{ {
for(uint8_t i=0;i<len;i++) for(uint8_t i=0;i<len;i++)
buf[i]=pgm_read_byte_near( &pncodes[row][col][i] ); buf[i]=pgm_read_byte_near( &DSM_pncodes[row][col][i] );
} }
static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel) static uint8_t __attribute__((unused)) DSM_get_pn_row(uint8_t channel)
{ {
return ((sub_protocol == DSMX_11 || sub_protocol == DSMX_22 )? (channel - 2) % 5 : channel % 5); return ((sub_protocol == DSMX_11 || sub_protocol == DSMX_22 )? (channel - 2) % 5 : channel % 5);
} }
const uint8_t PROGMEM init_vals[][2] = { const uint8_t PROGMEM DSM_init_vals[][2] = {
{CYRF_02_TX_CTRL, 0x00}, // All TX interrupt disabled {CYRF_02_TX_CTRL, 0x00}, // All TX interrupt disabled
{CYRF_05_RX_CTRL, 0x00}, // All RX interrupt disabled {CYRF_05_RX_CTRL, 0x00}, // All RX interrupt disabled
{CYRF_28_CLK_EN, 0x02}, // Force receive clock enable {CYRF_28_CLK_EN, 0x02}, // Force receive clock enable
@ -154,7 +154,7 @@ const uint8_t PROGMEM init_vals[][2] = {
{CYRF_1E_RX_OVERRIDE, 0x14}, // Disable RX CRC, Force receive data rate, use RX synthesizer {CYRF_1E_RX_OVERRIDE, 0x14}, // Disable RX CRC, Force receive data rate, use RX synthesizer
}; };
const uint8_t PROGMEM data_vals[][2] = { const uint8_t PROGMEM DSM_data_vals[][2] = {
{CYRF_29_RX_ABORT, 0x20}, // Abort RX operation in case we are coming from bind {CYRF_29_RX_ABORT, 0x20}, // Abort RX operation in case we are coming from bind
{CYRF_0F_XACT_CFG, 0x24}, // Force Idle {CYRF_0F_XACT_CFG, 0x24}, // Force Idle
{CYRF_29_RX_ABORT, 0x00}, // Clear abort RX {CYRF_29_RX_ABORT, 0x00}, // Clear abort RX
@ -166,8 +166,8 @@ const uint8_t PROGMEM data_vals[][2] = {
static void __attribute__((unused)) DSM_cyrf_config() static void __attribute__((unused)) DSM_cyrf_config()
{ {
for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++) for(uint8_t i = 0; i < sizeof(DSM_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&init_vals[i][0]), pgm_read_byte_near(&init_vals[i][1])); CYRF_WriteRegister(pgm_read_byte_near(&DSM_init_vals[i][0]), pgm_read_byte_near(&DSM_init_vals[i][1]));
CYRF_WritePreamble(0x333304); CYRF_WritePreamble(0x333304);
CYRF_ConfigRFChannel(0x61); CYRF_ConfigRFChannel(0x61);
} }
@ -221,8 +221,8 @@ static void __attribute__((unused)) DSM_initialize_bind_phase()
static void __attribute__((unused)) DSM_cyrf_configdata() static void __attribute__((unused)) DSM_cyrf_configdata()
{ {
for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++) for(uint8_t i = 0; i < sizeof(DSM_data_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&data_vals[i][0]), pgm_read_byte_near(&data_vals[i][1])); CYRF_WriteRegister(pgm_read_byte_near(&DSM_data_vals[i][0]), pgm_read_byte_near(&DSM_data_vals[i][1]));
} }
static void __attribute__((unused)) DSM_update_channels() static void __attribute__((unused)) DSM_update_channels()
@ -240,7 +240,7 @@ static void __attribute__((unused)) DSM_update_channels()
if(DSM_num_ch>7 && DSM_num_ch<11 && (sub_protocol==DSM2_11 || sub_protocol==DSMX_11)) if(DSM_num_ch>7 && DSM_num_ch<11 && (sub_protocol==DSM2_11 || sub_protocol==DSMX_11))
idx+=5; // In 11ms mode change index only for channels 8..10 idx+=5; // In 11ms mode change index only for channels 8..10
for(uint8_t i=0;i<14;i++) for(uint8_t i=0;i<14;i++)
ch_map[i]=pgm_read_byte_near(&ch_map_progmem[idx][i]); ch_map[i]=pgm_read_byte_near(&DSM_ch_map_progmem[idx][i]);
} }
static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper) static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
@ -262,7 +262,9 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
if(sub_protocol==DSM2_22) if(sub_protocol==DSM2_22)
bits=10; // Only DSM_22 is using a resolution of 1024 bits=10; // Only DSM_22 is using a resolution of 1024
} }
#ifdef DSM_THROTTLE_KILL_CH
uint16_t kill_ch=Channel_data[DSM_THROTTLE_KILL_CH-1];
#endif
for (uint8_t i = 0; i < 7; i++) for (uint8_t i = 0; i < 7; i++)
{ {
uint8_t idx = ch_map[(upper?7:0) + i];//1,5,2,3,0,4 uint8_t idx = ch_map[(upper?7:0) + i];//1,5,2,3,0,4
@ -271,6 +273,17 @@ static void __attribute__((unused)) DSM_build_data_packet(uint8_t upper)
{ {
/* Spektrum own remotes transmit normal values during bind and actually use this (e.g. Nano CP X) to /* 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 */ select the transmitter mode (e.g. computer vs non-computer radio), so always send normal output */
#ifdef DSM_THROTTLE_KILL_CH
if(CH_TAER[idx]==THROTTLE && kill_ch<=604)
{//Activate throttle kill only if DSM_THROTTLE_KILL_CH below -50%
if(kill_ch<CHANNEL_MIN_100) // restrict val to 0...400
kill_ch=0;
else
kill_ch-=CHANNEL_MIN_100;
value=(kill_ch*21)/25; // kill channel -100%->904us ... -50%->1100us *0x150/400
}
else
#endif
#ifdef DSM_MAX_THROW #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 value=Channel_data[CH_TAER[idx]]; // -100%..+100% => 1024..1976us and -125%..+125% => 904..2096us based on Redcon 6 channel DSM2 RX
#else #else
@ -294,12 +307,12 @@ static void __attribute__((unused)) DSM_set_sop_data_crc()
else else
CYRF_ConfigCRCSeed(~crc); //CH1 CYRF_ConfigCRCSeed(~crc); //CH1
uint8_t pn_row = get_pn_row(hopping_frequency[hopping_frequency_no]); uint8_t pn_row = DSM_get_pn_row(hopping_frequency[hopping_frequency_no]);
uint8_t code[16]; uint8_t code[16];
read_code(code,pn_row,sop_col,8); // pn_row between 0 and 4, sop_col between 1 and 7 DSM_read_code(code,pn_row,sop_col,8); // pn_row between 0 and 4, sop_col between 1 and 7
CYRF_ConfigSOPCode(code); CYRF_ConfigSOPCode(code);
read_code(code,pn_row,7 - sop_col,8); // 7-sop_col between 0 and 6 DSM_read_code(code,pn_row,7 - sop_col,8); // 7-sop_col between 0 and 6
read_code(code+8,pn_row,7 - sop_col + 1,8); // 7-sop_col+1 between 1 and 7 DSM_read_code(code+8,pn_row,7 - sop_col + 1,8); // 7-sop_col+1 between 1 and 7
CYRF_ConfigDataCode(code, 16); CYRF_ConfigDataCode(code, 16);
CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]); CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]);
@ -536,7 +549,7 @@ uint16_t initDsm()
cyrfmfg_id[3]^=RX_num; cyrfmfg_id[3]^=RX_num;
//Calc sop_col //Calc sop_col
sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07; sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;
//Fix for OrangeRX using wrong pncodes by preventing access to "Col 8" //Fix for OrangeRX using wrong DSM_pncodes by preventing access to "Col 8"
if(sop_col==0) if(sop_col==0)
{ {
cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0 cyrfmfg_id[rx_tx_addr[0]%3]^=0x01; //Change a bit so sop_col will be different from 0

View File

@ -0,0 +1,244 @@
/*
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 E012 and E015
#if defined(E01X_NRF24L01_INO)
#include "iface_nrf24l01.h"
//Protocols constants
#define E01X_BIND_COUNT 500
#define E01X_INITIAL_WAIT 500
#define E01X_ADDRESS_LENGTH 5
#define E012_PACKET_PERIOD 4525
#define E012_RF_BIND_CHANNEL 0x3c
#define E012_NUM_RF_CHANNELS 4
#define E012_PACKET_SIZE 15
#define E015_PACKET_PERIOD 4500 // stock Tx=9000, but let's send more packets ...
#define E015_RF_CHANNEL 0x2d // 2445 MHz
#define E015_PACKET_SIZE 10
#define E015_BIND_PACKET_SIZE 9
//Channels
#define E01X_ARM_SW CH5_SW
#define E01X_FLIP_SW CH6_SW
#define E01X_LED_SW CH7_SW
#define E01X_HEADLESS_SW CH8_SW
#define E01X_RTH_SW CH9_SW
// E012 flags packet[1]
#define E012_FLAG_FLIP 0x40
#define E012_FLAG_HEADLESS 0x10
#define E012_FLAG_RTH 0x04
// E012 flags packet[7]
#define E012_FLAG_EXPERT 0x02
// E015 flags packet[6]
#define E015_FLAG_DISARM 0x80
#define E015_FLAG_ARM 0x40
// E015 flags packet[7]
#define E015_FLAG_FLIP 0x80
#define E015_FLAG_HEADLESS 0x10
#define E015_FLAG_RTH 0x08
#define E015_FLAG_LED 0x04
#define E015_FLAG_EXPERT 0x02
#define E015_FLAG_INTERMEDIATE 0x01
static void __attribute__((unused)) E015_check_arming()
{
uint8_t arm_channel = E01X_ARM_SW;
if (arm_channel != arm_channel_previous)
{
arm_channel_previous = arm_channel;
if (arm_channel)
{
armed = 1;
arm_flags ^= E015_FLAG_ARM;
}
else
{
armed = 0;
arm_flags ^= E015_FLAG_DISARM;
}
}
}
static void __attribute__((unused)) E01X_send_packet(uint8_t bind)
{
if(sub_protocol==E012)
{
packet_length=E012_PACKET_SIZE;
packet[0] = rx_tx_addr[1];
if(bind)
{
packet[1] = 0xaa;
memcpy(&packet[2], hopping_frequency, E012_NUM_RF_CHANNELS);
memcpy(&packet[6], rx_tx_addr, E01X_ADDRESS_LENGTH);
rf_ch_num=E012_RF_BIND_CHANNEL;
}
else
{
packet[1] = 0x01
| GET_FLAG(E01X_RTH_SW, E012_FLAG_RTH)
| GET_FLAG(E01X_HEADLESS_SW, E012_FLAG_HEADLESS)
| GET_FLAG(E01X_FLIP_SW, E012_FLAG_FLIP);
packet[2] = convert_channel_16b_limit(AILERON, 0xc8, 0x00); // aileron
packet[3] = convert_channel_16b_limit(ELEVATOR, 0x00, 0xc8); // elevator
packet[4] = convert_channel_16b_limit(RUDDER, 0xc8, 0x00); // rudder
packet[5] = convert_channel_16b_limit(THROTTLE, 0x00, 0xc8); // throttle
packet[6] = 0xaa;
packet[7] = E012_FLAG_EXPERT; // rate (0-2)
packet[8] = 0x00;
packet[9] = 0x00;
packet[10]= 0x00;
rf_ch_num=hopping_frequency[hopping_frequency_no++];
hopping_frequency_no %= E012_NUM_RF_CHANNELS;
}
packet[11] = 0x00;
packet[12] = 0x00;
packet[13] = 0x56;
packet[14] = rx_tx_addr[2];
}
else
{ // E015
if(bind)
{
packet[0] = 0x18;
packet[1] = 0x04;
packet[2] = 0x06;
// data phase address
memcpy(&packet[3], rx_tx_addr, E01X_ADDRESS_LENGTH);
// checksum
packet[8] = packet[3];
for(uint8_t i=4; i<8; i++)
packet[8] += packet[i];
packet_length=E015_BIND_PACKET_SIZE;
}
else
{
E015_check_arming();
packet[0] = convert_channel_16b_limit(THROTTLE, 0, 225); // throttle
packet[1] = convert_channel_16b_limit(RUDDER, 225, 0); // rudder
packet[2] = convert_channel_16b_limit(AILERON, 0, 225); // aileron
packet[3] = convert_channel_16b_limit(ELEVATOR, 225, 0); // elevator
packet[4] = 0x20; // elevator trim
packet[5] = 0x20; // aileron trim
packet[6] = arm_flags;
packet[7] = E015_FLAG_EXPERT
| GET_FLAG(E01X_FLIP_SW, E015_FLAG_FLIP)
| GET_FLAG(E01X_LED_SW, E015_FLAG_LED)
| GET_FLAG(E01X_HEADLESS_SW,E015_FLAG_HEADLESS)
| GET_FLAG(E01X_RTH_SW, E015_FLAG_RTH);
packet[8] = 0;
// checksum
packet[9] = packet[0];
for(uint8_t i=1; i<9; i++)
packet[9] += packet[i];
packet_length=E015_PACKET_SIZE;
}
}
// Power on, TX mode, CRC enabled
HS6200_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch_num);
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
HS6200_WritePayload(packet, packet_length);
// Check and adjust transmission power. We do this after
// transmission to not bother with timeout after power
// settings change - we have plenty of time until next
// packet.
NRF24L01_SetPower();
}
static void __attribute__((unused)) E01X_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
if(sub_protocol==E012)
HS6200_SetTXAddr((uint8_t *)"\x55\x42\x9C\x8F\xC9", E01X_ADDRESS_LENGTH);
else // E015
HS6200_SetTXAddr((uint8_t *)"\x62\x54\x79\x38\x53", E01X_ADDRESS_LENGTH);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03);
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1 Mbps
NRF24L01_SetPower();
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01); // Set feature bits on
NRF24L01_Activate(0x73);
}
uint16_t E01X_callback()
{
if(IS_BIND_IN_PROGRESS)
{
if (bind_counter == 0)
{
HS6200_SetTXAddr(rx_tx_addr, 5);
BIND_DONE;
}
else
{
E01X_send_packet(1);
bind_counter--;
}
}
else
E01X_send_packet(0);
return packet_period;
}
static void __attribute__((unused)) E012_initialize_txid()
{
// rf channels
uint32_t lfsr=random(0xfefefefe);
for(uint8_t i=0; i<E012_NUM_RF_CHANNELS; i++)
hopping_frequency[i] = 0x10 + (((lfsr >> (i*8)) & 0xff) % 0x32);
}
uint16_t initE01X()
{
BIND_IN_PROGRESS;
if(sub_protocol==E012)
{
E012_initialize_txid();
packet_period=E012_PACKET_PERIOD;
}
else
{ // E015
packet_period=E015_PACKET_PERIOD;
rf_ch_num=E015_RF_CHANNEL;
armed = 0;
arm_flags = 0;
arm_channel_previous = E01X_ARM_SW;
}
E01X_init();
bind_counter = E01X_BIND_COUNT;
hopping_frequency_no = 0;
return E01X_INITIAL_WAIT;
}
#endif

View File

@ -30,7 +30,7 @@ static void __attribute__((unused)) ESKY_set_data_address()
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4); NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4);
} }
static void __attribute__((unused)) ESKY_init(uint8_t bind) static void __attribute__((unused)) ESKY_init()
{ {
NRF24L01_Initialize(); NRF24L01_Initialize();
@ -38,7 +38,7 @@ static void __attribute__((unused)) ESKY_init(uint8_t bind)
NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO)); NRF24L01_WriteReg(NRF24L01_00_CONFIG, _BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0
if (bind) if (IS_BIND_IN_PROGRESS)
{ {
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3-byte RX/TX address for bind packets NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3-byte RX/TX address for bind packets
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x00\x00\x00", 3); NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x00\x00\x00", 3);
@ -63,7 +63,6 @@ static void __attribute__((unused)) ESKY_init(uint8_t bind)
static void __attribute__((unused)) ESKY_init2() static void __attribute__((unused)) ESKY_init2()
{ {
NRF24L01_FlushTx(); NRF24L01_FlushTx();
packet_sent = 0;
hopping_frequency_no = 0; hopping_frequency_no = 0;
uint16_t channel_ord = rx_tx_addr[0] % 74; uint16_t channel_ord = rx_tx_addr[0] % 74;
hopping_frequency[12] = 10 + (uint8_t)channel_ord; //channel_code hopping_frequency[12] = 10 + (uint8_t)channel_ord; //channel_code
@ -116,14 +115,12 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind)
// Each data packet is repeated 3 times on one channel, and 3 times on another channel // Each data packet is repeated 3 times on one channel, and 3 times on another channel
// For arithmetic simplicity, channels are repeated in rf_channels array // For arithmetic simplicity, channels are repeated in rf_channels array
if (hopping_frequency_no == 0) if (hopping_frequency_no == 0)
{
for (uint8_t i = 0; i < 6; i++) for (uint8_t i = 0; i < 6; i++)
{ {
uint16_t val=convert_channel_ppm(CH_AETR[i]); uint16_t val=convert_channel_ppm(CH_AETR[i]);
packet[i*2] = val>>8; //high byte of servo timing(1000-2000us) packet[i*2] = val>>8; //high byte of servo timing(1000-2000us)
packet[i*2+1] = val&0xFF; //low byte of servo timing(1000-2000us) packet[i*2+1] = val&0xFF; //low byte of servo timing(1000-2000us)
} }
}
rf_ch = hopping_frequency[hopping_frequency_no]; rf_ch = hopping_frequency[hopping_frequency_no];
packet[12] = hopping_frequency[hopping_frequency_no+6]; // end_bytes packet[12] = hopping_frequency[hopping_frequency_no+6]; // end_bytes
hopping_frequency_no++; hopping_frequency_no++;
@ -132,23 +129,15 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind)
NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch); NRF24L01_WriteReg(NRF24L01_05_RF_CH, rf_ch);
NRF24L01_FlushTx(); NRF24L01_FlushTx();
NRF24L01_WritePayload(packet, ESKY_PAYLOAD_SIZE); NRF24L01_WritePayload(packet, ESKY_PAYLOAD_SIZE);
packet_sent = 1;
if (! rf_ch_num)
NRF24L01_SetPower(); //Keep transmit power updated NRF24L01_SetPower(); //Keep transmit power updated
} }
uint16_t ESKY_callback() uint16_t ESKY_callback()
{ {
if(IS_BIND_DONE) if(IS_BIND_DONE)
{
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
return ESKY_PACKET_CHKTIME;
ESKY_send_packet(0); ESKY_send_packet(0);
}
else else
{ {
if (packet_sent && NRF24L01_packet_ack() != PKT_ACKED)
return ESKY_PACKET_CHKTIME;
ESKY_send_packet(1); ESKY_send_packet(1);
if (--bind_counter == 0) if (--bind_counter == 0)
{ {
@ -162,8 +151,9 @@ uint16_t ESKY_callback()
uint16_t initESKY(void) uint16_t initESKY(void)
{ {
bind_counter = ESKY_BIND_COUNT; bind_counter = ESKY_BIND_COUNT;
rx_tx_addr[2] = rx_tx_addr[3]; // Model match
rx_tx_addr[3] = 0xBB; rx_tx_addr[3] = 0xBB;
ESKY_init(IS_BIND_IN_PROGRESS); ESKY_init();
ESKY_init2(); ESKY_init2();
return 50000; return 50000;
} }

View File

@ -0,0 +1,116 @@
/*
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 GD005 C-17 and GD006 DA62 planes.
#if defined(GD00X_NRF24L01_INO)
#include "iface_nrf24l01.h"
//#define FORCE_GD00X_ORIGINAL_ID
#define GD00X_INITIAL_WAIT 500
#define GD00X_PACKET_PERIOD 3500
#define GD00X_RF_BIND_CHANNEL 2
#define GD00X_PAYLOAD_SIZE 15
#define GD00X_BIND_COUNT 857 //3sec
// flags going to packet[11]
#define GD00X_FLAG_DR 0x08
#define GD00X_FLAG_LIGHT 0x04
static void __attribute__((unused)) GD00X_send_packet()
{
packet[0] = IS_BIND_IN_PROGRESS?0xAA:0x55;
memcpy(packet+1,rx_tx_addr,4);
uint16_t channel=convert_channel_ppm(AILERON);
packet[5 ] = channel;
packet[6 ] = channel>>8;
channel=convert_channel_ppm(THROTTLE);
packet[7 ] = channel;
packet[8 ] = channel>>8;
channel=convert_channel_ppm(CH5); // TRIM
packet[9 ] = channel;
packet[10] = channel>>8;
packet[11] = GD00X_FLAG_DR // Force high rate
| GET_FLAG(CH6_SW, GD00X_FLAG_LIGHT);
packet[12] = 0x00;
packet[13] = 0x00;
packet[14] = 0x00;
// Power on, TX mode, CRC enabled
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
if(IS_BIND_DONE)
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
hopping_frequency_no &= 3; // 4 RF channels
}
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, GD00X_PAYLOAD_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) GD00X_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_SetTXAddr((uint8_t*)"\xcc\xcc\xcc\xcc\xcc", 5);
NRF24L01_WriteReg(NRF24L01_05_RF_CH, GD00X_RF_BIND_CHANNEL); // Bind channel
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
NRF24L01_SetPower();
}
static void __attribute__((unused)) GD00X_initialize_txid()
{
uint8_t start=76+(rx_tx_addr[0]&0x03);
for(uint8_t i=0; i<4;i++)
hopping_frequency[i]=start-(i<<1);
#ifdef FORCE_GD00X_ORIGINAL_ID
rx_tx_addr[0]=0x1F; // or 0xA5 or 0x26
rx_tx_addr[1]=0x39; // or 0x37 or 0x35
rx_tx_addr[2]=0x12; // Constant on 3 TXs
rx_tx_addr[3]=0x13; // Constant on 3 TXs
for(uint8_t i=0; i<4;i++)
hopping_frequency[i]=79-(i<<1); // or 77 or 78
#endif
}
uint16_t GD00X_callback()
{
if(IS_BIND_IN_PROGRESS)
if(--bind_counter==0)
BIND_DONE;
GD00X_send_packet();
return GD00X_PACKET_PERIOD;
}
uint16_t initGD00X()
{
BIND_IN_PROGRESS; // autobind protocol
GD00X_initialize_txid();
GD00X_init();
hopping_frequency_no = 0;
bind_counter=GD00X_BIND_COUNT;
return GD00X_INITIAL_WAIT;
}
#endif

View File

@ -32,7 +32,7 @@ enum {
GW008_DATA GW008_DATA
}; };
static void __attribute__((unused)) send_packet(uint8_t bind) static void __attribute__((unused)) GW008_send_packet(uint8_t bind)
{ {
packet[0] = rx_tx_addr[0]; packet[0] = rx_tx_addr[0];
if(bind) if(bind)
@ -123,7 +123,7 @@ uint16_t GW008_callback()
{ {
NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN); NRF24L01_SetTxRxMode(TX_EN);
send_packet(1); GW008_send_packet(1);
phase = GW008_BIND2; phase = GW008_BIND2;
return 300; return 300;
} }
@ -139,7 +139,7 @@ uint16_t GW008_callback()
return 5000; return 5000;
break; break;
case GW008_DATA: case GW008_DATA:
send_packet(0); GW008_send_packet(0);
break; break;
} }
return GW008_PACKET_PERIOD; return GW008_PACKET_PERIOD;

View File

@ -49,11 +49,18 @@ enum{
// flags going to packet[9] (H501S) // flags going to packet[9] (H501S)
FLAG_H501_VIDEO = 0x01, FLAG_H501_VIDEO = 0x01,
FLAG_H501_LED = 0x04, FLAG_H501_LED = 0x04,
FLAG_H122D_FLIP = 0x08, //H122D
FLAG_H501_RTH = 0x20, FLAG_H501_RTH = 0x20,
FLAG_H501_HEADLESS1 = 0x40, FLAG_H501_HEADLESS1 = 0x40,
FLAG_H501_GPS_HOLD = 0x80, FLAG_H501_GPS_HOLD = 0x80,
}; };
enum{
// flags going to packet[11] (H122D & H123D)
FLAG_H123D_FMODES = 0x03, //H123D 3 FMODES: Sport mode 1, Sport mode 2, Acro
FLAG_H122D_OSD = 0x20, //H122D OSD
};
enum{ enum{
// flags going to packet[13] (H501S) // flags going to packet[13] (H501S)
FLAG_H501_SNAPSHOT = 0x01, FLAG_H501_SNAPSHOT = 0x01,
@ -203,12 +210,25 @@ static void __attribute__((unused)) hubsan_build_packet()
packet[9] = 0x02 packet[9] = 0x02
| GET_FLAG(CH6_SW, FLAG_H501_LED) | GET_FLAG(CH6_SW, FLAG_H501_LED)
| GET_FLAG(CH8_SW, FLAG_H501_VIDEO) | GET_FLAG(CH8_SW, FLAG_H501_VIDEO)
| GET_FLAG(CH12_SW, FLAG_H122D_FLIP) // H122D specific -> flip
| GET_FLAG(CH5_SW, FLAG_H501_RTH) | GET_FLAG(CH5_SW, FLAG_H501_RTH)
| GET_FLAG(CH11_SW, FLAG_H501_GPS_HOLD) | GET_FLAG(CH10_SW, FLAG_H501_GPS_HOLD)
| GET_FLAG(CH9_SW, FLAG_H501_HEADLESS1); | GET_FLAG(CH9_SW, FLAG_H501_HEADLESS1);
//packet[10]= 0x1A; //packet[10]= 0x1A;
packet[13] = GET_FLAG(CH10_SW, FLAG_H501_HEADLESS2)
| GET_FLAG(CH12_SW, FLAG_H501_ALT_HOLD) //packet[11] content 0x00 is default
//H123D specific -> Flight modes
packet[11] = 0x41; // Sport mode 1
if(Channel_data[CH13]>CHANNEL_MAX_COMMAND)
packet[11]=0x43; // Acro
else if(Channel_data[CH13]>CHANNEL_MIN_COMMAND)
packet[11]=0x42; // Sport mode 2
//H122D specific -> OSD but useless...
//packet[11]|= 0x80
// | GET_FLAG(CHXX_SW,FLAG_H122D_OSD);
packet[13] = GET_FLAG(CH9_SW, FLAG_H501_HEADLESS2)
| GET_FLAG(CH11_SW, FLAG_H501_ALT_HOLD)
| GET_FLAG(CH7_SW, FLAG_H501_SNAPSHOT); | GET_FLAG(CH7_SW, FLAG_H501_SNAPSHOT);
} }
else else

View File

@ -8,7 +8,7 @@
8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI 8,YD717,YD717,SKYWLKR,SYMAX4,XINXUN,NIHUI
9,KN,WLTOYS,FEILUN 9,KN,WLTOYS,FEILUN
10,SymaX,SYMAX,SYMAX5C 10,SymaX,SYMAX,SYMAX5C
11,SLT,SLT,VISTA 11,SLT,SLT_V1,SLT_V2,Q100,Q200,MR100
12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041 12,CX10,GREEN,BLUE,DM007,---,J3015_1,J3015_2,MK33041
13,CG023,CG023,YD829 13,CG023,CG023,YD829
14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE 14,Bayang,Bayang,H8S3D,X16_AH,IRDRONE
@ -38,3 +38,11 @@
38,CFlie 38,CFlie
39,Hitec,OPT_FW,OPT_HUB,MINIMA 39,Hitec,OPT_FW,OPT_HUB,MINIMA
40,WFLY 40,WFLY
41,BUGS
42,BUGSMINI
43,Traxxas
44,NCC1701
45,E01X,E012,E015
46,V911S
47,GD00X
63,Test

View File

@ -18,8 +18,8 @@
//****************** //******************
#define VERSION_MAJOR 1 #define VERSION_MAJOR 1
#define VERSION_MINOR 2 #define VERSION_MINOR 2
#define VERSION_REVISION 0 #define VERSION_REVISION 1
#define VERSION_PATCH_LEVEL 32 #define VERSION_PATCH_LEVEL 23
//****************** //******************
// Protocols // Protocols
@ -67,6 +67,14 @@ enum PROTOCOLS
PROTO_CFLIE = 38, // =>NRF24L01 PROTO_CFLIE = 38, // =>NRF24L01
PROTO_HITEC = 39, // =>CC2500 PROTO_HITEC = 39, // =>CC2500
PROTO_WFLY = 40, // =>CYRF6936 PROTO_WFLY = 40, // =>CYRF6936
PROTO_BUGS = 41, // =>A7105
PROTO_BUGSMINI = 42, // =>NRF24L01
PROTO_TRAXXAS = 43, // =>CYRF6936
PROTO_NCC1701 = 44, // =>NRF24L01
PROTO_E01X = 45, // =>NRF24L01
PROTO_V911S = 46, // =>NRF24L01
PROTO_GD00X = 47, // =>NRF24L01
PROTO_TEST = 63, // =>NRF24L01
}; };
enum Flysky enum Flysky
@ -75,7 +83,7 @@ enum Flysky
V9X9 = 1, V9X9 = 1,
V6X6 = 2, V6X6 = 2,
V912 = 3, V912 = 3,
CX20 = 4 CX20 = 4,
}; };
enum Hubsan enum Hubsan
{ {
@ -93,7 +101,7 @@ enum AFHDS2A
enum Hisky enum Hisky
{ {
Hisky = 0, Hisky = 0,
HK310 = 1 HK310 = 1,
}; };
enum DSM enum DSM
{ {
@ -101,7 +109,7 @@ enum DSM
DSM2_11 = 1, DSM2_11 = 1,
DSMX_22 = 2, DSMX_22 = 2,
DSMX_11 = 3, DSMX_11 = 3,
DSM_AUTO = 4 DSM_AUTO = 4,
}; };
enum YD717 enum YD717
{ {
@ -109,22 +117,25 @@ enum YD717
SKYWLKR = 1, SKYWLKR = 1,
SYMAX4 = 2, SYMAX4 = 2,
XINXUN = 3, XINXUN = 3,
NIHUI = 4 NIHUI = 4,
}; };
enum KN enum KN
{ {
WLTOYS = 0, WLTOYS = 0,
FEILUN = 1 FEILUN = 1,
}; };
enum SYMAX enum SYMAX
{ {
SYMAX = 0, SYMAX = 0,
SYMAX5C = 1 SYMAX5C = 1,
}; };
enum SLT enum SLT
{ {
SLT = 0, SLT_V1 = 0,
VISTA = 1 SLT_V2 = 1,
Q100 = 2,
Q200 = 3,
MR100 = 4,
}; };
enum CX10 enum CX10
{ {
@ -162,7 +173,7 @@ enum MT99XX
H7 = 1, H7 = 1,
YZ = 2, YZ = 2,
LS = 3, LS = 3,
FY805 = 4 FY805 = 4,
}; };
enum MJXQ enum MJXQ
{ {
@ -185,7 +196,7 @@ enum HONTAI
HONTAI = 0, HONTAI = 0,
JJRCX1 = 1, JJRCX1 = 1,
X5C1 = 2, X5C1 = 2,
FQ777_951 =3 FQ777_951 =3,
}; };
enum V2X2 enum V2X2
{ {
@ -239,6 +250,11 @@ enum HITEC
OPT_HUB = 1, OPT_HUB = 1,
MINIMA = 2, MINIMA = 2,
}; };
enum E01X
{
E012 = 0,
E015 = 1,
};
#define NONE 0 #define NONE 0
#define P_HIGH 1 #define P_HIGH 1
@ -355,12 +371,13 @@ enum MultiPacketTypes
//******************** //********************
#if defined(STM32_BOARD) && defined (DEBUG_SERIAL) #if defined(STM32_BOARD) && defined (DEBUG_SERIAL)
uint16_t debug_time=0; uint16_t debug_time=0;
#define debug(msg, ...) {char buf[64]; sprintf(buf, msg, ##__VA_ARGS__); Serial.write(buf);} #define debug(msg, ...) {char debug_buf[64]; sprintf(debug_buf, msg, ##__VA_ARGS__); Serial.write(debug_buf);}
#define debugln(msg, ...) {char buf[64]; sprintf(buf, msg "\r\n", ##__VA_ARGS__); Serial.write(buf);} #define debugln(msg, ...) {char debug_buf[64]; sprintf(debug_buf, msg "\r\n", ##__VA_ARGS__); Serial.write(debug_buf);}
#define debug_time(msg) { uint16_t debug_time_TCNT1=TCNT1; debug_time=debug_time_TCNT1-debug_time; debugln(msg "%u", debug_time); debug_time=debug_time_TCNT1; } #define debug_time(msg) { uint16_t debug_time_TCNT1=TCNT1; debug_time=debug_time_TCNT1-debug_time; debug(msg "%u", debug_time>>1); debug_time=debug_time_TCNT1; }
#else #else
#define debug(...) { } #define debug(...) { }
#define debugln(...) { } #define debugln(...) { }
#define debug_time(...) { }
#undef DEBUG_SERIAL #undef DEBUG_SERIAL
#endif #endif
@ -510,9 +527,11 @@ enum {
#define EEPROM_ID_OFFSET 10 // Module ID (4 bytes) #define EEPROM_ID_OFFSET 10 // Module ID (4 bytes)
#define EEPROM_BANK_OFFSET 15 // Current bank number (1 byte) #define EEPROM_BANK_OFFSET 15 // Current bank number (1 byte)
#define EEPROM_ID_VALID_OFFSET 20 // 1 byte flag that ID is valid #define EEPROM_ID_VALID_OFFSET 20 // 1 byte flag that ID is valid
#define MODELMODE_EEPROM_OFFSET 30 // Autobind mode, 1 byte per model, end is 46 #define MODELMODE_EEPROM_OFFSET 30 // Autobind mode, 1 byte per model, end is 30+16=46
#define AFHDS2A_EEPROM_OFFSET 50 // RX ID, 4 byte per model id, end is 114 #define AFHDS2A_EEPROM_OFFSET 50 // RX ID, 4 bytes per model id, end is 50+64=114
#define CONFIG_EEPROM_OFFSET 120 // Current configuration of the multimodule #define BUGS_EEPROM_OFFSET 114 // TX ID, 4 bytes per model id, end is 114+64=178
#define BUGSMINI_EEPROM_OFFSET 178 // RX ID, 2 bytes per model id, end is 178+32=210
//#define CONFIG_EEPROM_OFFSET 210 // Current configuration of the multimodule
//**************************************** //****************************************
//*** MULTI protocol serial definition *** //*** MULTI protocol serial definition ***
@ -571,6 +590,13 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
CFlie 38 CFlie 38
Hitec 39 Hitec 39
WFLY 40 WFLY 40
BUGS 41
BUGSMINI 42
TRAXXAS 43
NCC1701 44
E01X 45
V911S 46
GD00X 47
BindBit=> 0x80 1=Bind/0=No BindBit=> 0x80 1=Bind/0=No
AutoBindBit=> 0x40 1=Yes /0=No AutoBindBit=> 0x40 1=Yes /0=No
RangeCheck=> 0x20 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No
@ -620,9 +646,6 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
Q222 0 Q222 0
Q242 1 Q242 1
Q282 2 Q282 2
sub_protocol==SLT
SLT 0
VISTA 1
sub_protocol==CG023 sub_protocol==CG023
CG023 0 CG023 0
YD829 1 YD829 1
@ -695,6 +718,15 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
OPT_FW 0 OPT_FW 0
OPT_HUB 1 OPT_HUB 1
MINIMA 2 MINIMA 2
sub_protocol==SLT
SLT_V1 0
SLT_V2 1
Q100 2
Q200 3
MR100 4
sub_protocol==E01X
E012 0
E015 1
Power value => 0x80 0=High/1=Low Power value => 0x80 0=High/1=Low
Stream[3] = option_protocol; Stream[3] = option_protocol;

View File

@ -23,7 +23,7 @@
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
//#define DEBUG_PIN // Use pin TX for AVR and SPI_CS for STM32 => DEBUG_PIN_on, DEBUG_PIN_off, DEBUG_PIN_toggle //#define DEBUG_PIN // Use pin TX for AVR and SPI_CS for STM32 => DEBUG_PIN_on, DEBUG_PIN_off, DEBUG_PIN_toggle
//#define DEBUG_SERIAL // Only for STM32_BOARD compiled with Upload method "Serial"->usart1, "STM32duino bootloader"->USB serial //#define DEBUG_SERIAL // Only for STM32_BOARD, compiled with Upload method "Serial"->usart1, "STM32duino bootloader"->USB serial
#ifdef __arm__ // Let's automatically select the board if arm is selected #ifdef __arm__ // Let's automatically select the board if arm is selected
#define STM32_BOARD #define STM32_BOARD
@ -89,7 +89,7 @@ uint8_t Channel_AUX;
// Protocol variables // Protocol variables
uint8_t cyrfmfg_id[6];//for dsm2 and devo uint8_t cyrfmfg_id[6];//for dsm2 and devo
uint8_t rx_tx_addr[5]; uint8_t rx_tx_addr[5];
uint8_t rx_id[4]; uint8_t rx_id[5];
uint8_t phase; uint8_t phase;
uint16_t bind_counter; uint16_t bind_counter;
uint8_t bind_phase; uint8_t bind_phase;
@ -110,8 +110,9 @@ uint16_t seed;
uint16_t failsafe_count; uint16_t failsafe_count;
uint16_t state; uint16_t state;
uint8_t len; uint8_t len;
uint8_t armed, arm_flags, arm_channel_previous;
#if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) #if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) || defined(HITEC_CC2500_INO)
uint8_t calData[48]; uint8_t calData[48];
#endif #endif
@ -404,11 +405,16 @@ void setup()
//Protocol and interrupts initialization //Protocol and interrupts initialization
if(mode_select != MODE_SERIAL) if(mode_select != MODE_SERIAL)
{ // PPM { // PPM
uint8_t line=bank*14+mode_select-1; #ifndef MY_PPM_PROT
protocol = PPM_prot[line].protocol; const PPM_Parameters *PPM_prot_line=&PPM_prot[bank*14+mode_select-1];
#else
const PPM_Parameters *PPM_prot_line=&My_PPM_prot[bank*14+mode_select-1];
#endif
protocol = PPM_prot_line->protocol;
cur_protocol[1] = protocol; cur_protocol[1] = protocol;
sub_protocol = PPM_prot[line].sub_proto; sub_protocol = PPM_prot_line->sub_proto;
RX_num = PPM_prot[line].rx_num; RX_num = PPM_prot_line->rx_num;
//Forced frequency tuning values for CC2500 protocols //Forced frequency tuning values for CC2500 protocols
#if defined(FORCE_FRSKYD_TUNING) && defined(FRSKYD_CC2500_INO) #if defined(FORCE_FRSKYD_TUNING) && defined(FRSKYD_CC2500_INO)
@ -441,15 +447,14 @@ void setup()
option = FORCE_HITEC_TUNING; // Use config-defined tuning value for HITEC option = FORCE_HITEC_TUNING; // Use config-defined tuning value for HITEC
else else
#endif #endif
option = PPM_prot[line].option; // Use radio-defined option value option = PPM_prot_line->option; // Use radio-defined option value
if(PPM_prot[line].power) POWER_FLAG_on; if(PPM_prot_line->power) POWER_FLAG_on;
if(PPM_prot[line].autobind) if(PPM_prot_line->autobind)
{ {
AUTOBIND_FLAG_on; AUTOBIND_FLAG_on;
BIND_IN_PROGRESS; // Force a bind at protocol startup BIND_IN_PROGRESS; // Force a bind at protocol startup
} }
line++;
protocol_init(); protocol_init();
@ -614,7 +619,7 @@ uint8_t Update_All()
update_led_status(); update_led_status();
#if defined(TELEMETRY) #if defined(TELEMETRY)
#if ( !( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) ) ) #if ( !( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) ) )
if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC)) if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_BAYANG) || (protocol==PROTO_NCC1701) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_FRSKYX) || (protocol==PROTO_DSM) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC))
#endif #endif
TelemetryUpdate(); TelemetryUpdate();
#endif #endif
@ -651,7 +656,7 @@ static void update_channels_aux(void)
{ {
//Reverse channels direction //Reverse channels direction
#ifdef REVERSE_AILERON #ifdef REVERSE_AILERON
reverse_channel(AILREON); reverse_channel(AILERON);
#endif #endif
#ifdef REVERSE_ELEVATOR #ifdef REVERSE_ELEVATOR
reverse_channel(ELEVATOR); reverse_channel(ELEVATOR);
@ -915,6 +920,13 @@ static void protocol_init()
remote_callback = ReadHubsan; remote_callback = ReadHubsan;
break; break;
#endif #endif
#if defined(BUGS_A7105_INO)
case PROTO_BUGS:
PE1_off; //antenna RF1
next_callback = initBUGS();
remote_callback = ReadBUGS;
break;
#endif
#endif #endif
#ifdef CC2500_INSTALLED #ifdef CC2500_INSTALLED
#if defined(FRSKYD_CC2500_INO) #if defined(FRSKYD_CC2500_INO)
@ -1180,6 +1192,42 @@ static void protocol_init()
remote_callback = cflie_callback; remote_callback = cflie_callback;
break; break;
#endif #endif
#if defined(BUGSMINI_NRF24L01_INO)
case PROTO_BUGSMINI:
next_callback=initBUGSMINI();
remote_callback = BUGSMINI_callback;
break;
#endif
#if defined(NCC1701_NRF24L01_INO)
case PROTO_NCC1701:
next_callback=initNCC();
remote_callback = NCC_callback;
break;
#endif
#if defined(E01X_NRF24L01_INO)
case PROTO_E01X:
next_callback=initE01X();
remote_callback = E01X_callback;
break;
#endif
#if defined(V911S_NRF24L01_INO)
case PROTO_V911S:
next_callback=initV911S();
remote_callback = V911S_callback;
break;
#endif
#if defined(GD00X_NRF24L01_INO)
case PROTO_GD00X:
next_callback=initGD00X();
remote_callback = GD00X_callback;
break;
#endif
#if defined(TEST_NRF24L01_INO)
case PROTO_TEST:
next_callback=initTest();
remote_callback = Test_callback;
break;
#endif
#endif #endif
} }
} }
@ -1569,7 +1617,7 @@ void pollBoot()
#if defined(TELEMETRY) #if defined(TELEMETRY)
void PPM_Telemetry_serial_init() void PPM_Telemetry_serial_init()
{ {
if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG) || (protocol==PROTO_CABELL) ) if( (protocol==PROTO_FRSKYD) || (protocol==PROTO_HUBSAN) || (protocol==PROTO_AFHDS2A) || (protocol==PROTO_BAYANG)|| (protocol==PROTO_NCC1701) || (protocol==PROTO_CABELL) || (protocol==PROTO_HITEC) || (protocol==PROTO_BUGS) || (protocol==PROTO_BUGSMINI))
initTXSerial( SPEED_9600 ) ; initTXSerial( SPEED_9600 ) ;
if(protocol==PROTO_FRSKYX) if(protocol==PROTO_FRSKYX)
initTXSerial( SPEED_57600 ) ; initTXSerial( SPEED_57600 ) ;

View File

@ -0,0 +1,277 @@
/*
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/>.
*/
#if defined(NCC1701_NRF24L01_INO)
#include "iface_nrf24l01.h"
#define NCC_WRITE_WAIT 2000
#define NCC_PACKET_INTERVAL 10333
#define NCC_TX_PACKET_LEN 16
#define NCC_RX_PACKET_LEN 13
enum {
NCC_BIND_TX1=0,
NCC_BIND_RX1,
NCC_BIND_TX2,
NCC_BIND_RX2,
NCC_TX3,
NCC_RX3,
};
static void __attribute__((unused)) NCC_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xE7\xE7\xC7\xD7\x67",5);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xE7\xE7\xC7\xD7\x67",5);
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, NCC_RX_PACKET_LEN); // Enable rx pipe 0
NRF24L01_SetBitrate(NRF24L01_BR_250K); // NRF24L01_BR_1M, NRF24L01_BR_2M, NRF24L01_BR_250K
NRF24L01_SetPower();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC) // switch to TX mode and disable CRC
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (0 << NRF24L01_00_PRIM_RX));
}
const uint8_t NCC_xor[]={0x80, 0x44, 0x64, 0x75, 0x6C, 0x71, 0x2A, 0x36, 0x7C, 0xF1, 0x6E, 0x52, 0x09, 0x9D};
static void __attribute__((unused)) NCC_Crypt_Packet()
{
uint16_t crc=0;
for(uint8_t i=0; i< NCC_TX_PACKET_LEN-2; i++)
{
packet[i]^=NCC_xor[i];
crc=crc16_update(crc, packet[i], 8);
}
crc^=0x60DE;
packet[NCC_TX_PACKET_LEN-2]=crc>>8;
packet[NCC_TX_PACKET_LEN-1]=crc;
}
static boolean __attribute__((unused)) NCC_Decrypt_Packet()
{
uint16_t crc=0;
debug("RX: ");
for(uint8_t i=0; i< NCC_RX_PACKET_LEN-2; i++)
{
crc=crc16_update(crc, packet[i], 8);
packet[i]^=NCC_xor[i];
debug("%02X ",packet[i]);
}
crc^=0xA950;
if( (crc>>8)==packet[NCC_RX_PACKET_LEN-2] && (crc&0xFF)==packet[NCC_RX_PACKET_LEN-1] )
{// CRC match
debugln("OK");
return true;
}
debugln("NOK");
return false;
}
static void __attribute__((unused)) NCC_Write_Packet()
{
packet[0]=0xAA;
packet[1]=rx_tx_addr[0];
packet[2]=rx_tx_addr[1];
packet[3]=rx_id[0];
packet[4]=rx_id[1];
packet[5]=convert_channel_8b(THROTTLE)>>2; // 00-3D
packet[6]=convert_channel_8b(ELEVATOR); // original: 61-80-9F but works with 00-80-FF
packet[7]=convert_channel_8b(AILERON ); // original: 61-80-9F but works with 00-80-FF
packet[8]=convert_channel_8b(RUDDER ); // original: 61-80-9F but works with 00-80-FF
packet[9]=rx_id[2];
packet[10]=rx_id[3];
packet[11]=rx_id[4];
packet[12]=GET_FLAG(CH5_SW, 0x02); // Warp:0x00 -> 0x02
packet[13]=packet[5]+packet[6]+packet[7]+packet[8]+packet[12];
if(phase==NCC_BIND_TX1)
{
packet[0]=0xBB;
packet[5]=0x01;
packet[6]=rx_tx_addr[2];
memset((void *)(packet+7),0x55,7);
hopping_frequency_no^=1;
}
else
{
hopping_frequency_no++;
if(hopping_frequency_no>2) hopping_frequency_no=0;
}
// change frequency
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
// switch to TX mode and disable CRC
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(TX_EN);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC)
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (0 << NRF24L01_00_PRIM_RX));
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
// send packet
NCC_Crypt_Packet();
NRF24L01_WritePayload(packet,NCC_TX_PACKET_LEN);
NRF24L01_SetPower();
}
uint16_t NCC_callback()
{
switch(phase)
{
case NCC_BIND_TX1:
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN);
if(NCC_Decrypt_Packet() && packet[1]==rx_tx_addr[0] && packet[2]==rx_tx_addr[1])
{
rx_id[0]=packet[3];
rx_id[1]=packet[4];
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
phase=NCC_BIND_TX2;
return NCC_PACKET_INTERVAL;
}
}
NCC_Write_Packet();
phase = NCC_BIND_RX1;
return NCC_WRITE_WAIT;
case NCC_BIND_RX1:
// switch to RX mode and disable CRC
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC)
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
NRF24L01_FlushRx();
phase = NCC_BIND_TX1;
return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT;
case NCC_BIND_TX2:
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN);
if(NCC_Decrypt_Packet() && packet[1]==rx_tx_addr[0] && packet[2]==rx_tx_addr[1] && packet[3]==rx_id[0] && packet[4]==rx_id[1])
{
rx_id[2]=packet[8];
rx_id[3]=packet[9];
rx_id[4]=packet[10];
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
BIND_DONE;
phase=NCC_TX3;
return NCC_PACKET_INTERVAL;
}
}
NCC_Write_Packet();
phase = NCC_BIND_RX2;
return NCC_WRITE_WAIT;
case NCC_BIND_RX2:
// switch to RX mode and disable CRC
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC)
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
NRF24L01_FlushRx();
phase = NCC_BIND_TX2;
return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT;
case NCC_TX3:
if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & _BV(NRF24L01_07_RX_DR))
{ // RX fifo data ready
NRF24L01_ReadPayload(packet, NCC_RX_PACKET_LEN);
if(NCC_Decrypt_Packet() && packet[1]==rx_tx_addr[0] && packet[2]==rx_tx_addr[1] && packet[3]==rx_id[0] && packet[4]==rx_id[1])
{
//Telemetry
//packet[5] and packet[7] roll angle
//packet[6] crash detect: 0x00 no crash, 0x02 crash
#ifdef NCC1701_HUB_TELEMETRY
v_lipo1 = packet[6]?0xFF:0x00; // Crash indication
v_lipo2 = 0x00;
RX_RSSI = 0x7F; // Dummy RSSI
TX_RSSI = 0x7F; // Dummy RSSI
telemetry_link=1;
#endif
}
}
NCC_Write_Packet();
phase = NCC_RX3;
return NCC_WRITE_WAIT;
case NCC_RX3:
// switch to RX mode and disable CRC
NRF24L01_SetTxRxMode(TXRX_OFF);
NRF24L01_SetTxRxMode(RX_EN);
NRF24L01_WriteReg(NRF24L01_00_CONFIG, (0 << NRF24L01_00_EN_CRC)
| (1 << NRF24L01_00_CRCO)
| (1 << NRF24L01_00_PWR_UP)
| (1 << NRF24L01_00_PRIM_RX));
NRF24L01_FlushRx();
phase = NCC_TX3;
return NCC_PACKET_INTERVAL - NCC_WRITE_WAIT;
}
return 0;
}
const uint8_t PROGMEM NCC_TX_DATA[][6]= {
{ 0x6D, 0x97, 0x04, 0x48, 0x43, 0x26 },
{ 0x35, 0x4B, 0x80, 0x44, 0x4C, 0x0B },
{ 0x50, 0xE2, 0x32, 0x2D, 0x4B, 0x0A },
{ 0xBF, 0x34, 0xF3, 0x45, 0x4D, 0x0D },
{ 0xDD, 0x7D, 0x5A, 0x46, 0x28, 0x23 },
{ 0xED, 0x19, 0x06, 0x2C, 0x4A, 0x09 },
{ 0xE9, 0xA8, 0x91, 0x2B, 0x49, 0x07 },
{ 0x66, 0x17, 0x7D, 0x48, 0x43, 0x26 },
{ 0xC2, 0x93, 0x55, 0x44, 0x4C, 0x0B },
};
uint16_t initNCC(void)
{
BIND_IN_PROGRESS; // autobind protocol
// Load TX data
uint8_t rand=rx_tx_addr[3]%9;
for(uint8_t i=0; i<3; i++)
{
rx_tx_addr[i]=pgm_read_byte_near(&NCC_TX_DATA[rand][i]);
hopping_frequency[i]=pgm_read_byte_near(&NCC_TX_DATA[rand][i+3]);
}
// RX data is acquired during bind
rx_id[0]=0x00;
rx_id[1]=0x00;
rx_id[2]=0x20;
rx_id[3]=0x20;
rx_id[4]=0x20;
hopping_frequency[4]=0x08; // bind channel 1
hopping_frequency[5]=0x2A; // bind channel 2
hopping_frequency_no=4; // start with bind
NCC_init();
phase=NCC_BIND_TX1;
#ifdef NCC1701_HUB_TELEMETRY
init_frskyd_link_telemetry();
#endif
return 10000;
}
#endif

View File

@ -457,16 +457,46 @@ void XN297_WriteEnhancedPayload(uint8_t* msg, uint8_t len, uint8_t noack, uint16
pid=0; pid=0;
} }
void XN297_ReadPayload(uint8_t* msg, uint8_t len) boolean XN297_ReadPayload(uint8_t* msg, uint8_t len)
{ { //!!! Don't forget if using CRC to do a +2 on any of the used NRF24L01_11_RX_PW_Px !!!
// TODO: if xn297_crc==1, check CRC before filling *msg uint8_t buf[32];
NRF24L01_ReadPayload(msg, len); if (xn297_crc)
NRF24L01_ReadPayload(buf, len+2); // Read payload + CRC
else
NRF24L01_ReadPayload(buf, len);
// Decode payload
for(uint8_t i=0; i<len; i++) for(uint8_t i=0; i<len; i++)
{ {
uint8_t b_in=buf[i];
if(xn297_scramble_enabled) if(xn297_scramble_enabled)
msg[i] ^= xn297_scramble[i+xn297_addr_len]; b_in ^= xn297_scramble[i+xn297_addr_len];
msg[i] = bit_reverse(msg[i]); msg[i] = bit_reverse(b_in);
} }
if (!xn297_crc)
return true; // No CRC so OK by default...
// Calculate CRC
uint16_t crc = 0xb5d2;
//process address
for (uint8_t i = 0; i < xn297_addr_len; ++i)
{
uint8_t b_in=xn297_tx_addr[xn297_addr_len-i-1];
if(xn297_scramble_enabled)
b_in ^= xn297_scramble[i];
crc = crc16_update(crc, b_in, 8);
}
//process payload
for (uint8_t i = 0; i < len; ++i)
crc = crc16_update(crc, buf[i], 8);
//xorout
if(xn297_scramble_enabled)
crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]);
else
crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]);
//test
if( (crc >> 8) == buf[len] && (crc & 0xff) == buf[len+1])
return true; // CRC OK
return false; // CRC NOK
} }
uint8_t XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len) uint8_t XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len)
@ -490,6 +520,111 @@ uint8_t XN297_ReadEnhancedPayload(uint8_t* msg, uint8_t len)
// End of XN297 emulation // End of XN297 emulation
//
// HS6200 emulation layer
///////////////////////////
static uint8_t hs6200_crc;
static uint16_t hs6200_crc_init;
static uint8_t hs6200_tx_addr[5];
static uint8_t hs6200_address_length;
static const uint8_t hs6200_scramble[] = {
0x80,0xf5,0x3b,0x0d,0x6d,0x2a,0xf9,0xbc,
0x51,0x8e,0x4c,0xfd,0xc1,0x65,0xd0 }; // todo: find all 32 bytes ...
void HS6200_SetTXAddr(const uint8_t* addr, uint8_t len)
{
if(len < 4)
len = 4;
else if(len > 5)
len = 5;
// use nrf24 address field as a longer preamble
if(addr[len-1] & 0x80)
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x55\x55\x55\x55\x55", 5);
else
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xaa\xaa\xaa\xaa\xaa", 5);
// precompute address crc
hs6200_crc_init = 0xffff;
for(int i=0; i<len; i++)
hs6200_crc_init = crc16_update(hs6200_crc_init, addr[len-1-i], 8);
memcpy(hs6200_tx_addr, addr, len);
hs6200_address_length = len;
}
static uint16_t hs6200_calc_crc(uint8_t* msg, uint8_t len)
{
uint8_t pos;
uint16_t crc = hs6200_crc_init;
// pcf + payload
for(pos=0; pos < len-1; pos++)
crc = crc16_update(crc, msg[pos], 8);
// last byte (1 bit only)
if(len > 0)
crc = crc16_update(crc, msg[pos+1], 1);
return crc;
}
void HS6200_Configure(uint8_t flags)
{
hs6200_crc = !!(flags & _BV(NRF24L01_00_EN_CRC));
flags &= ~(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO));
NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xff);
}
void HS6200_WritePayload(uint8_t* msg, uint8_t len)
{
uint8_t payload[32];
const uint8_t no_ack = 1; // never ask for an ack
static uint8_t pid;
uint8_t pos = 0;
if(len > sizeof(hs6200_scramble))
len = sizeof(hs6200_scramble);
// address
for(int i=hs6200_address_length-1; i>=0; i--)
payload[pos++] = hs6200_tx_addr[i];
// guard bytes
payload[pos++] = hs6200_tx_addr[0];
payload[pos++] = hs6200_tx_addr[0];
// packet control field
payload[pos++] = ((len & 0x3f) << 2) | (pid & 0x03);
payload[pos] = (no_ack & 0x01) << 7;
pid++;
// scrambled payload
if(len > 0)
{
payload[pos++] |= (msg[0] ^ hs6200_scramble[0]) >> 1;
for(uint8_t i=1; i<len; i++)
payload[pos++] = ((msg[i-1] ^ hs6200_scramble[i-1]) << 7) | ((msg[i] ^ hs6200_scramble[i]) >> 1);
payload[pos] = (msg[len-1] ^ hs6200_scramble[len-1]) << 7;
}
// crc
if(hs6200_crc)
{
uint16_t crc = hs6200_calc_crc(&payload[hs6200_address_length+2], len+2);
uint8_t hcrc = crc >> 8;
uint8_t lcrc = crc & 0xff;
payload[pos++] |= (hcrc >> 1);
payload[pos++] = (hcrc << 7) | (lcrc >> 1);
payload[pos++] = lcrc << 7;
}
NRF24L01_WritePayload(payload, pos);
delayMicroseconds(option);
NRF24L01_WritePayload(payload, pos);
}
//
// End of HS6200 emulation
////////////////////////////
/////////////// ///////////////
// LT8900 emulation layer // LT8900 emulation layer
uint8_t LT8900_buffer[64]; uint8_t LT8900_buffer[64];

View File

@ -18,17 +18,37 @@
#include "iface_nrf24l01.h" #include "iface_nrf24l01.h"
//#define SLT_Q200_FORCE_ID
// For code readability // For code readability
#define SLT_PAYLOADSIZE 7 #define SLT_PAYLOADSIZE_V1 7
#define SLT_PAYLOADSIZE_V2 11
#define SLT_NFREQCHANNELS 15 #define SLT_NFREQCHANNELS 15
#define SLT_TXID_SIZE 4 #define SLT_TXID_SIZE 4
enum{
// flags going to packet[6] (Q200)
FLAG_Q200_FMODE = 0x20,
FLAG_Q200_VIDON = 0x10,
FLAG_Q200_FLIP = 0x08,
FLAG_Q200_VIDOFF= 0x04,
};
enum{
// flags going to packet[6] (MR100 & Q100)
FLAG_MR100_FMODE = 0x20,
FLAG_MR100_FLIP = 0x04,
FLAG_MR100_VIDEO = 0x02,
FLAG_MR100_PICTURE = 0x01,
};
enum { enum {
SLT_BUILD=0, SLT_BUILD=0,
SLT_DATA1, SLT_DATA1,
SLT_DATA2, SLT_DATA2,
SLT_DATA3, SLT_DATA3,
SLT_BIND SLT_BIND1,
SLT_BIND2
}; };
static void __attribute__((unused)) SLT_init() static void __attribute__((unused)) SLT_init()
@ -43,7 +63,10 @@ static void __attribute__((unused)) SLT_init()
NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 4); // bytes of data payload for pipe 1 NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 4); // bytes of data payload for pipe 1
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 256kbps NRF24L01_SetBitrate(NRF24L01_BR_250K); // 256kbps
NRF24L01_SetPower(); NRF24L01_SetPower();
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xC3\xC3\xAA\x55", 4); if(sub_protocol==SLT_V1)
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\xC3\xC3\xAA\x55", SLT_TXID_SIZE);
else // V2
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE);
NRF24L01_FlushRx(); NRF24L01_FlushRx();
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE); NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE);
NRF24L01_FlushTx(); NRF24L01_FlushTx();
@ -61,13 +84,17 @@ static void __attribute__((unused)) SLT_set_freq(void)
hopping_frequency[i*4 + 0] = (rx_tx_addr[i] & 0x3f) + base; hopping_frequency[i*4 + 0] = (rx_tx_addr[i] & 0x3f) + base;
hopping_frequency[i*4 + 1] = (rx_tx_addr[i] >> 2) + base; hopping_frequency[i*4 + 1] = (rx_tx_addr[i] >> 2) + base;
hopping_frequency[i*4 + 2] = (rx_tx_addr[i] >> 4) + (rx_tx_addr[next_i] & 0x03)*0x10 + base; hopping_frequency[i*4 + 2] = (rx_tx_addr[i] >> 4) + (rx_tx_addr[next_i] & 0x03)*0x10 + base;
if (i*4 + 3 < SLT_NFREQCHANNELS) // guard for 16 channel
hopping_frequency[i*4 + 3] = (rx_tx_addr[i] >> 6) + (rx_tx_addr[next_i] & 0x0f)*0x04 + base; hopping_frequency[i*4 + 3] = (rx_tx_addr[i] >> 6) + (rx_tx_addr[next_i] & 0x0f)*0x04 + base;
} }
// unique // Unique freq
uint8_t max_freq=0x50; //V1 and V2
if(sub_protocol==Q200)
max_freq=45;
for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i) for (uint8_t i = 0; i < SLT_NFREQCHANNELS; ++i)
{ {
if(sub_protocol==Q200 && hopping_frequency[i] >= max_freq)
hopping_frequency[i] = hopping_frequency[i] - max_freq + 0x03;
uint8_t done = 0; uint8_t done = 0;
while (!done) while (!done)
{ {
@ -77,8 +104,8 @@ static void __attribute__((unused)) SLT_set_freq(void)
{ {
done = 0; done = 0;
hopping_frequency[i] += 7; hopping_frequency[i] += 7;
if (hopping_frequency[i] >= 0x50) if (hopping_frequency[i] >= max_freq)
hopping_frequency[i] = hopping_frequency[i] - 0x50 + 0x03; hopping_frequency[i] = hopping_frequency[i] - max_freq + 0x03;
} }
} }
} }
@ -91,18 +118,19 @@ static void __attribute__((unused)) SLT_wait_radio()
packet_sent = 0; packet_sent = 0;
} }
static void __attribute__((unused)) SLT_send_data(uint8_t *data, uint8_t len) static void __attribute__((unused)) SLT_send_packet(uint8_t len)
{ {
SLT_wait_radio(); SLT_wait_radio();
NRF24L01_FlushTx(); NRF24L01_FlushTx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_MAX_RT)); NRF24L01_WriteReg(NRF24L01_07_STATUS, _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_MAX_RT));
NRF24L01_WritePayload(data, len); NRF24L01_WritePayload(packet, len);
//NRF24L01_PulseCE();
packet_sent = 1; packet_sent = 1;
} }
static void __attribute__((unused)) SLT_build_packet() static void __attribute__((unused)) SLT_build_packet()
{ {
static uint8_t calib_counter=0;
// Set radio channel - once per packet batch // Set radio channel - once per packet batch
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]);
if (++hopping_frequency_no >= SLT_NFREQCHANNELS) if (++hopping_frequency_no >= SLT_NFREQCHANNELS)
@ -113,6 +141,8 @@ static void __attribute__((unused)) SLT_build_packet()
for (uint8_t i = 0; i < 4; ++i) for (uint8_t i = 0; i < 4; ++i)
{ {
uint16_t v = convert_channel_10b(CH_AETR[i]); uint16_t v = convert_channel_10b(CH_AETR[i]);
if(sub_protocol>SLT_V2 && (CH_AETR[i]==THROTTLE || CH_AETR[i]==ELEVATOR) )
v=1023-v; // reverse throttle and elevator channels for Q100/Q200/MR100 protocols
packet[i] = v; packet[i] = v;
e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0); e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0);
} }
@ -121,6 +151,33 @@ static void __attribute__((unused)) SLT_build_packet()
// 8-bit channels // 8-bit channels
packet[5] = convert_channel_8b(CH5); packet[5] = convert_channel_8b(CH5);
packet[6] = convert_channel_8b(CH6); packet[6] = convert_channel_8b(CH6);
if(sub_protocol!=SLT_V1)
{
if(sub_protocol==Q200)
packet[6] = GET_FLAG(CH9_SW , FLAG_Q200_FMODE)
|GET_FLAG(CH10_SW, FLAG_Q200_FLIP)
|GET_FLAG(CH11_SW, FLAG_Q200_VIDON)
|GET_FLAG(CH12_SW, FLAG_Q200_VIDOFF);
else if(sub_protocol==MR100 || sub_protocol==Q100)
packet[6] = GET_FLAG(CH9_SW , FLAG_MR100_FMODE)
|GET_FLAG(CH10_SW, FLAG_MR100_FLIP)
|GET_FLAG(CH11_SW, FLAG_MR100_VIDEO) // Does not exist on the Q100 but...
|GET_FLAG(CH12_SW, FLAG_MR100_PICTURE); // Does not exist on the Q100 but...
packet[7]=convert_channel_8b(CH7);
packet[8]=convert_channel_8b(CH8);
packet[9]=0xAA; //normal mode for Q100/Q200, unknown for V2/MR100
packet[10]=0x00; //normal mode for Q100/Q200, unknown for V2/MR100
if((sub_protocol==Q100 || sub_protocol==Q200) && CH13_SW)
{//Calibrate
packet[9]=0x77; //enter calibration
if(calib_counter>=20 && calib_counter<=25) // 7 packets for Q100 / 3 packets for Q200
packet[10]=0x20; //launch calibration
calib_counter++;
if(calib_counter>250) calib_counter=250;
}
else
calib_counter=0;
}
} }
static void __attribute__((unused)) SLT_send_bind_packet() static void __attribute__((unused)) SLT_send_bind_packet()
@ -132,14 +189,25 @@ static void __attribute__((unused)) SLT_send_bind_packet()
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE); NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x7E\xB8\x63\xA9", SLT_TXID_SIZE);
NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x50); NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x50);
SLT_send_data(rx_tx_addr, SLT_TXID_SIZE); memcpy((void*)packet,(void*)rx_tx_addr,SLT_TXID_SIZE);
if(phase==SLT_BIND2)
SLT_send_packet(SLT_TXID_SIZE);
else // SLT_BIND1
SLT_send_packet(SLT_PAYLOADSIZE_V2);
SLT_wait_radio(); //Wait until the packet's sent before changing TX address! SLT_wait_radio(); //Wait until the packet's sent before changing TX address!
NRF24L01_SetPower(); //Change power back to normal level NRF24L01_SetPower(); //Change power back to normal level
if(phase==SLT_BIND2) // after V1 bind and V2 second bind packet
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE); NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, SLT_TXID_SIZE);
} }
#define SLT_TIMING_BUILD 1000
#define SLT_V1_TIMING_PACKET 1000
#define SLT_V2_TIMING_PACKET 2042
#define SLT_V1_TIMING_BIND2 1000
#define SLT_V2_TIMING_BIND1 6507
#define SLT_V2_TIMING_BIND2 2112
uint16_t SLT_callback() uint16_t SLT_callback()
{ {
switch (phase) switch (phase)
@ -147,33 +215,59 @@ uint16_t SLT_callback()
case SLT_BUILD: case SLT_BUILD:
SLT_build_packet(); SLT_build_packet();
phase++; phase++;
return 1000; return SLT_TIMING_BUILD;
case SLT_DATA1: case SLT_DATA1:
SLT_send_data(packet, SLT_PAYLOADSIZE);
phase++;
return 1000;
case SLT_DATA2: case SLT_DATA2:
SLT_send_data(packet, SLT_PAYLOADSIZE);
phase++; phase++;
return 1000; if(sub_protocol==SLT_V1)
case SLT_DATA3:
SLT_send_data(packet, SLT_PAYLOADSIZE);
if (++packet_count >= 100)
{ {
SLT_send_packet(SLT_PAYLOADSIZE_V1);
return SLT_V1_TIMING_PACKET;
}
else //V2
{
SLT_send_packet(SLT_PAYLOADSIZE_V2);
return SLT_V2_TIMING_PACKET;
}
case SLT_DATA3:
if(sub_protocol==SLT_V1)
SLT_send_packet(SLT_PAYLOADSIZE_V1);
else //V2
SLT_send_packet(SLT_PAYLOADSIZE_V2);
if (++packet_count >= 100)
{// Send bind packet
packet_count = 0; packet_count = 0;
phase++; if(sub_protocol==SLT_V1)
return 1000; {
phase=SLT_BIND2;
return SLT_V1_TIMING_BIND2;
}
else //V2
{
phase=SLT_BIND1;
return SLT_V2_TIMING_BIND1;
}
} }
else else
{ {// Continue to send normal packets
NRF24L01_SetPower(); // Set tx_power NRF24L01_SetPower(); // Set tx_power
phase = SLT_BUILD; phase = SLT_BUILD;
return 19000; if(sub_protocol==SLT_V1)
return 20000-SLT_TIMING_BUILD;
else //V2
return 13730-SLT_TIMING_BUILD;
} }
case SLT_BIND: case SLT_BIND1:
SLT_send_bind_packet();
phase++;
return SLT_V2_TIMING_BIND2;
case SLT_BIND2:
SLT_send_bind_packet(); SLT_send_bind_packet();
phase = SLT_BUILD; phase = SLT_BUILD;
return 18000; if(sub_protocol==SLT_V1)
return 20000-SLT_TIMING_BUILD-SLT_V1_TIMING_BIND2;
else //V2
return 13730-SLT_TIMING_BUILD-SLT_V2_TIMING_BIND1-SLT_V2_TIMING_BIND2;
} }
return 19000; return 19000;
} }
@ -183,9 +277,18 @@ uint16_t initSLT()
packet_count = 0; packet_count = 0;
packet_sent = 0; packet_sent = 0;
hopping_frequency_no = 0; hopping_frequency_no = 0;
if(sub_protocol==Q200)
{ //Q200: Force high part of the ID otherwise it won't bind
rx_tx_addr[0]=0x01;
rx_tx_addr[1]=0x02;
#ifdef SLT_Q200_FORCE_ID // ID taken from TX dumps
rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x6A;rx_tx_addr[3]=0x31;
/* rx_tx_addr[0]=0x01;rx_tx_addr[1]=0x02;rx_tx_addr[2]=0x0B;rx_tx_addr[3]=0x57;*/
#endif
}
SLT_set_freq(); SLT_set_freq();
SLT_init(); SLT_init();
phase = SLT_BIND; phase = SLT_BUILD;
return 50000; return 50000;
} }

View File

@ -367,7 +367,7 @@ void frsky_link_frame()
telemetry_link |= 2 ; // Send hub if available telemetry_link |= 2 ; // Send hub if available
} }
else else
if (protocol==PROTO_HUBSAN||protocol==PROTO_AFHDS2A||protocol==PROTO_BAYANG||protocol==PROTO_CABELL||protocol==PROTO_HITEC) if (protocol==PROTO_HUBSAN||protocol==PROTO_AFHDS2A||protocol==PROTO_BAYANG||protocol==PROTO_NCC1701||protocol==PROTO_CABELL||protocol==PROTO_HITEC||protocol==PROTO_BUGS||protocol==PROTO_BUGSMINI)
{ {
frame[1] = v_lipo1; frame[1] = v_lipo1;
frame[2] = v_lipo2; frame[2] = v_lipo2;
@ -997,7 +997,7 @@ void TelemetryUpdate()
#endif #endif
if((telemetry_link & 1 )&& protocol != PROTO_FRSKYX) if((telemetry_link & 1 )&& protocol != PROTO_FRSKYX)
{ // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec { // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + BugsMini + NCC1701
frsky_link_frame(); frsky_link_frame();
return; return;
} }

View File

@ -0,0 +1,175 @@
/*
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 V911S
#if defined(V911S_NRF24L01_INO)
#include "iface_nrf24l01.h"
//#define V911S_ORIGINAL_ID
#define V911S_PACKET_PERIOD 5000
#define V911S_BIND_PACKET_PERIOD 3300
#define V911S_INITIAL_WAIT 500
#define V911S_PACKET_SIZE 16
#define V911S_RF_BIND_CHANNEL 35
#define V911S_NUM_RF_CHANNELS 8
#define V911S_BIND_COUNT 200
// flags going to packet[1]
#define V911S_FLAG_EXPERT 0x04
// flags going to packet[2]
#define V911S_FLAG_CALIB 0x01
static void __attribute__((unused)) V911S_send_packet(uint8_t bind)
{
if(bind)
{
packet[0] = 0x42;
packet[1] = 0x4E;
packet[2] = 0x44;
for(uint8_t i=0;i<5;i++)
packet[i+3] = rx_tx_addr[i];
for(uint8_t i=0;i<8;i++)
packet[i+8] = hopping_frequency[i];
}
else
{
uint8_t channel=hopping_frequency_no;
if(rf_ch_num&1)
{
if((hopping_frequency_no&1)==0)
channel+=8;
channel>>=1;
}
if(rf_ch_num&2)
channel=7-channel;
packet[ 0]=(rf_ch_num<<3)|channel;
packet[ 1]=V911S_FLAG_EXPERT; // short press on left button
packet[ 2]=GET_FLAG(CH5_SW,V911S_FLAG_CALIB); // long press on right button
memset(packet+3,0x00,14);
//packet[3..6]=trims TAER signed
uint16_t ch=convert_channel_16b_limit(THROTTLE ,0,0x7FF);
packet[ 7] = ch;
packet[ 8] = ch>>8;
ch=convert_channel_16b_limit(AILERON ,0x7FF,0);
packet[ 8]|= ch<<3;
packet[ 9] = ch>>5;
ch=convert_channel_16b_limit(ELEVATOR,0,0x7FF);
packet[10] = ch;
packet[11] = ch>>8;
ch=convert_channel_16b_limit(RUDDER ,0x7FF,0);
packet[11]|= ch<<3;
packet[12] = ch>>5;
}
// Power on, TX mode, 2byte CRC
XN297_Configure(_BV(NRF24L01_00_EN_CRC) | _BV(NRF24L01_00_CRCO) | _BV(NRF24L01_00_PWR_UP));
if (!bind)
{
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[channel]);
hopping_frequency_no++;
hopping_frequency_no&=7; // 8 RF channels
}
// clear packet status bits and TX FIFO
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70);
NRF24L01_FlushTx();
XN297_WritePayload(packet, V911S_PACKET_SIZE);
NRF24L01_SetPower(); // Set tx_power
}
static void __attribute__((unused)) V911S_init()
{
NRF24L01_Initialize();
NRF24L01_SetTxRxMode(TX_EN);
XN297_SetTXAddr((uint8_t *)"\x4B\x4E\x42\x4E\x44", 5); // Bind address
NRF24L01_WriteReg(NRF24L01_05_RF_CH, V911S_RF_BIND_CHANNEL); // Bind channel
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only
NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps
NRF24L01_SetPower();
}
static void __attribute__((unused)) V911S_initialize_txid()
{
//channels
uint8_t offset=rx_tx_addr[3]%5; // 0-4
for(uint8_t i=0;i<V911S_NUM_RF_CHANNELS;i++)
hopping_frequency[i]=0x10+i*5+offset;
if(!offset) hopping_frequency[0]++;
// channels order
rf_ch_num=random(0xfefefefe)&0x03; // 0-3
}
uint16_t V911S_callback()
{
if(IS_BIND_DONE)
V911S_send_packet(0);
else
{
if (bind_counter == 0)
{
BIND_DONE;
XN297_SetTXAddr(rx_tx_addr, 5);
packet_period=V911S_PACKET_PERIOD;
}
else
{
V911S_send_packet(1);
bind_counter--;
if(bind_counter==100) // same as original TX...
packet_period=V911S_BIND_PACKET_PERIOD*3;
}
}
return packet_period;
}
uint16_t initV911S(void)
{
V911S_initialize_txid();
#ifdef V911S_ORIGINAL_ID
rx_tx_addr[0]=0xA5;
rx_tx_addr[1]=0xFF;
rx_tx_addr[2]=0x70;
rx_tx_addr[3]=0x8D;
rx_tx_addr[4]=0x76;
for(uint8_t i=0;i<V911S_NUM_RF_CHANNELS;i++)
hopping_frequency[i]=0x10+i*5;
hopping_frequency[0]++;
rf_ch_num=0;
#endif
V911S_init();
if(IS_BIND_IN_PROGRESS)
{
bind_counter = V911S_BIND_COUNT;
packet_period= V911S_BIND_PACKET_PERIOD;
}
else
{
XN297_SetTXAddr(rx_tx_addr, 5);
packet_period= V911S_PACKET_PERIOD;
}
hopping_frequency_no=0;
return V911S_INITIAL_WAIT;
}
#endif

View File

@ -138,6 +138,7 @@
#undef FLYSKY_A7105_INO #undef FLYSKY_A7105_INO
#undef HUBSAN_A7105_INO #undef HUBSAN_A7105_INO
#undef AFHDS2A_A7105_INO #undef AFHDS2A_A7105_INO
#undef BUGS_A7105_INO
#endif #endif
#ifndef CYRF6936_INSTALLED #ifndef CYRF6936_INSTALLED
#undef DEVO_CYRF6936_INO #undef DEVO_CYRF6936_INO
@ -145,6 +146,7 @@
#undef J6PRO_CYRF6936_INO #undef J6PRO_CYRF6936_INO
#undef WFLY_CYRF6936_INO #undef WFLY_CYRF6936_INO
#undef WK2x01_CYRF6936_INO #undef WK2x01_CYRF6936_INO
#undef TRAXXAS_CYRF6936_INO
#endif #endif
#ifndef CC2500_INSTALLED #ifndef CC2500_INSTALLED
#undef FRSKYD_CC2500_INO #undef FRSKYD_CC2500_INO
@ -174,11 +176,16 @@
#undef HONTAI_NRF24L01_INO #undef HONTAI_NRF24L01_INO
#undef Q303_NRF24L01_INO #undef Q303_NRF24L01_INO
#undef GW008_NRF24L01_INO #undef GW008_NRF24L01_INO
#undef GD00X_NRF24L01_INO
#undef DM002_NRF24L01_INO #undef DM002_NRF24L01_INO
#undef CABELL_NRF24L01_INO #undef CABELL_NRF24L01_INO
#undef ESKY150_NRF24L01_INO #undef ESKY150_NRF24L01_INO
#undef H8_3D_NRF24L01_INO #undef H8_3D_NRF24L01_INO
#undef CFLIE_NRF24L01_INO #undef CFLIE_NRF24L01_INO
#undef BUGSMINI_NRF24L01_INO
#undef NCC1701_NRF24L01_INO
#undef E01X_NRF24L01_INO
#undef V911S_NRF24L01_INO
#endif #endif
//Make sure telemetry is selected correctly //Make sure telemetry is selected correctly
@ -191,6 +198,8 @@
#undef BAYANG_HUB_TELEMETRY #undef BAYANG_HUB_TELEMETRY
#undef CABELL_HUB_TELEMETRY #undef CABELL_HUB_TELEMETRY
#undef HUBSAN_HUB_TELEMETRY #undef HUBSAN_HUB_TELEMETRY
#undef BUGS_HUB_TELEMETRY
#undef NCC1701_HUB_TELEMETRY
#undef HUB_TELEMETRY #undef HUB_TELEMETRY
#undef SPORT_TELEMETRY #undef SPORT_TELEMETRY
#undef SPORT_POLLING #undef SPORT_POLLING
@ -204,6 +213,12 @@
#if not defined(BAYANG_NRF24L01_INO) #if not defined(BAYANG_NRF24L01_INO)
#undef BAYANG_HUB_TELEMETRY #undef BAYANG_HUB_TELEMETRY
#endif #endif
#if not defined(NCC1701_NRF24L01_INO)
#undef NCC1701_HUB_TELEMETRY
#endif
#if not ( defined(BUGS_A7105_INO) || defined(BUGSMINI_NRF24L01_INO) )
#undef BUGS_HUB_TELEMETRY
#endif
#if not defined(CABELL_NRF24L01_INO) #if not defined(CABELL_NRF24L01_INO)
#undef CABELL_HUB_TELEMETRY #undef CABELL_HUB_TELEMETRY
#endif #endif
@ -234,7 +249,7 @@
#if not defined(DSM_CYRF6936_INO) #if not defined(DSM_CYRF6936_INO)
#undef DSM_TELEMETRY #undef DSM_TELEMETRY
#endif #endif
#if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY) #if not defined(DSM_TELEMETRY) && not defined(SPORT_TELEMETRY) && not defined(HUB_TELEMETRY) && not defined(HUBSAN_HUB_TELEMETRY) && not defined(BUGS_HUB_TELEMETRY) && not defined(NCC1701_HUB_TELEMETRY) && not defined(BAYANG_HUB_TELEMETRY) && not defined(CABELL_HUB_TELEMETRY) && not defined(AFHDS2A_HUB_TELEMETRY) && not defined(AFHDS2A_FW_TELEMETRY) && not defined(MULTI_TELEMETRY) && not defined(MULTI_STATUS) && not defined(HITEC_HUB_TELEMETRY) && not defined(HITEC_FW_TELEMETRY)
#undef TELEMETRY #undef TELEMETRY
#undef INVERT_TELEMETRY #undef INVERT_TELEMETRY
#undef SPORT_POLLING #undef SPORT_POLLING
@ -258,6 +273,24 @@
#endif #endif
#endif #endif
#if defined(DSM_THROTTLE_KILL_CH)
#if DSM_THROTTLE_KILL_CH<4
#error DSM_THROTTLE_KILL_CH must be above 4.
#endif
#if DSM_THROTTLE_KILL_CH>16
#error DSM_THROTTLE_KILL_CH must be below or equal to 16.
#endif
#endif
#if defined(AFHDS2A_LQI_CH)
#if AFHDS2A_LQI_CH<4
#error AFHDS2A_LQI_CH must be above 4.
#endif
#if AFHDS2A_LQI_CH>14
#error AFHDS2A_LQI_CH must be below or equal to 14.
#endif
#endif
#if MIN_PPM_CHANNELS>16 #if MIN_PPM_CHANNELS>16
#error MIN_PPM_CHANNELS must be below or equal to 16. The default for this value is 4. #error MIN_PPM_CHANNELS must be below or equal to 16. The default for this value is 4.
#endif #endif

View File

@ -57,7 +57,7 @@ const uint8_t PROGMEM WFLY_init_vals[][2] = {
static void __attribute__((unused)) WFLY_cyrf_bind_config() static void __attribute__((unused)) WFLY_cyrf_bind_config()
{ {
for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++) for(uint8_t i = 0; i < sizeof(WFLY_init_vals) / 2; i++)
CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1])); CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1]));
CYRF_PROGMEM_ConfigSOPCode(WFLY_sop_bind); CYRF_PROGMEM_ConfigSOPCode(WFLY_sop_bind);
@ -67,7 +67,7 @@ static void __attribute__((unused)) WFLY_cyrf_bind_config()
static void __attribute__((unused)) WFLY_cyrf_data_config() static void __attribute__((unused)) WFLY_cyrf_data_config()
{ {
for(uint8_t i = 0; i < (sizeof(init_vals) / 2)-3; i++) for(uint8_t i = 0; i < (sizeof(WFLY_init_vals) / 2)-3; i++)
CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1])); CYRF_WriteRegister(pgm_read_byte_near(&WFLY_init_vals[i][0]), pgm_read_byte_near(&WFLY_init_vals[i][1]));
//CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x08); // Do not accept CRC with 0 seed but not needed since the RX is not sending any data... //CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x08); // Do not accept CRC with 0 seed but not needed since the RX is not sending any data...

View File

@ -49,24 +49,19 @@
//#define REVERSE_THROTTLE //#define REVERSE_THROTTLE
//#define REVERSE_RUDDER //#define REVERSE_RUDDER
//DSM protocol is using by default the Spektrum throw of 1100..1900us @100% and 1000..2000us @125%.
//For more throw, 1024..1976us @100% and 904..2096us @125%, remove the "//" on the line below. Be aware that too much throw can damage some UMX servos. To achieve standard throw in this mode use a channel weight of 84%.
//#define DSM_MAX_THROW
/*************************/ /*****************/
/*** BIND FROM CHANNEL ***/ /*** AUTO BIND ***/ // Also referred as "Bind on powerup"
/*************************/ /*****************/
//Bind from channel enables you to bind when a specified channel is going from low to high. This feature is only active //Bind from channel enables you to bind when a specified channel is going from low to high. This feature is only active
// if you specify AUTOBIND in PPM mode or set AutoBind to YES for serial mode. It also requires that the throttle channel is low. // if you specify AUTOBIND in PPM mode or set AutoBind to YES for serial mode. It also requires that the throttle channel is low.
//Comment to globaly disable the bind feature from a channel. //Comment to globaly disable the bind feature from a channel.
#define ENABLE_BIND_CH #define ENABLE_BIND_CH
//Set the channel number used for bind. Default is 16. //Set the channel number used for bind. Default is 16.
#define BIND_CH 16 #define BIND_CH 16
//Comment to disable the wait for bind feature. This feature will not activate the selected //Comment to disable the wait for bind feature. If Autobind is enabled in the model config, this feature will not activate
// protocol unless a bind is requested using bind from channel or the GUI "Bind" button. // the selected protocol unless a bind is requested using bind from channel or the GUI "Bind" button.
//The goal is to prevent binding other people's model when powering up the TX, changing model or scanning through protocols. //The goal is to prevent binding other people's model when powering up the TX, changing model or scanning through protocols.
#define WAIT_FOR_BIND #define WAIT_FOR_BIND
@ -75,7 +70,7 @@
/*** RF CHIPS ***/ /*** RF CHIPS ***/
/****************/ /****************/
//There are 4 RF components supported. If one of them is not installed you must comment it using "//". //There are 4 RF components supported. If one of them is not installed you must comment it using "//".
//If a chip is not installed all associated protocols are disabled. //If a chip is not installed all associated protocols are automatically disabled.
//4-in-1 modules have all RF chips installed //4-in-1 modules have all RF chips installed
//!!!If a RF chip is present it MUST be marked as installed!!! or weird things will happen you have been warned. //!!!If a RF chip is present it MUST be marked as installed!!! or weird things will happen you have been warned.
#define A7105_INSTALLED #define A7105_INSTALLED
@ -112,6 +107,7 @@
//#define FORCE_FLYSKY_TUNING 0 //#define FORCE_FLYSKY_TUNING 0
//#define FORCE_HUBSAN_TUNING 0 //#define FORCE_HUBSAN_TUNING 0
//#define FORCE_AFHDS2A_TUNING 0 //#define FORCE_AFHDS2A_TUNING 0
//#define FORCE_BUGS_TUNING 0
/** Low Power **/ /** Low Power **/
//Low power is reducing the transmit power of the multi module. This setting is configurable per model in PPM (table below) or Serial mode (radio GUI). //Low power is reducing the transmit power of the multi module. This setting is configurable per model in PPM (table below) or Serial mode (radio GUI).
@ -151,6 +147,7 @@
#define AFHDS2A_A7105_INO #define AFHDS2A_A7105_INO
#define FLYSKY_A7105_INO #define FLYSKY_A7105_INO
#define HUBSAN_A7105_INO #define HUBSAN_A7105_INO
#define BUGS_A7105_INO
//The protocols below need a CYRF6936 to be installed //The protocols below need a CYRF6936 to be installed
#define DEVO_CYRF6936_INO #define DEVO_CYRF6936_INO
@ -158,6 +155,7 @@
#define J6PRO_CYRF6936_INO #define J6PRO_CYRF6936_INO
#define WFLY_CYRF6936_INO #define WFLY_CYRF6936_INO
#define WK2x01_CYRF6936_INO #define WK2x01_CYRF6936_INO
//#define TRAXXAS_CYRF6936_INO
//The protocols below need a CC2500 to be installed //The protocols below need a CC2500 to be installed
#define CORONA_CC2500_INO #define CORONA_CC2500_INO
@ -170,15 +168,18 @@
//The protocols below need a NRF24L01 to be installed //The protocols below need a NRF24L01 to be installed
#define ASSAN_NRF24L01_INO #define ASSAN_NRF24L01_INO
#define BAYANG_NRF24L01_INO #define BAYANG_NRF24L01_INO
#define BUGSMINI_NRF24L01_INO
#define CABELL_NRF24L01_INO #define CABELL_NRF24L01_INO
#define CFLIE_NRF24L01_INO #define CFLIE_NRF24L01_INO
#define CG023_NRF24L01_INO #define CG023_NRF24L01_INO
#define CX10_NRF24L01_INO //Include Q2X2 protocol #define CX10_NRF24L01_INO //Include Q2X2 protocol
#define DM002_NRF24L01_INO #define DM002_NRF24L01_INO
#define E01X_NRF24L01_INO
#define ESKY_NRF24L01_INO #define ESKY_NRF24L01_INO
#define ESKY150_NRF24L01_INO #define ESKY150_NRF24L01_INO
#define FQ777_NRF24L01_INO #define FQ777_NRF24L01_INO
#define FY326_NRF24L01_INO #define FY326_NRF24L01_INO
#define GD00X_NRF24L01_INO
#define GW008_NRF24L01_INO #define GW008_NRF24L01_INO
#define HISKY_NRF24L01_INO #define HISKY_NRF24L01_INO
#define HONTAI_NRF24L01_INO #define HONTAI_NRF24L01_INO
@ -186,14 +187,37 @@
#define KN_NRF24L01_INO #define KN_NRF24L01_INO
#define MJXQ_NRF24L01_INO #define MJXQ_NRF24L01_INO
#define MT99XX_NRF24L01_INO #define MT99XX_NRF24L01_INO
#define NCC1701_NRF24L01_INO
#define Q303_NRF24L01_INO #define Q303_NRF24L01_INO
#define SHENQI_NRF24L01_INO #define SHENQI_NRF24L01_INO
#define SLT_NRF24L01_INO #define SLT_NRF24L01_INO
#define SYMAX_NRF24L01_INO #define SYMAX_NRF24L01_INO
#define V2X2_NRF24L01_INO #define V2X2_NRF24L01_INO
#define V911S_NRF24L01_INO
#define YD717_NRF24L01_INO #define YD717_NRF24L01_INO
/***************************/
/*** PROTOCOLS SETTINGS ***/
/***************************/
//DSM specific settings
//---------------------
//The DSM protocol is using by default the Spektrum throw of 1100..1900us @100% and 1000..2000us @125%.
// For more throw, 1024..1976us @100% and 904..2096us @125%, remove the "//" on the line below. Be aware that too much throw can damage some UMX servos. To achieve standard throw in this mode use a channel weight of 84%.
//#define DSM_MAX_THROW
//Some models (X-Vert, Blade 230S...) require a special value to instant stop the motor(s).
// You can disable this feature by adding "//" on the line below. You have to specify which channel (15 by default) will be used to kill the throttle channel.
// If the channel 15 is above -50% the throttle is untouched but if it is between -50% and -100%, the throttle output will be forced between -100% and -150%.
// For example, a value of -80% applied on channel 15 will instantly kill the motors on the X-Vert.
#define DSM_THROTTLE_KILL_CH 15
//AFHDS2A specific settings
//-------------------------
//When enabled (remove the "//"), the below setting makes LQI (Link Quality Indicator) available on one of the RX ouput channel (5-14).
//#define AFHDS2A_LQI_CH 14
/**************************/ /**************************/
/*** FAILSAFE SETTINGS ***/ /*** FAILSAFE SETTINGS ***/
/**************************/ /**************************/
@ -207,7 +231,7 @@
//Value between -125% and +125%. Default -100. //Value between -125% and +125%. Default -100.
#define FAILSAFE_THROTTLE_LOW -100 #define FAILSAFE_THROTTLE_LOW -100
//The radio using serial protocol can set failsafe data (ersky9x only for now). //The radio using serial protocol can set failsafe data.
// Two options are available: // Two options are available:
// a. replace the default failsafe data with serial failsafe data when they are received. // a. replace the default failsafe data with serial failsafe data when they are received.
// b. wait for the radio to provide failsafe before sending it. Enable advanced settings like "FAILSAFE NOT SET" or "FAILSAFE RX". // b. wait for the radio to provide failsafe before sending it. Enable advanced settings like "FAILSAFE NOT SET" or "FAILSAFE RX".
@ -247,7 +271,9 @@
#define AFHDS2A_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to TX like er9x #define AFHDS2A_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to TX like er9x
#define HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define BAYANG_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define BAYANG_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define BUGS_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define HUBSAN_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define HUBSAN_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define NCC1701_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define CABELL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX #define CABELL_HUB_TELEMETRY // Use FrSkyD Hub format to send telemetry to TX
#define HITEC_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to the radios which can decode it like er9x, ersky9x and OpenTX #define HITEC_HUB_TELEMETRY // Use FrSkyD Hub format to send basic telemetry to the radios which can decode it like er9x, ersky9x and OpenTX
#define HITEC_FW_TELEMETRY // Under development: Forward received telemetry packets to be decoded by ersky9x and OpenTX #define HITEC_FW_TELEMETRY // Under development: Forward received telemetry packets to be decoded by ersky9x and OpenTX
@ -255,6 +281,7 @@
//SPORT_POLLING is an implementation of the same polling routine as XJT module for sport telemetry bidirectional communication. //SPORT_POLLING is an implementation of the same polling routine as XJT module for sport telemetry bidirectional communication.
//This is useful for passing sport control frames from TX to RX(ex: changing Betaflight PID or VTX channels on the fly using LUA scripts with OpentX). //This is useful for passing sport control frames from TX to RX(ex: changing Betaflight PID or VTX channels on the fly using LUA scripts with OpentX).
//Using this feature requires to uncomment INVERT_TELEMETRY as this TX output on telemetry pin only inverted signal. //Using this feature requires to uncomment INVERT_TELEMETRY as this TX output on telemetry pin only inverted signal.
//!!!! This is a work in progress!!! Do not enable unless you want to test and report
//#define SPORT_POLLING //#define SPORT_POLLING
@ -263,7 +290,7 @@
/****************************/ /****************************/
//In this section you can configure the serial mode. //In this section you can configure the serial mode.
//The serial mode enables full editing of all the parameters in the GUI of the radio. It is enabled by placing the rotary switch on position 0. //The serial mode enables full editing of all the parameters in the GUI of the radio. It is enabled by placing the rotary switch on position 0.
//This is available natively for ER9X and ERSKY9X. It is available for OpenTX on Taranis with a special version. //This is available natively for ER9X, ERSKY9X and OpenTX.
//If you do not plan to use the Serial mode comment this line using "//" to save Flash space //If you do not plan to use the Serial mode comment this line using "//" to save Flash space
#define ENABLE_SERIAL #define ENABLE_SERIAL
@ -331,11 +358,11 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
/* 6 */ {PROTO_AFHDS2A, PWM_IBUS , 2 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 4 /* 6 */ {PROTO_AFHDS2A, PWM_IBUS , 2 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 4
/* 7 */ {PROTO_AFHDS2A, PWM_IBUS , 3 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 5 /* 7 */ {PROTO_AFHDS2A, PWM_IBUS , 3 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 5
/* 8 */ {PROTO_SFHSS, H107 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 8 */ {PROTO_SFHSS, H107 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 9 */ {PROTO_FRSKYV, 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 9 */ {PROTO_FRSKYV, NONE , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
/* 10 */ {PROTO_FRSKYD, 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 10 */ {PROTO_FRSKYD, NONE , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
/* 11 */ {PROTO_FRSKYX, CH_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 11 */ {PROTO_FRSKYX, CH_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
/* 12 */ {PROTO_FRSKYX, EU_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 12 */ {PROTO_FRSKYX, EU_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
/* 13 */ {PROTO_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 13 */ {PROTO_DEVO , NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 14 */ {PROTO_WK2x01, WK2801 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 14 */ {PROTO_WK2x01, WK2801 , 0 , P_HIGH , NO_AUTOBIND , 0 },
#endif #endif
#if NBR_BANKS > 1 #if NBR_BANKS > 1
@ -349,19 +376,19 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
/* 6 */ {PROTO_DSM , DSM2_22 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels /* 6 */ {PROTO_DSM , DSM2_22 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels
/* 7 */ {PROTO_DSM , DSMX_11 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels /* 7 */ {PROTO_DSM , DSMX_11 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels
/* 8 */ {PROTO_DSM , DSMX_22 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels /* 8 */ {PROTO_DSM , DSMX_22 , 0 , P_HIGH , NO_AUTOBIND , 8 }, // option=number of channels
/* 9 */ {PROTO_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 9 */ {PROTO_SLT , SLT_V1 , 0 , P_HIGH , NO_AUTOBIND , 6 },
/* 10 */ {PROTO_HUBSAN, H107 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 10 */ {PROTO_HUBSAN, H107 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 11 */ {PROTO_HUBSAN, H301 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 11 */ {PROTO_HUBSAN, H301 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 12 */ {PROTO_HUBSAN, H501 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 12 */ {PROTO_HUBSAN, H501 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 13 */ {PROTO_HISKY, Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 13 */ {PROTO_HISKY, Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 14 */ {PROTO_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 14 */ {PROTO_V2X2 , NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
#endif #endif
#if NBR_BANKS > 2 #if NBR_BANKS > 2
//****************************** BANK 3 ****************************** //****************************** BANK 3 ******************************
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option // Switch Protocol Sub protocol RX_Num Power Auto Bind Option
/* 1 */ {PROTO_ESKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 1 */ {PROTO_ESKY , NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 2 */ {PROTO_ESKY150, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 2 */ {PROTO_ESKY150, NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 3 */ {PROTO_ASSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 3 */ {PROTO_ASSAN, NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 4 */ {PROTO_CORONA, COR_V2 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 4 */ {PROTO_CORONA, COR_V2 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 5 */ {PROTO_SYMAX, SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 5 */ {PROTO_SYMAX, SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 6 */ {PROTO_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 6 */ {PROTO_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 },
@ -406,159 +433,11 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
/* 9 */ {PROTO_Q2X2 , Q282 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 9 */ {PROTO_Q2X2 , Q282 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 10 */ {PROTO_CG023, CG023 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 10 */ {PROTO_CG023, CG023 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 11 */ {PROTO_CG023, YD829 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 11 */ {PROTO_CG023, YD829 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 12 */ {PROTO_FQ777, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 12 */ {PROTO_FQ777, NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 13 */ {PROTO_YD717, YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 13 */ {PROTO_YD717, YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 14 */ {PROTO_MT99XX, MT99 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 14 */ {PROTO_MT99XX, MT99 , 0 , P_HIGH , NO_AUTOBIND , 0 },
#endif #endif
}; };
/* Available protocols and associated sub protocols to pick and choose from
PROTO_FLYSKY
Flysky
V9X9
V6X6
V912
CX20
PROTO_HUBSAN
H107
H301
H501
PROTO_FRSKYV
NONE
PROTO_FRSKYD
NONE
PROTO_FRSKYX
CH_16
CH_8
EU_16
EU_8
PROTO_HISKY
Hisky
HK310
PROTO_V2X2
V2X2
JXD506
PROTO_DSM
DSM2_22
DSM2_11
DSMX_22
DSMX_11
PROTO_DEVO
NONE
PROTO_YD717
YD717
SKYWLKR
SYMAX4
XINXUN
NIHUI
PROTO_KN
WLTOYS
FEILUN
PROTO_SYMAX
SYMAX
SYMAX5C
PROTO_SLT
NONE
PROTO_CX10
CX10_GREEN
CX10_BLUE
DM007
JC3015_1
JC3015_2
MK33041
PROTO_Q2X2
Q222
Q242
Q282
PROTO_SLT
SLT
VISTA
PROTO_CG023
CG023
YD829
PROTO_BAYANG
BAYANG
H8S3D
X16_AH
IRDRONE
PROTO_ESKY
NONE
PROTO_MT99XX
MT99
H7
YZ
LS
FY805
PROTO_MJXQ
WLH08
X600
X800
H26D
E010
H26WH
PROTO_SHENQI
NONE
PROTO_FY326
FY326
FY319
PROTO_SFHSS
NONE
PROTO_J6PRO
NONE
PROTO_FQ777
NONE
PROTO_ASSAN
NONE
PROTO_HONTAI
HONTAI
JJRCX1
X5C1
FQ777_951
PROTO_AFHDS2A
PWM_IBUS
PPM_IBUS
PWM_SBUS
PPM_SBUS
PROTO_WK2x01
WK2801
WK2401
W6_5_1
W6_6_1
W6_HEL
W6_HEL_I
PROTO_Q303
Q303
CX35
CX10D
CX10WD
PROTO_GW008
NONE
PROTO_DM002
NONE
PROTO_CABELL
CABELL_V3
CABELL_V3_TELEMETRY
CABELL_SET_FAIL_SAFE
CABELL_UNBIND
PROTO_ESKY150
PROTO_H8_3D
H8_3D
H20H
H20MINI
H30MINI
PROTO_CORONA
COR_V1
COR_V2
FD_V3
PROTO_CFLIE
NONE
PROTO_HITEC
OPT_FW
OPT_HUB
MINIMA
PROTO_WFLY
NONE
*/
// RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded... // RX_Num is used for TX & RX match. Using different RX_Num values for each receiver will prevent starting a model with the false config loaded...
// RX_Num value is between 0 and 15. // RX_Num value is between 0 and 15.
@ -572,3 +451,168 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
// Option: the value is between -128 and +127. // Option: the value is between -128 and +127.
// The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md // The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md
/* Available protocols and associated sub protocols to pick and choose from (Listed in alphabetical order)
PROTO_AFHDS2A
PWM_IBUS
PPM_IBUS
PWM_SBUS
PPM_SBUS
PROTO_ASSAN
NONE
PROTO_BAYANG
BAYANG
H8S3D
X16_AH
IRDRONE
PROTO_BUGS
NONE
PROTO_BUGSMINI
NONE
PROTO_CABELL
CABELL_V3
CABELL_V3_TELEMETRY
CABELL_SET_FAIL_SAFE
CABELL_UNBIND
PROTO_CFLIE
NONE
PROTO_CG023
CG023
YD829
PROTO_CORONA
COR_V1
COR_V2
FD_V3
PROTO_CX10
CX10_GREEN
CX10_BLUE
DM007
JC3015_1
JC3015_2
MK33041
PROTO_DEVO
NONE
PROTO_DM002
NONE
PROTO_DSM
DSM2_22
DSM2_11
DSMX_22
DSMX_11
PROTO_E01X
E012
E015
PROTO_ESKY
NONE
PROTO_ESKY150
NONE
PROTO_FLYSKY
Flysky
V9X9
V6X6
V912
CX20
PROTO_FQ777
NONE
PROTO_FRSKYD
NONE
PROTO_FRSKYV
NONE
PROTO_FRSKYX
CH_16
CH_8
EU_16
EU_8
PROTO_FY326
FY326
FY319
PROTO_GD00X
NONE
PROTO_GW008
NONE
PROTO_H8_3D
H8_3D
H20H
H20MINI
H30MINI
PROTO_HISKY
Hisky
HK310
PROTO_HITEC
OPT_FW
OPT_HUB
MINIMA
PROTO_HONTAI
HONTAI
JJRCX1
X5C1
FQ777_951
PROTO_HUBSAN
H107
H301
H501
PROTO_J6PRO
NONE
PROTO_KN
WLTOYS
FEILUN
PROTO_MJXQ
WLH08
X600
X800
H26D
E010
H26WH
PROTO_MT99XX
MT99
H7
YZ
LS
FY805
PROTO_NCC1701
NONE
PROTO_Q2X2
Q222
Q242
Q282
PROTO_Q303
Q303
CX35
CX10D
CX10WD
PROTO_SFHSS
NONE
PROTO_SHENQI
NONE
PROTO_SLT
SLT_V1
SLT_V2
Q100
Q200
MR100
PROTO_SYMAX
SYMAX
SYMAX5C
PROTO_TRAXXAS
NONE
PROTO_V2X2
V2X2
JXD506
PROTO_V911S
NONE
PROTO_WFLY
NONE
PROTO_WK2x01
WK2801
WK2401
W6_5_1
W6_6_1
W6_HEL
W6_HEL_I
PROTO_YD717
YD717
SKYWLKR
SYMAX4
XINXUN
NIHUI
*/

View File

@ -9,7 +9,7 @@
// For example you can also define multiple module configurations, uncomment the one you want to compile for: // For example you can also define multiple module configurations, uncomment the one you want to compile for:
#define Module_1 #define Module_1
//#define Module_2 //#define Module_2
//#define Module_2 //#define Module_3
//#define Module_4 //#define Module_4
//Example on how to force the "Flash from TX" feature for all modules //Example on how to force the "Flash from TX" feature for all modules
@ -53,7 +53,27 @@
#define MULTI_TELEMETRY #define MULTI_TELEMETRY
#elif defined Module_4 #elif defined Module_4
//Example of a module which will be PPM only //Example of a module which will be PPM only with a different protocol table
#undef ENABLE_SERIAL #undef ENABLE_SERIAL
#undef NBR_BANKS
#define NBR_BANKS 1 // redefine the number of banks
#define MY_PPM_PROT // Use the bellow protocol list
const PPM_Parameters My_PPM_prot[14*NBR_BANKS]={
//****************************** BANK 1 ******************************
// Switch Protocol Sub protocol RX_Num Power Auto Bind Option
/* 1 */ {PROTO_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 2 */ {PROTO_FLYSKY, Flysky , 0 , P_HIGH , AUTOBIND , 0 },
/* 3 */ {PROTO_AFHDS2A, PWM_IBUS , 1 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 1
/* 4 */ {PROTO_AFHDS2A, PWM_IBUS , 2 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 2
/* 5 */ {PROTO_AFHDS2A, PWM_IBUS , 3 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 3
/* 6 */ {PROTO_AFHDS2A, PWM_IBUS , 2 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 4
/* 7 */ {PROTO_AFHDS2A, PWM_IBUS , 3 , P_HIGH , NO_AUTOBIND , 0 }, // RX number 5
/* 8 */ {PROTO_SFHSS, H107 , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 9 */ {PROTO_FRSKYV, NONE , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
/* 10 */ {PROTO_FRSKYD, NONE , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
/* 11 */ {PROTO_FRSKYX, CH_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
/* 12 */ {PROTO_FRSKYX, EU_16 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning
/* 13 */ {PROTO_DEVO , NONE , 0 , P_HIGH , NO_AUTOBIND , 0 },
/* 14 */ {PROTO_WK2x01, WK2801 , 0 , P_HIGH , NO_AUTOBIND , 0 },
};
#endif #endif

View File

@ -55,6 +55,66 @@ Notes:
## Serial mode ## Serial mode
Serial mode is selected by placing the rotary switch to position 0 before power on of the radio. Serial mode is selected by placing the rotary switch to position 0 before power on of the radio.
You've upgraded the module but the radio does not display the name of the protocol you are loking for:
* ersky9x:
- Place the file [Multi.txt](https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module/master/Multiprotocol/Multi.txt) (which is part of the MPM source files) on the root of your SD card.
- If the entry still does not appear or is broken, [upgrade](https://openrcforums.com/forum/viewtopic.php?f=7&t=4676) to version R222d2 or newer.
* OpenTX:
- Upgrade to the latest version of OpenTX.
- If still not listed, use the Custom entry along with the protocol and sub_protocol values indicated by the italic numbers under each protocol. You'll find a summary of the protocols and numbers to use in table below.
# Available Protocol Table of Contents (Listed Alphabetically)
Protocol Name|Protocol Number|Sub_Proto 0|Sub_Proto 1|Sub_Proto 2|Sub_Proto 3|Sub_Proto 4|Sub_Proto 5|Sub_Proto 6|Sub_Proto 7|RF Module
---|---|---|---|---|---|---|---|---|---|---
[Assan](Protocols_Details.md#ASSAN---24)|24|ASSAN||||||||NRF24L01
[Bayang](Protocols_Details.md#BAYANG---14)|14|Bayang|H8S3D|X16_AH|IRDRONE|||||NRF24L01
[Bugs](Protocols_Details.md#BUGS---41)|41|BUGS||||||||A7105
[BugsMini](Protocols_Details.md#BUGSMINI---42)|42|BUGSMINI||||||||NRF24L01
[Cabell](Protocols_Details.md#Cabell---34)|34|Cabell_V3|C_TELEM|-|-|-|-|F_SAFE|UNBIND|NRF24L01
CFlie|38|CFlie||||||||NRF24L01
[CG023](Protocols_Details.md#CG023---13)|13|CG023|YD829|||||||NRF24L01
[Corona](Protocols_Details.md#CORONA---37)|37|COR_V1|COR_V2|FD_V3||||||CC2500
[CX10](Protocols_Details.md#CX10---12)|12|GREEN|BLUE|DM007|-|J3015_1|J3015_2|MK33041||NRF24L01
[Devo](Protocols_Details.md#DEVO---7)|7|Devo||||||||CYRF6936
[DM002](Protocols_Details.md#DM002---33)|33|DM002||||||||NRF24L01
[DSM](Protocols_Details.md#DSM---6)|6|DSM2-22|DSM2-11|DSMX-22|DSMX-11|AUTO||||CYRF6936
[E01X](Protocols_Details.md#E01X---45)|45|E012|E015|||||||NRF24L01
[ESky](Protocols_Details.md#ESKY---16)|16|ESky||||||||NRF24L01
[ESky150](Protocols_Details.md#ESKY150---35)|35|ESKY150||||||||NRF24L01
[Flysky](Protocols_Details.md#FLYSKY---1)|1|Flysky|V9x9|V6x6|V912|CX20||||A7105
[Flysky AFHDS2A](Protocols_Details.md#FLYSKY-AFHDS2A---28)|28|PWM_IBUS|PPM_IBUS|PWM_SBUS|PPM_SBUS|||||A7105
[FQ777](Protocols_Details.md#FQ777---23)|23|FQ777||||||||NRF24L01
[FrskyD](Protocols_Details.md#FRSKYD---3)|3|FrskyD||||||||CC2500
[FrskyV](Protocols_Details.md#FRSKYV---25)|25|FrskyV||||||||CC2500
[FrskyX](Protocols_Details.md#FRSKYX---15)|15|CH_16|CH_8|EU_16|EU_8|||||CC2500
[FY326](Protocols_Details.md#FY326---20)|20|FY326|FY319|||||||NRF24L01
[GD00X](Protocols_Details.md#GD00X---47)|47|GD00X||||||||NRF24L01
[GW008](Protocols_Details.md#GW008---32)|32|GW008||||||||NRF24L01
[H8_3D](Protocols_Details.md#H8_3D---36)|36|H8_3D|H20H|H20Mini|H30Mini|||||NRF24L01
[Hisky](Protocols_Details.md#HISKY---4)|4|Hisky|HK310|||||||NRF24L01
[Hitec](Protocols_Details.md#HITEC---39)|39|OPT_FW|OPT_HUB|MINIMA||||||CC2500
[Hontai](Protocols_Details.md#HONTAI---26)|26|HONTAI|JJRCX1|X5C1|FQ777_951|||||NRF24L01
[Hubsan](Protocols_Details.md#HUBSAN---2)|2|H107|H301|H501||||||A7105
[J6Pro](Protocols_Details.md#J6Pro---22)|22|J6PRO||||||||CYRF6936
[KN](Protocols_Details.md#KN---9)|9|WLTOYS|FEILUN|||||||NRF24L01
[MJXq](Protocols_Details.md#MJXQ---18)|18|WLH08|X600|X800|H26D|E010|H26WH|||NRF24L01
[MT99xx](Protocols_Details.md#MT99XX---17)|17|MT|H7|YZ|LS|FY805||||NRF24L01
[NCC1701](Protocols_Details.md#NCC1701---44)|44|NCC1701||||||||NRF24L01
[OpenLRS](Protocols_Details.md#OpenLRS---27)|27|||||||||None
[Q2X2](Protocols_Details.md#Q2X2---29)|29|Q222|Q242|Q282||||||NRF24L01
[Q303](Protocols_Details.md#Q303---31)|31|Q303|CX35|CX10D|CX10WD|||||NRF24L01
[SFHSS](Protocols_Details.md#SFHSS---21)|21|SFHSS||||||||CC2500
[Shenqi](Protocols_Details.md#Shenqi---19)|19|Shenqi||||||||NRF24L01
[SLT](Protocols_Details.md#SLT---11)|11|SLT_V1|SLT_V2|Q100|Q200|MR100||||NRF24L01
[SymaX](Protocols_Details.md#Symax---10)|10|SYMAX|SYMAX5C|||||||NRF24L01
Traxxas|43|Traxxas||||||||NRF24L01
[V2x2](Protocols_Details.md#V2X2---5)|5|V2x2|JXD506|||||||NRF24L01
[V911S](Protocols_Details.md#V911S---46)|46|V911S||||||||NRF24L01
[WFly](Protocols_Details.md#WFLY---40)|40|WFLY||||||||CYRF6936
[WK2x01](Protocols_Details.md#WK2X01---30)|30|WK2801|WK2401|W6_5_1|W6_6_1|W6_HEL|W6_HEL_I|||CYRF6936
[YD717](Protocols_Details.md#YD717---8)|8|YD717|SKYWLKR|SYMAX4|XINXUN|NIHUI||||NRF24L01
# A7105 RF Module # A7105 RF Module
## FLYSKY - *1* ## FLYSKY - *1*
@ -102,11 +162,13 @@ Option is used to change the servo refresh rate. A value of 0 gives 50Hz (min),
If telemetry is incomplete (missing RX RSSI for example), it means that you have to upgrade your RX firmware to version 1.6 or later. You can do it from an original Flysky TX or using a STLink like explained in [this tutorial](https://www.rcgroups.com/forums/showthread.php?2677694-How-to-upgrade-Flysky-Turnigy-iA6B-RX-to-firmware-1-6-with-a-ST-Link). If telemetry is incomplete (missing RX RSSI for example), it means that you have to upgrade your RX firmware to version 1.6 or later. You can do it from an original Flysky TX or using a STLink like explained in [this tutorial](https://www.rcgroups.com/forums/showthread.php?2677694-How-to-upgrade-Flysky-Turnigy-iA6B-RX-to-firmware-1-6-with-a-ST-Link).
AFHDS2A_LQI_CH is a feature which is disabled by defaut in the _config.h file. When enabled, it makes LQI (Link Quality Indicator) available on one of the RX ouput channel (5-14).
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14
---|---|---|---|---|---|---|---|---|---|---|---|---|--- ---|---|---|---|---|---|---|---|---|---|---|---|---|---
A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14 A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14
Note that the RX ouput will be AETR. Note that the RX ouput will be AETR whatever the input channel order is.
### Sub_protocol PWM_IBUS - *0* ### Sub_protocol PWM_IBUS - *0*
### Sub_protocol PPM_IBUS - *1* ### Sub_protocol PPM_IBUS - *1*
@ -135,12 +197,29 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|--- ---|---|---|---|---|---|---|---
A|E|T|R|RTH|LIGHT|STAB|VIDEO A|E|T|R|RTH|LIGHT|STAB|VIDEO
### Sub_protocol H501 - *1* ### Sub_protocol H501 - *2*
Models: Hubsan H501S Models: Hubsan H501S, H122D, H123D
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13
---|---|---|---|---|---|---|---|---|---|---|--- ---|---|---|---|---|---|---|---|---|----|----|----|----
A|E|T|R|RTH|LIGHT|PICTURE|VIDEO|HEADLESS1|HEADLESS2|GPS_HOLD|ALT_HOLD A|E|T|R|RTH|LIGHT|PICTURE|VIDEO|HEADLESS|GPS_HOLD|ALT_HOLD|FLIP|FMODES
H122D: FLIP
H123D: FMODES -> -100%=Sport mode 1,0%=Sport mode 2,+100%=Acro
## BUGS - *41*
Models: MJX Bugs 3, 6 and 8
Telemetry enabled for RX & TX RSSI, Battery voltage good/bad
**RX_Num is used to give a number to a given model. You must use a different RX_Num per MJX Bugs. A maximum of 16 Bugs are supported.**
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|---
A|E|T|R|ARM|ANGLE|FLIP|PICTURE|VIDEO|LED
ANGLE: angle is +100%, acro is -100%
*** ***
# CC2500 RF Module # CC2500 RF Module
@ -176,8 +255,9 @@ To bind V2 RXs you must follow the below procedure (original):
### Sub_protocol FD_V3 - *2* ### Sub_protocol FD_V3 - *2*
FlyDream RXs like IS-4R and IS-4R0 FlyDream RXs like IS-4R and IS-4R0
## FRSKYV = FrSky 1 way - *25* ## FRSKYV - *25*
Models: FrSky receivers V8R4, V8R7 and V8FR. Models: FrSky receivers V8R4, V8R7 and V8FR.
- FrSkyV = FrSky 1 way
Extended limits supported Extended limits supported
@ -389,15 +469,16 @@ Telemetry enabled for TSSI and plugins
option=number of channels from 4 to 12. An invalid option value will end up with 6 channels. option=number of channels from 4 to 12. An invalid option value will end up with 6 channels.
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|----|----|CH15
---|---|---|---|---|---|---|---|---|----|----|---- ---|---|---|---|---|---|---|---|---|----|----|----|----|----|----
A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|----|----|TH_KILL
Notes: Notes:
- model/type/number of channels indicated on the RX can be different from what the RX is in fact wanting to see. So don't hesitate to test different combinations until you have something working. Using Auto is the best way to find these settings. - model/type/number of channels indicated on the RX can be different from what the RX is in fact wanting to see. So don't hesitate to test different combinations until you have something working. Using Auto is the best way to find these settings.
- RX output will match the Spektrum standard TAER independently of the input configuration AETR, RETA... - RX output will match the Spektrum standard TAER independently of the input configuration AETR, RETA...
- RX output will match the Spektrum standard throw (1500µs +/- 400µs -> 1100..1900µs) for a 100% input. This is true for both Serial and PPM input. For PPM, make sure the end points PPM_MIN_100 and PPM_MAX_100 in _config.h are matching your TX ouput. The maximum ouput is 1000..2000µs based on an input of 125%. - RX output will match the Spektrum standard throw (1500µs +/- 400µs -> 1100..1900µs) for a 100% input. This is true for both Serial and PPM input. For PPM, make sure the end points PPM_MIN_100 and PPM_MAX_100 in _config.h are matching your TX ouput. The maximum ouput is 1000..2000µs based on an input of 125%.
- If you want to override the above and get maximum throw (old way) uncomment in _config.h the line #define DSM_FULL_THROW . In this mode to achieve standard throw use a channel weight of 84%. - If you want to override the above and get maximum throw (old way) uncomment in _config.h the line #define DSM_MAX_THROW . In this mode to achieve standard throw use a channel weight of 84%.
- TH_KILL is a feature which is enabled on channel 15 by default (can be disabled/changed) in the _config.h file. Some models (X-Vert, Blade 230S...) require a special position to instant stop the motor(s). If the channel 15 is above -50% the throttle is untouched but if it is between -50% and -100%, the throttle output will be forced between -100% and -150%. For example, a value of -80% applied on channel 15 will instantly kill the motors on the X-Vert.
### Sub_protocol DSM2_22 - *0* ### Sub_protocol DSM2_22 - *0*
DSM2, Resolution 1024, refresh rate 22ms DSM2, Resolution 1024, refresh rate 22ms
@ -478,6 +559,19 @@ CH12|CH13
----|---- ----|----
TAKE_OFF|EMG_STOP TAKE_OFF|EMG_STOP
## BUGSMINI - *42*
Models: MJX Bugs 3 Mini and 3H
Telemetry enabled for RX RSSI, Battery voltage good/warning/bad
**RX_Num is used to give a number to a given model. You must use a different RX_Num per MJX Bugs Mini. A maximum of 16 Bugs Mini are supported.**
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|---
A|E|T|R|ARM|ANGLE|FLIP|PICTURE|VIDEO|LED
ANGLE: angle is +100%, acro is -100%
## Cabell - *34* ## Cabell - *34*
Homegrown protocol with variable number of channels (4-16) and telemetry (RSSI, V1, V2). Homegrown protocol with variable number of channels (4-16) and telemetry (RSSI, V1, V2).
@ -574,6 +668,23 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11
---|---|---|---|---|---|---|---|---|----|---- ---|---|---|---|---|---|---|---|---|----|----
A|E|T|R|FLIP|LED|CAMERA1|CAMERA2|HEADLESS|RTH|RATE_LOW A|E|T|R|FLIP|LED|CAMERA1|CAMERA2|HEADLESS|RTH|RATE_LOW
## E01X - *45*
Autobind protocol
### Sub_protocol E012 - *0*
Models: Eachine E012
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R||FLIP||HEADLESS|RTH
### Sub_protocol E015 - *1*
Models: Eachine E015
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R|ARM|FLIP|LED|HEADLESS|RTH
## ESKY - *16* ## ESKY - *16*
CH1|CH2|CH3|CH4|CH5|CH6 CH1|CH2|CH3|CH4|CH5|CH6
@ -604,6 +715,13 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|--- ---|---|---|---|---|---|---|---
A|E|T|R|FLIP|RTH|HEADLESS|EXPERT A|E|T|R|FLIP|RTH|HEADLESS|EXPERT
## GD00X - *47*
Model: GD005 C-17 Transport and GD006 DA62
CH1|CH2|CH3|CH4|CH5|CH6
---|---|---|---|---|---
A||T||TRIM|LED
## GW008 - *32* ## GW008 - *32*
Model: Global Drone GW008 from Banggood Model: Global Drone GW008 from Banggood
@ -743,6 +861,19 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|--- ---|---|---|---|---|---|---|---|---
A|E|T|R|FLIP||||HEADLESS A|E|T|R|FLIP||||HEADLESS
## NCC1701 - *44*
Model: Air Hogs Star Trek USS Enterprise NCC-1701-A
Autobind protocol
Telemetry: RSSI is a dummy value. A1 voltage is dummy but used for crash detection. In case of a crash event A1>0V, you can assign a sound to be played on the TX in that case (siren on the original transmitter).
Only 9 IDs available, cycle through them using RX_Num.
CH1|CH2|CH3|CH4|CH5
---|---|---|---|---
A|E|T|R|Warp
## Q2X2 - *29* ## Q2X2 - *29*
### Sub_protocol Q222 - *0* ### Sub_protocol Q222 - *0*
Models: Q222 v1 and V686 v2 Models: Q222 v1 and V686 v2
@ -807,10 +938,75 @@ Throttle +100%=full forward,0%=stop,-100%=full backward.
## SLT - *11* ## SLT - *11*
Autobind protocol Autobind protocol
### Sub_protocol V1 - *0*
CH1|CH2|CH3|CH4|CH5|CH6 CH1|CH2|CH3|CH4|CH5|CH6
---|---|---|---|---|--- ---|---|---|---|---|---
A|E|T|R|GEAR|PITCH A|E|T|R|GEAR|PITCH
### Sub_protocol V2 - *1*
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
A|E|T|R|CH5|CH6|CH7|CH8
### Sub_protocol Q100 - *2*
Models: Dromida Ominus UAV
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13
---|---|---|---|---|---|---|---|---|---|---|---|---
A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|-|-|CALIB
RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock setting), +50%=max rates
CH7 and CH8 have no visible effect
MODE: -100% level, +100% acro
FLIP: sets model into flip mode for approx 5 seconds at each throw of switch (rear red LED goes out while active) -100%..+100% or +100%..-100%
CALIB: -100% normal mode, +100% gyro calibration
### Sub_protocol Q200 - *3*
Model: Dromida Ominus Quadcopter FPV, the Nine Eagles - FENG FPV and may be others
Dromida Ominus FPV channels mapping:
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13
---|---|---|---|---|---|---|---|---|---|---|---|---
A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|VID_ON|VID_OFF|CALIB
FENG FPV: channels mapping:
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13
---|---|---|---|---|---|---|---|---|---|---|---|---
A|E|T|R|RATES|-|CH7|CH8|FLIP|MODE|VID_ON|VID_OFF|CALIB
RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock setting), +50%=max rates
CH7 and CH8 have no visible effect
MODE: -100% level, +100% acro
FLIP: sets model into flip mode for approx 5 seconds at each throw of switch (rear red LED goes out while active) -100%..+100% or +100%..-100%
CALIB: -100% normal mode, +100% gyro calibration
### Sub_protocol MR100 - *4*
Models: Vista UAV, FPV, FPV v2
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12
---|---|---|---|---|---|---|---|---|---|---|---
A|E|T|R|RATES|-|CH7|CH8|MODE|FLIP|VIDEO|PICTURE
RATES takes any value between -50..+50%: -50%=min rates, 0%=mid rates (stock setting), +50%=max rates
CH7 and CH8 have no visible effect
FLIP: sets model into flip mode for approx 5 seconds at each throw of switch (rear red LED goes out while active) -100%..+100% or +100%..-100%
MODE: -100% level, +100% acro
## Symax - *10* ## Symax - *10*
Autobind protocol Autobind protocol
@ -845,6 +1041,13 @@ CH10|CH11|CH12
---|---|--- ---|---|---
Start/Stop|EMERGENCY|CAMERA_UP/DN Start/Stop|EMERGENCY|CAMERA_UP/DN
## V911S - *46*
Model: WLtoys V911S
CH1|CH2|CH3|CH4|CH5
---|---|---|---|---
A|E|T|R|CALIB
## YD717 - *8* ## YD717 - *8*
Autobind protocol Autobind protocol
@ -858,3 +1061,8 @@ A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS
### Sub_protocol XINXUN - *3* ### Sub_protocol XINXUN - *3*
### Sub_protocol NIHUI - *4* ### Sub_protocol NIHUI - *4*
Same channels assignement as above. Same channels assignement as above.
# OpenLRS module
## OpenLRS - *27*
This is a reservation for OpenLRSng which is using Multi's serial protocol for their modules: https://openlrsng.org/. On the Multi side there is no protocol affected on 27 so it's just ignored.

View File

@ -3,7 +3,7 @@
The **Multiprotocol Tx Module** (or **MULTI-Module**) is a 2.4GHz transmitter module which enables almost any transmitter to control many different receivers and models, including many popular helicopters, planes, quadcopters, and miniquads. The **Multiprotocol Tx Module** (or **MULTI-Module**) is a 2.4GHz transmitter module which enables almost any transmitter to control many different receivers and models, including many popular helicopters, planes, quadcopters, and miniquads.
The source code is partly based on the [Deviation TX project](http://www.deviationtx.com), thanks to all the developers for their great job on protocols. The main forum for protocol requests and questions is on [RCGroups.com](https://www.rcgroups.com/forums/showthread.php?2165676-DIY-Multiprotocol-TX-Module/page10000).
If you like this project and want to support further development please consider making a [donation](docs/Donations.md). If you like this project and want to support further development please consider making a [donation](docs/Donations.md).
@ -17,6 +17,13 @@ If you like this project and want to support further development please consider
</tr> </tr>
</table> </table>
## Development status
Current Multiprotocol code check status: [![Travis Build Status for Multi](https://api.travis-ci.org/pascallanger/DIY-Multiprotocol-TX-Module.svg)](https://travis-ci.org/pascallanger/DIY-Multiprotocol-TX-Module)
Current Multiprotocol boards check status: [![Travis Build Status for Multi Boards](https://api.travis-ci.org/pascallanger/DIY-Multiprotocol-TX-Module-Boards.svg)](https://travis-ci.org/pascallanger/DIY-Multiprotocol-TX-Module-Boards)
## Quicklinks ## Quicklinks
* [Download latest releases of the firmware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) and [instructions to upload .hex files](docs/Advanced_Manually_Setting_ATmega328_Fuses.md) * [Download latest releases of the firmware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) and [instructions to upload .hex files](docs/Advanced_Manually_Setting_ATmega328_Fuses.md)
* [Forum on rcgroups](http://www.rcgroups.com/forums/showthread.php?t=2165676) * [Forum on rcgroups](http://www.rcgroups.com/forums/showthread.php?t=2165676)
@ -120,12 +127,14 @@ Visit the [Troubleshooting](docs/Troubleshooting.md) page. Please bear in mind
# A final word # A final word
A very big thanks to all the people who have shared their time so graciously to create this great project. If you come across them on RC Groups, please be kind and show appreciation. In no particular order: A very big thanks to all the people who have shared their time so graciously to create this great project. If you come across them on RC Groups, please be kind and show appreciation. In no particular order:
* Pascal Langer (rcgroups: hpnuts) * Pascal Langer (rcgroups: hpnuts)
* Ben Lye (rcgroups: benzo99)
* Midelic (rcgroups: midelic) * Midelic (rcgroups: midelic)
* Mike Blandford (rcgroups: Mike Blandford) * Mike Blandford (rcgroups: Mike Blandford)
* PhracturedBlue from Deviation-tx * schwabe - from OpenTX
* goebish from Deviation-tx * PhracturedBlue from [Deviation TX project](http://www.deviationtx.com)
* victzh from Deviation-tx * goebish from [Deviation TX project](http://www.deviationtx.com)
* hexfet from Deviation-tx * victzh from [Deviation TX project](http://www.deviationtx.com)
* hexfet from [Deviation TX project](http://www.deviationtx.com)
Your help would be greatly appreciated. If protocol reverse-engineering and dev is not your thing then any help with testing and contributing to the documentation would be amazing. Given the number of different Tx/module hardware/RF module/protocol/model combinations the process of testing and documenting is a major bottleneck for the developers. Anything you can do to help will free them up to do even greater things. Your help would be greatly appreciated. If protocol reverse-engineering and dev is not your thing then any help with testing and contributing to the documentation would be amazing. Given the number of different Tx/module hardware/RF module/protocol/model combinations the process of testing and documenting is a major bottleneck for the developers. Anything you can do to help will free them up to do even greater things.

3
buildroot/bin/opt_add Executable file
View File

@ -0,0 +1,3 @@
#!/usr/bin/env bash
eval "echo \"#define ${1} ${2}\" >>Multiprotocol/_Config.h"

7
buildroot/bin/opt_disable Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
SED=$(which gsed || which sed)
for opt in "$@" ; do
eval "${SED} -i 's/^\([[:blank:]]*\)\(#define[[:blank:]]*\b${opt}\b\)/\1\/\/\2/g' Multiprotocol/_Config.h"
done

7
buildroot/bin/opt_enable Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
SED=$(which gsed || which sed)
for opt in "$@" ; do
eval "${SED} -i 's/\/\{2,\}[[:blank:]]*\(#define[[:blank:]]*\b${opt}\b\)/\1/g' Multiprotocol/_Config.h"
done

5
buildroot/bin/opt_set Executable file
View File

@ -0,0 +1,5 @@
#!/usr/bin/env bash
SED=$(which gsed || which sed)
eval "${SED} -i 's/\(#define \b${1}\b\).*$/\1 ${2}/g' Multiprotocol/_Config.h"

View File

@ -6,3 +6,6 @@ It is possible to access the telemetry stream coming from the receiver through t
# Manually setting fuses on ATmega328 # Manually setting fuses on ATmega328
This document describes a relatively simple process to set the fuses on ATmega328. See the [Advanced Manually Setting ATmega328 Fuses](Advanced_Manually_Setting_ATmega328_Fuses.md) page for more details. This document describes a relatively simple process to set the fuses on ATmega328. See the [Advanced Manually Setting ATmega328 Fuses](Advanced_Manually_Setting_ATmega328_Fuses.md) page for more details.
# EEPROM Backup and Restore
This document describes how to back up and restore the EEPROM for both Atmega328p and STM32 MULTI-modules. This can be useful if cloning a module, or to preserve settings. See the [MULTI-Module EEPROM](EEPROM.md) page for more details.

View File

@ -113,7 +113,7 @@ The bootloader only needs to be burned once, unless you decide to switch from on
There are two bootloader options: There are two bootloader options:
* **'No bootloader'** maximises flash space for protocols * **'No bootloader'** maximises flash space for protocols
* **'Flash from TX'** (highly recommended) installs a small (512 byte) bootloader which allows flashing the module firmware using from a radio running ersky9x * **'Flash from TX'** installs a small (512 byte) bootloader which allows flashing the module firmware using from a radio running ersky9x
**Note:** 'Burning the bootloader' is necessary even if the 'No bootloader' option is selected, as it sets the fuses on the AVR module. This only needs to be once (unless you decide to change your bootloader choice later) **Note:** 'Burning the bootloader' is necessary even if the 'No bootloader' option is selected, as it sets the fuses on the AVR module. This only needs to be once (unless you decide to change your bootloader choice later)
@ -122,17 +122,15 @@ There are two bootloader options:
### Upload the firmware ### Upload the firmware
You are now ready to upload the firmware to the multiprotocol module. There are two methods for uploading the firmware: You are now ready to upload the firmware to the multiprotocol module. There are two methods for uploading the firmware:
* **Flash from TX** uses the maintenance mode in radios running ersky9x to upload the firmware * **Flash from TX** - uses the bootloader mode of radios running ersky9x or OpenTX to upload the firmware. The radio needs to run the latest bootloader with the Flash Multi app.
* **Upload using Arduino IDE** uses the Arduino IDE and the USBasp programmer to upload the firmware * **Upload using Arduino IDE** uses the Arduino IDE and the USBasp programmer to upload the firmware
**Note:** 'Flash from TX' is only available with radios running ersky9x r221e2 or newer.
#### Flash from TX #### Flash from TX
1. The MPM module must have the 'Flash from TX' bootloader installed
1. In the Arduino IDE click **Sketch -> Export compiled Binary**, or press **Ctrl+Alt+S** 1. In the Arduino IDE click **Sketch -> Export compiled Binary**, or press **Ctrl+Alt+S**
1. Locate the file named **multifw.hex** in the **Multiprotocol** folder 1. Locate the file named **multi-avr-x.x.x.x.hex** in the **Multiprotocol source folder** (x.x.x.x is the multi version)
1. Follow the instructions [here](/docs/Flash_from_Tx.md) to upload the firmware using your radio 1. Follow the instructions [here](/docs/Flash_from_Tx.md) to upload the firmware using your radio
1. Once the previous step is completed your module is ready to be used
You can disconnect the programmer now as it is not needed any more.
#### Upload using Arduino IDE #### Upload using Arduino IDE
**Note:** If you have burned the 'Upload from TX' bootloader and you then upload firmware to your module using **Upload Using Programmer**, you will erase the bootloader. That's just the way the Arduino IDE works - avrdude will erase the entire flash memory prior to writing the new code, *including the bootloader*, and the upload will not put it back. If this happens you can [burn it again](#burn-bootloader-and-set-fuses). **Note:** If you have burned the 'Upload from TX' bootloader and you then upload firmware to your module using **Upload Using Programmer**, you will erase the bootloader. That's just the way the Arduino IDE works - avrdude will erase the entire flash memory prior to writing the new code, *including the bootloader*, and the upload will not put it back. If this happens you can [burn it again](#burn-bootloader-and-set-fuses).

View File

@ -60,6 +60,7 @@ The 4-pin header needs to be soldered onto the board as indicated by the red rec
### Configure the Arduino IDE ### Configure the Arduino IDE
1. Under **Tools -> Board** select **Multi 4-in-1 (STM32FC103)** 1. Under **Tools -> Board** select **Multi 4-in-1 (STM32FC103)**
1. Under **Tools -> Upload method** select **Auto Detect (USB or Serial)** <- more details on this subject later on
1. Under **Tools -> Programmer** select **stm32flash (FTDI)** 1. Under **Tools -> Programmer** select **stm32flash (FTDI)**
## Configure the firmware ## Configure the firmware
@ -67,7 +68,7 @@ The STM32 module has more than enough flash space for all the available protocol
You can still disable protocols if you wish, and you may also enable or disable other optional Multiprotocol features. You can still disable protocols if you wish, and you may also enable or disable other optional Multiprotocol features.
## Verify the firmware ## Verify the firmware
To check that the program will compile correctly and fit in the Atmega click **Sketch -> Verify/Compile**, or press **Ctrl+R**. To check that the program will compile correctly and fit in the STM32 click **Sketch -> Verify/Compile**, or press **Ctrl+R**.
If there are errors, carefully read it, go to the line number indicated and correct your typo. If there are errors, carefully read it, go to the line number indicated and correct your typo.
@ -86,14 +87,14 @@ STM modules, until now, do not come with a preloaded bootloader which makes the
The latest Jumper 4-in-1 modules come with a USB port but it's in fact a built in FTDI appearing on the computer as a CP2102 serial device. You should use the method **Upload via Serial inc. Bootloader** instead of Upload via USB. 'Flash from TX' is supported once the bootloader is installed. The latest Jumper 4-in-1 modules come with a USB port but it's in fact a built in FTDI appearing on the computer as a CP2102 serial device. You should use the method **Upload via Serial inc. Bootloader** instead of Upload via USB. 'Flash from TX' is supported once the bootloader is installed.
### Select an Upload Method ### Select an Upload Method
There are three methods to upload firmware to an STM32 module: There are a total of five firmware upload methods to an STM32 module:
* **Flash from TX** - highly recommended, uses maintenance mode in radios running ersky9x or OpenTX to upload the firmware * **Flash from TX** - uses the bootloader mode of radios running ersky9x or OpenTX to upload the firmware. The radio needs to run the latest bootloader with the Multi Flash app.
* **Upload via USB** - uses the USB port on the module * **Auto Detect (USB or Serial)** - Detects automatically if the upload method is USB or Serial. You need to configure the correct COM port in the IDE which is created when plugging the module.
* **Upload via Serial inc. Bootloader (FTDI)** - uses the serial interface on the module via a USB-to-TTL adapter * **Upload via USB** - uses the USB upload method through the USB plug of the module. It requires the presence of a bootloader in the module.
* **Upload via Serial inc. Bootloader (FTDI)** - uses the serial interface of the module via a USB-to-TTL adapter to install the bootloader and firmware.
* **Upload via Serial (FTDI)** - uses the serial interface of the module via a USB-to-TTL adapter to install the firmware.
**Note:** 'Flash from TX' is available with radios supporting ersky9x or OpenTX and running the latest bootloader with the Multi Flash app. You will most likely use only once on a brand new module the **Upload via Serial inc. Bootloader (FTDI)** method to load the bootloader+firmware. Any successive updates will be done using either **Auto Detect (USB or Serial)** or **Flash from TX** depending on your preference.
**Flash from TX** is highly recommended if your transmitter supports it, **Upload via USB** is recommended for all others. **Upload via Serial inc. Bootloader** can be used if your module does not have a USB port and your transmitter does not run ersky9x or OpenTX.
1. Under **Tools -> Upload Method** select an upload method 1. Under **Tools -> Upload Method** select an upload method
@ -132,6 +133,7 @@ In order to flash the bootloader the **BOOT0** jumper must be installed connecti
1. Verify that you have selected the upload method **Upload via Serial inc. Bootloader (FTDI)** under **Tools -> Upload Method** 1. Verify that you have selected the upload method **Upload via Serial inc. Bootloader (FTDI)** under **Tools -> Upload Method**
1. Verify that you have selected **stm32flash (FTDI)** as the programmer under **Tools -> Programmer** 1. Verify that you have selected **stm32flash (FTDI)** as the programmer under **Tools -> Programmer**
1. Verify that the USB-to-TTL adapter is correctly connected to your module and you have selected the correct port under **Tools -> Port** 1. Verify that the USB-to-TTL adapter is correctly connected to your module and you have selected the correct port under **Tools -> Port**
1. In the Arduino IDE click **Sketch -> Upload**, or press **Ctrl+U**
Output will look similar to this: Output will look similar to this:
``` ```
@ -167,14 +169,18 @@ Assuming the process is successful:
1. Power off the transmitter 1. Power off the transmitter
1. Remove the **BOOT0** jumper 1. Remove the **BOOT0** jumper
1. Disconnect the USB-to-TTL adapter 1. Disconnect the USB-to-TTL adapter
1. Your module is ready to use, enjoy!!!
## Flash from TX ## Flash from TX
1. The MPM module must have a recent bootloader installed
1. Click **Tools -> Upload method -> Flash from TX**
1. Click **Sketch -> Export compiled Binary**, or press **Ctrl+Alt+S** 1. Click **Sketch -> Export compiled Binary**, or press **Ctrl+Alt+S**
1. Locate the file named **multifw.bin** in the **Multiprotocol** folder 1. Locate the file named **multi-stm-x.x.x.x.bin** in the **Multiprotocol source folder** folder (x.x.x.x is the multi version)
1. Follow the instructions [here](/docs/Flash_from_Tx.md) to upload the firmware using your radio 1. Follow the instructions [here](/docs/Flash_from_Tx.md) to upload the firmware using your radio
1. Once done your module is ready to be used
## Upload via USB ## Upload via USB
In order for the module to be correctly identified in Windows it is necessary to install drivers. This only needs to be done once. In order for the module to be correctly identified it is necessary and only once to do some operations based on your operating system.
### Install the Maple USB drivers ### Install the Maple USB drivers
##### Windows 7 or newer: ##### Windows 7 or newer:
@ -228,14 +234,12 @@ After adding yourself to the groups as above and installing and running the udev
**Note:** Some modules require external power in order for the USB port to work. If your module does not power on with USB power alone, install it in the transmitter and switch the transmitter on. It is generally safe for the module to recieve power from both USB and the transmitter. **Note:** Some modules require external power in order for the USB port to work. If your module does not power on with USB power alone, install it in the transmitter and switch the transmitter on. It is generally safe for the module to recieve power from both USB and the transmitter.
1. Connect the USB cable to the Multiprotocol module 1. Connect the USB cable to the Multiprotocol module
1. Verify that a Maple device appears (**Maple DFU** for a module with only a bootloader, **Maple Serial** for a module with a bootloader and firmware) 1. Click **Tools -> Upload method -> Auto Detect (USB or Serial)**
1. On Windows look for the USB device in the Windows Device Manager 1. Select the correct COM port **Tools -> Port**, which should be labelled **COMx (Multi 4-in-1 (STM32F103CB))**.<p align="center"><img src="images/maple-serial-port-select.jpg"/></p>
1. On Mac OSX look in the System Information which is accessed by holding option and selecting the first item under the Apple Menu. Select the USB list on the left and look for the USB device.
1. On Linux execute the command ```lsusb``` and examine the output.
1. select the correct COM port, which should be labelled **COMx (Multi 4-in-1 (STM32F103CB))**. If the device is in "DFU" mode, the module COM port will not appear, select any available COM port to continue the upload procedure.
<p align="center"><img src="images/maple-serial-port-select.jpg"/></p>
1. In the Arduino IDE click **Sketch -> Upload**, or press **Ctrl+U** 1. In the Arduino IDE click **Sketch -> Upload**, or press **Ctrl+U**
**Note:** If the module appears as a **Maple DFU** for a module with only a bootloader, **Maple Serial** for a module with a bootloader and firmware then follow the same process by selecting any available COM port (you must select one, if you don't have one appearing plug any device that will create a com port (an Arduino board for example)).
You should see output similar to this: You should see output similar to this:
``` ```
Sketch uses 68564 bytes (52%) of program storage space. Maximum is 131072 bytes. Sketch uses 68564 bytes (52%) of program storage space. Maximum is 131072 bytes.
@ -265,7 +269,7 @@ Resetting USB to switch back to runtime mode
error resetting after download: usb_reset: could not reset device, win error: The system cannot find the file specified. error resetting after download: usb_reset: could not reset device, win error: The system cannot find the file specified.
``` ```
**Note:** The line `Reset via USB Serial Failed! Did you select the right serial port?` is expected because the uploader initially looks for a Maple Serial device, which isn't yet available, before failing back to Maple DFU. That error only appears the first time and won't appear when re-flashing firmware. The final line warning, stating that the device could not be reset, is also expected. **Note:** The line `Reset via USB Serial Failed! Did you select the right serial port?` or a warning line stating that the device could not be reset is **not a problem**.
## Flashing pre-compiled binaries ## Flashing pre-compiled binaries
Pre-compiled binaries are available [here](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases). Pre-compiled binaries are available [here](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases).

255
docs/EEPROM.md Normal file
View File

@ -0,0 +1,255 @@
# Multi-Module EEPROM
The EEPROM is used to store the Multiprotocol Modules's global ID as well as details of bound receivers for certain protocols (AFHDS2A, Bugs, Devo, Walkera).
On an Atmega328p module the EEPROM is a dedicated and persistent data store, separate from the 32KB of flash memory. On the STM32 module there is no dedicated EEPROM, so EEPROM functionality is emulated in the last 2KB of flash memory.
This makes it relatively easy for the STM32 EEPROM data to be accidentally erased.
If the EEPROM is erased a new global ID will be generated (random for Atmega modules; the MCU UUID for STM32 modules) and models will need to be re-bound.
Backups of the EEPROM data can be made so that configuration such as module ID and bound receivers can be moved between modules.
**Note:** Backups can only restored to a module with same MCU type - i.e. an Atmega backup cannot be restored to an STM32 module.
The remainder of this doc is separated into sections for the STM32 and Atmega328p modules.
## STM32 Module
The EEPROM data is stored in the last 2KB of flash memory. It is read using stm32flash with the module in BOOT0 mode.
#### Tools Needed
* stm32flash (Download: [Windows](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/source/stm32/tools/win/stm32flash.exe), [Linux 32-bit](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/source/stm32/tools/linux/stm32flash/stm32flash), [Linux 64-bit](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/source/stm32/tools/linux64/stm32flash/stm32flash), [macOS](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module-Boards/raw/master/source/stm32/tools/macosx/stm32flash/stm32flash))
* Working USB-to-Serial (FTDI) adapter
#### Preparation
Ensure that the `BOOT0` jumper is installed and the module is connected via a USB-to-Serial adapter.
### Backing up the STM32 EEPROM
The syntax of the backup command is:
`stm32flash -r [file name] -S 0x801F800:2048 [serial port]`
The `-S 0x801F800:2048` option tells stm32flash to read 2048 bytes starting at 0x801F800.
Windows example:
`stm32flash.exe -r C:\Temp\eeprom.bin -S 0x801F800:2048 COM4`
Linux and macOS example:
`stm32flash -r /tmp/eeprom.bin -S 0x801F800:2048 /dev/ttyUSB0`
Output will look similar to this:
```
stm32flash 0.4
http://stm32flash.googlecode.com/
Interface serial_w32: 57600 8E1
Version : 0x22
Option 1 : 0x00
Option 2 : 0x00
Device ID : 0x0410 (Medium-density)
- RAM : 20KiB (512b reserved by bootloader)
- Flash : 128KiB (sector size: 4x1024)
- Option RAM : 16b
- System RAM : 2KiB
Memory read
Read address 0x08020000 (100.00%) Done.
```
### Restoring the STM32 EEPROM
The syntax of the restore command is:
`stm32flash -w [file name] -e 0 -v -S 0x801F800:2048 [serial port]`
Again, the `-S 0x801F800:2048` option tells stm32flash to write 2048 bytes starting at 0x801F800. Additionally `-e 0` tells the tool not to erase any other blocks, which will preserve the rest of the data in the module's memory.
Windows example:
`stm32flash.exe -w C:\Temp\eeprom.bin -e 0 -v -S 0x801F800:2048 COM4`
Linux and macOS example:
`stm32flash -w /tmp/eeprom.bin -e 0 -v -S 0x801F800:2048 /dev/ttyUSB0`
Output will look similar to this:
```
stm32flash 0.4
http://stm32flash.googlecode.com/
Interface serial_w32: 57600 8E1
Version : 0x22
Option 1 : 0x00
Option 2 : 0x00
Device ID : 0x0410 (Medium-density)
- RAM : 20KiB (512b reserved by bootloader)
- Flash : 128KiB (sector size: 4x1024)
- Option RAM : 16b
- System RAM : 2KiB
Write to memory
Wrote and verified address 0x08020000 (100.00%) Done.
```
### Erasing the STM32 EEPROM
The syntax of the erase command is:
`stm32flash -o -S 0x801F800:2048 [serial port]`
Again, the `-S 0x801F800:2048` option tells stm32flash to erase 2048 bytes starting at 0x801F800.
Windows example:
`stm32flash.exe -o -S 0x801F800:2048 COM4`
Linux and macOS example:
`stm32flash -o -S 0x801F800:2048 /dev/ttyUSB0`
Output will look similar to this:
```
stm32flash 0.4
http://stm32flash.googlecode.com/
Interface serial_w32: 57600 8E1
Version : 0x22
Option 1 : 0x00
Option 2 : 0x00
Device ID : 0x0410 (Medium-density)
- RAM : 20KiB (512b reserved by bootloader)
- Flash : 128KiB (sector size: 4x1024)
- Option RAM : 16b
- System RAM : 2KiB
Erasing flash
```
## Atmega328p Module
The EEPROM on the Atmega328p module is a dedicated 1KB data space, separate from the main flash memory.
By default the EEPROM would be erased every time the module is flashed, but we configure the `EESAVE` bit so that the EEPROM is not erased during flashes. This is one reason why it is crucial to set the 'fuses' on a new module using the **Burn Bootloader** command in the Arduino IDE, as described in the [documentation](Compiling.md#burn-bootloader-and-set-fuses).
The module's EEPROM can be read, written, and erased using the avrdude tool.
#### Tools needed
* A USBasp device, or another Arduino programmed to function as a USBasp
* avrdude - installed as part of the Arduino IDE installation, or [downloaded separately](http://savannah.nongnu.org/projects/avrdude)
With a default Arduino IDE installation, the path to avrdude will be:
* Windows - `C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe`
* Linux - `[Arduino IDE path]/hardware/tools/avr/bin/avrdude`
* macOS - TBD
You will also need to know the path to the avrdude configuration file. Default locations are:
* Windows - `C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf`
* Linux - `[Arduino IDE path]/hardware/tools/avr/etc/avrdude.conf`
* macOS - TBD
#### Preparation
Connect the module using the USBasp.
### Backing up the Atmega328p EEPROM
The syntax of the backup command is:
`avrdude -C [config file] -c usbasp -p atmega328p -U eeprom:r:[filename]:i`
Windows example:
`"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe" -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c usbasp -p atmega328p -U eeprom:r:C:\Temp\eeprom.hex:i`
Linux and macOS example:
`~/Downloads/arduino-1.8.5/hardware/tools/avr/bin/avrdude -C ~/Downloads/arduino-1.8.5/hardware/tools/avr/etc/avrdude.conf -c usbasp -p atmega328p -U eeprom:r:/tmp/eeprom.hex:i`
Output will look similar to this:
```
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.10s
avrdude.exe: Device signature = 0x1e950f (probably m328p)
avrdude.exe: reading eeprom memory:
Reading | ################################################## | 100% 7.51s
avrdude.exe: writing output file "C:\Temp\eeprom.hex"
avrdude.exe: safemode: Fuses OK (E:FD, H:D6, L:FF)
avrdude.exe done. Thank you.
```
### Restoring the Atmega328p EEPROM
The syntax of the restore command is:
`avrdude -C [config file] -c usbasp -p atmega328p -U eeprom:w:[filename]:i`
Windows example:
`"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe" -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c usbasp -p atmega328p -U eeprom:w:C:\Temp\eeprom.hex:i`
Linux and macOS example:
`~/Downloads/arduino-1.8.5/hardware/tools/avr/bin/avrdude -C ~/Downloads/arduino-1.8.5/hardware/tools/avr/etc/avrdude.conf -c usbasp -p atmega328p -U eeprom:w:/tmp/eeprom.hex:i`
Output will look similar to this:
```
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.04s
avrdude.exe: Device signature = 0x1e950f (probably m328p)
avrdude.exe: reading input file "C:\Temp\eeprom.hex"
avrdude.exe: writing eeprom (1024 bytes):
Writing | ################################################## | 100% 17.17s
avrdude.exe: 1024 bytes of eeprom written
avrdude.exe: verifying eeprom memory against C:\Temp\eeprom.hex:
avrdude.exe: load data eeprom data from input file C:\Temp\eeprom.hex:
avrdude.exe: input file C:\Temp\eeprom.hex contains 1024 bytes
avrdude.exe: reading on-chip eeprom data:
Reading | ################################################## | 100% 6.51s
avrdude.exe: verifying ...
avrdude.exe: 1024 bytes of eeprom verified
avrdude.exe: safemode: Fuses OK (E:FD, H:D6, L:FF)
avrdude.exe done. Thank you.
```
### Erasing the Atmega328p EEPROM
It's not possible to simply erase the EEPROM so instead we write a file which overwrites all of the content with `0xFF`. Download the 'erase.hex' file [here](https://raw.githubusercontent.com/pascallanger/DIY-Multiprotocol-TX-Module/master/docs/erase.hex).
The syntax of the 'erase' command is the same as the restore command.
Windows example:
`"C:\Program Files (x86)\Arduino\hardware\tools\avr\bin\avrdude.exe" -C "C:\Program Files (x86)\Arduino\hardware\tools\avr\etc\avrdude.conf" -c usbasp -p atmega328p -U eeprom:w:C:\Temp\erase.hex:i`
Linux and macOS example:
`~/Downloads/arduino-1.8.5/hardware/tools/avr/bin/avrdude -C ~/Downloads/arduino-1.8.5/hardware/tools/avr/etc/avrdude.conf -c usbasp -p atmega328p -U eeprom:r:/tmp/erase.hex:i`
Output will look similar to this:
```
avrdude.exe: AVR device initialized and ready to accept instructions
Reading | ################################################## | 100% 0.04s
avrdude.exe: Device signature = 0x1e950f (probably m328p)
avrdude.exe: reading input file "C:\Temp\erase.hex"
avrdude.exe: writing eeprom (1024 bytes):
Writing | ################################################## | 100% 17.17s
avrdude.exe: 1024 bytes of eeprom written
avrdude.exe: verifying eeprom memory against C:\Temp\erase.hex:
avrdude.exe: load data eeprom data from input file C:\Temp\erase.hex:
avrdude.exe: input file C:\Temp\erase.hex contains 1024 bytes
avrdude.exe: reading on-chip eeprom data:
Reading | ################################################## | 100% 6.51s
avrdude.exe: verifying ...
avrdude.exe: 1024 bytes of eeprom verified
avrdude.exe: safemode: Fuses OK (E:FD, H:D6, L:FF)
avrdude.exe done. Thank you.
```

View File

@ -1,33 +1,61 @@
# Flashing from the Transmitter # Flashing from the Transmitter
For radios running ersky9x r221e2 or newer, there is an option to flash a precompiled firmware file to the multiprotocol module using the transmitter's Maintenance Mode. For radios running ersky9x and OpenTX, there is an option to flash a precompiled firmware file to the multiprotocol module using the transmitter's Bootloader mode.
## Tools required ## Tools required
* A compatible transmitter running ersky9x r221e2, or newer * A compatible transmitter running an ersky9x bootloader v2.9 or newer. This is true for both OpenTX and ersky9x.
* A precompiled multiprotocol firmware file (.hex for Atmega328p or .bin for STM32) * A precompiled multiprotocol firmware file (.hex for Atmega328p or .bin for STM32)
* A **Flash from TX** bootloader installed on the multiprotocol module * A **Flash from TX** bootloader installed on an Atmega328p or STM32 multiprotocol module
* A means to get the firmware file onto the transmitter's SD card * A means to get the firmware file onto the transmitter's SD card
Consult the [ersky9x site](http://www.er9x.com/) to see if your transmitter is compatible. ## Radio bootloader and apps
The transmitter firmware can be downloaded from the [ersky9x test firmware page](http://openrcforums.com/forum/viewtopic.php?f=7&t=4676). ### How to check the bootloader version
1. Push both horizontals trims inwards (close to each others) while powering on the radio
1. The screen title should indicate `Boot Loader V2.9Ready` or newer<p align="center"><img src="images/Bootloader.jpg" height=200/></p>
1. Launch the `FlashMulti_xxx.app` app from the `Run App` menu
1. The App version at the bottom right of the screen should be `28.Aug.18` or newer<p align="center"><img src="images/FlashMulti.jpg" height=200/></p>
1. If everything is correct you are ready to upgrade the Multimodule firmware
## Procedure ### Upgrade the bootloader and install app(s)
1. Download the latest zip file of the [ersky9x firmware](https://openrcforums.com/forum/viewtopic.php?f=7&t=4676)
1. Extract the .bin file corresponding to your radio in your SD card `\FIRMWARE` directory
1. Download the latest [Flash Multiprotocol Module app](http://www.er9x.com/Ersky9xapps.html) for your radio
1. Copy the .app file in a folder called `APPS` at the root of the SD card (if the directory does not exist create it)
1. For ersky9x
1. Power on the radio in `MAINTENANCE` mode while pushing both horizontals trims outwards (away from each others)
1. Select `Update Bootloader`
1. Select the ersky9x firmware matching your radio
1. Long press it and select `Flash bootloader`
1. For OpenTX
1. Boot the radio normaly
1. Go in the `RADIO SETUP` menu page 2 called `SD-HC CARD`
1. Open the `FIRMWARE` directory
1. Select the ersky9x firmware matching your radio
1. Long press it and select `Flash bootloader`
1. Check by rebooting the radio in bootloader mode that everything is [ok](###-How-to-check-the-bootloader-version)
**Note**: For OpenTX radio, this bootloader is an upgraded version of the existing bootloader shipped with OpenTX. It's providing you the exact same level of default features while adding more through apps. You can go back and forth between the 2 bootloaders without an issue.
## Multimodule upgrade procedure
1. Either: 1. Either:
1. Connect the transmitter using a USB cable and power it on, or 1. Connect the transmitter using a USB cable and power it on, or
1. Remove the SD card from the transmitter and mount it using a suitable reader 1. Remove the SD card from the transmitter and mount it using a suitable reader
1. Copy the pre-compiled firmware file into the **\firmware** folder of the SD card (create the folder if it does not exist) 1. Copy the pre-compiled firmware file into the `\FIRMWARE` folder of the SD card (create the folder if it does not exist)
1. Power the transmitter off and remove the USB cable or put the SD card back in the transmitter 1. Power the transmitter off and remove the USB cable or put the SD card back in the transmitter
1. Enter the transmitter's Maintenance Menu by powering it on with the outer buttons of the two horizontal trims held down 1. Push both horizontals trims inwards (close to each others) while powering on the radio
1. Select **Update Multi**, 1. The screen title should indicate `Boot Loader V2.9Ready` or newer
1. Launch the `FlashMulti_xxx.app` app from the `Run App` menu
1. Choose the appropriate file type 1. Choose the appropriate file type
1. **HEX** to update an Atmega328p module 1. `HEX` to update an Atmega328p module
1. **BIN** to update an STM32 module 1. `BIN` to update an STM32 module
1. Select **Update** 1. Select `Update`
1. Choose the firmware file to flash, long press to select it 1. Choose the firmware file to flash, long press to select it
1. Long press again to flash the selected file to the module 1. Long press again to flash the selected file to the module
1. When flashing has finished, long press EXIT to reboot in normal mode
When flashing has finished, long press EXIT to reboot in normal mode. ### Troubleshooting
1. If the flashing procedure fails try to redo the process with `Invert Com Port` enabled
## Troubleshooting 1. Make sure to have the latest bootloader on the MPM module before attempting to Flash from the TX:
TBD 1. For an Atmega328p module use the bootloader bundled with the `Multi 4-in1 AVR board 1.0.3` or later
1. For a STM32 module use the bootloader bundled with the `Multi 4-in1 STM32 board 1.0.9` or later

33
docs/erase.hex Normal file
View File

@ -0,0 +1,33 @@
:20000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
:20002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:20004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
:20006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
:20008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80
:2000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60
:2000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40
:2000E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20
:20010000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
:20012000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF
:20014000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF
:20016000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F
:20018000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F
:2001A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F
:2001C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F
:2001E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F
:20020000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE
:20022000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDE
:20024000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBE
:20026000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9E
:20028000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7E
:2002A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5E
:2002C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3E
:2002E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1E
:20030000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD
:20032000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDD
:20034000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBD
:20036000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9D
:20038000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7D
:2003A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D
:2003C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3D
:2003E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1D
:00000001FF

BIN
docs/images/Bootloader.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

BIN
docs/images/FlashMulti.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 320 KiB