1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-29 07:24:13 +01:00

Initial release of UAVObjects and UAVTalk GCS plugins (work in progress)

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@277 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
vassilis 2010-03-10 13:25:12 +00:00 committed by vassilis
parent e66c491942
commit 3489b0c2ab
27 changed files with 1721 additions and 1 deletions

View File

@ -4,7 +4,7 @@
TEMPLATE = subdirs
SUBDIRS = plugin_coreplugin \
plugin_welcome
plugin_welcome \
# Blank Template Plugin, not compiled by default
#SUBDIRS += plugin_donothing
@ -18,4 +18,15 @@ plugin_coreplugin.subdir = coreplugin
plugin_welcome.subdir = welcome
plugin_welcome.depends = plugin_coreplugin
# UAVObjects plug-in
#SUBDIRS += plugin_uavobjects
#plugin_uavobjects.subdir = uavobjects
#plugin_uavobjects.depends = plugin_coreplugin
# UAVTalk plug-in
#SUBDIRS += plugin_uavtalk
#plugin_uavtalk.subdir = uavtalk
#plugin_uavtalk.depends = plugin_uavobjects
#plugin_uavtalk.depends += plugin_coreplugin

View File

@ -0,0 +1,87 @@
#include "uavdataobject.h"
UAVDataObject::UAVDataObject(quint32 objID, quint32 instID, bool isSingleInst, QString& name, quint32 numBytes):
UAVObject(objID, instID, isSingleInst, name, numBytes)
{
data = new quint8[numBytes]; // create data buffer, object fields are stored there as a packed structure
mobj = NULL;
}
void UAVDataObject::initialize(QList<UAVObjectField*> fields, Metadata& mdata)
{
UAVMetaObject* obj = new UAVMetaObject(objID+1, name.append("Meta"), mdata, this);
initialize(fields, obj);
}
void UAVDataObject::initialize(QList<UAVObjectField*> fields, UAVMetaObject* mobj)
{
// Initialize fields and create data buffer
this->mobj = mobj;
this->fields = fields;
quint32 offset = 0;
for (int n = 0; n < fields.length(); ++n)
{
fields.value(n)->initialize(data, offset, this);
offset += fields.value(n)->getNumBytes();
connect(fields.value(n), SIGNAL(fieldUpdated(UAVObjectField*)), this, SLOT(fieldUpdated(UAVObjectField*)));
}
}
void UAVDataObject::fieldUpdated(UAVObjectField* field)
{
emit objectUpdated(this, false); // trigger object updated event
}
qint32 UAVDataObject::getNumFields()
{
return fields.count();
}
QList<UAVObjectField*> UAVDataObject::getFields()
{
return fields;
}
UAVObjectField* UAVDataObject::getField(QString& name)
{
// Look for field
for (int n = 0; n < fields.length(); ++n)
{
if (name.compare(fields.value(n)->getName()) == 0)
{
return fields.value(n);
}
}
// If this point is reached then the field was not found
return NULL;
}
qint32 UAVDataObject::pack(quint8* dataOut)
{
QMutexLocker locker(mutex);
memcpy(dataOut, data, numBytes);
return numBytes;
}
qint32 UAVDataObject::unpack(const quint8* dataIn)
{
QMutexLocker locker(mutex);
memcpy(data, dataIn, numBytes);
emit objectUpdated(this, true); // trigger object updated event
return numBytes;
}
void UAVDataObject::setMetadata(const Metadata& mdata)
{
mobj->setData(mdata);
}
UAVObject::Metadata UAVDataObject::getMetadata(void)
{
return mobj->getData();
}
UAVMetaObject* UAVDataObject::getMetaObject()
{
return mobj;
}

View File

@ -0,0 +1,40 @@
#ifndef UAVDATAOBJECT_H
#define UAVDATAOBJECT_H
#include "uavobject.h"
#include "uavobjectfield.h"
#include "uavmetaobject.h"
#include <QList>
class UAVDataObject: public UAVObject
{
Q_OBJECT
public:
UAVDataObject(quint32 objID, quint32 instID, bool isSingleInst, QString& name, quint32 numBytes);
void initialize(QList<UAVObjectField*> fields, Metadata& mdata);
void initialize(QList<UAVObjectField*> fields, UAVMetaObject* mobj);
qint32 getNumFields();
QList<UAVObjectField*> getFields();
UAVObjectField* getField(QString& name);
qint32 pack(quint8* dataOut);
qint32 unpack(const quint8* dataIn);
void setMetadata(const Metadata& mdata);
Metadata getMetadata();
UAVMetaObject* getMetaObject();
private slots:
void fieldUpdated(UAVObjectField* field);
private:
quint8* data;
QList<UAVObjectField*> fields;
UAVMetaObject* mobj;
void initialize(QList<UAVObjectField*> fields);
};
#endif // UAVDATAOBJECT_H

View File

@ -0,0 +1,58 @@
#include "UAVMetaObject.h"
UAVMetaObject::UAVMetaObject(quint32 objID, QString& name, Metadata& mdata, UAVObject* parent):
UAVObject(objID, 0, true, name, sizeof(Metadata))
{
this->parentMetadata = mdata;
this->parent = parent;
ownMetadata.ackRequired = 1;
ownMetadata.flightTelemetryUpdateMode = UPDATEMODE_ONCHANGE;
ownMetadata.flightTelemetryUpdatePeriod = 0;
ownMetadata.gcsTelemetryUpdateMode = UPDATEMODE_ONCHANGE;
ownMetadata.gcsTelemetryUpdatePeriod = 0;
ownMetadata.loggingUpdateMode = UPDATEMODE_ONCHANGE;
ownMetadata.loggingUpdatePeriod = 0;
}
UAVObject* UAVMetaObject::getParentObject()
{
return parent;
}
qint32 UAVMetaObject::pack(quint8* dataOut)
{
QMutexLocker locker(mutex);
memcpy(dataOut, &parentMetadata, sizeof(Metadata));
return sizeof(Metadata);
}
qint32 UAVMetaObject::unpack(const quint8* dataIn)
{
QMutexLocker locker(mutex);
memcpy(&parentMetadata, dataIn, sizeof(Metadata));
emit objectUpdated(this, true); // trigger object updated event
return sizeof(Metadata);
}
void UAVMetaObject::setMetadata(const Metadata& mdata)
{
return; // can not update metaobject's metadata
}
UAVObject::Metadata UAVMetaObject::getMetadata()
{
return ownMetadata;
}
void UAVMetaObject::setData(const Metadata& mdata)
{
QMutexLocker locker(mutex);
parentMetadata = mdata;
emit objectUpdated(this, false); // trigger object updated event
}
UAVObject::Metadata UAVMetaObject::getData()
{
QMutexLocker locker(mutex);
return parentMetadata;
}

