From 4946f946fdbd3cd21a9a27f650cf82572f8a5817 Mon Sep 17 00:00:00 2001 From: Raphael Coeffic Date: Sun, 18 Aug 2019 17:45:35 +0200 Subject: [PATCH] use proper structures for module union fields .. and quite some fixes. --- companion/src/firmwares/eepromimportexport.h | 72 +++++ companion/src/firmwares/moduledata.cpp | 1 + companion/src/firmwares/moduledata.h | 23 +- .../src/firmwares/opentx/opentxeeprom.cpp | 289 ++++++++++++------ companion/src/firmwares/opentx/opentxeeprom.h | 2 +- 5 files changed, 292 insertions(+), 95 deletions(-) diff --git a/companion/src/firmwares/eepromimportexport.h b/companion/src/firmwares/eepromimportexport.h index e5cbab7e5..be562fb41 100644 --- a/companion/src/firmwares/eepromimportexport.h +++ b/companion/src/firmwares/eepromimportexport.h @@ -585,6 +585,78 @@ class TransformedField: public DataField { DataField & field; }; +template +class UnionField: public DataField { + public: + + class UnionMember { + public: + virtual ~UnionMember() {} + virtual bool select(const selectorT& attr) const = 0; + virtual DataField* getField() = 0; + }; + + class TransformedMember: public UnionMember, public TransformedField { + public: + TransformedMember(DataField* parent, DataField& field): + TransformedField(parent, field) + { + } + virtual DataField* getField() + { + return this; + } + }; + + UnionField(DataField * parent, selectorT& selectField, const char * name="Union"): + DataField(parent, name), selectField(selectField), maxSize(0) + { + } + + ~UnionField() { + foreach(UnionMember *member, members) { + delete member; + } + } + + inline void Append(UnionMember * member) { + members.append(member); + if (member->getField()->size() > maxSize) + maxSize = member->getField()->size(); + } + + virtual void ExportBits(QBitArray & output) + { + foreach(UnionMember *member, members) { + if (member->select(selectField)) { + member->getField()->ExportBits(output); + break; + } + } + output.resize(maxSize); + } + + virtual void ImportBits(const QBitArray & input) + { + foreach(UnionMember *member, members) { + if (member->select(selectField)) { + member->getField()->ImportBits(input); + break; + } + } + } + + virtual unsigned int size() + { + return maxSize; + } + + protected: + selectorT& selectField; + QList members; + unsigned int maxSize; +}; + class ConversionTable { public: diff --git a/companion/src/firmwares/moduledata.cpp b/companion/src/firmwares/moduledata.cpp index 4b11df7af..001d0d956 100644 --- a/companion/src/firmwares/moduledata.cpp +++ b/companion/src/firmwares/moduledata.cpp @@ -105,6 +105,7 @@ QString ModuleData::protocolToString(unsigned protocol) "DIY Multiprotocol Module", "FrSky PXX R9M", "FrSky PXX R9M Lite", + "FrSky PXX R9M Lite Pro", "SBUS output at VBat", "FrSky ACCESS ISRM", "FrSky ACCST ISRM D16", "FrSky ACCESS R9M", diff --git a/companion/src/firmwares/moduledata.h b/companion/src/firmwares/moduledata.h index 2f940c504..1752afb64 100644 --- a/companion/src/firmwares/moduledata.h +++ b/companion/src/firmwares/moduledata.h @@ -48,6 +48,7 @@ enum PulsesProtocol { PULSES_MULTIMODULE, PULSES_PXX_R9M, PULSES_PXX_R9M_LITE, + PULSES_PXX_R9M_LITE_PRO, PULSES_SBUS, PULSES_ACCESS_ISRM, PULSES_ACCST_ISRM_D16, @@ -130,13 +131,18 @@ enum ModuleSubtypeR9M { MODULE_SUBTYPE_R9M_LAST=MODULE_SUBTYPE_R9M_AUPLUS }; +constexpr unsigned int PXX2_MAX_RECEIVERS_PER_MODULE = 3; +constexpr unsigned int PXX2_LEN_RX_NAME = 8; + class ModuleData { Q_DECLARE_TR_FUNCTIONS(ModuleData) public: ModuleData() { clear(); } unsigned int modelId; - int protocol; + unsigned int protocol; // type in datastructs.h + int rfProtocol; // rfProtocol in datastructs.h + unsigned int subType; bool invertedSerial; unsigned int channelsStart; @@ -144,14 +150,14 @@ class ModuleData { unsigned int failsafeMode; int failsafeChannels[CPN_MAX_CHNOUT]; - struct { + struct PPM { int delay; bool pulsePol; // false = positive bool outputType; // false = open drain, true = push pull int frameLength; } ppm; - struct { + struct Multi { unsigned int rfProtocol; bool autoBindMode; bool lowPowerMode; @@ -159,18 +165,17 @@ class ModuleData { int optionValue; } multi; - struct { - int power; // 0 10 mW, 1 100 mW, 2 500 mW, 3 1W + struct PXX { + unsigned int power; // 0 10 mW, 1 100 mW, 2 500 mW, 3 1W bool receiver_telem_off; // false = receiver telem enabled bool receiver_channel_9_16; // false = pwm out 1-8, true 9-16 bool external_antenna; // false = internal antenna, true = external antenna bool sport_out; } pxx; - struct { - // unsigned int receivers; - // char receiverName[3][8]; - char data[1 + 3 * 8]; + struct Access { + unsigned int receivers; + char receiverName[PXX2_MAX_RECEIVERS_PER_MODULE][PXX2_LEN_RX_NAME]; } access; void clear() { memset(this, 0, sizeof(ModuleData)); } diff --git a/companion/src/firmwares/opentx/opentxeeprom.cpp b/companion/src/firmwares/opentx/opentxeeprom.cpp index a23c439ea..591f67341 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.cpp +++ b/companion/src/firmwares/opentx/opentxeeprom.cpp @@ -1939,14 +1939,213 @@ class SensorField: public TransformedField { int exportPpmDelay(int delay) { return (delay - 300) / 50; } int importPpmDelay(int delay) { return 300 + 50 * delay; } +class ModuleUnionField: public UnionField { + + class PPMField: public UnionField::UnionMember, public StructField { + public: + PPMField(DataField * parent, ModuleData::PPM& ppm): + StructField(parent, "PPM") + { + Append(new ConversionField< SignedField<6> >(parent, ppm.delay, exportPpmDelay, importPpmDelay)); + Append(new BoolField<1>(parent, ppm.pulsePol)); + Append(new BoolField<1>(parent, ppm.outputType)); + Append(new SignedField<8>(parent, ppm.frameLength)); + } + + virtual bool select(const unsigned int& attr) const + { + return true; // take what's left + } + + virtual DataField* getField() + { + return this; + } + }; + + class MultiField: public UnionField::TransformedMember { + public: + MultiField(DataField * parent, ModuleData& module): + UnionField::TransformedMember(parent, internalField), + internalField(this, "Multi"), + module(module), + rfProtExtra(0) + { + ModuleData::Multi& multi = module.multi; + internalField.Append(new UnsignedField<2>(this, rfProtExtra)); + internalField.Append(new SpareBitsField<3>(this)); + internalField.Append(new BoolField<1>(this, multi.autoBindMode)); + internalField.Append(new BoolField<1>(this, multi.lowPowerMode)); + internalField.Append(new BoolField<1>(this, multi.customProto)); + internalField.Append(new SignedField<8>(this, multi.optionValue)); + } + + virtual bool select(const unsigned int& attr) const + { + return attr==PULSES_MULTIMODULE; + } + + virtual void beforeExport() + { + module.rfProtocol = module.multi.rfProtocol & 0xf; + rfProtExtra = (module.multi.rfProtocol >> 4) & 0x03; + } + + virtual void afterImport() + { + module.multi.rfProtocol = + (rfProtExtra & 0x3) << 4 | (module.rfProtocol & 0xf); + } + + private: + StructField internalField; + ModuleData& module; + unsigned int rfProtExtra; + }; + + class PxxField: public UnionField::TransformedMember { + public: + PxxField(DataField * parent, ModuleData& module): + UnionField::TransformedMember(parent, internalField), + internalField(this, "Pxx"), + module(module) + { + ModuleData::PXX& pxx = module.pxx; + internalField.Append(new UnsignedField<2>(this, pxx.power)); + internalField.Append(new SpareBitsField<2>(this)); + internalField.Append(new BoolField<1>(this, pxx.receiver_telem_off)); + internalField.Append(new BoolField<1>(this, pxx.receiver_channel_9_16)); + internalField.Append(new BoolField<1>(this, pxx.external_antenna)); + internalField.Append(new BoolField<1>(this, pxx.sport_out)); + } + + bool select(const unsigned int& attr) const { + return attr==PULSES_PXX_XJT_X16 || + attr==PULSES_PXX_DJT || + attr==PULSES_PXX_R9M || + attr==PULSES_PXX_R9M_LITE; + } + + virtual void beforeExport() + { + if (module.protocol >= PULSES_PXX_XJT_X16 && module.protocol <= PULSES_PXX_XJT_LR12) { + module.subType = module.protocol - PULSES_PXX_XJT_X16; + } + } + + virtual void afterImport() + { + if (module.protocol == PULSES_PXX_XJT_X16) { + module.protocol += module.subType; + } + } + + private: + StructField internalField; + ModuleData& module; + }; + + class AccessField: public UnionField::TransformedMember { + public: + AccessField(DataField * parent, ModuleData& module): + UnionField::TransformedMember(parent, internalField), + internalField(this, "Access"), + module(module) + { + internalField.Append(new UnsignedField<3>(this, module.access.receivers)); + internalField.Append(new SpareBitsField<5>(this)); + + for (int i=0; i(this, module.access.receiverName[i])); + } + + bool select(const unsigned int& attr) const { + return attr >= PULSES_ACCESS_ISRM && attr <= PULSES_ACCESS_R9M_LITE_PRO; + } + + virtual void beforeExport() + { + if (module.protocol == PULSES_ACCST_ISRM_D16 || + module.protocol == PULSES_ACCESS_ISRM) { + module.subType = module.protocol - PULSES_ACCESS_ISRM; + } + } + + virtual void afterImport() + { + if (module.protocol == PULSES_ACCESS_ISRM) { + module.protocol += module.subType; + } + } + + private: + StructField internalField; + ModuleData& module; + }; + + public: + ModuleUnionField(DataField * parent, ModuleData & module): + UnionField(parent, module.protocol) + { + Append(new AccessField(parent, module)); + Append(new PxxField(parent, module)); + Append(new MultiField(parent, module)); + Append(new PPMField(parent, module.ppm)); + } +}; + + +class ModuleField: public TransformedField { + public: + ModuleField(DataField * parent, ModuleData & module, Board::Type board, unsigned int version): + TransformedField(parent, internalField), + internalField(this, "Module"), + module(module), + protocolsConversionTable(board) + { + internalField.Append(new ConversionField >(this, module.protocol, &protocolsConversionTable, "Protocol", DataField::tr("OpenTX doesn't accept this radio protocol"))); + internalField.Append(new SignedField<4>(this, module.rfProtocol)); + internalField.Append(new UnsignedField<8>(this, module.channelsStart)); + internalField.Append(new ConversionField >(this, module.channelsCount, -8)); + internalField.Append(new UnsignedField<4>(this, module.failsafeMode)); + internalField.Append(new UnsignedField<3>(this, module.subType)); + internalField.Append(new BoolField<1>(this, module.invertedSerial)); + if (version <= 218) { + for (int i=0; i<32; i++) { + internalField.Append(new SignedField<16>(this, module.failsafeChannels[i])); + } + } + + internalField.Append(new ModuleUnionField(parent, module)); + } + + virtual void beforeExport() + { + if (module.protocol >= PULSES_LP45 && module.protocol <= PULSES_DSMX) { + module.rfProtocol = module.protocol - PULSES_LP45; + } + } + + virtual void afterImport() + { + if (module.protocol == PULSES_LP45) { + module.protocol += module.rfProtocol; + } + } + + private: + StructField internalField; + ModuleData& module; + ProtocolsConversionTable protocolsConversionTable; +}; + OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsigned int version, unsigned int variant): TransformedField(nullptr, internalField), internalField(this, "ModelData"), modelData(modelData), board(board), version(version), - variant(variant), - protocolsConversionTable(board) + variant(variant) { sprintf(name, "Model %s", modelData.name); @@ -2094,26 +2293,8 @@ OpenTxModelData::OpenTxModelData(ModelData & modelData, Board::Type board, unsig int modulesCount = (version <= 218 ? 3 : 2); for (int module=0; module >(this, modelData.moduleData[module].protocol, &protocolsConversionTable, "Protocol", DataField::tr("OpenTX doesn't accept this radio protocol"))); - internalField.Append(new SignedField<4>(this, subprotocols[module])); - internalField.Append(new UnsignedField<8>(this, modelData.moduleData[module].channelsStart)); - internalField.Append(new ConversionField >(this, modelData.moduleData[module].channelsCount, -8)); - internalField.Append(new UnsignedField<4>(this, modelData.moduleData[module].failsafeMode)); - internalField.Append(new UnsignedField<3>(this, modelData.moduleData[module].subType)); - internalField.Append(new BoolField<1>(this, modelData.moduleData[module].invertedSerial)); - if (version <= 218) { - for (int i=0; i<32; i++) { - internalField.Append(new SignedField<16>(this, modelData.moduleData[module].failsafeChannels[i])); - } - } - internalField.Append(new ConversionField< SignedField<6> >(this, modelData.moduleData[module].ppm.delay, exportPpmDelay, importPpmDelay)); - internalField.Append(new BoolField<1>(this, modelData.moduleData[module].ppm.pulsePol)); - internalField.Append(new BoolField<1>(this, modelData.moduleData[module].ppm.outputType)); - internalField.Append(new SignedField<8>(this, modelData.moduleData[module].ppm.frameLength)); - if (version >= 219) { - // TODO ACCESS - internalField.Append(new CharField<1 + 3 * 8 - 2>(this, modelData.moduleData[module].access.data)); - } + + internalField.Append(new ModuleField(this, modelData.moduleData[module], board, version)); } if (version >= 219) { @@ -2221,38 +2402,6 @@ void OpenTxModelData::beforeExport() // qDebug() << QString("before export model") << modelData.name; for (int module=0; module<2; module++) { - if ((modelData.moduleData[module].protocol >= PULSES_PXX_XJT_X16 && modelData.moduleData[module].protocol <= PULSES_PXX_XJT_LR12) || - modelData.moduleData[module].protocol == PULSES_PXX_R9M) { - - if (modelData.moduleData[module].protocol != PULSES_PXX_R9M) { - subprotocols[module] = modelData.moduleData[module].protocol - PULSES_PXX_XJT_X16; - } - int pxxByte = (modelData.moduleData[module].pxx.power & 0x03) - | modelData.moduleData[module].pxx.receiver_telem_off << 4 - | modelData.moduleData[module].pxx.receiver_channel_9_16 << 5; - modelData.moduleData[module].ppm.delay = 300 + 50 * pxxByte; - modelData.moduleData[module].ppm.pulsePol = modelData.moduleData[module].pxx.external_antenna; - modelData.moduleData[module].ppm.outputType = modelData.moduleData[module].pxx.sport_out; - } - else if (modelData.moduleData[module].protocol >= PULSES_LP45 && modelData.moduleData[module].protocol <= PULSES_DSMX) { - subprotocols[module] = modelData.moduleData[module].protocol - PULSES_LP45; - } - else if (modelData.moduleData[module].protocol == PULSES_MULTIMODULE) { - // copy multi settings to ppm settings to get them written to the eeprom - // (reverse the int => ms logic of the ppm delay) since only ppm is written - subprotocols[module] = modelData.moduleData[module].multi.rfProtocol & (0x1f); - int multiByte = ((modelData.moduleData[module].multi.rfProtocol >> 4) & 0x03) | (modelData.moduleData[module].multi.customProto << 7); - modelData.moduleData[module].ppm.delay = 300 + 50 * multiByte; - modelData.moduleData[module].ppm.frameLength = modelData.moduleData[module].multi.optionValue; - modelData.moduleData[module].ppm.outputType = modelData.moduleData[module].multi.lowPowerMode; - modelData.moduleData[module].ppm.pulsePol = modelData.moduleData[module].multi.autoBindMode; - } - else if (modelData.moduleData[module].protocol == PULSES_ACCST_ISRM_D16 || modelData.moduleData[module].protocol == PULSES_ACCESS_ISRM) { - subprotocols[module] = modelData.moduleData[module].protocol - PULSES_ACCESS_ISRM; - } - else { - subprotocols[module] = (module == 0 ? -1 : 0); - } } if (IS_HORUS(board)) { @@ -2271,41 +2420,11 @@ void OpenTxModelData::afterImport() { qCDebug(eepromImport) << QString("OpenTxModelData::afterImport()") << modelData.name; + // ??? what's this ??? if (IS_HORUS(board)) { modelData.moduleData[0].protocol = PULSES_PXX_XJT_X16; } - for (int module=0; module<2; module++) { - if (modelData.moduleData[module].protocol == PULSES_PXX_XJT_X16 - || modelData.moduleData[module].protocol == PULSES_LP45 - || modelData.moduleData[module].protocol == PULSES_ACCESS_ISRM) { - if (subprotocols[module] >= 0) - modelData.moduleData[module].protocol += subprotocols[module]; - else - modelData.moduleData[module].protocol = PULSES_OFF; - } - else if (modelData.moduleData[module].protocol == PULSES_MULTIMODULE) { - // Copy data from ppm struct to multi struct - auto multiByte = (unsigned int)((modelData.moduleData[module].ppm.delay - 300) / 50); - modelData.moduleData[module].multi.rfProtocol = (subprotocols[module] & 0x0f) | ((multiByte & 0x3) << 4); - modelData.moduleData[module].multi.customProto = (multiByte & 0x80) == 0x80; - modelData.moduleData[module].multi.optionValue = modelData.moduleData[module].ppm.frameLength; - modelData.moduleData[module].multi.lowPowerMode = modelData.moduleData[module].ppm.outputType; - modelData.moduleData[module].multi.autoBindMode = modelData.moduleData[module].ppm.pulsePol; - } - - if ((modelData.moduleData[module].protocol >= PULSES_PXX_XJT_X16 && modelData.moduleData[module].protocol <= PULSES_PXX_XJT_LR12) || - modelData.moduleData[module].protocol == PULSES_PXX_R9M) { - // Do the same for pxx - auto pxxByte = (unsigned int)((modelData.moduleData[module].ppm.delay - 300) / 50); - modelData.moduleData[module].pxx.power = pxxByte & 0x03; - modelData.moduleData[module].pxx.receiver_telem_off = static_cast(pxxByte & (1 << 4)); - modelData.moduleData[module].pxx.receiver_channel_9_16 = static_cast(pxxByte & (1 << 5)); - modelData.moduleData[module].pxx.sport_out = modelData.moduleData[module].ppm.outputType; - modelData.moduleData[module].pxx.external_antenna = modelData.moduleData[module].ppm.pulsePol; - } - } - if (IS_HORUS(board)) { uint32_t newSwitchWarningStates = 0; for (int i = 0; i < MAX_SWITCHES(board, version); i++) { diff --git a/companion/src/firmwares/opentx/opentxeeprom.h b/companion/src/firmwares/opentx/opentxeeprom.h index ff11a0dc3..9785c5f7b 100644 --- a/companion/src/firmwares/opentx/opentxeeprom.h +++ b/companion/src/firmwares/opentx/opentxeeprom.h @@ -97,6 +97,7 @@ class ProtocolsConversionTable: public ConversionTable addConversion(PULSES_ACCESS_R9M, val++); addConversion(PULSES_PXX_R9M_LITE, val++); addConversion(PULSES_ACCESS_R9M_LITE, val++); + addConversion(PULSES_PXX_R9M_LITE_PRO, val++); addConversion(PULSES_ACCESS_R9M_LITE_PRO, val++); addConversion(PULSES_SBUS, val++); @@ -146,7 +147,6 @@ class OpenTxModelData: public TransformedField { unsigned int variant; char name[256]; int subprotocols[CPN_MAX_MODULES+1/*trainer*/]; - ProtocolsConversionTable protocolsConversionTable; ChannelsConversionTable channelsConversionTable; QStringList _errors; };