1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2025-02-21 11:54:15 +01:00

Merge branch 'next' of ssh://git.openpilot.org/OpenPilot into next

This commit is contained in:
chris pember 2012-09-27 20:41:33 -07:00
commit c6c8ff9487
28 changed files with 531 additions and 430 deletions

View File

@ -435,9 +435,6 @@ void PIOS_MPU6000_IRQHandler(void)
if(PIOS_MPU6000_ClaimBus() != 0) if(PIOS_MPU6000_ClaimBus() != 0)
return; 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) { if(PIOS_SPI_TransferBlock(dev->spi_id, &mpu6000_send_buf[0], &mpu6000_rec_buf[0], sizeof(mpu6000_send_buf), NULL) < 0) {
PIOS_MPU6000_ReleaseBus(); PIOS_MPU6000_ReleaseBus();
mpu6000_fails++; mpu6000_fails++;

View File

@ -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; 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); 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 wValue0 = pInformation->USBwValue0;
uint8_t wValue1 = pInformation->USBwValue1; uint8_t wValue1 = pInformation->USBwValue1;
@ -338,14 +341,25 @@ static struct usb_cdc_line_coding line_coding = {
.bDataBits = 8, .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; 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); 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) 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; 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); bool valid = PIOS_USB_CDC_validate(usb_cdc_dev);
PIOS_Assert(valid); if (!valid) {
/* No CDC interface is configured */
return NULL;
}
if (Length == 0) { if (Length == 0) {
pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding); pInformation->Ctrl_Info.Usb_wLength = sizeof(line_coding);

View File

@ -293,13 +293,16 @@ static void PIOS_USBHOOK_Status_Out(void)
* Output : None. * Output : None.
* Return : USB_UNSUPPORT or USB_SUCCESS. * 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); extern const uint8_t *PIOS_USB_CDC_GetLineCoding(uint16_t Length);
static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo) 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) { switch (Type_Recipient) {
case (STANDARD_REQUEST | INTERFACE_RECIPIENT): case (STANDARD_REQUEST | INTERFACE_RECIPIENT):
@ -313,10 +316,10 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
case GET_DESCRIPTOR: case GET_DESCRIPTOR:
switch (pInformation->USBwValue1) { switch (pInformation->USBwValue1) {
case USB_DESC_TYPE_REPORT: case USB_DESC_TYPE_REPORT:
CopyRoutine = PIOS_USBHOOK_GetReportDescriptor; CopyInRoutine = PIOS_USBHOOK_GetReportDescriptor;
break; break;
case USB_DESC_TYPE_HID: case USB_DESC_TYPE_HID:
CopyRoutine = PIOS_USBHOOK_GetHIDDescriptor; CopyInRoutine = PIOS_USBHOOK_GetHIDDescriptor;
break; break;
} }
} }
@ -332,7 +335,7 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
#endif #endif
switch (RequestNo) { switch (RequestNo) {
case USB_HID_REQ_GET_PROTOCOL: case USB_HID_REQ_GET_PROTOCOL:
CopyRoutine = PIOS_USBHOOK_GetProtocolValue; CopyInRoutine = PIOS_USBHOOK_GetProtocolValue;
break; break;
} }
@ -340,8 +343,11 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
#if defined(PIOS_INCLUDE_USB_CDC) #if defined(PIOS_INCLUDE_USB_CDC)
case 0: /* CDC Call Control Interface */ case 0: /* CDC Call Control Interface */
switch (RequestNo) { switch (RequestNo) {
case USB_CDC_REQ_SET_LINE_CODING:
CopyOutRoutine = PIOS_USB_CDC_SetLineCoding;
break;
case USB_CDC_REQ_GET_LINE_CODING: case USB_CDC_REQ_GET_LINE_CODING:
//CopyRoutine = PIOS_USB_CDC_GetLineCoding; CopyInRoutine = PIOS_USB_CDC_GetLineCoding;
break; break;
} }
@ -359,13 +365,27 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
break; break;
} }
if (CopyRoutine == NULL) { /* No registered copy routine */
if ((CopyInRoutine == NULL) && (CopyOutRoutine == NULL)) {
return USB_UNSUPPORT; return USB_UNSUPPORT;
} }
pInformation->Ctrl_Info.CopyDataIn = CopyRoutine; /* Registered copy in AND copy out routine */
pInformation->Ctrl_Info.Usb_wOffset = 0; if ((CopyInRoutine != NULL) && (CopyOutRoutine != NULL)) {
(*CopyRoutine) (0); /* 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; return USB_SUCCESS;
} }
@ -377,7 +397,6 @@ static RESULT PIOS_USBHOOK_Data_Setup(uint8_t RequestNo)
* Return : USB_UNSUPPORT or USB_SUCCESS. * Return : USB_UNSUPPORT or USB_SUCCESS.
*******************************************************************************/ *******************************************************************************/
extern RESULT PIOS_USB_CDC_SetControlLineState(void); extern RESULT PIOS_USB_CDC_SetControlLineState(void);
extern RESULT PIOS_USB_CDC_SetLineCoding(void);
static RESULT PIOS_USBHOOK_NoData_Setup(uint8_t RequestNo) 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) #if defined(PIOS_INCLUDE_USB_CDC)
case 0: /* CDC Call Control Interface */ case 0: /* CDC Call Control Interface */
switch (RequestNo) { switch (RequestNo) {
case USB_CDC_REQ_SET_LINE_CODING:
return PIOS_USB_CDC_SetLineCoding();
break;
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
return PIOS_USB_CDC_SetControlLineState(); return PIOS_USB_CDC_SetControlLineState();
break; break;

View File

@ -267,7 +267,7 @@ enum usb_cdc_requests {
USB_CDC_REQ_SET_LINE_CODING = 0x20, USB_CDC_REQ_SET_LINE_CODING = 0x20,
USB_CDC_REQ_GET_LINE_CODING = 0x21, 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 { struct usb_cdc_header_func_desc {

View File

@ -38,40 +38,41 @@
namespace Utils { 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 double latitude = LLA[0];
// double longitude = LLA[1];
// output params: ECEF, RNE and Be double altitude = LLA[2];
int HomeLocationUtil::getDetails(double LLA[3], double ECEF[3], double RNE[9], double Be[3])
{
// *************
// check input parms
double latitude = LLA[0]; if (latitude != latitude) return -1; // prevent nan error
double longitude = LLA[1]; if (longitude != longitude) return -2; // prevent nan error
double altitude = LLA[2]; if (altitude != altitude) return -3; // prevent nan error
if (latitude != latitude) return -1; // prevent nan error if (latitude < -90 || latitude > 90) return -4; // range checking
if (longitude != longitude) return -2; // prevent nan error if (longitude < -180 || longitude > 180) return -5; // range checking
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
// ************* 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); return 0; // OK
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
} }
} }

View File

@ -40,7 +40,7 @@ namespace Utils {
public: public:
HomeLocationUtil(); HomeLocationUtil();
int getDetails(double LLA[3], double ECEF[3], double RNE[9], double Be[3]); int getDetails(double LLA[3], double Be[3]);
private: private:

View File

@ -52,8 +52,10 @@ const char * const GCS_YEAR = "2012";
const char * const GCS_HELP = "http://wiki.openpilot.org"; const char * const GCS_HELP = "http://wiki.openpilot.org";
#ifdef GCS_REVISION #ifdef GCS_REVISION
const char * const GCS_REVISION_STR = STRINGIFY(GCS_REVISION); const char * const GCS_REVISION_STR = STRINGIFY(GCS_REVISION);
const char * const UAVOSHA1_STR = STRINGIFY(UAVO_HASH);
#else #else
const char * const GCS_REVISION_STR = ""; const char * const GCS_REVISION_STR = "";
const char * const UAVOSHA1_STR = "";
#endif #endif
#undef GCS_VERSION #undef GCS_VERSION

View File

@ -12,12 +12,14 @@
VERSION_INFO_SCRIPT = $$ROOT_DIR/make/scripts/version-info.py VERSION_INFO_SCRIPT = $$ROOT_DIR/make/scripts/version-info.py
VERSION_INFO_TEMPLATE = $$ROOT_DIR/make/templates/gcsversioninfotemplate.h VERSION_INFO_TEMPLATE = $$ROOT_DIR/make/templates/gcsversioninfotemplate.h
VERSION_INFO_COMMAND = python \"$$VERSION_INFO_SCRIPT\" VERSION_INFO_COMMAND = python \"$$VERSION_INFO_SCRIPT\"
UAVO_DEF_PATH = $$ROOT_DIR/shared/uavobjectdefinition
# Create custom version_info target which generates a header # Create custom version_info target which generates a header
version_info.target = $$VERSION_INFO_HEADER version_info.target = $$VERSION_INFO_HEADER
version_info.commands = $$VERSION_INFO_COMMAND \ version_info.commands = $$VERSION_INFO_COMMAND \
--path=\"$$GCS_SOURCE_TREE\" \ --path=\"$$GCS_SOURCE_TREE\" \
--template=\"$$VERSION_INFO_TEMPLATE\" \ --template=\"$$VERSION_INFO_TEMPLATE\" \
--uavodir=\"$$UAVO_DEF_PATH\" \
--outfile=\"$$VERSION_INFO_HEADER\" --outfile=\"$$VERSION_INFO_HEADER\"
version_info.depends = FORCE version_info.depends = FORCE
QMAKE_EXTRA_TARGETS += version_info QMAKE_EXTRA_TARGETS += version_info

View File

@ -67,6 +67,26 @@ VersionDialog::VersionDialog(QWidget *parent)
//: This gets conditionally inserted as argument %8 into the description string. //: This gets conditionally inserted as argument %8 into the description string.
ideRev = tr("From revision %1<br/>").arg(QString::fromLatin1(GCS_REVISION_STR).left(60)); ideRev = tr("From revision %1<br/>").arg(QString::fromLatin1(GCS_REVISION_STR).left(60));
#endif #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<br/>").arg(gcsUavoHashStr);
#endif
const QString description = tr( const QString description = tr(
"<h3>OpenPilot GCS %1 %9 (%10)</h3>" "<h3>OpenPilot GCS %1 %9 (%10)</h3>"
@ -76,6 +96,8 @@ VersionDialog::VersionDialog(QWidget *parent)
"<br/>" "<br/>"
"%8" "%8"
"<br/>" "<br/>"
"%11"
"<br/>"
"Copyright 2010-%6 %7. All rights reserved.<br/>" "Copyright 2010-%6 %7. All rights reserved.<br/>"
"<br/>" "<br/>"
"<small>This program is free software; you can redistribute it and/or modify<br/>" "<small>This program is free software; you can redistribute it and/or modify<br/>"
@ -87,7 +109,7 @@ VersionDialog::VersionDialog(QWidget *parent)
"PARTICULAR PURPOSE.</small><br/>") "PARTICULAR PURPOSE.</small><br/>")
.arg(version, QLatin1String(QT_VERSION_STR), QString::number(QSysInfo::WordSize), .arg(version, QLatin1String(QT_VERSION_STR), QString::number(QSysInfo::WordSize),
QLatin1String(__DATE__), QLatin1String(__TIME__), QLatin1String(GCS_YEAR), 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); QLabel *copyRightLabel = new QLabel(description);
copyRightLabel->setWordWrap(true); copyRightLabel->setWordWrap(true);

View File

@ -46,7 +46,6 @@
#include "uavtalk/telemetrymanager.h" #include "uavtalk/telemetrymanager.h"
#include "uavobject.h" #include "uavobject.h"
#include "uavobjectmanager.h"
#include "positionactual.h" #include "positionactual.h"
#include "homelocation.h" #include "homelocation.h"
@ -590,6 +589,7 @@ void OPMapGadgetWidget::updatePosition()
VelocityActual *velocityActualObj = VelocityActual::GetInstance(obm); VelocityActual *velocityActualObj = VelocityActual::GetInstance(obm);
Gyros *gyrosObj = Gyros::GetInstance(obm); Gyros *gyrosObj = Gyros::GetInstance(obm);
Q_ASSERT(attitudeActualObj);
Q_ASSERT(positionActualObj); Q_ASSERT(positionActualObj);
Q_ASSERT(velocityActualObj); Q_ASSERT(velocityActualObj);
Q_ASSERT(gyrosObj); Q_ASSERT(gyrosObj);
@ -919,7 +919,7 @@ void OPMapGadgetWidget::setHome(QPointF pos)
/** /**
Sets the home position on the map widget 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) if (!m_widget || !m_map)
return; return;
@ -941,13 +941,13 @@ void OPMapGadgetWidget::setHome(internals::PointLatLng pos_lat_lon,double altitu
if (longitude > 180) longitude = 180; if (longitude > 180) longitude = 180;
else else
if (longitude < -180) longitude = -180; 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->SetAltitude(altitude);
m_map->Home->RefreshPos(); m_map->Home->RefreshPos();
@ -1659,7 +1659,15 @@ void OPMapGadgetWidget::onSetHomeAct_triggered()
if (!m_widget || !m_map) if (!m_widget || !m_map)
return; 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 setHomeLocationObject(); // update the HomeLocation UAVObject
} }

View File

@ -281,15 +281,7 @@ void OsgEarthItemRenderer::initScene()
//setup caching //setup caching
osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(m_model.get()); osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(m_model.get());
if (mapNode) { 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 {
qWarning() << Q_FUNC_INFO << sceneFile << " doesn't look like an osgEarth file"; qWarning() << Q_FUNC_INFO << sceneFile << " doesn't look like an osgEarth file";
} }

View File

@ -126,9 +126,6 @@ public slots:
signals: signals:
void frameReady(); void frameReady();
private slots:
void updateFBO();
private: private:
enum { FboCount = 3 }; enum { FboCount = 3 };
OsgEarthItem *m_item; OsgEarthItem *m_item;

View File

@ -92,6 +92,7 @@ plugin_uploader.subdir = uploader
plugin_uploader.depends = plugin_coreplugin plugin_uploader.depends = plugin_coreplugin
plugin_uploader.depends += plugin_uavobjects plugin_uploader.depends += plugin_uavobjects
plugin_uploader.depends += plugin_rawhid plugin_uploader.depends += plugin_rawhid
plugin_uploader.depends += plugin_uavobjectutil
SUBDIRS += plugin_uploader SUBDIRS += plugin_uploader
#Dial gadget #Dial gadget

View File

@ -8,6 +8,8 @@ public:
QString gitHash; QString gitHash;
QString gitDate; QString gitDate;
QString gitTag; QString gitTag;
QByteArray fwHash;
QByteArray uavoHash;
int boardType; int boardType;
int boardRevision; int boardRevision;
static QString idToBoardName(int id) static QString idToBoardName(int id)

View File

@ -35,7 +35,10 @@
#include <QEventLoop> #include <QEventLoop>
#include <QTimer> #include <QTimer>
#include <objectpersistence.h> #include <objectpersistence.h>
#include <firmwareiapobj.h>
#include "firmwareiapobj.h"
#include "homelocation.h"
#include "gpsposition.h"
// ****************************** // ******************************
// constructor/destructor // constructor/destructor
@ -48,6 +51,18 @@ UAVObjectUtilManager::UAVObjectUtilManager()
failureTimer.setSingleShot(true); failureTimer.setSingleShot(true);
failureTimer.setInterval(1000); failureTimer.setInterval(1000);
connect(&failureTimer, SIGNAL(timeout()),this,SLOT(objectPersistenceOperationFailed())); connect(&failureTimer, SIGNAL(timeout()),this,SLOT(objectPersistenceOperationFailed()));
pm = NULL;
obm = NULL;
obum = NULL;
pm = ExtensionSystem::PluginManager::instance();
if (pm)
{
obm = pm->getObject<UAVObjectManager>();
obum = pm->getObject<UAVObjectUtilManager>();
}
} }
UAVObjectUtilManager::~UAVObjectUtilManager() UAVObjectUtilManager::~UAVObjectUtilManager()
@ -67,10 +82,8 @@ UAVObjectUtilManager::~UAVObjectUtilManager()
UAVObjectManager* UAVObjectUtilManager::getObjectManager() { UAVObjectManager* UAVObjectUtilManager::getObjectManager() {
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); Q_ASSERT(obm);
UAVObjectManager * objMngr = pm->getObject<UAVObjectManager>(); return obm;
Q_ASSERT(objMngr);
return objMngr;
} }
@ -107,7 +120,7 @@ void UAVObjectUtilManager::saveNextObject()
// Get next object from the queue // Get next object from the queue
UAVObject* obj = queue.head(); 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<ObjectPersistence*>( getObjectManager()->getObject(ObjectPersistence::NAME) ); ObjectPersistence* objper = dynamic_cast<ObjectPersistence*>( getObjectManager()->getObject(ObjectPersistence::NAME) );
connect(objper, SIGNAL(transactionCompleted(UAVObject*,bool)), this, SLOT(objectPersistenceTransactionCompleted(UAVObject*,bool))); connect(objper, SIGNAL(transactionCompleted(UAVObject*,bool)), this, SLOT(objectPersistenceTransactionCompleted(UAVObject*,bool)));
@ -233,16 +246,7 @@ FirmwareIAPObj::DataFields UAVObjectUtilManager::getFirmwareIap()
{ {
FirmwareIAPObj::DataFields dummy; FirmwareIAPObj::DataFields dummy;
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); FirmwareIAPObj *firmwareIap = FirmwareIAPObj::GetInstance(obm);
Q_ASSERT(pm);
if (!pm)
return dummy;
UAVObjectManager *om = pm->getObject<UAVObjectManager>();
Q_ASSERT(om);
if (!om)
return dummy;
FirmwareIAPObj *firmwareIap = FirmwareIAPObj::GetInstance(om);
Q_ASSERT(firmwareIap); Q_ASSERT(firmwareIap);
if (!firmwareIap) if (!firmwareIap)
return dummy; return dummy;
@ -257,7 +261,12 @@ FirmwareIAPObj::DataFields UAVObjectUtilManager::getFirmwareIap()
int UAVObjectUtilManager::getBoardModel() int UAVObjectUtilManager::getBoardModel()
{ {
FirmwareIAPObj::DataFields firmwareIapData = getFirmwareIap(); FirmwareIAPObj::DataFields firmwareIapData = getFirmwareIap();
return (firmwareIapData.BoardType << 8) + firmwareIapData.BoardRevision; qDebug()<<"Board type="<<firmwareIapData.BoardType;
qDebug()<<"Board revision="<<firmwareIapData.BoardRevision;
int ret=firmwareIapData.BoardType <<8;
ret = ret + firmwareIapData.BoardRevision;
qDebug()<<"Board info="<<ret;
return ret;
} }
/** /**
@ -301,121 +310,47 @@ QByteArray UAVObjectUtilManager::getBoardDescription()
int UAVObjectUtilManager::setHomeLocation(double LLA[3], bool save_to_sdcard) int UAVObjectUtilManager::setHomeLocation(double LLA[3], bool save_to_sdcard)
{ {
double ECEF[3]; double Be[3];
double RNE[9];
double Be[3];
UAVObjectField *field;
QMutexLocker locker(mutex); Q_ASSERT (Utils::HomeLocationUtil().getDetails(LLA, Be) >= 0);
if (Utils::HomeLocationUtil().getDetails(LLA, ECEF, RNE, Be) < 0) // ******************
return -1; // error // save the new settings
// ****************** HomeLocation *homeLocation = HomeLocation::GetInstance(obm);
// save the new settings Q_ASSERT(homeLocation != NULL);
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); HomeLocation::DataFields homeLocationData = homeLocation->getData();
if (!pm) return -2; homeLocationData.Latitude = LLA[0] * 1e7;
homeLocationData.Longitude = LLA[1] * 1e7;
homeLocationData.Altitude = LLA[2];
UAVObjectManager *om = pm->getObject<UAVObjectManager>(); homeLocationData.Be[0] = Be[0];
if (!om) return -3; homeLocationData.Be[1] = Be[1];
homeLocationData.Be[2] = Be[2];
UAVDataObject *obj = dynamic_cast<UAVDataObject *>(om->getObject(QString("HomeLocation"))); homeLocationData.Set = HomeLocation::SET_TRUE;
if (!obj) return -4;
UAVObjectField *ECEF_field = obj->getField(QString("ECEF")); homeLocation->setData(homeLocationData);
if (!ECEF_field) return -5;
UAVObjectField *RNE_field = obj->getField(QString("RNE")); if (save_to_sdcard)
if (!RNE_field) return -6; saveObjectToSD(homeLocation);
UAVObjectField *Be_field = obj->getField(QString("Be")); return 0;
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
} }
int UAVObjectUtilManager::getHomeLocation(bool &set, double LLA[3]) 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(); set = homeLocationData.Set;
if (!pm) return -1;
UAVObjectManager *om = pm->getObject<UAVObjectManager>(); LLA[0] = homeLocationData.Latitude*1e-7;
if (!om) return -2; LLA[1] = homeLocationData.Longitude*1e-7;
LLA[2] = homeLocationData.Altitude;
UAVDataObject *obj = dynamic_cast<UAVDataObject *>(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();
if (LLA[0] != LLA[0]) LLA[0] = 0; // nan detection if (LLA[0] != LLA[0]) LLA[0] = 0; // nan detection
else else
@ -434,88 +369,20 @@ int UAVObjectUtilManager::getHomeLocation(bool &set, double LLA[3])
return 0; // OK 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<UAVObjectManager>();
if (!om) return -2;
UAVDataObject *obj = dynamic_cast<UAVDataObject *>(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 // GPS
int UAVObjectUtilManager::getGPSPosition(double LLA[3]) 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(); LLA[0] = gpsPositionData.Latitude;
if (!pm) return -1; LLA[1] = gpsPositionData.Longitude;
LLA[2] = gpsPositionData.Altitude;
UAVObjectManager *om = pm->getObject<UAVObjectManager>();
if (!om) return -2;
UAVDataObject *obj = dynamic_cast<UAVDataObject *>(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();
if (LLA[0] != LLA[0]) LLA[0] = 0; // nan detection if (LLA[0] != LLA[0]) LLA[0] = 0; // nan detection
else else
@ -534,102 +401,14 @@ int UAVObjectUtilManager::getGPSPosition(double LLA[3])
return 0; // OK 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<UAVObjectManager>();
if (!om) return -2;
UAVDataObject *obj = dynamic_cast<UAVDataObject *>(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<UAVObjectManager>();
if (!om) return -2;
UAVDataObject *obj = dynamic_cast<UAVDataObject *>(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<UAVObjectManager>();
if (!om) return -3;
UAVDataObject *obj = dynamic_cast<UAVDataObject *>(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 UAVObjectUtilManager::getBoardDescriptionStruct()
{ {
deviceDescriptorStruct ret; deviceDescriptorStruct ret;
descriptionToStructure(getBoardDescription(),&ret); descriptionToStructure(getBoardDescription(),ret);
return ret; return ret;
} }
bool UAVObjectUtilManager::descriptionToStructure(QByteArray desc, deviceDescriptorStruct *struc) bool UAVObjectUtilManager::descriptionToStructure(QByteArray desc, deviceDescriptorStruct & struc)
{ {
if (desc.startsWith("OpFw")) { if (desc.startsWith("OpFw")) {
/* /*
@ -639,9 +418,9 @@ bool UAVObjectUtilManager::descriptionToStructure(QByteArray desc, deviceDescrip
* 4 bytes: Unix timestamp of last git commit * 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. * 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 * 26 bytes: commit tag if it is there, otherwise "Unreleased". Zero-padded
* ---- 40 bytes limit ---
* 20 bytes: SHA1 sum of the firmware. * 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: // Note: the ARM binary is big-endian:
@ -650,23 +429,26 @@ bool UAVObjectUtilManager::descriptionToStructure(QByteArray desc, deviceDescrip
gitCommitHash = gitCommitHash << 8; gitCommitHash = gitCommitHash << 8;
gitCommitHash += desc.at(7-i) & 0xFF; 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; quint32 gitDate = desc.at(11) & 0xFF;
for (int i = 1; i < 4; i++) { for (int i = 1; i < 4; i++) {
gitDate = gitDate << 8; gitDate = gitDate << 8;
gitDate += desc.at(11-i) & 0xFF; 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)); QString gitTag = QString(desc.mid(14,26));
struc->gitTag = gitTag; struc.gitTag = gitTag;
// TODO: check platform compatibility // TODO: check platform compatibility
QByteArray targetPlatform = desc.mid(12,2); QByteArray targetPlatform = desc.mid(12,2);
struc->boardType = (int)targetPlatform.at(0); struc.boardType = (int)targetPlatform.at(0);
struc->boardRevision = (int)targetPlatform.at(1); 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 true;
} }
return false; return false;

View File

@ -55,20 +55,15 @@ public:
int setHomeLocation(double LLA[3], bool save_to_sdcard); int setHomeLocation(double LLA[3], bool save_to_sdcard);
int getHomeLocation(bool &set, double LLA[3]); 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 getGPSPosition(double LLA[3]);
int setTelemetrySerialPortSpeed(QString speed, bool save_to_sdcard);
int getTelemetrySerialPortSpeed(QString &speed);
int getTelemetrySerialPortSpeeds(QComboBox *comboBox);
int getBoardModel(); int getBoardModel();
QByteArray getBoardCPUSerial(); QByteArray getBoardCPUSerial();
quint32 getFirmwareCRC(); quint32 getFirmwareCRC();
QByteArray getBoardDescription(); QByteArray getBoardDescription();
deviceDescriptorStruct getBoardDescriptionStruct(); deviceDescriptorStruct getBoardDescriptionStruct();
static bool descriptionToStructure(QByteArray desc,deviceDescriptorStruct * struc); static bool descriptionToStructure(QByteArray desc,deviceDescriptorStruct & struc);
UAVObjectManager* getObjectManager(); UAVObjectManager* getObjectManager();
void saveObjectToSD(UAVObject *obj); void saveObjectToSD(UAVObject *obj);
protected: protected:
@ -78,11 +73,15 @@ signals:
void saveCompleted(int objectID, bool status); void saveCompleted(int objectID, bool status);
private: private:
QMutex *mutex; QMutex *mutex;
QQueue<UAVObject *> queue; QQueue<UAVObject *> queue;
enum {IDLE, AWAITING_ACK, AWAITING_COMPLETED} saveState; enum {IDLE, AWAITING_ACK, AWAITING_COMPLETED} saveState;
void saveNextObject(); void saveNextObject();
QTimer failureTimer; QTimer failureTimer;
ExtensionSystem::PluginManager *pm;
UAVObjectManager *obm;
UAVObjectUtilManager *obum;
private slots: private slots:
//void transactionCompleted(UAVObject *obj, bool success); //void transactionCompleted(UAVObject *obj, bool success);

View File

@ -154,7 +154,7 @@ void deviceWidget::freeze()
*/ */
bool deviceWidget::populateBoardStructuredDescription(QByteArray desc) bool deviceWidget::populateBoardStructuredDescription(QByteArray desc)
{ {
if(UAVObjectUtilManager::descriptionToStructure(desc,&onBoardDescription)) if(UAVObjectUtilManager::descriptionToStructure(desc,onBoardDescription))
{ {
myDevice->lblGitTag->setText(onBoardDescription.gitHash); myDevice->lblGitTag->setText(onBoardDescription.gitHash);
myDevice->lblBuildDate->setText(onBoardDescription.gitDate.insert(4,"-").insert(7,"-")); myDevice->lblBuildDate->setText(onBoardDescription.gitDate.insert(4,"-").insert(7,"-"));
@ -184,7 +184,7 @@ bool deviceWidget::populateBoardStructuredDescription(QByteArray desc)
} }
bool deviceWidget::populateLoadedStructuredDescription(QByteArray desc) bool deviceWidget::populateLoadedStructuredDescription(QByteArray desc)
{ {
if(UAVObjectUtilManager::descriptionToStructure(desc,&LoadedDescription)) if(UAVObjectUtilManager::descriptionToStructure(desc,LoadedDescription))
{ {
myDevice->lblGitTagL->setText(LoadedDescription.gitHash); myDevice->lblGitTagL->setText(LoadedDescription.gitHash);
myDevice->lblBuildDateL->setText( LoadedDescription.gitDate.insert(4,"-").insert(7,"-")); myDevice->lblBuildDateL->setText( LoadedDescription.gitDate.insert(4,"-").insert(7,"-"));

View File

@ -101,7 +101,7 @@ void runningDeviceWidget::populate()
QByteArray description = utilMngr->getBoardDescription(); QByteArray description = utilMngr->getBoardDescription();
deviceDescriptorStruct devDesc; deviceDescriptorStruct devDesc;
if(UAVObjectUtilManager::descriptionToStructure(description,&devDesc)) if(UAVObjectUtilManager::descriptionToStructure(description,devDesc))
{ {
if(devDesc.gitTag.startsWith("release",Qt::CaseInsensitive)) if(devDesc.gitTag.startsWith("release",Qt::CaseInsensitive))
{ {

View File

@ -650,18 +650,41 @@ void UploaderGadgetWidget::versionMatchCheck()
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
UAVObjectUtilManager *utilMngr = pm->getObject<UAVObjectUtilManager>(); UAVObjectUtilManager *utilMngr = pm->getObject<UAVObjectUtilManager>();
deviceDescriptorStruct boardDescription = utilMngr->getBoardDescriptionStruct(); 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); QByteArray fwVersion=boardDescription.uavoHash;
QString gcsGitHash = gcsDescription.mid(gcsDescription.indexOf(":")+1, 8); if (fwVersion != uavoHashArray) {
gcsGitHash.remove( QRegExp("^[0]*") );
QString gcsGitDate = gcsDescription.mid(gcsDescription.indexOf(" ")+1, 14); QString gcsDescription = QString::fromLatin1(Core::Constants::GCS_REVISION_STR);
QString gcsVersion = gcsGitDate + " (" + gcsGitHash + ")"; QString gcsGitHash = gcsDescription.mid(gcsDescription.indexOf(":")+1, 8);
QString fwVersion = boardDescription.gitDate + " (" + boardDescription.gitHash + ")"; 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( QString warning = QString(tr(
"GCS and firmware versions do not match which can cause configuration problems. " "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); "GCS version: %1 Firmware version: %2.")).arg(gcsVersion).arg(fwVersion);
msg->showMessage(warning); msg->showMessage(warning);
} }
} }

View File

@ -161,6 +161,9 @@ int main(int argc, char *argv[])
QString res = parser->parseXML(xmlstr, filename); QString res = parser->parseXML(xmlstr, filename);
if (!res.isNull()) { if (!res.isNull()) {
if (!verbose) {
cout << "Error in XML file: " << fileinfo.fileName().toStdString() << endl;
}
cout << "Error parsing " << res.toStdString() << endl; cout << "Error parsing " << res.toStdString() << endl;
return RETURN_ERR_XML; return RETURN_ERR_XML;
} }

View File

@ -213,6 +213,9 @@ QString UAVObjectParser::parseXML(QString& xml, QString& filename)
qStableSort(info->fields.begin(), info->fields.end(), fieldTypeLessThan); qStableSort(info->fields.begin(), info->fields.end(), fieldTypeLessThan);
// Make sure that required elements were found // Make sure that required elements were found
if ( !fieldFound )
return QString("Object::field element is missing");
if ( !accessFound ) if ( !accessFound )
return QString("Object::access element is missing"); return QString("Object::access element is missing");
@ -381,11 +384,38 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in
// Get name attribute // Get name attribute
QDomNamedNodeMap elemAttributes = childNode.attributes(); QDomNamedNodeMap elemAttributes = childNode.attributes();
QDomNode elemAttr = elemAttributes.namedItem("name"); QDomNode elemAttr = elemAttributes.namedItem("name");
if ( elemAttr.isNull() ) if (elemAttr.isNull()) {
return QString("Object:field:name attribute is missing"); 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 // Get units attribute
elemAttr = elemAttributes.namedItem("units"); elemAttr = elemAttributes.namedItem("units");
@ -410,6 +440,8 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in
} }
// Get numelements or elementnames attribute // Get numelements or elementnames attribute
field->numElements = 0;
// Look for element names as an attribute first
elemAttr = elemAttributes.namedItem("elementnames"); elemAttr = elemAttributes.namedItem("elementnames");
if ( !elemAttr.isNull() ) { if ( !elemAttr.isNull() ) {
// Get element names // Get element names
@ -422,9 +454,26 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in
field->defaultElementNames = false; field->defaultElementNames = false;
} }
else { 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"); elemAttr = elemAttributes.namedItem("elements");
if ( elemAttr.isNull() ) { 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 { else {
field->numElements = elemAttr.nodeValue().toInt(); field->numElements = elemAttr.nodeValue().toInt();
@ -434,19 +483,34 @@ QString UAVObjectParser::processObjectFields(QDomNode& childNode, ObjectInfo* in
field->defaultElementNames = true; 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) { if (field->type == FIELDTYPE_ENUM) {
// Get options attribute // Look for options attribute
elemAttr = elemAttributes.namedItem("options"); elemAttr = elemAttributes.namedItem("options");
if ( elemAttr.isNull() ) 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) {
QStringList options = elemAttr.nodeValue().split(",", QString::SkipEmptyParts); options[n] = options[n].trimmed();
for (int n = 0; n < options.length(); ++n) }
options[n] = options[n].trimmed(); field->options = options;
}
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) // 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"); return QString("Object:field:incorrect number of default values");
/*support legacy single default for multiple elements /*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++) for(int ct=1; ct< field->numElements; ct++)
defaults.append(defaults[0]); defaults.append(defaults[0]);
} }
field->defaultValues = defaults; field->defaultValues = defaults;
} }
// Limits attribute
elemAttr = elemAttributes.namedItem("limits"); elemAttr = elemAttributes.namedItem("limits");
if ( elemAttr.isNull() ) { if ( elemAttr.isNull() ) {
field->limitValues=QString(); field->limitValues=QString();

View File

@ -131,7 +131,8 @@ $(1).firmwareinfo.c: $(1) $(TOP)/make/templates/firmwareinfotemplate.c FORCE
--outfile=$$@ \ --outfile=$$@ \
--image=$(1) \ --image=$(1) \
--type=$(2) \ --type=$(2) \
--revision=$(3) --revision=$(3) \
--uavodir=$(TOP)/shared/uavobjectdefinition
$(eval $(call COMPILE_C_TEMPLATE, $(1).firmwareinfo.c)) $(eval $(call COMPILE_C_TEMPLATE, $(1).firmwareinfo.c))

View File

@ -250,6 +250,57 @@ def xtrim(string, suffix, length):
assert n > 0, "length of truncated string+suffix exceeds maximum length" assert n > 0, "length of truncated string+suffix exceeds maximum length"
return ''.join([string[:n], '+', suffix]) 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 <file>".
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(): def main():
"""This utility uses git repository in the current working directory """This utility uses git repository in the current working directory
or from the given path to extract some info about it and HEAD commit. 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'); help='board type, for example, 0x04 for CopterControl');
parser.add_option('--revision', default = "", parser.add_option('--revision', default = "",
help='board revision, for example, 0x01'); help='board revision, for example, 0x01');
parser.add_option('--uavodir', default = "",
help='uav object definition directory');
(args, positional_args) = parser.parse_args() (args, positional_args) = parser.parse_args()
if len(positional_args) != 0: if len(positional_args) != 0:
parser.error("incorrect number of arguments, try --help for help") parser.error("incorrect number of arguments, try --help for help")
@ -328,6 +380,7 @@ dependent targets.
BOARD_TYPE = args.type, BOARD_TYPE = args.type,
BOARD_REVISION = args.revision, BOARD_REVISION = args.revision,
SHA1 = sha1(args.image), SHA1 = sha1(args.image),
UAVOSHA1= GetHashofDirs(args.uavodir,0),
) )
if args.info: if args.info:

View File

@ -30,8 +30,6 @@
/** /**
* We have 100 bytes for the whole description. * 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: * Structure is:
* 4 bytes: header: "OpFw". * 4 bytes: header: "OpFw".
@ -39,9 +37,9 @@
* 4 bytes: Unix timestamp of compile time. * 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. * 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. * 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. * 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 board_revision;
uint8_t commit_tag_name[26]; uint8_t commit_tag_name[26];
uint8_t sha1sum[20]; 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"))) = { 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}, .board_revision = ${BOARD_REVISION},
.commit_tag_name = "${FWTAG}", .commit_tag_name = "${FWTAG}",
.sha1sum = { ${SHA1} }, .sha1sum = { ${SHA1} },
.uavosha1 = { ${UAVOSHA1} },
}; };
/** /**

View File

@ -26,7 +26,7 @@
*/ */
#define GCS_REVISION ${TAG_OR_BRANCH}:${HASH8}${DIRTY} ${DATETIME} #define GCS_REVISION ${TAG_OR_BRANCH}:${HASH8}${DIRTY} ${DATETIME}
#define UAVO_HASH "{ ${UAVOSHA1} }"
/** /**
* @} * @}
*/ */

View File

@ -2,7 +2,7 @@
<object name="FirmwareIAPObj" singleinstance="true" settings="false"> <object name="FirmwareIAPObj" singleinstance="true" settings="false">
<description>Queries board for SN, model, revision, and sends reset command</description> <description>Queries board for SN, model, revision, and sends reset command</description>
<field name="Command" units="" type="uint16" elements="1"/> <field name="Command" units="" type="uint16" elements="1"/>
<field name="Description" units="" type="uint8" elements="40"/> <field name="Description" units="" type="uint8" elements="100"/>
<field name="CPUSerial" units="" type="uint8" elements="12" /> <field name="CPUSerial" units="" type="uint8" elements="12" />
<field name="BoardRevision" units="" type="uint16" elements="1"/> <field name="BoardRevision" units="" type="uint16" elements="1"/>
<field name="BoardType" units="" type="uint8" elements="1"/> <field name="BoardType" units="" type="uint8" elements="1"/>

View File

@ -5,29 +5,76 @@
<field name="FeedForward" units="" type="float" elements="1" defaultvalue="0"/> <field name="FeedForward" units="" type="float" elements="1" defaultvalue="0"/>
<field name="AccelTime" units="ms" type="float" elements="1" defaultvalue="0"/> <field name="AccelTime" units="ms" type="float" elements="1" defaultvalue="0"/>
<field name="DecelTime" units="ms" type="float" elements="1" defaultvalue="0"/> <field name="DecelTime" units="ms" type="float" elements="1" defaultvalue="0"/>
<field name="ThrottleCurve1" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="0,0,0,0,0"/> <field name="ThrottleCurve1" units="percent" type="float" elementnames="0,25,50,75,100" defaultvalue="0,0,0,0,0"/>
<field name="Curve2Source" units="" type="enum" elements="1" options="Throttle,Roll,Pitch,Yaw,Collective,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Throttle"/> <field name="Curve2Source" units="" type="enum" elements="1" defaultvalue="Throttle">
<field name="ThrottleCurve2" units="percent" type="float" elements="5" elementnames="0,25,50,75,100" defaultvalue="0,0.25,0.5,0.75,1"/> <options>
<field name="Mixer1Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> <option>Throttle</option>
<field name="Mixer1Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> <option>Roll</option>
<field name="Mixer2Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> <option>Pitch</option>
<field name="Mixer2Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> <option>Yaw</option>
<field name="Mixer3Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> <option>Collective</option>
<field name="Mixer3Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> <option>Accessory0</option>
<field name="Mixer4Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> <option>Accessory1</option>
<field name="Mixer4Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> <option>Accessory2</option>
<field name="Mixer5Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> <option>Accessory3</option>
<field name="Mixer5Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> <option>Accessory4</option>
<field name="Mixer6Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> <option>Accessory5</option>
<field name="Mixer6Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> </options>
<field name="Mixer7Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> </field>
<field name="Mixer7Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> <field name="ThrottleCurve2" units="percent" type="float" elementnames="0,25,50,75,100" defaultvalue="0,0.25,0.5,0.75,1"/>
<field name="Mixer8Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> <field name="Mixer1Type" units="" type="enum" elements="1" defaultvalue="Disabled">
<field name="Mixer8Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> <options>
<field name="Mixer9Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> <option>Disabled</option>
<field name="Mixer9Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> <option>Motor</option>
<field name="Mixer10Type" units="" type="enum" elements="1" options="Disabled,Motor,Servo,CameraRoll,CameraPitch,CameraYaw,Accessory0,Accessory1,Accessory2,Accessory3,Accessory4,Accessory5" defaultvalue="Disabled"/> <option>Servo</option>
<field name="Mixer10Vector" units="" type="int8" elements="5" elementnames="ThrottleCurve1,ThrottleCurve2,Roll,Pitch,Yaw" defaultvalue="0"/> <option>CameraRoll</option>
<option>CameraPitch</option>
<option>CameraYaw</option>
<option>Accessory0</option>
<option>Accessory1</option>
<option>Accessory2</option>
<option>Accessory3</option>
<option>Accessory4</option>
<option>Accessory5</option>
</options>
</field>
<field name="Mixer1Vector" units="" type="int8" defaultvalue="0">
<elementnames>
<elementname>ThrottleCurve1</elementname>
<elementname>ThrottleCurve2</elementname>
<elementname>Roll</elementname>
<elementname>Pitch</elementname>
<elementname>Yaw</elementname>
</elementnames>
</field>
<field name="Mixer2Type" cloneof="Mixer1Type"/>
<field name="Mixer2Vector" cloneof="Mixer1Vector"/>
<field name="Mixer3Type" cloneof="Mixer1Type"/>
<field name="Mixer3Vector" cloneof="Mixer1Vector"/>
<field name="Mixer4Type" cloneof="Mixer1Type"/>
<field name="Mixer4Vector" cloneof="Mixer1Vector"/>
<field name="Mixer5Type" cloneof="Mixer1Type"/>
<field name="Mixer5Vector" cloneof="Mixer1Vector"/>
<field name="Mixer6Type" cloneof="Mixer1Type"/>
<field name="Mixer6Vector" cloneof="Mixer1Vector"/>
<field name="Mixer7Type" cloneof="Mixer1Type"/>
<field name="Mixer7Vector" cloneof="Mixer1Vector"/>
<field name="Mixer8Type" cloneof="Mixer1Type"/>
<field name="Mixer8Vector" cloneof="Mixer1Vector"/>
<field name="Mixer9Type" cloneof="Mixer1Type"/>
<field name="Mixer9Vector" cloneof="Mixer1Vector"/>
<field name="Mixer10Type" cloneof="Mixer1Type"/>
<field name="Mixer10Vector" cloneof="Mixer1Vector"/>
<access gcs="readwrite" flight="readwrite"/> <access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="true" updatemode="onchange" period="0"/> <telemetrygcs acked="true" updatemode="onchange" period="0"/>
<telemetryflight acked="true" updatemode="onchange" period="0"/> <telemetryflight acked="true" updatemode="onchange" period="0"/>

View File

@ -1,9 +1,79 @@
<xml> <xml>
<object name="TaskInfo" singleinstance="true" settings="false"> <object name="TaskInfo" singleinstance="true" settings="false">
<description>Task information</description> <description>Task information</description>
<field name="StackRemaining" units="bytes" type="uint16" elementnames="System,Actuator,Attitude,Sensors,TelemetryTx,TelemetryTxPri,TelemetryRx,GPS,ManualControl,Altitude,Stabilization,AltitudeHold,Guidance,FlightPlan,Com2UsbBridge,Usb2ComBridge,OveroSync,Autotune,EventDispatcher"/> <field name="StackRemaining" units="bytes" type="uint16">
<field name="Running" units="bool" type="enum" options="False,True" elementnames="System,Actuator,Attitude,Sensors,TelemetryTx,TelemetryTxPri,TelemetryRx,GPS,ManualControl,Altitude,Stabilization,AltitudeHold,Guidance,FlightPlan,Com2UsbBridge,Usb2ComBridge,OveroSync,Autotune,EventDispatcher"/> <elementnames>
<field name="RunningTime" units="%" type="uint8" elementnames="System,Actuator,Attitude,Sensors,TelemetryTx,TelemetryTxPri,TelemetryRx,GPS,ManualControl,Altitude,Stabilization,AltitudeHold,Guidance,FlightPlan,Com2UsbBridge,Usb2ComBridge,OveroSync,Autotune,EventDispatcher"/> <elementname>System</elementname>
<elementname>Actuator</elementname>
<elementname>Attitude</elementname>
<elementname>Sensors</elementname>
<elementname>TelemetryTx</elementname>
<elementname>TelemetryTxPri</elementname>
<elementname>TelemetryRx</elementname>
<elementname>GPS</elementname>
<elementname>ManualControl</elementname>
<elementname>Altitude</elementname>
<elementname>Stabilization</elementname>
<elementname>AltitudeHold</elementname>
<elementname>Guidance</elementname>
<elementname>FlightPlan</elementname>
<elementname>Com2UsbBridge</elementname>
<elementname>Usb2ComBridge</elementname>
<elementname>OveroSync</elementname>
<elementname>Autotune</elementname>
<elementname>EventDispatcher</elementname>
</elementnames>
</field>
<field name="Running" units="bool" type="enum">
<elementnames>
<elementname>System</elementname>
<elementname>Actuator</elementname>
<elementname>Attitude</elementname>
<elementname>Sensors</elementname>
<elementname>TelemetryTx</elementname>
<elementname>TelemetryTxPri</elementname>
<elementname>TelemetryRx</elementname>
<elementname>GPS</elementname>
<elementname>ManualControl</elementname>
<elementname>Altitude</elementname>
<elementname>Stabilization</elementname>
<elementname>AltitudeHold</elementname>
<elementname>Guidance</elementname>
<elementname>FlightPlan</elementname>
<elementname>Com2UsbBridge</elementname>
<elementname>Usb2ComBridge</elementname>
<elementname>OveroSync</elementname>
<elementname>Autotune</elementname>
<elementname>EventDispatcher</elementname>
</elementnames>
<options>
<option>False</option>
<option>True</option>
</options>
</field>
<field name="RunningTime" units="%" type="uint8">
<elementnames>
<elementname>System</elementname>
<elementname>Actuator</elementname>
<elementname>Attitude</elementname>
<elementname>Sensors</elementname>
<elementname>TelemetryTx</elementname>
<elementname>TelemetryTxPri</elementname>
<elementname>TelemetryRx</elementname>
<elementname>GPS</elementname>
<elementname>ManualControl</elementname>
<elementname>Altitude</elementname>
<elementname>Stabilization</elementname>
<elementname>AltitudeHold</elementname>
<elementname>Guidance</elementname>
<elementname>FlightPlan</elementname>
<elementname>Com2UsbBridge</elementname>
<elementname>Usb2ComBridge</elementname>
<elementname>OveroSync</elementname>
<elementname>Autotune</elementname>
<elementname>EventDispatcher</elementname>
</elementnames>
</field>
<access gcs="readwrite" flight="readwrite"/> <access gcs="readwrite" flight="readwrite"/>
<telemetrygcs acked="true" updatemode="onchange" period="0"/> <telemetrygcs acked="true" updatemode="onchange" period="0"/>
<telemetryflight acked="true" updatemode="periodic" period="10000"/> <telemetryflight acked="true" updatemode="periodic" period="10000"/>