View File

@ -0,0 +1,28 @@
#ifndef UAVMETAOBJECT_H
#define UAVMETAOBJECT_H
#include "UAVObject.h"
class UAVMetaObject: public UAVObject
{
Q_OBJECT
public:
UAVMetaObject(quint32 objID, QString& name, Metadata& mdata, UAVObject* parent);
UAVObject* getParentObject();
qint32 pack(quint8* dataOut);
qint32 unpack(const quint8* dataIn);
void setMetadata(const Metadata& mdata);
Metadata getMetadata();
void setData(const Metadata& mdata);
Metadata getData();
private:
UAVObject* parent;
Metadata ownMetadata;
Metadata parentMetadata;
};
#endif // UAVMETAOBJECT_H

View File

@ -0,0 +1,68 @@
#include "uavobject.h"
UAVObject::UAVObject(quint32 objID, quint32 instID, bool isSingleInst, QString& name, quint32 numBytes): QObject()
{
this->objID = objID;
this->instID = instID;
this->isSingleInst = isSingleInst;
this->name = name;
this->numBytes = numBytes;
this->mutex = new QMutex(QMutex::Recursive);
}
quint32 UAVObject::getObjID()
{
return objID;
}
quint32 UAVObject::getInstID()
{
return instID;
}
bool UAVObject::isSingleInstance()
{
return isSingleInst;
}
QString UAVObject::getName()
{
return name;
}
quint32 UAVObject::getNumBytes()
{
return numBytes;
}
void UAVObject::requestUpdate()
{
emit updateRequested(this);
}
void UAVObject::updated()
{
emit objectUpdated(this, false);
}
void UAVObject::lock()
{
mutex->lock();
}
void UAVObject::lock(int timeoutMs)
{
mutex->tryLock(timeoutMs);
}
void UAVObject::unlock()
{
mutex->unlock();
}
QMutex* UAVObject::getMutex()
{
return mutex;
}

View File

@ -0,0 +1,72 @@
#ifndef UAVOBJECT_H
#define UAVOBJECT_H
#include <QtGlobal>
#include <QObject>
#include <QMutex>
#include <QMutexLocker>
#include <QString>
class UAVObject: public QObject
{
Q_OBJECT
public:
/**
* Object update mode
*/
typedef enum {
UPDATEMODE_PERIODIC = 0, /** Automatically update object at periodic intervals */
UPDATEMODE_ONCHANGE, /** Only update object when its data changes */
UPDATEMODE_MANUAL, /** Manually update object, by calling the updated() function */
UPDATEMODE_NEVER /** Object is never updated */
} UpdateMode;
/**
* Object metadata, each object has a meta object that holds its metadata. The metadata define
* properties for each object and can be used by multiple modules (e.g. telemetry and logger)
*/
typedef struct {
quint8 ackRequired; /** Defines if an ack is required for the transactions of this object (1:acked, 0:not acked) */
UpdateMode flightTelemetryUpdateMode; /** Update mode used by the autopilot */
qint32 flightTelemetryUpdatePeriod; /** Update period used by the autopilot (only if telemetry mode is PERIODIC) */
UpdateMode gcsTelemetryUpdateMode; /** Update mode used by the GCS */
qint32 gcsTelemetryUpdatePeriod; /** Update period used by the GCS (only if telemetry mode is PERIODIC) */
UpdateMode loggingUpdateMode; /** Update mode used by the logging module */
qint32 loggingUpdatePeriod; /** Update period used by the logging module (only if logging mode is PERIODIC) */
} Metadata;
UAVObject(quint32 objID, quint32 instID, bool isSingleInst, QString& name, quint32 numBytes);
quint32 getObjID();
quint32 getInstID();
bool isSingleInstance();
QString getName();
quint32 getNumBytes();
virtual qint32 pack(quint8* dataOut) = 0;
virtual qint32 unpack(const quint8* dataIn) = 0;
virtual void setMetadata(const Metadata& mdata) = 0;
virtual Metadata getMetadata() = 0;
void requestUpdate();
void updated();
void lock();
void lock(int timeoutMs);
void unlock();
QMutex* getMutex();
signals:
void objectUpdated(UAVObject* obj, bool unpacked);
void updateRequested(UAVObject* obj);
protected:
quint32 objID;
quint32 instID;
bool isSingleInst;
QString name;
quint32 numBytes;
QMutex* mutex;
};
#endif // UAVOBJECT_H

View File

