Skip to content
44 changes: 40 additions & 4 deletions Multiprotocol/FX_nrf24l01.ino
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ Multiprotocol is distributed in the hope that it will be useful,
#define FX_QF012_PACKET_PERIOD 12194
#define FX_QF012_RX_PAYLOAD_SIZE 3

#define FX_BM26_BIND_CHANNEL 40
#define FX_BM26_PACKET_PERIOD 14066

//#define FORCE_FX620_ID
//#define FORCE_FX9630_ID
//#define FORCE_QIDI_ID
Expand Down Expand Up @@ -90,6 +93,12 @@ static void __attribute__((unused)) FX_send_packet()
packet[1] = convert_channel_8b(AILERON);
packet[2] = 0xFF - convert_channel_8b(ELEVATOR);
packet[3] = convert_channel_8b(RUDDER);
if ( sub_protocol == FX_BM26 ) // BM26 Ail, Elev, Rud range between 0x00-0x3F-0x7F
{
packet[1] >>= 1;
packet[2] >>= 1;
packet[3] >>= 1;
}
val = trim_ch==0 ? 0x20 : (convert_channel_8b(trim_ch + CH6) >> 2); // no trim on Throttle
packet[4] = val; // Trim for channel x 0C..20..34
packet[5] = (trim_ch << 4) // channel x << 4
Expand All @@ -103,6 +112,22 @@ static void __attribute__((unused)) FX_send_packet()
else if (sub_protocol == FX_QF012)
packet[5] |= GET_FLAG(CH7_SW, 0x40) // QF012 invert flight
| GET_FLAG(CH8_SW, 0x80); // QF012 Restore fine tunning midpoint
else if ( sub_protocol == FX_BM26 )
{
if ( packet_count == 0 || packet_count > 3 ) {
packet[5] = 0x00;
packet_count = 0;
}
else packet[5] += 0x40;
packet_count++;
// BM26 P51=>0:beginner(6G), 1:mid(3D), 2:expert(Gyro off)
packet[5] |= (Channel_data[CH6] < CHANNEL_MIN_COMMAND ? 0x08 : (Channel_data[CH6] > CHANNEL_MAX_COMMAND ? 0x0C : 0x0A));

packet[6] = (Channel_data[CH5] > CHANNEL_MAX_COMMAND ? 0x20 : 0x00 ) // 6G Roll
| (Channel_data[CH7] > CHANNEL_MAX_COMMAND ? 0x00 : 0x08 ) // Light control switch, default on
| (Channel_data[CH8] > CHANNEL_MAX_COMMAND ? 0x00 : 0x10 ) // Turn signal switch, default on
| (Channel_data[CH9] > CHANNEL_MAX_COMMAND ? 0x01 : 0x00 ); // Gyro Calibration
}
}
else // FX816 & FX620
{
Expand Down Expand Up @@ -164,6 +189,8 @@ static void __attribute__((unused)) FX_send_packet()
val = val ^ 0xFF;
packet[last_packet_idx]=val;

if ( IS_BIND_IN_PROGRESS && sub_protocol == FX_BM26 ) packet[7] = packet[6];

//Debug
#if 0
for(uint8_t i=0;i<packet_length;i++)
Expand Down Expand Up @@ -194,6 +221,13 @@ static void __attribute__((unused)) FX_RF_init()
packet_period = FX620_BIND_PACKET_PERIOD;
packet_length = FX620_PAYLOAD_SIZE;
}
else if (sub_protocol == FX_BM26)
{
XN297_SetTXAddr((uint8_t *)"\x12\x34\x10\x10", 4);
XN297_RFChannel(FX_BM26_BIND_CHANNEL);
packet_period = FX_BM26_PACKET_PERIOD;
packet_length = FX9630_PAYLOAD_SIZE;
}
else // FX9630 & FX_Q560 & FX_QF012
{
XN297_SetTXAddr((uint8_t *)"\x56\x78\x90\x12", 4);
Expand Down Expand Up @@ -229,7 +263,7 @@ static void __attribute__((unused)) FX_initialize_txid()
else // FX9630 & FX_Q560 & FX_QF012
{
//??? Need to find out how the first RF channel is calculated ???
hopping_frequency[0] = 0x13;
hopping_frequency[0] = sub_protocol == FX_BM26? 0x0C : 0x13;
//Other 2 RF channels are sent during the bind phase so they can be whatever
hopping_frequency[1] = RX_num & 0x0F + 0x1A;
hopping_frequency[2] = rx_tx_addr[3] & 0x0F + 0x38;
Expand All @@ -245,7 +279,8 @@ static void __attribute__((unused)) FX_initialize_txid()
//memcpy(rx_tx_addr,(uint8_t*)"\x38\xC7\x6D\x8D", 4);
//memcpy(hopping_frequency,"\x0D\x20\x3A", FX9630_NUM_CHANNELS);
#endif
}
// BM26 rx_tx_addr: "\x17\x03\x00\x00", hopping_frequency: 0x0C,0x30,0x43(12,48,67)
}
}

