1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-28 06:24:10 +01:00

Merged in mindnever/librepilot/LP-599_Extend_cloneof_attribute_functionality_in_uavobject_xml (pull request #514)

LP-599 Extend cloneof attribute functionality in uavobject xml

Approved-by: Vladimir Zidar <mr_w@mindnever.org>
Approved-by: Jan NIJS <dr.oblivium@gmail.com>
Approved-by: Philippe Renon <philippe_renon@yahoo.fr>
Approved-by: Lalanne Laurent <f5soh@free.fr>
This commit is contained in:
Vladimir Zidar 2018-09-29 09:58:05 +00:00 committed by Lalanne Laurent
commit 230d770498
6 changed files with 298 additions and 144 deletions

View File

@ -40,6 +40,7 @@
#ifndef $(NAMEUC)_H
#define $(NAMEUC)_H
#include <stdbool.h>
$(INCLUDE)
/* Object constants */
#define $(NAMEUC)_OBJID $(OBJIDHEX)
#define $(NAMEUC)_ISSINGLEINST $(ISSINGLEINST)

View File

@ -35,6 +35,7 @@
#define $(NAMEUC)_H
#include "uavdataobject.h"
$(INCLUDE)
class UAVObjectManager;

View File

@ -24,6 +24,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <QSet>
#include "uavobjectgeneratorflight.h"
using namespace std;
@ -169,52 +170,91 @@ bool UAVObjectGeneratorFlight::process_object(ObjectInfo *info)
enums.append(QString("/* Field %1 information */\n").arg(info->fields[n]->name));
// Only for enum types
if (info->fields[n]->type == FIELDTYPE_ENUM) {
enums.append(QString("\n// Enumeration options for field %1\n").arg(info->fields[n]->name));
enums.append("typedef enum __attribute__ ((__packed__)) {\n");
// Go through each option
QStringList options = info->fields[n]->options;
for (int m = 0; m < options.length(); ++m) {
QString s = (m == (options.length() - 1)) ? " %1_%2_%3=%4\n" : " %1_%2_%3=%4,\n";
enums.append(s
.arg(info->name.toUpper())
.arg(info->fields[n]->name.toUpper())
.arg(options[m].toUpper().replace(QRegExp(ENUM_SPECIAL_CHARS), ""))
.arg(m));
if (info->fields[n]->parentObjectName.length() > 0) {
enums.append(QString("typedef %1%2Options %3%4Options;\n")
.arg(info->fields[n]->parentObjectName)
.arg(info->fields[n]->parentFieldName)
.arg(info->name)
.arg(info->fields[n]->name));
} else {
enums.append(QString("\n// Enumeration options for field %1\n").arg(info->fields[n]->name));
enums.append("typedef enum __attribute__ ((__packed__)) {\n");
// Go through each option
QStringList options = info->fields[n]->options;
for (int m = 0; m < options.length(); ++m) {
QString s = (m == (options.length() - 1)) ? " %1_%2_%3=%4\n" : " %1_%2_%3=%4,\n";
enums.append(s
.arg(info->name.toUpper())
.arg(info->fields[n]->name.toUpper())
.arg(options[m].toUpper().replace(QRegExp(ENUM_SPECIAL_CHARS), ""))
.arg(m));
}
enums.append(QString("} %1%2Options;\n")
.arg(info->name)
.arg(info->fields[n]->name));
}
enums.append(QString("} %1%2Options;\n")
.arg(info->name)
.arg(info->fields[n]->name));
}
// Generate element names (only if field has more than one element)
if (info->fields[n]->numElements > 1 && !info->fields[n]->defaultElementNames) {
enums.append(QString("\n// Array element names for field %1\n").arg(info->fields[n]->name));
enums.append("typedef enum {\n");
// Go through the element names
QStringList elemNames = info->fields[n]->elementNames;
for (int m = 0; m < elemNames.length(); ++m) {
QString s = (m != (elemNames.length() - 1)) ? " %1_%2_%3=%4,\n" : " %1_%2_%3=%4\n";
enums.append(s
.arg(info->name.toUpper())
.arg(info->fields[n]->name.toUpper())
.arg(elemNames[m].toUpper())
.arg(m));
if (info->fields[n]->parentObjectName.length() > 0) {
enums.append(QString("typedef %1%2Elem %3%4Elem;\n")
.arg(info->fields[n]->parentObjectName)
.arg(info->fields[n]->parentFieldName)
.arg(info->name)
.arg(info->fields[n]->name));
} else {
enums.append(QString("\n// Array element names for field %1\n").arg(info->fields[n]->name));
enums.append("typedef enum {\n");
// Go through the element names
QStringList elemNames = info->fields[n]->elementNames;
for (int m = 0; m < elemNames.length(); ++m) {
QString s = (m != (elemNames.length() - 1)) ? " %1_%2_%3=%4,\n" : " %1_%2_%3=%4\n";
enums.append(s
.arg(info->name.toUpper())
.arg(info->fields[n]->name.toUpper())
.arg(elemNames[m].toUpper())
.arg(m));
}
enums.append(QString("} %1%2Elem;\n")
.arg(info->name)
.arg(info->fields[n]->name));
}
enums.append(QString("} %1%2Elem;\n")
.arg(info->name)
.arg(info->fields[n]->name));
}
// Generate array information
if (info->fields[n]->numElements > 1) {
enums.append(QString("\n// Number of elements for field %1\n").arg(info->fields[n]->name));
enums.append(QString("#define %1_%2_NUMELEM %3\n")
.arg(info->name.toUpper())
.arg(info->fields[n]->name.toUpper())
.arg(info->fields[n]->numElements));
if (info->fields[n]->parentObjectName.length() > 0) {
enums.append(QString("#define %1_%2_NUMELEM %3_%4_NUMELEM\n")
.arg(info->name.toUpper())
.arg(info->fields[n]->name.toUpper())
.arg(info->fields[n]->parentObjectName.toUpper())
.arg(info->fields[n]->parentFieldName.toUpper()));
} else {
enums.append(QString("#define %1_%2_NUMELEM %3\n")
.arg(info->name.toUpper())
.arg(info->fields[n]->name.toUpper())
.arg(info->fields[n]->numElements));
}
}
enums.append(QString("\n"));
}
QString includes;
QSet<QString> parentObjects;
for (int n = 0; n < info->fields.length(); ++n) {
if (info->fields[n]->parentObjectName.length() > 0) {
parentObjects.insert(info->fields[n]->parentObjectName);
}
}
foreach(const QString &objectName, parentObjects) {
includes.append("#include \"" + objectName.toLower() + ".h\"\n");
}
outInclude.replace(QString("$(DATAFIELDINFO)"), enums);
outInclude.replace(QString("$(INCLUDE)"), includes);
// Replace the $(INITFIELDS) tag
QString initfields;

View File

@ -24,7 +24,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <QSet>
#include "uavobjectgeneratorgcs.h"
#define VERBOSE false
@ -52,27 +52,32 @@ void info(ObjectInfo *object, QString msg)
}
struct Context {
ObjectInfo *object;
ObjectInfo *object;
// parent objects
QSet<QString> parentObjects;
// enums
QString enums;
QString enumsCount;
QString registerImpl;
QString enums;
QString enumsCount;
QString registerImpl;
// interface
QString fields;
QString fieldsInfo;
QString properties;
QString deprecatedProperties;
QString getters;
QString setters;
QString notifications;
QString fields;
QString fieldsInfo;
QString properties;
QString deprecatedProperties;
QString getters;
QString setters;
QString notifications;
// implementation
QString fieldsInit;
QString fieldsDefault;
QString propertiesImpl;
QString notificationsImpl;
QString fieldsInit;
QString fieldsDefault;
QString propertiesImpl;
QString notificationsImpl;
};
struct FieldContext {
FieldContext(FieldInfo *fieldInfo, ObjectInfo *object);
FieldContext(const FieldContext &fieldContext);
FieldInfo *field;
// field
QString fieldName;
@ -82,6 +87,10 @@ struct FieldContext {
QString ucPropName;
QString propType;
QString propRefType;
//
QString parentClassName;
QString parentFieldName;
QString ucParentPropName;
// deprecation
bool hasDeprecatedProperty;
bool hasDeprecatedGetter;
@ -226,6 +235,10 @@ QString generate(Context &ctxt, FieldContext &fieldCtxt, const QString &fragment
str.replace(":elementCount", QString::number(fieldCtxt.field->numElements));
str.replace(":enumCount", QString::number(fieldCtxt.field->numOptions));
str.replace(":parentFieldName", fieldCtxt.parentFieldName);
str.replace(":parentClassName", fieldCtxt.parentClassName);
str.replace(":ParentPropName", fieldCtxt.ucParentPropName);
return str;
}
@ -234,34 +247,42 @@ void generateFieldInfo(Context &ctxt, FieldContext &fieldCtxt)
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " // :fieldName\n");
if (fieldCtxt.field->type == FIELDTYPE_ENUM) {
QStringList options = fieldCtxt.field->options;
ctxt.fieldsInfo += " typedef enum { ";
for (int m = 0; m < options.length(); ++m) {
if (m > 0) {
ctxt.fieldsInfo.append(", ");
if (fieldCtxt.field->parentObjectName.length() > 0) {
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " typedef :parentClassName:::parentFieldNameOptions :fieldNameOptions;\n");
} else {
QStringList options = fieldCtxt.field->options;
ctxt.fieldsInfo += " typedef enum { ";
for (int m = 0; m < options.length(); ++m) {
if (m > 0) {
ctxt.fieldsInfo.append(", ");
}
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, "%1_%2=%3")
.arg(fieldCtxt.field->name.toUpper())
.arg(options[m].toUpper().replace(QRegExp(ENUM_SPECIAL_CHARS), ""))
.arg(m);
}
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, "%1_%2=%3")
.arg(fieldCtxt.field->name.toUpper())
.arg(options[m].toUpper().replace(QRegExp(ENUM_SPECIAL_CHARS), ""))
.arg(m);
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " } :fieldNameOptions;\n");
}
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " } :fieldNameOptions;\n");
}
// Generate element names (only if field has more than one element)
if (fieldCtxt.field->numElements > 1 && !fieldCtxt.field->defaultElementNames) {
QStringList elemNames = fieldCtxt.field->elementNames;
ctxt.fieldsInfo += " typedef enum { ";
for (int m = 0; m < elemNames.length(); ++m) {
if (m > 0) {
ctxt.fieldsInfo.append(", ");
if (fieldCtxt.field->parentObjectName.length() > 0) {
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " typedef :parentClassName:::parentFieldNameElem :fieldNameElem;\n");
} else {
QStringList elemNames = fieldCtxt.field->elementNames;
ctxt.fieldsInfo += " typedef enum { ";
for (int m = 0; m < elemNames.length(); ++m) {
if (m > 0) {
ctxt.fieldsInfo.append(", ");
}
ctxt.fieldsInfo += QString("%1_%2=%3")
.arg(fieldCtxt.field->name.toUpper())
.arg(elemNames[m].toUpper())
.arg(m);
}
ctxt.fieldsInfo += QString("%1_%2=%3")
.arg(fieldCtxt.field->name.toUpper())
.arg(elemNames[m].toUpper())
.arg(m);
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " } :fieldNameElem;\n");
}
ctxt.fieldsInfo += generate(ctxt, fieldCtxt, " } :fieldNameElem;\n");
}
// Generate array information
@ -341,6 +362,9 @@ void generateFieldDefault(Context &ctxt, FieldContext &fieldCtxt)
void generateField(Context &ctxt, FieldContext &fieldCtxt)
{
if (fieldCtxt.parentClassName.length() > 0) {
ctxt.parentObjects.insert(fieldCtxt.parentClassName);
}
if (fieldCtxt.field->numElements > 1) {
ctxt.fields += generate(ctxt, fieldCtxt, " :fieldType :fieldName[:elementCount];\n");
} else {
@ -355,20 +379,24 @@ void generateEnum(Context &ctxt, FieldContext &fieldCtxt)
{
Q_ASSERT(fieldCtxt.field->type == FIELDTYPE_ENUM);
QString enumStringList = toEnumStringList(ctxt.object, fieldCtxt.field);
if (fieldCtxt.field->parentObjectName.length() > 0) {
ctxt.enums += generate(ctxt, fieldCtxt, "typedef :parentClassName_:ParentPropName :ClassName_:PropName;\n\n");
} else {
QString enumStringList = toEnumStringList(ctxt.object, fieldCtxt.field);
ctxt.enums += generate(ctxt, fieldCtxt,
"class :ClassName_:PropName : public QObject {\n"
" Q_OBJECT\n"
"public:\n"
" enum Enum { %1 };\n"
" Q_ENUMS(Enum) // TODO switch to Q_ENUM once on Qt 5.5\n"
"};\n\n").arg(enumStringList);
ctxt.enums += generate(ctxt, fieldCtxt,
"class :ClassName_:PropName : public QObject {\n"
" Q_OBJECT\n"
"public:\n"
" enum Enum { %1 };\n"
" Q_ENUMS(Enum) // TODO switch to Q_ENUM once on Qt 5.5\n"
"};\n\n").arg(enumStringList);
ctxt.enumsCount += generate(ctxt, fieldCtxt, ":PropNameCount = :enumCount, ");
ctxt.enumsCount += generate(ctxt, fieldCtxt, ":PropNameCount = :enumCount, ");
ctxt.registerImpl += generate(ctxt, fieldCtxt,
" qmlRegisterType<:ClassName_:PropName>(\"%1.:ClassName\", 1, 0, \":PropName\");\n").arg("UAVTalk");
ctxt.registerImpl += generate(ctxt, fieldCtxt,
" qmlRegisterType<:ClassName_:PropName>(\"%1.:ClassName\", 1, 0, \":PropName\");\n").arg("UAVTalk");
}
}
void generateBaseProperty(Context &ctxt, FieldContext &fieldCtxt)
@ -507,14 +535,10 @@ void generateIndexedProperty(Context &ctxt, FieldContext &fieldCtxt)
sep = "_";
}
FieldContext elementCtxt;
elementCtxt.field = fieldCtxt.field;
elementCtxt.fieldName = fieldCtxt.fieldName + "_" + elementName;
elementCtxt.fieldType = fieldCtxt.fieldType;
elementCtxt.propName = fieldCtxt.propName + sep + elementName;
elementCtxt.ucPropName = fieldCtxt.ucPropName + sep + elementName;
elementCtxt.propType = fieldCtxt.propType;
elementCtxt.propRefType = fieldCtxt.propRefType;
FieldContext elementCtxt(fieldCtxt);
elementCtxt.fieldName = fieldCtxt.fieldName + "_" + elementName;
elementCtxt.propName = fieldCtxt.propName + sep + elementName;
elementCtxt.ucPropName = fieldCtxt.ucPropName + sep + elementName;
// deprecation
elementCtxt.hasDeprecatedProperty = (elementCtxt.fieldName != elementCtxt.propName) && DEPRECATED;
elementCtxt.hasDeprecatedGetter = DEPRECATED;
@ -593,6 +617,44 @@ bool UAVObjectGeneratorGCS::generate(UAVObjectParser *parser, QString templatepa
return true;
}
FieldContext::FieldContext(const FieldContext &fieldContext)
{
*this = fieldContext;
}
FieldContext::FieldContext(FieldInfo *fieldInfo, ObjectInfo *object)
{
field = fieldInfo;
// field properties
fieldName = field->name;
fieldType = fieldTypeStrCPP(field->type);
parentClassName = field->parentObjectName;
parentFieldName = field->parentFieldName;
ucParentPropName = toPropertyName(field->parentFieldName);
ucPropName = toPropertyName(field->name);
propName = toLowerCamelCase(ucPropName);
propType = fieldType;
if (field->type == FIELDTYPE_INT8) {
propType = fieldTypeStrCPP(FIELDTYPE_INT16);
} else if (field->type == FIELDTYPE_UINT8) {
propType = fieldTypeStrCPP(FIELDTYPE_UINT16);
} else if (field->type == FIELDTYPE_ENUM) {
QString enumClassName = object->name + "_" + ucPropName;
propType = enumClassName + "::Enum";
}
// reference type
propRefType = propType;
// deprecation
hasDeprecatedProperty = (fieldName != propName) && DEPRECATED;
hasDeprecatedGetter = DEPRECATED;
hasDeprecatedSetter = ((fieldName != ucPropName) || (fieldType != propType)) && DEPRECATED;
hasDeprecatedNotification = ((fieldName != propName) || (fieldType != propType)) && DEPRECATED;
}
/**
* Generate the GCS object files
*
@ -634,32 +696,7 @@ bool UAVObjectGeneratorGCS::process_object(ObjectInfo *object)
FieldInfo *field = object->fields[n];
// field context
FieldContext fieldCtxt;
fieldCtxt.field = field;
// field properties
fieldCtxt.fieldName = field->name;
fieldCtxt.fieldType = fieldTypeStrCPP(field->type);
fieldCtxt.ucPropName = toPropertyName(field->name);
fieldCtxt.propName = toLowerCamelCase(fieldCtxt.ucPropName);
fieldCtxt.propType = fieldCtxt.fieldType;
if (field->type == FIELDTYPE_INT8) {
fieldCtxt.propType = fieldTypeStrCPP(FIELDTYPE_INT16);
} else if (field->type == FIELDTYPE_UINT8) {
fieldCtxt.propType = fieldTypeStrCPP(FIELDTYPE_UINT16);
} else if (field->type == FIELDTYPE_ENUM) {
QString enumClassName = object->name + "_" + fieldCtxt.ucPropName;
fieldCtxt.propType = enumClassName + "::Enum";
}
// reference type
fieldCtxt.propRefType = fieldCtxt.propType;
// deprecation
fieldCtxt.hasDeprecatedProperty = (fieldCtxt.fieldName != fieldCtxt.propName) && DEPRECATED;
fieldCtxt.hasDeprecatedGetter = DEPRECATED;
fieldCtxt.hasDeprecatedSetter = ((fieldCtxt.fieldName != fieldCtxt.ucPropName) || (fieldCtxt.fieldType != fieldCtxt.propType)) && DEPRECATED;
fieldCtxt.hasDeprecatedNotification = ((fieldCtxt.fieldName != fieldCtxt.propName) || (fieldCtxt.fieldType != fieldCtxt.propType)) && DEPRECATED;
FieldContext fieldCtxt(field, object);
generateField(ctxt, fieldCtxt);
@ -671,6 +708,12 @@ bool UAVObjectGeneratorGCS::process_object(ObjectInfo *object)
generateProperty(ctxt, fieldCtxt);
}
QString includes;
foreach(const QString &objectName, ctxt.parentObjects) {
includes.append("#include \"" + objectName.toLower() + ".h\"\n");
}
outInclude.replace("$(INCLUDE)", includes);
outInclude.replace("$(ENUMS)", ctxt.enums);
outInclude.replace("$(ENUMS_COUNT)", ctxt.enumsCount);
outInclude.replace("$(DATAFIELDS)", ctxt.fields);

View File

@ -69,6 +69,15 @@ ObjectInfo *UAVObjectParser::getObjectByIndex(int objIndex)
return objInfo[objIndex];
}
ObjectInfo *UAVObjectParser::getObjectByName(const QString & objName)
{
foreach(ObjectInfo * info, objInfo) {
if (objName == info->name) {
return info;
}
}
return 0;
}
/**
* Get the name of the object
*/
@ -404,6 +413,7 @@ QString UAVObjectParser::processObjectAccess(QDomNode & childNode, ObjectInfo *i
*/
QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *info)
{
bool isClone = false;
// Create field
FieldInfo *field = new FieldInfo;
// Get name attribute
@ -419,20 +429,39 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
// field that has already been declared
elemAttr = elemAttributes.namedItem("cloneof");
if (!elemAttr.isNull()) {
QString parentName = elemAttr.nodeValue();
QString parentName = elemAttr.nodeValue().section('.', 1);
ObjectInfo *parentObject;
if (parentName.isEmpty()) {
parentName = elemAttr.nodeValue();
parentObject = info;
} else {
QString objName = elemAttr.nodeValue().section('.', 0, 0);
parentObject = getObjectByName(objName);
if (!parentObject) {
return QString("Object:field:cloneof parent object unknown");
}
}
if (!parentName.isEmpty()) {
foreach(FieldInfo * parent, info->fields) {
foreach(FieldInfo * parent, parentObject->fields) {
if (parent->name == parentName) {
// clone from this parent
*field = *parent; // safe shallow copy, no ptrs in struct
field->name = name; // set our name
// Add field to object
info->fields.append(field);
// Done
return QString();
// Done, but allow certain overrides
field->parentObjectName = parentObject->name;
field->parentFieldName = parent->name;
isClone = true;
break;
}
}
return QString("Object:field::cloneof parent unknown");
if (!isClone) {
return QString("Object:field:cloneof parent unknown");
}
} else {
return QString("Object:field:cloneof attribute is empty");
}
@ -459,31 +488,45 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
// Get units attribute
elemAttr = elemAttributes.namedItem("units");
if (elemAttr.isNull()) {
return QString("Object:field:units attribute is missing");
if (!isClone) {
return QString("Object:field:units attribute is missing");
}
} else {
if (isClone) {
return QString("Object:field:units attribute is not allowed for cloned fields");
}
field->units = elemAttr.nodeValue();
all_units << field->units;
}
field->units = elemAttr.nodeValue();
all_units << field->units;
// Get type attribute
elemAttr = elemAttributes.namedItem("type");
if (elemAttr.isNull()) {
return QString("Object:field:type attribute is missing");
}
int index = fieldTypeStrXML.indexOf(elemAttr.nodeValue());
if (index >= 0) {
field->type = (FieldType)index;
field->numBytes = fieldTypeNumBytes[index];
if (!isClone) {
return QString("Object:field:type attribute is missing");
}
} else {
return QString("Object:field:type attribute value is invalid");
if (isClone) {
return QString("Object:field:type attribute is not allowed for cloned fields");
}
int index = fieldTypeStrXML.indexOf(elemAttr.nodeValue());
if (index >= 0) {
field->type = (FieldType)index;
field->numBytes = fieldTypeNumBytes[index];
} else {
return QString("Object:field:type attribute value is invalid");
}
}
// Get numelements or elementnames attribute
field->numElements = 0;
if (!isClone) {
field->numElements = 0;
}
// Look for element names as an attribute first
elemAttr = elemAttributes.namedItem("elementnames");
if (!elemAttr.isNull()) {
if (isClone) {
return QString("Object:field:elementnames attribute is not allowed for cloned fields");
}
// Get element names
QStringList names = elemAttr.nodeValue().split(",", QString::SkipEmptyParts);
for (int n = 0; n < names.length(); ++n) {
@ -497,6 +540,9 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
// Look for a list of child elementname nodes
QDomNode listNode = childNode.firstChildElement("elementnames");
if (!listNode.isNull()) {
if (isClone) {
return QString("Object:field:elementnames element is not allowed for cloned fields");
}
for (QDomElement node = listNode.firstChildElement("elementname");
!node.isNull(); node = node.nextSiblingElement("elementname")) {
QDomNode name = node.firstChild();
@ -515,6 +561,9 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
if (elemAttr.isNull()) {
return QString("Object:field:elements and Object:field:elementnames attribute/element is missing");
} else {
if (isClone) {
return QString("Object:field:elements attribute is not allowed for cloned fields");
}
field->numElements = elemAttr.nodeValue().toInt();
for (int n = 0; n < field->numElements; ++n) {
field->elementNames.append(QString("%1").arg(n));
@ -524,15 +573,18 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
}
}
// Get options attribute or child elements (only if an enum type)
// We allow "options" attribute/element for cloned fields also, but they work slightly different here -
// they set limits on parent options.
if (field->type == FIELDTYPE_ENUM) {
// Look for options attribute
QStringList options;
elemAttr = elemAttributes.namedItem("options");
if (!elemAttr.isNull()) {
QStringList options = elemAttr.nodeValue().split(",", QString::SkipEmptyParts);
options = elemAttr.nodeValue().split(",", QString::SkipEmptyParts);
for (int n = 0; n < options.length(); ++n) {
options[n] = options[n].trimmed();
}
field->options = options;
} else {
// Look for a list of child 'option' nodes
QDomNode listNode = childNode.firstChildElement("options");
@ -541,12 +593,28 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
!node.isNull(); node = node.nextSiblingElement("option")) {
QDomNode name = node.firstChild();
if (!name.isNull() && name.isText() && !name.nodeValue().isEmpty()) {
field->options.append(name.nodeValue());
options.append(name.nodeValue());
}
}
}
}
field->numOptions = field->options.size();
if (isClone) {
if (!options.isEmpty()) {
// Verify options subset and build limits value from it.
foreach(const QString &option, options) {
if (!field->options.contains(option)) {
return QString("Object:field:options is not a subset of parent options");
}
}
field->limitValues = QString("%EQ:") + options.join(':');
qDebug() << "Created field->limitValues: " << field->limitValues;
}
} else {
field->numOptions = options.size();
field->options = options;
}
if (field->numOptions == 0) {
return QString("Object:field:options attribute/element is missing");
}
@ -554,12 +622,7 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
// Get the default value attribute (required for settings objects, optional for the rest)
elemAttr = elemAttributes.namedItem("defaultvalue");
if (elemAttr.isNull()) {
if (info->isSettings) {
return QString("Object:field:defaultvalue attribute is missing (required for settings objects)");
}
field->defaultValues = QStringList();
} else {
if (!elemAttr.isNull()) {
QStringList defaults = elemAttr.nodeValue().split(",", QString::SkipEmptyParts);
for (int n = 0; n < defaults.length(); ++n) {
defaults[n] = defaults[n].trimmed();
@ -578,6 +641,9 @@ QString UAVObjectParser::processObjectFields(QDomNode & childNode, ObjectInfo *i
}
field->defaultValues = defaults;
}
if (field->defaultValues.isEmpty() && info->isSettings) {
return QString("Object:field:defaultvalue attribute is missing (required for settings objects)");
}
// Limits attribute
elemAttr = elemAttributes.namedItem("limits");

View File

@ -59,6 +59,8 @@ typedef struct {
bool defaultElementNames;
QStringList defaultValues;
QString limitValues;
QString parentObjectName;
QString parentFieldName;
} FieldInfo;
/**
@ -113,6 +115,7 @@ public:
quint32 getObjectID(int objIndex);
ObjectInfo *getObjectByIndex(int objIndex);
ObjectInfo *getObjectByName(const QString & objName);
int getNumBytes(int objIndex);
QStringList all_units;