FX/BM26: new subprotocol

This commit is contained in:
pascallanger
2026-07-14 22:29:07 +02:00
parent 80d08c25e0
commit 93bade15d0
4 changed files with 62 additions and 15 deletions

View File

@@ -86,11 +86,13 @@
55,1,FrSkyRX,CloneTX,0
55,2,FrSkyRX,EraseTX,0
55,3,FrSkyRX,CPPM,0,CH5,CH6,CH7,CH8,CH9,CH10,CH11,CH12,CH13,CH14,CH15,CH16
58,0,FX,816,1
58,1,FX,620,1
58,0,FX,FX816,1
58,1,FX,FX620,1
58,2,FX,9630,1,Rate,Gyro,TrimR,TrimA,TrimE
58,3,FX,Q560,1,FLIP,Gyro,LEDs
58,4,FX,QF012,1,FLIP,Gyro,Invert,Reset
58,5,FX,BM26,1,FLIP,Gyro,LEDs,LED,CALIB
58,6,FX,FX818,1
20,0,FY326,FY326,1,Flip,RTH,HLess,Expert,Calib
20,1,FY326,FY319,1,Flip,RTH,HLess,Expert,Calib
23,0,FY326,FY326,1,Flip,RTH,HLess,Expert
@@ -235,3 +237,4 @@
104,0,KAMTOM,Std,0,ST_Tr,TH_Tr,TH_DR
105,0,Shenqi2,Std,1
106,0,WL91x,Std,0
107,0,WPL,Std,0,Light,TH_DR,ST_DR

View File

@@ -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
@@ -85,11 +88,17 @@ static void __attribute__((unused)) FX_send_packet()
//Channels
uint8_t val;
if (sub_protocol >= FX9630)
{ // FX9630 & FX_Q560 & FX_QF012
{ // FX9630 & FX_Q560 & FX_QF012 & FX_BM26
packet[0] = convert_channel_8b(THROTTLE);
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
@@ -103,6 +112,17 @@ 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 )
{
packet[5] &= 0xC0;
packet[5] += 0x40;
// 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] = GET_FLAG( CH5_SW, 0x20) // 6G Roll
| GET_FLAG(!CH7_SW, 0x08) // Light control switch, default on
| GET_FLAG(!CH8_SW, 0x10) // Turn signal switch, default on
| GET_FLAG( CH9_SW, 0x01); // Gyro Calibration
}
}
else // FX816 & FX620
{
@@ -142,7 +162,7 @@ static void __attribute__((unused)) FX_send_packet()
packet[5] = 0xAB; // Is it based on ID??
}
}
else // FX9630 & FX_Q560 & FX_QF012
else // FX9630 & FX_Q560 & FX_QF012 & FX_BM26
{
if(IS_BIND_IN_PROGRESS)
{
@@ -164,6 +184,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++)
@@ -194,6 +216,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);
@@ -226,10 +255,10 @@ static void __attribute__((unused)) FX_initialize_txid()
for(uint8_t i=1;i<FX_NUM_CHANNELS;i++)
hopping_frequency[i] = i*10 + hopping_frequency[0];
}
else // FX9630 & FX_Q560 & FX_QF012
else // FX9630 & FX_Q560 & FX_QF012 & FX_BM26
{
//??? 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;
@@ -245,6 +274,7 @@ 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)
}
}
@@ -288,9 +318,11 @@ 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 = low voltage 3.7V
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]);

View File

@@ -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,FX816,FX620,9630,Q560,QF012,BM26,FX818
59,Bayang_RX,Multi,CPPM
60,Pelikan,Pro,Lite,SCX24
61,EazyRC
@@ -102,3 +102,4 @@
104,KAMTOM
105,Shenqi2
106,WL91x
107,WPL

View File

@@ -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)||58|FX816|FX620|9630|Q560|QF012|FX818|||NRF24L01|
[FX](Protocols_Details.md#FX---58)||58|FX816|FX620|9630|Q560|QF012|BM26|FX818||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
@@ -1894,7 +1894,18 @@ Gyro: -100%=6G, 0%=3D+Gyro, +100%=3D
Reset: Restore fine tunning midpoint
### Sub_protocol FX818 - *5*
### 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|LEDs|Turning Light switch|Calib
Gyro: -100%=6G, 0%=3D+Gyro, +100%=3D
### Sub_protocol FX818 - *6*
Model: FX818/FX820/FX822/FX823
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.