Skip to content

Commit

Permalink
Added demag and stall events to edt status frame
Browse files Browse the repository at this point in the history
Fixed demag osd_warning

Added fix for incorrect RPM debug values writtings in debug buffer

Updated dshot status frame

Added debug capabilities to dshot edt frames. DBG3 edt frame becomes demag metric frame

DSHOT debug data packs 5 signals in a value. Added command to check debug data

Added retries to activate EDT, because sometimes EDT is not successfully activated

Added debug modes to be in sync between betaflight, betaflight-configurator and blackbox-explorer. Some of others will be deleted on future merge
  • Loading branch information
damosvil committed Jan 21, 2023
1 parent fb29036 commit 5a94fbc
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 43 deletions.
8 changes: 8 additions & 0 deletions src/main/build/debug.c
Expand Up @@ -107,5 +107,13 @@ const char * const debugModeNames[DEBUG_COUNT] = {
"ATTITUDE",
"VTX_MSP",
"GPS_DOP",
"ANGLEMODE",
"FAILSAFE",
"DSHOT_STATUS_N_TEMPERATURE",
"DSHOT_STATUS_N_VOLTAGE",
"DSHOT_STATUS_N_CURRENT",
"DSHOT_STATUS_N_DEBUG1",
"DSHOT_STATUS_N_DEBUG2",
"DSHOT_STATUS_N_DEMAG_METRIC",
"DSHOT_STATUS_N_ERPM_FRACTION",
};
8 changes: 8 additions & 0 deletions src/main/build/debug.h
Expand Up @@ -105,7 +105,15 @@ typedef enum {
DEBUG_ATTITUDE,
DEBUG_VTX_MSP,
DEBUG_GPS_DOP,
DEBUG_ANGLEMODE,
DEBUG_FAILSAFE,
DEBUG_DSHOT_STATUS_N_TEMPERATURE,
DEBUG_DSHOT_STATUS_N_VOLTAGE,
DEBUG_DSHOT_STATUS_N_CURRENT,
DEBUG_DSHOT_STATUS_N_DEBUG1,
DEBUG_DSHOT_STATUS_N_DEBUG2,
DEBUG_DSHOT_STATUS_N_DEMAG_METRIC,
DEBUG_DSHOT_STATUS_N_ERPM_FRACTION_18,
DEBUG_COUNT
} debugType_e;

Expand Down
22 changes: 16 additions & 6 deletions src/main/cli/cli.c
Expand Up @@ -6126,10 +6126,10 @@ static void cliDshotTelemetryInfo(const char *cmdName, char *cmdline)
cliPrintLinefeed();

#ifdef USE_DSHOT_TELEMETRY_STATS
cliPrintLine("Motor Type eRPM RPM Hz Invalid TEMP VCC CURR ST/EV DBG1 DBG2 DBG3");
cliPrintLine("Motor Type eRPM RPM Hz Invalid TEMP VCC CURR STAT DBG1 DBG2 DMET");
cliPrintLine("===== ====== ====== ====== ====== ======= ====== ====== ====== ====== ====== ====== ======");
#else
cliPrintLine("Motor Type eRPM RPM Hz TEMP VCC CURR ST/EV DBG1 DBG2 DBG3");
cliPrintLine("Motor Type eRPM RPM Hz TEMP VCC CURR STAT DBG1 DBG2 DMET");
cliPrintLine("===== ====== ====== ====== ====== ====== ====== ====== ====== ====== ====== ======");
#endif

Expand All @@ -6143,7 +6143,7 @@ static void cliDshotTelemetryInfo(const char *cmdName, char *cmdline)
((dshotTelemetryState.motorState[i].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_TEMPERATURE)) ? 'T' : '-'),
((dshotTelemetryState.motorState[i].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_VOLTAGE)) ? 'V' : '-'),
((dshotTelemetryState.motorState[i].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_CURRENT)) ? 'C' : '-'),
((dshotTelemetryState.motorState[i].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_STATE_EVENTS)) ? 'S' : '-'),
((dshotTelemetryState.motorState[i].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_STATUS)) ? 'S' : '-'),
erpm * 100, rpm, rpm / 60);

#ifdef USE_DSHOT_TELEMETRY_STATS
Expand All @@ -6155,15 +6155,15 @@ static void cliDshotTelemetryInfo(const char *cmdName, char *cmdline)
}
#endif

