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"
# include <QtEndian>
# include <QDebug>
// 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-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
{
2013-05-19 16:37:30 +02:00
this - > objID = objID ;
2013-04-05 22:46:56 +02:00
this - > instID = 0 ;
this - > isSingleInst = isSingleInst ;
2013-05-19 16:37:30 +02:00
this - > name = name ;
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 ) ;
}
/**
* Signal that the object has been updated
*/
void UAVObject : : updated ( )
{
emit objectUpdatedManual ( this ) ;
emit objectUpdated ( this ) ;
}
/**
* 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
2013-05-19 16:37:30 +02:00
qWarning ( ) < < " UAVObject::getField Non existant field " < < name < < " requested. 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 ;
}
/**
* 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
2013-11-26 01:27:25 +01:00
sout . append ( QString ( " %1 (ID: %2:%3, %4bytes, %5) " )
2013-05-19 16:37:30 +02:00
. arg ( getName ( ) )
. arg ( getObjID ( ) )
. 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 ;
}
/**
* 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 ) ;
}
/**
* 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 |
UPDATEMODE_ONCHANGE < < UAVOBJ_GCS_TELEMETRY_UPDATE_MODE_SHIFT ;
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
}