feat(radio): allow disabling USB charge while the radio is running (on compatible hardware) (#7564)

Co-authored-by: 3djc <3djc@gh.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Peter Feerick <5500713+pfeerick@users.noreply.github.com>
Co-authored-by: Peter Feerick <peter.feerick@gmail.com>
This commit is contained in:
3djc
2026-08-21 20:16:55 +10:00
committed by GitHub
co-authored by 3djc Claude Opus 5 Peter Feerick Peter Feerick
parent 2baf75f3aa
commit a51946c4e2
38 changed files with 134 additions and 15 deletions
@@ -254,6 +254,7 @@ Node convert<GeneralSettings>::encode(const GeneralSettings& rhs)
node["disableRssiPoweroffAlarm"] = (int)rhs.disableRssiPoweroffAlarm;
node["disableTrainerPoweroffAlarm"] = (int)rhs.disableTrainerPoweroffAlarm;
node["USBMode"] = rhs.usbMode;
node["usbChargeDisabled"] = (int)rhs.usbChargeDisabled;
node["hatsMode"] = hatsModeLut << rhs.hatsMode;
node["stickDeadZone"] = rhs.stickDeadZone;
node["jackMode"] = rhs.jackMode;
@@ -542,6 +543,7 @@ bool convert<GeneralSettings>::decode(const Node& node, GeneralSettings& rhs)
node["disableRssiPoweroffAlarm"] >> rhs.disableRssiPoweroffAlarm;
node["disableTrainerPoweroffAlarm"] >> rhs.disableTrainerPoweroffAlarm;
node["USBMode"] >> rhs.usbMode;
node["usbChargeDisabled"] >> rhs.usbChargeDisabled;
node["hatsMode"] >> hatsModeLut >> rhs.hatsMode;
node["stickDeadZone"] >> rhs.stickDeadZone;
node["jackMode"] >> rhs.jackMode;
@@ -318,6 +318,7 @@ class GeneralSettings {
bool disableRssiPoweroffAlarm;
bool disableTrainerPoweroffAlarm;
unsigned int usbMode;
bool usbChargeDisabled;
unsigned int hatsMode;
unsigned int stickDeadZone;
unsigned int jackMode;
@@ -97,6 +97,17 @@ ui(new Ui::GeneralSetup)
ui->adjustRTC->setChecked(generalSettings.adjustRTC);
ui->usbModeCB->setCurrentIndex(generalSettings.usbMode);
// "Charge while radio on" is only available on RadioMaster radios
// that expose the charger-enable pin (rm-h750 based targets).
if (IS_RADIOMASTER_TX16SMK3(board) || IS_RADIOMASTER_TX15(board) ||
IS_RADIOMASTER_GX15(board)) {
ui->usbChargeChkB->setChecked(!generalSettings.usbChargeDisabled); // Default is zero=checked
}
else {
ui->usbChargeLabel->hide();
ui->usbChargeChkB->hide();
}
if (IS_FLYSKY_EL18(board) || IS_FLYSKY_NV14(board) || IS_FAMILY_PL18(board)) {
ui->hatsModeCB->setModel(panelFilteredModels->getItemModel(FIM_HATSMODE));
ui->hatsModeCB->setField(generalSettings.hatsMode, this);
@@ -384,6 +395,14 @@ void GeneralSetupPanel::on_usbModeCB_currentIndexChanged(int index)
}
}
void GeneralSetupPanel::on_usbChargeChkB_stateChanged(int)
{
if (!lock) {
generalSettings.usbChargeDisabled = !ui->usbChargeChkB->isChecked();
emit modified();
}
}
void GeneralSetupPanel::on_jackModeCB_currentIndexChanged(int index)
{
if (!lock) {
+1
View File
@@ -62,6 +62,7 @@ class GeneralSetupPanel : public GeneralPanel
void on_hapticLengthCB_currentIndexChanged(int index);
void on_backlightswCB_currentIndexChanged(int index);
void on_usbModeCB_currentIndexChanged(int index);
void on_usbChargeChkB_stateChanged(int);
void on_jackModeCB_currentIndexChanged(int index);
void on_backlightColor_SL_valueChanged();
void on_mavbaud_CB_currentIndexChanged(int index);
+25 -11
View File
@@ -392,7 +392,7 @@ Mode 4:
</property>
</widget>
</item>
<item row="28" column="1">
<item row="29" column="1">
<widget class="QComboBox" name="ppm_units_CB">
<property name="currentText">
<string>0.--</string>
@@ -414,7 +414,7 @@ Mode 4:
</item>
</widget>
</item>
<item row="27" column="1">
<item row="28" column="1">
<widget class="AutoComboBox" name="hatsModeCB" native="true"/>
</item>
<item row="23" column="1">
@@ -506,7 +506,7 @@ Acceptable values are 3v..12v</string>
</property>
</widget>
</item>
<item row="28" column="0">
<item row="29" column="0">
<widget class="QLabel" name="ppm_units_label">
<property name="text">
<string>PPM Units</string>
@@ -854,7 +854,7 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="26" column="1">
<item row="27" column="1">
<widget class="QComboBox" name="jackModeCB">
<item>
<property name="text">
@@ -897,6 +897,20 @@ p, li { white-space: pre-wrap; }
</item>
</widget>
</item>
<item row="26" column="0">
<widget class="QLabel" name="usbChargeLabel">
<property name="text">
<string>Charge while radio on</string>
</property>
</widget>
</item>
<item row="26" column="1">
<widget class="QCheckBox" name="usbChargeChkB">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="17" column="0">
<widget class="QLabel" name="label_15">
<property name="sizePolicy">
@@ -916,7 +930,7 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="27" column="0">
<item row="28" column="0">
<widget class="QLabel" name="hatsModeLabel">
<property name="text">
<string>Hats Mode</string>
@@ -955,7 +969,7 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="26" column="0">
<item row="27" column="0">
<widget class="QLabel" name="jackModeLabel">
<property name="text">
<string>Jack Mode</string>
@@ -1077,7 +1091,7 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="30" column="0">
<item row="32" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
@@ -1304,28 +1318,28 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="29" column="0">
<item row="30" column="0">
<widget class="QLabel" name="label_3">
<property name="text">
<string>One log per day</string>
</property>
</widget>
</item>
<item row="29" column="1">
<item row="30" column="1">
<widget class="QCheckBox" name="chkOneLogPerDay">
<property name="text">
<string/>
</property>
</widget>
</item>
<item row="30" column="0">
<item row="31" column="0">
<widget class="QLabel" name="label_keyLockEnabled">
<property name="text">
<string>Key lock</string>
</property>
</widget>
</item>
<item row="30" column="1">
<item row="31" column="1">
<widget class="QCheckBox" name="chkKeyLockEnabled">
<property name="text">
<string/>
+4
View File
@@ -241,4 +241,8 @@ void usbChargerInit();
bool usbChargerLed();
#endif
#if defined(USB_CHARGE_CONTROL)
void usbChargerEnableCharge(bool enable);
#endif
#endif // _BOARD_H_
@@ -25,7 +25,15 @@
#include "board.h"
#include "hal/usb_driver.h"
//TODO: charger enable control
#if defined(USB_CHARGE_CONTROL)
void usbChargerEnableCharge(bool enable)
{
if (enable)
gpio_clear(UCHARGER_EN_GPIO);
else
gpio_set(UCHARGER_EN_GPIO);
}
#endif
void usbChargerInit()
{
@@ -36,6 +44,13 @@ void usbChargerInit()
bool usbChargerLed()
{
#if defined(USB_CHARGE_CONTROL)
// When charging is disabled via the "Charge while radio on" setting,
// the charger-enable pin is driven high to hold the charger off, so it is
// not charging.
if (gpio_read(UCHARGER_EN_GPIO))
return false;
#endif
#if defined UCHARGER_INVERTED
return (!gpio_read(UCHARGER_GPIO) && usbPlugged());
#else
+7
View File
@@ -1169,7 +1169,14 @@ PACK(struct RadioData {
// Radio level tabs control (global settings)
NOBACKUP(uint8_t modelSelectLayout:2);
NOBACKUP(uint8_t radioThemesDisabled:1);
#if defined(USB_CHARGE_CONTROL)
// 0 = charge while USB active (default), 1 = hold the charger off while USB
// is plugged in SD/Joystick/VCP mode
NOBACKUP(uint8_t usbChargeDisabled:1);
NOBACKUP(uint8_t spare:6 SKIP);
#else
NOBACKUP(uint8_t spare:7 SKIP);
#endif
#elif LCD_W == 128
uint8_t invertLCD:1; // Invert B&W LCD display
NOBACKUP(uint8_t spare:4 SKIP);
@@ -966,6 +966,23 @@ const static SetupLineDef setupLines[] = {
GET_SET_DEFAULT(g_eeGeneral.USBMode));
}
},
#if defined(USB_CHARGE_CONTROL)
{
// Charge while radio on
STR_DEF(STR_USB_CHARGE),
[](Window* parent, coord_t x, coord_t y) {
new ToggleSwitch(parent, {x, y, 0, 0},
GET_INVERTED(g_eeGeneral.usbChargeDisabled),
[](uint8_t newValue) {
g_eeGeneral.usbChargeDisabled = !newValue;
SET_DIRTY();
// take effect now, not only on the next plug
if (usbPlugged())
usbChargerEnableCharge(!g_eeGeneral.usbChargeDisabled);
});
}
},
#endif
#if defined(ROTARY_ENCODER_NAVIGATION) && !defined(USE_HATS_AS_KEYS)
{
STR_DEF(STR_ROTARY_ENC_MODE),
+8
View File
@@ -170,10 +170,18 @@ void handleUsbConnection()
TRACE("USB unplugged");
closeUsbMenu();
_pluggedUsb = false;
#if defined(USB_CHARGE_CONTROL)
usbChargerEnableCharge(true);
#endif
} else if (!_pluggedUsb && usbPlugged()) {
TRACE("USB plugged");
_pluggedUsb = true;
_usbDisabled = false;
#if defined(USB_CHARGE_CONTROL)
// Apply on plug, not on usbStart(): the mode popup can sit open for a long
// time and the radio would charge until a mode is picked
usbChargerEnableCharge(!g_eeGeneral.usbChargeDisabled);
#endif
}
if (!_usbDisabled && !usbStarted() && usbPlugged()) {
@@ -87,6 +87,7 @@ const struct YamlIdStr enum_Functions[] = {
{ FUNC_DISABLE_AUDIO_AMP, "DISABLE_AUDIO_AMP" },
{ FUNC_RGB_LED, "RGB_LED" },
{ FUNC_PUSH_CUST_SWITCH, "PUSH_CUST_SWITCH" },
{ FUNC_DISABLE_KEYS, "DISABLE_KEYS" },
{ FUNC_TEST, "TEST" },
{ 0, NULL }
};
@@ -482,7 +483,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "favMultiMode", 1 ),
YAML_UNSIGNED( "modelSelectLayout", 2 ),
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 7 ),
YAML_UNSIGNED( "usbChargeDisabled", 1 ),
YAML_PADDING( 6 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
@@ -483,7 +483,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "favMultiMode", 1 ),
YAML_UNSIGNED( "modelSelectLayout", 2 ),
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 7 ),
YAML_UNSIGNED( "usbChargeDisabled", 1 ),
YAML_PADDING( 6 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
@@ -484,7 +484,8 @@ static const struct YamlNode struct_RadioData[] = {
YAML_UNSIGNED( "favMultiMode", 1 ),
YAML_UNSIGNED( "modelSelectLayout", 2 ),
YAML_UNSIGNED( "radioThemesDisabled", 1 ),
YAML_PADDING( 7 ),
YAML_UNSIGNED( "usbChargeDisabled", 1 ),
YAML_PADDING( 6 ),
YAML_UNSIGNED( "pwrOffIfInactive", 8 ),
YAML_ARRAY("keyShortcuts", 8, 6, struct_KeyShortcut, NULL),
YAML_ARRAY("qmFavorites", 8, 12, struct_QMFavorite, NULL),
+1
View File
@@ -47,6 +47,7 @@ add_definitions(-DFIRMWARE_QSPI)
add_definitions(-DFIRMWARE_FORMAT_UF2)
add_definitions(-DUSE_CUSTOM_EXTI_IRQ)
add_definitions(-DUSB_CHARGER)
add_definitions(-DUSB_CHARGE_CONTROL)
set(FLAVOUR gx15)
add_definitions(-DRADIO_GX15)
+3
View File
@@ -24,6 +24,9 @@
#include "definitions.h"
bool usbChargerLed() { return true; }
#if defined(USB_CHARGE_CONTROL)
void usbChargerEnableCharge(bool enable) {}
#endif
void ledRed() {}
void ledGreen() {}
void ledBlue() {}
+1
View File
@@ -61,6 +61,7 @@ add_definitions(-DFIRMWARE_QSPI)
add_definitions(-DFIRMWARE_FORMAT_UF2)
add_definitions(-DUSE_CUSTOM_EXTI_IRQ)
add_definitions(-DUSB_CHARGER)
add_definitions(-DUSB_CHARGE_CONTROL)
set(FLAVOUR tx15)
add_definitions(-DMANUFACTURER_RADIOMASTER)
@@ -64,6 +64,7 @@ add_definitions(-DFIRMWARE_QSPI)
add_definitions(-DFIRMWARE_FORMAT_UF2)
add_definitions(-DUSE_CUSTOM_EXTI_IRQ)
add_definitions(-DUSB_CHARGER)
add_definitions(-DUSB_CHARGE_CONTROL)
add_definitions(-DLUMINOSITY_SENSOR)
set(FLAVOUR tx16smk3)
+1
View File
@@ -947,6 +947,7 @@
#define TR_SENSOR "传感器"
#define TR_COUNTRY_CODE "国别码"
#define TR_USBMODE "USB模式"
#define TR_USB_CHARGE "开机时充电"
#define TR_JACK_MODE "教练插口模式"
#define TR_VOICE_LANGUAGE "播报语言"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -944,6 +944,7 @@
#define TR_SENSOR "SENZOR"
#define TR_COUNTRY_CODE "Kód regionu"
#define TR_USBMODE "Režim USB"
#define TR_USB_CHARGE "Nabíjení za chodu"
#define TR_JACK_MODE "Režim Jack"
#define TR_VOICE_LANGUAGE "Jazyk hlasu"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -952,6 +952,7 @@
#define TR_SENSOR "SENSOR"
#define TR_COUNTRY_CODE "Lande kode"
#define TR_USBMODE "USB tilstand"
#define TR_USB_CHARGE "Oplad med radio tændt"
#define TR_JACK_MODE "Jack tilstand"
#define TR_VOICE_LANGUAGE "Stemme sprog"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -947,6 +947,7 @@
#define TR_SENSOR TR_BW_COL("SENSOR", "Sensor")
#define TR_COUNTRY_CODE "Landescode"
#define TR_USBMODE "USB Modus"
#define TR_USB_CHARGE "Laden wenn Sender an"
#define TR_JACK_MODE "Klinken-Modus"
#define TR_VOICE_LANGUAGE "Sprachansagen"
#define TR_TEXT_LANGUAGE "Textsprache"
+1
View File
@@ -948,6 +948,7 @@
#define TR_SENSOR "SENSOR"
#define TR_COUNTRY_CODE "Country code"
#define TR_USBMODE "USB mode"
#define TR_USB_CHARGE "Charge while radio on"
#define TR_JACK_MODE "Jack mode"
#define TR_VOICE_LANGUAGE "Voice language"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -940,6 +940,7 @@
#define TR_SENSOR "SENSOR"
#define TR_COUNTRY_CODE "Código país"
#define TR_USBMODE "Modo USB"
#define TR_USB_CHARGE "Cargar con radio ON"
#define TR_JACK_MODE "Modo Jack"
#define TR_VOICE_LANGUAGE "Idioma voces"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -940,6 +940,7 @@
#define TR_SENSOR "SENSORI"
#define TR_COUNTRY_CODE "Maatunnus"
#define TR_USBMODE "USB-tila"
#define TR_USB_CHARGE "Lataa radio päällä"
#define TR_JACK_MODE "Jack Mode"
#define TR_VOICE_LANGUAGE "Äänen kieli"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -944,6 +944,7 @@
#define TR_SENSOR "CAPTEUR"
#define TR_COUNTRY_CODE TR("Zone géo.", "Zone géographique")
#define TR_USBMODE "Mode USB"
#define TR_USB_CHARGE "Charge radio allumée"
#define TR_JACK_MODE "Mode Jack"
#define TR_VOICE_LANGUAGE TR("Langue voix", "Langue annonces vocales")
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -950,6 +950,7 @@
#define TR_SENSOR "חיישן"
#define TR_COUNTRY_CODE "קוד ארץ"
#define TR_USBMODE "USB מצב"
#define TR_USB_CHARGE "טעינה כאשר השלט פועל"
#define TR_JACK_MODE "Jack mode"
#define TR_VOICE_LANGUAGE "שפת שמע"
#define TR_TEXT_LANGUAGE "שפת הטקסט"
+1
View File
@@ -947,6 +947,7 @@
#define TR_SENSOR "SENSORE"
#define TR_COUNTRY_CODE TR("Cod. Paese", "Codice del Paese")
#define TR_USBMODE "Modo USB"
#define TR_USB_CHARGE "Carica con radio accesa"
#define TR_JACK_MODE "Modo JACK"
#define TR_VOICE_LANGUAGE "Lingua vocale"
#define TR_TEXT_LANGUAGE "Lingua testo"
+1
View File
@@ -946,6 +946,7 @@
#define TR_SENSOR "センサー"
#define TR_COUNTRY_CODE "カントリーコード"
#define TR_USBMODE "USBモード"
#define TR_USB_CHARGE "電源オン時に充電"
#define TR_JACK_MODE "Jackモード"
#define TR_VOICE_LANGUAGE "音声言語"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -990,6 +990,7 @@
#define TR_SENSOR "센서"
#define TR_COUNTRY_CODE "국가 코드"
#define TR_USBMODE "USB 모드"
#define TR_USB_CHARGE "전원 켜짐 시 충전"
#define TR_JACK_MODE "잭 모드"
#define TR_VOICE_LANGUAGE "음성 언어"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -942,6 +942,7 @@
#define TR_SENSOR "SENSOR"
#define TR_COUNTRY_CODE "Landcode"
#define TR_USBMODE "USB Mode"
#define TR_USB_CHARGE "Laden als zender aan"
#define TR_JACK_MODE "Jack Mode"
#define TR_VOICE_LANGUAGE "Taal"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -939,6 +939,7 @@
#define TR_SENSOR "SENSOR"
#define TR_COUNTRY_CODE "Kod regionu"
#define TR_USBMODE "Tryb USB"
#define TR_USB_CHARGE "Ładuj gdy radio włączone"
#define TR_JACK_MODE "Tryb Jack"
#define TR_VOICE_LANGUAGE "Język głosu"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -947,6 +947,7 @@
#define TR_SENSOR "SENSOR"
#define TR_COUNTRY_CODE "Código pais"
#define TR_USBMODE "Modo USB"
#define TR_USB_CHARGE "Carregar com rádio ON"
#define TR_JACK_MODE "Jack mode"
#define TR_VOICE_LANGUAGE "Idoma da Voz"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -949,6 +949,7 @@
#define TR_SENSOR "СЕНСОР"
#define TR_COUNTRY_CODE "Код страны"
#define TR_USBMODE "Режим USB"
#define TR_USB_CHARGE "Зарядка при вкл. пульте"
#define TR_JACK_MODE "Режим разъема"
#define TR_VOICE_LANGUAGE "Язык озвучки"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -947,6 +947,7 @@
#define TR_SENSOR "SENSOR"
#define TR_COUNTRY_CODE "Landskod"
#define TR_USBMODE "USB-läge"
#define TR_USB_CHARGE "Ladda när radion är på"
#define TR_JACK_MODE "Uttagsläge"
#define TR_VOICE_LANGUAGE "Röstspråk"
#define TR_TEXT_LANGUAGE "Textspråk"
+1
View File
@@ -944,6 +944,7 @@
#define TR_SENSOR "傳感器"
#define TR_COUNTRY_CODE "國別碼"
#define TR_USBMODE "USB模式"
#define TR_USB_CHARGE "開機時充電"
#define TR_JACK_MODE "教練插口模式"
#define TR_VOICE_LANGUAGE "播報語言"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -948,6 +948,7 @@
#define TR_SENSOR "СЕНСОР"
#define TR_COUNTRY_CODE "Код країни"
#define TR_USBMODE "Режим USB"
#define TR_USB_CHARGE "Заряджати коли увімкнено"
#define TR_JACK_MODE "Режим коннектора"
#define TR_VOICE_LANGUAGE "Мова голосу"
#define TR_TEXT_LANGUAGE "Text language"
+1
View File
@@ -1013,6 +1013,7 @@
#define STR_UPDATE_RX_OPTIONS currentLangStrings->STR_UPDATE_RX_OPTIONS
#define STR_UPDATE_TX_OPTIONS currentLangStrings->STR_UPDATE_TX_OPTIONS
#define STR_US currentLangStrings->STR_US
#define STR_USB_CHARGE currentLangStrings->STR_USB_CHARGE
#define STR_USB_JOYSTICK currentLangStrings->STR_USB_JOYSTICK
#define STR_USB_MASS_STORAGE currentLangStrings->STR_USB_MASS_STORAGE
#define STR_USB_SERIAL currentLangStrings->STR_USB_SERIAL
+1
View File
@@ -1004,6 +1004,7 @@ STR(UNSUPPORTED_RX)
STR(UPDATE_RX_OPTIONS)
STR(UPDATE_TX_OPTIONS)
STR(US)
STR(USB_CHARGE)
STR(USB_JOYSTICK)
STR(USB_MASS_STORAGE)
STR(USB_SERIAL)