use proper structures for module union fields

.. and quite some fixes.
This commit is contained in:
Raphael Coeffic
2019-08-18 17:45:35 +02:00
parent ac0ee91078
commit 4946f946fd
5 changed files with 292 additions and 95 deletions
@@ -585,6 +585,78 @@ class TransformedField: public DataField {
DataField & field;
};
template<class selectorT>
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<UnionMember *> members;
unsigned int maxSize;
};
class ConversionTable {
public:
+1
View File
@@ -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",
+14 -9
View File
@@ -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)); }
+204 -85
View File
@@ -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<unsigned int> {
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<PXX2_MAX_RECEIVERS_PER_MODULE; i++)
internalField.Append(new CharField<8>(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<unsigned int>(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<UnsignedField<4> >(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<SignedField<8> >(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<modulesCount; module++) {
internalField.Append(new ConversionField<SignedField<4> >(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<SignedField<8> >(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<bool>(pxxByte & (1 << 4));
modelData.moduleData[module].pxx.receiver_channel_9_16 = static_cast<bool>(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++) {
@@ -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;
};