From 53e2db3b2421889c039a4c843c4b594e16eaeb41 Mon Sep 17 00:00:00 2001 From: "Richard Flay (Hyper)" <hyperreality.au+openpilot@gmail.com> Date: Sat, 8 Sep 2012 14:41:55 +0930 Subject: [PATCH] Added a backwards-compatible way to specify UAVO field element names and options as lists of child elements of the field element. Added the ability to specify that a field is a clone of another field, just with a different name --- ground/uavobjgenerator/main.cpp | 3 + ground/uavobjgenerator/uavobjectparser.cpp | 96 +++++++++++++++++--- shared/uavobjectdefinition/mixersettings.xml | 93 ++++++++++++++----- shared/uavobjectdefinition/taskinfo.xml | 73 ++++++++++++++- 4 files changed, 224 insertions(+), 41 deletions(-) diff --git a/ground/uavobjgenerator/main.cpp b/ground/uavobjgenerator/main.cpp index 725d65cd3..8bce4fd09 100644 --- a/ground/uavobjgenerator/main.cpp +++ b/ground/uavobjgenerator/main.cpp @@ -161,6 +161,9 @@ int main(int argc, char *argv[]) QString res = parser->parseXML(xmlstr, filename); if (!res.isNull()) { + if (!verbose) { + cout << "Error in XML file: " << fileinfo.fileName().toStdString() << endl; + } cout << "Error parsing " << res.toStdString() << endl; return RETURN_ERR_XML; } diff --git a/ground/uavobjgenerator/uavobjectparser.cpp b/ground/uavobjgenerator/uavobjectparser.cpp index 73c4833b0..2d1d28c66 100644 --- a/ground/uavobjgenerator/uavobjectparser.cpp +++ b/ground/uavobjgenerator/uavobjectparser.cpp @@ -213,6 +213,9 @@ QString UAVObjectParser::parseXML(QString& xml, QString& filename) qStableSort(info->fields.begin(), info->fields.end(), fieldTypeLessThan); // Make sure that required elements were found + if ( !fieldFound ) + return QString("Object::field element is missing"); + if ( !accessFound ) return QString("Object::access element is missing"); @@ -381,11 +384,38 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in // Get name attribute QDomNamedNodeMap elemAttributes = childNode.attributes(); QDomNode elemAttr = elemAttributes.namedItem("name"); - if ( elemAttr.isNull() ) + if (elemAttr.isNull()) { return QString("Object:field:name attribute is missing"); + } + QString name = elemAttr.nodeValue(); - field->name = elemAttr.nodeValue(); - + // Check to see is this field is a clone of another + // field that has already been declared + elemAttr = elemAttributes.namedItem("cloneof"); + if (!elemAttr.isNull()) { + QString parentName = elemAttr.nodeValue(); + if (!parentName.isEmpty()) { + foreach(FieldInfo * parent, info->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(); + } + } + return QString("Object:field::cloneof parent unknown"); + } + else { + return QString("Object:field:cloneof attribute is empty"); + } + } + else { + // this field is not a clone, so remember its name + field->name = name; + } // Get units attribute elemAttr = elemAttributes.namedItem("units"); @@ -410,6 +440,8 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in } // Get numelements or elementnames attribute + field->numElements = 0; + // Look for element names as an attribute first elemAttr = elemAttributes.namedItem("elementnames"); if ( !elemAttr.isNull() ) { // Get element names @@ -422,9 +454,26 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in field->defaultElementNames = false; } else { + // Look for a list of child elementname nodes + QDomNode listNode = childNode.firstChildElement("elementnames"); + if (!listNode.isNull()) { + for (QDomElement node = listNode.firstChildElement("elementname"); + !node.isNull(); node = node.nextSiblingElement("elementname")) { + QDomNode name = node.firstChild(); + if (!name.isNull() && name.isText() && !name.nodeValue().isEmpty()) { + field->elementNames.append(name.nodeValue()); + } + } + field->numElements = field->elementNames.length(); + field->defaultElementNames = false; + } + } + // If no element names were found, then fall back to looking + // for the number of elements in the 'elements' attribute + if (field->numElements == 0) { elemAttr = elemAttributes.namedItem("elements"); if ( elemAttr.isNull() ) { - return QString("Object:field:elements and Object:field:elementnames attribute is missing"); + return QString("Object:field:elements and Object:field:elementnames attribute/element is missing"); } else { field->numElements = elemAttr.nodeValue().toInt(); @@ -434,19 +483,34 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in field->defaultElementNames = true; } } - // Get options attribute (only if an enum type) + // Get options attribute or child elements (only if an enum type) if (field->type == FIELDTYPE_ENUM) { - // Get options attribute + // Look for options attribute elemAttr = elemAttributes.namedItem("options"); - if ( elemAttr.isNull() ) - return QString("Object:field:options attribute is missing"); - - QStringList options = elemAttr.nodeValue().split(",", QString::SkipEmptyParts); - for (int n = 0; n < options.length(); ++n) - options[n] = options[n].trimmed(); - - field->options = options; + if (!elemAttr.isNull()) { + QStringList 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"); + if (!listNode.isNull()) { + for (QDomElement node = listNode.firstChildElement("option"); + !node.isNull(); node = node.nextSiblingElement("option")) { + QDomNode name = node.firstChild(); + if (!name.isNull() && name.isText() && !name.nodeValue().isEmpty()) { + field->options.append(name.nodeValue()); + } + } + } + } + if (field->options.length() == 0) { + return QString("Object:field:options attribute/element is missing"); + } } // Get the default value attribute (required for settings objects, optional for the rest) @@ -466,12 +530,14 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in return QString("Object:field:incorrect number of default values"); /*support legacy single default for multiple elements - We sould really issue a warning*/ + We should really issue a warning*/ for(int ct=1; ct< field->numElements; ct++) defaults.append(defaults[0]); } field->defaultValues = defaults; } + + // Limits attribute elemAttr = elemAttributes.namedItem("limits"); if ( elemAttr.isNull() ) { field->limitValues=QString(); diff --git a/shared/uavobjectdefinition/mixersettings.xml b/shared/uavobjectdefinition/mixersettings.xml index 6e0d519f1..ffbc067f9 100644 --- a/shared/uavobjectdefinition/mixersettings.xml +++ b/shared/uavobjectdefinition/mixersettings.xml @@ -5,29 +5,76 @@ <field name="FeedForward" units="" type="float" elements="1" defaultvalue="0"/> <field name="AccelTime" units="ms" type="float" elements="1" defaultvalue="0"/> <field name="DecelTime" units="ms" type="float" elements="1" defaultvalue="0"/> - <field name="ThrottleCurve1" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="0,0,0,0,0"/> - <field name="Curve2Source" units="" type="enum" elements="1" options="Throttle,Roll,Pitch,Yaw,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Throttle"/> - <field name="ThrottleCurve2" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="0,0.25,0.5,0.75,1"/> - <field name="Mixer1Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer1Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> - <field name="Mixer2Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer2Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> - <field name="Mixer3Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer3Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> - <field name="Mixer4Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer4Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> - <field name="Mixer5Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer5Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> - <field name="Mixer6Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer6Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> - <field name="Mixer7Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer7Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> - <field name="Mixer8Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer8Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> - <field name="Mixer9Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer9Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> - <field name="Mixer10Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> - <field name="Mixer10Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> + <field name="ThrottleCurve1" units="percent" type="float" elementnames="0,25,50,75,100" defaultvalue="0,0,0,0,0"/> + <field name="Curve2Source" units="" type="enum" elements="1" defaultvalue="Throttle"> + <options> + <option>Throttle</option> + <option>Roll</option> + <option>Pitch</option> + <option>Yaw</option> + <option>Collective</option> + <option>Accessory0</option> + <option>Accessory1</option> + <option>Accessory2</option> + <option>Accessory3</option> + <option>Accessory4</option> + <option>Accessory5</option> + </options> + </field> + <field name="ThrottleCurve2" units="percent" type="float" elementnames="0,25,50,75,100" defaultvalue="0,0.25,0.5,0.75,1"/> + <field name="Mixer1Type" units="" type="enum" elements="1" defaultvalue="Disabled"> + <options> + <option>Disabled</option> + <option>Motor</option> + <option>Servo</option> + <option>CameraRoll</option> + <option>CameraPitch</option> + <option>CameraYaw</option> + <option>Accessory0</option> + <option>Accessory1</option> + <option>Accessory2</option> + <option>Accessory3</option> + <option>Accessory4</option> + <option>Accessory5</option> + </options> + </field> + <field name="Mixer1Vector" units="" type="int8" defaultvalue="0"> + <elementnames> + <elementname>ThrottleCurve1</elementname> + <elementname>ThrottleCurve2</elementname> + <elementname>Roll</elementname> + <elementname>Pitch</elementname> + <elementname>Yaw</elementname> + </elementnames> + </field> + + <field name="Mixer2Type" cloneof="Mixer1Type"/> + <field name="Mixer2Vector" cloneof="Mixer1Vector"/> + + <field name="Mixer3Type" cloneof="Mixer1Type"/> + <field name="Mixer3Vector" cloneof="Mixer1Vector"/> + + <field name="Mixer4Type" cloneof="Mixer1Type"/> + <field name="Mixer4Vector" cloneof="Mixer1Vector"/> + + <field name="Mixer5Type" cloneof="Mixer1Type"/> + <field name="Mixer5Vector" cloneof="Mixer1Vector"/> + + <field name="Mixer6Type" cloneof="Mixer1Type"/> + <field name="Mixer6Vector" cloneof="Mixer1Vector"/> + + <field name="Mixer7Type" cloneof="Mixer1Type"/> + <field name="Mixer7Vector" cloneof="Mixer1Vector"/> + + <field name="Mixer8Type" cloneof="Mixer1Type"/> + <field name="Mixer8Vector" cloneof="Mixer1Vector"/> + + <field name="Mixer9Type" cloneof="Mixer1Type"/> + <field name="Mixer9Vector" cloneof="Mixer1Vector"/> + + <field name="Mixer10Type" cloneof="Mixer1Type"/> + <field name="Mixer10Vector" cloneof="Mixer1Vector"/> + <access gcs="readwrite" flight="readwrite"/> <telemetrygcs acked="true" updatemode="onchange" period="0"/> <telemetryflight acked="true" updatemode="onchange" period="0"/> diff --git a/shared/uavobjectdefinition/taskinfo.xml b/shared/uavobjectdefinition/taskinfo.xml index 551167501..e4f2ae652 100644 --- a/shared/uavobjectdefinition/taskinfo.xml +++ b/shared/uavobjectdefinition/taskinfo.xml @@ -1,9 +1,76 @@ <xml> <object name="TaskInfo" singleinstance="true" settings="false"> <description>Task information</description> - <field name="StackRemaining" units="bytes" type="uint16" elementnames="System,Actuator,Attitude,Sensors,TelemetryTx,TelemetryTxPri,TelemetryRx,GPS,ManualControl,Altitude,Stabilization,AltitudeHold,Guidance,FlightPlan,Com2UsbBridge,Usb2ComBridge,OveroSync,EventDispatcher"/> - <field name="Running" units="bool" type="enum" options="False,True" elementnames="System,Actuator,Attitude,Sensors,TelemetryTx,TelemetryTxPri,TelemetryRx,GPS,ManualControl,Altitude,Stabilization,AltitudeHold,Guidance,FlightPlan,Com2UsbBridge,Usb2ComBridge,OveroSync,EventDispatcher"/> - <field name="RunningTime" units="%" type="uint8" elementnames="System,Actuator,Attitude,Sensors,TelemetryTx,TelemetryTxPri,TelemetryRx,GPS,ManualControl,Altitude,Stabilization,AltitudeHold,Guidance,FlightPlan,Com2UsbBridge,Usb2ComBridge,OveroSync,EventDispatcher"/> + <field name="StackRemaining" units="bytes" type="uint16"> + <elementnames> + <elementname>System</elementname> + <elementname>Actuator</elementname> + <elementname>Attitude</elementname> + <elementname>Sensors</elementname> + <elementname>TelemetryTx</elementname> + <elementname>TelemetryTxPri</elementname> + <elementname>TelemetryRx</elementname> + <elementname>GPS</elementname> + <elementname>ManualControl</elementname> + <elementname>Altitude</elementname> + <elementname>Stabilization</elementname> + <elementname>AltitudeHold</elementname> + <elementname>Guidance</elementname> + <elementname>FlightPlan</elementname> + <elementname>Com2UsbBridge</elementname> + <elementname>Usb2ComBridge</elementname> + <elementname>OveroSync</elementname> + <elementname>EventDispatcher</elementname> + </elementnames> + </field> + <field name="Running" units="bool" type="enum"> + <elementnames> + <elementname>System</elementname> + <elementname>Actuator</elementname> + <elementname>Attitude</elementname> + <elementname>Sensors</elementname> + <elementname>TelemetryTx</elementname> + <elementname>TelemetryTxPri</elementname> + <elementname>TelemetryRx</elementname> + <elementname>GPS</elementname> + <elementname>ManualControl</elementname> + <elementname>Altitude</elementname> + <elementname>Stabilization</elementname> + <elementname>AltitudeHold</elementname> + <elementname>Guidance</elementname> + <elementname>FlightPlan</elementname> + <elementname>Com2UsbBridge</elementname> + <elementname>Usb2ComBridge</elementname> + <elementname>OveroSync</elementname> + <elementname>EventDispatcher</elementname> + </elementnames> + <options> + <option>False</option> + <option>True</option> + </options> + </field> + <field name="RunningTime" units="%" type="uint8"> + <elementnames> + <elementname>System</elementname> + <elementname>Actuator</elementname> + <elementname>Attitude</elementname> + <elementname>Sensors</elementname> + <elementname>TelemetryTx</elementname> + <elementname>TelemetryTxPri</elementname> + <elementname>TelemetryRx</elementname> + <elementname>GPS</elementname> + <elementname>ManualControl</elementname> + <elementname>Altitude</elementname> + <elementname>Stabilization</elementname> + <elementname>AltitudeHold</elementname> + <elementname>Guidance</elementname> + <elementname>FlightPlan</elementname> + <elementname>Com2UsbBridge</elementname> + <elementname>Usb2ComBridge</elementname> + <elementname>OveroSync</elementname> + <elementname>EventDispatcher</elementname> + </elementnames> + </field> <access gcs="readwrite" flight="readwrite"/> <telemetrygcs acked="true" updatemode="onchange" period="0"/> <telemetryflight acked="true" updatemode="periodic" period="10000"/>