New Protocol: PROPEL

Compatible model: PROPEL 74-Z Speeder Bike
Protcol: PROPEL (66)
Sub protocol: none
Autobind protocol
Extended limits not supported
Telemetry supported
14 channels in use due to many features
This commit is contained in:
Pascal Langer 2020-04-03 19:36:05 +02:00
parent cab782b38e
commit 0a5b97a177
10 changed files with 365 additions and 11 deletions

View File

@ -256,10 +256,6 @@ static void __attribute__((unused)) FrSkyX_build_packet()
uint16_t ReadFrSkyX()
{
#ifdef DEBUG_SERIAL
static uint16_t fr_time=0;
#endif
switch(state)
{
default:

View File

@ -63,3 +63,4 @@
63,XN_DUMP,250K,1M,2M,AUTO
64,FrskyX2,CH_16,CH_8,EU_16,EU_8
65,FrSkyR9,915MHz,868MHz,915_8ch,868_8ch
66,PROPEL,74-Z

View File

@ -79,6 +79,7 @@ const char STR_TIGER[] ="Tiger";
const char STR_XK[] ="XK";
const char STR_XN297DUMP[] ="XN297DP";
const char STR_FRSKYR9[] ="FrSkyR9";
const char STR_PROPEL[] ="PROPEL";
const char STR_SUBTYPE_FLYSKY[] = "\x04""Std\0""V9x9""V6x6""V912""CX20";
const char STR_SUBTYPE_HUBSAN[] = "\x04""H107""H301""H501";
@ -121,6 +122,7 @@ const char STR_SUBTYPE_V911S[] = "\x05""V911S""E119\0";
const char STR_SUBTYPE_XK[] = "\x04""X450""X420";
const char STR_SUBTYPE_FRSKYR9[] = "\x07""915MHz\0""868MHz\0""915 8ch""868 8ch";
const char STR_SUBTYPE_ESKY[] = "\x03""Std""ET4";
const char STR_SUBTYPE_PROPEL[] = "\x04""74-Z";
enum
{
@ -327,7 +329,10 @@ const mm_protocol_definition multi_protocols[] = {
{PROTO_XN297DUMP, STR_XN297DUMP, 4, STR_SUBTYPE_XN297DUMP, OPTION_RFCHAN },
#endif
#if defined(FRSKYR9_SX1276_INO)
{PROTO_FRSKY_R9, STR_FRSKYR9, 4, STR_SUBTYPE_FRSKYR9, OPTION_NONE },
{PROTO_FRSKY_R9, STR_FRSKYR9, 4, STR_SUBTYPE_FRSKYR9, OPTION_NONE },
#endif
#if defined(PROPEL_NRF24L01_INO)
{PROTO_PROPEL, STR_PROPEL, 4, STR_SUBTYPE_PROPEL, OPTION_NONE },
#endif
{0x00, nullptr, 0, nullptr, 0 }
};

View File

@ -19,7 +19,7 @@
#define VERSION_MAJOR 1
#define VERSION_MINOR 3
#define VERSION_REVISION 0
#define VERSION_PATCH_LEVEL 79
#define VERSION_PATCH_LEVEL 80
//******************
// Protocols
@ -92,6 +92,7 @@ enum PROTOCOLS
PROTO_XN297DUMP = 63, // =>NRF24L01
PROTO_FRSKYX2 = 64, // =>CC2500
PROTO_FRSKY_R9 = 65, // =>SX1276
PROTO_PROPEL = 66, // =>NRF24L01
};
enum Flysky
@ -727,6 +728,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p --
XN297DUMP 63
FRSKYX2 64
FRSKY_R9 65
PROPEL 66
BindBit=> 0x80 1=Bind/0=No
AutoBindBit=> 0x40 1=Yes /0=No
RangeCheck=> 0x20 1=Yes /0=No

View File

@ -737,7 +737,7 @@ bool Update_All()
update_led_status();
#if defined(TELEMETRY)
#if ( !( defined(MULTI_TELEMETRY) || defined(MULTI_STATUS) ) )
if((protocol == PROTO_BAYANG_RX) || (protocol == PROTO_AFHDS2A_RX) || (protocol == PROTO_FRSKY_RX) || (protocol == PROTO_SCANNER) || (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) || (protocol==PROTO_HOTT) || (protocol==PROTO_FRSKYX2))
if((protocol == PROTO_BAYANG_RX) || (protocol == PROTO_AFHDS2A_RX) || (protocol == PROTO_FRSKY_RX) || (protocol == PROTO_SCANNER) || (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) || (protocol==PROTO_HOTT) || (protocol==PROTO_FRSKYX2) || (protocol==PROTO_PROPEL))
#endif
if(IS_DISABLE_TELEM_off)
TelemetryUpdate();
@ -1485,6 +1485,12 @@ static void protocol_init()
remote_callback = XK_callback;
break;
#endif
#if defined(PROPEL_NRF24L01_INO)
case PROTO_PROPEL:
next_callback=initPROPEL();
remote_callback = PROPEL_callback;
break;
#endif
#if defined(XN297DUMP_NRF24L01_INO)
case PROTO_XN297DUMP:
next_callback=initXN297Dump();
@ -2067,7 +2073,7 @@ void pollBoot()
#if defined(TELEMETRY)
void PPM_Telemetry_serial_init()
{
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)
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) || (protocol==PROTO_PROPEL)
#ifdef TELEMETRY_FRSKYX_TO_FRSKYD
|| (protocol==PROTO_FRSKYX) || (protocol==PROTO_FRSKYX2)
#endif

View File

@ -0,0 +1,328 @@
/*
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 PROPEL 74-Z Speeder Bike.
#if defined(PROPEL_NRF24L01_INO)
#include "iface_nrf24l01.h"
//#define PROPEL_FORCE_ID
#define PROPEL_INITIAL_WAIT 500
#define PROPEL_PACKET_PERIOD 10000
#define PROPEL_BIND_RF_CHANNEL 0x23
#define PROPEL_PAYLOAD_SIZE 16
#define PROPEL_SEARCH_PERIOD 50 //*10ms
#define PROPEL_BIND_PERIOD 1500
#define PROPEL_PACKET_SIZE 14
#define PROPEL_RF_NUM_CHANNELS 4
#define PROPEL_ADDRESS_LENGTH 5
#define PROPEL_DEFAULT_PERIOD 20
enum {
PROPEL_BIND1 = 0,
PROPEL_BIND2,
PROPEL_BIND3,
PROPEL_DATA1,
};
static uint16_t __attribute__((unused)) PROPEL_checksum()
{
typedef union {
struct {
uint8_t h:1;
uint8_t g:1;
uint8_t f:1;
uint8_t e:1;
uint8_t d:1;
uint8_t c:1;
uint8_t b:1;
uint8_t a:1;
} bits;
uint8_t byte:8;
} byte_bits_t;
uint8_t sum = packet[0];
for (uint8_t i = 1; i < PROPEL_PACKET_SIZE - 2; i++)
sum += packet[i];
byte_bits_t in = { .byte = sum };
byte_bits_t out = { .byte = sum };
out.byte ^= 0x0a;
out.bits.d = !(in.bits.d ^ in.bits.h);
out.bits.c = (!in.bits.c && !in.bits.d && in.bits.g)
|| (in.bits.c && !in.bits.d && !in.bits.g)
|| (!in.bits.c && in.bits.g && !in.bits.h)
|| (in.bits.c && !in.bits.g && !in.bits.h)
|| (in.bits.c && in.bits.d && in.bits.g && in.bits.h)
|| (!in.bits.c && in.bits.d && !in.bits.g && in.bits.h);
out.bits.b = (!in.bits.b && !in.bits.c && !in.bits.d)
|| (in.bits.b && in.bits.c && in.bits.g)
|| (!in.bits.b && !in.bits.c && !in.bits.g)
|| (!in.bits.b && !in.bits.d && !in.bits.g)
|| (!in.bits.b && !in.bits.c && !in.bits.h)
|| (!in.bits.b && !in.bits.g && !in.bits.h)
|| (in.bits.b && in.bits.c && in.bits.d && in.bits.h)
|| (in.bits.b && in.bits.d && in.bits.g && in.bits.h);
out.bits.a = (in.bits.a && !in.bits.b)
|| (in.bits.a && !in.bits.c && !in.bits.d)
|| (in.bits.a && !in.bits.c && !in.bits.g)
|| (in.bits.a && !in.bits.d && !in.bits.g)
|| (in.bits.a && !in.bits.c && !in.bits.h)
|| (in.bits.a && !in.bits.g && !in.bits.h)
|| (!in.bits.a && in.bits.b && in.bits.c && in.bits.g)
|| (!in.bits.a && in.bits.b && in.bits.c && in.bits.d && in.bits.h)
|| (!in.bits.a && in.bits.b && in.bits.d && in.bits.g && in.bits.h);
return (sum << 8) | (out.byte & 0xff);
}
static void __attribute__((unused)) PROPEL_bind_packet(bool valid_rx_id)
{
memset(packet, 0, PROPEL_PACKET_SIZE);
packet[0] = 0xD0;
memcpy(&packet[1], rx_tx_addr, 4); // only 4 bytes sent of 5-byte address
if (valid_rx_id) memcpy(&packet[5], rx_id, 4);
packet[9] = rf_ch_num; // hopping table to be used when switching to normal mode
packet[11] = 0x05; // unknown, 0x01 on TX2??
uint16_t check = PROPEL_checksum();
packet[12] = check >> 8;
packet[13] = check & 0xff;
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)));
NRF24L01_FlushTx();
NRF24L01_FlushRx();
NRF24L01_WritePayload(packet, PROPEL_PACKET_SIZE);
}
static void __attribute__((unused)) PROPEL_data_packet()
{
memset(packet, 0, PROPEL_PACKET_SIZE);
packet[0] = 0xC0;
packet[1] = convert_channel_16b_limit(THROTTLE, 0x2f, 0xcf);
packet[2] = convert_channel_16b_limit(RUDDER , 0xcf, 0x2f);
packet[3] = convert_channel_16b_limit(ELEVATOR, 0x2f, 0xcf);
packet[4] = convert_channel_16b_limit(AILERON , 0xcf, 0x2f);
packet[5] = 0x40; //might be trims but unsused
packet[6] = 0x40; //might be trims but unsused
packet[7] = 0x40; //might be trims but unsused
packet[8] = 0x40; //might be trims but unsused
if (bind_phase)
{//need to send a couple of default packets after bind
bind_phase--;
packet[10] = 0x80; // LEDs
}
else
{
packet[9] = 0x02 // Always fast speed, slow=0x00, medium=0x01, fast=0x02, 0x03=flight training mode
| GET_FLAG( CH14_SW, 0x03) // Flight training mode
| GET_FLAG( CH10_SW, 0x04) // Calibrate
| GET_FLAG( CH12_SW, 0x08) // Take off
| GET_FLAG( CH8_SW, 0x10) // Fire
| GET_FLAG( CH11_SW, 0x20) // Altitude hold=0x20
| GET_FLAG( CH6_SW, 0x40) // Roll CW
| GET_FLAG( CH7_SW, 0x80); // Roll CCW
packet[10] = GET_FLAG( CH13_SW, 0x20) // Land
| GET_FLAG( CH9_SW, 0x40) // Weapon system activted=0x40
| GET_FLAG(!CH5_SW, 0x80); // LEDs
}
packet[11] = 5; // unknown, 0x01 on TX2??
uint16_t check = PROPEL_checksum();
packet[12] = check >> 8;
packet[13] = check & 0xff;
NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]);
hopping_frequency_no &= 0x03;
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, (_BV(NRF24L01_07_RX_DR) | _BV(NRF24L01_07_TX_DS) | _BV(NRF24L01_07_MAX_RT)));
NRF24L01_FlushTx();
NRF24L01_WritePayload(packet, PROPEL_PACKET_SIZE);
}
static void __attribute__((unused)) PROPEL_init()
{
NRF24L01_Initialize();
NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x7f);
NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3f); // AA on all pipes
NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x3f); // Enable all pipes
NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte address
NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x36); // retransmit 1ms, 6 times
NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps
NRF24L01_SetPower();
NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x07); // ?? match protocol capture
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x99\x77\x55\x33\x11", PROPEL_ADDRESS_LENGTH); //Bind address
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x99\x77\x55\x33\x11", PROPEL_ADDRESS_LENGTH); //Bind address
NRF24L01_WriteReg(NRF24L01_05_RF_CH, PROPEL_BIND_RF_CHANNEL);
NRF24L01_Activate(0x73); // Activate feature register
NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); // Enable dynamic payload length
NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); // Enable all features
// Beken 2425 register bank 1 initialized here in stock tx capture
// Hopefully won't matter for nRF compatibility
NRF24L01_FlushTx();
NRF24L01_SetTxRxMode(TX_EN);
}
const uint8_t PROGMEM PROPEL_hopping []= { 0x47,0x36,0x27,0x44,0x33,0x0D,0x3C,0x2E,0x1B,0x39,0x2A,0x18 };
static void __attribute__((unused)) PROPEL_initialize_txid()
{
//address last byte
rx_tx_addr[4]=0x11;
//random hopping channel table
rf_ch_num=random(0xfefefefe)&0x03;
for(uint8_t i=0; i<3; i++)
hopping_frequency[i]=pgm_read_byte_near( &PROPEL_hopping[i + 3*rf_ch_num] );
hopping_frequency[3]=0x23;
#ifdef PROPEL_FORCE_ID
if(RX_num&1)
memcpy(rx_tx_addr, (uint8_t *)"\x73\xd3\x31\x30\x11", PROPEL_ADDRESS_LENGTH); //TX1: 73 d3 31 30 11
else
memcpy(rx_tx_addr, (uint8_t *)"\x94\xc5\x31\x30\x11", PROPEL_ADDRESS_LENGTH); //TX2: 94 c5 31 30 11
rf_ch_num = 0x03; //TX1
memcpy(hopping_frequency,(uint8_t *)"\x39\x2A\x18\x23",PROPEL_RF_NUM_CHANNELS); //TX1: 57,42,24,35
rf_ch_num = 0x00; //TX2
memcpy(hopping_frequency,(uint8_t *)"\x47\x36\x27\x23",PROPEL_RF_NUM_CHANNELS); //TX2: 71,54,39,35
rf_ch_num = 0x01; // Manual search
memcpy(hopping_frequency,(uint8_t *)"\x44\x33\x0D\x23",PROPEL_RF_NUM_CHANNELS); //Manual: 68,51,13,35
rf_ch_num = 0x02; // Manual search
memcpy(hopping_frequency,(uint8_t *)"\x3C\x2E\x1B\x23",PROPEL_RF_NUM_CHANNELS); //Manual: 60,46,27,35
#endif
}
uint16_t PROPEL_callback()
{
uint8_t status;
switch (phase)
{
case PROPEL_BIND1:
PROPEL_bind_packet(false); //rx_id unknown
phase++; //BIND2
return PROPEL_BIND_PERIOD;
case PROPEL_BIND2:
status=NRF24L01_ReadReg(NRF24L01_07_STATUS);
if (status & _BV(NRF24L01_07_MAX_RT))
{// Max retry (6) reached
phase = PROPEL_BIND1;
return PROPEL_BIND_PERIOD;
}
if (!(_BV(NRF24L01_07_RX_DR) & status))
return PROPEL_BIND_PERIOD; // nothing received
// received frame, got rx_id, save it
NRF24L01_ReadPayload(packet_in, PROPEL_PACKET_SIZE);
memcpy(rx_id, &packet_in[1], 4);
PROPEL_bind_packet(true); //send bind packet with rx_id
phase++; //BIND3
break;
case PROPEL_BIND3:
if (_BV(NRF24L01_07_RX_DR) & NRF24L01_ReadReg(NRF24L01_07_STATUS))
{
NRF24L01_ReadPayload(packet_in, PROPEL_PACKET_SIZE);
if (packet_in[0] == 0xa3 && memcmp(&packet_in[1],rx_id,4)==0)
{//confirmation from the model
phase++; //PROPEL_DATA1
bind_phase=PROPEL_DEFAULT_PERIOD;
packet_count=0;
BIND_DONE;
break;
}
}
NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, PROPEL_ADDRESS_LENGTH);
NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, PROPEL_ADDRESS_LENGTH);
PROPEL_bind_packet(true); //send bind packet with rx_id
break;
case PROPEL_DATA1:
if (_BV(NRF24L01_07_RX_DR) & NRF24L01_ReadReg(NRF24L01_07_STATUS))
{// data received from the model
NRF24L01_ReadPayload(packet_in, PROPEL_PACKET_SIZE);
if (packet_in[0] == 0xa3 && memcmp(&packet_in[1],rx_id,4)==0)
{
telemetry_counter++; //LQI
v_lipo1=packet[5]; //number of life left?
if(telemetry_lost==0)
telemetry_link=1;
}
}
PROPEL_data_packet();
packet_count++;
if(packet_count>=100)
{//LQI calculation
packet_count=0;
TX_LQI=telemetry_counter;
RX_RSSI=telemetry_counter;
telemetry_counter = 0;
telemetry_lost=0;
}
break;
}
return PROPEL_PACKET_PERIOD;
}
uint16_t initPROPEL()
{
BIND_IN_PROGRESS; // autobind protocol
PROPEL_initialize_txid();
PROPEL_init();
hopping_frequency_no = 0;
phase=PROPEL_BIND1;
return PROPEL_INITIAL_WAIT;
}
#endif
// equations for checksum check byte from truth table
// (1) z = a && !b
// || a && !c && !d
// || a && !c && !g
// || a && !d && !g
// || a && !c && !h
// || a && !g && !h
// || !a && b && c && g
// || !a && b && c && d && h
// || !a && b && d && g && h;
//
// (2) y = !b && !c && !d
// || b && c && g
// || !b && !c && !g
// || !b && !d && !g
// || !b && !c && !h
// || !b && !g && !h
// || b && c && d && h
// || b && d && g && h;
//
// (3) x = !c && !d && g
// || c && !d && !g
// || !c && g && !h
// || c && !g && !h
// || c && d && g && h
// || !c && d && !g && h;
//
// (4) w = d && h
// || !d && !h;
//
// (5) v = !e;
//
// (6) u = f;
//
// (7) t = !g;
//
// (8) s = h;

View File

@ -514,7 +514,7 @@ void frsky_link_frame()
telemetry_link |= 2 ; // Send hub if available
}
else
{//PROTO_HUBSAN, PROTO_AFHDS2A, PROTO_BAYANG, PROTO_NCC1701, PROTO_CABELL, PROTO_HITEC, PROTO_BUGS, PROTO_BUGSMINI, PROTO_FRSKYX, PROTO_FRSKYX2
{//PROTO_HUBSAN, PROTO_AFHDS2A, PROTO_BAYANG, PROTO_NCC1701, PROTO_CABELL, PROTO_HITEC, PROTO_BUGS, PROTO_BUGSMINI, PROTO_FRSKYX, PROTO_FRSKYX2, PROTO_PROPEL
frame[1] = v_lipo1;
frame[2] = v_lipo2;
frame[3] = RX_RSSI;
@ -935,7 +935,7 @@ void TelemetryUpdate()
#endif
if( telemetry_link & 1 )
{ // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + BugsMini + NCC1701
{ // FrSkyD + Hubsan + AFHDS2A + Bayang + Cabell + Hitec + Bugs + BugsMini + NCC1701 + PROPEL
// FrSkyX telemetry if in PPM
frsky_link_frame();
return;

View File

@ -250,6 +250,7 @@
#undef BAYANG_RX_NRF24L01_INO
#undef TIGER_NRF24L01_INO
#undef XK_NRF24L01_INO
#undef PROPEL_NRF24L01_INO
#endif
#if not defined(STM32_BOARD)
#undef SX1276_INSTALLED

View File

@ -212,6 +212,7 @@
#define MT99XX_NRF24L01_INO
#define NCC1701_NRF24L01_INO
#define POTENSIC_NRF24L01_INO
#define PROPEL_NRF24L01_INO
#define Q303_NRF24L01_INO
#define SHENQI_NRF24L01_INO
#define SLT_NRF24L01_INO
@ -638,6 +639,8 @@ const PPM_Parameters PPM_prot[14*NBR_BANKS]= {
NONE
PROTO_POTENSIC
NONE
PROTO_PROPEL
NONE
PROTO_Q2X2
Q222
Q242

View File

@ -112,6 +112,7 @@ CFlie|38|CFlie||||||||NRF24L01|
[OpenLRS](Protocols_Details.md#OpenLRS---27)|27|||||||||None|
[Pelikan](Protocols_Details.md#Pelikan---60)|60|||||||||A7105|
[Potensic](Protocols_Details.md#Potensic---51)|51|A20||||||||NRF24L01|XN297
[PROPEL](Protocols_Details.md#PROPEL---66)|66|74-Z||||||||NRF24L01|
[Q2X2](Protocols_Details.md#Q2X2---29)|29|Q222|Q242|Q282||||||NRF24L01|
[Q303](Protocols_Details.md#Q303---31)|31|Q303|CX35|CX10D|CX10WD|||||NRF24L01|XN297
[Redpine](Protocols_Details.md#Redpine---50)|50|FAST|SLOW|||||||NRF24L01|
@ -1107,7 +1108,7 @@ CH1|CH2|CH3|CH4|CH5
A|E|T|R|Warp
## Potensic - *51*
Models: Potensic A20
Model: Potensic A20
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8
---|---|---|---|---|---|---|---
@ -1121,6 +1122,17 @@ MODE: Beginner -100%, Medium 0%, Advanced +100%
HEADLESS: Off -100%, On +100%
## PROPEL - *66*
Model: PROPEL 74-Z Speeder Bike
Autobind protocol
Telemetry: RSSI is equal to TX_LQI which indicates how well the TX receives the RX (0-100%). A1 voltage should indicate the numbers of life remaining (not tested).
CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14
---|---|---|---|---|---|---|---|---|----|----|----|----|----
A|E|T|R|LEDs|RollCW|RollCCW|Fire|Weapons|Calib|Alt_Hold|Take_off|Land|Training
## Q2X2 - *29*
### Sub_protocol Q222 - *0*
Models: Q222 v1 and V686 v2