cliPrintLinef(" %6d %3d.%02d %6d %6d %6d %6d %6d",
cliPrintLinef(" %6d %3d.%02d %6d %6x %6d %6d %6d",
dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_TEMPERATURE],
dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_VOLTAGE] / 4,
25 * (dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_VOLTAGE] % 4),
dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_CURRENT],
dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_STATE_EVENTS],
dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS],
dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_DEBUG1],
dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_DEBUG2],
dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_DEBUG3]
dshotTelemetryState.motorState[i].telemetryData[DSHOT_TELEMETRY_TYPE_DEMAG_METRIC]
);
}
cliPrintLinefeed();
Expand Down Expand Up @@ -6395,6 +6395,15 @@ static void printConfig(const char *cmdName, char *cmdline, bool doDiff)
restoreConfigs(0);
}

static void showDebugInfo(const char *cmdName, char *cmdline)
{
(void)cmdName;
(void)cmdline;
cliPrintLinef("Mode: %s", debugModeNames[debugMode]);
cliPrintLinef("Dec: %d %d %d %d", debug[0], debug[1], debug[2], debug[3]);
cliPrintLinef("Hex: %04X %04X %04X %04X", debug[0], debug[1], debug[2], debug[3]);
}

static void cliDump(const char *cmdName, char *cmdline)
{
printConfig(cmdName, cmdline, false);
Expand Down Expand Up @@ -6625,6 +6634,7 @@ const clicmd_t cmdTable[] = {
CLI_COMMAND_DEF("vtx_info", "vtx power config dump", NULL, cliVtxInfo),
CLI_COMMAND_DEF("vtxtable", "vtx frequency table", "<band> <bandname> <bandletter> [FACTORY|CUSTOM] <freq> ... <freq>\r\n", cliVtxTable),
#endif
CLI_COMMAND_DEF("debug_info", "show debug info", NULL, showDebugInfo),
};

static void cliHelp(const char *cmdName, char *cmdline)
Expand Down
81 changes: 63 additions & 18 deletions src/main/drivers/dshot.c
Expand Up @@ -31,6 +31,7 @@

#include "build/debug.h"
#include "build/atomic.h"
#include "build/debug.h"

#include "common/maths.h"

Expand All @@ -47,6 +48,10 @@
#include "rx/rx.h"
#include "dshot.h"

#define SHIFT_BYTE (8u)
#define MULTIPLE_RPM300_ERPM_FRACTION (18u)


void dshotInitEndpoints(const motorConfig_t *motorConfig, float outputLimit, float *outputLow, float *outputHigh, float *disarm, float *deadbandMotor3dHigh, float *deadbandMotor3dLow)
{
float outputLimitOffset = DSHOT_RANGE * (1 - outputLimit);
Expand Down Expand Up @@ -154,6 +159,7 @@ static uint32_t dshot_decode_eRPM_telemetry_value(uint16_t value)

static void dshot_decode_telemetry_value(uint8_t motorIndex, uint32_t *pDecoded, dshotTelemetryType_t *pType)
{
uint16_t dshotDebugHighByte;
uint16_t value = dshotTelemetryState.motorState[motorIndex].rawValue;

if (dshotTelemetryState.motorState[motorIndex].telemetryTypes == DSHOT_NORMAL_TELEMETRY_MASK) { /* Check DSHOT_TELEMETRY_TYPE_eRPM mask */
Expand All @@ -169,62 +175,98 @@ static void dshot_decode_telemetry_value(uint8_t motorIndex, uint32_t *pDecoded,
*pType = DSHOT_TELEMETRY_TYPE_eRPM;
} else {
// Decode Extended DSHOT telemetry
switch (value & 0x0f00) {
switch (value & DSHOT_TELEMETRY_RANGE_MASK) {

case 0x0200:
case DSHOT_TELEMETRY_RANGE_TEMPERATURE:
// Temperature range (in degree Celsius, just like Blheli_32 and KISS)
*pDecoded = value & 0x00ff;
*pDecoded = value & DSHOT_TELEMETRY_VALUE_MASK;

// Update debug buffer
if (motorIndex < 4) {
dshotDebugHighByte = dshotTelemetryState.motorState[motorIndex].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] << SHIFT_BYTE;
DEBUG_SET(DEBUG_DSHOT_STATUS_N_TEMPERATURE, motorIndex, dshotDebugHighByte | *pDecoded);
}

// Set telemetry type
*pType = DSHOT_TELEMETRY_TYPE_TEMPERATURE;
break;

case 0x0400:
case DSHOT_TELEMETRY_RANGE_VOLTAGE:
// Voltage range (0-63,75V step 0,25V)
*pDecoded = value & 0x00ff;
*pDecoded = value & DSHOT_TELEMETRY_VALUE_MASK;

// Update debug buffer
if (motorIndex < 4) {
dshotDebugHighByte = dshotTelemetryState.motorState[motorIndex].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] << SHIFT_BYTE;
DEBUG_SET(DEBUG_DSHOT_STATUS_N_VOLTAGE, motorIndex, dshotDebugHighByte | *pDecoded);
}

// Set telemetry type
*pType = DSHOT_TELEMETRY_TYPE_VOLTAGE;
break;

case 0x0600:
case DSHOT_TELEMETRY_RANGE_CURRENT:
// Current range (0-255A step 1A)
*pDecoded = value & 0x00ff;
*pDecoded = value & DSHOT_TELEMETRY_VALUE_MASK;

// Update debug buffer
if (motorIndex < 4) {
dshotDebugHighByte = dshotTelemetryState.motorState[motorIndex].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] << SHIFT_BYTE;
DEBUG_SET(DEBUG_DSHOT_STATUS_N_CURRENT, motorIndex, dshotDebugHighByte | *pDecoded);
}

// Set telemetry type
*pType = DSHOT_TELEMETRY_TYPE_CURRENT;
break;

case 0x0800:
case DSHOT_TELEMETRY_RANGE_DEBUG1:
// Debug 1 value
*pDecoded = value & 0x00ff;
*pDecoded = value & DSHOT_TELEMETRY_VALUE_MASK;

// Update debug buffer
if (motorIndex < 4) {
dshotDebugHighByte = dshotTelemetryState.motorState[motorIndex].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] << SHIFT_BYTE;
DEBUG_SET(DEBUG_DSHOT_STATUS_N_DEBUG1, motorIndex, dshotDebugHighByte | *pDecoded);
}

// Set telemetry type
*pType = DSHOT_TELEMETRY_TYPE_DEBUG1;
break;

case 0x0A00:
case DSHOT_TELEMETRY_RANGE_DEBUG2:
// Debug 2 value
*pDecoded = value & 0x00ff;
*pDecoded = value & DSHOT_TELEMETRY_VALUE_MASK;

// Update debug buffer
if (motorIndex < 4) {
dshotDebugHighByte = dshotTelemetryState.motorState[motorIndex].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] << SHIFT_BYTE;
DEBUG_SET(DEBUG_DSHOT_STATUS_N_DEBUG2, motorIndex, dshotDebugHighByte | *pDecoded);
}

// Set telemetry type
*pType = DSHOT_TELEMETRY_TYPE_DEBUG2;
break;

case 0x0C00:
// Debug 3 value
*pDecoded = value & 0x00ff;
case DSHOT_TELEMETRY_RANGE_DEMAG_METRIC:
// Demag metric value
*pDecoded = value & DSHOT_TELEMETRY_VALUE_MASK;

// Update debug buffer
if (motorIndex < 4) {
dshotDebugHighByte = dshotTelemetryState.motorState[motorIndex].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] << SHIFT_BYTE;
DEBUG_SET(DEBUG_DSHOT_STATUS_N_DEMAG_METRIC, motorIndex, dshotDebugHighByte | *pDecoded);
}

// Set telemetry type
*pType = DSHOT_TELEMETRY_TYPE_DEBUG3;
*pType = DSHOT_TELEMETRY_TYPE_DEMAG_METRIC;
break;

case 0x0E00:
case DSHOT_TELEMETRY_RANGE_STATUS:
// State / events
*pDecoded = value & 0x00ff;
*pDecoded = value & DSHOT_TELEMETRY_VALUE_MASK;

// Set telemetry type
*pType = DSHOT_TELEMETRY_TYPE_STATE_EVENTS;
*pType = DSHOT_TELEMETRY_TYPE_STATUS;
break;

default:
Expand All @@ -233,6 +275,9 @@ static void dshot_decode_telemetry_value(uint8_t motorIndex, uint32_t *pDecoded,

// Update debug buffer
if (motorIndex < 4) {
// In this case two debug options to maximize logging info
dshotDebugHighByte = dshotTelemetryState.motorState[motorIndex].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] << SHIFT_BYTE;
DEBUG_SET(DEBUG_DSHOT_STATUS_N_ERPM_FRACTION_18, motorIndex, dshotDebugHighByte | ((*pDecoded) / MULTIPLE_RPM300_ERPM_FRACTION));
DEBUG_SET(DEBUG_DSHOT_RPM_TELEMETRY, motorIndex, *pDecoded);
}

Expand Down
24 changes: 20 additions & 4 deletions src/main/drivers/dshot.h
Expand Up @@ -54,8 +54,14 @@ typedef struct dshotTelemetryQuality_s {
extern dshotTelemetryQuality_t dshotTelemetryQuality[MAX_SUPPORTED_MOTORS];
#endif // USE_DSHOT_TELEMETRY_STATS

#define DSHOT_NORMAL_TELEMETRY_MASK (1 << DSHOT_TELEMETRY_TYPE_eRPM)
#define DSHOT_EXTENDED_TELEMETRY_MASK (~DSHOT_NORMAL_TELEMETRY_MASK)
#define DSHOT_NORMAL_TELEMETRY_MASK (1 << DSHOT_TELEMETRY_TYPE_eRPM)
#define DSHOT_EXTENDED_TELEMETRY_MASK (~DSHOT_NORMAL_TELEMETRY_MASK)
#define DSHOT_TELEMETRY_RANGE_MASK (0x0f00u)
#define DSHOT_TELEMETRY_VALUE_MASK (0x00ffu)
#define DSHOT_TELEMETRY_STATUS_DEMAG_EVENT_MASK (0x80u)
#define DSHOT_TELEMETRY_STATUS_DESYNC_EVENT_MASK (0x40u)
#define DSHOT_TELEMETRY_STATUS_STALL_EVENT_MASK (0x20u)
#define DSHOT_TELEMETRY_STATUS_DEMAG_METRIC_MASK (0x0Fu)

typedef enum dshotTelemetryType_e {
DSHOT_TELEMETRY_TYPE_eRPM = 0,
Expand All @@ -64,11 +70,21 @@ typedef enum dshotTelemetryType_e {
DSHOT_TELEMETRY_TYPE_CURRENT = 3,
DSHOT_TELEMETRY_TYPE_DEBUG1 = 4,
DSHOT_TELEMETRY_TYPE_DEBUG2 = 5,
DSHOT_TELEMETRY_TYPE_DEBUG3 = 6,
DSHOT_TELEMETRY_TYPE_STATE_EVENTS = 7,
DSHOT_TELEMETRY_TYPE_DEMAG_METRIC = 6,
DSHOT_TELEMETRY_TYPE_STATUS = 7,
DSHOT_TELEMETRY_TYPE_COUNT = 8
} dshotTelemetryType_t;

typedef enum dshotTelemetryRange_e {
DSHOT_TELEMETRY_RANGE_TEMPERATURE = 0x200,
DSHOT_TELEMETRY_RANGE_VOLTAGE = 0x400,
DSHOT_TELEMETRY_RANGE_CURRENT = 0x600,
DSHOT_TELEMETRY_RANGE_DEBUG1 = 0x800,
DSHOT_TELEMETRY_RANGE_DEBUG2 = 0xA00,
DSHOT_TELEMETRY_RANGE_DEMAG_METRIC = 0xC00,
DSHOT_TELEMETRY_RANGE_STATUS = 0xE00
} dshotTelemetryRange_t;

typedef enum dshotRawValueState_e {
DSHOT_RAW_VALUE_STATE_INVALID = 0,
DSHOT_RAW_VALUE_STATE_NOT_PROCESSED = 1,
Expand Down
2 changes: 1 addition & 1 deletion src/main/drivers/dshot_bitbang.c
Expand Up @@ -541,7 +541,7 @@ static bool bbUpdateStart(void)
if (rawValue != DSHOT_TELEMETRY_INVALID) {
// Check EDT enable or store raw value
if ((rawValue == 0x0E00) && (dshotCommandGetCurrent(motorIndex) == DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE)) {
dshotTelemetryState.motorState[motorIndex].telemetryTypes = 1 << DSHOT_TELEMETRY_TYPE_STATE_EVENTS;
dshotTelemetryState.motorState[motorIndex].telemetryTypes = 1 << DSHOT_TELEMETRY_TYPE_STATUS;
} else {
dshotTelemetryState.motorState[motorIndex].rawValue = rawValue;
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/drivers/pwm_output_dshot_shared.c
Expand Up @@ -215,7 +215,7 @@ FAST_CODE_NOINLINE bool pwmStartDshotMotorUpdate(void)
if (rawValue != DSHOT_TELEMETRY_INVALID) {
// Check EDT enable or store raw value
if ((rawValue == 0x0E00) && (dshotCommandGetCurrent(i) == DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE)) {
dshotTelemetryState.motorState[i].telemetryTypes = 1 << DSHOT_TELEMETRY_TYPE_STATE_EVENTS;
dshotTelemetryState.motorState[i].telemetryTypes = 1 << DSHOT_TELEMETRY_TYPE_STATUS;
} else {
dshotTelemetryState.motorState[i].rawValue = rawValue;
}
Expand Down
2 changes: 2 additions & 0 deletions src/main/fc/core.c
Expand Up @@ -517,6 +517,8 @@ void tryArm(void)
dshotCleanTelemetryData();
if (motorConfig()->dev.useDshotEdt) {
dshotCommandWrite(ALL_MOTORS, getMotorCount(), DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE, DSHOT_CMD_TYPE_INLINE);
dshotCommandWrite(ALL_MOTORS, getMotorCount(), DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE, DSHOT_CMD_TYPE_INLINE);
dshotCommandWrite(ALL_MOTORS, getMotorCount(), DSHOT_CMD_EXTENDED_TELEMETRY_ENABLE, DSHOT_CMD_TYPE_INLINE);
}
}
#endif
Expand Down
35 changes: 22 additions & 13 deletions src/main/osd/osd_warnings.c
Expand Up @@ -337,20 +337,29 @@ void renderOsdWarning(char *warningText, bool *blinking, uint8_t *displayAttr)
warningText[dshotEscErrorLength++] = '0' + k + 1;

// Add esc warnings
if (ARMING_FLAG(ARMED) && osdConfig()->esc_rpm_alarm != ESC_RPM_ALARM_OFF
&& (dshotTelemetryState.motorState[k].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_eRPM)) != 0
&& (dshotTelemetryState.motorState[k].telemetryData[DSHOT_TELEMETRY_TYPE_eRPM] * 100 * 2 / motorConfig()->motorPoleCount) <= osdConfig()->esc_rpm_alarm) {
warningText[dshotEscErrorLength++] = 'R';
}
if (osdConfig()->esc_temp_alarm != ESC_TEMP_ALARM_OFF
&& (dshotTelemetryState.motorState[k].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_TEMPERATURE)) != 0
&& dshotTelemetryState.motorState[k].telemetryData[DSHOT_TELEMETRY_TYPE_TEMPERATURE] >= osdConfig()->esc_temp_alarm) {
if ((osdConfig()->esc_temp_alarm != ESC_TEMP_ALARM_OFF) &&
(dshotTelemetryState.motorState[k].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_TEMPERATURE)) != 0 &&
(dshotTelemetryState.motorState[k].telemetryData[DSHOT_TELEMETRY_TYPE_TEMPERATURE] >= osdConfig()->esc_temp_alarm))
warningText[dshotEscErrorLength++] = 'T';
}
if (ARMING_FLAG(ARMED) && osdConfig()->esc_current_alarm != ESC_CURRENT_ALARM_OFF
&& (dshotTelemetryState.motorState[k].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_CURRENT)) != 0
&& dshotTelemetryState.motorState[k].telemetryData[DSHOT_TELEMETRY_TYPE_CURRENT] >= osdConfig()->esc_current_alarm) {
warningText[dshotEscErrorLength++] = 'C';
if (ARMING_FLAG(ARMED)) {
if ((osdConfig()->esc_rpm_alarm != ESC_RPM_ALARM_OFF) &&
(dshotTelemetryState.motorState[k].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_eRPM)) != 0 &&
(dshotTelemetryState.motorState[k].telemetryData[DSHOT_TELEMETRY_TYPE_eRPM] * 100 * 2 / motorConfig()->motorPoleCount) <= osdConfig()->esc_rpm_alarm)
warningText[dshotEscErrorLength++] = 'R';
if ((osdConfig()->esc_current_alarm != ESC_CURRENT_ALARM_OFF) &&
(dshotTelemetryState.motorState[k].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_CURRENT)) != 0 &&
(dshotTelemetryState.motorState[k].telemetryData[DSHOT_TELEMETRY_TYPE_CURRENT] >= osdConfig()->esc_current_alarm))
warningText[dshotEscErrorLength++] = 'C';
if ((dshotTelemetryState.motorState[k].telemetryTypes & (1 << DSHOT_TELEMETRY_TYPE_STATUS)) != 0) {
#if defined(DEBUG_DSHOT_DEMAG_EVENTS)
if (dshotTelemetryState.motorState[k].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] & DSHOT_TELEMETRY_STATUS_DEMAG_EVENT_MASK)
warningText[dshotEscErrorLength++] = 'X';
#endif
if (dshotTelemetryState.motorState[k].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] & DSHOT_TELEMETRY_STATUS_DESYNC_EVENT_MASK)
warningText[dshotEscErrorLength++] = 'D';
if (dshotTelemetryState.motorState[k].telemetryData[DSHOT_TELEMETRY_TYPE_STATUS] & DSHOT_TELEMETRY_STATUS_STALL_EVENT_MASK)
warningText[dshotEscErrorLength++] = 'S';
}
}

// If no esc warning data undo esc nr (esc telemetry data types depends on the esc hw/sw)
Expand Down

0 comments on commit 5a94fbc

Please sign in to comment.