@ -0,0 +1,203 @@
#include "uavobjectfield.h"
#include <QtEndian>
UAVObjectField::UAVObjectField(QString& name, QString& units, FieldType type, quint32 numElements)
{
// Copy params
this->name = name;
this->units = units;
this->type = type;
this->numElements = numElements;
this->offset = 0;
this->data = NULL;
this->obj = NULL;
// Calculate the number of bytes per element based on the type
switch (type) {
case FIELDTYPE_CHAR:
case FIELDTYPE_INT8:
this->numBytesPerElement = 1;
break;
case FIELDTYPE_INT16:
this->numBytesPerElement = 2;
break;
case FIELDTYPE_INT32:
case FIELDTYPE_FLOAT32:
this->numBytesPerElement = 4;
break;
default:
this->numBytesPerElement = 0;
}
}
void UAVObjectField::initialize(quint8* data, quint32 dataOffset, UAVObject* obj)
{
this->data = data;
this->offset = dataOffset;
this->obj = obj;
clear();
}
UAVObject* UAVObjectField::getObject()
{
return obj;
}
void UAVObjectField::clear()
{
if (data != NULL)
{
QMutexLocker locker(obj->getMutex());
for (unsigned int n = 0; n < numBytesPerElement*numElements; ++n)
{
data[offset + n] = 0;
}
}
}
QString UAVObjectField::getName()
{
return name;
}
QString UAVObjectField::getUnits()
{
return units;
}
UAVObjectField::FieldType UAVObjectField::getType()
{
return type;
}
quint32 UAVObjectField::getNumElements()
{
return numElements;
}
double UAVObjectField::getValue(quint32 index)
{
double ret = 0.0;
// Check if index is out of bounds or no data available
if (index < numElements && data != NULL)
{
// Get value from data
QMutexLocker locker(obj->getMutex());
switch (type) {
case FIELDTYPE_CHAR:
case FIELDTYPE_INT8:
qint8 value8;
value8 = data[offset + numBytesPerElement*index];
ret = (double)value8;
break;
case FIELDTYPE_INT16:
qint16 value16;
value16 = (qint16)qFromBigEndian<qint16>(&data[offset + numBytesPerElement*index]);
ret = (double)value16;
break;
case FIELDTYPE_INT32:
qint32 value32;
value32 = (qint32)qFromBigEndian<qint32>(&data[offset + numBytesPerElement*index]);
ret = (double)value32;
break;
case FIELDTYPE_FLOAT32:
qint32 tmp;
float valuef;
tmp = (qint32)qFromBigEndian<qint32>(&data[offset + numBytesPerElement*index]);
memcpy(&valuef, &tmp, 4);
ret = (double)valuef;
break;
default:
ret = 0.0;
}
}
return ret;
}
void UAVObjectField::setValue(double value, quint32 index)
{
// Check if index is out of bounds or no data available
if (index < numElements && data != NULL)
{
// Set value
QMutexLocker locker(obj->getMutex());
switch (type) {
case FIELDTYPE_CHAR:
case FIELDTYPE_INT8:
data[offset + numBytesPerElement*index] = (qint8)value;
break;
case FIELDTYPE_INT16:
qToBigEndian<qint16>((qint16)value, &data[offset + numBytesPerElement*index]);
break;
case FIELDTYPE_INT32:
qToBigEndian<qint32>((qint32)value, &data[offset + numBytesPerElement*index]);
break;
case FIELDTYPE_FLOAT32:
qint32 tmp;
memcpy(&tmp, &value, 4);
qToBigEndian<qint32>((qint32)tmp, &data[offset + numBytesPerElement*index]);
break;
}
}
// Emit updated event
emit fieldUpdated(this);
}
double UAVObjectField::getValue()
{
return getValue(0);
}
void UAVObjectField::setValue(double value)
{
setValue(value, 0);
}
QString UAVObjectField::getString()
{
QString str;
if (data != NULL)
{
QMutexLocker locker(obj->getMutex());
data[offset + numElements - 1] = '\0'; // null terminate
if (type == FIELDTYPE_CHAR)
{
str.append((char*)&data[offset]);
}
}
return str;
}
void UAVObjectField::setString(QString& str)
{
QByteArray barray = str.toAscii();
if (data != NULL)
{
QMutexLocker locker(obj->getMutex());
for (int n = 0; n < barray.length() && n < (int)numElements; ++n)
{
data[offset+n] = barray[n];
}
data[offset + numElements - 1] = '\0'; // null terminate
}
}
quint32 UAVObjectField::getDataOffset()
{
return offset;
}
quint32 UAVObjectField::getNumBytes()
{
return numBytesPerElement * numElements;
}
quint32 UAVObjectField::getNumBytesElement()
{
return numBytesPerElement;
}

View File

@ -0,0 +1,57 @@
#ifndef UAVOBJECTFIELD_H
#define UAVOBJECTFIELD_H
#include "uavobject.h"
class UAVObjectField: public QObject
{
Q_OBJECT
public:
/**
* Recognized field types
*/
typedef enum {
FIELDTYPE_INT8 = 0,
FIELDTYPE_INT16,
FIELDTYPE_INT32,
FIELDTYPE_FLOAT32,
FIELDTYPE_CHAR
} FieldType;
UAVObjectField(QString& name, QString& units, FieldType type, quint32 numElements);
void initialize(quint8* data, quint32 dataOffset, UAVObject* obj);
UAVObject* getObject();
QString getName();
QString getUnits();
FieldType getType();
quint32 getNumElements();
double getValue();
void setValue(double value);
double getValue(quint32 index);
void setValue(double value, quint32 index);
QString getString();
void setString(QString& str);
quint32 getDataOffset();
quint32 getNumBytes();
quint32 getNumBytesElement();
signals:
void fieldUpdated(UAVObjectField* field);
private:
QString name;
QString units;
FieldType type;
quint32 numElements;
quint32 numBytesPerElement;
quint32 offset;
quint8* data;
UAVObject* obj;
void clear();
};
#endif // UAVOBJECTFIELD_H

View File