uint16_t FX_callback()
Expand Down Expand Up @@ -288,9 +323,9 @@ uint16_t FX_callback()
debug("RX");
if(XN297_ReadPayload(packet_in, FX_QF012_RX_PAYLOAD_SIZE))
{//Good CRC
//packets: A5 00 11 -> A5 01 11
telemetry_link = 1;
v_lipo1 = packet_in[1] ? 60:81; // low voltage 3.7V
if ( sub_protocol == FX_BM26 ) v_lipo1 = packet_in[0] < packet_in[2]? 60:81; // packets: AA 00 55 -> 55 00 AA
else v_lipo1 = packet_in[1] ? 60:81; //packets: A5 00 11 -> A5 01 11 // low voltage 3.7V
#if 0
for(uint8_t i=0; i < FX_QF012_RX_PAYLOAD_SIZE; i++)
debug(" %02X", packet_in[i]);
Expand Down Expand Up @@ -328,6 +363,7 @@ void FX_init()
FX_RF_init();
hopping_frequency_no = 0;
bind_counter=FX_BIND_COUNT;
packet_count = 0;
#ifdef FX_HUB_TELEMETRY
RX_RSSI = 100; // Dummy value
phase = FX_DATA;
Expand Down
4 changes: 3 additions & 1 deletion Multiprotocol/Hontai_nrf24l01.ino
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ static void __attribute__((unused)) HONTAI_send_packet()
packet[i+3] = convert_channel_16b_limit(CH_TAER[i],0x28,0xD8);
packet[6] ^= 0xFF; //Reverse rudder
//flags
packet[1] = GET_FLAG(CH8_SW, 0x04); //Gyro calibration (momentary)
//packet[1] = GET_FLAG(CH8_SW, 0x04); //Gyro calibration (momentary)
packet[1] = GET_FLAG(CH8_SW, 0x04) //Gyro calibration (momentary)
| GET_FLAG(CH11_SW, 0x10); //XK K270 optical flow switch
// |GET_FLAG(CH_SW, 0x08) //Unk long press second top right button (momentary)
// |GET_FLAG(CH_SW, 0x10) //Unk short press second top right button (toggle)
// |GET_FLAG(CH_SW, 0x40) //Unk short press second top left button (momentary)
Expand Down
3 changes: 2 additions & 1 deletion Multiprotocol/Multi.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
55,Frsky_RX,Multi,CloneTX,EraseTX,CPPM
56,AFHDS2A_RX,Multi,CPPM
57,HoTT,Sync,No_Sync
58,FX,816,620,9630,Q560,QF012
58,FX,816,620,9630,Q560,QF012,BM26
59,Bayang_RX,Multi,CPPM
60,Pelikan,Pro,Lite,SCX24
61,EazyRC
Expand Down Expand Up @@ -102,3 +102,4 @@
104,KAMTOM
105,Shenqi2
106,WL91x

4 changes: 2 additions & 2 deletions Multiprotocol/Multi_Protos.ino
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ const char STR_SUBTYPE_JJRC345[] = "\x08""JJRC345\0""SkyTmblr";
const char STR_SUBTYPE_MOULDKG[] = "\x05""A4444""D4444""A664\0";
const char STR_SUBTYPE_KF606[] = "\x06""KF606\0""MIG320""ZCZ50\0";
const char STR_SUBTYPE_E129[] = "\x04""E129""C186";
const char STR_SUBTYPE_FX[] = "\x05""816\0 ""620\0 ""9630\0""Q560\0""QF012";
const char STR_SUBTYPE_FX[] = "\x05""816\0 ""620\0 ""9630\0""Q560\0""QF012""BM26\0";
const char STR_SUBTYPE_SGF22[] = "\x04""F22\0""F22S""J20\0""CX10";
const char STR_SUBTYPE_JIABAILE[] = "\x04""Std\0""Gyro";
#define NO_SUBTYPE nullptr
Expand Down Expand Up @@ -345,7 +345,7 @@ const mm_protocol_definition multi_protocols[] = {
{PROTO_FUTABA, STR_FUTABA, STR_SUBTYPE_FUTABA, 1, OPTION_RFTUNE, 1, 1, SW_CC2500, SFHSS_init, SFHSS_callback },
#endif
#if defined(FX_NRF24L01_INO)
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 5, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
{PROTO_FX, STR_FX, STR_SUBTYPE_FX, 6, OPTION_NONE, 0, 0, SW_NRF, FX_init, FX_callback },
#endif
#if defined(FY326_NRF24L01_INO)
{PROTO_FY326, STR_FY326, STR_SUBTYPE_FY326, 2, OPTION_NONE, 0, 0, SW_NRF, FY326_init, FY326_callback },
Expand Down
1 change: 1 addition & 0 deletions Multiprotocol/Multiprotocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ enum FX
FX9630 = 2,
FX_Q560 = 3,
FX_QF012 = 4,
FX_BM26 = 5,
};
enum SGF22
{
Expand Down
4 changes: 3 additions & 1 deletion Multiprotocol/XK2_ccnrf.ino
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ static void __attribute__((unused)) XK2_send_packet()
packet[5] |= 0x10; //Gyro off (senior mode)
else if(Channel_data[CH6] > CHANNEL_MIN_COMMAND)
packet[5] |= 0x08; //3D
packet[5] |= GET_FLAG(CH9_SW, 0x04) ; //SkyViper Vector stunt flag
//SkyViper Vector: Telemetry A1 value is changed from 8.4v to 7.1v when the battery voltage is less than 3.3v
//Requiest telemetry flag
packet[6] = 0x01;
//RXID checksum
Expand Down Expand Up @@ -428,4 +430,4 @@ P[6] = 00 telemetry nok
01 telemetry ok but sometimes switch to 1 also when telemetry is nok...
P[7] = C8 -> sum RX_ID[0..2]
P[8] = sum P[0..7] + TX_ID[0] - TX_ID[1] + TX_ID[2] + 21 +10
*/
*/
1 change: 1 addition & 0 deletions Multiprotocol/_Config.h
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
FX9630
Q560
QF012
BM26
PROTO_FY326
FY326
FY319
Expand Down
29 changes: 22 additions & 7 deletions Protocols_Details.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ CFlie|AIR|38|CFlie||||||||NRF24L01|
[FrskyX2](Protocols_Details.md#FRSKYX2---64)||64|CH_16|CH_8|EU_16|EU_8|Cloned|Cloned_8|||CC2500|
[Frsky_RX](Protocols_Details.md#FRSKY_RX---55)||55|Multi|CloneTX|EraseTX|CPPM|||||CC2500|
[Futaba/SFHSS](Protocols_Details.md#Futaba---21)||21|SFHSS||||||||CC2500|
[FX](Protocols_Details.md#FX---58)||28|816|620|9630|Q560|QF012||||NRF24L01|
[FX](Protocols_Details.md#FX---58)||28|816|620|9630|Q560|QF012|BM26|||NRF24L01|
[FY326](Protocols_Details.md#FY326---20)||20|FY326|FY319|||||||NRF24L01|
[GD00X](Protocols_Details.md#GD00X---47)||47|GD_V1*|GD_V2*|||||||NRF24L01|XN297L
[GW008](Protocols_Details.md#GW008---32)||32|||||||||NRF24L01|XN297
Expand Down Expand Up @@ -1574,9 +1574,9 @@ If a CC2500 is installed it will be used for this sub protocol. Option in this c

If only a NRF24L01 is installed then this sub protocol might be problematic because it is using the xn297L emulation with a transmission speed of 250kbps which doesn't work very well with every NRF24L01, this is an hardware issue with the authenticity and accuracy of the components.

CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
A|E|T|R|Rate|Mode|Hover|Light
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R|Rate|Mode|Hover|Light|Stunt

The plane does not need to be bound each time if it is powered on **after** the radio/protocol is on.

Expand All @@ -1586,6 +1586,8 @@ The rudder trim is driven from the rudder channel to increase the range (Origina

Mode: -100%=6G, 0%=3D, +100%=Gyro off (Senior mode)

CH9 - Stunt is for SkyViper Vector.

### Sub_protocol X4 - *0*
Transmitter: XK X4-A160, X5S, model: XK A160S, XK A280, XK A300

Expand Down Expand Up @@ -1890,6 +1892,17 @@ Gyro: -100%=6G, 0%=3D+Gyro, +100%=3D

Reset: Restore fine tunning midpoint

### Sub_protocol BM26 - *5*
Model: BM26 P51

Telemetry supported. The plane sends a battery status of good->empty which is visible in A1 (good=4.2V->empty=3.1V) and RSSI gets a dummy value of 100.

CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9
---|---|---|---|---|---|---|---|---
A|E|T|R|FLIP|GYRO|Light Switch|Turning Light switch|Gyro Calibration

Gyro: -100%=6G, 0%=3D+Gyro, +100%=3D

## FY326 - *20*

### Sub_protocol FY326 - *0*
Expand Down Expand Up @@ -2005,12 +2018,14 @@ ARM|

Model: XK K170 UH-60L Black hawk

CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10
---|---|---|---|---|---|---|---|---|---
A|E|T|R|RATE|EMERGENCY|TAKE_OFF/LANDING|CALIB|TrimA|TrimE
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11
---|---|---|---|---|---|---|---|---|---|---
A|E|T|R|RATE|EMERGENCY|TAKE_OFF/LANDING|CALIB|TrimA|TrimE|Optical

RATE: -100% Low, 0% Mid, +100% High

CH11: XK K270 only

## JIABAILE - *102*

### Sub_protocol Std - *0*
Expand Down
Loading