diff --git a/flight/PiOS.posix/posix/pios_delay.c b/flight/PiOS.posix/posix/pios_delay.c index 386e2bb2f..6cdeabd0d 100644 --- a/flight/PiOS.posix/posix/pios_delay.c +++ b/flight/PiOS.posix/posix/pios_delay.c @@ -64,7 +64,7 @@ int32_t PIOS_DELAY_WaituS(uint32_t uS) static struct timespec wait,rest; wait.tv_sec=0; wait.tv_nsec=1000*uS; - while (!nanosleep(&wait,&rest)) { + while (nanosleep(&wait,&rest)!=0) { wait=rest; } @@ -90,7 +90,7 @@ int32_t PIOS_DELAY_WaitmS(uint32_t mS) static struct timespec wait,rest; wait.tv_sec=mS/1000; wait.tv_nsec=(mS%1000)*1000000; - while (!nanosleep(&wait,&rest)) { + while (nanosleep(&wait,&rest)!=0) { wait=rest; } //} diff --git a/flight/UAVObjects/inc/uavobjectmanager.h b/flight/UAVObjects/inc/uavobjectmanager.h index bd1dc7f5f..fe7c21d07 100644 --- a/flight/UAVObjects/inc/uavobjectmanager.h +++ b/flight/UAVObjects/inc/uavobjectmanager.h @@ -59,10 +59,10 @@ typedef void* UAVObjHandle; * Object update mode, used by multiple modules (e.g. telemetry and logger) */ typedef enum { - UPDATEMODE_PERIODIC = 0, /** Automatically update object at periodic intervals */ - UPDATEMODE_ONCHANGE = 1, /** Only update object when its data changes */ - UPDATEMODE_THROTTLED = 2, /** Object is updated on change, but not more often than the interval time */ - UPDATEMODE_MANUAL = 3 /** Manually update object, by calling the updated() function */ + UPDATEMODE_MANUAL = 0, /** Manually update object, by calling the updated() function */ + UPDATEMODE_PERIODIC = 1, /** Automatically update object at periodic intervals */ + UPDATEMODE_ONCHANGE = 2, /** Only update object when its data changes */ + UPDATEMODE_THROTTLED = 3 /** Object is updated on change, but not more often than the interval time */ } UAVObjUpdateMode; /** diff --git a/ground/openpilotgcs/src/plugins/scope/plotdata.cpp b/ground/openpilotgcs/src/plugins/scope/plotdata.cpp index 154a9aa06..57b17c193 100644 --- a/ground/openpilotgcs/src/plugins/scope/plotdata.cpp +++ b/ground/openpilotgcs/src/plugins/scope/plotdata.cpp @@ -99,7 +99,7 @@ bool SequentialPlotData::append(UAVObject* obj) double currentValue = valueAsDouble(obj, field) * pow(10, scalePower); - //Compute boxcar average + //Perform scope math, if necessary if (mathFunction == "Boxcar average" || mathFunction == "Standard deviation"){ //Put the new value at the front yDataHistory->append( currentValue ); @@ -163,8 +163,8 @@ bool ChronoPlotData::append(UAVObject* obj) QDateTime NOW = QDateTime::currentDateTime(); //THINK ABOUT REIMPLEMENTING THIS TO SHOW UAVO TIME, NOT SYSTEM TIME double currentValue = valueAsDouble(obj, field) * pow(10, scalePower); - //Compute boxcar average - if (meanSamples > 1){ + //Perform scope math, if necessary + if (mathFunction == "Boxcar average" || mathFunction == "Standard deviation"){ //Put the new value at the front yDataHistory->append( currentValue ); diff --git a/ground/openpilotgcs/src/plugins/scope/scopegadgetwidget.cpp b/ground/openpilotgcs/src/plugins/scope/scopegadgetwidget.cpp index 967ede982..7b53a060f 100644 --- a/ground/openpilotgcs/src/plugins/scope/scopegadgetwidget.cpp +++ b/ground/openpilotgcs/src/plugins/scope/scopegadgetwidget.cpp @@ -51,6 +51,7 @@ #include #include #include +#include //using namespace Core; @@ -65,8 +66,8 @@ ScopeGadgetWidget::ScopeGadgetWidget(QWidget *parent) : QwtPlot(parent) replotTimer = new QTimer(this); connect(replotTimer, SIGNAL(timeout()), this, SLOT(replotNewData())); - // Listen to telemetry connection/disconnection events, no point - // running the scopes if we are not connected and not replaying logs + // Listen to telemetry connection/disconnection events, no point in + // running the scopes if we are not connected and not replaying logs. // Also listen to disconnect actions from the user Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager(); connect(cm, SIGNAL(deviceAboutToDisconnect()), this, SLOT(stopPlotting())); @@ -124,13 +125,18 @@ void ScopeGadgetWidget::mouseReleaseEvent(QMouseEvent *e) void ScopeGadgetWidget::mouseDoubleClickEvent(QMouseEvent *e) { - mutex.lock(); - if (legend()) - deleteLegend(); - else - addLegend(); - mutex.unlock(); - update(); + //On double-click, toggle legend + mutex.lock(); + if (legend()) + deleteLegend(); + else + addLegend(); + mutex.unlock(); + + //On double-click, reset plot zoom + setAxisAutoScale(QwtPlot::yLeft, true); + + update(); QwtPlot::mouseDoubleClickEvent(e); } @@ -142,6 +148,33 @@ void ScopeGadgetWidget::mouseMoveEvent(QMouseEvent *e) void ScopeGadgetWidget::wheelEvent(QWheelEvent *e) { + //Change zoom on scroll wheel event + QwtInterval yInterval=axisInterval(QwtPlot::yLeft); + if (yInterval.minValue() != yInterval.maxValue()) //Make sure that the two values are never the same. Sometimes axisInterval returns (0,0) + { + //Determine what y value to zoom about. NOTE, this approach has a bug that the in that + //the value returned by Qt includes the legend, whereas the value transformed by Qwt + //does *not*. Thus, when zooming with a legend, there will always be a small bias error. + //In practice, this seems not to be a UI problem. + QPoint mouse_pos=e->pos(); //Get the mouse coordinate in the frame + double zoomLine=invTransform(QwtPlot::yLeft, mouse_pos.y()); //Transform the y mouse coordinate into a frame value. + + double zoomScale=1.1; //THIS IS AN ARBITRARY CONSTANT, AND PERHAPS SHOULD BE IN A DEFINE INSTEAD OF BURIED HERE + + mutex.lock(); //DOES THIS mutex.lock NEED TO BE HERE? I DON'T KNOW, I JUST COPIED IT FROM THE ABOVE CODE + // Set the scale + if (e->delta()<0){ + setAxisScale(QwtPlot::yLeft, + (yInterval.minValue()-zoomLine)*zoomScale+zoomLine, + (yInterval.maxValue()-zoomLine)*zoomScale+zoomLine ); + } + else{ + setAxisScale(QwtPlot::yLeft, + (yInterval.minValue()-zoomLine)/zoomScale+zoomLine, + (yInterval.maxValue()-zoomLine)/zoomScale+zoomLine ); + } + mutex.unlock(); + } QwtPlot::wheelEvent(e); } @@ -203,17 +236,17 @@ void ScopeGadgetWidget::addLegend() // legend->setFrameStyle(QFrame::Box | QFrame::Sunken); // insertLegend(legend, QwtPlot::BottomLegend); - // Update the checked/unchecked state of the legend items - // -> this is necessary when hiding a legend where some plots are - // not visible, and the un-hiding it. - foreach (QwtPlotItem *item, this->itemList()) { - bool on = item->isVisible(); - QWidget *w = legend->find(item); - if ( w && w->inherits("QwtLegendItem") ) - ((QwtLegendItem *)w)->setChecked(!on); - } + // Update the checked/unchecked state of the legend items + // -> this is necessary when hiding a legend where some plots are + // not visible, and the un-hiding it. + foreach (QwtPlotItem *item, this->itemList()) { + bool on = item->isVisible(); + QWidget *w = legend->find(item); + if ( w && w->inherits("QwtLegendItem") ) + ((QwtLegendItem *)w)->setChecked(!on); + } - connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)), this, SLOT(showCurve(QwtPlotItem *, bool))); + connect(this, SIGNAL(legendChecked(QwtPlotItem *, bool)), this, SLOT(showCurve(QwtPlotItem *, bool))); } void ScopeGadgetWidget::preparePlot(PlotType plotType) @@ -234,27 +267,27 @@ void ScopeGadgetWidget::preparePlot(PlotType plotType) // setPalette(pal); // setCanvasBackground(Utils::StyleHelper::baseColor()); - setCanvasBackground(QColor(64, 64, 64)); + setCanvasBackground(QColor(64, 64, 64)); //Add grid lines QwtPlotGrid *grid = new QwtPlotGrid; - grid->setMajPen(QPen(Qt::gray, 0, Qt::DashLine)); - grid->setMinPen(QPen(Qt::lightGray, 0, Qt::DotLine)); - grid->setPen(QPen(Qt::darkGray, 1, Qt::DotLine)); - grid->attach(this); + grid->setMajPen(QPen(Qt::gray, 0, Qt::DashLine)); + grid->setMinPen(QPen(Qt::lightGray, 0, Qt::DotLine)); + grid->setPen(QPen(Qt::darkGray, 1, Qt::DotLine)); + grid->attach(this); - // Add the legend - addLegend(); + // Add the legend + addLegend(); // Only start the timer if we are already connected Core::ConnectionManager *cm = Core::ICore::instance()->connectionManager(); - if (cm->getCurrentConnection() && replotTimer) - { - if (!replotTimer->isActive()) - replotTimer->start(m_refreshInterval); - else - replotTimer->setInterval(m_refreshInterval); - } + if (cm->getCurrentConnection() && replotTimer) + { + if (!replotTimer->isActive()) + replotTimer->start(m_refreshInterval); + else + replotTimer->setInterval(m_refreshInterval); + } } void ScopeGadgetWidget::showCurve(QwtPlotItem *item, bool on) @@ -412,7 +445,7 @@ void ScopeGadgetWidget::addCurvePlot(QString uavObject, QString uavFieldSubField //Keep the curve details for later m_curvesData.insert(curveNameScaled, plotData); - //Link to the signal of new data only if this UAVObject has not been to connected yet + //Link to the new signal data only if this UAVObject has not been connected yet if (!m_connectedUAVObjects.contains(obj->getName())) { m_connectedUAVObjects.append(obj->getName()); connect(obj, SIGNAL(objectUpdated(UAVObject*)), this, SLOT(uavObjectReceived(UAVObject*))); @@ -470,6 +503,7 @@ void ScopeGadgetWidget::replotNewData() replot(); } +/* void ScopeGadgetWidget::setupExamplePlot() { preparePlot(SequentialPlot); @@ -514,6 +548,7 @@ void ScopeGadgetWidget::setupExamplePlot() replot(); mutex.unlock(); } +*/ void ScopeGadgetWidget::clearCurvePlots() { diff --git a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp index 543034aa7..bfdd7f401 100644 --- a/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjectbrowser/uavobjecttreemodel.cpp @@ -205,6 +205,7 @@ void UAVObjectTreeModel::addSingleField(int index, UAVObjectField *field, TreeIt FieldTreeItem *item; UAVObjectField::FieldType type = field->getType(); switch (type) { + case UAVObjectField::BITFIELD: case UAVObjectField::ENUM: { QStringList options = field->getOptions(); QVariant value = field->getValue(); diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavmetaobject.cpp b/ground/openpilotgcs/src/plugins/uavobjects/uavmetaobject.cpp index e3fd7fdbb..2805c9a1f 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavmetaobject.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavmetaobject.cpp @@ -38,17 +38,13 @@ UAVMetaObject::UAVMetaObject(quint32 objID, const QString& name, UAVObject *pare // Setup default metadata of metaobject (can not be changed) UAVObject::MetadataInitialize(ownMetadata); // Setup fields - QStringList boolEnum; - boolEnum << tr("False") << tr("True"); - QStringList updateModeEnum; - updateModeEnum << tr("Periodic") << tr("On Change") << tr("Manual") << tr("Never"); - QStringList accessModeEnum; - accessModeEnum << tr("Read/Write") << tr("Read Only"); + QStringList modesBitField; + modesBitField << tr("FlightReadOnly") << tr("GCSReadOnly") << tr("FlightTelemetryAcked") << tr("GCSTelemetryAcked") << tr("FlightUpdatePeriodic") << tr("FlightUpdateOnChange") << tr("GCSUpdatePeriodic") << tr("GCSUpdateOnChange"); QList fields; - fields.append( new UAVObjectField(tr("Modes"), tr(""), UAVObjectField::UINT8, 1, accessModeEnum) ); - fields.append( new UAVObjectField(tr("Flight Telemetry Update Period"), tr(""), UAVObjectField::UINT16, 1, QStringList()) ); - fields.append( new UAVObjectField(tr("GCS Telemetry Update Period"), tr(""), UAVObjectField::UINT16, 1, QStringList()) ); - fields.append( new UAVObjectField(tr("Logging Update Period"), tr(""), UAVObjectField::UINT16, 1, QStringList()) ); + fields.append( new UAVObjectField(tr("Modes"), tr("boolean"), UAVObjectField::BITFIELD, modesBitField, QStringList()) ); + fields.append( new UAVObjectField(tr("Flight Telemetry Update Period"), tr("ms"), UAVObjectField::UINT16, 1, QStringList()) ); + fields.append( new UAVObjectField(tr("GCS Telemetry Update Period"), tr("ms"), UAVObjectField::UINT16, 1, QStringList()) ); + fields.append( new UAVObjectField(tr("Logging Update Period"), tr("ms"), UAVObjectField::UINT16, 1, QStringList()) ); // Initialize parent UAVObject::initialize(0); UAVObject::initializeFields(fields, (quint8*)&parentMetadata, sizeof(Metadata)); diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.h b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.h index 56e74152e..d092c6731 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobject.h +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobject.h @@ -59,10 +59,10 @@ public: * Object update mode */ typedef enum { - UPDATEMODE_PERIODIC = 0, /** Automatically update object at periodic intervals */ - UPDATEMODE_ONCHANGE = 1, /** Only update object when its data changes */ - UPDATEMODE_THROTTLED = 2, /** Object is updated on change, but not more often than the interval time */ - UPDATEMODE_MANUAL = 3 /** Manually update object, by calling the updated() function */ + UPDATEMODE_MANUAL = 0, /** Manually update object, by calling the updated() function */ + UPDATEMODE_PERIODIC = 1, /** Automatically update object at periodic intervals */ + UPDATEMODE_ONCHANGE = 2, /** Only update object when its data changes */ + UPDATEMODE_THROTTLED = 3 /** Object is updated on change, but not more often than the interval time */ } UpdateMode; /** diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjectfield.cpp b/ground/openpilotgcs/src/plugins/uavobjects/uavobjectfield.cpp index f5df52396..5ccd7371f 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobjectfield.cpp +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjectfield.cpp @@ -86,6 +86,10 @@ void UAVObjectField::constructorInitialize(const QString& name, const QString& u case ENUM: numBytesPerElement = sizeof(quint8); break; + case BITFIELD: + numBytesPerElement = sizeof(quint8); + this->options = QStringList()<=struc.values.at(0).toUInt() && var.toUInt()<=struc.values.at(1).toUInt())) return false; return true; @@ -316,6 +324,7 @@ bool UAVObjectField::isWithinLimits(QVariant var,quint32 index) case UINT8: case UINT16: case UINT32: + case BITFIELD: if(!(var.toUInt()>=struc.values.at(0).toUInt())) return false; return true; @@ -350,6 +359,7 @@ bool UAVObjectField::isWithinLimits(QVariant var,quint32 index) case UINT8: case UINT16: case UINT32: + case BITFIELD: if(!(var.toUInt()<=struc.values.at(0).toUInt())) return false; return true; @@ -457,6 +467,8 @@ QString UAVObjectField::getTypeAsString() return "float32"; case UAVObjectField::ENUM: return "enum"; + case UAVObjectField::BITFIELD: + return "bitfield"; case UAVObjectField::STRING: return "string"; default: @@ -477,7 +489,15 @@ UAVObject* UAVObjectField::getObject() void UAVObjectField::clear() { QMutexLocker locker(obj->getMutex()); - memset(&data[offset], 0, numBytesPerElement*numElements); + switch (type) + { + case BITFIELD: + memset(&data[offset], 0, numBytesPerElement*((quint32)(1+(numElements-1)/8))); + break; + default: + memset(&data[offset], 0, numBytesPerElement*numElements); + break; + } } QString UAVObjectField::getName() @@ -507,7 +527,15 @@ quint32 UAVObjectField::getDataOffset() quint32 UAVObjectField::getNumBytes() { - return numBytesPerElement * numElements; + switch (type) + { + case BITFIELD: + return numBytesPerElement * ((quint32) (1+(numElements-1)/8)); + break; + default: + return numBytesPerElement * numElements; + break; + } } QString UAVObjectField::toString() @@ -584,6 +612,12 @@ qint32 UAVObjectField::pack(quint8* dataOut) dataOut[numBytesPerElement*index] = data[offset + numBytesPerElement*index]; } break; + case BITFIELD: + for (quint32 index = 0; index < (quint32)(1+(numElements-1)/8); ++index) + { + dataOut[numBytesPerElement*index] = data[offset + numBytesPerElement*index]; + } + break; case STRING: memcpy(dataOut, &data[offset], numElements); break; @@ -653,6 +687,12 @@ qint32 UAVObjectField::unpack(const quint8* dataIn) data[offset + numBytesPerElement*index] = dataIn[numBytesPerElement*index]; } break; + case BITFIELD: + for (quint32 index = 0; index < (quint32)(1+(numElements-1)/8); ++index) + { + data[offset + numBytesPerElement*index] = dataIn[numBytesPerElement*index]; + } + break; case STRING: memcpy(&data[offset], dataIn, numElements); break; @@ -661,11 +701,6 @@ qint32 UAVObjectField::unpack(const quint8* dataIn) return getNumBytes(); } -quint32 UAVObjectField::getNumBytesElement() -{ - return numBytesPerElement; -} - bool UAVObjectField::isNumeric() { switch (type) @@ -694,6 +729,9 @@ bool UAVObjectField::isNumeric() case ENUM: return false; break; + case BITFIELD: + return true; + break; case STRING: return false; break; @@ -730,6 +768,9 @@ bool UAVObjectField::isText() case ENUM: return true; break; + case BITFIELD: + return false; + break; case STRING: return true; break; @@ -810,6 +851,14 @@ QVariant UAVObjectField::getValue(quint32 index) return QVariant( options[tmpenum] ); break; } + case BITFIELD: + { + quint8 tmpbitfield; + memcpy(&tmpbitfield, &data[offset + numBytesPerElement*((quint32)(index/8))], numBytesPerElement); + tmpbitfield = (tmpbitfield >> (index % 8)) & 1; + return QVariant( tmpbitfield ); + break; + } case STRING: { data[offset + numElements - 1] = '\0'; @@ -845,6 +894,7 @@ bool UAVObjectField::checkValue(const QVariant& value, quint32 index) case UINT32: case FLOAT32: case STRING: + case BITFIELD: return true; break; case ENUM: @@ -926,6 +976,14 @@ void UAVObjectField::setValue(const QVariant& value, quint32 index) memcpy(&data[offset + numBytesPerElement*index], &tmpenum, numBytesPerElement); break; } + case BITFIELD: + { + quint8 tmpbitfield; + memcpy(&tmpbitfield, &data[offset + numBytesPerElement*((quint32)(index/8))], numBytesPerElement); + tmpbitfield = (tmpbitfield & ~(1 << (index % 8))) | ( (value.toUInt()!=0?1:0) << (index % 8) ); + memcpy(&data[offset + numBytesPerElement*((quint32)(index/8))], &tmpbitfield, numBytesPerElement); + break; + } case STRING: { QString str = value.toString(); diff --git a/ground/openpilotgcs/src/plugins/uavobjects/uavobjectfield.h b/ground/openpilotgcs/src/plugins/uavobjects/uavobjectfield.h index faad2e568..c99db17a2 100644 --- a/ground/openpilotgcs/src/plugins/uavobjects/uavobjectfield.h +++ b/ground/openpilotgcs/src/plugins/uavobjects/uavobjectfield.h @@ -42,7 +42,7 @@ class UAVOBJECTS_EXPORT UAVObjectField: public QObject Q_OBJECT public: - typedef enum { INT8 = 0, INT16, INT32, UINT8, UINT16, UINT32, FLOAT32, ENUM, STRING } FieldType; + typedef enum { INT8 = 0, INT16, INT32, UINT8, UINT16, UINT32, FLOAT32, ENUM, BITFIELD, STRING } FieldType; typedef enum { EQUAL,NOT_EQUAL,BETWEEN,BIGGER,SMALLER } LimitType; typedef struct { @@ -70,7 +70,6 @@ public: void setDouble(double value, quint32 index = 0); quint32 getDataOffset(); quint32 getNumBytes(); - quint32 getNumBytesElement(); bool isNumeric(); bool isText(); QString toString(); diff --git a/ground/uavobjgenerator/generators/generator_common.cpp b/ground/uavobjgenerator/generators/generator_common.cpp index 5ba513dc6..12fae596d 100644 --- a/ground/uavobjgenerator/generators/generator_common.cpp +++ b/ground/uavobjgenerator/generators/generator_common.cpp @@ -37,8 +37,9 @@ void replaceCommonTags(QString& out, ObjectInfo* info) { QStringList updateModeStr,accessModeStr; - updateModeStr << "UPDATEMODE_PERIODIC" << "UPDATEMODE_ONCHANGE" - << "UPDATEMODE_THROTTLED" << "UPDATEMODE_MANUAL"; + updateModeStr << "UPDATEMODE_MANUAL" << "UPDATEMODE_PERIODIC" + << "UPDATEMODE_ONCHANGE" + << "UPDATEMODE_THROTTLED"; accessModeStr << "ACCESS_READWRITE" << "ACCESS_READONLY"; diff --git a/ground/uavobjgenerator/uavobjectparser.cpp b/ground/uavobjgenerator/uavobjectparser.cpp index e5759a399..73c4833b0 100644 --- a/ground/uavobjgenerator/uavobjectparser.cpp +++ b/ground/uavobjgenerator/uavobjectparser.cpp @@ -34,7 +34,7 @@ UAVObjectParser::UAVObjectParser() fieldTypeStrXML << "int8" << "int16" << "int32" << "uint8" << "uint16" << "uint32" <<"float" << "enum"; - updateModeStrXML << "periodic" << "onchange" << "throttled" << "manual"; + updateModeStrXML << "manual" << "periodic" << "onchange" << "throttled"; accessModeStr << "ACCESS_READWRITE" << "ACCESS_READONLY"; diff --git a/ground/uavobjgenerator/uavobjectparser.h b/ground/uavobjgenerator/uavobjectparser.h index 5babfbc40..cad891d3c 100644 --- a/ground/uavobjgenerator/uavobjectparser.h +++ b/ground/uavobjgenerator/uavobjectparser.h @@ -64,10 +64,10 @@ typedef struct { * Object update mode */ typedef enum { - UPDATEMODE_PERIODIC = 0, /** Automatically update object at periodic intervals */ - UPDATEMODE_ONCHANGE, /** Only update object when its data changes */ - UPDATEMODE_THROTTLED, /** Object is updated on change, but not more often than the interval time */ - UPDATEMODE_MANUAL /** Manually update object, by calling the updated() function */ + UPDATEMODE_MANUAL = 0, /** Manually update object, by calling the updated() function */ + UPDATEMODE_PERIODIC = 1, /** Automatically update object at periodic intervals */ + UPDATEMODE_ONCHANGE = 2, /** Only update object when its data changes */ + UPDATEMODE_THROTTLED = 3 /** Object is updated on change, but not more often than the interval time */ } UpdateMode;