@ -0,0 +1,275 @@
#include "uavobjectmanager.h"
UAVObjectManager::UAVObjectManager()
{
mutex = new QMutex(QMutex::Recursive);
}
bool UAVObjectManager::registerObject(UAVObject* obj)
{
QMutexLocker locker(mutex);
// Check if this object type is already in the list
for (int objidx = 0; objidx < objects.length(); ++objidx)
{
// Check if the object ID is in the list
if (objects[objidx].length() > 0 && objects[objidx][0]->getObjID() == obj->getObjID())
{
// Check if the instance is already in the list
for (int instidx = 0; instidx < objects[objidx].length(); ++instidx)
{
if ( objects[objidx][instidx]->getInstID() == obj->getInstID() )
{
// Object already registered, do not add
return false;
}
}
// If this point is reached, the object is not in the list, so now we can add it in the existing list
objects[objidx].append(obj);
emit newObject(obj);
return true;
}
}
// If this point is reached then this is the first time this object ID is added in the list
// create a new list of the instances and add in the object collection.
QList<UAVObject*> list;
list.append(obj);
objects.append(list);
emit newObject(obj);
return true;
}
UAVDataObject* UAVObjectManager::newObjectInstance(QString& name, quint32 instId)
{
return newObjectInstance(&name, 0, instId);
}
UAVDataObject* UAVObjectManager::newObjectInstance(quint32 objId, quint32 instId)
{
return newObjectInstance(NULL, objId, instId);
}
UAVDataObject* UAVObjectManager::newObjectInstance(QString* name, quint32 objId, quint32 instId)
{
QMutexLocker locker(mutex);
// Get object of the same name from collection
UAVObject* tmpObj;
if (name != NULL)
{
tmpObj = getObject(*name);
}
else
{
tmpObj = getObject(objId);
}
if (tmpObj == NULL)
{
return NULL;
}
// Make sure this is a data object
UAVDataObject* refObj = dynamic_cast<UAVDataObject*>(tmpObj);
if (refObj == NULL)
{
return NULL;
}
// Check if this is single instance object
if (refObj->isSingleInstance())
{
return NULL;
}
// Make a deep copy of the fields in the reference object
QList<UAVObjectField*> fields;
QList<UAVObjectField*> refFields = refObj->getFields();
for (int n = 0; n < refFields.length(); ++n)
{
QString fname = refFields[n]->getName();
QString funits = refFields[n]->getUnits();
UAVObjectField* field = new UAVObjectField(fname, funits, refFields[n]->getType(),
refFields[n]->getNumElements());
fields.append(field);
}
// Calculate instance ID, if the one specified is 0
// (the first object registered always gets the instance ID of zero, so any new instances will be >1)
if (instId == 0)
{
instId = getNumInstances(tmpObj->getObjID()) + 1;
}
// Create new instance, by using properties from reference object
QString oname = refObj->getName();
UAVDataObject* obj = new UAVDataObject(refObj->getObjID(), instId, refObj->isSingleInstance(),
oname, refObj->getNumBytes());
obj->initialize(fields, refObj->getMetaObject());
// Register
registerObject(obj);
// Trigger update
obj->updated();
return obj;
}
QList< QList<UAVObject*> > UAVObjectManager::getObjects()
{
QMutexLocker locker(mutex);
return objects;
}
QList< QList<UAVDataObject*> > UAVObjectManager::getDataObjects()
{
QMutexLocker locker(mutex);
QList< QList<UAVDataObject*> > dObjects;
// Go through objects and copy to new list when types match
for (int objidx = 0; objidx < objects.length(); ++objidx)
{
if (objects[objidx].length() > 0)
{
// Check type
UAVDataObject* obj = dynamic_cast<UAVDataObject*>(objects[objidx][0]);
if (obj != NULL)
{
// Create instance list
QList<UAVDataObject*> list;
// Go through instances and cast them to UAVDataObject, then add to list
for (int instidx = 0; instidx < objects[objidx].length(); ++instidx)
{
obj = dynamic_cast<UAVDataObject*>(objects[objidx][instidx]);
if (obj != NULL)
{
list.append(obj);
}
}
// Append to object list
dObjects.append(list);
}
}
}
// Done
return dObjects;
}
QList <QList<UAVMetaObject*> > UAVObjectManager::getMetaObjects()
{
QMutexLocker locker(mutex);
QList< QList<UAVMetaObject*> > mObjects;
// Go through objects and copy to new list when types match
for (int objidx = 0; objidx < objects.length(); ++objidx)
{
if (objects[objidx].length() > 0)
{
// Check type
UAVMetaObject* obj = dynamic_cast<UAVMetaObject*>(objects[objidx][0]);
if (obj != NULL)
{
// Create instance list
QList<UAVMetaObject*> list;
// Go through instances and cast them to UAVMetaObject, then add to list
for (int instidx = 0; instidx < objects[objidx].length(); ++instidx)
{
obj = dynamic_cast<UAVMetaObject*>(objects[objidx][instidx]);
if (obj != NULL)
{
list.append(obj);
}
}
// Append to object list
mObjects.append(list);
}
}
}
// Done
return mObjects;
}
UAVObject* UAVObjectManager::getObject(QString& name, quint32 instId)
{
return getObject(&name, 0, instId);
}
UAVObject* UAVObjectManager::getObject(quint32 objId, quint32 instId)
{
return getObject(NULL, objId, instId);
}
UAVObject* UAVObjectManager::getObject(QString* name, quint32 objId, quint32 instId)
{
QMutexLocker locker(mutex);
// Check if this object type is already in the list
for (int objidx = 0; objidx < objects.length(); ++objidx)
{
// Check if the object ID is in the list
if (objects[objidx].length() > 0)
{
if ( (name != NULL && objects[objidx][0]->getName().compare(name) == 0) || (name == NULL && objects[objidx][0]->getObjID() == objId) )
{
// Look for the requested instance ID
for (int instidx = 0; instidx < objects[objidx].length(); ++instidx)
{
if (objects[objidx][instidx]->getInstID() == instId)
{
return objects[objidx][instidx];
}
}
}
}
}
// If this point is reached then the requested object could not be found
return NULL;
}
QList<UAVObject*> UAVObjectManager::getObjectInstances(QString& name)
{
return getObjectInstances(&name, 0);
}
QList<UAVObject*> UAVObjectManager::getObjectInstances(quint32 objId)
{
return getObjectInstances(NULL, objId);
}
QList<UAVObject*> UAVObjectManager::getObjectInstances(QString* name, quint32 objId)
{
QMutexLocker locker(mutex);
// Check if this object type is already in the list
for (int objidx = 0; objidx < objects.length(); ++objidx)
{
// Check if the object ID is in the list
if (objects[objidx].length() > 0)
{
if ( (name != NULL && objects[objidx][0]->getName().compare(name) == 0) || (name == NULL && objects[objidx][0]->getObjID() == objId) )
{
return objects[objidx];
}
}
}
// If this point is reached then the requested object could not be found
return QList<UAVObject*>();
}
qint32 UAVObjectManager::getNumInstances(QString& name)
{
return getNumInstances(&name, 0);
}
qint32 UAVObjectManager::getNumInstances(quint32 objId)
{
return getNumInstances(NULL, objId);
}
qint32 UAVObjectManager::getNumInstances(QString* name, quint32 objId)
{
QMutexLocker locker(mutex);
// Check if this object type is already in the list
for (int objidx = 0; objidx < objects.length(); ++objidx)
{
// Check if the object ID is in the list
if (objects[objidx].length() > 0)
{
if ( (name != NULL && objects[objidx][0]->getName().compare(name) == 0) || (name == NULL && objects[objidx][0]->getObjID() == objId) )
{
return objects[objidx].length();
}
}
}
// If this point is reached then the requested object could not be found
return -1;
}

