Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions companion/src/firmwares/boards.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,12 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
return ((IS_FAMILY_HORUS_OR_T16(board) && getCapability(board, HasAuxSerialMode)) ||
IS_RADIOMASTER_TX15(board) || IS_RADIOMASTER_TX16SMK3(board));

case HasKeyLockCombo:
return !(IS_HELLORADIOSKY_V12(board) || IS_TARANIS_XLITE(board) ||
IS_FLYSKY_PA01(board) || IS_FLYSKY_NV14(board) ||
IS_FLYSKY_EL18(board) || IS_FAMILY_PL18(board) ||
board == Board::BOARD_FLYSKY_NB4P);

case HasLedStripGPIO:
return (IS_RADIOMASTER_MT12(board) || IS_FAMILY_PL18(board) ||
IS_HELLORADIOSKY_V16(board));
Expand Down
1 change: 1 addition & 0 deletions companion/src/firmwares/boards.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ namespace Board {
HasInternalGPS,
HasInternalModuleSupport,
HasIntModuleHeartbeatGPIO,
HasKeyLockCombo,
HasLedStripGPIO,
HasRTC,
HasSDCard,
Expand Down
2 changes: 2 additions & 0 deletions companion/src/firmwares/edgetx/yaml_generalsettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ Node convert<GeneralSettings>::encode(const GeneralSettings& rhs)
}

node["oneLogPerDay"] = (int)rhs.oneLogPerDay;
node["keyLockEnabled"] = (int)rhs.keyLockEnabled;

return node;
}
Expand Down Expand Up @@ -737,6 +738,7 @@ bool convert<GeneralSettings>::decode(const Node& node, GeneralSettings& rhs)
}

node["oneLogPerDay"] >> rhs.oneLogPerDay;
node["keyLockEnabled"] >> rhs.keyLockEnabled;

// override critical settings after import
// TODO: for consistency move up call stack to use existing eeprom and profile conversions
Expand Down
1 change: 1 addition & 0 deletions companion/src/firmwares/generalsettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,7 @@ class GeneralSettings {
unsigned int keyShortcuts[MAX_KEYSHORTCUTS];
unsigned int qmFavorites[MAX_QMFAVOURITES];
bool oneLogPerDay;
bool keyLockEnabled;

void switchConfigClear();

Expand Down
18 changes: 18 additions & 0 deletions companion/src/generaledit/generalsetup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,16 @@ void GeneralSetupPanel::setValues()

ui->modelQuickSelect_CB->setChecked(generalSettings.modelQuickSelect);
ui->chkOneLogPerDay->setChecked(generalSettings.oneLogPerDay);
{
bool hasCombo = Boards::getCapability(board, Board::HasKeyLockCombo);
ui->chkKeyLockEnabled->setChecked(hasCombo && generalSettings.keyLockEnabled);
ui->chkKeyLockEnabled->setEnabled(hasCombo);
ui->label_keyLockEnabled->setEnabled(hasCombo);
if (!hasCombo) {
ui->chkKeyLockEnabled->setToolTip(tr("Not available on this radio (no key combo defined)"));
ui->label_keyLockEnabled->setToolTip(tr("Not available on this radio (no key combo defined)"));
}
}

if (Boards::getCapability(board, Board::HasColorLcd)) {
ui->modelSelectLayout_CB->setCurrentIndex(generalSettings.modelSelectLayout);
Expand Down Expand Up @@ -1141,3 +1151,11 @@ void GeneralSetupPanel::on_chkOneLogPerDay_stateChanged(int)
emit modified();
}
}

void GeneralSetupPanel::on_chkKeyLockEnabled_stateChanged(int)
{
if (!lock) {
generalSettings.keyLockEnabled = ui->chkKeyLockEnabled->isChecked();
emit modified();
}
}
1 change: 1 addition & 0 deletions companion/src/generaledit/generalsetup.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class GeneralSetupPanel : public GeneralPanel

void on_pwrOffIfInactiveSB_editingFinished();
void on_chkOneLogPerDay_stateChanged(int);
void on_chkKeyLockEnabled_stateChanged(int);

