2013-04-05 22:46:56 +02:00
|
|
|
/**
|
|
|
|
******************************************************************************
|
|
|
|
*
|
|
|
|
* @file uavobject.cpp
|
|
|
|
* @author The OpenPilot Team, http://www.openpilot.org Copyright (C) 2010.
|
|
|
|
* @see The GNU Public License (GPL) Version 3
|
|
|
|
* @addtogroup GCSPlugins GCS Plugins
|
|
|
|
* @{
|
|
|
|
* @addtogroup UAVObjectsPlugin UAVObjects Plugin
|
|
|
|
* @{
|
|
|
|
* @brief The UAVUObjects GCS plugin
|
|
|
|
*****************************************************************************/
|
|
|
|
/*
|
2013-05-19 16:37:30 +02:00
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2013-04-05 22:46:56 +02:00
|
|
|
* (at your option) any later version.
|
2013-05-19 16:37:30 +02:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
2013-04-05 22:46:56 +02:00
|
|
|
* for more details.
|
2013-05-19 16:37:30 +02:00
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
2013-04-05 22:46:56 +02:00
|
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
#include "uavobject.h"
|
2014-01-12 15:08:12 +01:00
|
|
|
|
|
|
|
#include <utils/crc.h>
|
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
#include <QtEndian>
|
|
|
|
#include <QDebug>
|
2014-09-15 22:46:28 +02:00
|
|
|
#include <QtWidgets>
|
2013-04-05 22:46:56 +02:00
|
|
|
|
2014-01-12 15:08:12 +01:00
|
|
|
using namespace Utils;
|
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
// Constants
|
2013-05-19 16:37:30 +02:00
|
|
|
#define UAVOBJ_ACCESS_SHIFT 0
|
|
|
|
#define UAVOBJ_GCS_ACCESS_SHIFT 1
|
|
|
|
#define UAVOBJ_TELEMETRY_ACKED_SHIFT 2
|
|
|
|
#define UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT 3
|
|
|
|
#define UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT 4
|
2013-04-05 22:46:56 +02:00
|
|
|
#define UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT 6
|
2013-11-17 14:00:42 +01:00
|
|
|
#define UAVOBJ_LOGGING_UPDATE_MODE_SHIFT 8
|
2013-05-19 16:37:30 +02:00
|
|
|
#define UAVOBJ_UPDATE_MODE_MASK 0x3
|
2013-04-05 22:46:56 +02:00
|
|
|
|
|
|
|
// Macros
|
2013-05-19 16:37:30 +02:00
|
|
|
#define SET_BITS(var, shift, value, mask) var = (var & ~(mask << shift)) | (value << shift);
|
2013-04-05 22:46:56 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor
|
|
|
|
* @param objID The object ID
|
|
|
|
* @param isSingleInst True if this object can only have a single instance
|
|
|
|
* @param name Object name
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
UAVObject::UAVObject(quint32 objID, bool isSingleInst, const QString & name)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
2014-01-14 22:46:01 +01:00
|
|
|
this->objID = objID;
|
|
|
|
this->instID = 0;
|
2013-04-05 22:46:56 +02:00
|
|
|
this->isSingleInst = isSingleInst;
|
2014-01-14 22:46:01 +01:00
|
|
|
this->name = name;
|
|
|
|
this->data = 0;
|
|
|
|
this->numBytes = 0;
|
|
|
|
this->mutex = new QMutex(QMutex::Recursive);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize object with its instance ID
|
|
|
|
*/
|
|
|
|
void UAVObject::initialize(quint32 instID)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
2013-05-19 16:37:30 +02:00
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
this->instID = instID;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize objects' data fields
|
|
|
|
* @param fields List of fields held by the object
|
|
|
|
* @param data Pointer to that actual object data, this is needed by the fields to access the data
|
|
|
|
* @param numBytes Number of bytes in the object (total, including all fields)
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::initializeFields(QList<UAVObjectField *> & fields, quint8 *data, quint32 numBytes)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
2013-05-19 16:37:30 +02:00
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
this->numBytes = numBytes;
|
2013-05-19 16:37:30 +02:00
|
|
|
this->data = data;
|
|
|
|
this->fields = fields;
|
2013-04-05 22:46:56 +02:00
|
|
|
// Initialize fields
|
|
|
|
quint32 offset = 0;
|
2013-05-19 16:37:30 +02:00
|
|
|
for (int n = 0; n < fields.length(); ++n) {
|
2013-04-05 22:46:56 +02:00
|
|
|
fields[n]->initialize(data, offset, this);
|
|
|
|
offset += fields[n]->getNumBytes();
|
2013-05-19 16:37:30 +02:00
|
|
|
connect(fields[n], SIGNAL(fieldUpdated(UAVObjectField *)), this, SLOT(fieldUpdated(UAVObjectField *)));
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called from the fields each time they are updated
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::fieldUpdated(UAVObjectField *field)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
Q_UNUSED(field);
|
2013-05-19 16:37:30 +02:00
|
|
|
// emit objectUpdatedAuto(this); // trigger object updated event
|
|
|
|
// emit objectUpdated(this);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the object ID
|
|
|
|
*/
|
|
|
|
quint32 UAVObject::getObjID()
|
|
|
|
{
|
|
|
|
return objID;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the instance ID
|
|
|
|
*/
|
|
|
|
quint32 UAVObject::getInstID()
|
|
|
|
{
|
|
|
|
return instID;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns true if this is a single instance object
|
|
|
|
*/
|
|
|
|
bool UAVObject::isSingleInstance()
|
|
|
|
{
|
|
|
|
return isSingleInst;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the name of the object
|
|
|
|
*/
|
|
|
|
QString UAVObject::getName()
|
|
|
|
{
|
|
|
|
return name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the description of the object
|
|
|
|
*/
|
|
|
|
QString UAVObject::getDescription()
|
|
|
|
{
|
|
|
|
return description;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the description of the object
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::setDescription(const QString & description)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
this->description = description;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the category of the object
|
|
|
|
*/
|
|
|
|
QString UAVObject::getCategory()
|
|
|
|
{
|
|
|
|
return category;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the category of the object
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::setCategory(const QString & category)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
this->category = category;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the total number of bytes of the object's data
|
|
|
|
*/
|
|
|
|
quint32 UAVObject::getNumBytes()
|
|
|
|
{
|
|
|
|
return numBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Request that this object is updated with the latest values from the autopilot
|
|
|
|
*/
|
|
|
|
void UAVObject::requestUpdate()
|
|
|
|
{
|
|
|
|
emit updateRequested(this);
|
|
|
|
}
|
|
|
|
|
2013-12-01 19:25:44 +01:00
|
|
|
/**
|
|
|
|
* Request that all instances of this object are updated with the latest values from the autopilot
|
|
|
|
* Must be called on instance zero
|
|
|
|
*/
|
|
|
|
void UAVObject::requestUpdateAll()
|
|
|
|
{
|
|
|
|
if (instID == 0) {
|
|
|
|
emit updateRequested(this, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
/**
|
|
|
|
* Signal that the object has been updated
|
|
|
|
*/
|
|
|
|
void UAVObject::updated()
|
|
|
|
{
|
|
|
|
emit objectUpdatedManual(this);
|
|
|
|
emit objectUpdated(this);
|
|
|
|
}
|
|
|
|
|
2013-12-01 19:25:44 +01:00
|
|
|
/**
|
|
|
|
* Signal that all instance of the object have been updated
|
|
|
|
* Must be called on instance zero
|
|
|
|
*/
|
|
|
|
void UAVObject::updatedAll()
|
|
|
|
{
|
|
|
|
if (instID == 0) {
|
|
|
|
emit objectUpdatedManual(this, true);
|
|
|
|
// TODO call objectUpdated() for all instances?
|
2014-01-14 22:46:01 +01:00
|
|
|
// emit objectUpdated(this);
|
2013-12-01 19:25:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
/**
|
|
|
|
* Lock mutex of this object
|
|
|
|
*/
|
|
|
|
void UAVObject::lock()
|
|
|
|
{
|
|
|
|
mutex->lock();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Lock mutex of this object
|
|
|
|
*/
|
|
|
|
void UAVObject::lock(int timeoutMs)
|
|
|
|
{
|
|
|
|
mutex->tryLock(timeoutMs);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unlock mutex of this object
|
|
|
|
*/
|
|
|
|
void UAVObject::unlock()
|
|
|
|
{
|
|
|
|
mutex->unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get object's mutex
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
QMutex *UAVObject::getMutex()
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
return mutex;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the number of fields held by this object
|
|
|
|
*/
|
|
|
|
qint32 UAVObject::getNumFields()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
2013-05-19 16:37:30 +02:00
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
return fields.count();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the object's fields
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
QList<UAVObjectField *> UAVObject::getFields()
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
2013-05-19 16:37:30 +02:00
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
return fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a specific field
|
|
|
|
* @returns The field or NULL if not found
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
UAVObjectField *UAVObject::getField(const QString & name)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
2013-05-19 16:37:30 +02:00
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
// Look for field
|
2013-05-19 16:37:30 +02:00
|
|
|
for (int n = 0; n < fields.length(); ++n) {
|
|
|
|
if (name.compare(fields[n]->getName()) == 0) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return fields[n];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If this point is reached then the field was not found
|
2014-01-12 15:08:12 +01:00
|
|
|
qWarning() << "UAVObject::getField Non existant field" << name << "requested."
|
2014-01-14 22:46:01 +01:00
|
|
|
<< "This indicates a bug. Make sure you also have null checking for non-debug code.";
|
2013-04-05 22:46:56 +02:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Pack the object data into a byte array
|
|
|
|
* @returns The number of bytes copied
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
qint32 UAVObject::pack(quint8 *dataOut)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
|
|
|
qint32 offset = 0;
|
2013-05-19 16:37:30 +02:00
|
|
|
|
|
|
|
for (int n = 0; n < fields.length(); ++n) {
|
2013-04-05 22:46:56 +02:00
|
|
|
fields[n]->pack(&dataOut[offset]);
|
|
|
|
offset += fields[n]->getNumBytes();
|
|
|
|
}
|
|
|
|
return numBytes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unpack the object data from a byte array
|
|
|
|
* @returns The number of bytes copied
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
qint32 UAVObject::unpack(const quint8 *dataIn)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
|
|
|
qint32 offset = 0;
|
2013-05-19 16:37:30 +02:00
|
|
|
|
|
|
|
for (int n = 0; n < fields.length(); ++n) {
|
2013-04-05 22:46:56 +02:00
|
|
|
fields[n]->unpack(&dataIn[offset]);
|
|
|
|
offset += fields[n]->getNumBytes();
|
|
|
|
}
|
|
|
|
emit objectUnpacked(this); // trigger object updated event
|
|
|
|
emit objectUpdated(this);
|
|
|
|
|
|
|
|
return numBytes;
|
|
|
|
}
|
|
|
|
|
2014-01-12 15:08:12 +01:00
|
|
|
/**
|
|
|
|
* Update a CRC with the object data
|
|
|
|
* @returns The updated CRC
|
|
|
|
*/
|
|
|
|
quint8 UAVObject::updateCRC(quint8 crc)
|
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
|
|
|
|
2014-01-14 22:46:01 +01:00
|
|
|
// crc = Crc::updateCRC(crc, (quint8 *) &objID, sizeof(objID));
|
|
|
|
// crc = Crc::updateCRC(crc, (quint8 *) &instID, sizeof(instID));
|
2014-01-12 15:08:12 +01:00
|
|
|
crc = Crc::updateCRC(crc, data, numBytes);
|
|
|
|
|
|
|
|
return crc;
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
/**
|
|
|
|
* Save the object data to the file.
|
|
|
|
* The file will be created in the current directory
|
|
|
|
* and its name will be the same as the object with
|
|
|
|
* the .uavobj extension.
|
|
|
|
* @returns True on success, false on failure
|
|
|
|
*/
|
|
|
|
bool UAVObject::save()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
|
|
|
|
|
|
|
// Open file
|
|
|
|
QFile file(name + ".uavobj");
|
2013-05-19 16:37:30 +02:00
|
|
|
|
|
|
|
if (!file.open(QFile::WriteOnly)) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write object
|
2013-05-19 16:37:30 +02:00
|
|
|
if (!save(file)) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close file
|
|
|
|
file.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Save the object data to the file.
|
|
|
|
* The file is expected to be already open for writting.
|
|
|
|
* The data will be appended and the file will not be closed.
|
|
|
|
* @returns True on success, false on failure
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
bool UAVObject::save(QFile & file)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
|
|
|
quint8 buffer[numBytes];
|
|
|
|
quint8 tmpId[4];
|
|
|
|
|
|
|
|
// Write the object ID
|
|
|
|
qToLittleEndian<quint32>(objID, tmpId);
|
2013-05-19 16:37:30 +02:00
|
|
|
if (file.write((const char *)tmpId, 4) == -1) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the instance ID
|
2013-05-19 16:37:30 +02:00
|
|
|
if (!isSingleInst) {
|
2013-04-05 22:46:56 +02:00
|
|
|
qToLittleEndian<quint16>(instID, tmpId);
|
2013-05-19 16:37:30 +02:00
|
|
|
if (file.write((const char *)tmpId, 2) == -1) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write the data
|
|
|
|
pack(buffer);
|
2013-05-19 16:37:30 +02:00
|
|
|
if (file.write((const char *)buffer, numBytes) == -1) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Done
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Load the object data from a file.
|
|
|
|
* The file will be openned in the current directory
|
|
|
|
* and its name will be the same as the object with
|
|
|
|
* the .uavobj extension.
|
|
|
|
* @returns True on success, false on failure
|
|
|
|
*/
|
|
|
|
bool UAVObject::load()
|
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
|
|
|
|
|
|
|
// Open file
|
|
|
|
QFile file(name + ".uavobj");
|
2013-05-19 16:37:30 +02:00
|
|
|
|
|
|
|
if (!file.open(QFile::ReadOnly)) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load object
|
2013-05-19 16:37:30 +02:00
|
|
|
if (!load(file)) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close file
|
|
|
|
file.close();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Load the object data from file.
|
|
|
|
* The file is expected to be already open for reading.
|
|
|
|
* The data will be read and the file will not be closed.
|
|
|
|
* @returns True on success, false on failure
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
bool UAVObject::load(QFile & file)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
QMutexLocker locker(mutex);
|
|
|
|
quint8 buffer[numBytes];
|
|
|
|
quint8 tmpId[4];
|
|
|
|
|
|
|
|
// Read the object ID
|
2013-05-19 16:37:30 +02:00
|
|
|
if (file.read((char *)tmpId, 4) != 4) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the IDs match
|
2013-05-19 16:37:30 +02:00
|
|
|
if (qFromLittleEndian<quint32>(tmpId) != objID) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the instance ID
|
2013-05-19 16:37:30 +02:00
|
|
|
if (file.read((char *)tmpId, 2) != 2) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check that the IDs match
|
2013-05-19 16:37:30 +02:00
|
|
|
if (qFromLittleEndian<quint16>(tmpId) != instID) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read and unpack the data
|
2013-05-19 16:37:30 +02:00
|
|
|
if (file.read((char *)buffer, numBytes) != numBytes) {
|
2013-04-05 22:46:56 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
unpack(buffer);
|
|
|
|
|
|
|
|
// Done
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a string with the object information
|
|
|
|
*/
|
|
|
|
QString UAVObject::toString()
|
|
|
|
{
|
|
|
|
QString sout;
|
2013-05-19 16:37:30 +02:00
|
|
|
|
|
|
|
sout.append(toStringBrief());
|
2013-11-26 01:27:25 +01:00
|
|
|
sout.append('\n');
|
2013-05-19 16:37:30 +02:00
|
|
|
sout.append(toStringData());
|
2013-04-05 22:46:56 +02:00
|
|
|
return sout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a string with the object information (only the header)
|
|
|
|
*/
|
|
|
|
QString UAVObject::toStringBrief()
|
|
|
|
{
|
|
|
|
QString sout;
|
2013-05-19 16:37:30 +02:00
|
|
|
|
2014-01-07 21:55:26 +01:00
|
|
|
// object Id is converted to uppercase hexadecimal
|
2013-11-29 19:40:10 +01:00
|
|
|
sout.append(QString("%1 (ID: %2-%3, %4 bytes, %5)")
|
2013-05-19 16:37:30 +02:00
|
|
|
.arg(getName())
|
2014-01-07 21:55:26 +01:00
|
|
|
.arg(getObjID(), 1, 16).toUpper()
|
2013-05-19 16:37:30 +02:00
|
|
|
.arg(getInstID())
|
|
|
|
.arg(getNumBytes())
|
2013-11-26 01:27:25 +01:00
|
|
|
.arg(isSingleInstance() ? "single" : "multiple"));
|
2013-04-05 22:46:56 +02:00
|
|
|
return sout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a string with the object information (only the data)
|
|
|
|
*/
|
|
|
|
QString UAVObject::toStringData()
|
|
|
|
{
|
|
|
|
QString sout;
|
2013-05-19 16:37:30 +02:00
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
sout.append("Data:\n");
|
2013-05-19 16:37:30 +02:00
|
|
|
for (int n = 0; n < fields.length(); ++n) {
|
|
|
|
sout.append(QString("\t%1").arg(fields[n]->toString()));
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
return sout;
|
|
|
|
}
|
|
|
|
|
2014-03-08 10:50:32 +01:00
|
|
|
void UAVObject::toXML(QXmlStreamWriter *xmlWriter)
|
|
|
|
{
|
|
|
|
xmlWriter->writeStartElement("object");
|
|
|
|
xmlWriter->writeAttribute("name", getName());
|
2014-09-15 22:46:28 +02:00
|
|
|
xmlWriter->writeAttribute("id", QString("%1").arg(getObjID(), 1, 16).toUpper());
|
|
|
|
xmlWriter->writeAttribute("instance", QString("%1").arg(getInstID()));
|
2014-03-08 10:50:32 +01:00
|
|
|
xmlWriter->writeStartElement("fields");
|
2014-03-09 10:41:21 +01:00
|
|
|
foreach(UAVObjectField * field, fields) {
|
2014-03-08 10:50:32 +01:00
|
|
|
field->toXML(xmlWriter);
|
|
|
|
}
|
|
|
|
xmlWriter->writeEndElement(); // fields
|
|
|
|
xmlWriter->writeEndElement(); // object
|
|
|
|
}
|
|
|
|
|
2014-09-08 22:27:02 +02:00
|
|
|
void UAVObject::fromXML(QXmlStreamReader *xmlReader)
|
|
|
|
{
|
2014-09-15 22:46:28 +02:00
|
|
|
// Check that we are the correct object by name, and that we are the same instance id
|
|
|
|
// but dont check id since we want to be able to be forward compatible.
|
2014-09-16 23:44:23 +02:00
|
|
|
if (xmlReader->name() == "object" &&
|
|
|
|
xmlReader->attributes().value("name") == getName() &&
|
|
|
|
xmlReader->attributes().value("instance") == QString("%1").arg(getInstID())) {
|
|
|
|
QXmlStreamReader::TokenType token = xmlReader->readNext();
|
|
|
|
if (token == QXmlStreamReader::StartElement && xmlReader->name() == "fields") {
|
|
|
|
while (xmlReader->readNextStartElement()) {
|
|
|
|
if (xmlReader->name() == "field") {
|
|
|
|
QStringRef fieldName = xmlReader->attributes().value("name");
|
|
|
|
if (fieldName != "") {
|
|
|
|
getField(*fieldName.string())->fromXML(xmlReader);
|
|
|
|
}
|
2014-09-15 22:46:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-09-08 22:27:02 +02:00
|
|
|
}
|
|
|
|
|
2014-09-15 22:46:28 +02:00
|
|
|
void UAVObject::toJson(QJsonObject &jsonObject)
|
2014-09-08 22:27:02 +02:00
|
|
|
{
|
2014-09-16 23:44:23 +02:00
|
|
|
jsonObject["name"] = getName();
|
|
|
|
jsonObject["setting"] = isSettingsObject();
|
2014-09-15 22:46:28 +02:00
|
|
|
jsonObject["id"] = QString("%1").arg(getObjID(), 1, 16).toUpper();
|
|
|
|
jsonObject["instance"] = (int)getInstID();
|
|
|
|
QJsonArray jSonFields;
|
|
|
|
foreach(UAVObjectField * field, fields) {
|
|
|
|
QJsonObject jSonField;
|
2014-09-16 23:44:23 +02:00
|
|
|
|
2014-09-15 22:46:28 +02:00
|
|
|
field->toJson(jSonField);
|
|
|
|
jSonFields.append(jSonField);
|
|
|
|
}
|
|
|
|
jsonObject["fields"] = jSonFields;
|
2014-09-08 22:27:02 +02:00
|
|
|
}
|
|
|
|
|
2014-09-15 22:46:28 +02:00
|
|
|
void UAVObject::fromJson(const QJsonObject &jsonObject)
|
2014-09-08 22:27:02 +02:00
|
|
|
{
|
2014-09-16 23:44:23 +02:00
|
|
|
if (jsonObject["name"].toString() == getName() &&
|
|
|
|
jsonObject["instance"].toInt() == (int)getInstID()) {
|
|
|
|
QJsonArray jsonFields = jsonObject["fields"].toArray();
|
|
|
|
for (int i = 0; i < jsonFields.size(); i++) {
|
|
|
|
QJsonObject jsonField = jsonFields.at(i).toObject();
|
|
|
|
UAVObjectField *field = getField(jsonField["name"].toString());
|
|
|
|
if (field != NULL) {
|
|
|
|
field->fromJson(jsonField);
|
|
|
|
}
|
2014-09-15 22:46:28 +02:00
|
|
|
}
|
2014-09-16 23:44:23 +02:00
|
|
|
updated();
|
2014-09-15 22:46:28 +02:00
|
|
|
}
|
2014-09-08 22:27:02 +02:00
|
|
|
}
|
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
/**
|
|
|
|
* Emit the transactionCompleted event (used by the UAVTalk plugin)
|
|
|
|
*/
|
|
|
|
void UAVObject::emitTransactionCompleted(bool success)
|
|
|
|
{
|
|
|
|
emit transactionCompleted(this, success);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Emit the newInstance event
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::emitNewInstance(UAVObject *obj)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
|
|
|
emit newInstance(obj);
|
|
|
|
}
|
|
|
|
|
2014-03-06 00:41:48 +01:00
|
|
|
bool UAVObject::isSettingsObject()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UAVObject::isDataObject()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool UAVObject::isMetaDataObject()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-04-05 22:46:56 +02:00
|
|
|
/**
|
|
|
|
* Initialize a UAVObjMetadata object.
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::MetadataInitialize(UAVObject::Metadata & metadata)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
2013-05-19 16:37:30 +02:00
|
|
|
metadata.flags =
|
|
|
|
ACCESS_READWRITE << UAVOBJ_ACCESS_SHIFT |
|
|
|
|
ACCESS_READWRITE << UAVOBJ_GCS_ACCESS_SHIFT |
|
|
|
|
1 << UAVOBJ_TELEMETRY_ACKED_SHIFT |
|
|
|
|
1 << UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT |
|
|
|
|
UPDATEMODE_ONCHANGE << UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT |
|
2013-11-17 14:00:42 +01:00
|
|
|
UPDATEMODE_ONCHANGE << UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT |
|
|
|
|
UPDATEMODE_ONCHANGE << UAVOBJ_LOGGING_UPDATE_MODE_SHIFT;
|
2013-05-19 16:37:30 +02:00
|
|
|
metadata.flightTelemetryUpdatePeriod = 0;
|
|
|
|
metadata.gcsTelemetryUpdatePeriod = 0;
|
|
|
|
metadata.loggingUpdatePeriod = 0;
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the UAVObject metadata access member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \return the access type
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
UAVObject::AccessMode UAVObject::GetFlightAccess(const UAVObject::Metadata & metadata)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
2013-05-19 16:37:30 +02:00
|
|
|
return UAVObject::AccessMode((metadata.flags >> UAVOBJ_ACCESS_SHIFT) & 1);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the UAVObject metadata access member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \param[in] mode The access mode
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::SetFlightAccess(UAVObject::Metadata & metadata, UAVObject::AccessMode mode)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
2013-05-19 16:37:30 +02:00
|
|
|
SET_BITS(metadata.flags, UAVOBJ_ACCESS_SHIFT, mode, 1);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the UAVObject metadata GCS access member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \return the GCS access type
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
UAVObject::AccessMode UAVObject::GetGcsAccess(const UAVObject::Metadata & metadata)
|
2013-04-05 22:46:56 +02:00
|
|
|
{
|
2013-05-19 16:37:30 +02:00
|
|
|
return UAVObject::AccessMode((metadata.flags >> UAVOBJ_GCS_ACCESS_SHIFT) & 1);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the UAVObject metadata GCS access member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \param[in] mode The access mode
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::SetGcsAccess(UAVObject::Metadata & metadata, UAVObject::AccessMode mode)
|
|
|
|
{
|
|
|
|
SET_BITS(metadata.flags, UAVOBJ_GCS_ACCESS_SHIFT, mode, 1);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the UAVObject metadata telemetry acked member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \return the telemetry acked boolean
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
quint8 UAVObject::GetFlightTelemetryAcked(const UAVObject::Metadata & metadata)
|
|
|
|
{
|
|
|
|
return (metadata.flags >> UAVOBJ_TELEMETRY_ACKED_SHIFT) & 1;
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the UAVObject metadata telemetry acked member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \param[in] val The telemetry acked boolean
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::SetFlightTelemetryAcked(UAVObject::Metadata & metadata, quint8 val)
|
|
|
|
{
|
|
|
|
SET_BITS(metadata.flags, UAVOBJ_TELEMETRY_ACKED_SHIFT, val, 1);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the UAVObject metadata GCS telemetry acked member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \return the telemetry acked boolean
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
quint8 UAVObject::GetGcsTelemetryAcked(const UAVObject::Metadata & metadata)
|
|
|
|
{
|
|
|
|
return (metadata.flags >> UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT) & 1;
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the UAVObject metadata GCS telemetry acked member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \param[in] val The GCS telemetry acked boolean
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::SetGcsTelemetryAcked(UAVObject::Metadata & metadata, quint8 val)
|
|
|
|
{
|
|
|
|
SET_BITS(metadata.flags, UAVOBJ_GCS_TELEMETRY_ACKED_SHIFT, val, 1);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the UAVObject metadata telemetry update mode
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \return the telemetry update mode
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
UAVObject::UpdateMode UAVObject::GetFlightTelemetryUpdateMode(const UAVObject::Metadata & metadata)
|
|
|
|
{
|
|
|
|
return UAVObject::UpdateMode((metadata.flags >> UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT) & UAVOBJ_UPDATE_MODE_MASK);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the UAVObject metadata telemetry update mode member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \param[in] val The telemetry update mode
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::SetFlightTelemetryUpdateMode(UAVObject::Metadata & metadata, UAVObject::UpdateMode val)
|
|
|
|
{
|
|
|
|
SET_BITS(metadata.flags, UAVOBJ_TELEMETRY_UPDATE_MODE_SHIFT, val, UAVOBJ_UPDATE_MODE_MASK);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the UAVObject metadata GCS telemetry update mode
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \return the GCS telemetry update mode
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
UAVObject::UpdateMode UAVObject::GetGcsTelemetryUpdateMode(const UAVObject::Metadata & metadata)
|
|
|
|
{
|
|
|
|
return UAVObject::UpdateMode((metadata.flags >> UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT) & UAVOBJ_UPDATE_MODE_MASK);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the UAVObject metadata GCS telemetry update mode member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \param[in] val The GCS telemetry update mode
|
|
|
|
*/
|
2013-05-19 16:37:30 +02:00
|
|
|
void UAVObject::SetGcsTelemetryUpdateMode(UAVObject::Metadata & metadata, UAVObject::UpdateMode val)
|
|
|
|
{
|
|
|
|
SET_BITS(metadata.flags, UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT, val, UAVOBJ_UPDATE_MODE_MASK);
|
2013-04-05 22:46:56 +02:00
|
|
|
}
|
2014-03-19 17:08:33 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the UAVObject metadata logging update mode
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \return the logging update mode
|
|
|
|
*/
|
|
|
|
UAVObject::UpdateMode UAVObject::GetLoggingUpdateMode(const UAVObject::Metadata & metadata)
|
|
|
|
{
|
|
|
|
return UAVObject::UpdateMode((metadata.flags >> UAVOBJ_LOGGING_UPDATE_MODE_SHIFT) & UAVOBJ_UPDATE_MODE_MASK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set the UAVObject metadata logging update mode member
|
|
|
|
* \param[in] metadata The metadata object
|
|
|
|
* \param[in] val The logging update mode
|
|
|
|
*/
|
|
|
|
void UAVObject::SetLoggingUpdateMode(UAVObject::Metadata & metadata, UAVObject::UpdateMode val)
|
|
|
|
{
|
|
|
|
SET_BITS(metadata.flags, UAVOBJ_LOGGING_UPDATE_MODE_SHIFT, val, UAVOBJ_UPDATE_MODE_MASK);
|
|
|
|
}
|