chore: Companion - port of OpenTX function switches management (#1694)

* TPro - Port of OpenTX function switches management (https://github.com/opentx/opentx/pull/8847)

* cleanup

* Corrections

* Fix YAML generation and adjusted switches to match TPRO firmware

Co-authored-by: Batam <batam@macbook-pro.home>
This commit is contained in:
Batambatam
2022-03-21 10:43:27 +10:00
committed by GitHub
co-authored by Batam
parent 1d7c153979
commit ab15a5a514
22 changed files with 434 additions and 186 deletions
@@ -114,6 +114,7 @@ RawSourceItemModel::RawSourceItemModel(const GeneralSettings * const generalSett
addItems(SOURCE_TYPE_TRIM, RawSource::TrimsGroup, board->getCapability(Board::NumTrims));
addItems(SOURCE_TYPE_MAX, RawSource::SourcesGroup, 1);
addItems(SOURCE_TYPE_SWITCH, RawSource::SwitchesGroup, board->getCapability(Board::Switches));
addItems(SOURCE_TYPE_FUNCTIONSWITCH, RawSource::SwitchesGroup, board->getCapability(Board::FunctionSwitches));
addItems(SOURCE_TYPE_CUSTOM_SWITCH, RawSource::SwitchesGroup, firmware->getCapability(LogicalSwitches));
addItems(SOURCE_TYPE_CYC, RawSource::SourcesGroup, CPN_MAX_CYC);
addItems(SOURCE_TYPE_PPM, RawSource::SourcesGroup, firmware->getCapability(TrainerInputs));
@@ -163,7 +164,7 @@ RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSett
AbstractDynamicItemModel(generalSettings, modelData, firmware, board, boardType)
{
setId(IMID_RawSwitch);
setUpdateMask(IMUE_FlightModes | IMUE_LogicalSwitches | IMUE_TeleSensors);
setUpdateMask(IMUE_FlightModes | IMUE_LogicalSwitches | IMUE_TeleSensors | IMUE_FunctionSwitches);
// Descending switch direction: NOT (!) switches
addItems(SWITCH_TYPE_ACT, -1);
@@ -173,11 +174,13 @@ RawSwitchItemModel::RawSwitchItemModel(const GeneralSettings * const generalSett
addItems(SWITCH_TYPE_VIRTUAL, -firmware->getCapability(LogicalSwitches));
addItems(SWITCH_TYPE_TRIM, -board->getCapability(Board::NumTrimSwitches));
addItems(SWITCH_TYPE_MULTIPOS_POT, -(board->getCapability(Board::MultiposPots) * board->getCapability(Board::MultiposPotsPositions)));
addItems(SWITCH_TYPE_FUNCTIONSWITCH, -board->getCapability(Board::NumFunctionSwitchesPositions));
addItems(SWITCH_TYPE_SWITCH, -board->getCapability(Board::SwitchPositions));
// Ascending switch direction (including zero)
addItems(SWITCH_TYPE_NONE, 1);
addItems(SWITCH_TYPE_SWITCH, board->getCapability(Board::SwitchPositions));
addItems(SWITCH_TYPE_FUNCTIONSWITCH, board->getCapability(Board::NumFunctionSwitchesPositions));
addItems(SWITCH_TYPE_MULTIPOS_POT, board->getCapability(Board::MultiposPots) * board->getCapability(Board::MultiposPotsPositions));
addItems(SWITCH_TYPE_TRIM, board->getCapability(Board::NumTrimSwitches));
addItems(SWITCH_TYPE_VIRTUAL, firmware->getCapability(LogicalSwitches));
@@ -202,7 +205,7 @@ void RawSwitchItemModel::addItems(const RawSwitchType & type, int count)
// handle exceptions in RawSwitch() index values
const short rawIdxAdj = rawSwitchIndexBaseZeroTypes.contains(type) ? -1 : 0;
// determine cotext flags
// determine context flags
int context = RawSwitch::AllSwitchContexts;
switch (type) {
case SWITCH_TYPE_FLIGHT_MODE:
+15 -14
View File
@@ -67,20 +67,21 @@ class AbstractItemModel: public QStandardItemModel
Q_ENUM(ItemModelDataGroups)
enum ItemModelUpdateEvent {
IMUE_None = 0,
IMUE_SystemRefresh = 1 << 0,
IMUE_Channels = 1 << 1,
IMUE_Curves = 1 << 2,
IMUE_FlightModes = 1 << 3,
IMUE_GVars = 1 << 4,
IMUE_Inputs = 1 << 5,
IMUE_LogicalSwitches = 1 << 6,
IMUE_Scripts = 1 << 7,
IMUE_TeleSensors = 1 << 8,
IMUE_Timers = 1 << 9,
IMUE_Modules = 1 << 10,
IMUE_All = IMUE_SystemRefresh | IMUE_Channels | IMUE_Curves | IMUE_FlightModes | IMUE_GVars | IMUE_Inputs |
IMUE_LogicalSwitches | IMUE_Scripts | IMUE_TeleSensors | IMUE_Timers | IMUE_Modules
IMUE_None = 0,
IMUE_SystemRefresh = 1 << 0,
IMUE_Channels = 1 << 1,
IMUE_Curves = 1 << 2,
IMUE_FlightModes = 1 << 3,
IMUE_GVars = 1 << 4,
IMUE_Inputs = 1 << 5,
IMUE_LogicalSwitches = 1 << 6,
IMUE_Scripts = 1 << 7,
IMUE_TeleSensors = 1 << 8,
IMUE_Timers = 1 << 9,
IMUE_Modules = 1 << 10,
IMUE_FunctionSwitches = 1 << 11,
IMUE_All = IMUE_SystemRefresh | IMUE_Channels | IMUE_Curves | IMUE_FlightModes | IMUE_GVars | IMUE_Inputs |
IMUE_LogicalSwitches | IMUE_Scripts | IMUE_TeleSensors | IMUE_Timers | IMUE_Modules | IMUE_FunctionSwitches
};
Q_ENUM(ItemModelUpdateEvent)
+11 -5
View File
@@ -449,6 +449,9 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
else
return 7;
case FunctionSwitches:
return (IS_JUMPER_TPRO(board) ? 6 : 0);
case FactoryInstalledSwitches:
if (IS_TARANIS_X9E(board))
return 8;
@@ -469,6 +472,10 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
else
return 9;
case NumFunctionSwitchesPositions:
return getCapability(board, Board::FunctionSwitches) * 3;
case NumTrims:
if (IS_FAMILY_HORUS_OR_T16(board) && !IS_FLYSKY_NV14(board))
return 6;
@@ -484,9 +491,6 @@ int Boards::getCapability(Board::Type board, Board::Capability capability)
case HasColorLcd:
return IS_FAMILY_HORUS_OR_T16(board);
case NumFunctionSwitches:
return IS_JUMPER_TPRO(board) ? 6 : 0;
case HasSDCard:
return IS_STM32(board);
@@ -867,10 +871,12 @@ int Boards::getDefaultInternalModules(Board::Type board)
case BOARD_RADIOMASTER_TX12:
case BOARD_RADIOMASTER_T8:
case BOARD_JUMPER_TLITE:
case BOARD_RADIOMASTER_ZORRO:
case BOARD_JUMPER_TPRO:
return (int)MODULE_TYPE_MULTIMODULE;
case BOARD_RADIOMASTER_ZORRO:
return (int)MODULE_TYPE_CROSSFIRE;
case BOARD_FLYSKY_NV14:
return (int)MODULE_TYPE_FLYSKY;
+2 -1
View File
@@ -140,13 +140,14 @@ namespace Board {
MultiposPots,
MultiposPotsPositions,
Switches,
FunctionSwitches,
SwitchPositions,
NumFunctionSwitchesPositions,
FactoryInstalledSwitches,
NumTrims,
NumTrimSwitches,
HasRTC,
HasColorLcd,
NumFunctionSwitches,
HasSDCard,
HasInternalModuleSupport,
SportMaxBaudRate
@@ -957,7 +957,7 @@ Node convert<ModelData>::encode(const ModelData& rhs)
node["modelRegistrationID"] = rhs.registrationId;
if (getCurrentFirmware()->getCapability(FunctionSwitches)) {
if (Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) {
node["functionSwitchConfig"] = rhs.functionSwitchConfig;
node["functionSwitchGroup"] = rhs.functionSwitchGroup;
node["functionSwitchStartConfig"] = rhs.functionSwitchStartConfig;
@@ -965,8 +965,7 @@ Node convert<ModelData>::encode(const ModelData& rhs)
for (int i = 0; i < CPN_MAX_FUNCTION_SWITCHES; i++) {
if (strlen(rhs.functionSwitchNames[i]) > 0) {
node["functionSwitchNames"][std::to_string(i)] =
rhs.functionSwitchNames[i];
node["switchNames"][std::to_string(i)]["val"] = rhs.functionSwitchNames[i];
}
}
}
@@ -1137,8 +1136,7 @@ bool convert<ModelData>::decode(const Node& node, ModelData& rhs)
node["functionSwitchGroup"] >> rhs.functionSwitchGroup;
node["functionSwitchStartConfig"] >> rhs.functionSwitchStartConfig;
node["functionSwitchLogicalState"] >> rhs.functionSwitchLogicalState;
node["functionSwitchNames"] >> rhs.functionSwitchNames;
node["switchNames"] >> rhs.functionSwitchNames;
return true;
}
@@ -24,6 +24,7 @@
std::string YamlRawSourceEncode(const RawSource& rhs)
{
std::string src_str;
char c = 'A';
switch (rhs.type) {
case SOURCE_TYPE_VIRTUAL_INPUT:
src_str += "I" + std::to_string(rhs.index);
@@ -52,6 +53,14 @@ std::string YamlRawSourceEncode(const RawSource& rhs)
src_str += std::to_string(rhs.index + 1);
src_str += ")";
break;
case SOURCE_TYPE_FUNCTIONSWITCH:
if (IS_JUMPER_TPRO(getCurrentBoard())) {
c += Boards::getCapability(getCurrentBoard(), Board::Switches);
c += rhs.index;
src_str += "S";
src_str += c;
}
break;
case SOURCE_TYPE_CYC:
src_str = getCurrentFirmware()->getRawSourceCyclicTag(rhs.index);
break;
@@ -114,9 +123,19 @@ RawSource YamlRawSourceDecode(const std::string& src_str)
&& val[1] <= 'Z') {
int idx = getCurrentFirmware()->getSwitchesIndex(src_str.c_str());
if (idx >= 0 && idx < CPN_MAX_SWITCHES)
if (idx >= 0 && idx < CPN_MAX_SWITCHES) {
rhs = RawSource(SOURCE_TYPE_SWITCH, idx);
} else if (IS_JUMPER_TPRO(getCurrentBoard())) {
int numSw = Boards::getCapability(getCurrentBoard(), Board::Switches);
idx = val[1] - 'A';
idx -= numSw;
if(idx >= 0 and idx < Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) {
rhs = RawSource(SOURCE_TYPE_FUNCTIONSWITCH, idx);
}
}
} else if (val_len > 4 &&
val[0] == 'l' &&
val[1] == 'u' &&
@@ -142,6 +161,17 @@ RawSource YamlRawSourceDecode(const std::string& src_str)
if (ls > 0 && ls <= CPN_MAX_LOGICAL_SWITCHES)
rhs = RawSource(SOURCE_TYPE_CUSTOM_SWITCH, ls - 1);
} else if (val_len > 3 &&
val[0] == 'f' &&
val[1] == 's' &&
val[2] == '(') {
std::stringstream src(src_str.substr(3));
int fs = 0;
src >> fs;
if (fs > 0 && fs <= CPN_MAX_FUNCTION_SWITCHES)
rhs = RawSource(SOURCE_TYPE_FUNCTIONSWITCH, fs - 1);
} else if (val_len > 3 &&
val[0] == 't' &&
val[1] == 'r' &&
@@ -24,6 +24,7 @@
std::string YamlRawSwitchEncode(const RawSwitch& rhs)
{
std::string sw_str;
char c = 'A';
int32_t sval = rhs.index;
if (rhs.index < 0) {
sval = -sval;
@@ -42,6 +43,16 @@ std::string YamlRawSwitchEncode(const RawSwitch& rhs)
sw_str += "L";
sw_str += std::to_string(sval);
break;
case SWITCH_TYPE_FUNCTIONSWITCH:
if (IS_JUMPER_TPRO(getCurrentBoard())) {
c += Boards::getCapability(getCurrentBoard(), Board::Switches);
c += (sval - 1) / 3;
sw_str += "S";
sw_str += c;
sw_str += std::to_string((sval - 1) % 3);
}
break;
case SWITCH_TYPE_MULTIPOS_POT:
sw_str += "6P";
@@ -143,6 +154,16 @@ RawSwitch YamlRawSwitchDecode(const std::string& sw_str)
if (sw_idx >= 0) {
rhs.type = SWITCH_TYPE_SWITCH;
rhs.index = sw_idx * 3 + (val[2] - '0' + 1);
} else if (IS_JUMPER_TPRO(getCurrentBoard())) {
int numSw = Boards::getCapability(getCurrentBoard(), Board::Switches);
int idx = val[1] - 'A';
idx = idx - numSw;
if(idx >= 0 and idx < Boards::getCapability(getCurrentBoard(), Board::FunctionSwitches)) {
idx = idx * 3 + (val[2] - '0' + 1);
rhs = RawSwitch(SWITCH_TYPE_FUNCTIONSWITCH, idx);
}
}
// these types use index = 1
@@ -158,7 +179,6 @@ RawSwitch YamlRawSwitchDecode(const std::string& sw_str)
// TODO: SWITCH_TYPE_TIMER_MODE
// check as it appears to be depreciated as not in RawSwitch data model and not in radio yaml export
} else {
// types which do not use index
int sw_type = getCurrentFirmware()->getRawSwitchTypesIndex(sw_str_tmp.c_str());
@@ -165,7 +165,6 @@ enum Capability {
HasADCJitterFilter,
HasTelemetryBaudrate,
TopBarZones,
FunctionSwitches,
HasModelsList,
HasFlySkyGimbals
};
+139 -67
View File
@@ -218,8 +218,8 @@ void ModelData::setDefaultFunctionSwitches(int functionSwitchCount)
return;
for (int i = 0; i < functionSwitchCount; i++) {
functionSwitchConfig |= (Board::SWITCH_2POS << 2 * i);
functionSwitchGroup |= (1 << 2 * i);
setFuncSwitchConfig(i, Board::SWITCH_2POS);
setFuncSwitchGroup(i, 1);
}
}
@@ -232,7 +232,7 @@ void ModelData::setDefaultValues(unsigned int id, const GeneralSettings & settin
moduleData[i].modelId = id + 1;
}
setDefaultMixes(settings);
setDefaultFunctionSwitches(getCurrentFirmware()->getCapability(FunctionSwitches));
setDefaultFunctionSwitches(Boards::getCapability(getCurrentFirmware()->getBoard(), Board::FunctionSwitches));
}
int ModelData::getTrimValue(int phaseIdx, int trimIdx)
@@ -384,6 +384,28 @@ int ModelData::getChannelsMax(bool forceExtendedLimits) const
return 100;
}
bool ModelData::isFunctionSwitchPositionAvailable(int index) const
{
if (index == 0)
return true;
div_t qr = div(abs(index) - 1, 3);
int fs = getFuncSwitchConfig(qr.quot);
if (qr.rem == 1) {
return false;
}
else {
return fs != Board::SWITCH_NOT_AVAILABLE;
}
}
bool ModelData::isFunctionSwitchSourceAllowed(int index) const
{
return (int)getFuncSwitchConfig(index) != Board::SWITCH_NOT_AVAILABLE;
}
bool ModelData::isAvailable(const RawSwitch & swtch) const
{
unsigned index = abs(swtch.index) - 1;
@@ -397,6 +419,9 @@ bool ModelData::isAvailable(const RawSwitch & swtch) const
else if (swtch.type == SWITCH_TYPE_SENSOR) {
return strlen(sensorData[index].label) > 0;
}
else if (swtch.type == SWITCH_TYPE_FUNCTIONSWITCH) {
return isFunctionSwitchPositionAvailable(index + 1);
}
else {
return true;
}
@@ -1654,76 +1679,123 @@ AbstractStaticItemModel * ModelData::trainerModeItemModel(const GeneralSettings
return mdl;
}
QString ModelData::funcSwitchConfigToString(const int index) const
{
if (index < CPN_MAX_FUNCTION_SWITCHES)
return funcSwitchConfigToString(index, (int)(functionSwitchConfig >> (2 * index)) & 0x03);
else
return CPN_STR_UNKNOWN_ITEM;
}
// static
QString ModelData::funcSwitchConfigToString(const int index, const int value)
{
switch (value) {
case FUNC_SWITCH_CONFIG_NONE:
return tr("NONE");
case FUNC_SWITCH_CONFIG_TOGGLE:
return tr("TOGGLE");
case FUNC_SWITCH_CONFIG_2POS:
return tr("2POS");
default:
return CPN_STR_UNKNOWN_ITEM;
}
}
unsigned int ModelData::getFuncSwitchConfig(unsigned int index) const
{
if (index < CPN_MAX_FUNCTION_SWITCHES)
return Helpers::getBitmappedValue(functionSwitchConfig, index, 2);
else
return FUNC_SWITCH_CONFIG_NONE;
}
// static
AbstractStaticItemModel * ModelData::funcSwitchConfigItemModel()
{
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
mdl->setName(AIM_MODELDATA_FUNCSWITCHCONFIG);
void ModelData::setFuncSwitchConfig(unsigned int index, unsigned int value)
{
if (index < CPN_MAX_FUNCTION_SWITCHES)
Helpers::setBitmappedValue(functionSwitchConfig, value, index, 2);
}
for (int i = FUNC_SWITCH_CONFIG_FIRST; i <= FUNC_SWITCH_CONFIG_LAST; i++) {
mdl->appendToItemList(funcSwitchConfigToString(0, i), i);
}
// static
QString ModelData::funcSwitchConfigToString(unsigned int value)
{
switch (value) {
case FUNC_SWITCH_CONFIG_NONE:
return tr("NONE");
case FUNC_SWITCH_CONFIG_TOGGLE:
return tr("TOGGLE");
case FUNC_SWITCH_CONFIG_2POS:
return tr("2POS");
default:
return CPN_STR_UNKNOWN_ITEM;
}
}
mdl->loadItemList();
return mdl;
}
// static
AbstractStaticItemModel * ModelData::funcSwitchConfigItemModel()
{
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
mdl->setName(AIM_MODELDATA_FUNCSWITCHCONFIG);
QString ModelData::funcSwitchStartToString(const int index) const
{
if (index < CPN_MAX_FUNCTION_SWITCHES)
return funcSwitchStartToString(index, (int)(functionSwitchStartConfig >> (2 * index)) & 0x03);
else
return CPN_STR_UNKNOWN_ITEM;
}
for (unsigned int i = FUNC_SWITCH_CONFIG_FIRST; i <= FUNC_SWITCH_CONFIG_LAST; i++) {
mdl->appendToItemList(funcSwitchConfigToString(i), i);
}
// static
QString ModelData::funcSwitchStartToString(const int index, const int value)
{
switch (value) {
case FUNC_SWITCH_START_INACTIVE:
return tr("Inactive");
case FUNC_SWITCH_START_ACTIVE:
return tr("Active");
case FUNC_SWITCH_START_PREVIOUS:
return tr("Restore");
default:
return CPN_STR_UNKNOWN_ITEM;
}
}
mdl->loadItemList();
return mdl;
}
// static
AbstractStaticItemModel * ModelData::funcSwitchStartItemModel()
{
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
mdl->setName(AIM_MODELDATA_FUNCSWITCHSTART);
unsigned int ModelData::getFuncSwitchGroup(unsigned int index) const
{
if (index < CPN_MAX_FUNCTION_SWITCHES)
return Helpers::getBitmappedValue(functionSwitchGroup, index, 2);
else
return 0;
}
for (int i = FUNC_SWITCH_START_FIRST; i <= FUNC_SWITCH_START_LAST; i++) {
mdl->appendToItemList(funcSwitchStartToString(0, i), i);
}
void ModelData::setFuncSwitchGroup(unsigned int index, unsigned int value)
{
if (index < CPN_MAX_FUNCTION_SWITCHES)
Helpers::setBitmappedValue(functionSwitchGroup, value, index, 2);
}
mdl->loadItemList();
return mdl;
}
unsigned int ModelData::getFuncSwitchAlwaysOnGroup(unsigned int index) const
{
if (index < CPN_MAX_FUNCTION_SWITCHES) {
unsigned int grp = getFuncSwitchGroup(index);
unsigned int switchcnt = Boards::getCapability(getCurrentFirmware()->getBoard(), Board::FunctionSwitches);
return Helpers::getBitmappedValue(functionSwitchGroup, grp, 1, 2 * switchcnt);
}
else
return 0;
}
void ModelData::setFuncSwitchAlwaysOnGroup(unsigned int index, unsigned int value)
{
if (index < CPN_MAX_FUNCTION_SWITCHES) {
unsigned int grp = getFuncSwitchGroup(index);
unsigned int switchcnt = Boards::getCapability(getCurrentFirmware()->getBoard(), Board::FunctionSwitches);
Helpers::setBitmappedValue(functionSwitchGroup, value, grp, 1, 2 * switchcnt);
}
}
unsigned int ModelData::getFuncSwitchStart(unsigned int index) const
{
if (index < CPN_MAX_FUNCTION_SWITCHES)
return Helpers::getBitmappedValue(functionSwitchStartConfig, index, 2);
else
return FUNC_SWITCH_START_INACTIVE;
}
void ModelData::setFuncSwitchStart(unsigned int index, unsigned int value)
{
if (index < CPN_MAX_FUNCTION_SWITCHES)
Helpers::setBitmappedValue(functionSwitchStartConfig, value, index, 2);
}
// static
QString ModelData::funcSwitchStartToString(unsigned int value)
{
switch (value) {
case FUNC_SWITCH_START_INACTIVE:
return tr("Inactive");
case FUNC_SWITCH_START_ACTIVE:
return tr("Active");
case FUNC_SWITCH_START_PREVIOUS:
return tr("Restore");
default:
return CPN_STR_UNKNOWN_ITEM;
}
}
// static
AbstractStaticItemModel * ModelData::funcSwitchStartItemModel()
{
AbstractStaticItemModel * mdl = new AbstractStaticItemModel();
mdl->setName(AIM_MODELDATA_FUNCSWITCHSTART);
for (unsigned int i = FUNC_SWITCH_START_FIRST; i <= FUNC_SWITCH_START_LAST; i++) {
mdl->appendToItemList(funcSwitchStartToString(i), i);
}
mdl->loadItemList();
return mdl;
}
+19 -6
View File
@@ -184,9 +184,10 @@ class ModelData {
};
enum FunctionSwitchStart {
FUNC_SWITCH_START_INACTIVE,
FUNC_SWITCH_START_FIRST = FUNC_SWITCH_START_INACTIVE,
FUNC_SWITCH_START_ACTIVE,
FUNC_SWITCH_START_FIRST = FUNC_SWITCH_START_ACTIVE,
FUNC_SWITCH_START_INACTIVE,
//FUNC_SWITCH_START_FIRST = FUNC_SWITCH_START_INACTIVE,
FUNC_SWITCH_START_PREVIOUS,
FUNC_SWITCH_START_LAST = FUNC_SWITCH_START_PREVIOUS
};
@@ -232,6 +233,8 @@ class ModelData {
int getChannelsMax(bool forceExtendedLimits=false) const;
bool isAvailable(const RawSwitch & swtch) const;
bool isFunctionSwitchPositionAvailable(int index) const;
bool isFunctionSwitchSourceAllowed(int index) const;
enum ReferenceUpdateAction {
REF_UPD_ACT_CLEAR,
@@ -287,13 +290,23 @@ class ModelData {
static QString trainerModeToString(const int value);
static bool isTrainerModeAvailable(const GeneralSettings & generalSettings, const Firmware * firmware, const int value);
static AbstractStaticItemModel * trainerModeItemModel(const GeneralSettings & generalSettings, const Firmware * firmware);
QString funcSwitchConfigToString(const int index) const;
static QString funcSwitchConfigToString(const int index, const int value);
unsigned int getFuncSwitchConfig(unsigned int index) const;
void setFuncSwitchConfig(unsigned int index, unsigned int value);
static QString funcSwitchConfigToString(unsigned int value);
static AbstractStaticItemModel * funcSwitchConfigItemModel();
QString funcSwitchStartToString(const int index) const;
static QString funcSwitchStartToString(const int index, const int value);
unsigned int getFuncSwitchGroup(unsigned int index) const;
void setFuncSwitchGroup(unsigned int index, unsigned int value);
unsigned int getFuncSwitchAlwaysOnGroup(unsigned int index) const;
void setFuncSwitchAlwaysOnGroup(unsigned int index, unsigned int value);
unsigned int getFuncSwitchStart(unsigned int index) const;
void setFuncSwitchStart(unsigned int index, unsigned int value);
static QString funcSwitchStartToString(unsigned int value);
static AbstractStaticItemModel * funcSwitchStartItemModel();
protected:
void removeGlobalVar(int & var);
+37 -10
View File
@@ -45,26 +45,44 @@ inline int MAX_SWITCHES(Board::Type board, int version)
if (IS_TARANIS_X9D(board))
return 9;
if (IS_JUMPER_TPRO(board))
return 10;
if (IS_FAMILY_T12(board))
return 8;
if (IS_TARANIS_X7(board))
return 8;
if (IS_JUMPER_TPRO(board))
return 10;
return Boards::getCapability(board, Board::Switches);
}
inline int MAX_SWITCHES_SOURCE(Board::Type board, int version)
{
if (IS_JUMPER_TPRO(board)) // 10 switches are allocated in EEprom but 6 are reserved for FS
return Boards::getCapability(board, Board::Switches);
else
return MAX_SWITCHES(board, version);
}
inline int MAX_SWITCHES_POSITION(Board::Type board, int version)
{
if (IS_HORUS_OR_TARANIS(board)) {
if (IS_JUMPER_TPRO(board))
return Boards::getCapability(board, Board::SwitchPositions);
else if (IS_HORUS_OR_TARANIS(board))
return MAX_SWITCHES(board, version) * 3;
}
else {
else
return Boards::getCapability(board, Board::SwitchPositions);
}
inline int MAX_FUNCTIONSWITCHES(Board::Type board, int version)
{
return Boards::getCapability(board, Board::FunctionSwitches);
}
inline int MAX_FUNCTIONSWITCHES_POSITION(Board::Type board, int version)
{
return Boards::getCapability(board, Board::NumFunctionSwitchesPositions);
}
inline int POTS_CONFIG_SIZE(Board::Type board, int version)
@@ -156,7 +174,7 @@ inline int SWITCHES_CONFIG_SIZE(Board::Type board, int version)
if (IS_FAMILY_HORUS_OR_T16(board))
return 32;
if (version >= 219 && IS_TARANIS_X9D(board))
if (version >= 219 && (IS_TARANIS_X9D(board) || IS_JUMPER_TPRO(board)))
return 32;
return 16;
@@ -220,6 +238,13 @@ class SwitchesConversionTable: public ConversionTable {
val++;
}
for (int i=1; i<=MAX_FUNCTIONSWITCHES_POSITION(board, version); i++) {
int s = switchIndex(i, board, version);
addConversion(RawSwitch(SWITCH_TYPE_FUNCTIONSWITCH, s), val);
addConversion(RawSwitch(SWITCH_TYPE_FUNCTIONSWITCH, -s), -val+offset);
val++;
}
if (IS_HORUS_OR_TARANIS(board)) {
for (int i=1; i<=MAX_XPOTS(board, version)*6; i++) {
addConversion(RawSwitch(SWITCH_TYPE_MULTIPOS_POT, -i), -val+offset);
@@ -368,8 +393,10 @@ class SourcesConversionTable: public ConversionTable {
addConversion(RawSource(SOURCE_TYPE_SWITCH, 0), val++);
if (!(flags & FLAG_NOSWITCHES)) {
for (int i=1; i<MAX_SWITCHES(board, version); i++)
for (int i=1; i<MAX_SWITCHES_SOURCE(board, version); i++)
addConversion(RawSource(SOURCE_TYPE_SWITCH, i), val++);
for (int i=0; i<MAX_FUNCTIONSWITCHES(board, version); i++)
addConversion(RawSource(SOURCE_TYPE_FUNCTIONSWITCH, i), val++);
for (int i=0; i<MAX_LOGICAL_SWITCHES(board, version); i++)
addConversion(RawSource(SOURCE_TYPE_CUSTOM_SWITCH, i), val++);
}
@@ -2877,7 +2904,7 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig
internalField.Append(new UnsignedField<16>(this, modelData.functionSwitchGroup));
internalField.Append(new UnsignedField<16>(this, modelData.functionSwitchStartConfig));
internalField.Append(new UnsignedField<8>(this, modelData.functionSwitchLogicalState));
for (int i=0; i < MAX_FUNCTION_SWITCHES(board, version); ++i) {
for (int i=0; i < Boards::getCapability(board, Board::FunctionSwitches); ++i) {
internalField.Append(new ZCharField<3>(this, modelData.functionSwitchNames[i], "Function switch name"));
}
}
@@ -3209,7 +3236,7 @@ OpenTxGeneralData::OpenTxGeneralData(GeneralSettings & generalData, Board::Type
if (IS_TARANIS_X9E(board))
internalField.Append(new SpareBitsField<64>(this)); // switchUnlockStates
else if (version >= 219 && IS_TARANIS_X9D(board))
else if (version >= 219 && (IS_TARANIS_X9D(board) || IS_JUMPER_TPRO(board)))
internalField.Append(new SpareBitsField<32>(this)); // switchUnlockStates
else if (IS_TARANIS(board))
internalField.Append(new SpareBitsField<16>(this)); // switchUnlockStates
@@ -757,8 +757,6 @@ int OpenTxFirmware::getCapability(::Capability capability)
return IS_HORUS_OR_TARANIS(board);
case TopBarZones:
return getCapability(LcdWidth) > getCapability(LcdHeight) ? 4 : 2;
case FunctionSwitches:
return IS_JUMPER_TPRO(board) ? 6 : 0;
case HasModelsList:
return IS_FAMILY_HORUS_OR_T16(board);
case HasFlySkyGimbals:
+14
View File
@@ -196,6 +196,13 @@ QString RawSource::toString(const ModelData * model, const GeneralSettings * con
result = Boards::getSwitchInfo(board, index).name;
return result;
case SOURCE_TYPE_FUNCTIONSWITCH:
if (model)
result = QString(model->functionSwitchNames[index]).trimmed();
if (result.isEmpty())
result = tr("SW%1").arg(index + 1);
return result;
case SOURCE_TYPE_CUSTOM_SWITCH:
return RawSwitch(SWITCH_TYPE_VIRTUAL, index + 1).toString();
@@ -309,10 +316,17 @@ bool RawSource::isAvailable(const ModelData * const model, const GeneralSettings
if (type == SOURCE_TYPE_SWITCH && index >= b.getCapability(Board::Switches))
return false;
if (type == SOURCE_TYPE_FUNCTIONSWITCH)
if (!model || index >= b.getCapability(Board::FunctionSwitches))
return false;
if (type == SOURCE_TYPE_SPECIAL && index >= SOURCE_TYPE_SPECIAL_FIRST_RESERVED && index <= SOURCE_TYPE_SPECIAL_LAST_RESERVED)
return false;
if (model) {
if (type == SOURCE_TYPE_FUNCTIONSWITCH && !model->isFunctionSwitchSourceAllowed(index))
return false;
if (type == SOURCE_TYPE_VIRTUAL_INPUT && !model->isInputValid(index))
return false;
+1
View File
@@ -169,6 +169,7 @@ enum RawSourceType {
SOURCE_TYPE_TRIM,
SOURCE_TYPE_MAX,
SOURCE_TYPE_SWITCH,
SOURCE_TYPE_FUNCTIONSWITCH,
SOURCE_TYPE_CUSTOM_SWITCH,
SOURCE_TYPE_CYC,
SOURCE_TYPE_PPM,
+22 -4
View File
@@ -73,7 +73,7 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen
switch(type) {
case SWITCH_TYPE_SWITCH:
if (IS_HORUS_OR_TARANIS(board)) {
qr = div(index-1, 3);
qr = div(index - 1, 3);
if (generalSettings)
swName = QString(generalSettings->switchName[qr.quot]).trimmed();
if (swName.isEmpty())
@@ -90,9 +90,19 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen
else
return LogicalSwitchData().nameToString(index-1);
case SWITCH_TYPE_FUNCTIONSWITCH:
if (!Boards::getCapability(board, Board::FunctionSwitches))
return CPN_STR_UNKNOWN_ITEM;
qr = div(index - 1, 3);
if (modelData)
swName = QString(modelData->functionSwitchNames[qr.quot]).trimmed();
if (swName.isEmpty())
swName = tr("SW%1").arg(qr.quot + 1);
return swName + directionIndicators.at(qr.rem > -1 && qr.rem < directionIndicators.size() ? qr.rem : 1);
case SWITCH_TYPE_MULTIPOS_POT:
if (!Boards::getCapability(board, Board::MultiposPotsPositions))
return tr("???");
return CPN_STR_UNKNOWN_ITEM;
qr = div(index - 1, Boards::getCapability(board, Board::MultiposPotsPositions));
if (generalSettings && qr.quot < (int)DIM(generalSettings->potConfig))
swName = QString(generalSettings->potName[qr.quot]);
@@ -140,8 +150,8 @@ QString RawSwitch::toString(Board::Type board, const GeneralSettings * const gen
return tr("Telemetry");
default:
return tr("???");
}
return CPN_STR_UNKNOWN_ITEM;
}
}
}
@@ -155,6 +165,13 @@ bool RawSwitch::isAvailable(const ModelData * const model, const GeneralSettings
if (type == SWITCH_TYPE_SWITCH && abs(index) > b.getCapability(Board::SwitchPositions))
return false;
if (type == SWITCH_TYPE_FUNCTIONSWITCH) {
if (!model || abs(index) > b.getCapability(Board::NumFunctionSwitchesPositions))
return false;
else if (!model->isFunctionSwitchPositionAvailable(abs(index)))
return false;
}
if (type == SWITCH_TYPE_TRIM && abs(index) > b.getCapability(Board::NumTrimSwitches))
return false;
@@ -257,6 +274,7 @@ StringTagMappingTable RawSwitch::getRawSwitchTypesLookupTable()
{std::to_string(SWITCH_TYPE_ON), "ON"},
{std::to_string(SWITCH_TYPE_OFF), "OFF"},
{std::to_string(SWITCH_TYPE_ONE), "ONE"},
{std::to_string(SWITCH_TYPE_FUNCTIONSWITCH), "Sxn"},
{std::to_string(SWITCH_TYPE_FLIGHT_MODE), "FMn"},
{std::to_string(SWITCH_TYPE_TIMER_MODE), "Timer"},
{std::to_string(SWITCH_TYPE_TELEMETRY), "TELEMETRY_STREAMING"},
+1
View File
@@ -34,6 +34,7 @@ class RadioDataConversionState;
enum RawSwitchType {
SWITCH_TYPE_NONE,
SWITCH_TYPE_SWITCH,
SWITCH_TYPE_FUNCTIONSWITCH,
SWITCH_TYPE_VIRTUAL,
SWITCH_TYPE_MULTIPOS_POT,
SWITCH_TYPE_TRIM,
+18
View File
@@ -305,6 +305,24 @@ void Helpers::exportAppSettings(QWidget * dlgParent)
exportAppSettings(dlgParent);
}
unsigned int Helpers::getBitmappedValue(const unsigned int & field, const unsigned int index, const unsigned int numbits, const unsigned int offset)
{
int mask = -1;
mask = mask << numbits;
mask = ~mask;
return (field >> (numbits * index + offset)) & (unsigned int)mask;
}
void Helpers::setBitmappedValue(unsigned int & field, unsigned int value, unsigned int index, unsigned int numbits, unsigned int offset)
{
int mask = -1;
mask = mask << numbits;
mask = ~mask;
unsigned int fieldmask = ((unsigned int)mask << (numbits * index + offset));
field = (field & ~fieldmask) | (value << (numbits * index + offset));
}
void startSimulation(QWidget * parent, RadioData & radioData, int modelIdx)
{
QString fwId = SimulatorLoader::findSimulatorByFirmwareName(getCurrentFirmware()->getId());
+2
View File
@@ -113,6 +113,8 @@ namespace Helpers
QString getChecklistFilename(const ModelData * model);
QString getChecklistFilePath(const ModelData * model);
QString removeAccents(const QString & str);
unsigned int getBitmappedValue(const unsigned int & field, const unsigned int index, const unsigned int numbits = 1, const unsigned int offset = 0);
void setBitmappedValue(unsigned int & field, unsigned int value, unsigned int index, unsigned int numbits = 1, unsigned int offset = 0);
} // namespace Helpers
+36 -26
View File
@@ -1026,7 +1026,7 @@ FunctionSwitchesPanel::FunctionSwitchesPanel(QWidget * parent, ModelData & model
QRegExp rx(CHAR_FOR_NAMES_REGEX);
switchcnt = Boards::getCapability(firmware->getBoard(), Board::NumFunctionSwitches);
switchcnt = Boards::getCapability(firmware->getBoard(), Board::FunctionSwitches);
for (int i = 0; i < switchcnt; i++) {
QLabel * lblSwitchId = new QLabel(this);
@@ -1062,6 +1062,7 @@ FunctionSwitchesPanel::FunctionSwitchesPanel(QWidget * parent, ModelData & model
ui->gridSwitches->addWidget(sbGroup, row++, i + coloffset);
ui->gridSwitches->addWidget(cbAlwaysOnGroup, row++, i + coloffset);
connect(aleName, &AutoLineEdit::currentDataChanged, this, &FunctionSwitchesPanel::on_nameEditingFinished);
connect(cboConfig, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FunctionSwitchesPanel::on_configCurrentIndexChanged);
connect(cboStartPosn, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &FunctionSwitchesPanel::on_startPosnCurrentIndexChanged);
connect(sbGroup, QOverload<int>::of(&QSpinBox::valueChanged), this, &FunctionSwitchesPanel::on_groupChanged);
@@ -1097,11 +1098,11 @@ void FunctionSwitchesPanel::update(int index)
for (int i = 0; i < switchcnt; i++) {
aleNames[i]->update();
cboConfigs[i]->setCurrentIndex((model->functionSwitchConfig >> (2 * i)) & 0x03);
cboStartupPosns[i]->setCurrentIndex((model->functionSwitchStartConfig >> (2 * i)) & 0x03);
const int grp = (model->functionSwitchGroup >> (2 * i)) & 0x03;
cboConfigs[i]->setCurrentIndex(model->getFuncSwitchConfig(i));
cboStartupPosns[i]->setCurrentIndex(model->getFuncSwitchStart(i));
unsigned int grp = model->getFuncSwitchGroup(i);
sbGroups[i]->setValue(grp);
cbAlwaysOnGroups[i]->setChecked((model->functionSwitchGroup >> (2 * switchcnt + grp)) & 0x01);
cbAlwaysOnGroups[i]->setChecked(model->getFuncSwitchAlwaysOnGroup(i));
if (cboConfigs[i]->currentIndex() < 2)
cboStartupPosns[i]->setEnabled(false);
@@ -1122,6 +1123,12 @@ void FunctionSwitchesPanel::update(int index)
lock = false;
}
void FunctionSwitchesPanel::on_nameEditingFinished()
{
emit updateDataModels();
}
void FunctionSwitchesPanel::on_configCurrentIndexChanged(int index)
{
if (!sender())
@@ -1132,17 +1139,17 @@ void FunctionSwitchesPanel::on_configCurrentIndexChanged(int index)
if (cb && !lock) {
lock = true;
bool ok = false;
int i = sender()->property("index").toInt(&ok);
if (ok && ((model->functionSwitchConfig >> (2 * i)) & 0x03) != (unsigned int)index) {
unsigned int mask = ((unsigned int) 0x03 << (2 * i));
model->functionSwitchConfig = (model->functionSwitchConfig & ~ mask) | ((unsigned int) index << (2 * i));
unsigned int i = sender()->property("index").toInt(&ok);
if (ok && model->getFuncSwitchConfig(i) != (unsigned int)index) {
model->setFuncSwitchConfig(i, index);
if (index < 2)
model->functionSwitchStartConfig = (model->functionSwitchStartConfig & ~ mask) | ((unsigned int) 0 << (2 * i));
model->setFuncSwitchStart(i, ModelData::FUNC_SWITCH_START_INACTIVE);
if (index < 1)
model->functionSwitchGroup = (model->functionSwitchGroup & ~ mask) | ((unsigned int) 0 << (2 * i));
model->setFuncSwitchGroup(i, 0);
update(i);
emit modified();
}
emit updateDataModels();
}
lock = false;
}
}
@@ -1157,10 +1164,9 @@ void FunctionSwitchesPanel::on_startPosnCurrentIndexChanged(int index)
if (cb && !lock) {
lock = true;
bool ok = false;
int i = sender()->property("index").toInt(&ok);
if (ok && ((model->functionSwitchStartConfig >> (2 * i)) & 0x03) != (unsigned int)index) {
unsigned int mask = ((unsigned int) 0x03 << (2 * i));
model->functionSwitchStartConfig = (model->functionSwitchStartConfig & ~ mask) | ((unsigned int) index << (2 * i));
unsigned int i = sender()->property("index").toInt(&ok);
if (ok && model->getFuncSwitchStart(i) != (unsigned int)index) {
model->setFuncSwitchStart(i, index);
emit modified();
}
lock = false;
@@ -1178,9 +1184,8 @@ void FunctionSwitchesPanel::on_groupChanged(int value)
lock = true;
bool ok = false;
int i = sender()->property("index").toInt(&ok);
if (ok && ((model->functionSwitchGroup >> (2 * i)) & 0x03) != (unsigned int)value) {
unsigned int mask = ((unsigned int) 0x03 << (2 * i));
model->functionSwitchGroup = (model->functionSwitchGroup & ~ mask) | ((unsigned int) value << (2 * i));
if (ok && model->getFuncSwitchGroup(i) != (unsigned int)value) {
model->setFuncSwitchGroup(i, (unsigned int)value);
update(i);
emit modified();
}
@@ -1201,9 +1206,7 @@ void FunctionSwitchesPanel::on_alwaysOnGroupChanged(int value)
int i = sender()->property("index").toInt(&ok);
if (ok) {
const int grp = (model->functionSwitchGroup >> (2 * i)) & 0x03;
unsigned int mask = ((unsigned int) 0x01 << (2 * switchcnt + grp));
model->functionSwitchGroup = (model->functionSwitchGroup & ~ mask) | ((unsigned int) value << (2 * switchcnt + grp));
model->setFuncSwitchAlwaysOnGroup(i, (unsigned int)value);
update();
emit modified();
}
@@ -1458,10 +1461,12 @@ SetupPanel::SetupPanel(QWidget * parent, ModelData & model, GeneralSettings & ge
ui->trimsDisplay->setField(model.trimsDisplay, this);
if (Boards::getCapability(firmware->getBoard(), Board::NumFunctionSwitches) > 0)
ui->functionSwitchesLayout->addWidget(new FunctionSwitchesPanel(this, model, generalSettings, firmware));
//else
// ui->functionSwitchesLayout->hide();
if (Boards::getCapability(firmware->getBoard(), Board::FunctionSwitches) > 0) {
funcswitches = new FunctionSwitchesPanel(this, model, generalSettings, firmware);
ui->functionSwitchesLayout->addWidget(funcswitches);
connect(funcswitches, &FunctionSwitchesPanel::modified, this, &SetupPanel::modified);
connect(funcswitches, &FunctionSwitchesPanel::updateDataModels, this, &SetupPanel::onFunctionSwitchesUpdateItemModels);
}
for (int i = firmware->getCapability(NumFirstUsableModule); i < firmware->getCapability(NumModules); i++) {
modules[i] = new ModulePanel(this, model, model.moduleData[i], generalSettings, firmware, i, panelFilteredModels);
@@ -2001,3 +2006,8 @@ void SetupPanel::onModuleUpdateItemModels()
{
sharedItemModels->update(AbstractItemModel::IMUE_Modules);
}
void SetupPanel::onFunctionSwitchesUpdateItemModels()
{
sharedItemModels->update(AbstractItemModel::IMUE_FunctionSwitches);
}
+7
View File
@@ -143,7 +143,11 @@ class FunctionSwitchesPanel : public ModelPanel
virtual void update();
void update(int index);
signals:
void updateDataModels();
private slots:
void on_nameEditingFinished();
void on_configCurrentIndexChanged(int index);
void on_startPosnCurrentIndexChanged(int index);
void on_groupChanged(int value);
@@ -207,6 +211,7 @@ class SetupPanel : public ModelPanel
void onItemModelAboutToBeUpdated();
void onItemModelUpdateComplete();
void onModuleUpdateItemModels();
void onFunctionSwitchesUpdateItemModels();
void on_jitterFilter_currentIndexChanged(int index);
private:
@@ -217,6 +222,8 @@ class SetupPanel : public ModelPanel
QVector<QCheckBox *> centerBeepCheckboxes;
ModulePanel * modules[CPN_MAX_MODULES + 1];
TimerPanel * timers[CPN_MAX_TIMERS];
FunctionSwitchesPanel * funcswitches;
void updateStartupSwitches();
void updatePotWarnings();
void updateBeepCenter();
+4 -4
View File
@@ -369,7 +369,7 @@ QString ModelPrinter::printInputLine(const ExpoData & input)
str += " " + flightModesStr.toHtmlEscaped();
if (input.swtch.type != SWITCH_TYPE_NONE)
str += " " + tr("Switch(%1)").arg(input.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
str += " " + tr("Switch(%1)").arg(input.swtch.toString(getCurrentBoard(), &generalSettings, &model)).toHtmlEscaped();
if (firmware->getCapability(VirtualInputs)) {
@@ -418,7 +418,7 @@ QString ModelPrinter::printMixerLine(const MixData & mix, bool showMultiplex, in
str += " " + flightModesStr.toHtmlEscaped();
if (mix.swtch.type != SWITCH_TYPE_NONE)
str += " " + tr("Switch(%1)").arg(mix.swtch.toString(getCurrentBoard(), &generalSettings)).toHtmlEscaped();
str += " " + tr("Switch(%1)").arg(mix.swtch.toString(getCurrentBoard(), &generalSettings, &model)).toHtmlEscaped();
if (mix.carryTrim > 0)
str += " " + tr("NoTrim");
@@ -650,7 +650,7 @@ QString ModelPrinter::printCurveName(int idx)
QString ModelPrinter::printCurve(int idx)
{
const CurveData & curve = model.curves[idx];
const CurveData & curve = model.curves[idx];
return QString("%1 %2").arg(curve.typeToString()).arg(curve.pointsToString());
}
@@ -759,7 +759,7 @@ QString ModelPrinter::printSwitchWarnings()
uint64_t switchStates = model.switchWarningStates;
uint64_t value;
for (int idx=0; idx<board.getCapability(Board::Switches); idx++) {
for (int idx=0; idx<board.getCapability(Board::Switches) + board.getCapability(Board::FunctionSwitches); idx++) {
Board::SwitchInfo switchInfo = Boards::getSwitchInfo(board.getBoardType(), idx);
switchInfo.config = Board::SwitchType(generalSettings.switchConfig[idx]);
if (switchInfo.config == Board::SWITCH_NOT_AVAILABLE || switchInfo.config == Board::SWITCH_TOGGLE) {
+46 -37
View File
@@ -277,9 +277,10 @@ QString MultiModelPrinter::print(QTextDocument * document)
if (firmware->getCapability(Timers)) {
str.append(printTimers());
}
if (Boards::getCapability(firmware->getBoard(), Board::NumFunctionSwitches)) {
if (Boards::getCapability(firmware->getBoard(), Board::FunctionSwitches)) {
str.append(printFunctionSwitches());
}
str.append(printModules());
if (firmware->getCapability(Heli))
str.append(printHeliSetup());
@@ -942,51 +943,59 @@ QString MultiModelPrinter::printChecklist()
return str;
}
QString MultiModelPrinter::printFunctionSwitches()
{
QString str;
MultiColumns columns(modelPrinterMap.size());
columns.appendSectionTableStart();
int numFS = Boards::getCapability(firmware->getBoard(), Board::NumFunctionSwitches);
int colwidth = 80 / numFS;
QString MultiModelPrinter::printFunctionSwitches()
{
QString str;
MultiColumns columns(modelPrinterMap.size());
columns.appendSectionTableStart();
QStringList headings = { tr("Function Switches") };
for (int i = 0; i < numFS; i++) {
headings << tr("Switch %1").arg(i + 1);
}
columns.appendRowHeader(headings);
int numFS = Boards::getCapability(firmware->getBoard(), Board::FunctionSwitches);
int colwidth = 80 / numFS;
columns.appendRowStart(tr("Name"), 20);
QStringList headings = { tr("Function Switches") };
for (int i = 0; i < numFS; i++) {
headings << tr("Switch %1").arg(i + 1);
}
columns.appendRowHeader(headings);
for (int i = 0; i < numFS; i++) {
COMPARECELLWIDTH(model->functionSwitchNames[i], colwidth);
}
columns.appendRowStart(tr("Name"), 20);
columns.appendRowEnd();
columns.appendRowStart(tr("Type"), 20);
for (int i = 0; i < numFS; i++) {
COMPARECELLWIDTH(model->functionSwitchNames[i], colwidth);
}
for (int i = 0; i < numFS; i++) {
COMPARECELLWIDTH(model->funcSwitchConfigToString((unsigned int)i), colwidth);
}
columns.appendRowEnd();
columns.appendRowStart(tr("Type"), 20);
columns.appendRowEnd();
columns.appendRowStart(tr("Start"), 20);
for (int i = 0; i < numFS; i++) {
COMPARECELLWIDTH(model->funcSwitchConfigToString(model->getFuncSwitchConfig((unsigned int)i)), colwidth);
}
for (int i = 0; i < numFS; i++) {
COMPARECELLWIDTH(model->funcSwitchStartToString((unsigned int)i), colwidth);
}
columns.appendRowEnd();
columns.appendRowStart(tr("Start"), 20);
columns.appendRowEnd();
columns.appendRowStart(tr("Group"), 20);
for (int i = 0; i < numFS; i++) {
COMPARECELLWIDTH(model->funcSwitchStartToString(model->getFuncSwitchStart((unsigned int)i)), colwidth);
}
for (int i = 0; i < numFS; i++) {
COMPARECELLWIDTH((model->functionSwitchGroup >> (2 * i)) & 0x03, colwidth);
}
columns.appendRowEnd();
columns.appendRowStart(tr("Group"), 20);
columns.appendRowEnd();
for (int i = 0; i < numFS; i++) {
COMPARECELLWIDTH(model->getFuncSwitchGroup((unsigned int)i), colwidth);
}
columns.appendTableEnd();
str.append(columns.print());
return str;
}
columns.appendRowEnd();
columns.appendRowStart(tr("Always On"), 20);
for (int i = 0; i < numFS; i++) {
COMPARECELLWIDTH((model->getFuncSwitchAlwaysOnGroup((unsigned int)i) == 0 ? "No" : "Yes"), colwidth);
}
columns.appendRowEnd();
columns.appendTableEnd();
str.append(columns.print());
return str;
}