private:
Ui::GeneralSetup *ui;
Expand Down
16 changes: 15 additions & 1 deletion companion/src/generaledit/generalsetup.ui
Original file line number Diff line number Diff line change
Expand Up @@ -1727,7 +1727,7 @@ p, li { white-space: pre-wrap; }
</property>
</widget>
</item>
<item row="31" column="0">
<item row="32" column="0">
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
Expand Down Expand Up @@ -2544,6 +2544,20 @@ Mode 4:
</property>
</widget>
</item>
<item row="31" column="0">
<widget class="QLabel" name="label_keyLockEnabled">
<property name="text">
<string>Key lock</string>
</property>
</widget>
</item>
<item row="31" column="1">
<widget class="QCheckBox" name="chkKeyLockEnabled">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">
Expand Down
6 changes: 3 additions & 3 deletions radio/src/datastructs_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -1159,14 +1159,14 @@ PACK(struct RadioData {

NOBACKUP(uint8_t modelQuickSelect:1);
NOBACKUP(uint8_t oneLogPerDay:1);
NOBACKUP(uint8_t keyLockEnabled:1);

#if defined(COLORLCD)
NOBACKUP(uint8_t spare:4 SKIP);
NOBACKUP(uint8_t spare:3 SKIP);
#elif LCD_W == 128
uint8_t invertLCD:1; // Invert B&W LCD display
NOBACKUP(uint8_t spare:1 SKIP);
#else
NOBACKUP(uint8_t spare:2 SKIP);
NOBACKUP(uint8_t spare:1 SKIP);
#endif

NOBACKUP(uint8_t pwrOffIfInactive);
Expand Down
16 changes: 16 additions & 0 deletions radio/src/gui/128x64/radio_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ enum {
CASE_BACKLIGHT(ITEM_RADIO_SETUP_BRIGHTNESS)
CASE_CONTRAST(ITEM_RADIO_SETUP_CONTRAST)
CASE_BACKLIGHT(ITEM_RADIO_SETUP_FLASH_BEEP)
CASE_KEY_LOCK(ITEM_RADIO_SETUP_KEY_LOCK)
ITEM_RADIO_ONE_LOG_PER_DAY,
CASE_SPLASH_PARAM(ITEM_RADIO_SETUP_DISABLE_SPLASH)
CASE_PWR_BUTTON_PRESS(ITEM_RADIO_SETUP_PWR_ON_SPEED)
Expand Down Expand Up @@ -218,6 +219,7 @@ void menuRadioSetup(event_t event)
CASE_BACKLIGHT(0)
CASE_CONTRAST(0)
CASE_BACKLIGHT(0)
CASE_KEY_LOCK(0)
0,
CASE_SPLASH_PARAM(0)
CASE_PWR_BUTTON_PRESS(0)
Expand Down Expand Up @@ -594,6 +596,20 @@ void menuRadioSetup(event_t event)
break;
}

#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2)
case ITEM_RADIO_SETUP_KEY_LOCK: {
static char lbl[45];
const char* k1 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY1);
const char* k2 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY2);
snprintf(lbl, sizeof(lbl), STR_KEY_LOCK_FMT,
k1 ? k1 : "?", k2 ? k2 : "?");
lcdDrawTextAlignedLeft(y, lbl);
g_eeGeneral.keyLockEnabled =
editCheckBox(g_eeGeneral.keyLockEnabled, LCD_W - 9, y, nullptr, attr, event);
break;
}
#endif