View File

@ -0,0 +1,44 @@
#ifndef UAVOBJECTMANAGER_H
#define UAVOBJECTMANAGER_H
#include "uavobject.h"
#include "uavdataobject.h"
#include "uavmetaobject.h"
#include <QList>
#include <QMutex>
class UAVObjectManager: public QObject
{
Q_OBJECT
public:
UAVObjectManager();
bool registerObject(UAVObject* obj);
UAVDataObject* newObjectInstance(QString& name, quint32 instId = 0);
UAVDataObject* newObjectInstance(quint32 objId, quint32 instId = 0);
QList< QList<UAVObject*> > getObjects();
QList< QList<UAVDataObject*> > getDataObjects();
QList< QList<UAVMetaObject*> > getMetaObjects();
UAVObject* getObject(QString& name, quint32 instId = 0);
UAVObject* getObject(quint32 objId, quint32 instId = 0);
QList<UAVObject*> getObjectInstances(QString& name);
QList<UAVObject*> getObjectInstances(quint32 objId);
qint32 getNumInstances(QString& name);
qint32 getNumInstances(quint32 objId);
signals:
void newObject(UAVObject* obj);
private:
QList< QList<UAVObject*> > objects;
QMutex* mutex;
UAVDataObject* newObjectInstance(QString* name, quint32 objId, quint32 instId);
UAVObject* getObject(QString* name, quint32 objId, quint32 instId);
QList<UAVObject*> getObjectInstances(QString* name, quint32 objId);
qint32 getNumInstances(QString* name, quint32 objId);
};
#endif // UAVOBJECTMANAGER_H

View File

@ -0,0 +1,10 @@
<plugin name="UAVObjects" version="0.0.1" compatVersion="1.1">
<vendor>The OpenPilot Project</vendor>
<copyright>(C) 2010 OpenPilot Project</copyright>
<license>Your License goes here</license>
<description>UAV telemetry objects</description>
<url>http://www.openpilot.org</url>
<dependencyList>
<dependency name="Core" version="1.1"/>
</dependencyList>
</plugin>

View File

@ -0,0 +1,19 @@
TEMPLATE = lib
TARGET = UAVObjects
include(../../openpilotgcsplugin.pri)
include(../../plugins/coreplugin/coreplugin.pri)
HEADERS += uavobject.h \
uavmetaobject.h \
uavobjectmanager.h \
uavdataobject.h \
uavobjectfield.h \
uavobjectsinit.h \
uavobjectsplugin.h
SOURCES += uavobject.cpp \
uavmetaobject.cpp \
uavobjectmanager.cpp \
uavdataobject.cpp \
uavobjectfield.cpp \
uavobjectsinit.cpp \
uavobjectsplugin.cpp
OTHER_FILES += uavobjects.pluginspec

View File

@ -0,0 +1,6 @@
#include "uavobjectsinit.h"
void UAVObjectsInitialize(UAVObjectManager* objMngr)
{
//objMngr->registerObject( new TestObject() );
}

View File

@ -0,0 +1,8 @@
#ifndef UAVOBJECTSINIT_H
#define UAVOBJECTSINIT_H
#include "uavobjectmanager.h"
void UAVObjectsInitialize(UAVObjectManager* objMngr);
#endif // UAVOBJECTSINIT_H

View File

@ -0,0 +1,35 @@
#include "uavobjectsplugin.h"
#include "uavobjectsinit.h"
UAVObjectsPlugin::UAVObjectsPlugin()
{
}
UAVObjectsPlugin::~UAVObjectsPlugin()
{
}
void UAVObjectsPlugin::extensionsInitialized()
{
}
bool UAVObjectsPlugin::initialize(const QStringList & arguments, QString * errorString)
{
// Create object manager and expose object
UAVObjectManager* objMngr = new UAVObjectManager();
addObject(objMngr);
// Initialize UAVObjects
UAVObjectsInitialize(objMngr);
// Done
Q_UNUSED(arguments);
Q_UNUSED(errorString);
return true;
}
void UAVObjectsPlugin::shutdown()
{
}

View File

@ -0,0 +1,19 @@
#ifndef UAVOBJECTSPLUGIN_H
#define UAVOBJECTSPLUGIN_H
#include <extensionsystem/iplugin.h>
#include <QtPlugin>
#include "uavobjectmanager.h"
class UAVObjectsPlugin: public ExtensionSystem::IPlugin
{
public:
UAVObjectsPlugin();
~UAVObjectsPlugin();
void extensionsInitialized();
bool initialize(const QStringList & arguments, QString * errorString);
void shutdown();
};
#endif // UAVOBJECTSPLUGIN_H

View File

