mirror of
https://github.com/betaflight/betaflight.git
synced 2025-07-16 04:45:24 +03:00
Improve features (+ cli) (#13494)
* Features - refactor featureNames[] Use designated initializers for used features. NULL values are stored in gaps. Use ARRAYLEN() for featureNames iteration Use `unsigned` for bitmasks * Features - add featuresSupportedByBuild bitmask of features that are supported in current build configuration. Copied from init.c sanitization * Features - simplify feature sanitization code featuresSupportedByBuild makes things much easier * Features - improve cli feature handling - refuse all features that are not compiled in - AlreadyDisabled/AlreadyEnabled info - refuse operation if multiple features match * fixup! Features - improve cli feature handling * Features - print available and not supported features separately * Update src/main/cli/cli.c Co-authored-by: Mark Haslinghuis <mark@numloq.nl> * features - print full state without command --------- Co-authored-by: Petr Ledvina <ledvinap@hp124.ekotip.cz> Co-authored-by: Mark Haslinghuis <mark@numloq.nl>
This commit is contained in:
parent
dac4939215
commit
286cfb5022
4 changed files with 155 additions and 157 deletions
|
@ -207,7 +207,6 @@ static bool signatureUpdated = false;
|
|||
#endif // USE_BOARD_INFO
|
||||
|
||||
static const char* const emptyName = "-";
|
||||
static const char* const emptyString = "";
|
||||
|
||||
#define MAX_CHANGESET_ID_LENGTH 8
|
||||
#define MAX_DATE_LENGTH 20
|
||||
|
@ -228,14 +227,31 @@ static const char * const mixerNames[] = {
|
|||
#endif
|
||||
|
||||
// sync this with features_e
|
||||
#define _R(_flag, _name) [LOG2(_flag)] = _name
|
||||
static const char * const featureNames[] = {
|
||||
"RX_PPM", "", "INFLIGHT_ACC_CAL", "RX_SERIAL", "MOTOR_STOP",
|
||||
"SERVO_TILT", "SOFTSERIAL", "GPS", "",
|
||||
"RANGEFINDER", "TELEMETRY", "", "3D", "RX_PARALLEL_PWM",
|
||||
"RX_MSP", "RSSI_ADC", "LED_STRIP", "DISPLAY", "OSD",
|
||||
"", "CHANNEL_FORWARDING", "TRANSPONDER", "AIRMODE",
|
||||
"", "", "RX_SPI", "", "ESC_SENSOR", "ANTI_GRAVITY", "", NULL
|
||||
_R(FEATURE_RX_PPM, "RX_PPM"),
|
||||
_R(FEATURE_INFLIGHT_ACC_CAL, "INFLIGHT_ACC_CAL"),
|
||||
_R(FEATURE_RX_SERIAL, "RX_SERIAL"),
|
||||
_R(FEATURE_MOTOR_STOP, "MOTOR_STOP"),
|
||||
_R(FEATURE_SERVO_TILT, "SERVO_TILT"),
|
||||
_R(FEATURE_SOFTSERIAL, "SOFTSERIAL"),
|
||||
_R(FEATURE_GPS, "GPS"),
|
||||
_R(FEATURE_RANGEFINDER, "RANGEFINDER"),
|
||||
_R(FEATURE_TELEMETRY, "TELEMETRY"),
|
||||
_R(FEATURE_3D, "3D"),
|
||||
_R(FEATURE_RX_PARALLEL_PWM, "RX_PARALLEL_PWM"),
|
||||
_R(FEATURE_RSSI_ADC, "RSSI_ADC"),
|
||||
_R(FEATURE_LED_STRIP, "LED_STRIP"),
|
||||
_R(FEATURE_DASHBOARD, "DISPLAY"),
|
||||
_R(FEATURE_OSD, "OSD"),
|
||||
_R(FEATURE_CHANNEL_FORWARDING, "CHANNEL_FORWARDING"),
|
||||
_R(FEATURE_TRANSPONDER, "TRANSPONDER"),
|
||||
_R(FEATURE_AIRMODE, "AIRMODE"),
|
||||
_R(FEATURE_RX_SPI, "RX_SPI"),
|
||||
_R(FEATURE_ESC_SENSOR, "ESC_SENSOR"),
|
||||
_R(FEATURE_ANTI_GRAVITY, "ANTI_GRAVITY"),
|
||||
};
|
||||
#undef _R
|
||||
|
||||
// sync this with rxFailsafeChannelMode_e
|
||||
static const char rxFailsafeModeCharacters[] = "ahs";
|
||||
|
@ -3232,23 +3248,23 @@ static void cliMcuId(const char *cmdName, char *cmdline)
|
|||
static void printFeature(dumpFlags_t dumpMask, const uint32_t mask, const uint32_t defaultMask, const char *headingStr)
|
||||
{
|
||||
headingStr = cliPrintSectionHeading(dumpMask, false, headingStr);
|
||||
for (uint32_t i = 0; featureNames[i]; i++) { // disabled features first
|
||||
if (strcmp(featureNames[i], emptyString) != 0) { //Skip unused
|
||||
for (unsigned i = 0; i < ARRAYLEN(featureNames); i++) { // disabled features first
|
||||
if (featureNames[i]) { //Skip unused
|
||||
const char *format = "feature -%s";
|
||||
const bool equalsDefault = (~defaultMask | mask) & (1 << i);
|
||||
const bool equalsDefault = (~defaultMask | mask) & (1U << i);
|
||||
headingStr = cliPrintSectionHeading(dumpMask, !equalsDefault, headingStr);
|
||||
cliDefaultPrintLinef(dumpMask, (defaultMask | ~mask) & (1 << i), format, featureNames[i]);
|
||||
cliDefaultPrintLinef(dumpMask, (defaultMask | ~mask) & (1U << i), format, featureNames[i]);
|
||||
cliDumpPrintLinef(dumpMask, equalsDefault, format, featureNames[i]);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; featureNames[i]; i++) { // enabled features
|
||||
if (strcmp(featureNames[i], emptyString) != 0) { //Skip unused
|
||||
for (unsigned i = 0; i < ARRAYLEN(featureNames); i++) { // enabled features
|
||||
if (featureNames[i]) { //Skip unused
|
||||
const char *format = "feature %s";
|
||||
if (defaultMask & (1 << i)) {
|
||||
cliDefaultPrintLinef(dumpMask, (~defaultMask | mask) & (1 << i), format, featureNames[i]);
|
||||
if (defaultMask & (1U << i)) {
|
||||
cliDefaultPrintLinef(dumpMask, (~defaultMask | mask) & (1U << i), format, featureNames[i]);
|
||||
}
|
||||
if (mask & (1 << i)) {
|
||||
const bool equalsDefault = (defaultMask | ~mask) & (1 << i);
|
||||
if (mask & (1U << i)) {
|
||||
const bool equalsDefault = (defaultMask | ~mask) & (1U << i);
|
||||
headingStr = cliPrintSectionHeading(dumpMask, !equalsDefault, headingStr);
|
||||
cliDumpPrintLinef(dumpMask, equalsDefault, format, featureNames[i]);
|
||||
}
|
||||
|
@ -3256,34 +3272,31 @@ static void printFeature(dumpFlags_t dumpMask, const uint32_t mask, const uint32
|
|||
}
|
||||
}
|
||||
|
||||
static void printFeatureList(const char* header, uint32_t mask, const char* delimiter, bool lineFeed)
|
||||
{
|
||||
if (header) {
|
||||
cliPrint(header);
|
||||
}
|
||||
for (unsigned i = 0; i < ARRAYLEN(featureNames); i++) {
|
||||
if (featureNames[i] && (mask & (1U << i))) {
|
||||
cliPrintf("%s%s", i ? delimiter : "", featureNames[i]);
|
||||
}
|
||||
}
|
||||
if (lineFeed) {
|
||||
cliPrintLinefeed();
|
||||
}
|
||||
}
|
||||
|
||||
static void cliFeature(const char *cmdName, char *cmdline)
|
||||
{
|
||||
uint32_t len = strlen(cmdline);
|
||||
const uint32_t mask = featureConfig()->enabledFeatures;
|
||||
if (len == 0) {
|
||||
cliPrint("Enabled: ");
|
||||
for (uint32_t i = 0; ; i++) {
|
||||
if (featureNames[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
if (mask & (1 << i)) {
|
||||
cliPrintf("%s ", featureNames[i]);
|
||||
}
|
||||
}
|
||||
cliPrintLinefeed();
|
||||
} else if (strncasecmp(cmdline, "list", len) == 0) {
|
||||
cliPrint("Available:");
|
||||
for (uint32_t i = 0; ; i++) {
|
||||
if (featureNames[i] == NULL)
|
||||
break;
|
||||
if (strcmp(featureNames[i], emptyString) != 0) //Skip unused
|
||||
cliPrintf(" %s", featureNames[i]);
|
||||
}
|
||||
cliPrintLinefeed();
|
||||
return;
|
||||
if (len == 0 // `feature`
|
||||
|| strncasecmp(cmdline, "list", len) == 0) { // old `feature list` invocation
|
||||
printFeatureList("Enabled: ", mask, " ", true);
|
||||
printFeatureList("Available: ", ~mask & featuresSupportedByBuild, " ", true);
|
||||
printFeatureList("Unavailable: ", ~featuresSupportedByBuild, " ", true);
|
||||
} else {
|
||||
uint32_t feature;
|
||||
|
||||
bool remove = false;
|
||||
if (cmdline[0] == '-') {
|
||||
// remove feature
|
||||
|
@ -3292,36 +3305,31 @@ static void cliFeature(const char *cmdName, char *cmdline)
|
|||
len--;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; ; i++) {
|
||||
if (featureNames[i] == NULL) {
|
||||
cliPrintErrorLinef(cmdName, ERROR_INVALID_NAME, cmdline);
|
||||
break;
|
||||
unsigned found = 0;
|
||||
int featureIdx = -1;
|
||||
for (unsigned i = 0; !found && i < ARRAYLEN(featureNames); i++) {
|
||||
if (featureNames[i] && strncasecmp(cmdline, featureNames[i], len) == 0) {
|
||||
found++;
|
||||
featureIdx = i;
|
||||
}
|
||||
|
||||
if (strncasecmp(cmdline, featureNames[i], len) == 0) {
|
||||
feature = 1 << i;
|
||||
#ifndef USE_GPS
|
||||
if (feature & FEATURE_GPS) {
|
||||
cliPrintLine("unavailable");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifndef USE_RANGEFINDER
|
||||
if (feature & FEATURE_RANGEFINDER) {
|
||||
cliPrintLine("unavailable");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (remove) {
|
||||
if (found == 1) {
|
||||
uint32_t feature = 1U << featureIdx;
|
||||
const char *verb;
|
||||
if ((feature & featuresSupportedByBuild) == 0) {
|
||||
verb = "Unavailable";
|
||||
} else if (remove) {
|
||||
featureConfigClear(feature);
|
||||
cliPrint("Disabled");
|
||||
verb = (mask & feature) ? "Disabled" : "AlreadyDisabled";
|
||||
} else {
|
||||
featureConfigSet(feature);
|
||||
cliPrint("Enabled");
|
||||
}
|
||||
cliPrintLinef(" %s", featureNames[i]);
|
||||
break;
|
||||
verb = (mask & feature) ? "AlreadyEnabled" : "Enabled";
|
||||
}
|
||||
cliPrintLinef("%s %s", verb, featureNames[featureIdx]);
|
||||
} else if (found > 1) {
|
||||
cliPrintErrorLinef(cmdName, "Multiple features match %s", cmdline);
|
||||
} else /* found <= 0 */ {
|
||||
cliPrintErrorLinef(cmdName, ERROR_INVALID_NAME, cmdline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -415,98 +415,20 @@ static void validateAndFixConfig(void)
|
|||
gyroConfigMutable()->gyro_hardware_lpf = GYRO_HARDWARE_LPF_NORMAL;
|
||||
}
|
||||
|
||||
// clear features that are not supported.
|
||||
// I have kept them all here in one place, some could be moved to sections of code above.
|
||||
// clear features that are not supported.
|
||||
featureDisableImmediate(~featuresSupportedByBuild);
|
||||
|
||||
#ifndef USE_RX_PPM
|
||||
featureDisableImmediate(FEATURE_RX_PPM);
|
||||
#endif
|
||||
|
||||
#ifndef USE_SERIALRX
|
||||
featureDisableImmediate(FEATURE_RX_SERIAL);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_SOFTSERIAL)
|
||||
featureDisableImmediate(FEATURE_SOFTSERIAL);
|
||||
#endif
|
||||
|
||||
#ifndef USE_RANGEFINDER
|
||||
featureDisableImmediate(FEATURE_RANGEFINDER);
|
||||
#endif
|
||||
|
||||
#ifndef USE_TELEMETRY
|
||||
featureDisableImmediate(FEATURE_TELEMETRY);
|
||||
#endif
|
||||
|
||||
#ifndef USE_RX_PWM
|
||||
featureDisableImmediate(FEATURE_RX_PARALLEL_PWM);
|
||||
#endif
|
||||
|
||||
#ifndef USE_RX_MSP
|
||||
featureDisableImmediate(FEATURE_RX_MSP);
|
||||
#endif
|
||||
|
||||
#ifndef USE_LED_STRIP
|
||||
featureDisableImmediate(FEATURE_LED_STRIP);
|
||||
#endif
|
||||
|
||||
#ifndef USE_DASHBOARD
|
||||
featureDisableImmediate(FEATURE_DASHBOARD);
|
||||
#endif
|
||||
|
||||
#ifndef USE_OSD
|
||||
featureDisableImmediate(FEATURE_OSD);
|
||||
#endif
|
||||
|
||||
#ifndef USE_SERVOS
|
||||
featureDisableImmediate(FEATURE_SERVO_TILT | FEATURE_CHANNEL_FORWARDING);
|
||||
#endif
|
||||
|
||||
#ifndef USE_TRANSPONDER
|
||||
featureDisableImmediate(FEATURE_TRANSPONDER);
|
||||
#endif
|
||||
|
||||
#ifndef USE_RX_SPI
|
||||
featureDisableImmediate(FEATURE_RX_SPI);
|
||||
#endif
|
||||
|
||||
#ifndef USE_ESC_SENSOR
|
||||
featureDisableImmediate(FEATURE_ESC_SENSOR);
|
||||
#endif
|
||||
|
||||
#if !defined(USE_ADC)
|
||||
featureDisableImmediate(FEATURE_RSSI_ADC);
|
||||
#endif
|
||||
|
||||
if (systemConfig()->configurationState == CONFIGURATION_STATE_UNCONFIGURED) {
|
||||
|
||||
#ifdef USE_DASHBOARD
|
||||
featureEnableImmediate(FEATURE_DASHBOARD);
|
||||
#endif
|
||||
#ifdef USE_LED_STRIP
|
||||
featureEnableImmediate(FEATURE_LED_STRIP);
|
||||
#endif
|
||||
#ifdef USE_OSD
|
||||
featureEnableImmediate(FEATURE_OSD);
|
||||
#endif
|
||||
#ifdef USE_RANGEFINDER
|
||||
featureEnableImmediate(FEATURE_RANGEFINDER);
|
||||
#endif
|
||||
#ifdef USE_SERVOS
|
||||
featureEnableImmediate(FEATURE_CHANNEL_FORWARDING);
|
||||
featureEnableImmediate(FEATURE_SERVO_TILT);
|
||||
#endif
|
||||
if (systemConfig()->configurationState == CONFIGURATION_STATE_UNCONFIGURED) {
|
||||
// enable some compiled-in features by default
|
||||
uint32_t autoFeatures =
|
||||
FEATURE_DASHBOARD | FEATURE_LED_STRIP | FEATURE_OSD | FEATURE_RANGEFINDER
|
||||
| FEATURE_CHANNEL_FORWARDING | FEATURE_SERVO_TILT
|
||||
#if defined(SOFTSERIAL1_RX_PIN) || defined(SOFTSERIAL2_RX_PIN) || defined(SOFTSERIAL1_TX_PIN) || defined(SOFTSERIAL2_TX_PIN)
|
||||
featureEnableImmediate(FEATURE_SOFTSERIAL);
|
||||
| FEATURE_SOFTSERIAL
|
||||
#endif
|
||||
#ifdef USE_TELEMETRY
|
||||
featureEnableImmediate(FEATURE_TELEMETRY);
|
||||
#endif
|
||||
#ifdef USE_TRANSPONDER
|
||||
featureEnableImmediate(FEATURE_TRANSPONDER);
|
||||
#endif
|
||||
|
||||
}
|
||||
;
|
||||
featureEnableImmediate(autoFeatures & featuresSupportedByBuild);
|
||||
}
|
||||
|
||||
#if defined(USE_BEEPER)
|
||||
#ifdef USE_TIMER
|
||||
|
|
|
@ -35,6 +35,67 @@ PG_RESET_TEMPLATE(featureConfig_t, featureConfig,
|
|||
.enabledFeatures = DEFAULT_FEATURES | DEFAULT_RX_FEATURE | FEATURE_ANTI_GRAVITY | FEATURE_AIRMODE,
|
||||
);
|
||||
|
||||
// bitmask of features that are supported in current build configuration
|
||||
uint32_t featuresSupportedByBuild =
|
||||
0
|
||||
#ifdef USE_PPM
|
||||
| FEATURE_RX_PPM,
|
||||
#endif
|
||||
| FEATURE_INFLIGHT_ACC_CAL // always available
|
||||
#ifdef USE_SERIALRX
|
||||
| FEATURE_RX_SERIAL
|
||||
#endif
|
||||
| FEATURE_MOTOR_STOP // always available
|
||||
#ifdef USE_SERVOS
|
||||
| FEATURE_SERVO_TILT
|
||||
#endif
|
||||
#ifdef USE_SOFTSERIAL
|
||||
| FEATURE_SOFTSERIAL
|
||||
#endif
|
||||
#ifdef USE_GPS
|
||||
| FEATURE_GPS
|
||||
#endif
|
||||
#ifdef USE_RANGEFINDER
|
||||
| FEATURE_RANGEFINDER
|
||||
#endif
|
||||
#ifdef USE_TELEMETRY
|
||||
| FEATURE_TELEMETRY
|
||||
#endif
|
||||
| FEATURE_3D // always available
|
||||
#ifdef USE_PWM
|
||||
| FEATURE_RX_PARALLEL_PWM
|
||||
#endif
|
||||
#ifdef USE_RX_MSP
|
||||
| FEATURE_RX_MSP
|
||||
#endif
|
||||
#ifdef USE_ADC
|
||||
| FEATURE_RSSI_ADC
|
||||
#endif
|
||||
#ifdef USE_LED_STRIP // but cms will try to use it
|
||||
| FEATURE_LED_STRIP
|
||||
#endif
|
||||
#ifdef USE_DASHBOARD
|
||||
| FEATURE_DASHBOARD
|
||||
#endif
|
||||
#ifdef USE_OSD
|
||||
| FEATURE_OSD
|
||||
#endif
|
||||
#ifdef USE_SERVOS
|
||||
| FEATURE_CHANNEL_FORWARDING
|
||||
#endif
|
||||
#ifdef USE_TRANSPONDER
|
||||
| FEATURE_TRANSPONDER
|
||||
#endif
|
||||
| FEATURE_AIRMODE // always available
|
||||
#ifdef USE_RX_SPI
|
||||
| FEATURE_RX_SPI
|
||||
#endif
|
||||
#ifdef USE_ESC_SENSOR
|
||||
| FEATURE_ESC_SENSOR
|
||||
#endif
|
||||
| FEATURE_ANTI_GRAVITY // always available
|
||||
;
|
||||
|
||||
static uint32_t runtimeFeatureMask;
|
||||
|
||||
void featureInit(void)
|
||||
|
|
|
@ -39,6 +39,9 @@
|
|||
|
||||
#endif // DEFAULT_RX_FEATURE
|
||||
|
||||
// features must be listed in
|
||||
// config/feature.c:featuresSupportedByBuild
|
||||
// cli/cli.c:featureNames
|
||||
typedef enum {
|
||||
FEATURE_RX_PPM = 1 << 0,
|
||||
FEATURE_INFLIGHT_ACC_CAL = 1 << 2,
|
||||
|
@ -72,6 +75,10 @@ typedef struct featureConfig_s {
|
|||
|
||||
PG_DECLARE(featureConfig_t, featureConfig);
|
||||
|
||||
// Mask of features that have code compiled in with current config.
|
||||
// Other restrictions on available features may apply.
|
||||
extern uint32_t featuresSupportedByBuild;
|
||||
|
||||
void featureInit(void);
|
||||
bool featureIsEnabled(const uint32_t mask);
|
||||
bool featureIsConfigured(const uint32_t mask);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue