diff --git a/flight/PiOS/Common/pios_mpu6000.c b/flight/PiOS/Common/pios_mpu6000.c index 56e8cccbd..b77a4f6df 100644 --- a/flight/PiOS/Common/pios_mpu6000.c +++ b/flight/PiOS/Common/pios_mpu6000.c @@ -435,9 +435,6 @@ void PIOS_MPU6000_IRQHandler(void) if(PIOS_MPU6000_ClaimBus() != 0) return; - uint8_t mpu6000_send_buf[1+sizeof(struct pios_mpu6000_data)] = {PIOS_MPU6000_FIFO_REG | 0x80, 0, 0, 0, 0, 0, 0, 0, 0}; - uint8_t mpu6000_rec_buf[1+sizeof(struct pios_mpu6000_data)]; - if(PIOS_SPI_TransferBlock(dev->spi_id, &mpu6000_send_buf[0], &mpu6000_rec_buf[0], sizeof(mpu6000_send_buf), NULL) < 0) { PIOS_MPU6000_ReleaseBus(); mpu6000_fails++; 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 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 { diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml index 4e443abe0..cab264e14 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS.xml @@ -2500,9 +2500,9 @@ splitter - PFDGadget + PfdQmlGadget - raw + NoTerrain uavGadget diff --git a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml index 3b3ceddd5..960c10355 100644 --- a/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml +++ b/ground/openpilotgcs/share/openpilotgcs/default_configurations/OpenPilotGCS_wide.xml @@ -2494,9 +2494,9 @@ splitter - PFDGadget + PfdQmlGadget - raw + NoTerrain uavGadget diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml index 6e5b608f7..a8f4d66b2 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/AltitudeScale.qml @@ -2,26 +2,24 @@ import Qt 4.7 Item { id: sceneItem - property variant sourceSize + property variant sceneSize - Image { + SvgElementImage { id: altitude_bg - source: "image://svg/pfd.svg!altitude-bg" - sourceSize: sceneItem.sourceSize + elementName: "altitude-bg" + sceneSize: sceneItem.sceneSize clip: true property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "altitude-bg") - x: scaledBounds.x * sceneItem.width - y: scaledBounds.y * sceneItem.height - width: scaledBounds.width * sceneItem.width - height: scaledBounds.height * sceneItem.height + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) - Image { + SvgElementImage { id: altitude_scale - source: "image://svg/pfd.svg!altitude-scale" - sourceSize: sceneItem.sourceSize + elementName: "altitude-scale" + sceneSize: sceneItem.sceneSize anchors.verticalCenter: parent.verticalCenter // The altitude scale represents 30 meters, @@ -55,12 +53,12 @@ Item { } - Image { + SvgElementImage { id: altitude_window clip: true - source: "image://svg/pfd.svg!altitude-window" - sourceSize: sceneItem.sourceSize + elementName: "altitude-window" + sceneSize: sceneItem.sceneSize property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "altitude-window") diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/Compass.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Compass.qml new file mode 100644 index 000000000..3c956d526 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Compass.qml @@ -0,0 +1,37 @@ +import Qt 4.7 +import "." + +Item { + id: sceneItem + property variant sceneSize + + SvgElementImage { + id: compass + elementName: "compass" + sceneSize: sceneItem.sceneSize + + clip: true + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + //anchors.horizontalCenter: parent.horizontalCenter + + //split compass band to 8 parts to ensure it doesn't exceed the max texture size + Row { + anchors.centerIn: parent + //the band is 540 degrees wide, AttitudeActual.Yaw is converted to -180..180 range + anchors.horizontalCenterOffset: -1*((AttitudeActual.Yaw+180+720) % 360 - 180)/540*width + + Repeater { + model: 5 + SvgElementImage { + id: compass_band + elementName: "compass-band" + sceneSize: background.sceneSize + hSliceCount: 5 + hSlice: index + } + } + } + } +} diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/Pfd.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Pfd.qml index b25596def..e393b185e 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/Pfd.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/Pfd.qml @@ -4,15 +4,13 @@ import "." Rectangle { color: "#666666" - Image { + SvgElementImage { id: background - source: "image://svg/pfd.svg!background" - + elementName: "background" fillMode: Image.PreserveAspectFit anchors.fill: parent - sourceSize.width: width - sourceSize.height: height + sceneSize: Qt.size(width, height) Item { id: sceneItem @@ -27,60 +25,74 @@ Rectangle { source: qmlWidget.terrainEnabled ? "PfdTerrainView.qml" : "PfdWorldView.qml" } - Image { + SvgElementImage { id: rollscale - source: "image://svg/pfd.svg!rollscale" - sourceSize: background.sourceSize + elementName: "rollscale" + sceneSize: background.sceneSize + smooth: true - anchors.centerIn: parent - //rotate it around the center of scene - transform: Rotation { - angle: -AttitudeActual.Roll - origin.x : sceneItem.width/2 - x - origin.y : sceneItem.height/2 - y - } + anchors.centerIn: parent + //rotate it around the center of scene + transform: Rotation { + angle: -AttitudeActual.Roll + origin.x : sceneItem.width/2 - x + origin.y : sceneItem.height/2 - y + } } - Image { + SvgElementImage { id: foreground - source: "image://svg/pfd.svg!foreground" - sourceSize: background.sourceSize + elementName: "foreground" + sceneSize: background.sceneSize + anchors.centerIn: parent } - Image { - id: compass - source: "image://svg/pfd.svg!compass" - sourceSize: background.sourceSize - clip: true + SvgElementImage { + id: side_slip + elementName: "sideslip" + sceneSize: background.sceneSize + smooth: true - y: 12 - anchors.horizontalCenter: parent.horizontalCenter - - Image { - id: compass_band - source: "image://svg/pfd.svg!compass-band" - sourceSize: background.sourceSize - - anchors.centerIn: parent - //the band is 540 degrees wide - anchors.horizontalCenterOffset: -1*AttitudeActual.Yaw/540*width + property real sideSlip: Accels.y + //smooth side slip changes, a low pass filter replacement + //accels are updated once per second + Behavior on sideSlip { + SmoothedAnimation { + duration: 1000 + velocity: -1 + } } + + anchors.horizontalCenter: foreground.horizontalCenter + //0.5 coefficient is empirical to limit indicator movement + anchors.horizontalCenterOffset: -sideSlip*width*0.5 + y: scaledBounds.y * sceneItem.height + } + + Compass { + anchors.fill: parent + sceneSize: background.sceneSize } SpeedScale { anchors.fill: parent - sourceSize: background.sourceSize + sceneSize: background.sceneSize } AltitudeScale { anchors.fill: parent - sourceSize: background.sourceSize + sceneSize: background.sourceSize + } + + VsiScale { + anchors.fill: parent + sceneSize: background.sourceSize } PfdIndicators { anchors.fill: parent - sourceSize: background.sourceSize + sceneSize: background.sourceSize } } } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml index d520dcf00..8d821e7c3 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdIndicators.qml @@ -2,21 +2,19 @@ import Qt 4.7 Item { id: sceneItem - property variant sourceSize + property variant sceneSize //telemetry status arrow - Image { + SvgElementImage { id: telemetry_status - source: "image://svg/pfd.svg!gcstelemetry-"+statusName - sourceSize: sceneItem.sourceSize + elementName: "gcstelemetry-"+statusName + sceneSize: sceneItem.sceneSize property string statusName : ["Disconnected","HandshakeReq","HandshakeAck","Connected"][GCSTelemetryStats.Status] - property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "gcstelemetry-Disconnected") - x: scaledBounds.x * sceneItem.width - y: scaledBounds.y * sceneItem.height - width: scaledBounds.width * sceneItem.width - height: scaledBounds.height * sceneItem.height + scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "gcstelemetry-Disconnected") + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) } //telemetry rate text @@ -41,8 +39,8 @@ Item { visible: GPSPosition.Satellites > 0 property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "gps-txt") - x: scaledBounds.x * sceneItem.width - y: scaledBounds.y * sceneItem.height + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) } Text { @@ -63,8 +61,7 @@ Item { visible: FlightBatteryState.Voltage > 0 || FlightBatteryState.Current > 0 property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "battery-txt") - x: scaledBounds.x * sceneItem.width - y: scaledBounds.y * sceneItem.height - + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) } } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdWorldView.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdWorldView.qml index 9e4a02b3b..9a461464f 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdWorldView.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/PfdWorldView.qml @@ -1,23 +1,29 @@ import Qt 4.7 Item { - //worldView should fill the source size of svg document id: worldView - Image { + Rectangle { id: world - source: "image://svg/pfd.svg!world" - - sourceSize.width: worldView.width - sourceSize.height: worldView.height - smooth: true + property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "world") + width: Math.round(sceneItem.width*scaledBounds.width/2)*2 + height: Math.round(sceneItem.height*scaledBounds.height/2)*2 + + gradient: Gradient { + GradientStop { position: 0.3; color: "#6589E2" } + GradientStop { position: 0.4999; color: "#AFC2F0" } + GradientStop { position: 0.5; color: "#A46933" } + GradientStop { position: 0.8; color: "black" } + } + transform: [ Translate { id: pitchTranslate - x: (world.parent.width - world.width)/2 - y: (world.parent.height - world.height)/2 + AttitudeActual.Pitch*world.parent.height/94 + x: Math.round((world.parent.width - world.width)/2) + y: Math.round((world.parent.height - world.height)/2 + + AttitudeActual.Pitch*world.parent.height/94) }, Rotation { angle: -AttitudeActual.Roll @@ -25,5 +31,26 @@ Item { origin.y : world.parent.height/2 } ] + + SvgElementImage { + id: pitch_scale + elementName: "pitch_scale" + //worldView is loaded with Loader, so background element is visible + sceneSize: background.sceneSize + anchors.centerIn: parent + border: 64 //sometimes numbers are excluded from bounding rect + + smooth: true + } + + SvgElementImage { + id: horizont_line + elementName: "world-centerline" + //worldView is loaded with Loader, so background element is visible + sceneSize: background.sceneSize + anchors.centerIn: parent + border: 1 + smooth: true + } } } diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml index ddc82b571..1340b9cdb 100644 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SpeedScale.qml @@ -2,28 +2,24 @@ import Qt 4.7 Item { id: sceneItem - property variant sourceSize + property variant sceneSize property real groundSpeed : 3.6 * Math.sqrt(Math.pow(VelocityActual.North,2)+ Math.pow(VelocityActual.East,2)) - Image { + SvgElementImage { id: speed_bg - source: "image://svg/pfd.svg!speed-bg" - sourceSize: sceneItem.sourceSize + elementName: "speed-bg" + sceneSize: sceneItem.sceneSize clip: true - property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "speed-bg") + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) - x: scaledBounds.x * sceneItem.width - y: scaledBounds.y * sceneItem.height - width: scaledBounds.width * sceneItem.width - height: scaledBounds.height * sceneItem.height - - Image { + SvgElementImage { id: speed_scale - source: "image://svg/pfd.svg!speed-scale" - sourceSize: sceneItem.sourceSize + elementName: "speed-scale" + sceneSize: sceneItem.sceneSize anchors.verticalCenter: parent.verticalCenter // The speed scale represents 30 meters, @@ -63,14 +59,12 @@ Item { } - Image { + SvgElementImage { id: speed_window clip: true - source: "image://svg/pfd.svg!speed-window" - sourceSize: sceneItem.sourceSize - - property variant scaledBounds: svgRenderer.scaledElementBounds("pfd.svg", "speed-window") + elementName: "speed-window" + sceneSize: sceneItem.sceneSize x: scaledBounds.x * sceneItem.width y: scaledBounds.y * sceneItem.height diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementImage.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementImage.qml new file mode 100644 index 000000000..ea9d54626 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/SvgElementImage.qml @@ -0,0 +1,34 @@ +import Qt 4.7 + +Image { + id: sceneItem + property variant sceneSize + property string elementName + property string svgFileName: "pfd.svg" + property int vSlice: 0 + property int vSliceCount: 0 + property int hSlice: 0 + property int hSliceCount: 0 + //border property is useful to extent the area of image e bit, + //so it looks well antialiased when rotated + property int border: 0 + property variant scaledBounds: svgRenderer.scaledElementBounds(svgFileName, elementName) + + sourceSize.width: Math.round(sceneSize.width*scaledBounds.width) + sourceSize.height: Math.round(sceneSize.height*scaledBounds.height) + + Component.onCompleted: { + var params = "" + if (hSliceCount > 1) + params += "hslice="+hSlice+":"+hSliceCount+";" + if (vSliceCount > 1) + params += "vslice="+vSlice+":"+vSliceCount+";" + if (border > 0) + params += "border="+border+";" + + if (params != "") + params = "?" + params + + source = "image://svg/"+svgFileName+"!"+elementName+params + } +} diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/VsiScale.qml b/ground/openpilotgcs/share/openpilotgcs/pfd/default/VsiScale.qml new file mode 100644 index 000000000..171c048e0 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/VsiScale.qml @@ -0,0 +1,77 @@ +import Qt 4.7 + +Item { + id: sceneItem + property variant sceneSize + + SvgElementImage { + id: vsi_bg + elementName: "vsi-bg" + sceneSize: sceneItem.sceneSize + clip: true + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + + SvgElementImage { + id: vsi_bar + + elementName: "vsi-bar" + sceneSize: sceneItem.sceneSize + + //the scale in 1000 ft/min with height == 5200 ft/min + height: (-VelocityActual.Down*3.28*60/1000)*(vsi_scale.height/5.2) + + + anchors.bottom: parent.verticalCenter + anchors.left: parent.left + } + + SvgElementImage { + id: vsi_scale + + elementName: "vsi-scale" + sceneSize: sceneItem.sceneSize + + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + + //Text labels + Column { + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.right + + Repeater { + model: [2, 1, 0, 1, 2] + Item { + height: vsi_scale.height / 5.2 //the scale height is 5200 + width: vsi_bg.width - vsi_scale.width //fill area right to scale + + Text { + text: modelData + visible: modelData !== 0 //hide "0" label + color: "white" + font.pixelSize: parent.height / 4 + font.family: "Arial" + + anchors.centerIn: parent + } + } + } + } + } + } + + + SvgElementImage { + id: vsi_window + clip: true + smooth: true + + elementName: "vsi-window" + sceneSize: sceneItem.sceneSize + + x: Math.floor(scaledBounds.x * sceneItem.width) + y: Math.floor(scaledBounds.y * sceneItem.height) + } +} diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg b/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg index 95724c8b8..2fb70210c 100755 --- a/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/pfd.svg @@ -15,11 +15,11 @@ id="svg2" version="1.1" inkscape:version="0.48.3.1 r9886" - sodipodi:docname="pfd.svg" + sodipodi:docname="pfd-6.svg" style="display:inline" - inkscape:export-filename="H:\Documents\Hobbies\OpenPilot\SVN\artwork\PFD-2.png" - inkscape:export-xdpi="269.53" - inkscape:export-ydpi="269.53"> + inkscape:export-filename="C:\Users\Nuno\Desktop\OpenPilot\PFD\PFD-4.png" + inkscape:export-xdpi="71.993568" + inkscape:export-ydpi="71.993568"> + + + + + + + + @@ -1689,14 +1721,14 @@ image/svg+xml - + + transform="translate(230.4171,-2.5493479)" + sodipodi:insensitive="true"> @@ -2097,13 +2046,13 @@ id="speed-bg" width="110.05586" height="450" - x="-209.23766" + x="-147.23766" y="131.33096" /> @@ -2280,11 +2229,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + 1 + 2 + 1 + + + + + + - diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/readymap.earth b/ground/openpilotgcs/share/openpilotgcs/pfd/default/readymap.earth new file mode 100644 index 000000000..55adca838 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/readymap.earth @@ -0,0 +1,35 @@ + + + + + http://readymap.org/readymap/tiles/1.0.0/7/ + + + + http://readymap.org/readymap/tiles/1.0.0/35/ + + + + http://readymap.org/readymap/tiles/1.0.0/9/ + + + + + false + 6.0 + + + + diff --git a/ground/openpilotgcs/share/openpilotgcs/pfd/default/yahoo_readymap.earth b/ground/openpilotgcs/share/openpilotgcs/pfd/default/yahoo_readymap.earth new file mode 100644 index 000000000..6846feb27 --- /dev/null +++ b/ground/openpilotgcs/share/openpilotgcs/pfd/default/yahoo_readymap.earth @@ -0,0 +1,25 @@ + + + + + + satellite + + + + + http://readymap.org/readymap/tiles/1.0.0/9/ + + + + + false + 6.0 + + + diff --git a/ground/openpilotgcs/src/libs/utils/homelocationutil.cpp b/ground/openpilotgcs/src/libs/utils/homelocationutil.cpp index 18b1fd9af..448830573 100644 --- a/ground/openpilotgcs/src/libs/utils/homelocationutil.cpp +++ b/ground/openpilotgcs/src/libs/utils/homelocationutil.cpp @@ -38,40 +38,41 @@ namespace Utils { - HomeLocationUtil::HomeLocationUtil() +HomeLocationUtil::HomeLocationUtil() +{ +} + +/* + /** + * @brief Get local magnetic field + * @param[in] LLA The longitude-latitude-altitude coordinate to compute the magnetic field at + * @param[out] Be The resulting magnetic field at that location and time in [mGau](?) + * @returns 0 if successful, -1 otherwise. + */ + int HomeLocationUtil::getDetails(double LLA[3], double Be[3]) { -// Initialize(); - } + // ************* + // check input parms - // input params: LLA - // - // output params: ECEF, RNE and Be - int HomeLocationUtil::getDetails(double LLA[3], double ECEF[3], double RNE[9], double Be[3]) - { - // ************* - // check input parms + double latitude = LLA[0]; + double longitude = LLA[1]; + double altitude = LLA[2]; - double latitude = LLA[0]; - double longitude = LLA[1]; - double altitude = LLA[2]; + if (latitude != latitude) return -1; // prevent nan error + if (longitude != longitude) return -2; // prevent nan error + if (altitude != altitude) return -3; // prevent nan error - if (latitude != latitude) return -1; // prevent nan error - if (longitude != longitude) return -2; // prevent nan error - if (altitude != altitude) return -3; // prevent nan error + if (latitude < -90 || latitude > 90) return -4; // range checking + if (longitude < -180 || longitude > 180) return -5; // range checking - if (latitude < -90 || latitude > 90) return -4; // range checking - if (longitude < -180 || longitude > 180) return -5; // range checking + // ************* - // ************* + QDateTime dt = QDateTime::currentDateTime().toUTC(); - QDateTime dt = QDateTime::currentDateTime().toUTC(); + //Fetch world magnetic model + Q_ASSERT(WorldMagModel().GetMagVector(LLA, dt.date().month(), dt.date().day(), dt.date().year(), Be) >= 0); - CoordinateConversions().LLA2ECEF(LLA, ECEF); - CoordinateConversions().RneFromLLA(LLA, (double (*)[3])RNE); - if (WorldMagModel().GetMagVector(LLA, dt.date().month(), dt.date().day(), dt.date().year(), Be) < 0) - return -6; - - return 0; // OK + return 0; // OK } } diff --git a/ground/openpilotgcs/src/libs/utils/homelocationutil.h b/ground/openpilotgcs/src/libs/utils/homelocationutil.h index 6448c3e52..acfc43888 100644 --- a/ground/openpilotgcs/src/libs/utils/homelocationutil.h +++ b/ground/openpilotgcs/src/libs/utils/homelocationutil.h @@ -40,7 +40,7 @@ namespace Utils { public: HomeLocationUtil(); - int getDetails(double LLA[3], double ECEF[3], double RNE[9], double Be[3]); + int getDetails(double LLA[3], double Be[3]); private: diff --git a/ground/openpilotgcs/src/libs/utils/svgimageprovider.cpp b/ground/openpilotgcs/src/libs/utils/svgimageprovider.cpp index e0f571369..102a24b26 100644 --- a/ground/openpilotgcs/src/libs/utils/svgimageprovider.cpp +++ b/ground/openpilotgcs/src/libs/utils/svgimageprovider.cpp @@ -67,12 +67,24 @@ QSvgRenderer *SvgImageProvider::loadRenderer(const QString &svgFile) } /** - requestedSize is realted to the whole svg file, not to specific element - */ + Supported id format: fileName[!elementName[?parameters]] + where parameters may be: + vslice=1:2;hslice=2:4 - use the 3rd horizontal slice of total 4 slices, slice numbering starts from 0 + borders=1 - 1 pixel wide transparent border + + requestedSize is related to the whole element size, even if slice is requested. + + usage: + + Image { + source: "image://svg/pfd.svg!world" + } +*/ QImage SvgImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) { QString svgFile = id; QString element; + QString parameters; int separatorPos = id.indexOf('!'); if (separatorPos != -1) { @@ -80,6 +92,34 @@ QImage SvgImageProvider::requestImage(const QString &id, QSize *size, const QSiz element = id.mid(separatorPos+1); } + int parametersPos = element.indexOf('?'); + if (parametersPos != -1) { + parameters = element.mid(parametersPos+1); + element = element.left(parametersPos); + } + + int hSlicesCount = 0; + int hSlice = 0; + int vSlicesCount = 0; + int vSlice = 0; + int border = 0; + if (!parameters.isEmpty()) { + QRegExp hSliceRx("hslice=(\\d+):(\\d+)"); + if (hSliceRx.indexIn(parameters) != -1) { + hSlice = hSliceRx.cap(1).toInt(); + hSlicesCount = hSliceRx.cap(2).toInt(); + } + QRegExp vSliceRx("vslice=(\\d+):(\\d+)"); + if (vSliceRx.indexIn(parameters) != -1) { + vSlice = vSliceRx.cap(1).toInt(); + vSlicesCount = vSliceRx.cap(2).toInt(); + } + QRegExp borderRx("border=(\\d+)"); + if (borderRx.indexIn(parameters) != -1) { + border = borderRx.cap(1).toInt(); + } + } + if (size) *size = QSize(); @@ -92,9 +132,15 @@ QImage SvgImageProvider::requestImage(const QString &id, QSize *size, const QSiz QSize docSize = renderer->defaultSize(); - if (!requestedSize.isEmpty() && !docSize.isEmpty()) { - xScale = qreal(requestedSize.width())/docSize.width(); - yScale = qreal(requestedSize.height())/docSize.height(); + if (!requestedSize.isEmpty()) { + if (!element.isEmpty()) { + QRectF elementBounds = renderer->boundsOnElement(element); + xScale = qreal(requestedSize.width())/elementBounds.width(); + yScale = qreal(requestedSize.height())/elementBounds.height(); + } else if (!docSize.isEmpty()) { + xScale = qreal(requestedSize.width())/docSize.width(); + yScale = qreal(requestedSize.height())/docSize.height(); + } } //keep the aspect ratio @@ -108,16 +154,37 @@ QImage SvgImageProvider::requestImage(const QString &id, QSize *size, const QSiz } QRectF elementBounds = renderer->boundsOnElement(element); - int w = qRound(elementBounds.width() * xScale); - int h = qRound(elementBounds.height() * yScale); + int elementWidth = qRound(elementBounds.width() * xScale); + int elementHeigh = qRound(elementBounds.height() * yScale); + int w = elementWidth; + int h = elementHeigh; + int x = 0; + int y = 0; - QImage img(w, h, QImage::Format_ARGB32_Premultiplied); + if (hSlicesCount > 1) { + x = (w*hSlice)/hSlicesCount; + w = (w*(hSlice+1))/hSlicesCount - x; + } + + if (vSlicesCount > 1) { + y = (h*(vSlice))/vSlicesCount; + h = (h*(vSlice+1))/vSlicesCount - y; + } + + QImage img(w+border*2, h+border*2, QImage::Format_ARGB32_Premultiplied); img.fill(0); QPainter p(&img); - renderer->render(&p, element); + p.setRenderHints(QPainter::TextAntialiasing | + QPainter::Antialiasing | + QPainter::SmoothPixmapTransform); + + p.translate(-x+border,-y+border); + renderer->render(&p, element, QRectF(0, 0, elementWidth, elementHeigh)); if (size) *size = QSize(w, h); + + //img.save(element+parameters+".png"); return img; } else { //render the whole svg file @@ -127,7 +194,12 @@ QImage SvgImageProvider::requestImage(const QString &id, QSize *size, const QSiz QImage img(w, h, QImage::Format_ARGB32_Premultiplied); img.fill(0); QPainter p(&img); - renderer->render(&p); + p.setRenderHints(QPainter::TextAntialiasing | + QPainter::Antialiasing | + QPainter::SmoothPixmapTransform); + + p.scale(xScale, yScale); + renderer->render(&p, QRectF(QPointF(), QSizeF(docSize))); if (size) *size = QSize(w, h); diff --git a/ground/openpilotgcs/src/plugins/coreplugin/coreconstants.h b/ground/openpilotgcs/src/plugins/coreplugin/coreconstants.h index c7a1db3b4..2117843b8 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/coreconstants.h +++ b/ground/openpilotgcs/src/plugins/coreplugin/coreconstants.h @@ -52,8 +52,10 @@ const char * const GCS_YEAR = "2012"; const char * const GCS_HELP = "http://wiki.openpilot.org"; #ifdef GCS_REVISION const char * const GCS_REVISION_STR = STRINGIFY(GCS_REVISION); +const char * const UAVOSHA1_STR = STRINGIFY(UAVO_HASH); #else const char * const GCS_REVISION_STR = ""; +const char * const UAVOSHA1_STR = ""; #endif #undef GCS_VERSION diff --git a/ground/openpilotgcs/src/plugins/coreplugin/gcsversioninfo.pri b/ground/openpilotgcs/src/plugins/coreplugin/gcsversioninfo.pri index 559dc3528..70bb8e475 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/gcsversioninfo.pri +++ b/ground/openpilotgcs/src/plugins/coreplugin/gcsversioninfo.pri @@ -12,12 +12,14 @@ VERSION_INFO_SCRIPT = $$ROOT_DIR/make/scripts/version-info.py VERSION_INFO_TEMPLATE = $$ROOT_DIR/make/templates/gcsversioninfotemplate.h VERSION_INFO_COMMAND = python \"$$VERSION_INFO_SCRIPT\" + UAVO_DEF_PATH = $$ROOT_DIR/shared/uavobjectdefinition # Create custom version_info target which generates a header version_info.target = $$VERSION_INFO_HEADER version_info.commands = $$VERSION_INFO_COMMAND \ --path=\"$$GCS_SOURCE_TREE\" \ --template=\"$$VERSION_INFO_TEMPLATE\" \ + --uavodir=\"$$UAVO_DEF_PATH\" \ --outfile=\"$$VERSION_INFO_HEADER\" version_info.depends = FORCE QMAKE_EXTRA_TARGETS += version_info diff --git a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp b/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp index 1fbb3b1b9..70a125d3b 100644 --- a/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp +++ b/ground/openpilotgcs/src/plugins/coreplugin/versiondialog.cpp @@ -67,6 +67,26 @@ VersionDialog::VersionDialog(QWidget *parent) //: This gets conditionally inserted as argument %8 into the description string. ideRev = tr("From revision %1
").arg(QString::fromLatin1(GCS_REVISION_STR).left(60)); #endif + QString uavoHashStr; + #ifdef UAVO_HASH + //: This gets conditionally inserted as argument %11 into the description string. + QByteArray uavoHashArray; + QString uavoHash = QString::fromLatin1(Core::Constants::UAVOSHA1_STR); + uavoHash.chop(2); + uavoHash.remove(0,2); + uavoHash=uavoHash.trimmed(); + bool ok; + foreach(QString str,uavoHash.split(",")) + { + uavoHashArray.append(str.toInt(&ok,16)); + } + QString gcsUavoHashStr; + foreach(char i, uavoHashArray) + { + gcsUavoHashStr.append(QString::number(i,16).right(2)); + } + uavoHashStr = tr("UAVO hash %1
").arg(gcsUavoHashStr); + #endif const QString description = tr( "

OpenPilot GCS %1 %9 (%10)

" @@ -76,6 +96,8 @@ VersionDialog::VersionDialog(QWidget *parent) "
" "%8" "
" + "%11" + "
" "Copyright 2010-%6 %7. All rights reserved.
" "
" "This program is free software; you can redistribute it and/or modify
" @@ -87,7 +109,7 @@ VersionDialog::VersionDialog(QWidget *parent) "PARTICULAR PURPOSE.

") .arg(version, QLatin1String(QT_VERSION_STR), QString::number(QSysInfo::WordSize), QLatin1String(__DATE__), QLatin1String(__TIME__), QLatin1String(GCS_YEAR), - (QLatin1String(GCS_AUTHOR)), ideRev).arg(QLatin1String(GCS_VERSION_TYPE), QLatin1String(GCS_VERSION_CODENAME)); + (QLatin1String(GCS_AUTHOR)), ideRev).arg(QLatin1String(GCS_VERSION_TYPE), QLatin1String(GCS_VERSION_CODENAME), uavoHashStr); QLabel *copyRightLabel = new QLabel(description); copyRightLabel->setWordWrap(true); diff --git a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.cpp index 2d8e01506..19a2a0426 100644 --- a/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/opmap/opmapgadgetwidget.cpp @@ -46,7 +46,6 @@ #include "uavtalk/telemetrymanager.h" #include "uavobject.h" -#include "uavobjectmanager.h" #include "positionactual.h" #include "homelocation.h" @@ -590,6 +589,7 @@ void OPMapGadgetWidget::updatePosition() VelocityActual *velocityActualObj = VelocityActual::GetInstance(obm); Gyros *gyrosObj = Gyros::GetInstance(obm); + Q_ASSERT(attitudeActualObj); Q_ASSERT(positionActualObj); Q_ASSERT(velocityActualObj); Q_ASSERT(gyrosObj); @@ -919,7 +919,7 @@ void OPMapGadgetWidget::setHome(QPointF pos) /** Sets the home position on the map widget */ -void OPMapGadgetWidget::setHome(internals::PointLatLng pos_lat_lon,double altitude) +void OPMapGadgetWidget::setHome(internals::PointLatLng pos_lat_lon, double altitude) { if (!m_widget || !m_map) return; @@ -941,13 +941,13 @@ void OPMapGadgetWidget::setHome(internals::PointLatLng pos_lat_lon,double altitu if (longitude > 180) longitude = 180; else if (longitude < -180) longitude = -180; - else if(altitude != altitude) altitude=0; // ********* - m_home_position.coord = internals::PointLatLng(latitude, longitude); + m_home_position.coord = internals::PointLatLng(latitude, longitude); + m_home_position.altitude = altitude; - m_map->Home->SetCoord(m_home_position.coord); + m_map->Home->SetCoord(m_home_position.coord); m_map->Home->SetAltitude(altitude); m_map->Home->RefreshPos(); @@ -1659,7 +1659,15 @@ void OPMapGadgetWidget::onSetHomeAct_triggered() if (!m_widget || !m_map) return; - setHome(m_context_menu_lat_lon,0); + float altitude=0; + bool ok; + + //Get desired HomeLocation altitude from dialog box. + //TODO: Populate box with altitude already in HomeLocation UAVO + altitude = QInputDialog::getDouble(this, tr("Set home altitude"), + tr("In [m], referenced to WGS84:"), altitude, -100, 100000, 2, &ok); + + setHome(m_context_menu_lat_lon, altitude); setHomeLocationObject(); // update the HomeLocation UAVObject } diff --git a/ground/openpilotgcs/src/plugins/pfdqml/osgearth.cpp b/ground/openpilotgcs/src/plugins/pfdqml/osgearth.cpp index ce8880ad9..a14fca75e 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/osgearth.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/osgearth.cpp @@ -281,15 +281,7 @@ void OsgEarthItemRenderer::initScene() //setup caching osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(m_model.get()); - if (mapNode) { - osgEarth::TMSCacheOptions cacheOptions; - //cacheOptions.cacheOnly() = true; - QString cacheDir = Utils::PathUtils().GetStoragePath()+QLatin1String("osgEarth_cache"); - cacheOptions.setPath(cacheDir.toStdString()); - osgEarth::Cache *cache= new osgEarth::TMSCache(cacheOptions); - - mapNode->getMap()->setCache(cache); - } else { + if (!mapNode) { qWarning() << Q_FUNC_INFO << sceneFile << " doesn't look like an osgEarth file"; } diff --git a/ground/openpilotgcs/src/plugins/pfdqml/osgearth.h b/ground/openpilotgcs/src/plugins/pfdqml/osgearth.h index 8d0d3f6fe..03f0543a1 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/osgearth.h +++ b/ground/openpilotgcs/src/plugins/pfdqml/osgearth.h @@ -126,9 +126,6 @@ public slots: signals: void frameReady(); -private slots: - void updateFBO(); - private: enum { FboCount = 3 }; OsgEarthItem *m_item; diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.cpp index 89d0b852d..770cc9744 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadget.cpp @@ -38,6 +38,7 @@ PfdQmlGadget::~PfdQmlGadget() void PfdQmlGadget::loadConfiguration(IUAVGadgetConfiguration* config) { PfdQmlGadgetConfiguration *m = qobject_cast(config); + m_widget->setOpenGLEnabled(m->openGLEnabled()); m_widget->setQmlFile(m->qmlFile()); m_widget->setEarthFile(m->earthFile()); m_widget->setTerrainEnabled(m->terrainEnabled()); @@ -51,8 +52,10 @@ void PfdQmlGadget::loadConfiguration(IUAVGadgetConfiguration* config) if (m->cacheOnly()) { qputenv("OSGEARTH_CACHE_ONLY", "true"); } else { - //how portable it is? - //unsetenv("OSGEARTH_CACHE_ONLY"); - qputenv("OSGEARTH_CACHE_ONLY", "false"); +#ifdef Q_OS_WIN32 + qputenv("OSGEARTH_CACHE_ONLY", ""); +#else + unsetenv("OSGEARTH_CACHE_ONLY"); +#endif } } diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp index 8a21da857..8991107fd 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.cpp @@ -25,7 +25,8 @@ PfdQmlGadgetConfiguration::PfdQmlGadgetConfiguration(QString classId, QSettings IUAVGadgetConfiguration(classId, parent), m_qmlFile("Unknown"), m_earthFile("Unknown"), - m_terrainEnabled(true), + m_openGLEnabled(true), + m_terrainEnabled(false), m_actualPositionUsed(false), m_latitude(0), m_longitude(0), @@ -40,6 +41,7 @@ PfdQmlGadgetConfiguration::PfdQmlGadgetConfiguration(QString classId, QSettings m_earthFile = qSettings->value("earthFile").toString(); m_earthFile=Utils::PathUtils().InsertDataPath(m_earthFile); + m_openGLEnabled = qSettings->value("openGLEnabled", true).toBool(); m_terrainEnabled = qSettings->value("terrainEnabled").toBool(); m_actualPositionUsed = qSettings->value("actualPositionUsed").toBool(); m_latitude = qSettings->value("latitude").toDouble(); @@ -57,6 +59,7 @@ IUAVGadgetConfiguration *PfdQmlGadgetConfiguration::clone() { PfdQmlGadgetConfiguration *m = new PfdQmlGadgetConfiguration(this->classId()); m->m_qmlFile = m_qmlFile; + m->m_openGLEnabled = m_openGLEnabled; m->m_earthFile = m_earthFile; m->m_terrainEnabled = m_terrainEnabled; m->m_actualPositionUsed = m_actualPositionUsed; @@ -78,6 +81,7 @@ void PfdQmlGadgetConfiguration::saveConfig(QSettings* qSettings) const { QString earthFile = Utils::PathUtils().RemoveDataPath(m_earthFile); qSettings->setValue("earthFile", earthFile); + qSettings->setValue("openGLEnabled", m_openGLEnabled); qSettings->setValue("terrainEnabled", m_terrainEnabled); qSettings->setValue("actualPositionUsed", m_actualPositionUsed); qSettings->setValue("latitude", m_latitude); diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h index 69205375c..b13f6ea0a 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetconfiguration.h @@ -29,6 +29,7 @@ public: void setQmlFile(const QString &fileName) { m_qmlFile=fileName; } void setEarthFile(const QString &fileName) { m_earthFile=fileName; } + void setOpenGLEnabled(bool flag) { m_openGLEnabled = flag; } void setTerrainEnabled(bool flag) { m_terrainEnabled = flag; } void setActualPositionUsed(bool flag) { m_actualPositionUsed = flag; } void setLatitude(double value) { m_latitude = value; } @@ -38,6 +39,7 @@ public: QString qmlFile() const { return m_qmlFile; } QString earthFile() const { return m_earthFile; } + bool openGLEnabled() const { return m_openGLEnabled; } bool terrainEnabled() const { return m_terrainEnabled; } bool actualPositionUsed() const { return m_actualPositionUsed; } double latitude() const { return m_latitude; } @@ -51,6 +53,7 @@ public: private: QString m_qmlFile; // The name of the dial's SVG source file QString m_earthFile; // The name of osgearth terrain file + bool m_openGLEnabled; bool m_terrainEnabled; bool m_actualPositionUsed; double m_latitude; diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp index 929dce289..bd4d21649 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.cpp @@ -53,6 +53,7 @@ QWidget *PfdQmlGadgetOptionsPage::createPage(QWidget *parent) options_page->earthFile->setPromptDialogTitle(tr("Choose OsgEarth terrain file")); options_page->earthFile->setPath(m_config->earthFile()); + options_page->useOpenGL->setChecked(m_config->openGLEnabled()); options_page->showTerrain->setChecked(m_config->terrainEnabled()); options_page->useActualLocation->setChecked(m_config->actualPositionUsed()); @@ -80,7 +81,13 @@ void PfdQmlGadgetOptionsPage::apply() { m_config->setQmlFile(options_page->qmlSourceFile->path()); m_config->setEarthFile(options_page->earthFile->path()); + m_config->setOpenGLEnabled(options_page->useOpenGL->isChecked()); + +#ifdef USE_OSG m_config->setTerrainEnabled(options_page->showTerrain->isChecked()); +#else + m_config->setTerrainEnabled(false); +#endif m_config->setActualPositionUsed(options_page->useActualLocation->isChecked()); m_config->setLatitude(options_page->latitude->text().toDouble()); diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.ui b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.ui index 5283cfff8..92e87fbb3 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.ui +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetoptionspage.ui @@ -6,8 +6,8 @@ 0 0 - 488 - 394 + 457 + 436 @@ -20,12 +20,6 @@ Form - - 0 - - - -1 - @@ -42,14 +36,11 @@ 0 0 - 488 - 394 + 439 + 418 - - 0 - @@ -81,6 +72,16 @@ + + + Use OpenGL + + + true + + + + Show Terrain: @@ -216,7 +217,7 @@ - + Qt::Vertical @@ -252,12 +253,12 @@ setEnabled(bool) - 150 - 138 + 167 + 188 - 142 - 172 + 260 + 222 @@ -268,12 +269,12 @@ setEnabled(bool) - 164 - 141 + 181 + 188 - 164 - 202 + 282 + 255 @@ -284,12 +285,28 @@ setEnabled(bool) - 190 - 141 + 207 + 188 - 190 - 237 + 308 + 288 + + + + + useOpenGL + toggled(bool) + showTerrain + setEnabled(bool) + + + 99 + 57 + + + 99 + 89 diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp index d6e43e70e..7ef3612aa 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.cpp @@ -34,6 +34,7 @@ PfdQmlGadgetWidget::PfdQmlGadgetWidget(QWidget *parent) : QDeclarativeView(parent), + m_openGLEnabled(false), m_terrainEnabled(false), m_actualPositionUsed(false), m_latitude(46.671478), @@ -44,12 +45,16 @@ PfdQmlGadgetWidget::PfdQmlGadgetWidget(QWidget *parent) : setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); setResizeMode(SizeRootObjectToView); - setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); + //setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); QStringList objectsToExport; objectsToExport << "VelocityActual" << "PositionActual" << "AttitudeActual" << + "Accels" << + "VelocityDesired" << + "PositionDesired" << + "AttitudeHoldDesired" << "GPSPosition" << "GCSTelemetryStats" << "FlightBatteryState"; @@ -106,9 +111,26 @@ void PfdQmlGadgetWidget::setEarthFile(QString arg) void PfdQmlGadgetWidget::setTerrainEnabled(bool arg) { - if (m_terrainEnabled != arg) { - m_terrainEnabled = arg; - emit terrainEnabledChanged(arg); + bool wasEnabled = terrainEnabled(); + m_terrainEnabled = arg; + + if (wasEnabled != terrainEnabled()) + emit terrainEnabledChanged(terrainEnabled()); +} + +void PfdQmlGadgetWidget::setOpenGLEnabled(bool arg) +{ + if (m_openGLEnabled != arg) { + m_openGLEnabled = arg; + + qDebug() << Q_FUNC_INFO << "Set OPENGL" << m_openGLEnabled; + if (m_openGLEnabled) + setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers))); + else + setViewport(new QWidget); + + //update terrainEnabled status with opengl status chaged + setTerrainEnabled(m_terrainEnabled); } } diff --git a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h index ba89f282c..2e8bb3f8e 100644 --- a/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h +++ b/ground/openpilotgcs/src/plugins/pfdqml/pfdqmlgadgetwidget.h @@ -39,7 +39,7 @@ public: void setQmlFile(QString fn); QString earthFile() const { return m_earthFile; } - bool terrainEnabled() const { return m_terrainEnabled; } + bool terrainEnabled() const { return m_terrainEnabled && m_openGLEnabled; } bool actualPositionUsed() const { return m_actualPositionUsed; } double latitude() const { return m_latitude; } @@ -49,6 +49,7 @@ public: public slots: void setEarthFile(QString arg); void setTerrainEnabled(bool arg); + void setOpenGLEnabled(bool arg); void setLatitude(double arg); void setLongitude(double arg); @@ -68,6 +69,7 @@ signals: private: QString m_qmlFileName; QString m_earthFile; + bool m_openGLEnabled; bool m_terrainEnabled; bool m_actualPositionUsed; diff --git a/ground/openpilotgcs/src/plugins/plugins.pro b/ground/openpilotgcs/src/plugins/plugins.pro index f28dc17c1..992b4acd2 100644 --- a/ground/openpilotgcs/src/plugins/plugins.pro +++ b/ground/openpilotgcs/src/plugins/plugins.pro @@ -92,6 +92,7 @@ plugin_uploader.subdir = uploader plugin_uploader.depends = plugin_coreplugin plugin_uploader.depends += plugin_uavobjects plugin_uploader.depends += plugin_rawhid +plugin_uploader.depends += plugin_uavobjectutil SUBDIRS += plugin_uploader #Dial gadget diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/devicedescriptorstruct.h b/ground/openpilotgcs/src/plugins/uavobjectutil/devicedescriptorstruct.h index b83a76a15..886ebe649 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/devicedescriptorstruct.h +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/devicedescriptorstruct.h @@ -8,6 +8,8 @@ public: QString gitHash; QString gitDate; QString gitTag; + QByteArray fwHash; + QByteArray uavoHash; int boardType; int boardRevision; static QString idToBoardName(int id) diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp index 1c69c63e9..bacadeb73 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.cpp @@ -35,7 +35,10 @@ #include #include #include -#include + +#include "firmwareiapobj.h" +#include "homelocation.h" +#include "gpsposition.h" // ****************************** // constructor/destructor @@ -48,6 +51,18 @@ UAVObjectUtilManager::UAVObjectUtilManager() failureTimer.setSingleShot(true); failureTimer.setInterval(1000); connect(&failureTimer, SIGNAL(timeout()),this,SLOT(objectPersistenceOperationFailed())); + + pm = NULL; + obm = NULL; + obum = NULL; + + pm = ExtensionSystem::PluginManager::instance(); + if (pm) + { + obm = pm->getObject(); + obum = pm->getObject(); + } + } UAVObjectUtilManager::~UAVObjectUtilManager() @@ -67,10 +82,8 @@ UAVObjectUtilManager::~UAVObjectUtilManager() UAVObjectManager* UAVObjectUtilManager::getObjectManager() { - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - UAVObjectManager * objMngr = pm->getObject(); - Q_ASSERT(objMngr); - return objMngr; + Q_ASSERT(obm); + return obm; } @@ -107,7 +120,7 @@ void UAVObjectUtilManager::saveNextObject() // Get next object from the queue UAVObject* obj = queue.head(); - qDebug() << "Request board to save object " << obj->getName(); + qDebug() << "Send save object request to board " << obj->getName(); ObjectPersistence* objper = dynamic_cast( getObjectManager()->getObject(ObjectPersistence::NAME) ); connect(objper, SIGNAL(transactionCompleted(UAVObject*,bool)), this, SLOT(objectPersistenceTransactionCompleted(UAVObject*,bool))); @@ -233,16 +246,7 @@ FirmwareIAPObj::DataFields UAVObjectUtilManager::getFirmwareIap() { FirmwareIAPObj::DataFields dummy; - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - Q_ASSERT(pm); - if (!pm) - return dummy; - UAVObjectManager *om = pm->getObject(); - Q_ASSERT(om); - if (!om) - return dummy; - - FirmwareIAPObj *firmwareIap = FirmwareIAPObj::GetInstance(om); + FirmwareIAPObj *firmwareIap = FirmwareIAPObj::GetInstance(obm); Q_ASSERT(firmwareIap); if (!firmwareIap) return dummy; @@ -257,7 +261,12 @@ FirmwareIAPObj::DataFields UAVObjectUtilManager::getFirmwareIap() int UAVObjectUtilManager::getBoardModel() { FirmwareIAPObj::DataFields firmwareIapData = getFirmwareIap(); - return (firmwareIapData.BoardType << 8) + firmwareIapData.BoardRevision; + qDebug()<<"Board type="<getField(QString("ECEF")); - if (!ECEF_field) return -5; + homeLocation->setData(homeLocationData); - UAVObjectField *RNE_field = obj->getField(QString("RNE")); - if (!RNE_field) return -6; + if (save_to_sdcard) + saveObjectToSD(homeLocation); - UAVObjectField *Be_field = obj->getField(QString("Be")); - if (!Be_field) return -7; - - field = obj->getField("Latitude"); - if (!field) return -8; - field->setDouble(LLA[0] * 10e6); - - field = obj->getField("Longitude"); - if (!field) return -9; - field->setDouble(LLA[1] * 10e6); - - field = obj->getField("Altitude"); - if (!field) return -10; - field->setDouble(LLA[2]); - - for (int i = 0; i < 3; i++) - ECEF_field->setDouble(ECEF[i] * 100, i); - - for (int i = 0; i < 9; i++) - RNE_field->setDouble(RNE[i], i); - - for (int i = 0; i < 3; i++) - Be_field->setDouble(Be[i], i); - - field = obj->getField("Set"); - if (!field) return -11; - field->setValue("TRUE"); - - obj->updated(); - - // ****************** - // save the new setting to SD card - - if (save_to_sdcard) - saveObjectToSD(obj); - - // ****************** - // debug -/* - qDebug() << "setting HomeLocation UAV Object .. " << endl; - QString s; - s = " LAT:" + QString::number(LLA[0], 'f', 7) + " LON:" + QString::number(LLA[1], 'f', 7) + " ALT:" + QString::number(LLA[2], 'f', 1); - qDebug() << s << endl; - s = " ECEF "; for (int i = 0; i < 3; i++) s += " " + QString::number((int)(ECEF[i] * 100)); - qDebug() << s << endl; - s = " RNE "; for (int i = 0; i < 9; i++) s += " " + QString::number(RNE[i], 'f', 7); - qDebug() << s << endl; - s = " Be "; for (int i = 0; i < 3; i++) s += " " + QString::number(Be[i], 'f', 2); - qDebug() << s << endl; -*/ - // ****************** - - return 0; // OK + return 0; } int UAVObjectUtilManager::getHomeLocation(bool &set, double LLA[3]) { - UAVObjectField *field; + HomeLocation *homeLocation = HomeLocation::GetInstance(obm); + Q_ASSERT(homeLocation != NULL); - QMutexLocker locker(mutex); + HomeLocation::DataFields homeLocationData = homeLocation->getData(); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) return -1; + set = homeLocationData.Set; - UAVObjectManager *om = pm->getObject(); - if (!om) return -2; - - UAVDataObject *obj = dynamic_cast(om->getObject(QString("HomeLocation"))); - if (!obj) return -3; - -// obj->requestUpdate(); - - field = obj->getField("Set"); - if (!field) return -4; - set = field->getValue().toBool(); - - field = obj->getField("Latitude"); - if (!field) return -5; - LLA[0] = field->getDouble() * 1e-7; - - field = obj->getField("Longitude"); - if (!field) return -6; - LLA[1] = field->getDouble() * 1e-7; - - field = obj->getField("Altitude"); - if (!field) return -7; - LLA[2] = field->getDouble(); + LLA[0] = homeLocationData.Latitude*1e-7; + LLA[1] = homeLocationData.Longitude*1e-7; + LLA[2] = homeLocationData.Altitude; if (LLA[0] != LLA[0]) LLA[0] = 0; // nan detection else @@ -434,88 +369,20 @@ int UAVObjectUtilManager::getHomeLocation(bool &set, double LLA[3]) return 0; // OK } -int UAVObjectUtilManager::getHomeLocation(bool &set, double LLA[3], double ECEF[3], double RNE[9], double Be[3]) -{ - UAVObjectField *field; - - QMutexLocker locker(mutex); - - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) return -1; - - UAVObjectManager *om = pm->getObject(); - if (!om) return -2; - - UAVDataObject *obj = dynamic_cast(om->getObject(QString("HomeLocation"))); - if (!obj) return -3; - -// obj->requestUpdate(); - - field = obj->getField("Set"); - if (!field) return -4; - set = field->getValue().toBool(); - - field = obj->getField("Latitude"); - if (!field) return -5; - LLA[0] = field->getDouble() * 1e-7; - - field = obj->getField("Longitude"); - if (!field) return -6; - LLA[1] = field->getDouble() * 1e-7; - - field = obj->getField("Altitude"); - if (!field) return -7; - LLA[2] = field->getDouble(); - - field = obj->getField(QString("ECEF")); - if (!field) return -8; - for (int i = 0; i < 3; i++) - ECEF[i] = field->getDouble(i); - - field = obj->getField(QString("RNE")); - if (!field) return -9; - for (int i = 0; i < 9; i++) - RNE[i] = field->getDouble(i); - - field = obj->getField(QString("Be")); - if (!field) return -10; - for (int i = 0; i < 3; i++) - Be[i] = field->getDouble(i); - - return 0; // OK -} // ****************************** // GPS int UAVObjectUtilManager::getGPSPosition(double LLA[3]) { - UAVObjectField *field; + GPSPosition *gpsPosition = GPSPosition::GetInstance(obm); + Q_ASSERT(gpsPosition != NULL); - QMutexLocker locker(mutex); + GPSPosition::DataFields gpsPositionData = gpsPosition->getData(); - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) return -1; - - UAVObjectManager *om = pm->getObject(); - if (!om) return -2; - - UAVDataObject *obj = dynamic_cast(om->getObject(QString("GPSPosition"))); - if (!obj) return -3; - -// obj->requestUpdate(); - - field = obj->getField(QString("Latitude")); - if (!field) return -4; - LLA[0] = field->getDouble() * 1e-7; - - field = obj->getField(QString("Longitude")); - if (!field) return -5; - LLA[1] = field->getDouble() * 1e-7; - - field = obj->getField(QString("Altitude")); - if (!field) return -6; - LLA[2] = field->getDouble(); + LLA[0] = gpsPositionData.Latitude; + LLA[1] = gpsPositionData.Longitude; + LLA[2] = gpsPositionData.Altitude; if (LLA[0] != LLA[0]) LLA[0] = 0; // nan detection else @@ -534,102 +401,14 @@ int UAVObjectUtilManager::getGPSPosition(double LLA[3]) return 0; // OK } -// ****************************** -// telemetry port - -int UAVObjectUtilManager::setTelemetrySerialPortSpeed(QString speed, bool save_to_sdcard) -{ - UAVObjectField *field; - - QMutexLocker locker(mutex); - - // ****************** - // save the new settings - - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) return -1; - - UAVObjectManager *om = pm->getObject(); - if (!om) return -2; - - UAVDataObject *obj = dynamic_cast(om->getObject(QString("/*TelemetrySettings*/"))); - if (!obj) return -3; - - field = obj->getField(QString("Speed")); - if (!field) return -4; - field->setValue(speed); - - obj->updated(); - - // ****************** - // save the new setting to SD card - - if (save_to_sdcard) - saveObjectToSD(obj); - - // ****************** - - return 0; // OK -} - -int UAVObjectUtilManager::getTelemetrySerialPortSpeed(QString &speed) -{ - UAVObjectField *field; - - QMutexLocker locker(mutex); - - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) return -1; - - UAVObjectManager *om = pm->getObject(); - if (!om) return -2; - - UAVDataObject *obj = dynamic_cast(om->getObject(QString("TelemetrySettings"))); - if (!obj) return -3; - -// obj->requestUpdate(); - - field = obj->getField(QString("Speed")); - if (!field) return -4; - speed = field->getValue().toString(); - - return 0; // OK -} - -int UAVObjectUtilManager::getTelemetrySerialPortSpeeds(QComboBox *comboBox) -{ - UAVObjectField *field; - - QMutexLocker locker(mutex); - - if (!comboBox) return -1; - - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (!pm) return -2; - - UAVObjectManager *om = pm->getObject(); - if (!om) return -3; - - UAVDataObject *obj = dynamic_cast(om->getObject(QString("TelemetrySettings"))); - if (!obj) return -4; - -// obj->requestUpdate(); - - field = obj->getField(QString("Speed")); - if (!field) return -5; - comboBox->addItems(field->getOptions()); - - return 0; // OK -} - deviceDescriptorStruct UAVObjectUtilManager::getBoardDescriptionStruct() { deviceDescriptorStruct ret; - descriptionToStructure(getBoardDescription(),&ret); + descriptionToStructure(getBoardDescription(),ret); return ret; } -bool UAVObjectUtilManager::descriptionToStructure(QByteArray desc, deviceDescriptorStruct *struc) +bool UAVObjectUtilManager::descriptionToStructure(QByteArray desc, deviceDescriptorStruct & struc) { if (desc.startsWith("OpFw")) { /* @@ -639,9 +418,9 @@ bool UAVObjectUtilManager::descriptionToStructure(QByteArray desc, deviceDescrip * 4 bytes: Unix timestamp of last git commit * 2 bytes: target platform. Should follow same rule as BOARD_TYPE and BOARD_REVISION in board define files. * 26 bytes: commit tag if it is there, otherwise "Unreleased". Zero-padded - * ---- 40 bytes limit --- * 20 bytes: SHA1 sum of the firmware. - * 40 bytes: free for now. + * 20 bytes: SHA1 sum of the UAVO definition files. + * 20 bytes: free for now. */ // Note: the ARM binary is big-endian: @@ -650,23 +429,26 @@ bool UAVObjectUtilManager::descriptionToStructure(QByteArray desc, deviceDescrip gitCommitHash = gitCommitHash << 8; gitCommitHash += desc.at(7-i) & 0xFF; } - struc->gitHash = QString::number(gitCommitHash, 16); + struc.gitHash = QString("%1").arg(gitCommitHash, 8, 16, QChar('0')); quint32 gitDate = desc.at(11) & 0xFF; for (int i = 1; i < 4; i++) { gitDate = gitDate << 8; gitDate += desc.at(11-i) & 0xFF; } - struc->gitDate = QDateTime::fromTime_t(gitDate).toUTC().toString("yyyyMMdd HH:mm"); + struc.gitDate = QDateTime::fromTime_t(gitDate).toUTC().toString("yyyyMMdd HH:mm"); QString gitTag = QString(desc.mid(14,26)); - struc->gitTag = gitTag; + struc.gitTag = gitTag; // TODO: check platform compatibility QByteArray targetPlatform = desc.mid(12,2); - struc->boardType = (int)targetPlatform.at(0); - struc->boardRevision = (int)targetPlatform.at(1); - + struc.boardType = (int)targetPlatform.at(0); + struc.boardRevision = (int)targetPlatform.at(1); + struc.fwHash.clear(); + struc.fwHash=desc.mid(40,20); + struc.uavoHash.clear(); + struc.uavoHash=desc.mid(60,20); return true; } return false; diff --git a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h index 6f71123b8..8ea9dc8f2 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h +++ b/ground/openpilotgcs/src/plugins/uavobjectutil/uavobjectutilmanager.h @@ -55,20 +55,15 @@ public: int setHomeLocation(double LLA[3], bool save_to_sdcard); int getHomeLocation(bool &set, double LLA[3]); - int getHomeLocation(bool &set, double LLA[3], double ECEF[3], double RNE[9], double Be[3]); int getGPSPosition(double LLA[3]); - int setTelemetrySerialPortSpeed(QString speed, bool save_to_sdcard); - int getTelemetrySerialPortSpeed(QString &speed); - int getTelemetrySerialPortSpeeds(QComboBox *comboBox); - int getBoardModel(); QByteArray getBoardCPUSerial(); quint32 getFirmwareCRC(); QByteArray getBoardDescription(); deviceDescriptorStruct getBoardDescriptionStruct(); - static bool descriptionToStructure(QByteArray desc,deviceDescriptorStruct * struc); + static bool descriptionToStructure(QByteArray desc,deviceDescriptorStruct & struc); UAVObjectManager* getObjectManager(); void saveObjectToSD(UAVObject *obj); protected: @@ -78,11 +73,15 @@ signals: void saveCompleted(int objectID, bool status); private: - QMutex *mutex; - QQueue queue; - enum {IDLE, AWAITING_ACK, AWAITING_COMPLETED} saveState; - void saveNextObject(); - QTimer failureTimer; + QMutex *mutex; + QQueue queue; + enum {IDLE, AWAITING_ACK, AWAITING_COMPLETED} saveState; + void saveNextObject(); + QTimer failureTimer; + + ExtensionSystem::PluginManager *pm; + UAVObjectManager *obm; + UAVObjectUtilManager *obum; private slots: //void transactionCompleted(UAVObject *obj, bool success); diff --git a/ground/openpilotgcs/src/plugins/uavtalk/telemetrymonitor.h b/ground/openpilotgcs/src/plugins/uavtalk/telemetrymonitor.h index 5d480a86e..2cd31c474 100644 --- a/ground/openpilotgcs/src/plugins/uavtalk/telemetrymonitor.h +++ b/ground/openpilotgcs/src/plugins/uavtalk/telemetrymonitor.h @@ -60,7 +60,7 @@ public slots: private: static const int STATS_UPDATE_PERIOD_MS = 4000; - static const int STATS_CONNECT_PERIOD_MS = 1000; + static const int STATS_CONNECT_PERIOD_MS = 2000; static const int CONNECTION_TIMEOUT_MS = 8000; UAVObjectManager* objMngr; diff --git a/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp b/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp index dec1fefb7..c944f9a37 100644 --- a/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/devicewidget.cpp @@ -154,7 +154,7 @@ void deviceWidget::freeze() */ bool deviceWidget::populateBoardStructuredDescription(QByteArray desc) { - if(UAVObjectUtilManager::descriptionToStructure(desc,&onBoardDescription)) + if(UAVObjectUtilManager::descriptionToStructure(desc,onBoardDescription)) { myDevice->lblGitTag->setText(onBoardDescription.gitHash); myDevice->lblBuildDate->setText(onBoardDescription.gitDate.insert(4,"-").insert(7,"-")); @@ -184,7 +184,7 @@ bool deviceWidget::populateBoardStructuredDescription(QByteArray desc) } bool deviceWidget::populateLoadedStructuredDescription(QByteArray desc) { - if(UAVObjectUtilManager::descriptionToStructure(desc,&LoadedDescription)) + if(UAVObjectUtilManager::descriptionToStructure(desc,LoadedDescription)) { myDevice->lblGitTagL->setText(LoadedDescription.gitHash); myDevice->lblBuildDateL->setText( LoadedDescription.gitDate.insert(4,"-").insert(7,"-")); diff --git a/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.cpp b/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.cpp index 40be848e7..284345b62 100644 --- a/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/runningdevicewidget.cpp @@ -101,7 +101,7 @@ void runningDeviceWidget::populate() QByteArray description = utilMngr->getBoardDescription(); deviceDescriptorStruct devDesc; - if(UAVObjectUtilManager::descriptionToStructure(description,&devDesc)) + if(UAVObjectUtilManager::descriptionToStructure(description,devDesc)) { if(devDesc.gitTag.startsWith("release",Qt::CaseInsensitive)) { diff --git a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp index 160944b8b..314914667 100755 --- a/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/uploader/uploadergadgetwidget.cpp @@ -650,18 +650,41 @@ void UploaderGadgetWidget::versionMatchCheck() ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); UAVObjectUtilManager *utilMngr = pm->getObject(); deviceDescriptorStruct boardDescription = utilMngr->getBoardDescriptionStruct(); + QByteArray uavoHashArray; + QString uavoHash = QString::fromLatin1(Core::Constants::UAVOSHA1_STR); + uavoHash.chop(2); + uavoHash.remove(0,2); + uavoHash=uavoHash.trimmed(); + bool ok; + foreach(QString str,uavoHash.split(",")) + { + uavoHashArray.append(str.toInt(&ok,16)); + } - QString gcsDescription = QString::fromLatin1(Core::Constants::GCS_REVISION_STR); - QString gcsGitHash = gcsDescription.mid(gcsDescription.indexOf(":")+1, 8); - gcsGitHash.remove( QRegExp("^[0]*") ); - QString gcsGitDate = gcsDescription.mid(gcsDescription.indexOf(" ")+1, 14); - QString gcsVersion = gcsGitDate + " (" + gcsGitHash + ")"; - QString fwVersion = boardDescription.gitDate + " (" + boardDescription.gitHash + ")"; + QByteArray fwVersion=boardDescription.uavoHash; + if (fwVersion != uavoHashArray) { + + QString gcsDescription = QString::fromLatin1(Core::Constants::GCS_REVISION_STR); + QString gcsGitHash = gcsDescription.mid(gcsDescription.indexOf(":")+1, 8); + gcsGitHash.remove( QRegExp("^[0]*") ); + QString gcsGitDate = gcsDescription.mid(gcsDescription.indexOf(" ")+1, 14); + + QString gcsUavoHashStr; + QString fwUavoHashStr; + foreach(char i, fwVersion) + { + fwUavoHashStr.append(QString::number(i,16).right(2)); + } + foreach(char i, uavoHashArray) + { + gcsUavoHashStr.append(QString::number(i,16).right(2)); + } + QString gcsVersion = gcsGitDate + " (" + gcsGitHash + "-"+ gcsUavoHashStr.right(8) + ")"; + QString fwVersion = boardDescription.gitDate + " (" + boardDescription.gitHash + "-" + fwUavoHashStr.right(8) + ")"; - if (boardDescription.gitHash != gcsGitHash) { QString warning = QString(tr( - "GCS and firmware versions do not match which can cause configuration problems. " - "GCS version: %1. Firmware version: %2.")).arg(gcsVersion).arg(fwVersion); + "GCS and firmware versions of the UAV objects set do not match which can cause configuration problems. " + "GCS version: %1 Firmware version: %2.")).arg(gcsVersion).arg(fwVersion); msg->showMessage(warning); } } 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/make/firmware-defs.mk b/make/firmware-defs.mk index 522d2e320..e77e71d2a 100644 --- a/make/firmware-defs.mk +++ b/make/firmware-defs.mk @@ -131,7 +131,8 @@ $(1).firmwareinfo.c: $(1) $(TOP)/make/templates/firmwareinfotemplate.c FORCE --outfile=$$@ \ --image=$(1) \ --type=$(2) \ - --revision=$(3) + --revision=$(3) \ + --uavodir=$(TOP)/shared/uavobjectdefinition $(eval $(call COMPILE_C_TEMPLATE, $(1).firmwareinfo.c)) diff --git a/make/scripts/version-info.py b/make/scripts/version-info.py index 8c4fe901e..2f742962b 100644 --- a/make/scripts/version-info.py +++ b/make/scripts/version-info.py @@ -250,6 +250,57 @@ def xtrim(string, suffix, length): assert n > 0, "length of truncated string+suffix exceeds maximum length" return ''.join([string[:n], '+', suffix]) +def GetHashofDirs(directory, verbose=0): + import hashlib, os + SHAhash = hashlib.sha1() + if not os.path.exists (directory): + return -1 + + try: + for root, dirs, files in os.walk(directory): + # os.walk() is unsorted. Must make sure we process files in sorted order so + # that the hash is stable across invocations and across OSes. + if files: + files.sort() + + for names in files: + if verbose == 1: + print 'Hashing', names + filepath = os.path.join(root,names) + try: + f1 = open(filepath, 'rb') + except: + # You can't open the file for some reason + f1.close() + continue + + # Compute file hash. Same as running "sha1sum ". + f1hash = hashlib.sha1() + while 1: + # Read file in as little chunks + buf = f1.read(4096) + if not buf : break + f1hash.update(buf) + f1.close() + + if verbose == 1: + print 'Hash is', f1hash.hexdigest() + + # Append the hex representation of the current file's hash into the cumulative hash + SHAhash.update(f1hash.hexdigest()) + + except: + import traceback + # Print the stack traceback + traceback.print_exc() + return -2 + + if verbose == 1: + print 'Final hash is', SHAhash.hexdigest() + + hex_stream = lambda s:",".join(['0x'+hex(ord(c))[2:].zfill(2) for c in s]) + return hex_stream(SHAhash.digest()) + def main(): """This utility uses git repository in the current working directory or from the given path to extract some info about it and HEAD commit. @@ -302,7 +353,8 @@ dependent targets. help='board type, for example, 0x04 for CopterControl'); parser.add_option('--revision', default = "", help='board revision, for example, 0x01'); - + parser.add_option('--uavodir', default = "", + help='uav object definition directory'); (args, positional_args) = parser.parse_args() if len(positional_args) != 0: parser.error("incorrect number of arguments, try --help for help") @@ -328,6 +380,7 @@ dependent targets. BOARD_TYPE = args.type, BOARD_REVISION = args.revision, SHA1 = sha1(args.image), + UAVOSHA1= GetHashofDirs(args.uavodir,0), ) if args.info: diff --git a/make/templates/firmwareinfotemplate.c b/make/templates/firmwareinfotemplate.c index b9297273e..6e4fbf8b3 100644 --- a/make/templates/firmwareinfotemplate.c +++ b/make/templates/firmwareinfotemplate.c @@ -30,8 +30,6 @@ /** * We have 100 bytes for the whole description. * - * Only the first 40 are visible on the FirmwareIAP uavobject, the remaining - * 60 are ok to use for packaging and will be saved in the flash. * * Structure is: * 4 bytes: header: "OpFw". @@ -39,9 +37,9 @@ * 4 bytes: Unix timestamp of compile time. * 2 bytes: target platform. Should follow same rule as BOARD_TYPE and BOARD_REVISION in board define files. * 26 bytes: commit tag if it is there, otherwise branch name. '-dirty' may be added if needed. Zero-padded. - * ---- 40 bytes limit --- * 20 bytes: SHA1 sum of the firmware. - * 40 bytes: free for now. + * 20 bytes: SHA1 sum of the uavo definitions. + * 20 bytes: free for now. * */ @@ -53,7 +51,8 @@ struct __attribute__((packed)) fw_version_info { uint8_t board_revision; uint8_t commit_tag_name[26]; uint8_t sha1sum[20]; - uint8_t pad[40]; + uint8_t uavosha1[20]; + uint8_t pad[20]; }; const struct fw_version_info fw_version_blob __attribute__((used)) __attribute__((__section__(".fw_version_blob"))) = { @@ -64,6 +63,7 @@ const struct fw_version_info fw_version_blob __attribute__((used)) __attribute__ .board_revision = ${BOARD_REVISION}, .commit_tag_name = "${FWTAG}", .sha1sum = { ${SHA1} }, + .uavosha1 = { ${UAVOSHA1} }, }; /** diff --git a/make/templates/gcsversioninfotemplate.h b/make/templates/gcsversioninfotemplate.h index 2130f59bf..7b7dc8100 100644 --- a/make/templates/gcsversioninfotemplate.h +++ b/make/templates/gcsversioninfotemplate.h @@ -26,7 +26,7 @@ */ #define GCS_REVISION ${TAG_OR_BRANCH}:${HASH8}${DIRTY} ${DATETIME} - +#define UAVO_HASH "{ ${UAVOSHA1} }" /** * @} */ diff --git a/shared/uavobjectdefinition/firmwareiapobj.xml b/shared/uavobjectdefinition/firmwareiapobj.xml index be8431ef5..9ce85bfcf 100644 --- a/shared/uavobjectdefinition/firmwareiapobj.xml +++ b/shared/uavobjectdefinition/firmwareiapobj.xml @@ -2,7 +2,7 @@ Queries board for SN, model, revision, and sends reset command - + 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/relaytuning.xml b/shared/uavobjectdefinition/relaytuning.xml index d781e45ca..e7b7419ee 100644 --- a/shared/uavobjectdefinition/relaytuning.xml +++ b/shared/uavobjectdefinition/relaytuning.xml @@ -3,7 +3,7 @@ The input to the relay tuning. - + diff --git a/shared/uavobjectdefinition/taskinfo.xml b/shared/uavobjectdefinition/taskinfo.xml index 45b1a3b09..23f503c80 100644 --- a/shared/uavobjectdefinition/taskinfo.xml +++ b/shared/uavobjectdefinition/taskinfo.xml @@ -1,9 +1,79 @@ Task information - - - + + + System + Actuator + Attitude + Sensors + TelemetryTx + TelemetryTxPri + TelemetryRx + GPS + ManualControl + Altitude + Stabilization + AltitudeHold + Guidance + FlightPlan + Com2UsbBridge + Usb2ComBridge + OveroSync + Autotune + EventDispatcher + + + + + System + Actuator + Attitude + Sensors + TelemetryTx + TelemetryTxPri + TelemetryRx + GPS + ManualControl + Altitude + Stabilization + AltitudeHold + Guidance + FlightPlan + Com2UsbBridge + Usb2ComBridge + OveroSync + Autotune + EventDispatcher + + + + + + + + + System + Actuator + Attitude + Sensors + TelemetryTx + TelemetryTxPri + TelemetryRx + GPS + ManualControl + Altitude + Stabilization + AltitudeHold + Guidance + FlightPlan + Com2UsbBridge + Usb2ComBridge + OveroSync + Autotune + EventDispatcher + +