@ -0,0 +1,33 @@
#include "uavobjecttemplate.h"
$(NAME)::$(NAME)(): UAVDataObject(OBJID, 0, SINGLEINST, NAME, NUMBYTES)
{
// Create fields
QList<UAVObjectField*> fields;
$(FIELDS)
// fields.append(new UAVObjectField($(FIELD_NAME), $(FIELD_UNITS), $(FIELD_TYPE), $(FIELD_NUMELEM));
// Create metadata
UAVObject::Metadata metadata;
metadata.ackRequired = $(ACK);
metadata.gcsTelemetryUpdateMode = $(GCSTELEM_UPDATEMODE);
metadata.gcsTelemetryUpdatePeriod = $(GCSTELEM_UPDATEPERIOD);
metadata.flightTelemetryUpdateMode = $(FLIGHTTELEM_UPDATEMODE);
metadata.flightTelemetryUpdatePeriod = $(FLIGHTTELEM_UPDATEPERIOD);
metadata.loggingUpdateMode = $(LOGGING_UPDATEMODE);
metadata.loggingUpdatePeriod = $(LOGGING_UPDATEPERIOD);
// Initialize object
initialize(fields, metadata);
}
$(NAME)Data $(NAME)::getData()
{
return data;
}
void $(NAME)::setData($(NAME)Data& data)
{
this->data = data;
}

View File

@ -0,0 +1,28 @@
#ifndef $(NAMEUC)_H
#define $(NAMEUC)_H
#include "uavdataobject.h"
class $(NAME): UAVDataObject
{
public:
static const quint32 OBJID = $(OBJID);
static const QString NAME = QString($(NAME));
static const bool SINGLEINST = $(SINGLEINST);
static const quint32 NUMBYTES = sizeof($(NAME)Data);
typedef struct {
$(DATAFIELDS)
} __attribute__((packed)) $(NAME)Data;
$(NAME)();
$(NAME)Data getData();
void setData($(NAME)Data& data);
private:
$(NAME)Data data;
};
#endif // $(NAMEUC)_H

View File

View File

View File

