From 53e2db3b2421889c039a4c843c4b594e16eaeb41 Mon Sep 17 00:00:00 2001 From: "Richard Flay (Hyper)" Date: Sat, 8 Sep 2012 14:41:55 +0930 Subject: [PATCH 1/4] 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 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ThrottleCurve1 + ThrottleCurve2 + Roll + Pitch + Yaw + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ Task information - - - + + + System + Actuator + Attitude + Sensors + TelemetryTx + TelemetryTxPri + TelemetryRx + GPS + ManualControl + Altitude + Stabilization + AltitudeHold + Guidance + FlightPlan + Com2UsbBridge + Usb2ComBridge + OveroSync + EventDispatcher + + + + + System + Actuator + Attitude + Sensors + TelemetryTx + TelemetryTxPri + TelemetryRx + GPS + ManualControl + Altitude + Stabilization + AltitudeHold + Guidance + FlightPlan + Com2UsbBridge + Usb2ComBridge + OveroSync + EventDispatcher + + + + + + + + + System + Actuator + Attitude + Sensors + TelemetryTx + TelemetryTxPri + TelemetryRx + GPS + ManualControl + Altitude + Stabilization + AltitudeHold + Guidance + FlightPlan + Com2UsbBridge + Usb2ComBridge + OveroSync + EventDispatcher + + From c056ac52611153df288997377c04a5e63f7217d1 Mon Sep 17 00:00:00 2001 From: Stacey Sheldon Date: Mon, 24 Sep 2012 00:53:12 -0400 Subject: [PATCH 2/4] usbcdc: don't assert on calls when CDC is not initialized The CDC interface is always advertised in the FW USB descriptors. It is NOT always enabled/initialized at runtime. Specifically, it can be Disabled in HwSettings. Previously, any CDC-related query that the host would send resulted in an assert and a watchdog. Now, a suitable return code indicating that the request is unsupported is returned in this scenario. --- flight/PiOS/STM32F10x/pios_usb_cdc.c | 15 ++++++++++++--- flight/PiOS/STM32F10x/pios_usbhook.c | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/flight/PiOS/STM32F10x/pios_usb_cdc.c b/flight/PiOS/STM32F10x/pios_usb_cdc.c index 7a9bc0b23..db142670f 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; @@ -343,7 +346,10 @@ RESULT PIOS_USB_CDC_SetLineCoding(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 NULL; + } return USB_SUCCESS; } @@ -353,7 +359,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..65af85849 100644 --- a/flight/PiOS/STM32F10x/pios_usbhook.c +++ b/flight/PiOS/STM32F10x/pios_usbhook.c @@ -341,7 +341,7 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo) case 0: /* CDC Call Control Interface */ switch (RequestNo) { case USB_CDC_REQ_GET_LINE_CODING: - //CopyRoutine = PIOS_USB_CDC_GetLineCoding; + CopyInRoutine = PIOS_USB_CDC_GetLineCoding; break; } From 5e374488145b2b949f993563c6381286a6aacc5a Mon Sep 17 00:00:00 2001 From: Stacey Sheldon Date: Mon, 24 Sep 2012 00:53:52 -0400 Subject: [PATCH 3/4] usb: correct enum for CDC SET_CONTROL_LINE_STATE request --- flight/PiOS/inc/pios_usb_defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flight/PiOS/inc/pios_usb_defs.h b/flight/PiOS/inc/pios_usb_defs.h index ea54306a7..ebe7f1f31 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 { From 215ff56fe8feb36b4e4e70c8a2395b8a7047933f Mon Sep 17 00:00:00 2001 From: Stacey Sheldon Date: Mon, 24 Sep 2012 00:56:25 -0400 Subject: [PATCH 4/4] usbcdc: fix handling of CDC SET_LINE_CODING request The SET_LINE_CODING request contains data and must be handled as such. Previously, the only requests that had data were IN requests. SET_LINE_CODING is an OUT request so it required additional changes to support a new type of data request. --- flight/PiOS/STM32F10x/pios_usb_cdc.c | 12 ++++++-- flight/PiOS/STM32F10x/pios_usbhook.c | 42 +++++++++++++++++++--------- 2 files changed, 39 insertions(+), 15 deletions(-) diff --git a/flight/PiOS/STM32F10x/pios_usb_cdc.c b/flight/PiOS/STM32F10x/pios_usb_cdc.c index db142670f..22d422077 100644 --- a/flight/PiOS/STM32F10x/pios_usb_cdc.c +++ b/flight/PiOS/STM32F10x/pios_usb_cdc.c @@ -341,7 +341,7 @@ 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; @@ -351,7 +351,15 @@ RESULT PIOS_USB_CDC_SetLineCoding(void) 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) diff --git a/flight/PiOS/STM32F10x/pios_usbhook.c b/flight/PiOS/STM32F10x/pios_usbhook.c index 65af85849..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,6 +343,9 @@ 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: 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;