feat: allow Sticky LS state to persist across EM or optionally across reboot (#4978)

This commit is contained in:
philmoz
2024-06-02 16:22:36 +10:00
committed by GitHub
parent 0399858a76
commit b16524837a
26 changed files with 121 additions and 46 deletions
@@ -116,6 +116,8 @@ Node convert<LogicalSwitchData>::encode(const LogicalSwitchData& rhs)
node["delay"] = rhs.delay;
node["duration"] = rhs.duration;
node["andsw"] = YamlRawSwitchEncode(RawSwitch(rhs.andsw));
node["lsPersist"] = (int)rhs.lsPersist;
node["lsState"] = (int)rhs.lsState;
return node;
}
@@ -200,6 +202,9 @@ bool convert<LogicalSwitchData>::decode(const Node& node,
node["andsw"] >> andsw;
rhs.andsw = andsw.toValue();
node["lsPersist"] >> rhs.lsPersist;
node["lsState"] >> rhs.lsState;
return true;
}
} // namespace YAML
@@ -76,6 +76,8 @@ class LogicalSwitchData {
unsigned int delay;
unsigned int duration;
int andsw;
bool lsState;
bool lsPersist;
void clear() { memset(this, 0, sizeof(LogicalSwitchData)); }
bool isEmpty() const;
@@ -47,6 +47,7 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
if (lsCapabilityExt) {
headerLabels << tr("Duration") << tr("Delay");
}
headerLabels << tr("Persistent");
TableLayout * tableLayout = new TableLayout(this, lsCapability, headerLabels);
const int channelsMax = model.getChannelsMax(true);
@@ -152,6 +153,13 @@ LogicalSwitchesPanel::LogicalSwitchesPanel(QWidget * parent, ModelData & model,
connect(dsbDelay[i], SIGNAL(valueChanged(double)), this, SLOT(onDelayChanged(double)));
tableLayout->addWidget(i, 6, dsbDelay[i]);
}
cbPersist[i] = new QCheckBox(this);
cbPersist[i]->setProperty("index", i);
cbPersist[i]->setText(tr(""));
cbPersist[i]->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
connect(cbPersist[i], SIGNAL(stateChanged(int)), this, SLOT(onPersistChanged()));
tableLayout->addWidget(i, 7, cbPersist[i]);
}
disableMouseScrolling();
@@ -257,6 +265,16 @@ void LogicalSwitchesPanel::onDelayChanged(double delay)
}
}
void LogicalSwitchesPanel::onPersistChanged()
{
if (!lock) {
QCheckBox *ckb = qobject_cast<QCheckBox*>(sender());
int index = ckb->property("index").toInt();
model->logicalSw[index].lsPersist = (ckb->checkState() ? 1 : 0);
emit modified();
}
}
void LogicalSwitchesPanel::onOffsetChanged()
{
offsetChangedAt(sender()->property("index").toInt());
@@ -343,6 +361,7 @@ void LogicalSwitchesPanel::updateTimerParam(QDoubleSpinBox *sb, int timer, doubl
#define DELAY_ENABLED 0x40
#define DURATION_ENABLED 0x80
#define LINE_ENABLED 0x100
#define PERSIST_ENABLED 0x200
void LogicalSwitchesPanel::updateLine(int i)
{
@@ -391,6 +410,8 @@ void LogicalSwitchesPanel::updateLine(int i)
}
case LS_FAMILY_STICKY: // no break
mask |= PERSIST_ENABLED;
cbPersist[i]->setChecked(model->logicalSw[i].lsPersist);
case LS_FAMILY_VBOOL:
mask |= SOURCE1_VISIBLE | SOURCE2_VISIBLE;
cbSource1[i]->setModel(rawSwitchFilteredModel);
@@ -432,6 +453,7 @@ void LogicalSwitchesPanel::updateLine(int i)
dsbOffset2[i]->setVisible(mask & VALUE3_VISIBLE);
teOffset[i]->setVisible(mask & VALUE_TO_VISIBLE);
cbAndSwitch[i]->setVisible(mask & LINE_ENABLED);
cbPersist[i]->setVisible(mask & PERSIST_ENABLED);
if (lsCapabilityExt) {
dsbDuration[i]->setVisible(mask & DURATION_ENABLED);
dsbDelay[i]->setVisible(mask & DELAY_ENABLED);
@@ -47,6 +47,7 @@ class LogicalSwitchesPanel : public ModelPanel
void onAndSwitchChanged(int value);
void onDurationChanged(double duration);
void onDelayChanged(double delay);
void onPersistChanged();
void onOffsetChanged();
bool offsetChangedAt(int index);
void updateLine(int index);
@@ -74,6 +75,7 @@ class LogicalSwitchesPanel : public ModelPanel
QDoubleSpinBox * dsbDelay[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbSource1[CPN_MAX_LOGICAL_SWITCHES];
QComboBox * cbSource2[CPN_MAX_LOGICAL_SWITCHES];
QCheckBox * cbPersist[CPN_MAX_LOGICAL_SWITCHES];
CompoundItemModelFactory * sharedItemModels;
FilteredItemModel * rawSwitchFilteredModel;
FilteredItemModel * rawSourceFilteredModel;
+2
View File
@@ -531,6 +531,8 @@ QString ModelPrinter::printLogicalSwitchLine(int idx)
sw1Name = RawSwitch(ls.val1).toString(getCurrentBoard(), &generalSettings);
sw2Name = RawSwitch(ls.val2).toString(getCurrentBoard(), &generalSettings);
result += tr("Sticky") + QString("(%1, %2)").arg(sw1Name).arg(sw2Name);
if (ls.lsPersist)
result += tr(" Persistent");
break;
case LS_FAMILY_TIMER:
result += tr("Timer") + QString("(%1, %2)").arg(ValToTim(ls.val1)).arg(ValToTim(ls.val2));
+3 -3
View File
@@ -134,9 +134,9 @@ PACK(struct LogicalSwitchData {
CUST_ATTR(def,r_logicSw,w_logicSw);
int32_t v1:10 SKIP;
int32_t v3:10 SKIP;
int32_t andsw:10 CUST(r_swtchSrc,w_swtchSrc); // TODO rename to xswtch
uint32_t andswtype:1 SKIP; // TODO rename to xswtchType (AND / OR)
uint32_t spare:1 SKIP; // anything else needed?
int32_t andsw:10 CUST(r_swtchSrc,w_swtchSrc);
uint32_t lsPersist:1;
uint32_t lsState:1;
int16_t v2 SKIP;
uint8_t delay;
uint8_t duration;
@@ -29,6 +29,7 @@ enum LogicalSwitchFields {
LS_FIELD_ANDSW,
LS_FIELD_DURATION,
LS_FIELD_DELAY,
LS_FIELD_PERSIST,
LS_FIELD_COUNT,
LS_FIELD_LAST = LS_FIELD_COUNT-1
};
@@ -219,6 +220,14 @@ void menuModelLogicalSwitchOne(event_t event)
CHECK_INCDEC_MODELVAR_ZERO(event, cs->delay, MAX_LS_DELAY);
}
break;
case LS_FIELD_PERSIST:
if (cstate == LS_FAMILY_STICKY) {
lcdDrawTextAlignedLeft(y, STR_PERSISTENT);
drawCheckBox(CSWONE_2ND_COLUMN, y, cs->lsPersist, attr);
if (attr) cs->lsPersist = checkIncDecModel(event, cs->lsPersist, 0, 1);
}
break;
}
}
}
@@ -30,6 +30,7 @@ enum LogicalSwitchFields {
LS_FIELD_ANDSW,
LS_FIELD_DURATION,
LS_FIELD_DELAY,
LS_FIELD_PERSIST,
LS_FIELD_COUNT,
LS_FIELD_LAST = LS_FIELD_COUNT-1
};
@@ -37,9 +38,10 @@ enum LogicalSwitchFields {
#define CSW_1ST_COLUMN (4*FW-3)
#define CSW_2ND_COLUMN (8*FW+2+FW/2)
#define CSW_3RD_COLUMN (14*FW+1+FW/2)
#define CSW_4TH_COLUMN (22*FW)
#define CSW_5TH_COLUMN (26*FW+3)
#define CSW_6TH_COLUMN (31*FW+1)
#define CSW_4TH_COLUMN (21*FW)
#define CSW_5TH_COLUMN (25*FW+3)
#define CSW_6TH_COLUMN (29*FW+3)
#define CSW_7TH_COLUMN (33*FW+3)
void putsEdgeDelayParam(coord_t x, coord_t y, LogicalSwitchData * cs, uint8_t lattr, uint8_t rattr)
{
@@ -83,10 +85,7 @@ void menuModelLogicalSwitches(event_t event)
int k = 0;
int sub = menuVerticalPosition;
horzpos_t horz = menuHorizontalPosition;
if (horz>=0) {
drawColumnHeader(STR_LSW_HEADERS, horz);
}
bool showHeader = true;
if (horz<0 && event==EVT_KEY_LONG(KEY_ENTER) && !READ_ONLY()) {
LogicalSwitchData * cs = lswAddress(sub);
@@ -202,6 +201,15 @@ void menuModelLogicalSwitches(event_t event)
if (attr && horz == LS_FIELD_V3 && cstate != LS_FAMILY_EDGE) {
repeatLastCursorMove(event);
showHeader = false;
}
// Persistent
if (cstate == LS_FAMILY_STICKY) {
drawCheckBox(CSW_7TH_COLUMN, y, cs->lsPersist, horz == LS_FIELD_PERSIST ? attr : 0);
} else if (attr && horz == LS_FIELD_PERSIST) {
repeatLastCursorMove(event);
showHeader = false;
}
if (s_editMode>0 && attr) {
@@ -253,7 +261,14 @@ void menuModelLogicalSwitches(event_t event)
case LS_FIELD_DELAY:
CHECK_INCDEC_MODELVAR_ZERO(event, cs->delay, MAX_LS_DELAY);
break;
case LS_FIELD_PERSIST:
cs->lsPersist = checkIncDecModel(event, cs->lsPersist, 0, 1);
break;
}
}
}
if (showHeader && menuHorizontalPosition>=0) {
drawColumnHeader(STR_LSW_HEADERS, menuHorizontalPosition);
}
}
+2
View File
@@ -35,7 +35,9 @@ void drawStick(coord_t centrex, int16_t xval, int16_t yval)
void drawColumnHeader(const char * const *headers, uint8_t index)
{
lcdDrawText(16*FW+3, 0, " ", 0);
lcdDrawText(17*FW, 0, headers[index], 0);
lcdDrawText(lcdNextPos, 0, " ", 0);
}
void drawCheckBox(coord_t x, coord_t y, uint8_t value, LcdFlags attr)
@@ -245,6 +245,13 @@ class LogicalSwitchEditPage : public Page
return formatNumberAsString(value, PREC1, 0, nullptr, "s");
});
}
// Sticky persist
if (cstate == LS_FAMILY_STICKY) {
line = logicalSwitchOneWindow->newLine(grid);
new StaticText(line, rect_t{}, STR_PERSISTENT);
new ToggleSwitch(line, rect_t{}, GET_SET_DEFAULT(cs->lsPersist));
}
}
void buildBody(Window* window)
+1
View File
@@ -1434,6 +1434,7 @@ void edgeTxInit()
// SDCARD not available, try to restore last model from RAM
TRACE("rambackupRestore");
rambackupRestore();
logicalSwitchesInit(true);
}
else {
storageReadAll();
+3
View File
@@ -23,6 +23,7 @@
#include "timers_driver.h"
#include "tasks/mixer_task.h"
#include "mixes.h"
#include "switches.h"
#if defined(USBJ_EX)
#include "usb_joystick.h"
@@ -244,6 +245,8 @@ if(g_model.rssiSource) {
customFunctionsReset();
logicalSwitchesInit(false);
restoreTimers();
for (int i=0; i<MAX_TELEMETRY_SENSORS; i++) {
@@ -459,8 +459,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
@@ -486,8 +486,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
@@ -486,8 +486,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
@@ -459,8 +459,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
@@ -459,8 +459,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
@@ -488,8 +488,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
@@ -488,8 +488,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
@@ -459,8 +459,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
@@ -460,8 +460,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
@@ -462,8 +462,8 @@ static const struct YamlNode struct_LogicalSwitchData[] = {
YAML_PADDING( 10 ),
YAML_PADDING( 10 ),
YAML_SIGNED_CUST( "andsw", 10, r_swtchSrc, w_swtchSrc ),
YAML_PADDING( 1 ),
YAML_PADDING( 1 ),
YAML_UNSIGNED( "lsPersist", 1 ),
YAML_UNSIGNED( "lsState", 1 ),
YAML_PADDING( 16 ),
YAML_UNSIGNED( "delay", 8 ),
YAML_UNSIGNED( "duration", 8 ),
+14
View File
@@ -457,6 +457,16 @@ PACK(typedef struct {
uint16_t duration:15;
}) ls_stay_struct;
void logicalSwitchesInit(bool force)
{
for (unsigned int idx=0; idx<MAX_LOGICAL_SWITCHES; idx++) {
LogicalSwitchData * ls = lswAddress(idx);
if (ls->func == LS_FUNC_STICKY && (force || ls->lsPersist)) {
lswFm[mixerCurrentFlightMode].lsw[idx].lastValue = ls->lsState;
}
}
}
bool getLogicalSwitch(uint8_t idx)
{
LogicalSwitchData * ls = lswAddress(idx);
@@ -745,6 +755,10 @@ void evalLogicalSwitches(bool isCurrentFlightmode)
}
}
context.state = result;
if ((g_model.logicalSw[idx].func == LS_FUNC_STICKY) && (g_model.logicalSw[idx].lsState != result)) {
g_model.logicalSw[idx].lsState = result;
storageDirty(EE_MODEL);
}
}
}
+3
View File
@@ -85,6 +85,9 @@ bool switchHasCustomName(uint8_t idx);
SwitchConfig switchGetMaxType(uint8_t idx);
// Restore switch state
void logicalSwitchesInit(bool force);
#if defined(FUNCTION_SWITCHES)
uint8_t getFSLogicalState(uint8_t index);
void setFSLogicalState(uint8_t index, uint8_t value);
+3 -15
View File
@@ -84,12 +84,6 @@
#define PSIZE(x) ( sizeof(x) - 1 )
#if defined(PCBTARANIS)
#define HINT(s) " " s " "
#else
#define HINT(s) s
#endif
#if LCD_W < LCD_H // Portrait mode
#define TR3(x, y, z) z
#define TR(x, y) y
@@ -967,16 +961,10 @@ extern const char STR_MIXNAME[];
extern const char STR_INPUTNAME[];
extern const char STR_EXPONAME[];
#if defined(COLORLCD)
#define TR_PHASES_HEADERS { TR_PHASES_HEADERS_NAME, TR_PHASES_HEADERS_SW, TR_PHASES_HEADERS_RUD_TRIM, TR_PHASES_HEADERS_ELE_TRIM, TR_PHASES_HEADERS_THT_TRIM, TR_PHASES_HEADERS_AIL_TRIM, TR_PHASES_HEADERS_CH5_TRIM, TR_PHASES_HEADERS_CH6_TRIM, TR_PHASES_HEADERS_FAD_IN, TR_PHASES_HEADERS_FAD_OUT }
#elif defined(PCBTARANIS)
#define TR_PHASES_HEADERS { HINT(TR_PHASES_HEADERS_NAME), HINT(TR_PHASES_HEADERS_SW), HINT(TR_PHASES_HEADERS_RUD_TRIM), HINT(TR_PHASES_HEADERS_ELE_TRIM), HINT(TR_PHASES_HEADERS_THT_TRIM), HINT(TR_PHASES_HEADERS_AIL_TRIM), HINT(TR_PHASES_HEADERS_FAD_IN), HINT(TR_PHASES_HEADERS_FAD_OUT) }
#endif
#define TR_LIMITS_HEADERS { HINT(TR_LIMITS_HEADERS_NAME), HINT(TR_LIMITS_HEADERS_SUBTRIM), HINT(TR_LIMITS_HEADERS_MIN), HINT(TR_LIMITS_HEADERS_MAX), HINT(TR_LIMITS_HEADERS_DIRECTION), HINT(TR_LIMITS_HEADERS_CURVE), HINT(TR_LIMITS_HEADERS_PPMCENTER), HINT(TR_LIMITS_HEADERS_SUBTRIMMODE) }
#define TR_LSW_HEADERS { HINT(TR_FUNC), HINT(TR_V1), HINT(TR_V2), HINT(TR_V2), HINT(TR_AND_SWITCH), HINT(TR_DURATION), HINT(TR_DELAY) }
#if LCD_W >= 212
#define TR_PHASES_HEADERS { TR_PHASES_HEADERS_NAME, TR_PHASES_HEADERS_SW, TR_PHASES_HEADERS_RUD_TRIM, TR_PHASES_HEADERS_ELE_TRIM, TR_PHASES_HEADERS_THT_TRIM, TR_PHASES_HEADERS_AIL_TRIM, TR_PHASES_HEADERS_FAD_IN, TR_PHASES_HEADERS_FAD_OUT }
#define TR_LIMITS_HEADERS { TR_LIMITS_HEADERS_NAME, TR_LIMITS_HEADERS_SUBTRIM, TR_LIMITS_HEADERS_MIN, TR_LIMITS_HEADERS_MAX, TR_LIMITS_HEADERS_DIRECTION, TR_LIMITS_HEADERS_CURVE, TR_LIMITS_HEADERS_PPMCENTER, TR_LIMITS_HEADERS_SUBTRIMMODE }
#define TR_LSW_HEADERS { TR_FUNC, TR_V1, TR_V2, TR_V2, TR_AND_SWITCH, TR_DURATION, TR_DELAY, TR_PERSISTENT }
extern const char * const STR_PHASES_HEADERS[];
extern const char * const STR_LIMITS_HEADERS[];
extern const char * const STR_LSW_HEADERS[];
+1 -1
View File
@@ -378,7 +378,7 @@
#define TR_THROTTLEREVERSE TR("Inv. gaz", "Inversion gaz")
#define TR_MINUTEBEEP TR("Bip min.", "Annonces minutes")
#define TR_BEEPCOUNTDOWN TR("Bip fin", "Compte à rebours")
#define TR_PERSISTENT TR( "Persist.", "Persistant")
#define TR_PERSISTENT TR("Persist.", "Persistant")
#define TR_BACKLIGHT_LABEL "Rétroéclairage"
#define TR_GHOST_MENU_LABEL "MENU GHOST"
#define TR_STATUS "Version"