case ITEM_RADIO_SETUP_DISABLE_SPLASH:
{
lcdDrawTextAlignedLeft(y, STR_SPLASHSCREEN);
Expand Down
16 changes: 16 additions & 0 deletions radio/src/gui/212x64/radio_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ enum MenuRadioSetupItems {
ITEM_RADIO_SETUP_CONTRAST,
CASE_PCBX9E_PCBX9DP(ITEM_RADIO_SETUP_BACKLIGHT_COLOR)
ITEM_RADIO_SETUP_FLASH_BEEP,
CASE_KEY_LOCK(ITEM_RADIO_SETUP_KEY_LOCK)
ITEM_RADIO_ONE_LOG_PER_DAY,
CASE_SPLASH_PARAM(ITEM_RADIO_SETUP_DISABLE_SPLASH)
CASE_PWR_BUTTON_PRESS(ITEM_RADIO_SETUP_PWR_ON_SPEED)
Expand Down Expand Up @@ -218,6 +219,7 @@ void menuRadioSetup(event_t event)
0, // contrast
CASE_PCBX9E_PCBX9DP(0) // backlight color
0, // flash beep
CASE_KEY_LOCK(0) // key lock
0,
CASE_SPLASH_PARAM(0) // disable splash
CASE_PWR_BUTTON_PRESS(0) // pwr on speed
Expand Down Expand Up @@ -577,6 +579,20 @@ void menuRadioSetup(event_t event)
break;
}

#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2)
case ITEM_RADIO_SETUP_KEY_LOCK: {
static char lbl[45];
const char* k1 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY1);
const char* k2 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY2);
snprintf(lbl, sizeof(lbl), STR_KEY_LOCK_FMT,
k1 ? k1 : "?", k2 ? k2 : "?");
lcdDrawTextAlignedLeft(y, lbl);
g_eeGeneral.keyLockEnabled =
editCheckBox(g_eeGeneral.keyLockEnabled, RADIO_SETUP_2ND_COLUMN, y, nullptr, attr, event);
break;
}
#endif

case ITEM_RADIO_SETUP_DISABLE_SPLASH:
lcdDrawTextAlignedLeft(y, STR_SPLASHSCREEN);
if (SPLASH_NEEDED()) {
Expand Down
23 changes: 23 additions & 0 deletions radio/src/gui/colorlcd/radio/radio_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,25 @@ class ManageModelsSetupPage : public SubPage
Window* favSelectMatch = nullptr;
};

#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2)
// Combo-specific label ("Lock keys (SYS+MDL)"), so built dynamically
// rather than as a SetupLineDef - can't be a plain STR_TYP entry.
static coord_t addKeyLockLine(Window* window, coord_t y, coord_t col2, PaddingSize padding)
{
static char keyLockLabel[45];
const char* k1 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY1);
const char* k2 = keysGetLabel((EnumKeys)KEYS_LOCK_KEY2);
snprintf(keyLockLabel, sizeof(keyLockLabel), STR_KEY_LOCK_FMT,
k1 ? k1 : "?", k2 ? k2 : "?");
Window* w = new SetupLine(window, y, col2, padding, keyLockLabel,
[=](Window* parent, coord_t x, coord_t y) {
new ToggleSwitch(parent, {x, y, 0, 0},
GET_SET_DEFAULT(g_eeGeneral.keyLockEnabled));
});
return y + w->height() + padding;
}
#endif

static SetupLineDef setupLines[] = {
{
// Have only one log per day
Expand Down Expand Up @@ -1013,5 +1032,9 @@ void RadioSetupPage::build(Window* window)
}, BTN_H);
y += w->height() + padding;

#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2)
y = addKeyLockLine(window, y, SubPage::EDT_X, padding);
#endif

SetupLine::showLines(window, y, SubPage::EDT_X, padding, setupLines, DIM(setupLines));
}
6 changes: 6 additions & 0 deletions radio/src/gui/common/stdlcd/feature_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@
#define CASE_BACKLIGHT(x)
#endif

#if defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2)
#define CASE_KEY_LOCK(x) x,
#else
#define CASE_KEY_LOCK(x)
#endif

#if defined(RTCLOCK)
#define CASE_RTCLOCK(x) x,
#else
Expand Down
5 changes: 5 additions & 0 deletions radio/src/hal/key_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,13 @@ uint32_t readTrims();
// Init GPIO ports
void keysInit();

// returns a bit field with each supported key
uint32_t keysGetSupported();

