diff --git a/flight/PiOS/STM32F10x/pios_usb_cdc.c b/flight/PiOS/STM32F10x/pios_usb_cdc.c
index 7a9bc0b23..22d422077 100644
--- a/flight/PiOS/STM32F10x/pios_usb_cdc.c
+++ b/flight/PiOS/STM32F10x/pios_usb_cdc.c
@@ -321,7 +321,10 @@ RESULT PIOS_USB_CDC_SetControlLineState(void)
struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
- PIOS_Assert(valid);
+ if (!valid) {
+ /* No CDC interface is configured */
+ return USB_UNSUPPORT;
+ }
uint8_t wValue0 = pInformation->USBwValue0;
uint8_t wValue1 = pInformation->USBwValue1;
@@ -338,14 +341,25 @@ static struct usb_cdc_line_coding line_coding = {
.bDataBits = 8,
};
-RESULT PIOS_USB_CDC_SetLineCoding(void)
+uint8_t *PIOS_USB_CDC_SetLineCoding(uint16_t Length)
{
struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
- PIOS_Assert(valid);
+ if (!valid) {
+ /* No CDC interface is configured */
+ return NULL;
+ }
- return USB_SUCCESS;
+ if (Length == 0) {
+ /* Report the number of bytes we're prepared to consume */
+ pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding);
+ pInformation->Ctrl_Info.Usb_rLength = sizeof(line_coding);
+ return NULL;
+ } else {
+ /* Give out a pointer to the data struct */
+ return ((uint8_t *) &line_coding);
+ }
}
const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length)
@@ -353,7 +367,10 @@ const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length)
struct pios_usb_cdc_dev * usb_cdc_dev = (struct pios_usb_cdc_dev *)pios_usb_cdc_id;
bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
- PIOS_Assert(valid);
+ if (!valid) {
+ /* No CDC interface is configured */
+ return NULL;
+ }
if (Length == 0) {
pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding);
diff --git a/flight/PiOS/STM32F10x/pios_usbhook.c b/flight/PiOS/STM32F10x/pios_usbhook.c
index cb3220227..a691d8447 100644
--- a/flight/PiOS/STM32F10x/pios_usbhook.c
+++ b/flight/PiOS/STM32F10x/pios_usbhook.c
@@ -293,13 +293,16 @@ static void PIOS_USBHOOK_Status_Out(void)
* Output : None.
* Return : USB_UNSUPPORT or USB_SUCCESS.
*******************************************************************************/
+extern uint8_t *PIOS_USB_CDC_SetLineCoding(uint16_t Length);
extern const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length);
static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
{
- const uint8_t *(*CopyRoutine) (uint16_t);
+ uint8_t *(*CopyOutRoutine) (uint16_t);
+ const uint8_t *(*CopyInRoutine) (uint16_t);
- CopyRoutine = NULL;
+ CopyInRoutine = NULL;
+ CopyOutRoutine = NULL;
switch (Type_Recipient) {
case (STANDARD_REQUEST | INTERFACE_RECIPIENT):
@@ -313,10 +316,10 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
case GET_DESCRIPTOR:
switch (pInformation->USBwValue1) {
case USB_DESC_TYPE_REPORT:
- CopyRoutine = PIOS_USBHOOK_GetReportDescriptor;
+ CopyInRoutine = PIOS_USBHOOK_GetReportDescriptor;
break;
case USB_DESC_TYPE_HID:
- CopyRoutine = PIOS_USBHOOK_GetHIDDescriptor;
+ CopyInRoutine = PIOS_USBHOOK_GetHIDDescriptor;
break;
}
}
@@ -332,7 +335,7 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
#endif
switch (RequestNo) {
case USB_HID_REQ_GET_PROTOCOL:
- CopyRoutine = PIOS_USBHOOK_GetProtocolValue;
+ CopyInRoutine = PIOS_USBHOOK_GetProtocolValue;
break;
}
@@ -340,8 +343,11 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
#if defined(PIOS_INCLUDE_USB_CDC)
case 0: /* CDC Call Control Interface */
switch (RequestNo) {
+ case USB_CDC_REQ_SET_LINE_CODING:
+ CopyOutRoutine = PIOS_USB_CDC_SetLineCoding;
+ break;
case USB_CDC_REQ_GET_LINE_CODING:
- //CopyRoutine = PIOS_USB_CDC_GetLineCoding;
+ CopyInRoutine = PIOS_USB_CDC_GetLineCoding;
break;
}
@@ -359,13 +365,27 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
break;
}
- if (CopyRoutine == NULL) {
+ /* No registered copy routine */
+ if ((CopyInRoutine == NULL) && (CopyOutRoutine == NULL)) {
return USB_UNSUPPORT;
}
- pInformation->Ctrl_Info.CopyDataIn = CopyRoutine;
- pInformation->Ctrl_Info.Usb_wOffset = 0;
- (*CopyRoutine) (0);
+ /* Registered copy in AND copy out routine */
+ if ((CopyInRoutine != NULL) && (CopyOutRoutine != NULL)) {
+ /* This should never happen */
+ return USB_UNSUPPORT;
+ }
+
+ if (CopyInRoutine != NULL) {
+ pInformation->Ctrl_Info.CopyDataIn = CopyInRoutine;
+ pInformation->Ctrl_Info.Usb_wOffset = 0;
+ (*CopyInRoutine) (0);
+ } else if (CopyOutRoutine != NULL) {
+ pInformation->Ctrl_Info.CopyDataOut = CopyOutRoutine;
+ pInformation->Ctrl_Info.Usb_rOffset = 0;
+ (*CopyOutRoutine) (0);
+ }
+
return USB_SUCCESS;
}
@@ -377,7 +397,6 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
* Return : USB_UNSUPPORT or USB_SUCCESS.
*******************************************************************************/
extern RESULT PIOS_USB_CDC_SetControlLineState(void);
-extern RESULT PIOS_USB_CDC_SetLineCoding(void);
static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo)
{
@@ -400,9 +419,6 @@ static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo)
#if defined(PIOS_INCLUDE_USB_CDC)
case 0: /* CDC Call Control Interface */
switch (RequestNo) {
- case USB_CDC_REQ_SET_LINE_CODING:
- return PIOS_USB_CDC_SetLineCoding();
- break;
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
return PIOS_USB_CDC_SetControlLineState();
break;
diff --git a/flight/PiOS/inc/pios_usb_defs.h b/flight/PiOS/inc/pios_usb_defs.h
index a26ff4425..d94289272 100644
--- a/flight/PiOS/inc/pios_usb_defs.h
+++ b/flight/PiOS/inc/pios_usb_defs.h
@@ -267,7 +267,7 @@ enum usb_cdc_requests {
USB_CDC_REQ_SET_LINE_CODING = 0x20,
USB_CDC_REQ_GET_LINE_CODING = 0x21,
- USB_CDC_REQ_SET_CONTROL_LINE_STATE = 0x23,
+ USB_CDC_REQ_SET_CONTROL_LINE_STATE = 0x22,
};
struct usb_cdc_header_func_desc {
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 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ThrottleCurve1
+ ThrottleCurve2
+ Roll
+ Pitch
+ Yaw
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/shared/uavobjectdefinition/taskinfo.xml b/shared/uavobjectdefinition/taskinfo.xml
index 091696f47..756143693 100644
--- a/shared/uavobjectdefinition/taskinfo.xml
+++ b/shared/uavobjectdefinition/taskinfo.xml
@@ -1,9 +1,94 @@