@ -0,0 +1,510 @@
#include "uavtalk.h"
#include <QtEndian>
UAVTalk::UAVTalk(QIODevice* iodev, UAVObjectManager* objMngr)
{
io = iodev;
this->objMngr = objMngr;
rxState = STATE_SYNC;
mutex = new QMutex(QMutex::Recursive);
respSema = new QSemaphore(0);
respObj = NULL;
connect(io, SIGNAL(readyRead()), this, SLOT(processInputStream()));
}
void UAVTalk::processInputStream()
{
quint8 tmp;
while (io->bytesAvailable() > 0)
{
io->read((char*)&tmp, 1);
processInputByte(tmp);
}
}
/**
* Request an update for the specified object, on success the object data would have been
* updated by the GCS.
* \param[in] obj Object to update
* \param[in] timeout Time to wait for the response, when zero it will return immediately
* \param[in] allInstances If set true then all instances will be updated
* \return Success (0), Failure (-1)
*/
qint32 UAVTalk::sendObjectRequest(UAVObject* obj, qint32 timeout, bool allInstances)
{
return objectTransaction(obj, TYPE_OBJ_REQ, timeout, allInstances);
}
/**
* Send the specified object through the telemetry link.
* \param[in] obj Object to send
* \param[in] acked Selects if an ack is required
* \param[in] timeoutMs Time to wait for the ack, when zero it will return immediately
* \param[in] allInstances If set true then all instances will be updated
* \return 0 Success
* \return -1 Failure
*/
qint32 UAVTalk::sendObject(UAVObject* obj, bool acked, qint32 timeoutMs)
{
if (acked)
{
return objectTransaction(obj, TYPE_OBJ_ACK, timeoutMs, false);
}
else
{
return objectTransaction(obj, TYPE_OBJ, timeoutMs, false);
}
}
/**
* Execute the requested transaction on an object.
* \param[in] obj Object
* \param[in] type Transaction type
* TYPE_OBJ: send object,
* TYPE_OBJ_REQ: request object update
* TYPE_OBJ_ACK: send object with an ack
* \param[in] allInstances If set true then all instances will be updated
* \param[in] timeoutMs Time to wait for the ack, when zero it will return immediately
* \return Success (true), Failure (false)
*/
bool UAVTalk::objectTransaction(UAVObject* obj, quint8 type, qint32 timeoutMs, bool allInstances)
{
bool respReceived;
// Lock
mutex->lock();
// Send object depending on if a response is needed
if (type == TYPE_OBJ_ACK || type == TYPE_OBJ_REQ)
{
if ( transmitObject(obj, type, allInstances) )
{
respObj = obj;
respAllInstances = allInstances;
mutex->unlock(); // need to release lock since the next call will block until a response is received
respSema->tryAcquire(); // the semaphore needs to block on the next call, here we make sure the value is zero (binary sema)
respReceived = respSema->tryAcquire(1, timeoutMs); // lock on object until a response is received (or timeout)
return respReceived;
}
else
{
mutex->unlock();
return false;
}
}
else if (type == TYPE_OBJ)
{
bool success = transmitObject(obj, TYPE_OBJ, allInstances);
mutex->unlock();
return success;
}
else
{
mutex->unlock();
return false;
}
}
/**
* Process an byte from the telemetry stream.
* \param[in] rxbyte Received byte
* \return Success (true), Failure (false)
*/
bool UAVTalk::processInputByte(quint8 rxbyte)
{
// Receive state machine
switch (rxState) {
case STATE_SYNC:
if ((rxbyte & TYPE_MASK) == TYPE_VER )
{
rxCS = rxbyte;
rxType = rxbyte;
rxState = STATE_OBJID;
rxCount = 0;
}
break;
case STATE_OBJID:
rxTmpBuffer[rxCount++] = rxbyte;
if (rxCount == 4)
{
// Search for object, if not found reset state machine
rxObjId = (qint32)qFromBigEndian<qint32>(rxTmpBuffer);
UAVObject* rxObj = objMngr->getObject(rxObjId);
if (rxObj == NULL)
{
rxState = STATE_SYNC;
}
else
{
// Update checksum
rxCS = updateChecksum(rxCS, rxTmpBuffer, 4);
// Determine data length
if (rxType == TYPE_OBJ_REQ || rxType == TYPE_ACK)
{
rxLength = 0;
}
else
{
rxLength = rxObj->getNumBytes();
}
// Check length and determine next state
if (rxLength >= MAX_PAYLOAD_LENGTH)
{
rxState = STATE_SYNC;
}
else
{
// Check if this is a single instance object (i.e. if the instance ID field is coming next)
if ( rxObj->isSingleInstance() )
{
// If there is a payload get it, otherwise receive checksum
if (rxLength > 0)
{
rxState = STATE_DATA;
}
else
{
rxState = STATE_CS;
}
rxInstId = 0;
rxCount = 0;
}
else
{
rxState = STATE_INSTID;
rxCount = 0;
}
}
}
}
break;
case STATE_INSTID:
rxTmpBuffer[rxCount++] = rxbyte;
if (rxCount == 2)
{
rxInstId = (qint16)qFromBigEndian<qint16>(rxTmpBuffer);
rxCS = updateChecksum(rxCS, rxTmpBuffer, 2);
rxCount = 0;
// If there is a payload get it, otherwise receive checksum
if (rxLength > 0)
{
rxState = STATE_DATA;
}
else
{
rxState = STATE_CS;
}
}
break;
case STATE_DATA:
rxBuffer[rxCount++] = rxbyte;
if (rxCount == rxLength)
{
rxCS = updateChecksum(rxCS, rxBuffer, rxLength);
rxState = STATE_CS;
rxCount = 0;
}
break;
case STATE_CS:
rxTmpBuffer[rxCount++] = rxbyte;
if (rxCount == 2)
{
rxCSPacket = (qint16)qFromBigEndian<qint16>(rxTmpBuffer);
if (rxCS == rxCSPacket)
{
mutex->lock();
receiveObject(rxType, rxObjId, rxInstId, rxBuffer, rxLength);
mutex->unlock();
}
rxState = STATE_SYNC;
}
break;
default:
rxState = STATE_SYNC;
}
// Done
return true;
}
/**
* Receive an object. This function process objects received through the telemetry stream.
* \param[in] type Type of received message (TYPE_OBJ, TYPE_OBJ_REQ, TYPE_OBJ_ACK, TYPE_ACK)
* \param[in] obj Handle of the received object
* \param[in] instId The instance ID of UAVOBJ_ALL_INSTANCES for all instances.
* \param[in] data Data buffer
* \param[in] length Buffer length
* \return Success (true), Failure (false)
*/
bool UAVTalk::receiveObject(quint8 type, quint32 objId, quint16 instId, quint8* data, qint32 length)
{
UAVObject* obj = NULL;
bool error = false;
bool allInstances = (instId == ALL_INSTANCES? true : false);
// Process message type
switch (type) {
case TYPE_OBJ:
// All instances, not allowed for OBJ messages
if (!allInstances)
{
// Get object and update its data
obj = updateObject(objId, instId, data);
// Check if an ack is pending
updateAck(obj);
}
else
{
error = true;
}
break;
case TYPE_OBJ_ACK:
// All instances, not allowed for OBJ_ACK messages
if (!allInstances)
{
// Get object and update its data
obj = updateObject(objId, instId, data);
// Transmit ACK
transmitObject(obj, TYPE_ACK, false);
}
else
{
error = true;
}
break;
case TYPE_OBJ_REQ:
// Get object, if all instances are requested get instance 0 of the object
if (allInstances)
{
obj = objMngr->getObject(objId);
}
else
{
obj = objMngr->getObject(objId, instId);
}
// If object was found transmit it
if (obj != NULL)
{
transmitObject(obj, TYPE_OBJ, allInstances);
}
else
{
error = true;
}
break;
case TYPE_ACK:
// All instances, not allowed for ACK messages
if (!allInstances)
{
// Get object
obj = objMngr->getObject(objId, instId);
// Check if an ack is pending
if (obj != NULL)
{
updateAck(obj);
}
else
{
error = true;
}
}
break;
default:
error = true;
}
// Done
return !error;
}
UAVObject* UAVTalk::updateObject(quint32 objId, quint16 instId, quint8* data)
{
// Get object
UAVObject* obj = objMngr->getObject(objId, instId);
// If the instance does not exist create it
if (obj == NULL)
{
obj = objMngr->newObjectInstance(objId, instId);
}
// Unpack data into object instance
obj->unpack(data);
return obj;
}
void UAVTalk::updateAck(UAVObject* obj)
{
if (respObj != NULL && respObj->getObjID() == obj->getObjID() && (respObj->getInstID() == obj->getInstID() || respAllInstances))
{
respSema->release();
respObj = NULL;
emit transactionCompleted(obj);
}
}
/**
* Send an object through the telemetry link.
* \param[in] obj Object to send
* \param[in] type Transaction type
* \param[in] allInstances True is all instances of the object are to be sent
* \return Success (true), Failure (false)
*/
bool UAVTalk::transmitObject(UAVObject* obj, quint8 type, bool allInstances)
{
// If all instances are requested on a single instance object it is an error
if (allInstances && obj->isSingleInstance())
{
return false;
}
// Process message type
if ( type == TYPE_OBJ || type == TYPE_OBJ_ACK )
{
if (allInstances)
{
// Get number of instances
quint32 numInst = objMngr->getNumInstances(obj->getObjID());
// Send all instances
for (quint32 instId = 0; instId < numInst; ++instId)
{
UAVObject* inst = objMngr->getObject(obj->getObjID(), instId);
transmitSingleObject(inst, type, false);
}
return true;
}
else
{
return transmitSingleObject(obj, type, false);
}
}
else if (type == TYPE_OBJ_REQ)
{
return transmitSingleObject(obj, type, allInstances);
}
else if (type == TYPE_ACK)
{
if (!allInstances)
{
return transmitSingleObject(obj, type, false);
}
else
{
return false;
}
}
else
{
return false;
}
}
/**
* Send an object through the telemetry link.
* \param[in] obj Object handle to send
* \param[in] type Transaction type
* \return Success (true), Failure (false)
*/
bool UAVTalk::transmitSingleObject(UAVObject* obj, quint8 type, bool allInstances)
{
qint32 length;
qint32 dataOffset;
quint16 cs = 0;
quint32 objId;
quint16 instId;
quint16 allInstId = ALL_INSTANCES;
// Setup type and object id fields
objId = obj->getObjID();
txBuffer[0] = type;
qToBigEndian<qint32>(objId, &txBuffer[1]);
// Setup instance ID if one is required
if ( obj->isSingleInstance() )
{
dataOffset = 5;
}
else
{
// Check if all instances are requested
if (allInstances)
{
qToBigEndian<qint16>(allInstId, &txBuffer[5]);
}
else
{
instId = obj->getInstID();
qToBigEndian<qint16>(instId, &txBuffer[5]);
}
dataOffset = 7;
}
// Determine data length
if (type == TYPE_OBJ_REQ || type == TYPE_ACK)
{
length = 0;
}
else
{
length = obj->getNumBytes();
}
// Check length
if (length >= MAX_PAYLOAD_LENGTH)
{
return false;
}
// Copy data (if any)
if (length > 0)
{
if ( !obj->pack(&txBuffer[dataOffset]) )
{
return false;
}
}
// Calculate checksum
cs = 0;
cs = updateChecksum(cs, txBuffer, dataOffset+length);
qToBigEndian<qint16>(cs, &txBuffer[dataOffset+length]);
// Send buffer
io->write((const char*)txBuffer, dataOffset+length+CHECKSUM_LENGTH);
// Done
return true;
}
/**
* Update checksum.
* TODO: Replace with CRC-16
* \param[in] data Data buffer to update checksum on
* \param[in] length Length of buffer
* \return Updated checksum
*/
quint16 UAVTalk::updateChecksum(quint16 cs, quint8* data, qint32 length)
{
qint32 n;
for (n = 0; n < length; ++n)
{
cs += (quint16)data[n];
}
return cs;
}