static inline bool keyIsSupported(EnumKeys key) {
return keysGetSupported() & (1 << key);
}

uint8_t keysGetMaxKeys();
uint8_t keysGetMaxTrims();

Expand Down
59 changes: 58 additions & 1 deletion radio/src/keys.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include "hal/rotary_encoder.h"
#include "dataconstants.h"

#if !defined(BOOT) && (defined(USE_HATS_AS_KEYS) || defined(PCBXLITE))
#if !defined(BOOT)
#include "edgetx.h"
#endif

Expand Down Expand Up @@ -183,6 +183,26 @@ void Key::killEvents()
static Key keys[MAX_KEYS];
static Key trim_keys[MAX_TRIMS * 2];

#if !defined(BOOT)
// Per-target key combo (from hal.h KEYS_LOCK_KEY1/KEY2) long-pressed together
// toggles a software key lock.
static bool s_keys_locked = false;
static bool s_keys_lock_notify = false;
static uint8_t s_keys_lock_combo_cnt = 0;

bool areKeysLocked() { return s_keys_locked; }

bool consumeKeysLockToggleEvent()
{
if (!s_keys_lock_notify) return false;
s_keys_lock_notify = false;
return true;
}
#else
bool areKeysLocked() { return false; }
bool consumeKeysLockToggleEvent() { return false; }
#endif

/**
* @brief returns true if there is an event waiting.
*
Expand Down Expand Up @@ -491,11 +511,48 @@ bool keysPollingCycle()
trims_input = READ_TRIMS();
#endif

#if !defined(BOOT) && defined(KEYS_LOCK_KEY1) && defined(KEYS_LOCK_KEY2)
// Combo keys (from hal.h) long-pressed together toggle the key lock; killing
// the per-key events while both are held prevents their individual actions
// from firing.
if (g_eeGeneral.keyLockEnabled &&
keyIsSupported(KEYS_LOCK_KEY1) && keyIsSupported(KEYS_LOCK_KEY2)) {
bool both = (keys_input & (1u << KEYS_LOCK_KEY1)) &&
(keys_input & (1u << KEYS_LOCK_KEY2));
if (both) {
keys[KEYS_LOCK_KEY1].killEvents();
keys[KEYS_LOCK_KEY2].killEvents();
if (s_keys_lock_combo_cnt < 0xFF) s_keys_lock_combo_cnt++;
if (s_keys_lock_combo_cnt == KEY_LONG_DELAY) {
s_keys_locked = !s_keys_locked;
s_keys_lock_notify = true;
}
} else {
s_keys_lock_combo_cnt = 0;
}
} else {
// Feature disabled: never leave keys stuck locked.
s_keys_locked = false;
s_keys_lock_combo_cnt = 0;
}
#endif

for (int i = 0; i < MAX_KEYS; i++) {
event_t evt = keys[i].input(keys_input & (1 << i));
if (evt) {
evt = keyMapping(evt | i);
#if !defined(BOOT)
if (evt) {
if (!s_keys_locked) {
pushEvent(evt);
} else if ((evt & _MSK_KEY_FLAGS) == _MSK_KEY_FIRST) {
// Re-show the "Keys locked" toast on each new key press while locked.
s_keys_lock_notify = true;
}
}
#else
if (evt) pushEvent(evt);
#endif
}
}

Expand Down
6 changes: 6 additions & 0 deletions radio/src/keys.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,12 @@ uint8_t keysGetTrimState(uint8_t trim);
bool keysPollingCycle();
bool rotaryEncoderPollingCycle();

// Holding the per-target combo (KEYS_LOCK_KEY1 + KEYS_LOCK_KEY2 from hal.h)
// for KEY_LONG_DELAY toggles the key lock. While locked, key events are
// suppressed; trims/sticks/switches still work.
bool areKeysLocked();
bool consumeKeysLockToggleEvent();

#if defined(USE_HATS_AS_KEYS)
void setHatsAsKeys(bool val);
bool getHatsAsKeys();
Expand Down
Loading
Loading