2010-06-23 04:33:53 +02:00
/**
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
2010-07-16 20:07:13 +02:00
* @ file uavobject . cpp
2010-06-23 04:33:53 +02:00
* @ author The OpenPilot Team , http : //www.openpilot.org Copyright (C) 2010.
* @ see The GNU Public License ( GPL ) Version 3
2010-07-16 19:32:18 +02:00
* @ addtogroup GCSPlugins GCS Plugins
* @ {
* @ addtogroup UAVObjectsPlugin UAVObjects Plugin
2010-06-23 04:33:53 +02:00
* @ {
2010-07-16 20:07:13 +02:00
* @ brief The UAVUObjects GCS plugin
2010-06-23 04:33:53 +02:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-07-16 19:32:18 +02:00
/*
2010-06-23 04:33:53 +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
* ( at your option ) any later version .
*
* 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
* for more details .
*
* 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 . ,
* 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include "uavobject.h"
# include <QtEndian>
/**
* Constructor
* @ param objID The object ID
* @ param isSingleInst True if this object can only have a single instance
* @ param name Object name
*/
UAVObject : : UAVObject ( quint32 objID , bool isSingleInst , const QString & name )
{
this - > objID = objID ;
this - > instID = 0 ;
this - > isSingleInst = isSingleInst ;
this - > name = name ;
this - > mutex = new QMutex ( QMutex : : Recursive ) ;
}
/**
* Initialize object with its instance ID
*/
void UAVObject : : initialize ( quint32 instID )
{
QMutexLocker locker ( mutex ) ;
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 )
*/
void UAVObject : : initializeFields ( QList < UAVObjectField * > & fields , quint8 * data , quint32 numBytes )
{
QMutexLocker locker ( mutex ) ;
this - > numBytes = numBytes ;
this - > data = data ;
this - > fields = fields ;
// Initialize fields
quint32 offset = 0 ;
for ( int n = 0 ; n < fields . length ( ) ; + + n )
{
fields [ n ] - > initialize ( data , offset , this ) ;
offset + = fields [ n ] - > getNumBytes ( ) ;
connect ( fields [ n ] , SIGNAL ( fieldUpdated ( UAVObjectField * ) ) , this , SLOT ( fieldUpdated ( UAVObjectField * ) ) ) ;
}
}
/**
* Called from the fields each time they are updated
*/
void UAVObject : : fieldUpdated ( UAVObjectField * field )
{
2010-09-21 21:29:45 +02:00
Q_UNUSED ( field ) ;
2010-06-23 04:33:53 +02:00
// emit objectUpdatedAuto(this); // trigger object updated event
// emit objectUpdated(this);
}
/**
* 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 ;
}
2010-12-22 22:29:23 +01:00
/**
* Get the description of the object
*/
QString UAVObject : : getDescription ( )
{
return description ;
}
/**
* Set the description of the object
*/
void UAVObject : : setDescription ( const QString & description )
{
this - > description = description ;
}
2010-06-23 04:33:53 +02:00
/**
* 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
*/
QMutex * UAVObject : : getMutex ( )
{
return mutex ;
}
/**
* Get the number of fields held by this object
*/
qint32 UAVObject : : getNumFields ( )
{
QMutexLocker locker ( mutex ) ;
return fields . count ( ) ;
}
/**
* Get the object ' s fields
*/
QList < UAVObjectField * > UAVObject : : getFields ( )
{
QMutexLocker locker ( mutex ) ;
return fields ;
}
/**
* Get a specific field
* @ returns The field or NULL if not found
*/
2010-07-19 07:37:12 +02:00
UAVObjectField * UAVObject : : getField ( const QString & name )
2010-06-23 04:33:53 +02:00
{
QMutexLocker locker ( mutex ) ;
// Look for field
for ( int n = 0 ; n < fields . length ( ) ; + + n )
{
if ( name . compare ( fields [ n ] - > getName ( ) ) = = 0 )
{
return fields [ n ] ;
}
}
// If this point is reached then the field was not found
2010-09-21 21:29:45 +02:00
Q_ASSERT_X ( 0 , " UAVObject::getField " , QString ( " Non existant field " + name + " requested. This indicates a bug. Make sure you also have null checking for non-debug code. " ) . toAscii ( ) ) ;
2010-06-23 04:33:53 +02:00
return NULL ;
}
/**
* Pack the object data into a byte array
* @ returns The number of bytes copied
*/
qint32 UAVObject : : pack ( quint8 * dataOut )
{
QMutexLocker locker ( mutex ) ;
qint32 offset = 0 ;
for ( int n = 0 ; n < fields . length ( ) ; + + n )
{
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
*/
qint32 UAVObject : : unpack ( const quint8 * dataIn )
{
QMutexLocker locker ( mutex ) ;
qint32 offset = 0 ;
for ( int n = 0 ; n < fields . length ( ) ; + + n )
{
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 " ) ;
if ( ! file . open ( QFile : : WriteOnly ) )
{
return false ;
}
// Write object
if ( ! save ( file ) )
{
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
*/
bool UAVObject : : save ( QFile & file )
{
QMutexLocker locker ( mutex ) ;
quint8 buffer [ numBytes ] ;
quint8 tmpId [ 4 ] ;
// Write the object ID
qToLittleEndian < quint32 > ( objID , tmpId ) ;
if ( file . write ( ( const char * ) tmpId , 4 ) = = - 1 )
{
return false ;
}
// Write the instance ID
if ( ! isSingleInst )
{
qToLittleEndian < quint16 > ( instID , tmpId ) ;
if ( file . write ( ( const char * ) tmpId , 2 ) = = - 1 )
{
return false ;
}
}
// Write the data
pack ( buffer ) ;
if ( file . write ( ( const char * ) buffer , numBytes ) = = - 1 )
{
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 " ) ;
if ( ! file . open ( QFile : : ReadOnly ) )
{
return false ;
}
// Load object
if ( ! load ( file ) )
{
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
*/
bool UAVObject : : load ( QFile & file )
{
QMutexLocker locker ( mutex ) ;
quint8 buffer [ numBytes ] ;
quint8 tmpId [ 4 ] ;
// Read the object ID
if ( file . read ( ( char * ) tmpId , 4 ) ! = 4 )
{
return false ;
}
// Check that the IDs match
if ( qFromLittleEndian < quint32 > ( tmpId ) ! = objID )
{
return false ;
}
// Read the instance ID
if ( file . read ( ( char * ) tmpId , 2 ) ! = 2 )
{
return false ;
}
// Check that the IDs match
if ( qFromLittleEndian < quint16 > ( tmpId ) ! = instID )
{
return false ;
}
// Read and unpack the data
if ( file . read ( ( char * ) buffer , numBytes ) ! = numBytes )
{
return false ;
}
unpack ( buffer ) ;
// Done
return true ;
}
/**
* Return a string with the object information
*/
QString UAVObject : : toString ( )
{
QString sout ;
sout . append ( toStringBrief ( ) ) ;
sout . append ( toStringData ( ) ) ;
return sout ;
}
/**
* Return a string with the object information ( only the header )
*/
QString UAVObject : : toStringBrief ( )
{
QString sout ;
sout . append ( QString ( " %1 (ID: %2, InstID: %3, NumBytes: %4, SInst: %5) \n " )
. arg ( getName ( ) )
. arg ( getObjID ( ) )
. arg ( getInstID ( ) )
. arg ( getNumBytes ( ) )
. arg ( isSingleInstance ( ) ) ) ;
return sout ;
}
/**
* Return a string with the object information ( only the data )
*/
QString UAVObject : : toStringData ( )
{
QString sout ;
sout . append ( " Data: \n " ) ;
for ( int n = 0 ; n < fields . length ( ) ; + + n )
{
sout . append ( QString ( " \t %1 " ) . arg ( fields [ n ] - > toString ( ) ) ) ;
}
return sout ;
}
/**
* Emit the transactionCompleted event ( used by the UAVTalk plugin )
*/
void UAVObject : : emitTransactionCompleted ( bool success )
{
emit transactionCompleted ( this , success ) ;
}