View File

@ -0,0 +1,73 @@
#ifndef UAVTALK_H
#define UAVTALK_H
#include <QIODevice>
#include <QMutex>
#include <QMutexLocker>
#include <QSemaphore>
#include "uavobjects\uavobjectmanager.h"
class UAVTalk: public QObject
{
Q_OBJECT
public:
UAVTalk(QIODevice* iodev, UAVObjectManager* objMngr);
qint32 sendObject(UAVObject* obj, bool acked, qint32 timeoutMs);
qint32 sendObjectRequest(UAVObject* obj, qint32 timeout, bool allInstances);
signals:
void transactionCompleted(UAVObject* obj);
private slots:
void processInputStream(void);
private:
// Constants
static const int TYPE_MASK = 0xFC;
static const int TYPE_VER = 0x10;
static const int TYPE_OBJ = (TYPE_VER | 0x00);
static const int TYPE_OBJ_REQ = (TYPE_VER | 0x01);
static const int TYPE_OBJ_ACK = (TYPE_VER | 0x02);
static const int TYPE_ACK = (TYPE_VER | 0x03);
static const int HEADER_LENGTH = 7; // type (1), object ID (4), instance ID (2, not used in single objects)
static const int CHECKSUM_LENGTH = 2;
static const int MAX_PAYLOAD_LENGTH = 256;
static const int MAX_PACKET_LENGTH = (HEADER_LENGTH+MAX_PAYLOAD_LENGTH+CHECKSUM_LENGTH);
static const quint16 ALL_INSTANCES = 0xFFFF;
typedef enum {STATE_SYNC, STATE_OBJID, STATE_INSTID, STATE_DATA, STATE_CS} RxStateType;
// Variables
QIODevice* io;
UAVObjectManager* objMngr;
QMutex* mutex;
QSemaphore* respSema;
UAVObject* respObj;
bool respAllInstances;
quint8 rxBuffer[MAX_PACKET_LENGTH];
quint8 txBuffer[MAX_PACKET_LENGTH];
// Variables used by the receive state machine
quint8 rxTmpBuffer[4];
quint8 rxType;
quint32 rxObjId;
quint16 rxInstId;
quint8 rxLength;
quint16 rxCSPacket, rxCS;
qint32 rxCount;
RxStateType rxState;
// Methods
bool objectTransaction(UAVObject* obj, quint8 type, qint32 timeoutMs, bool allInstances);
bool processInputByte(quint8 rxbyte);
bool receiveObject(quint8 type, quint32 objId, quint16 instId, quint8* data, qint32 length);
UAVObject* updateObject(quint32 objId, quint16 instId, quint8* data);
void updateAck(UAVObject* obj);
bool transmitObject(UAVObject* obj, quint8 type, bool allInstances);
bool transmitSingleObject(UAVObject* obj, quint8 type, bool allInstances);
quint16 updateChecksum(quint16 cs, quint8* data, qint32 length);
};
#endif // UAVTALK_H

View File

@ -0,0 +1,10 @@
<plugin name="UAVTalk" version="0.0.1" compatVersion="1.1">
<vendor>The OpenPilot Project</vendor>
<copyright>(C) 2010 OpenPilot Project</copyright>
<license>Your License goes here</license>
<description>UAVTalk telemetry protocol</description>
<url>http://www.openpilot.org</url>
<dependencyList>
<dependency name="Core" version="1.1"/>
</dependencyList>
</plugin>

View File

@ -0,0 +1,11 @@
TEMPLATE = lib
TARGET = UAVTalk
include(../../openpilotgcsplugin.pri)
include(../../plugins/coreplugin/coreplugin.pri)
HEADERS += uavtalk.h \
uavtalkplugin.h
SOURCES += uavtalk.cpp \
uavtalkplugin.cpp
HEADERS += telemetry.h
SOURCES += telemetry.cpp
OTHER_FILES += uavtalk.pluginspec

View File

@ -0,0 +1,5 @@
#include "uavtalkplugin.h"
UAVTalkPlugin::UAVTalkPlugin()
{
}

View File

@ -0,0 +1,10 @@
#ifndef UAVTALKPLUGIN_H
#define UAVTALKPLUGIN_H
class UAVTalkPlugin
{
public:
UAVTalkPlugin();
};
#endif // UAVTALKPLUGIN_H